# 需求综述 当前勇士属性修饰器 `IHeroModifier` 是非注册式的,无法直接存档。 目标是将其改为注册式,每种修饰器在使用前需先在属性对象上注册, 并实现 `ISaveableContent` 接口以支持存档读档。 注册接口签名:`registerModifier(identifier: string, cons: () => IHeroModifier): void` # 实现思路 ## 1. 修改 `IHeroModifier` 接口 - 将 `identifier` 改为 `type`:一类修饰器可能被添加多次, `type` 比 `identifier` 更准确地表达"修饰器类型"的含义。 - 新增泛型参数 `S = unknown` 作为存档类型,让接口继承 `ISaveableContent`: `IHeroModifier` - 大多数修饰器的可变状态只有 `value`,因此 `BaseHeroModifier` 将 `S` 默认为 `V`。 若修饰器需要特殊存储结构,可以不继承 `BaseHeroModifier`,自行编写实现类。 ## 2. 新增 `IModifierStateSave` 类型 `IModifierStateSave` 记录单条修饰器的存档信息: ```ts interface IModifierStateSave { readonly name: PropertyKey; // 属性名,如 'atk' readonly type: string; // 修饰器类型(与注册时的 key 对应) readonly state: unknown; // 修饰器 saveState 结果 } ``` ## 3. 修改 `IHeroStateSave`,新增 `modifiers` 字段 `attribute` 字段维持原来的 `THero` 只保存基础属性值, 修饰器列表单独作为顶层字段: ```ts readonly modifiers: readonly IModifierStateSave[]; ``` ## 4. 修改 `IHeroAttribute`,新增 `iterateModifiers` 方法 `HeroAttribute` 不再继承 `ISaveableContent`,也不负责存读档, 保留现有的 `toStructured(): THero`。 新增 `iterateModifiers` 方法,供 `HeroState` 在存档时遍历所有已挂载的修饰器: ```ts iterateModifiers(): Iterable<[keyof THero, IHeroModifier]>; ``` ## 5. 修改 `BaseHeroModifier`,新增 `S` 泛型并实现 `ISaveableContent` - 改为 `BaseHeroModifier` 隐式以 `S = V` 实现 `ISaveableContent` - 将 `abstract readonly identifier: string` 改为 `abstract readonly type: string` - `saveState()` 直接返回 `this.currentValue` - `loadState(state)` 调用 `this.setValue(state)` 恢复值 ## 6. 修改 `HeroState` 修饰器注册表移至 `HeroState`: - 新增 `private readonly registry: Map IHeroModifier>` 存储工厂函数 - 实现 `registerModifier(type, cons)`:向 `registry` 写入工厂, 并同步注册到接口签名中 - 实现 `createModifier(type)`:从 `registry` 取出对应工厂, 调用工厂函数创建并返回修饰器实例,类型为 `IHeroModifier` - 实现 `createAndInsertModifier(type, name)`: 调用 `createModifier` 创建实例后,自动调用 `this.attribute.addModifier(name, modifier)` 插入属性对象, 返回该修饰器实例,类型与 `createModifier` 一致 - 修改 `saveState()`: 1. `attribute` 字段调用 `this.attribute.toStructured()` 获取基础属性值(与现在一致) 2. 遍历 `this.attribute.iterateModifiers()`,对每个修饰器调用 `modifier.saveState(compression)` 并拼装 `IModifierStateSave[]`, 写入 `modifiers` 字段 - 修改 `loadState()`: 1. 创建新的 `HeroAttribute` 实例(使用 `state.attribute` 还原基础属性值,与现在一致) 2. 遍历 `state.modifiers`,通过 `registry.get(type)` 创建修饰器实例, 调用 `modifier.loadState(state)` 恢复值,再 `addModifier(name, modifier)` 挂载 # 涉及文件 ## 需要修改的文件 ### `@user/data-base/hero/types.ts` - [ ] 修改 `IHeroModifier` 接口: 改为 `IHeroModifier`,`identifier` 改名为 `type`, 继承 `ISaveableContent` - [ ] 新增 `IModifierStateSave` 接口:单条修饰器的存档格式 - [ ] 修改 `IHeroStateSave`:新增 `readonly modifiers: readonly IModifierStateSave[]` 字段 - [ ] 修改 `IReadonlyHeroAttribute`:新增 `iterateModifiers()` 方法签名 - [ ] 修改 `IHeroState`:新增以下方法签名 - `registerModifier(type: string, cons: () => IHeroModifier): void` - `createModifier(type: string): IHeroModifier` - `createAndInsertModifier(type: string, name: K): IHeroModifier` ### `@user/data-base/hero/attribute.ts` - [ ] 修改 `BaseHeroModifier`: 将 `abstract readonly identifier` 改为 `abstract readonly type`; 实现 `saveState` / `loadState` - [ ] 修改 `HeroAttribute`:实现 `iterateModifiers()` ### `@user/data-base/hero/state.ts` - [ ] 修改 `HeroState`:新增 `private readonly registry: Map IHeroModifier>` 成员 - [ ] 实现 `HeroState.registerModifier`:将工厂函数写入 `registry` - [ ] 实现 `HeroState.createModifier`:从 `registry` 取出工厂并调用,返回新实例; 若 `type` 未注册则抛出错误 - [ ] 实现 `HeroState.createAndInsertModifier`:调用 `createModifier` 后, 再调用 `this.attribute.addModifier(name, modifier)`,返回同一实例 - [ ] 修改 `HeroState.saveState`:遍历 `iterateModifiers()` 写入 `modifiers` 字段 - [ ] 修改 `HeroState.loadState`:遍历 `state.modifiers` 重建修饰器并挂载