feat: 新增英雄配置批量写入功能,优化buff和英雄预制体

1.  新增服务端/api/apply接口,支持直接覆盖写入heroSet.ts英雄配置区域
2.  前端管理页面新增「写入heroSet.ts」按钮,支持带确认的批量写入
3.  调整多个buff预制体的位置、缩放参数
4.  统一替换多款英雄预制体的关联资源引用与冗余属性
This commit is contained in:
pan
2026-09-04 09:10:21 +08:00
parent 7e94560e95
commit 50ea3a4954
3 changed files with 33 additions and 1 deletions

View File

@@ -442,6 +442,7 @@ export interface LvBonusEntry {
// @hero-setup:region-begin
export const HeroInfo: Record<number, heroInfo> = {
// @hero-setup:heroes-begin
5001: {
uuid: 5001, name: "叠甲骑士", path: "hk1", fac: FacSet.HERO, rarity: 1, lv: 1, type: HType.Melee, grow_type: HGrowType.Tank, role: HRole.Tank, hp: HERO_ROLE_BASE[HRole.Tank].hp + 20, ap: HERO_ROLE_BASE[HRole.Tank].ap, def: HERO_ROLE_BASE[HRole.Tank].def + 10,
skills: {
@@ -631,6 +632,7 @@ export const HeroInfo: Record<number, heroInfo> = {
},
info: "",
},
// @hero-setup:heroes-end
/*
*=============怪物配置列表================

View File

@@ -9,6 +9,10 @@ const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
const PROJECT_ROOT = path.resolve(__dirname, '..', '..')
const CONFIG_DIR = path.join(PROJECT_ROOT, 'assets/script/game/common/config')
const EXPORT_PATH = path.join(CONFIG_DIR, 'hexport.ts')
const HEROSET_PATH = path.join(CONFIG_DIR, 'heroSet.ts')
// heroSet.ts 中英雄条目区域标记(怪物配置在 end 标记之后,不受替换影响)
const HEROES_BEGIN = '// @hero-setup:heroes-begin'
const HEROES_END = '// @hero-setup:heroes-end'
const DATA_DIR = path.join(__dirname, 'data')
const HEROES_PATH = path.join(DATA_DIR, 'heroes.json')
@@ -131,7 +135,7 @@ function renderSingleHero(h) {
const lines = []
const indent = ' '
const push = (s) => lines.push(indent + s)
push(`// ${h.uuid} ${h.name} — ${h.comment || ''}`)
push(`// ${h.uuid} ${h.name}${h.comment ? ` — ${h.comment}` : ''}`)
push(`${h.uuid}: {`)
const roleExpr = `HERO_ROLE_BASE[HRole.${h.roleKey}]`
const stat = (k) => {
@@ -246,6 +250,31 @@ app.get('/api/export', (_req, res) => {
res.send(fs.readFileSync(EXPORT_PATH, 'utf8'))
})
/**
* 直接写回 heroSet.ts:用编辑器数据替换英雄条目区域(HEROES_BEGIN/END 标记之间),
* 怪物条目与区域外的其它配置保持不变。
*/
app.post('/api/apply', (req, res) => {
try {
const heroes = req.body?.heroes
if (!Array.isArray(heroes) || !heroes.length) {
return res.status(400).json({ error: 'heroes 不能为空' })
}
const src = fs.readFileSync(HEROSET_PATH, 'utf8')
const bi = src.indexOf(HEROES_BEGIN)
const ei = src.indexOf(HEROES_END)
if (bi < 0 || ei < 0 || ei < bi) {
return res.status(500).json({ error: 'heroSet.ts 中未找到英雄区域标记(@hero-setup:heroes-begin/end)' })
}
const body = heroes.map(renderSingleHero).join('')
const next = src.slice(0, bi) + HEROES_BEGIN + '\n' + body + HEROES_END + src.slice(ei + HEROES_END.length)
fs.writeFileSync(HEROSET_PATH, next, 'utf8')
res.json({ ok: true, path: HEROSET_PATH, count: heroes.length, bytes: Buffer.byteLength(next) })
} catch (e) {
res.status(500).json({ error: String(e?.message || e) })
}
})
const PORT = 3001
app.listen(PORT, () => {
console.log(`[hero-config-tool] server listening http://localhost:${PORT}`)

View File

@@ -6,5 +6,6 @@ export const api = {
fetchHeroes: () => axios.get('/api/heroes').then((r) => r.data),
saveHeroes: (heroes) => axios.post('/api/heroes', { heroes }).then((r) => r.data),
exportHeroes: (heroes) => axios.post('/api/export', { heroes }).then((r) => r.data),
applyHeroes: (heroes) => axios.post('/api/apply', { heroes }).then((r) => r.data),
fetchExport: () => axios.get('/api/export', { responseType: 'text' }).then((r) => r.data),
}