[P1][CR-B6/F5] 前后端边界:后端依赖 UI、前端直写引擎内部、globalThis 服务定位、import 环 #526
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
问题描述
e475c2e把 act-scene 拆成了scene/backend/和scene/frontend/,但依赖方向和写权限并没有随之分开:globalThis拿到 HUD 实例;结果是后端离不开浏览器和 UI,无法单独运行或测试。这也是 #520(状态双源)和 #523(模拟不确定)的结构性原因。
证据
1. 反向依赖:后端 → UI / 渲染
game → ui共 10 处。例如engine.ts从ui/inventory.ts引入金币上限规则:engine.ts:21。game → render共 5 处。scene/backend → ui共 2 处:skill-caster.ts:32-33。2.
globalThis服务定位globalThis读取 HUD 实例和前端回调,包括__d2webHudInstance、__d2PlayInventoryFullFeedback、__d2ShowNotification:skill-caster.ts:116、skill-caster.ts:128、skill-caster.ts:394-397。__d2*全局键。3. 后端输出"DOM 形状"的文案
castSkill的上下文参数里有一个status: { textContent }(skill-caster.ts:63)。skill-caster.ts中共有 62 处status.textContent = …。hudManager?.lang ?? getTblLang()决定(skill-caster.ts:115)。4. 前端直接写引擎内部
player.x/y、npcEntities、monsters、groundlevelId、isTownengine.dialog;NPC 治疗时直接写player.hp(this.engine as any).dialog、player.infernoChanneling等ui/world-panels.ts5. act-scene 仍然是一个巨型桶
runScene是一个 586 行的闭包(从 act-scene.ts:158 开始),通过十几个getX/setX回调共享可变的局部变量(act-scene.ts:214-249)。state。6. import 环
值级 import 构成了 6 个强连通分量。最大的一个由 17 个 drlg 文件组成;另外还有
skills.ts ↔ missile-engine ↔ combat-pipeline ↔ stat-list ↔ state-bus等。根因
这次拆分只移动了文件,没有定义接口。后端需要通知 UI、UI 需要改变世界时,没有一个约定好的通道,于是各处分别用 import、全局变量和直接赋值打通了。
修复指南
AGENTS.md,并用 lint 固化(见 #537):src/game/**和src/scene/backend/**不得 importui/、render/、scene/frontend/,也不得访问window、document和globalThis.__d2*。castSkill的status: { textContent }参数,以及所有globalThis.__d2*读取,都改为events.emit(...)。ground-items.ts里直接调用audioManager.playSfx的地方,也改为发出sfx事件。engine.loadLevel(spec):取代 pack-loader 里逐个字段改 terrain、player、monsters、ground、levelId、isTown 的代码。engine.execute(cmd):用于对话、治疗、交易、拾取等操作。它和 #520、#523 里的命令队列是同一个机制。private或readonly,由类型系统阻止直接赋值;删除所有(engine as any)。game/:金币上限(getInventoryGoldLimit)、itemToUiInventoryItem这类 item-bridge 逻辑从ui/移到game/,改为由 UI 依赖它们。runScene改为SceneController:getX/setX回调变成方法;start()/dispose(),与 #533 的监听器清理配合。import.meta.env.DEV下的一个类型化DebugApi。types.ts,然后开启import/no-cycle(见 #537)。验收标准
src/game/**和src/scene/backend/**中没有对ui/、render/、scene/frontend/的 import,也不访问globalThis.__d2*、window、document;对应的 lint 规则已开启。scene/frontend/**中没有对engine.*内部字段的直接赋值。skill-caster.ts中没有status.textContent。npm run typecheck0 error;npx vitest run全部通过。相关
SceneController的dispose与监听器清理。no-restricted-imports、import/no-cycle。WorldView解耦):方向一致,可以一起推进。