Runner v2 全弧第一相(HJ-RUNNER-ARC-001 / P1):用王蓝莓把"上层游戏宿主装载契约"
从零 spike 到"引擎真掌帧 + 游戏美术与引擎粒子同屏可玩",解锁 P2 泛化 / P3 生成。
契约与共享件
- 新增装载契约 game-runtime/src/core/game-host.d.ts(第9类 additive·暂名):
GameHostBootContext / GameInstance / GameHostFactory;游戏=纯模块工厂,零引擎 import,
能力经下层 ctx.getEngine()(受控面 6 项零改),绘制面 render(g) 的 g=引擎 mainContext
- makeEngineCaps 闭包提升为可 import 模块 host-dev/engine-caps.js(createEngineCaps):
host-dev/ref/未来生成游戏共用;engineMode 短路 / __engineCalls 探针 / null-engine 语义逐行不变
王蓝莓 real 通道(games/wanglanmei-ref)
- 增 ?engine=real:主循环从浏览器 RAF 改挂 engineInit 五回调(掌帧唯一源=引擎);
游戏美术绘制面从 #game 改引擎 mainContext(同屏合并);bundle 延后到 setupReal 内以
mainContext 建(getContext2d 闭包快照修);保 ?engine=stub 逐像素确定性回滚
- game-shop.js 抽为独立 GameHostFactory(零引擎 import,P3 生成 agent 可复制范本)
- entry.js 动态 import('littlejsengine')=node-import-safe ∧ esbuild iife 入包两全
- 驱动 e2e-input.cdp.cjs real 改造:禁 stepFrames 手摇(防双掌帧),真触摸+轮询;
门②同屏像素判据(暖色 warmHits ∧ 引擎粒子 brightHits 同张 #game-engine)
真机验收(mini-desktop real 引擎,5 门)
引擎掌帧 dFrame=31∈[20,45] / 同屏 warmHits=682∧brightHits=13028 同张 #game-engine /
particles.spawnEmitter+synthSfx call-ID 运行时真调引擎 / CDP 517 真触摸跑通整局
(第1天接待18·营收¥79.9·连击9) / console 零错;本机 88 单测全绿(含修复 4 红+补回归)
证据:games/wanglanmei-ref/evidence/p1-real/(e2e-evidence.json pass=true + 5 截图肉眼复核)
诚实 caveat:门② brightHits 在结算屏混入亮 UI,同屏合并由 warmHits(美术落引擎画布)+
call-ID(粒子真调引擎)+ 引擎架构(粒子渲同一 mainContext)三证成立,非阻断。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
21 KiB
P1 · 王蓝莓上引擎(spike 游戏宿主装载契约)· 评审版
状态:review 版 · 2026-06-13 · 给创始人决策(结论先行,不写代码级执行细节,多用 Mermaid)。已过对抗复审(2026-06-13 deep·全程读真源码):无致命项;4 重大项 + 5 项不明假设已全部纳入 execution 版钉死(逐条裁决见 execution §12)。readiness = ready-with-caveats(仅 1 个非阻断 open item:契约工件命名,见 §8)。 定位:本文是 Runner v2 全弧 P1 相(第一相)的评审版。母梁见
2026-06-13-runner-v2-arc-review.md§5.1。P1 的任务 = 把"游戏宿主装载契约"(arc 上层契约)用王蓝莓 spike 到真跑在引擎上;P2/P3 归并入母 spec(见 §7)。 前提(创始人已拍):① 推进 P1(全弧第一相);② O1 装载契约 = 新立 additive 第 9 类契约(不污染既有插件契约PluginContext),生命周期 =init/update/render/onInput+destroy,boot 时把引擎mainContext注入游戏层;③ O2 = P2 合并进母 spec Phase D;④ 不用 fable,一律 opus。 复审改点(结论级,详见 execution §12):契约工件落game-runtime/src/core/game-host.d.ts(与api.d.ts同目录,非 contracts/——contracts 是跨三仓五工位业务契约 SSOT,本契约是 game-runtime 内部 host↔游戏工厂接线面,让 SSOT 反向依赖业务源码且拆仓即断);real 通道补__refBootedReal就绪标记 + driver 范式从「stepFrames 手摇」切到「真触摸+轮询」(引擎掌帧下手摇=双掌帧违铁律);同屏门暖色阈值开工前坐实(不留占位);bundle 延后到 engineInit().then 内以 mainContext 建(防渲染面分裂)。 关联:边界铁律 engine-plugin-boundary-model、A0 地基 a0-engine-takeover-done、harness 配方.agents/skills/game-e2e-cdp-harness.md(§5 门0 / §6 门②)、A0 双通道(?engine=stub回滚)。
1. 结论先行
P1 = 给 wanglanmei-ref 加 ?engine=real 通道,用它把"游戏宿主装载契约"(新立 additive 第 9 类契约)spike 实,证三件事并人在 mini-desktop 浏览器真玩:
- 引擎真掌帧(
engineInit五回调驱动游戏update/render,废main.js自管的浏览器 RAF); - 游戏美术与引擎粒子同屏可玩(游戏绘制面从自带
#game2D 画布改引擎mainContext,两面合并成一张画布); - 回滚保真(
?engine=stub通道逐行保旧行为 + 逐像素确定性,A0 双通道范式)。
同时把已存在但仍是闭包的 makeEngineCaps(host.js:197-318)提升为可 import 模块 host-dev/engine-caps.js,host-dev / ref / 未来生成游戏共用同一份引擎能力包装层——这是"模块化已有件"(搬运),非从零造(arc §0-F2 已订正原稿"engine-caps.js 不存在=真新增工作")。
装载契约的本质(O1 已拍形态):一款游戏 = 一个纯模块工厂(零引擎 import,Q4 铁律),暴露稳定生命周期 init(ctx, mainCtx) / update(dt) / render(g) / onInput(ev) / destroy();其中 render(g) 的 g = 引擎 mainContext(boot 时注入),插件能力仍经下层已冻结的 ctx.getEngine() 拿。该契约落 game-runtime/src/core/game-host.d.ts(与既有 api.d.ts 同目录,复审改点;理由见上「复审改点」),与 api.d.ts 是 additive 关系——受控面 6 项契约零改(getContext2d/getInput/getAudioContext/getEngine,api.d.ts:269/281/286/303)。game 工厂必须是独立、可被 P3 复制的实现(独立文件默认导出、零引擎 import,禁 main.js 内联糊过——这是 P3 生成 agent 的真实参照靶,复审钉死的硬边界)。
⚠️ 为何必须新立、不能借
PluginContext:ref 的游戏层(core.update/drawFrame(g),main.js:621/648)不是插件、不走PluginContext;今天全仓没有"游戏整体↔引擎mainContext"的约定面(grep GameModule/装载契约在contracts/+src/零命中,已复证)。getEngine()(api.d.ts:303)是插件拿引擎能力的面,凑不上"游戏 update/render 主体怎么挂引擎"。这正是装载契约要补的缺口——它与PluginContext一个都不能替另一个(边界模型"同一职不留两条并行路")。
2. 装载契约决策(O1 已拍)
| 决策点 | 已拍结论 | 理由 / 证据 |
|---|---|---|
| 归属 | 新立 additive 第 9 类契约,不折进 api.d.ts 插件面 |
避免污染插件契约语义,与边界模型"一职一路"一致;PluginContext=插件面、GameHost=游戏面,两者正交(arc O1 建议①)。 |
| 落点(复审改) | game-runtime/src/core/game-host.d.ts(与 api.d.ts 同目录),非 contracts/ |
contracts/ 是跨三仓五工位的业务契约 SSOT(contracts/README.md §1,含拆仓计划);本契约是 game-runtime 内部 host↔游戏工厂接线面,消费方只在 game-runtime,落同目录 import 方向顺(./api.d.ts);落 contracts 会让 SSOT 反向相对 import ../game-runtime/src,违「契约即 SSOT」且拆仓即断(execution §12-A1)。 |
| 生命周期粒度 | init(ctx, mainCtx) / update(dt) / render(g) / onInput(ev) / destroy() 五件 |
init/update/render/onInput 对齐引擎五回调(engGameInit/Update/Render,host.js:883-887);destroy 补卸载卫生(P2 装载多游戏时复位)。其余(resize/onVisibility)additive 后补。 |
| 绘制面约定 | render(g) 的 g = 引擎 mainContext,boot 时注入游戏层 |
A0 已证 setGLEnable(false) 后引擎纯 2D 渲进 mainContext(host.js:904/919);游戏绘制面改它即与引擎粒子同屏(消除渲染面分裂)。不借 PluginContext。 |
| 能力获取 | 插件能力经下层已冻结 ctx.getEngine();游戏绝不 import littlejsengine |
Q4 铁律:引擎 import 只活 entry/host(entry.js:18-21/host.js:44)。 |
装载关系图(游戏 ↔ host ↔ 引擎):
flowchart TB
subgraph host["集成段 host 层(唯一 import 引擎处·Q4 铁律)"]
EI["LJS.engineInit 五回调<br/>(引擎内部 RAF 驱动)"]
EC["engine-caps.js 模块<br/>(提升自 host.js:197 闭包·非从零)<br/>particles/audio.synth/math 三面薄包装"]
BOOT["bootRef real 分支<br/>setGLEnable(false)+建 engineFactory<br/>+ 注入 mainContext 给游戏层"]
end
subgraph game["游戏侧(装载契约·零引擎 import·新立第9契约)"]
GH["game.init(ctx, mainCtx)<br/>game.update(dt)<br/>game.render(g=mainContext)<br/>game.onInput(ev)<br/>game.destroy()"]
end
subgraph low["下层契约(已冻结·复用·零改)"]
PC["PluginContext.getEngine()<br/>受控面 6 项 + 引擎能力面"]
end
EI -->|gameUpdate→| GH
EI -->|gameRender→ 引擎 mainContext| GH
BOOT -->|注入 mainCtx| GH
EC -->|engineFactory| BOOT
PC -. 插件能力 ctx.getEngine() .-> GH
GH -. 禁 .->|import littlejsengine| X1["❌ Q4 违例"]
3. 同屏方案与最大风险
3.1 同屏方案(real 通道改造主干)
| 改造点 | stub 通道(保旧,回滚锚) | real 通道(新增,引擎掌帧) |
|---|---|---|
| 掌帧源 | 浏览器 RAF + mockNowMs(墙钟近似),main.js:668-691 |
引擎 engineInit 五回调;RAF 旁置/门控;mockNowMs 改逻辑帧钟(每逻辑步 +FIXED_DT×1000) |
| 逻辑段 | frame(dtReal) 内 core.update/bundle.tick/applyEvents/fx.step |
同段移入 game.update(dt),由 gameUpdate 回调驱动 |
| 绘制段 | drawFrame(g)+palettePost.renderPost(g),g=#game 2D |
同段移入 game.render(g),g=引擎 mainContext(boot 注入),由 gameRender 回调驱动 |
| 插件受控面 context2d | host prepareCanvas(#game) 的 ctx |
快照引擎 mainContext(createHostDevContext 的 context2d 改它) |
| 粒子能力 | engineFactory 未传 → getEngine()=null → 粒子 NOOP_HANDLE(无粒子) |
经 engine-caps.js 建 engineFactory → 粒子真经引擎 ParticleEmitter 自渲落 mainContext |
3.2 最大风险(先标在最前)
| 风险 | 等级 | 缓解 / 回滚 |
|---|---|---|
| 真渲同屏过不了 / 假阳性(粒子渲到另一张分离画布,游戏画布无粒子命中) | P0 | 这是 P1 第一道真门,也是全弧第一道门。判据必须堵死假阳性:截取引擎接管后 DOM 可见那张 canvas(=mainContext 的 canvas,A0 已给它打 id #game-engine,host.js:830),断言同一张画布上既有游戏美术像素命中(店面暖色主色)又有引擎粒子像素命中(burst 白 maxCh>80)。复审改(M3):店面暖色阈值开工前已从 palette.js 坐实具体色域(r>140 && r−b>85 && g<r,排纸底/天光/近白),不留执行时占位——gate0/a6 的青蓝/亮度口径与暖色正相反,留占位会假阳/假阴(execution §8「门②(a)」)。若粒子渲到另一张画布 → 游戏画布粒子命中=0 → fail。回滚=?engine=stub。 |
掌帧冲突(main.js 自管 RAF + mockNowMs 与引擎掌帧直接冲突) |
P0 | A0 双通道已证引擎掌帧可行;real 通道废 RAF、mockNowMs 改逻辑帧钟,对齐 host.js real 分支既定做法(host.js:526/884)。 |
| real 通道就绪标记缺失(复审 M1)——driver 在引擎/game 就绪前驱动→打空/间歇绿 | P0 | real 下 __refBooted(index.html:81 bootRef().then 置)早于引擎就绪;补 real 专属 __refBootedReal(只在 engineInit().then 内 game.init 完成后置,仿 host-dev __hostBootedReal host.js:920),driver real 分支等它(execution 步骤 4.3/8a)。 |
driver 范式失效(复审 M2)——stepFrames 手摇在引擎掌帧下双掌帧违铁律、#game rect 取错画布 |
P0 | real driver 范式切换(非增量):禁 stepFrames,改真触摸+轮询;rect 选择器切 #game-engine。与 stub「手摇定量推帧」分道(stub 兜逐像素,real 只证掌帧+渲染+真玩,harness §5-坑6)。execution 步骤 8。 |
| 渲染面分裂(复审 M4)——real 顶层同步建 bundle 会快照错 ctx(受控面 context2d≠游戏 render 面) | P0 | bundle 必须延后到 engineInit().then 内、以 context2d=mainContext 建(getContext2d 一次性快照闭包捕获值,host.js:323-324);输入桥+game.init+就绪标记同移进。execution 步骤 4.3(M4)。 |
| engine-caps 模块化引入回归(探针/短路语义漂移) | P1 | 提升须保 engineMode 短路 / __engineCalls 探针 / null-engine 回归语义逐行不变;门0 8/8 + real 门 6/6 作回归基线。recHook 设计成可注入(默认 no-op)——探针绝不入渠道产物(见 §6)。 |
| receHook 探针泄进渠道产物 | P1 | 物理保证:createEngineCaps({recHook}) 默认 recHook=no-op;ref-bundle 构建时不传 recHook(或传 no-op),仅王蓝莓真玩取证脚本注入 rec。渠道产物 esbuild 入口不引取证注入点 → 探针代码 tree-shake 不进包。 |
| 体积(ref 197KB→~540KB,引擎真入包) | P2 | ~540KB raw min(host-dev entry 实测 544KB 量级);gz 远在 B1 入场券 gz≤350KB 内(LittleJS 完整版 raw≈55KB gz)→ 不触红线。SIZES.md 增"游戏产物=引擎+包装层"口径(与插件增量分离)。勿引"13KB"(已废)。 |
| 受控面被动 | P0 | 受控面 6 项契约零改是硬约束(engineFactory 是既有可选入参 api.d.ts:405);装载契约是 additive 新增,不改下层既冻 6 项。 |
4. 验收门概览(arc §5.1 六门 + 韧性)
| 门 | 判据 | 口径来源 |
|---|---|---|
| ① 掌帧 | 引擎掌帧帧增量区间 [20,45]/500ms |
gate0 G0-2(gate0-engine-takeover.cjs:75) |
| ② 同屏像素 | 同一张画布(#game-engine)上:游戏美术暖色命中(warmHits>200,色域 r>140 && r−b>85 && g<r,开工前坐实非占位·M3)∧ 引擎粒子像素命中(burst 白 maxCh>80、brightHits>0);粒子渲到另一画布则游戏画布命中=0=fail |
a6 A6-5(maxCh/brightHits)+ 暖色域自 palette.js:23-41(execution §8「门②(a)」) |
| ③ 真接线门② | window.__engineCalls 含 particles.spawnEmitter call-ID(插件运行时真调引擎) |
a6 A6-2(a6-engine-wiring.cjs:79) |
| ④ CDP 真玩 | CDP 真触摸逐 zone 真玩(开店→进货→营业→结算→升级)+ 四件套 evidence;driver 范式=真触摸+轮询,禁 stepFrames 手摇·M2;rect 选择器 #game-engine、就绪等 __refBootedReal;zone 名以 main.js computeZones 为唯一真相 |
ref e2e 扩 real 通道(execution 步骤 8)+ harness §2-律4 |
| ⑤ stub 回归 | ?engine=stub 逐像素确定性回归仍绿(双开哈希一致) |
ref e2e 门 B + harness §5-坑6 |
| ⑥ 提升回归 | engine-caps 提升后门0 8/8 + real 门 6/6 逐项不变 | gate0 + a6 |
| ⑦ console 干净 | console 零未捕获错误 | ref e2e(uncaught=[]) |
5. 回滚
- 代码回滚:
?engine=stub通道与今天main.js行为逐行等价(RAF +#game2D 画布 +mockNowMs墙钟)。real 通道过不了 → 用户/取证一律走 stub,stub 既有交付(T1b-α 49 单测 + e2e 四件套)零连累。 - 契约回滚:装载契约
game-host.d.ts是 additive 新增工件,受控面 6 项零改 → 移除新增不破存量。 - 模块回滚:engine-caps.js 提升若引入回归(门0/real 门红),可临时让 host.js 退回内联闭包(git revert 该文件 + host.js import 行),不连累 ref real 通道(ref 自带 engineFactory 经 createEngineCaps)。
6. 爆炸半径
| 触及 | 文件 | 性质 |
|---|---|---|
| ref 主循环重做 | games/wanglanmei-ref/{entry.js:15, src/main.js:112/583-602/617-691/648} |
real 通道改造(stub 保旧);含输入改挂 mainCanvas(M4) |
| 装载契约新工件 | game-runtime/src/core/game-host.d.ts(新增,复审改落点)+ contracts/README.md(仅指针登记) |
additive 第 9 类契约(game-runtime 内部) |
| engine-caps 模块化 | host-dev/engine-caps.js(新增,搬 host.js:197-318)+ host-dev/host.js(改 import) |
搬运已有件,语义零变 |
| ref 装载适配 | games/wanglanmei-ref/src/game-shop.js(新增·硬独立文件,A3):拆出符合装载契约的 game 工厂(默认导出、零引擎 import,禁 main.js 内联);entry import 引擎 |
real 通道接线 |
| ref 就绪标记 | games/wanglanmei-ref/index.html(real 通道接 __refBootedReal,M1) |
就绪信号(stub 仍用 __refBooted) |
| SIZES 口径 | SIZES.md 增"游戏产物(引擎+包装层)"新表 |
文档(与插件增量分离) |
| 受控面 6 项契约 | api.d.ts:269/281/286/303 |
零改(硬约束) |
| harness driver | e2e-input.cdp.cjs real 通道范式切换(真触摸+轮询/选择器 #game-engine/等 __refBootedReal/同屏暖色判据);非「加断言」增量(M1/M2/M3) |
取证范式重写 |
P1 不触及:后端发布主链 / game-studio / feed / 生成管线(那些是 P2/P3,归母 spec)。
双通道全景(real / stub)
graph TB
URL{"?engine="}
URL -->|real(新增·引擎掌帧)| R0
URL -->|stub(保旧·回滚锚)| S0
subgraph R["real 通道"]
R0["entry import LJS<br/>引擎真入 ref-bundle ~540KB"] --> R1["setGLEnable(false)<br/>engineInit 五回调"]
R1 --> R2["createEngineCaps 建 engineFactory<br/>注入 createHostDevContext"]
R2 --> R3["game.update←gameUpdate<br/>game.render(mainContext)←gameRender<br/>mockNowMs=逻辑帧钟·废 RAF"]
R3 --> R4["验收:门①掌帧/②同屏/③call-ID/④真玩/⑦console"]
end
subgraph S["stub 通道"]
S0["不 import 引擎<br/>ref-bundle 197KB"] --> S1["prepareCanvas(#game) 2D<br/>浏览器 RAF + mockNowMs 墙钟"]
S1 --> S2["frame(dtReal) 原样<br/>drawFrame(g=#game)"]
S2 --> S3["验收:门⑤逐像素双开哈希一致"]
end
R4 -.过不了回滚.-> S3
7. P2 / P3 归并(O2 已拍)
- P2(泛化宿主:装载任意 GamePackage)合并进母 spec
2026-06-13-T1b-β引擎真接线与Runner-v2-execution.mdPhase D(O2 已拍)。P1 验实的装载契约 = P2 的产品化基底:母 spec Phase D 的"ref 经发布主链入 feed"升级为"engine-aware 包(按装载契约 +packageUrl加载,game-package.schema.json:66)入 feed 跑引擎真玩"。P2 不在本 spec 展开。 - P3(W-G1 生成游戏按同一装载契约产出) 归 W-G1 自身 spec:agent 写码于插件库、产装载契约 bundle、20 基准 bake-off。P1 的装载契约 IDL 是 P3 生成 agent 的唯一产出靶。
8. 待确认 / 风险与假设(诚实标注)
对抗复审结论(2026-06-13·deep·全程读真源码):无致命项。装载契约 IDL 五件(init/update/render/onInput/destroy)形态合理、与引擎五回调对齐准确(
host.js:883-887);additive 关系成立(受控面 6 项零改api.d.ts:269/281/286/303/405);双通道回滚有 A0 实证。4 重大项已全部纳入 execution 版钉死(real 就绪标记 M1 / driver 范式切换 M2 / 暖色阈值坐实 M3 / bundle 延后建 M4),均为「会致执行 agent 临场返工或门假绿/假红的硬装配问题」,不翻盘但必须在 execution 钉死。5 项不明假设逐条处置(落点改 game-runtime/src·缺省分叉显式·game 工厂硬独立·部署 git-clone-scratch·步骤0 降常规核对)。逐条裁决见 execution §12。 唯一 open item(非阻断):装载契约工件命名(见末条)。
缺省值分叉(复审 A2·显式声明此分叉有意为之):host-dev 缺省 engine=real(host.js:340),ref 缺省 engine=stub(main.js:82 play 模式走 stub 通道)。有意不统一:真玩取证显式带 &engine=real 更稳、stub 兜逐像素回归;但须知 P3 复制 ref 作模板时,缺省 stub=「新游戏默认不上引擎」是过渡现状,引擎是正路(boot 注入装载契约)——这点 P3 spec 须承接。
- [verified] 装载契约全仓不存在(
grep GameModule/装载契约/engineInit在contracts/+src/零命中);既有契约 =PluginContext(api.d.ts:269/281/286/303,6 受控面 +getEngine())+packageUrl(game-package.schema.json:66)。 - [verified]
engine-caps.js文件不存在,但内容已大半存在:makeEngineCaps闭包(host.js:197-318)已包装 particles/audio.synth/math 三面并已注入engineFactory(host.js:359);engine-math.js已独立成模块(host.js:47import)。→ 提升=搬运。 - [verified] ref 游戏层
core.update(main.js:621)/drawFrame(g)(main.js:648,g=prepareCanvas(#game))/RAF(main.js:668-691)/mockNowMs步进钟(main.js:618);createHostDevContext仅 4 键无engineFactory(main.js:112)→ 粒子今天全NOOP_HANDLE。 - [verified] real 通道引擎掌帧范式已在 host.js 跑通:
engineInit五回调(host.js:917)+setupAfterEngine(LJS.mainContext)(host.js:919)+ 就绪标记__hostBootedReal在 then 内 game 就绪后置(host.js:920,注释明告 CDP 须等它再驱动:851/931)+ bundle 在 then 内建(host.js:323-324/353-371/379-381)+ 输入挂 mainCanvas(host.js:536-538)+setGLEnable(false)(host.js:904)+ 双时钟window.__engine(host.js:840)+mainCanvas.id='game-engine'(host.js:830)。这些 host-dev 已踩并解决的坑(M1/M4),ref 必须继承(execution §12)。 - [verified] burst 粒子
colorStart缺省白{r:1,g:1,b:1,a:...}(toEngineSpec,particles-juice/impl.js:217),故引擎粒子像素门判brightHits/maxCh(青蓝口径已对引擎渲染失效,harness §6-2);游戏美术暖色门另判暖色域(M3,自palette.js:23-41)。 - [verified·复审降级] ref 接引擎 import 能入包——host-dev/entry.js 末行已 import 引擎且 real 门 6/6 已过(同 monorepo node_modules);常规构建
grep ParticleEmitter核对(A5),非阻断门。 - [inferred] ref ~540KB 不触 B1 入场券——基于 host-dev entry 544KB 实测 + gz 量级;P1 用
size.mjs实测游戏产物 gz 坐实。 - [assumption] "好玩基线 v2 五要素"精确判据不在本 spec 范围(P3 验收门事);P1 只证装载契约可让真游戏真跑在引擎上同屏可玩。
- [open item·留创始人·非阻断] 装载契约工件命名
game-host.d.ts(暂名,arc 称"游戏宿主装载契约");若创始人偏好其它名(如game-loadable.d.ts),执行版改名即可,形态/落点(game-runtime/src/core)不变。改名零成本,不阻断执行。