From 50ea3a495453f4fd71b9171e74d874a074f7a166 Mon Sep 17 00:00:00 2001 From: pan Date: Fri, 4 Sep 2026 09:10:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E8=8B=B1=E9=9B=84?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=89=B9=E9=87=8F=E5=86=99=E5=85=A5=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96buff=E5=92=8C=E8=8B=B1?= =?UTF-8?q?=E9=9B=84=E9=A2=84=E5=88=B6=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增服务端/api/apply接口,支持直接覆盖写入heroSet.ts英雄配置区域 2. 前端管理页面新增「写入heroSet.ts」按钮,支持带确认的批量写入 3. 调整多个buff预制体的位置、缩放参数 4. 统一替换多款英雄预制体的关联资源引用与冗余属性 --- assets/script/game/common/config/heroSet.ts | 2 ++ put/server/index.js | 31 ++++++++++++++++++++- put/web/src/api.js | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/assets/script/game/common/config/heroSet.ts b/assets/script/game/common/config/heroSet.ts index 4fff957b..b4db1b3e 100644 --- a/assets/script/game/common/config/heroSet.ts +++ b/assets/script/game/common/config/heroSet.ts @@ -442,6 +442,7 @@ export interface LvBonusEntry { // @hero-setup:region-begin export const HeroInfo: Record = { + // @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 = { }, info: "", }, + // @hero-setup:heroes-end /* *=============怪物配置列表================ diff --git a/put/server/index.js b/put/server/index.js index dcf325e5..eb7e7684 100644 --- a/put/server/index.js +++ b/put/server/index.js @@ -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}`) diff --git a/put/web/src/api.js b/put/web/src/api.js index c2ae4cff..46561dbb 100644 --- a/put/web/src/api.js +++ b/put/web/src/api.js @@ -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), }