mirror of
https://github.com/motajs/template.git
synced 2026-10-18 21:00:19 +08:00
fix(04-03): revise plan per checker feedback (hook async/remove-legacy self-consistency)
This commit is contained in:
parent
d7f2e277d9
commit
c05fa322d0
@ -81,7 +81,7 @@ Phase 4 第三个增量(D-17 的适配半程)——**勇士本体适配:
|
||||
**大致解决方案:**
|
||||
- **绑定对象换成位置对象**:`MapHeroRenderer` 持有 `IHeroLocation`;坐标读 `IObjectMovable.x/.y`;朝向读 `getCurrentFaceDirection()`(构造期初始化)与 `mover.faceDirection`;移动方向读 `mover.moveDirection`;动画播放方向读 `mover.currAnimDir` 并改用 `ObjectAnimDirection`(R-03/R-05/R-06)。
|
||||
- **钩子改为订阅现有钩子**(D-21):在 `hero`(`IHeroLocationHooks`)与 `hero.mover`(`IObjectMoverHooks<IHeroLocation>`)上各注册一次 `MapHeroHook`,用 `load()` / `unload()` 管理(原 `controller` 字段拆为两个控制器字段)。渲染端实现现有钩子成员名,旧名全部删除;`onStepEnd` 成为逐格渲染的驱动点(此时 `tile` 坐标已更新),按 `ObjectMoveType` 分派到既有渲染内部方法。
|
||||
- **被动化**(D-20):`IMapHeroRenderer` 去掉「外部驱动渲染状态」的成员(`startMove` / `waitMoveEnd` / `stopMove` / `move` / `jumpTo` / `setPosition` / `turn` / `setHeroAnimateDirection`);这些方法退为渲染端内部实现,仅由钩子回调调用。
|
||||
- **被动化**(D-20):`IMapHeroRenderer` 去掉「外部驱动渲染状态」的成员(`startMove` / `waitMoveEnd` / `stopMove` / `move` / `jumpTo` / `setPosition` / `turn` / `setHeroAnimateDirection`;其中 `setHeroAnimateDirection` 因形参类型 `HeroAnimateDirection` 在数据端已不存在,在 Task 1 随类型改名一并删除,其余 7 个在 Task 2 删除);这些方法退为渲染端内部实现,仅由钩子回调调用。
|
||||
- **范围硬边界**:贴图 / 不透明度(D-18)、跟随者(D-22)、`action/move.ts` 与移动控制(D-19)、`core.*`(D-12)、裸函数(D-11)一律不动。
|
||||
|
||||
**执行前置关卡(AGENTS.md,第一个 block 点):** 本计划第一个执行步骤是 Task 0 —— 先向用户汇报「要解决的问题 / 大致解决方案(含逐钩子映射表)/ 拟新增或改写的成员命名清单 / 范围边界与禁令 / D-18 编译桥接的取舍」,然后**停下等待**用户明确回复「可以执行」四个字。收到该回复前,任何任务都不得执行,也不得派发执行子代理;无论触发方式或配置模式如何均不得自动放行。故本计划 `autonomous: false`。
|
||||
@ -106,7 +106,7 @@ Output: 三个在范围文件的适配改动(原子提交)+ 会话内可复
|
||||
| CONTEXT | D-17 | 下一步=勇士移动适配(先探索再适配) | 04-03 | COVERED | 04-02 完成探索;本计划即其适配实施(勇士本体部分) |
|
||||
| CONTEXT | D-18 | `HeroRendering` 暂不处理,用户先改数据端 | 04-03 | COVERED(排除 + 编译桥接) | 贴图 / 不透明度成员逐字保留;`hero.image` 只做最小编译桥接,不重设来源;Task 0 汇报该取舍 |
|
||||
| CONTEXT | D-19 | 移动控制由用户手动修改 | 04-03 | COVERED(排除) | `action/move.ts` 与移动控制 API 不在 `files_modified`;prohibitions 明列 |
|
||||
| CONTEXT | D-20 | 勇士渲染完全被动、旧驱动接口删除 | 04-03 | COVERED | Task 2 从 `IMapHeroRenderer` 删除 8 个外部驱动成员,改为钩子驱动 |
|
||||
| CONTEXT | D-20 | 勇士渲染完全被动、旧驱动接口删除 | 04-03 | COVERED | `IMapHeroRenderer` 删除 8 个外部驱动成员(`setHeroAnimateDirection` 随 Task 1 的类型改名一并删除,其余 7 个由 Task 2 删除),改为钩子驱动 |
|
||||
| CONTEXT | D-21 | 走现有 `IObjectMoverHooks` / `IHeroLocationHooks`,不新增数据端接口 | 04-03 | COVERED | Task 1/2 的两次 `addHook` 注册与逐钩子映射即本条的落地 |
|
||||
| CONTEXT | D-22 | 跟随者暂缓 | 04-03 | COVERED(排除) | 跟随者成员与钩子方法逐字保留、不删除不改写 |
|
||||
| CONTEXT | D-10 | `HeroRendering` 删除、渲染状态存储放渲染端 | 04-03 | COVERED(一致性依据) | D-20 的被动化与 D-18 的保留范围保持一致;贴图来源的最终归属留给 D-18 增量 |
|
||||
@ -158,9 +158,9 @@ Output: 三个在范围文件的适配改动(原子提交)+ 会话内可复
|
||||
|
||||
① **要解决的问题**:渲染端勇士本体仍按已删除的 `IHeroMoveController` 模型编写(`hero.direction` / `hero.image` / `IHeroMoveControllerHooks` 的 `onSetPosition` 等),数据端现行接口无这些成员,全靠 `// @ts-expect-error 需要重构` 压着(`#04-02-R-01/R-03/R-04/R-05/R-06/R-12`)。不改就会一直停在「编译靠压制、契约对不上」。
|
||||
|
||||
② **大致解决方案(三个文件)**:`manager.ts` 与 `types.ts` 的勇士键 / 参数类型由 `IHeroMoveController` 改为 `IHeroLocation`;`hero.ts` 构造器绑定 `IHeroLocation`(坐标 `x`/`y`、朝向 `getCurrentFaceDirection()`、动画方向 `ObjectAnimDirection` + `mover.currAnimDir`),在 `hero`(`IHeroLocationHooks`)与 `hero.mover`(`IObjectMoverHooks<IHeroLocation>`)上各 `addHook` 一次,`MapHeroHook` 改为实现现有钩子成员名;`IMapHeroRenderer` 按 D-20 去掉 8 个外部驱动成员(`startMove` / `waitMoveEnd` / `stopMove` / `move` / `jumpTo` / `setPosition` / `turn` / `setHeroAnimateDirection`)。**逐钩子映射表须逐行汇报**:数据端钩子 → 触发点(`file:line`)→ 渲染端动作。核心几条:`IHeroLocationHooks.onSetPos(x, y)`(`data-base/src/hero/location.ts:59-63`)→ 非移动中时 `setPosition(x, y)`,移动中交给 `onStepEnd`;`IObjectMoverHooks.onMoveStart` → `startMove()`;`onMoveEnd` → `await waitMoveEnd()`;`onStepEnd(code, step, tile, mover)`(坐标已更新,`data-common/src/common/mover.ts:674-678`)→ 按 `step.type`(`ObjectMoveType`)分派:`Dir`/`DirFace` → `move(step.move, mover.currentSpeed)`(`DirFace` 另 `turn(step.face)`)、`Special` → `move(mover.moveDirection, mover.currentSpeed)`、`Face` → `turn(step.value)`、`Teleport` → `setPosition(tile.x, tile.y)`、`Jump` → `jumpTo(tile.x, tile.y, mover.currentSpeed, false)`、`AnimDir`/`Speed` → 不处理;动画方向统一在 `onStepEnd` 取 `mover.currAnimDir`;`onSetFaceDir` → `turn(dir)`;`onSetPos`(mover 级)→ `setPosition(x, y)`;`onSetMoveDir` / `onStepStart` → 不处理(并说明理由)。
|
||||
② **大致解决方案(三个文件)**:`manager.ts` 与 `types.ts` 的勇士键 / 参数类型由 `IHeroMoveController` 改为 `IHeroLocation`;`hero.ts` 构造器绑定 `IHeroLocation`(坐标 `x`/`y`、朝向 `getCurrentFaceDirection()`、动画方向 `ObjectAnimDirection` + `mover.currAnimDir`),在 `hero`(`IHeroLocationHooks`)与 `hero.mover`(`IObjectMoverHooks<IHeroLocation>`)上各 `addHook` 一次,`MapHeroHook` 改为实现现有钩子成员名;`IMapHeroRenderer` 按 D-20 去掉 8 个外部驱动成员(`startMove` / `waitMoveEnd` / `stopMove` / `move` / `jumpTo` / `setPosition` / `turn` / `setHeroAnimateDirection`;其中 `setHeroAnimateDirection` 因形参类型 `HeroAnimateDirection` 已不存在,在 Task 1 连同其 jsDoc 一并删除,其余 7 个在 Task 2 删除)。**逐钩子映射表须逐行汇报**:数据端钩子 → 触发点(`file:line`)→ 渲染端动作。核心几条:`IHeroLocationHooks.onSetPos(x, y)`(`data-base/src/hero/location.ts:59-63`)→ 非移动中时 `setPosition(x, y)`,移动中交给 `onStepEnd`;`IObjectMoverHooks.onMoveStart` → `startMove()`;`onMoveEnd` → `await waitMoveEnd()`;`onStepEnd(code, step, tile, mover)`(坐标已更新,`data-common/src/common/mover.ts:674-678`)→ 按 `step.type`(`ObjectMoveType`)分派:`Dir`/`DirFace` → `move(step.move, mover.currentSpeed)`(`DirFace` 另 `turn(step.face)`)、`Special` → `move(mover.moveDirection, mover.currentSpeed)`、`Face` → `turn(step.value)`、`Teleport` → `setPosition(tile.x, tile.y)`、`Jump` → `jumpTo(tile.x, tile.y, mover.currentSpeed, false)`、`AnimDir`/`Speed` → 不处理;动画方向统一在 `onStepEnd` 取 `mover.currAnimDir`;`onSetFaceDir` → `turn(dir)`;`onSetPos`(mover 级)→ `setPosition(x, y)`;`onSetMoveDir` / `onStepStart` → 不处理(并说明理由)。
|
||||
|
||||
③ **成员命名清单(须用户同意,AGENTS.md 命名规则)**:**新增**渲染端字段 `locationController`(`IHookController<IHeroLocationHooks>`)与 `moverController`(`IHookController<IObjectMoverHooks<IHeroLocation>>`)——取代原单一 `controller` 字段;**不新增任何类**(沿用既有 `MapHeroHook` 类名);**删除**旧钩子方法名 `onSetPosition` / `onStartMove` / `onMoveHero` / `onEndMove` / `onJumpHero` / `onTurnHero` 与 `IMapHeroRenderer` 的 8 个驱动成员(连同其配套 jsDoc,属删除代码而非改写注释);**逐字保留** `setImage` / `setAlpha` / `setFollowerAlpha` / `onSetImage` / `onSetAlpha` / `onSetFollowerAlpha` 与跟随者族(D-18 / D-22)。备选命名(如用户不同意 `locationController` / `moverController`)请用户当场指定。
|
||||
③ **成员命名清单(须用户同意,AGENTS.md 命名规则)**:**新增**渲染端字段 `locationController`(`IHookController<IHeroLocationHooks>`)与 `moverController`(`IHookController<IObjectMoverHooks<IHeroLocation>>`)——取代原单一 `controller` 字段;**不新增任何类**(沿用既有 `MapHeroHook` 类名);**删除**旧钩子方法名 `onSetPosition` / `onStartMove` / `onMoveHero` / `onEndMove` / `onJumpHero` / `onTurnHero`(**Task 1 即删除,不留存为类上的多余方法**)与 `IMapHeroRenderer` 的 8 个驱动成员(连同其配套 jsDoc,属删除代码而非改写注释;其中 `setHeroAnimateDirection` 在 Task 1 删除,其余 7 个在 Task 2 删除);**新增**的钩子方法名 `onSetPos` / `onMoveStart` / `onMoveEnd` / `onStepEnd` / `onSetFaceDir` 逐字取自数据端现有钩子接口成员名(D-21,非自创命名),`onStepEnd` 的未使用首参按项目惯例命名为 `_code`(eslint `args: 'all'` + `argsIgnorePattern: '^_'`),一并请用户确认;**逐字保留** `setImage` / `setAlpha` / `setFollowerAlpha` / `onSetImage` / `onSetAlpha` / `onSetFollowerAlpha` 与跟随者族(D-18 / D-22)。备选命名(如用户不同意 `locationController` / `moverController`)请用户当场指定。
|
||||
|
||||
④ **D-18 编译桥接的取舍(须用户裁定)**:`hero` 类型改为 `IHeroLocation` 后,`addHeroMoving` 内读取贴图别名的 `hero.image`(`hero.ts:115,119,121`)失去数据端对位。本计划主张**只做最小编译桥接**:把该读取收敛为一处局部变量、用项目既有 `// @ts-expect-error 需要重构` 惯用法标注,运行分支与语义保持不变(`undefined` → 既有 `logger.warn(88)` 分支),**不重新设计贴图来源**(贴图来源与 `IHeroRendering` 属 D-18,等用户先改数据端)。请用户确认该桥接,或指定其它处理方式。
|
||||
|
||||
@ -197,8 +197,7 @@ Output: 三个在范围文件的适配改动(原子提交)+ 会话内可复
|
||||
</options>
|
||||
<resume-signal>回复「可以执行」四个字(如需改名或改桥接,请在回复中一并给出),或给出修订意见</resume-signal>
|
||||
<verify>
|
||||
<human-check>用户在对话中明确回复「可以执行」四个字(人工核对用户回复原文;本关卡为人工关卡,无自动命令,失败语义写在 action ⑦/⑧ 与 acceptance_criteria 中)</human-check>
|
||||
<fails_when>用户回复的是修订意见、改名要求未获确认、或未回复即继续 —— 必须停止执行,不派发任何执行子代理</fails_when>
|
||||
<human-check>用户在对话中明确回复「可以执行」四个字(人工核对用户回复原文;本关卡为人工关卡,无可运行的 `<automated>` 命令,故不携带 `<fails_when>`;失败语义(用户未回复或回复其它任何内容即视为未通过本关卡、必须立即停止执行、不派发任何执行子代理、保持只读且不写任何文件,直到用户明确回复「可以执行」四个字方可继续)完整写在 Task 0 的 action ⑦/⑧ 与 acceptance_criteria 中)</human-check>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- 用户回复中明确包含「可以执行」四个字
|
||||
@ -229,15 +228,15 @@ Output: 三个在范围文件的适配改动(原子提交)+ 会话内可复
|
||||
(0c) **类型门禁基线**:执行 `pnpm exec vue-tsc --noEmit`(整仓会以非 0 退出属预期——规划时有 122 条诊断)并记录 `client-modules` 的命中行;规划时恰为 2 条、与勇士移动无关:`packages-user/client-modules/src/client.ts(66,9): error TS2554: Expected 1 arguments, but got 0.` 与 `packages-user/client-modules/src/render/ui/load.tsx(77,31): error TS2504: Type 'ITaskManager' must have a 'Symbol.asyncIterator]()' method that returns an async iterator.`。同时确认三个在范围文件**当前 0 条诊断**。把这两条原样抄入 `04-03-SUMMARY.md` 的「类型门禁基线」段;**若与记录不一致,停止并汇报**(说明用户并发改动改变了基线,不得静默调整门禁)。
|
||||
(0d) 建立 `04-03-SUMMARY.md` 骨架(含上面三段 + 后续任务要填的空节),保持 CRLF。
|
||||
(1) **`manager.ts`(绑定层)**:删除首行 `// @ts-expect-error 需要重构`,把 `import { IHeroMoveController } from '@user/data-base'` 改为 `import { IHeroLocation, IMapLayer } from '@user/data-base'`(合并第三行的 `IMapLayer` import,避免重复 import 语句;若 lint 要求分行则按 lint 结果排布);`readonly heroMap: Map<IHeroLocation, IMapHeroRenderer>`;`addHero(state: IHeroLocation, layer: IMapLayer)`;`removeHero(state: IHeroLocation)`。`addDoor` / `removeDoor` / `addText` / `removeText` / `destroy` 一字不改。
|
||||
(2) **`types.ts`(契约层,本任务只改绑定类型,不动 D-20 裁剪)**:从 `@user/data-common` 的 import 中删除 `HeroAnimateDirection` 与 `IHeroMoveController`(连带其两行 `// @ts-expect-error 需要重构` 标记),改为从 `@user/data-base` 导入 `IHeroLocation`(与既有 `IMapLayer` 合并);`IMapExtensionManager.heroMap: Map<IHeroLocation, IMapHeroRenderer>`、`addHero(state: IHeroLocation, layer: IMapLayer)`、`removeHero(state: IHeroLocation)`;`Map<` / `addHero` / `removeHero` 的 jsDoc **不改写**(参数名与含义不变)。本任务**不动** `IMapHeroRenderer`(其 8 个驱动成员的删除在 Task 2)。
|
||||
(2) **`types.ts`(契约层:绑定类型 + 删除 `setHeroAnimateDirection` 声明)**:从 `@user/data-common` 的 import 中删除 `HeroAnimateDirection` 与 `IHeroMoveController`(连带其两行 `// @ts-expect-error 需要重构` 标记;删除后该 import 仅剩 `FaceDirection`,**不需要任何替代类型**),改为从 `@user/data-base` 导入 `IHeroLocation`(与既有 `IMapLayer` 合并);`IMapExtensionManager.heroMap: Map<IHeroLocation, IMapHeroRenderer>`、`addHero(state: IHeroLocation, layer: IMapLayer)`、`removeHero(state: IHeroLocation)`;**删除 `IMapHeroRenderer.setHeroAnimateDirection` 的成员声明及其配套 jsDoc**(原 `:143-147`;其形参类型 `HeroAnimateDirection` 在数据端已不存在,无法保留——若只删 import 而不删该成员,`types.ts` 会残留悬空引用并触发 TS2304):该成员本任务即删除,其实现方法 `MapHeroRenderer.setHeroAnimateDirection` 保留在类上(见 (3f));`IMapHeroRenderer` 的**其余 7 个驱动成员**(`setPosition` / `startMove` / `waitMoveEnd` / `stopMove` / `move` / `jumpTo` / `turn`)连同其 jsDoc 在 Task 2 删除,本任务不动。`Map<` / `addHero` / `removeHero` 的 jsDoc **不改写**(参数名与含义不变)。
|
||||
(3) **`hero.ts` import 与绑定(tracer 主路径)**:
|
||||
(3a) import 改造:`@user/data-common` 侧删除 `HeroAnimateDirection` / `IHeroMoveController` / `IHeroMoveControllerHooks`(连带 3 行 `// @ts-expect-error 需要重构` 标记),新增 `ObjectAnimDirection`、`IObjectMover`、`IObjectMoverHooks`、`ObjectMoveStep`、`ObjectMoveType`、`ObjectSpecialStep`;`@user/data-base` 侧把 `import { IMapLayer }` 扩为 `import { IHeroLocation, IHeroLocationHooks, IMapLayer }`(`IHeroLocation` / `IHeroLocationHooks` / `IHeroMover` 均可经该 barrel 取得,见 `data-base/src/hero/index.ts:10` 与 `data-base/src/index.ts:3`)。
|
||||
(3b) 实体类型:`HeroRenderEntity.animateDirection` 由 `HeroAnimateDirection` 改为 `ObjectAnimDirection`(`:53`);`new MapHeroRenderer(...)` 内的默认值 `HeroAnimateDirection.Forward` → `ObjectAnimDirection.Forward`(`:97`)。
|
||||
(3a) import 改造(**只在本任务内引入本任务用得到的名字**:项目 eslint 把 `@typescript-eslint/no-unused-vars` 设为 `error` 且 `args: 'all'`,未使用的 import 会直接报错,`--fix` 也不会删除未使用 import;反之 Task 2 也不得保留只在 Task 1 用过的名字):`@user/data-common` 侧删除 `HeroAnimateDirection` / `IHeroMoveController` / `IHeroMoveControllerHooks`(连带 3 行 `// @ts-expect-error 需要重构` 标记),新增 `ObjectAnimDirection`(本任务即消费:`:53` / `:97` / `:170` / `:372` 四处)与 `IObjectMoverHooks`(本任务即消费:`moverController` 字段类型);**不要**在本任务引入 `IObjectMover` / `ObjectMoveStep` / `ObjectMoveType`(本任务无使用点,留到 Task 2 首次使用时再引入);**不要**引入 `ObjectSpecialStep`(两个任务都不需要:`Special` 步的移动方向已由数据端 `ObjectMover.prepareStep` 写入 `mover.moveDirection`,渲染端无需读取 `step.direction`)。`@user/data-base` 侧把 `import { IMapLayer }` 扩为 `import { IHeroLocation, IHeroLocationHooks, IMapLayer }`(`IHeroLocation` / `IHeroLocationHooks` / `IHeroMover` 均可经该 barrel 取得,见 `data-base/src/hero/index.ts:10` 与 `data-base/src/index.ts:3`)。
|
||||
(3b) 实体类型与**全部取值点**:`HeroRenderEntity.animateDirection` 由 `HeroAnimateDirection` 改为 `ObjectAnimDirection`(`:53`);两处实体初始化的默认值 `HeroAnimateDirection.Forward` → `ObjectAnimDirection.Forward`(`:97` 构造器、`:372` `addFollower`);`tick` 内的播放方向比较 `v.animateDirection === HeroAnimateDirection.Forward` → `ObjectAnimDirection.Forward`(`:170`)。**四处取值点必须全部改到**,否则改名门禁(三文件不得出现 `HeroAnimateDirection`)与 scoped 类型门禁(该名字已从 import 移除,任何残留即 TS2304)都会失败。
|
||||
(3c) 构造器:`readonly hero: IHeroMoveController` → `readonly hero: IHeroLocation`(`:79`);`direction: hero.direction` → `direction: hero.getCurrentFaceDirection()`(`:89`);钩子注册由单一 `controller` 改为**两个控制器字段**:`readonly locationController: IHookController<IHeroLocationHooks>` 与 `readonly moverController: IHookController<IObjectMoverHooks<IHeroLocation>>`(替换原 `readonly controller: IHookController<IHeroMoveControllerHooks>` 字段,`:61`);构造体内 `const hook = new MapHeroHook(this); this.locationController = hero.addHook(hook); this.locationController.load(); this.moverController = hero.mover.addHook(hook); this.moverController.load();`(同一 hook 实例注册到两个 hookable,`Hookable.addHook` 按 hookable 实例分别存储,见 `packages/common/src/hook.ts:24-31`);`destroy()`(`:452-454`)改为 `this.locationController.unload(); this.moverController.unload();`。
|
||||
(3d) `addHeroMoving`(`:110-132`):参数 `hero: IHeroMoveController` → `IHeroLocation`;`degradeFace(hero.direction)` → `degradeFace(hero.getCurrentFaceDirection())`(`:125`);`hero.image` 的三处读取(`:115,119,121`)按 Task 0 确认的 **D-18 最小编译桥接**处理——收敛为一处局部读取(如 `const imageAlias = hero.image;`)并在其正上方加一行**新增**注释 `// @ts-expect-error 需要重构(贴图别名来源属 D-18,待用户先改数据端后处理)`,其后三处改用 `imageAlias`;分支结构与既有 `logger.warn(88/89)` 行为保持不变;**不得**改写既有注释、不得重设贴图来源。
|
||||
(3e) `setImage`(`:191-196`):只把内部的 `degradeFace(this.hero.direction)` 改为 `degradeFace(this.hero.getCurrentFaceDirection())`(同一朝向读取口径的编译修复),其余一字不改(D-18:贴图语义不动)。
|
||||
(3f) `setHeroAnimateDirection(direction: HeroAnimateDirection)`(`:437-439`)→ 形参类型改 `ObjectAnimDirection`;本任务保留其在 `IMapHeroRenderer` 中的声明(Task 2 再按 D-20 删除)。
|
||||
(3g) **`MapHeroHook` 重接(tracer 只贯通一条通路)**:类声明由 `implements Partial<IHeroMoveControllerHooks>` 改为 `implements Partial<IHeroLocationHooks & IObjectMoverHooks<IHeroLocation>>`(`:457`);把 `onSetPosition(x, y)`(`:469-471`)改为 `onSetPos(x: number, y: number): void`,实现「移动之外的直接定位才立刻同步、移动中的逐格定位交给 `onStepEnd`」:当 `this.hero.hero.mover.moving` 为 `true` 时直接 return,否则 `this.hero.setPosition(x, y)`;**其余旧命名方法本任务先保留为类上的多余方法(不影响实现 `Partial<...>` 的可赋值性),Task 2 再整体替换**——但不得新增任何旧命名方法。
|
||||
(3f) `MapHeroRenderer.setHeroAnimateDirection(direction: HeroAnimateDirection)`(`:437-439`)→ 形参类型改 `ObjectAnimDirection`,**保留为类上的内部实现方法**(本任务暂无调用点,Task 2 的 `onStepEnd` 钩子回调会调用它);其 `IMapHeroRenderer` 接口声明已在步骤 (2) 按 D-20 删除,本任务不得再保留接口侧的该成员。
|
||||
(3g) **`MapHeroHook` 重接(tracer 只贯通一条通路,旧名在本任务全部删除)**:类声明由 `implements Partial<IHeroMoveControllerHooks>` 改为 `implements Partial<IHeroLocationHooks & IObjectMoverHooks<IHeroLocation>>`(`:457`);把 `onSetPosition(x, y)`(`:469-471`)改为 `onSetPos(x: number, y: number): void`,实现「移动之外的直接定位才立刻同步、移动中的逐格定位交给 `onStepEnd`」:当 `this.hero.hero.mover.moving` 为 `true` 时直接 return,否则 `this.hero.setPosition(x, y)`;**同时删除**其余 5 个旧命名方法 `onTurnHero`(`:473-475`)、`onStartMove`(`:477-479`)、`onMoveHero`(`:481-483`)、`onEndMove`(`:485-487`)、`onJumpHero`(`:489-496`)——Task 2 再按映射表补上现有钩子成员名(`onMoveStart` / `onMoveEnd` / `onStepEnd` / `onSetFaceDir`);**本任务不得以「类上的多余方法」形式留存任何旧命名方法**,因为本任务的静态改名门禁(见 `<verify>`)与 acceptance 都要求三文件不再出现这些名字。D-18 / D-22 的保留方法(`onSetImage` / `onSetAlpha` / `onSetFollowerAlpha` / 跟随者三方法)本任务一字不改。
|
||||
(3h) 全程保持文件 CRLF;改完执行 `pnpm exec eslint --fix` 对三个文件,再 `pnpm exec eslint` 必须 0 错误。
|
||||
(4) **提交**:本任务改动是整体适配的中间态,**不单独提交**;Task 2 完成后再一次性原子提交(见 Task 2 步骤 (5))。若执行环境强制每任务提交,则提交信息为 `refactor(04-03): rebind hero renderer to IHeroLocation`,且必须与 Task 2 的提交在本次执行内连续完成。
|
||||
</action>
|
||||
@ -254,9 +253,10 @@ Output: 三个在范围文件的适配改动(原子提交)+ 会话内可复
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `manager.ts` 与 `types.ts` 的 `heroMap` / `addHero` / `removeHero` 均为 `IHeroLocation`,`manager.ts` 首行的 `// @ts-expect-error 需要重构` 已删除,且不再 import `IHeroMoveController`
|
||||
- `hero.ts` 的构造器参数为 `IHeroLocation`,构造期朝向取自 `hero.getCurrentFaceDirection()`;`HeroRenderEntity.animateDirection` 与默认值为 `ObjectAnimDirection`
|
||||
- `types.ts` 的 `IMapHeroRenderer` 不再声明 `setHeroAnimateDirection`(其形参类型 `HeroAnimateDirection` 已随类型改名删除,文件内无任何悬空引用);该接口的其余 7 个驱动成员与 D-18 / D-22 成员本任务未动
|
||||
- `hero.ts` 的构造器参数为 `IHeroLocation`,构造期朝向取自 `hero.getCurrentFaceDirection()`;`HeroRenderEntity.animateDirection` 的声明(`:53`)、两处初始化默认值(`:97` / `:372`)与 `tick` 内的比较(`:170`)均为 `ObjectAnimDirection`
|
||||
- `hero.ts` 同时存在 `hero.addHook(` 与 `hero.mover.addHook(`,并存在 `locationController` / `moverController` 两个字段;`destroy()` 对两者都 `unload()`
|
||||
- `MapHeroHook` 声明为 `Partial<IHeroLocationHooks & IObjectMoverHooks<IHeroLocation>>`,且已实现 `onSetPos`(旧 `onSetPosition` 已不存在)
|
||||
- `MapHeroHook` 声明为 `Partial<IHeroLocationHooks & IObjectMoverHooks<IHeroLocation>>`,且已实现 `onSetPos`;类上**不再存在任何旧命名方法**(`onSetPosition` / `onStartMove` / `onMoveHero` / `onEndMove` / `onJumpHero` / `onTurnHero` 本任务即全部删除,不留存为多余方法;Task 2 再按映射表补上现有钩子成员名)
|
||||
- 三个文件不再出现 `IHeroMoveController` / `IHeroMoveControllerHooks` / `HeroAnimateDirection` / `onSetPosition` / `onStartMove` / `onMoveHero` / `onEndMove` / `onJumpHero` / `onTurnHero`
|
||||
- `hero.ts` 中 `hero.image` 的读取已收敛为一处(带新增的 `// @ts-expect-error 需要重构(…D-18…)` 标注),既有 `logger.warn(88/89/90)` 分支结构未变;`setImage` / `setAlpha` / 跟随者族成员未被删除
|
||||
- `04-03-SUMMARY.md` 含「执行前核对」(步骤 0a 七条,每条带 `file:line`)、「执行前基线」(porcelain 条目 + `基线摘要 sha256`)与「类型门禁基线」(两条 client-modules 诊断原样)三段,全文 CRLF
|
||||
@ -266,28 +266,30 @@ Output: 三个在范围文件的适配改动(原子提交)+ 会话内可复
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2:逐钩子映射落地 + D-20 契约裁剪 —— 旧钩子方法名整体替换为现有钩子成员名;`IMapHeroRenderer` 去掉 8 个外部驱动成员(D-18 / D-22 成员逐字保留)</name>
|
||||
<name>Task 2:逐钩子映射落地 + D-20 契约裁剪收口 —— 现有钩子成员名(异步钩子以 `async` 实现)全部接上;`IMapHeroRenderer` 删除其余 7 个外部驱动成员(第 8 个 `setHeroAnimateDirection` 已在 Task 1 删除;D-18 / D-22 成员逐字保留)</name>
|
||||
<files>packages-user/client-modules/src/render/map/extension/hero.ts, packages-user/client-modules/src/render/map/extension/types.ts</files>
|
||||
<read_first>
|
||||
- packages-user/client-modules/src/render/map/extension/hero.ts(Task 1 产出的现状全文;重点 `MapHeroHook` 与 `IMapHeroRenderer` 的实现方法)
|
||||
- packages-user/client-modules/src/render/map/extension/types.ts:63-159(`IMapHeroRenderer` 当前 17 个成员)
|
||||
- packages-user/client-modules/src/render/map/extension/types.ts:63-159(`IMapHeroRenderer` 成员清单;Task 1 之后剩 16 个,本任务再删 7 个)
|
||||
- packages-user/data-common/src/common/mover.ts:166-233(钩子参数形态)、:641-687(`moveProgress` 的钩子时序:`onMoveStart` → 每步 `prepareStep` → `onStepStart`(坐标未变)→ `tile.setPos` → `onStepEnd`(坐标已更新)→ `onMoveEnd`)
|
||||
- packages-user/data-common/src/common/mover.ts:40-45,14-31,33-38(`ObjectAnimDirection` / `ObjectMoveType` / `ObjectSpecialStep` 成员名)
|
||||
- packages-user/data-base/src/hero/mover.ts:147-280(`HeroMover` 的 `onStepStart` / `onStepEnd` 与 `HeroMoveCode`,用于确认渲染侧读到的 `code` / `step` 语义)
|
||||
- .planning/phases/04-render-adaptation/04-CONTEXT.md(D-18 / D-19 / D-20 / D-21 / D-22)
|
||||
</read_first>
|
||||
<action>
|
||||
(1) **`MapHeroHook` 逐钩子映射落地(D-21:只接现有钩子,旧名全删)**。把 Task 1 保留的旧命名方法整体替换为现有钩子成员名,按下列映射实现(每条都要能对上数据端触发点):
|
||||
(0) **`hero.ts` import 补齐(只补本任务首次使用的名字)**:在 `@user/data-common` 的 import 中加入 `IObjectMover`(`onStepEnd` 的 `mover` 形参类型)、`ObjectMoveStep`(`onStepEnd` 的 `step` 形参类型)、`ObjectMoveType`(`step.type` 的 `case` 标签,按值使用);三者在本任务均有消费点,故在本任务引入(Task 1 不引入,见 Task 1 步骤 (3a))。**不要**引入 `ObjectSpecialStep`(本任务无使用点,会让 eslint `no-unused-vars` 报错)。
|
||||
|
||||
(1) **`MapHeroHook` 逐钩子映射落地(D-21:只接现有钩子,旧名全删;异步钩子必须 `async`)**。按下列映射实现(每条都要能对上数据端触发点)。**返回类型硬约束**:`IObjectMoverHooks` 的 `onMoveStart` / `onMoveEnd` / `onStepStart` / `onStepEnd` 在数据端均声明为 `(...) => Promise<void>`(`data-common/src/common/mover.ts:172,179,188-193,202-207`),实现方法若声明成 `: void` 会触发 TS2416「Type 'void' is not assignable to type 'Promise<void>'」;因此下面这三个(`onMoveStart` / `onMoveEnd` / `onStepEnd`)必须写成 `async` 方法并返回 `Promise<void>`(`async` 下各分支无需都写成 `return`,函数整体仍是 `Promise<void>`)。`onSetPos` / `onSetFaceDir` / `onSetMoveDir` 在数据端是同步 `void`,实现同样保持 `void`。`onStepEnd` 的首参 `code` 在本实现中不使用,必须命名为 `_code`(eslint 为 `args: 'all'` + `argsIgnorePattern: '^_'`,未使用的形参即使不在末尾也会报错,`_` 前缀是项目既有惯例):
|
||||
- `onSetPos(x: number, y: number): void`:**移动之外的直接定位**才立刻同步——当 `this.hero.hero.mover.moving` 为 `true` 时直接 return(移动中的逐格 `tile.setPos` 会触发本条,交给 `onStepEnd` 做动画),否则 `this.hero.setPosition(x, y)`。触发点:`HeroLocation.setPos`(`data-base/src/hero/location.ts:59-63`);移动中的逐格调用见 `data-common/src/common/mover.ts:671-673`。
|
||||
- `onMoveStart(): void` → `this.hero.startMove()`;触发点 `mover.ts:651-656`。
|
||||
- `onMoveEnd(): Promise<void>` → `return this.hero.waitMoveEnd()`;触发点 `mover.ts:682-686`。
|
||||
- `onStepEnd(code: number, step: Readonly<ObjectMoveStep>, tile: IHeroLocation, mover: IObjectMover<IHeroLocation>): Promise<void>`:**逐格渲染的唯一驱动点**(此时 `tile` 坐标已更新,见 `mover.ts:669-678`)。先 `this.hero.setHeroAnimateDirection(mover.currAnimDir)`(动画播放方向统一取自数据端 `currAnimDir`,即 R-03 的 `ObjectAnimDirection` 落地),再按 `step.type` 分派:`ObjectMoveType.Dir` → `return this.hero.move(step.move, mover.currentSpeed)`;`ObjectMoveType.DirFace` → `this.hero.turn(step.face); return this.hero.move(step.move, mover.currentSpeed)`;`ObjectMoveType.Special` → `return this.hero.move(mover.moveDirection, mover.currentSpeed)`(前进/后退的移动方向已由 `ObjectMover.prepareStep` 写入 `moveDirection`,见 `mover.ts:500-512`,无需自行取反);`ObjectMoveType.Face` → `this.hero.turn(step.value)`;`ObjectMoveType.Teleport` → `this.hero.setPosition(tile.x, tile.y)`;`ObjectMoveType.Jump` → `return this.hero.jumpTo(tile.x, tile.y, mover.currentSpeed, false)`;`ObjectMoveType.AnimDir` / `ObjectMoveType.Speed` → 不处理(动画方向已在 `currAnimDir` 中体现,速度由数据端消费)。
|
||||
- `async onMoveStart(): Promise<void>` → `this.hero.startMove()`;触发点 `mover.ts:651-656`。
|
||||
- `async onMoveEnd(): Promise<void>` → `await this.hero.waitMoveEnd()`;触发点 `mover.ts:682-686`。
|
||||
- `async onStepEnd(_code: number, step: Readonly<ObjectMoveStep>, tile: IHeroLocation, mover: IObjectMover<IHeroLocation>): Promise<void>`:**逐格渲染的唯一驱动点**(此时 `tile` 坐标已更新,见 `mover.ts:669-678`)。先 `this.hero.setHeroAnimateDirection(mover.currAnimDir)`(动画播放方向统一取自数据端 `currAnimDir`,即 R-03 的 `ObjectAnimDirection` 落地),再按 `step.type` 分派:`ObjectMoveType.Dir` → `return this.hero.move(step.move, mover.currentSpeed)`;`ObjectMoveType.DirFace` → `this.hero.turn(step.face); return this.hero.move(step.move, mover.currentSpeed)`;`ObjectMoveType.Special` → `return this.hero.move(mover.moveDirection, mover.currentSpeed)`(前进/后退的移动方向已由 `ObjectMover.prepareStep` 写入 `moveDirection`,见 `mover.ts:500-512`,无需自行取反);`ObjectMoveType.Face` → `this.hero.turn(step.value)`;`ObjectMoveType.Teleport` → `this.hero.setPosition(tile.x, tile.y)`;`ObjectMoveType.Jump` → `return this.hero.jumpTo(tile.x, tile.y, mover.currentSpeed, false)`;`ObjectMoveType.AnimDir` / `ObjectMoveType.Speed` → 不处理(动画方向已在 `currAnimDir` 中体现,速度由数据端消费)。本方法为 `async`,故 `Face` / `Teleport` 这类没有返回值的分支无需写成 `return`(若写成同步方法则必须显式 `return Promise.resolve()` 才能满足 `Promise<void>`,因此这里统一用 `async`)。
|
||||
- `onSetFaceDir(dir: FaceDirection): void` → `this.hero.turn(dir)`;触发点 `mover.ts:529-534`。
|
||||
- `onSetPos`(mover 级四参调用)与 location 级两参调用共用同一个两参方法:JS 会忽略多余实参,本方法的「移动中 return」守卫同时覆盖两条触发路径。
|
||||
- `onSetPos`(mover 级四参调用)与 location 级两参调用共用同一个两参方法:JS 会忽略多余实参,本方法的「移动中 return」守卫同时覆盖两条触发路径;该方法保持 `void` 返回(`IHeroLocationHooks.onSetPos` 与 `IObjectMoverHooks.onSetPos` 在数据端都是 `void`)。
|
||||
- **不实现**(在 `04-03-SUMMARY.md` 写明理由):`onStepStart`(渲染只在新坐标就绪后推进,避免重复驱动)、`onSetMoveDir`(渲染朝向只随 `onSetFaceDir` 变化;`moveDirection` 已由 `onStepEnd` 读取)、`IHeroLocationHooks.onSetFloor`(楼层切换需要重绑图层的接线路径,本增量不接线 `client.ts`;登记为后续增量事项,不在本计划实现)。
|
||||
- **逐字保留(D-18 / D-22,不得删除、改写语义或改名)**:`onSetImage(image: ImageIds)`、`onSetAlpha(alpha: number)`、`onSetFollowerAlpha(identifier: string, alpha: number)`、`onAddFollower(follower: number, identifier: string)`、`onRemoveFollower(identifier: string, animate: boolean)`、`onRemoveAllFollowers()`——它们是本类上的多余方法(不再属于任何现有钩子接口的成员),保持原样并**不注册到任何数据端对象**;其现有 jsDoc / 注释一字不改。是否在后续增量(D-18 / D-22 解开时)迁到数据端对象上,留待用户裁定。
|
||||
(2) **`IMapHeroRenderer` 按 D-20 裁剪(`types.ts`)**:删除以下 8 个成员声明**及其配套 jsDoc**(属删除代码,Task 0 已获用户确认):`setPosition(x, y)`(`:92`)、`startMove()`(`:97`)、`waitMoveEnd(waitFollower)`(`:103`)、`stopMove()`(`:108`)、`move(direction, time)`(`:114`)、`jumpTo(x, y, time, waitFollower)`(`:123`)、`setHeroAnimateDirection(direction)`(`:147`)、`turn(direction?)`(`:153`)。保留 `setImage` / `addFollower` / `removeFollower` / `removeAllFollowers` / `setAlpha` / `setFollowerAlpha` / `destroy`(D-18 / D-22 成员,逐字不动)。不得新增任何成员。
|
||||
(3) **`MapHeroRenderer` 侧配套**:上述 8 个方法在类上**保留为内部实现**(不删除、不改名),仅由 `MapHeroHook` 的回调调用;其可见性/实现细节保持不变。`waitMoveEnd()` 的实现签名(无参)与接口原声明的参数落差(04-02「未能从阅读确定」第 6 条)随接口成员移除而消解,在 `04-03-SUMMARY.md` 记为「由 D-20 契约裁剪消解」。`setHeroAnimateDirection(direction: ObjectAnimDirection)` 的形参类型在 Task 1 已改,本任务不再动它。
|
||||
(2) **`IMapHeroRenderer` 按 D-20 裁剪收口(`types.ts`)**:删除以下 **7 个**成员声明**及其配套 jsDoc**(属删除代码,Task 0 已获用户确认):`setPosition(x, y)`(`:92`)、`startMove()`(`:97`)、`waitMoveEnd(waitFollower)`(`:103`)、`stopMove()`(`:108`)、`move(direction, time)`(`:114`)、`jumpTo(x, y, time, waitFollower)`(`:123`)、`turn(direction?)`(`:153`)。D-20 的第 8 个成员 `setHeroAnimateDirection` 已在 Task 1 随类型改名删除(其声明连同 jsDoc 已不在 `types.ts`),**本任务不得为它重新引入任何声明**,故本任务结束时接口内的 8 个外部驱动成员全部不存在。保留 `setImage` / `addFollower` / `removeFollower` / `removeAllFollowers` / `setAlpha` / `setFollowerAlpha` / `destroy`(D-18 / D-22 成员,逐字不动)。不得新增任何成员。
|
||||
(3) **`MapHeroRenderer` 侧配套**:上述 8 个驱动方法(含 Task 1 已从 `IMapHeroRenderer` 删除声明的 `setHeroAnimateDirection`)在类上**保留为内部实现**(不删除、不改名),仅由 `MapHeroHook` 的回调调用;其可见性/实现细节保持不变。`waitMoveEnd()` 的实现签名(无参)与接口原声明的参数落差(04-02「未能从阅读确定」第 6 条)随接口成员移除而消解,在 `04-03-SUMMARY.md` 记为「由 D-20 契约裁剪消解」。`MapHeroRenderer.setHeroAnimateDirection(direction: ObjectAnimDirection)` 已在 Task 1 把形参类型改为 `ObjectAnimDirection`、并保留为类上的内部实现方法(`IMapHeroRenderer` 侧的声明已删除),本任务不再动它。
|
||||
(4) **不改的事**:不改 `MapHeroRenderer` 的动画算法(`tick` / `moveEntity` / `jumpEntity` / `generateJumpFn`)、不改 `addHeroMoving` 的贴图分支结构、不改 `setImage` / `setAlpha` / 跟随者族实现体、不接线 `client.ts`、不动 `action/move.ts`。既有注释一字不改(新增注释除外)。
|
||||
(5) **原子提交**:`refactor(04-03): rebind hero renderer to IHeroLocation and existing hooks`(或执行环境约定的等价信息),提交内容仅含 `hero.ts` / `types.ts` / `manager.ts` 三个文件;**不得**把用户的并发未提交改动纳入提交。随后执行 `pnpm exec eslint --fix` 对三个文件,再 `pnpm exec eslint` 必须 0 错误。
|
||||
</action>
|
||||
@ -303,6 +305,7 @@ Output: 三个在范围文件的适配改动(原子提交)+ 会话内可复
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `MapHeroHook` 实现 `onSetPos` / `onMoveStart` / `onMoveEnd` / `onStepStart`(可不实现)/ `onStepEnd` / `onSetFaceDir` / `onSetMoveDir`(可不实现)中的映射子集,且**不含**任何旧命名方法
|
||||
- 三个返回 `Promise<void>` 的钩子(`onMoveStart` / `onMoveEnd` / `onStepEnd`)均以 `async` 实现,签名与数据端 `IObjectMoverHooks` 可赋值(无 TS2416「void is not assignable to Promise<void>」);`onSetPos` / `onSetFaceDir` 保持 `void`;`onStepEnd` 的未使用首参命名为 `_code`(满足 eslint `args: 'all'` + `argsIgnorePattern: '^_'`),且 `hero.ts` 未引入任何本任务用不到的 import(尤其 `ObjectSpecialStep`)
|
||||
- `onStepEnd` 按 `ObjectMoveType` 分派到 `move` / `turn` / `setPosition` / `jumpTo`,并在开头以 `mover.currAnimDir` 设置动画方向;`onMoveStart` / `onMoveEnd` 分别驱动 `startMove` / `waitMoveEnd`
|
||||
- `IMapHeroRenderer` 不再声明 `setPosition` / `startMove` / `waitMoveEnd` / `stopMove` / `move` / `jumpTo` / `setHeroAnimateDirection` / `turn`,且 `setImage` / `addFollower` / `removeFollower` / `removeAllFollowers` / `setAlpha` / `setFollowerAlpha` / `destroy` 逐字保留
|
||||
- `hero.ts` 仍含全部 D-18 / D-22 钩子方法与实现方法(含 `onSetImage` / `onSetAlpha` / `onSetFollowerAlpha` 与跟随者三方法),且其注释与实现体未被改写
|
||||
@ -374,7 +377,7 @@ Output: 三个在范围文件的适配改动(原子提交)+ 会话内可复
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-04-03-01 | Tampering | `IMapHeroRenderer` 公共契约(`types.ts`) | high | mitigate | Task 2 删除 8 个外部驱动成员(D-20)并由 Task 2 / Task 3 的 D-20 契约门禁断言其不再出现;prohibitions 禁止新增任何接口成员;D-18 / D-22 成员设独立保留门禁,防误删 |
|
||||
| T-04-03-01 | Tampering | `IMapHeroRenderer` 公共契约(`types.ts`) | high | mitigate | Task 1 删除 `setHeroAnimateDirection`(随 `HeroAnimateDirection` 类型改名,无悬空引用)、Task 2 删除其余 7 个外部驱动成员(合计 8 个,D-20),并由 Task 2 / Task 3 的 D-20 契约门禁断言其不再出现;prohibitions 禁止新增任何接口成员;D-18 / D-22 成员设独立保留门禁,防误删 |
|
||||
| T-04-03-02 | Repudiation | 钩子映射与旧名清除的可追溯性 | medium | mitigate | 逐钩子映射在 Task 0 汇报并经用户确认;Task 2 / Task 3 的静态改名门禁断言 6 个旧钩子方法名与 3 个旧类型名不复现、5 个现有钩子成员落地;映射关系写入 SUMMARY 人工复核段 |
|
||||
| T-04-03-03 | Elevation of Privilege | 执行前置关卡(AGENTS.md 要求的第一处 block 点) | high | mitigate | Task 0 为 `checkpoint:decision` + `gate="blocking-human"` 且本计划 `autonomous: false`;Task 0 的 action ⑦/⑧ 与 acceptance_criteria 明示未收到「可以执行」四个字即必须停止、不派发执行子代理 |
|
||||
| T-04-03-04 | Tampering | 用户并发的未提交改动 | high | mitigate | Task 1 步骤 (0b) 记录 porcelain 条目 + 各文件内容 `sha256` 摘要;Task 3 用同一固定命令复算并断言集合与摘要未变;prohibitions 明确不得回滚 / 暂存 / 提交 / 修改;Task 3 范围门禁额外断言无范围外生产文件改动 |
|
||||
|
||||
Loading…
Reference in New Issue
Block a user