diff --git a/.planning/phases/10-docs-restructure/10-21-PLAN.md b/.planning/phases/10-docs-restructure/10-21-PLAN.md new file mode 100644 index 0000000..1772d63 --- /dev/null +++ b/.planning/phases/10-docs-restructure/10-21-PLAN.md @@ -0,0 +1,190 @@ +--- +phase: 10-docs-restructure +plan: 21 +type: execute +wave: 1 +depends_on: [] +files_modified: + - docs/advanced/ii/custom-range.md + - docs/advanced/ii/static-vs-dynamic-tiles.md +autonomous: false +requirements: [] +user_setup: [] +estimate: + tokens: 30000 + raw_tokens: 20000 + tasks: 3 + confidence: low +must_haves: + truths: + - "本计划先向用户汇报整套高级 II 的文档文件名、侧边栏分组名与读者人格,并等待「可以执行」;文件名与分组名未经用户批准不得落盘(D-13)" + - "`custom-range.md` 讲清 `IRange` 的职责、宿主 `IRangeHost`、内置范围与参数类型,并给出一个可运行的自定义范围类;示例说明它如何被怪物上下文与地图伤害复用" + - "`static-vs-dynamic-tiles.md` 讲清静态图块与动态图块的区别、双向转换与事件保留,并**单独成节**讲点事件与图块事件" + - "两篇均按 D-59 库文档风格写:先概念后示例、完整代码块、解释性注释充足(D-65)、主干与边界分离(D-61);不写中级教程的六步实操(D-58 / D-59)" + - "只写数据端内容;渲染端可视化、编辑器与状态栏相关内容一律用 D-47 非断链占位,不写 `src/client` 路径" + - "两篇均 kebab-case、CRLF、单 H1;无指向不存在页面的相对链接;构建 green、`build complete`、dead link = 0" + artifacts: + - "docs/advanced/ii/custom-range.md" + - "docs/advanced/ii/static-vs-dynamic-tiles.md" + - ".planning/phases/10-docs-restructure/10-21-SUMMARY.md" + key_links: + - "范围对象是光环、地图伤害、查询共用的底层能力,后两篇属性文档会回指本篇" + - "图块篇的点事件/图块事件是装备、寻路与地图伤害文档的事件前提" + - "10-25 负责把本计划产出的页面接入侧边栏,本计划不修改 `config.ts`" +--- + + +编写高级 II 的两篇基础篇:`custom-range.md`(自定义范围对象)与 `static-vs-dynamic-tiles.md`(静态图块与动态图块,含点事件与图块事件)。 + +Purpose: 范围对象与图块是高级 II 其它主题的公共底座——光环、地图伤害、查询都要扫描范围,装备与寻路都要和图层、图块事件打交道。先把这两篇写扎实,后续属性与战斗篇才能直接引用而不重复解释。 +Output: 两篇可构建的 `docs/advanced/ii/*.md` 正文。 + + + +@C:/Users/13194/.config/opencode/gsd-core/workflows/execute-plan.md +@C:/Users/13194/.config/opencode/gsd-core/templates/summary.md + + + +@.planning/phases/10-docs-restructure/10-CONTEXT.md +@docs/advanced/index.md +@docs/advanced/declarative-vs-imperative.md +@docs/advanced/plugin-system.md +@docs/intermediate/enemy-aura.md +@docs/intermediate/enemy-map-damage.md +@docs/intermediate/map-tiles.md +@docs/intermediate/map-structure.md +@packages/common/src/utils/types.ts +@packages/common/src/utils/range.ts +@packages-user/data-system/src/combat/context.ts +@packages-user/data-system/src/combat/mapDamage.ts +@packages-user/data-base/src/map/types.ts +@packages-user/data-base/src/map/tile.ts +@packages-user/data-base/src/map/staticTile.ts +@packages-user/data-base/src/map/dynamicTile.ts +@packages-user/data-base/src/map/mapLayer.ts + +**命名基线(须用户批准,D-13):** +- 高级 II 目录:`docs/advanced/ii/` +- 本计划两篇:`custom-range.md`(自定义范围对象)、`static-vs-dynamic-tiles.md`(静态图块与动态图块) +- 整套九篇:`ii/index.md`、`custom-range.md`、`static-vs-dynamic-tiles.md`、`equipment-system.md`、`custom-replay-command.md`、`pathfinding.md`、`adding-hero-attribute.md`、`adding-enemy-attribute.md`、`enemy-context-and-combat.md` + +**写作规范(D-53..D-66,逐条遵守):** +- D-59:按库文档写,先说要解决什么问题,再给完整示例与注释,最后说接入点;不写「复制什么 / 改什么」六步。 +- D-60:能删就删,不重复中级教程已讲清的内容。 +- D-61:主干只讲核心;边界情况(越界、性能取舍、非法参数)文末单独成节。 +- D-62:代码块必须是完整类/函数,不能只给类成员片段。 +- D-63:先理念、再引导语、再模板代码、最后解释。 +- D-64:只有读者需要自己实现接口时才给模板;纯调用只给示例。 +- D-65:示例注释越多越好,解释「为什么」而不是复述代码。 +- D-66:多个并列功能分开写示例,不合并成大块。 +- D-58:不写「不懂代码就改内置」一类中级提示,也不强制模板章节。 +- D-55:新增系统优先插件;需要改内置时再改。 +- D-47:指向高级 III 或尚不存在的页面时,只用代码 span(如 `高级 III · 范围性能`)或 `` 注释。 + +**写法口径:** +- 两篇都面向「有较好代码能力、能读懂引擎源码、想做系统级定制,但不熟悉具体系统实现」的读者。 +- 需要读者实现接口时给完整骨架,并用 `[需改]` 标出改动点;纯接口调用只给短示例。 +- 每一篇结尾给「怎么验证」段:给出可执行的调用或控制台检查方式,并说明预期现象。 + + + + + + Task 0: 汇报高级 II 规划基线并等待「可以执行」 + 向用户汇报:**要做什么**(编写高级 II 的两篇基础文档:自定义范围对象、静态图块与动态图块,并在后续计划中补齐其余六篇、导览、侧边栏注册与两轮修订)、**为什么**(D-67 把高级 II 定位为「深入定制」难度层;范围对象与图块是光环、地图伤害、装备、寻路的公共底座)、**大致怎么做**(本计划写两篇;10-22 写装备与录像指令;10-23 写寻路与勇士属性;10-24 写怪物属性与怪物上下文;10-25 写导览并接入侧边栏;10-26 读者审阅;10-27 用户主导修订循环)、**影响范围**(新增 `docs/advanced/ii/` 下两篇;不修改 `config.ts`、生产代码与渲染端内容)。同时请用户确认以下命名与设定(D-13): +1. 目录 `docs/advanced/ii/`; +2. 九篇文件名:`index.md`、`custom-range.md`、`static-vs-dynamic-tiles.md`、`equipment-system.md`、`custom-replay-command.md`、`pathfinding.md`、`adding-hero-attribute.md`、`adding-enemy-attribute.md`、`enemy-context-and-combat.md`; +3. 侧边栏分组显示名由「高级 II · 系统实现」改为「高级 II · 深入定制」(D-53 的分层是难度标签,不是领域分类); +4. 高级 II 读者人格:「你是一位有较好代码能力、能读懂引擎源码的数据端作者,想做系统级定制,但还不熟悉具体系统实现;你已经读完高级 I,正在读高级 II。」 +汇报中明确:本计划的修改方式为**派发子代理执行**,范围严格限于 `files_modified` 列出的两篇文档,执行者不内联修改文件。停下等待用户明确回复「可以执行」四个字;未收到前不得创建目录、不得写任何文档、不得派发子代理。 + 本计划内容:高级 II 两篇基础文档 + 整套高级 II 的命名与流程基线。 + 阅读上面的四段说明,重点确认九篇文件名、侧边栏分组名与读者人格;如要改名请直接给出替代名称。 + 回复「可以执行」以继续;其它回复视为未批准,本计划停在此处。 + + 用户已确认九篇文件名与侧边栏分组名,并回复「可以执行」。 + + 用户确认命名基线并回复「可以执行」。 + + + + Task 1: 编写自定义范围对象 custom-range.md + docs/advanced/ii/custom-range.md + 写 `docs/advanced/ii/custom-range.md`,单 H1「自定义范围对象」。正文顺序: +1. **范围对象解决什么问题**:光环、地图伤害、查询都需要「以某个点为中心,找出周围哪些格」;这些系统共用 `IRange`,因此自定义一次即可在多个系统复用。说明坐标索引约定 `index = y * width + x`。 +2. **范围对象与宿主**:`IRangeHost` 只有 `width` 与 `height`;`bindHost(host)` 决定边界;`inBound` / `inBoundIndex` 判断宿主边界。强调范围对象本身不保存地图,只保存宿主尺寸。 +3. **接口职责**:`iterateLoc(param)` 枚举范围内全部索引;`inRange(x, y, param)` 判断单点;`inRangeIndex` 是索引版;`iterate(list, param)` 过滤已有列表;`scan(list, param)` 按范围顺序命中集合;`autoDetect` 在两者间自动选择。说明 `scan` 与 `iterate` 的复杂度差异只作选型提示,不展开底层实现。 +4. **内置范围与参数**:表格列 `FullRange`、`RectRange` + `IRectRangeParam`、`ManhattanRange` + `IManhattanRangeParam`、`RayRange` + `IRayRangeParam`、`NoneRange`。每项写适用场景与参数含义(`x/y/w/h`、`cx/cy/radius`、`cx/cy/dir`)。 +5. **自定义范围**:说明继承 `BaseRange` 需要实现 `estimatePointCount(param)`、`iterateLoc(param)`、`inRange(x, y, param)`;给出完整类示例——**环形范围**(曼哈顿距离恰好等于 `radius` 的空心环),参数接口 `IRingRangeParam { cx, cy, radius }`。注释解释 `estimatePointCount` 用于 `autoDetect` 估算、`iterateLoc` 必须与 `inRange` 的判定完全一致、边界用 `inBound` 收口。不要引用不存在的接口名。 +6. **绑定到系统**:给出两段短示例——怪物上下文 `context.scanRange(new RingRange(), { cx, cy, radius: 2 })`;地图伤害/光环视图在 `apply` 中通过 `range.bindHost(context)` 后调用 `range.iterateLoc(param)`。说明宿主由系统注入,自定义范围不要自己保存地图宽高。 +7. **与视图/转换器的关系**:一句话说明光环视图的 `range` 与 `getRangeParam()` 返回范围对象与参数;具体转换器写法指向 `docs/intermediate/enemy-aura.md`,不重复。 +8. **怎么验证**:给出可执行的检查——在插件或事件里用 `state.enemyContext.bindHero(...)` 后调用 `scanRange`,打印命中坐标;预期环形只命中四条边、不含中心。若当前场景没有怪物,说明可先放两只测试怪。 +9. **边界与注意**:越界坐标必须返回 `false`;`iterateLoc` 与 `inRange` 不一致会让 `autoDetect` 产生偏差;`radius` 为负时按绝对值处理的约定;范围对象可复用但 `bindHost` 后不要跨不同尺寸的地图共用。 +按 D-59 叙述,不写六步实操;示例代码完整(接口 + 类 + 调用),注释充足;加粗符合 flanking。完成后跑 prettier `--write docs/advanced/ii/custom-range.md`。Commit:`docs(10-21): 编写高级 II 自定义范围对象`。 + + $ErrorActionPreference='Stop'; $p='docs/advanced/ii/custom-range.md'; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($raw -match "(?&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'RANGE-OK' + non-zero exit, or output contains "MISSING", "LF-ONLY", "H1-COUNT", "MISSING-CONTENT", "RENDERER-CONTENT", "DEAD-LINK", "NO-TS-BLOCK", "BUILD-FAIL", or "NO-BUILD-COMPLETE"; or output lacks "RANGE-OK" + + 范围篇存在、CRLF、单 H1;`IRange`/宿主/接口职责/内置范围/自定义环形范围/绑定系统/验证/边界齐全;代码块完整;无渲染端内容;无死链;构建通过。 + + + + Task 2: 编写静态图块与动态图块 static-vs-dynamic-tiles.md + docs/advanced/ii/static-vs-dynamic-tiles.md + 写 `docs/advanced/ii/static-vs-dynamic-tiles.md`,单 H1「静态图块与动态图块」。正文顺序: +1. **两种图块的分工**:静态图块 `IStaticTile` 是图层数组里的一格,位置固定;动态图块 `IDynamicTile` 有 `mover`、可移动、有独立实例。说明 `num()` / `raw()` / `locator` / `layer` 的共同点。 +2. **创建与获取**:静态图块通过 `layer.getTile(x, y)`;动态图块通过 `layer.createDynamic(num, x, y)` 或 `layer.transferToDynamic(x, y, keepEvent?)`;遍历用 `iterateDynamicTiles()` 与 `getDynamicTilesAt(x, y)`。 +3. **双向转换**:`IStaticTile.toDynamic()`;`IDynamicTile.toStatic()` 与 `toStaticIfSafe()`;图层级 `transferToDynamic` / `transferToStatic` / `transferToStaticIfSafe`;`moveBlock` 是「转动态 → 移动 → 转回静态」的简写,不适合高级配置。写清 `keepEvent` 的默认值与语义:保留时把原图块事件复制到目标实例,转换后源位置事件被清空;不保留时静态图块回退到原始定义的默认事件。 +4. **事件的两类归属(单独成节)**:点事件 `pointEvent()` 属于**坐标**,通过 `layer.event(x, y)` / `getPointEvent(x, y)` 访问,同一位置换图块仍保留;图块事件 `tileEvent()` 属于**图块实例**,随转换/复制走。给出对照表:归属、获取方式、是否跟随图块移动、典型用途(踩踏/进入某格 vs「这块可推动的石头被推开后事件跟着走」)。 +5. **事件视图接口**:`IReadonlyEventView` 的 `get()` / `ref()` / `dirty()`;`ILayerEventView` 的 `set(priority, eventId)` / `delete(priority)` / `reset()` / `clear()` / `markPure()`;事件值是 `IGameEventStore` 的 id,键是优先级。说明 `markPure` 建立「干净基准」,`dirty` 用于决定是否写入存档。 +6. **在代码里操作事件**:给一段完整示例——读取某格静态图块、给它的图块事件添加一个优先级事件、再用 `syncTileEvent` 复制到另一块;再给一段点事件示例——给某坐标设置事件并在换图块后读取确认仍在。注释解释「优先级冲突会覆盖并告警」「事件 id 必须已注册」。 +7. **转换的失败条件**:`toStatic` 在坐标为非整数或正在移动时返回 `null`;`toStaticIfSafe` 额外要求目标点为空;`delete()` 是 `Promise`,删除后 `onDeleteDynamic` 钩子触发。说明 `onCreateDynamic` / `onUpdateDynamicPosition` 的触发时机。 +8. **怎么验证**:用 `layer.getTile(x, y)?.toDynamic()` 创建动态图块,`step(FaceDirection.Right)` 移动一格后 `toStaticIfSafe()`;预期原位置变空、目标位置出现静态图块,图块事件跟随,点事件留在原地。给出打印语句。 +9. **边界与注意**:静态图块的 `set()` 会重置默认事件;动态图块不写回图层数组;`keepEvent` 不保留时不要误以为事件丢失是 bug;同一格多个动态图块的迭代顺序不保证。 +按 D-59 叙述,完整类/调用示例,注释充足;加粗符合 flanking。完成后跑 prettier `--write docs/advanced/ii/static-vs-dynamic-tiles.md`。Commit:`docs(10-21): 编写高级 II 静态与动态图块`。 + + $ErrorActionPreference='Stop'; $p='docs/advanced/ii/static-vs-dynamic-tiles.md'; if(-not(Test-Path -LiteralPath $p)){ Write-Error "MISSING $p" }; $raw=[IO.File]::ReadAllText((Resolve-Path -LiteralPath $p)); if($raw -match "(?&1; $ec=$LASTEXITCODE; $ErrorActionPreference='Stop'; if($ec -ne 0){ $out | Write-Output; Write-Error "BUILD-FAIL" }; $txt=($out | ForEach-Object { $_.ToString() }) -join "`n"; if($txt -notmatch 'build complete'){ Write-Error "NO-BUILD-COMPLETE" }; if($txt -match 'dead link'){ Write-Error "DEAD-LINK" }; Write-Output 'TILE-OK' + non-zero exit, or output contains "MISSING", "LF-ONLY", "H1-COUNT", "MISSING-CONTENT", "RENDERER-CONTENT", "DEAD-LINK", "NO-TS-BLOCK", "BUILD-FAIL", or "NO-BUILD-COMPLETE"; or output lacks "TILE-OK" + + 图块篇存在、CRLF、单 H1;静态/动态区分、创建、双向转换、`keepEvent`、点事件与图块事件对照、事件视图接口、失败条件、验证与边界齐全;代码块完整;无渲染端内容;无死链;构建通过。 + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| 执行者 → 子代理 | 文档由子代理按任务书编写,执行者只验收 | +| 构建期 markdown → 静态站点 | 正文由构建期静态渲染,无运行时输入 | +| 站点 → 浏览器读者 | 站内链接是唯一可点击指向面 | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan | +|-----------|----------|-----------|----------|-------------|-----------------| +| T-10-61 | Tampering / XSS | 新增两篇正文 | low | mitigate | 只写文本、代码块、表格;不引入原始 `