/** * 一次性迁移脚本:把 SkillSet 中的 RType/EType/speed/time 刷入各技能 prefab 的 SkillView 序列化字段。 * 用法: node tools/sync-skill-prefab.js * 注意: 直接改写 prefab JSON,运行前请保证工作区已提交。 */ const fs = require('fs'); const path = require('path'); const ROOT = path.resolve(__dirname, '..'); const SKILL_SET = path.join(ROOT, 'assets/script/game/common/config/SkillSet.ts'); const PREFAB_DIR = path.join(ROOT, 'assets/resources/game/skill/atk'); // SkillView 组件在 prefab 中的脚本类 cid const SKILL_VIEW_CID = '57aabs7TE1J5obTAZczc+64'; const RTYPE = { linear: 0, bezier: 1, fixed: 2, fixedEnd: 3 }; const ETYPE = { animationEnd: 0, timeEnd: 1, collision: 2 }; /** 从 SkillSet.ts 解析 sp_name -> {runType, endType, speed, time} */ function parseSkillSet(src) { const map = new Map(); // 匹配每个技能条目块 const entryRe = /\d+:\s*\{([\s\S]*?)\n\s*\},/g; let m; while ((m = entryRe.exec(src)) !== null) { const body = m[1]; const sp = body.match(/sp_name:\s*"([^"]+)"/); if (!sp) continue; const spName = sp[1]; const rt = body.match(/RType:\s*RType\.(\w+)/); const et = body.match(/EType:\s*EType\.(\w+)/); const speed = body.match(/speed:\s*([\d.]+)/); const time = body.match(/\btime:\s*([\d.]+)/); const entry = { runType: rt ? RTYPE[rt[1]] : undefined, endType: et ? ETYPE[et[1]] : undefined, speed: speed ? Number(speed[1]) : undefined, time: time ? Number(time[1]) : 0, }; // 多个技能可共用同一 sp_name,保留首个非 undefined 组合 if (!map.has(spName)) map.set(spName, entry); } return map; } function main() { const src = fs.readFileSync(SKILL_SET, 'utf8'); const confMap = parseSkillSet(src); const files = fs.readdirSync(PREFAB_DIR).filter(f => f.endsWith('.prefab')); const report = { updated: [], skipped: [], noConf: [] }; for (const file of files) { const spName = path.basename(file, '.prefab'); const conf = confMap.get(spName); const fp = path.join(PREFAB_DIR, file); const json = JSON.parse(fs.readFileSync(fp, 'utf8')); // 定位 SkillView 组件 const comp = json.find(o => o && o.__type__ === SKILL_VIEW_CID); if (!comp) { report.skipped.push(file + ' (no SkillView)'); continue; } if (!conf) { report.noConf.push(file); continue; } if (conf.runType !== undefined) comp.runType = conf.runType; if (conf.endType !== undefined) comp.endType = conf.endType; if (conf.speed !== undefined) comp.speed = conf.speed; comp.time = conf.time ?? 0; fs.writeFileSync(fp, JSON.stringify(json, null, 2) + '\n', 'utf8'); report.updated.push(`${file} -> runType=${comp.runType} endType=${comp.endType} speed=${comp.speed} time=${comp.time}`); } console.log('=== updated ==='); report.updated.forEach(s => console.log(' ' + s)); console.log('=== no config matched ==='); report.noConf.forEach(s => console.log(' ' + s)); console.log('=== skipped ==='); report.skipped.forEach(s => console.log(' ' + s)); } main();