diff --git a/packages-user/data-base/src/enemy/manager.ts b/packages-user/data-base/src/enemy/manager.ts index 4ea54b4..543fd81 100644 --- a/packages-user/data-base/src/enemy/manager.ts +++ b/packages-user/data-base/src/enemy/manager.ts @@ -1,16 +1,15 @@ import { logger } from '@motajs/common'; -import { Enemy as EnemyImpl } from './enemy'; import { IEnemy, IEnemyComparer, IEnemyManager, IEnemyManagerSaveState, - IEnemyLegacyBridge, IReadonlyEnemy, SpecialCreation, IEnemySaveState } from './types'; -import { SaveCompression } from '@user/data-common'; +import { ITileStore, SaveCompression } from '@user/data-common'; +import { isNil } from 'lodash-es'; export class EnemyManager implements IEnemyManager { /** 特殊属性注册表,code -> 创建函数 */ @@ -22,14 +21,8 @@ export class EnemyManager implements IEnemyManager { private readonly attributeRegistry: Map = new Map(); /** 怪物模板表,code -> IEnemy */ private readonly prefabByCode: Map> = new Map(); - /** 怪物模板表,id -> IEnemy */ - private readonly prefabById: Map> = new Map(); - /** 旧样板怪物 id 到 code 的映射,用于 fromLegacyEnemy 快速查找已有模板 */ - private readonly legacyIdToCode: Map = new Map(); /** 复用映射,reusedCode -> sourceCode */ private readonly reuseByCode: Map = new Map(); - /** 复用映射,reusedId -> sourceId */ - private readonly reuseById: Map = new Map(); /** 脏模板集合,存储发生了变化的模板 code */ private readonly dirtySet: Set = new Set(); /** 参考快照,code -> IReadonlyEnemy,由 compareWith 提供 */ @@ -39,7 +32,7 @@ export class EnemyManager implements IEnemyManager { /** 是否已首次调用 compareWith */ private hasReference: boolean = false; - constructor(readonly bridge: IEnemyLegacyBridge) {} + constructor(private readonly tileStore: ITileStore) {} registerSpecial(code: number, cons: SpecialCreation): void { this.specialRegistry.set(code, cons); @@ -61,59 +54,16 @@ export class EnemyManager implements IEnemyManager { this.attributeRegistry.set(name, defaultValue); } - fromLegacyEnemy(code: number, enemy: Enemy): IEnemy { - // 如果该旧样板怪物已经通过 addPrefabFromLegacy 注册为模板,直接克隆模板 - const existingCode = this.legacyIdToCode.get(enemy.id); - if (existingCode) { - const prefab = this.prefabByCode.get(existingCode); - if (prefab) { - return prefab.clone(); - } - } - - return this.convertLegacyEnemy(code, enemy); - } - /** - * 根据旧样板怪物与注册过的默认属性构造属性对象 - * @param enemy 旧样板怪物对象 + * 根据怪物的图块数字或 id 获取其模板 + * @param token 怪物的图块数字或 id + * @returns */ - private createAttributes(enemy: Enemy): TEnemy { - const attrs: Partial = {}; - for (const [name, defaultValue] of this.attributeRegistry) { - attrs[name] = structuredClone(defaultValue); - } - - Object.assign(attrs, this.bridge.fromLegacyEnemy(enemy, attrs)); - - return attrs as TEnemy; - } - - /** - * 真正执行旧样板怪物到新怪物对象的转换 - * @param code 怪物图块数字 - * @param enemy 旧样板怪物对象 - */ - private convertLegacyEnemy(code: number, enemy: Enemy): IEnemy { - const attrs = this.createAttributes(enemy); - const result = new EnemyImpl( - enemy.id, - code, - structuredClone(attrs) - ); - - // 转换特殊属性 - if (enemy.special) { - for (const specialCode of enemy.special) { - const creator = this.specialRegistry.get(specialCode); - if (!creator) continue; - const special = creator(result); - special.fromLegacyEnemy(enemy); - result.addSpecial(special); - } - } - - return result; + private internalGetPrefab(token: number | string) { + const num = this.tileStore.num(token); + if (isNil(num)) return null; + const sourceCode = this.reuseByCode.get(num) ?? num; + return this.prefabByCode.get(sourceCode) ?? null; } createEnemy(code: number): IEnemy | null { @@ -122,79 +72,39 @@ export class EnemyManager implements IEnemyManager { return prefab.clone(); } - // 不变式:所有按 code/id 取模板的公开入口都必须经 internalGetPrefab 解析复用映射, - // 复用映射把同一模板的多个朝向 code 别名到来源模板,绕过解析会让这些 code 取不到模板 - createEnemyById(id: string): IEnemy | null { - const prefab = this.internalGetPrefab(id); - if (!prefab) return null; - return prefab.clone(); - } - - private internalGetPrefab(code: number | string) { - if (typeof code === 'number') { - const sourceCode = this.reuseByCode.get(code) ?? code; - return this.prefabByCode.get(sourceCode) ?? null; - } else { - const sourceId = this.reuseById.get(code) ?? code; - return this.prefabById.get(sourceId) ?? null; - } - } - addPrefab(enemy: IEnemy): void { - if ( - this.prefabByCode.has(enemy.code) || - this.prefabById.has(enemy.id) - ) { + if (this.prefabByCode.has(enemy.code)) { return; } const cloned = enemy.clone(); this.prefabByCode.set(enemy.code, cloned); - this.prefabById.set(enemy.id, cloned); this.updateDirty(cloned.code, cloned); } - addPrefabFromLegacy(code: number, enemy: Enemy): void { - if (this.prefabByCode.has(code) || this.prefabById.has(enemy.id)) { - return; - } - const prefab = this.convertLegacyEnemy(code, enemy); - this.prefabByCode.set(code, prefab); - this.prefabById.set(prefab.id, prefab); - this.legacyIdToCode.set(enemy.id, code); - this.updateDirty(code, prefab); + getPrefab(token: number | string): IReadonlyEnemy | null { + return this.internalGetPrefab(token); } - getPrefab(code: number): IReadonlyEnemy | null { - const sourceCode = this.reuseByCode.get(code) ?? code; - return this.prefabByCode.get(sourceCode) ?? null; - } - - getPrefabById(id: string): IReadonlyEnemy | null { - const sourceId = this.reuseById.get(id) ?? id; - return this.prefabById.get(sourceId) ?? null; - } - - deletePrefab(code: number | string): void { - const prefab = this.internalGetPrefab(code); + deletePrefab(token: number | string): void { + const prefab = this.internalGetPrefab(token); if (!prefab) return; this.prefabByCode.delete(prefab.code); - this.prefabById.delete(prefab.id); } - changePrefab(code: number | string, enemy: IEnemy): void { + changePrefab(token: number | string, enemy: IEnemy): void { // 先删除旧的模板(如果存在) - this.deletePrefab(code); + this.deletePrefab(token); // 再添加新的模板 this.prefabByCode.set(enemy.code, enemy); - this.prefabById.set(enemy.id, enemy); this.updateDirty(enemy.code, enemy); } - reusePrefab(source: number | string, code: number, id: string): void { + reusePrefab(source: number | string, reuse: number | string): void { const prefab = this.internalGetPrefab(source); if (!prefab) return; - this.reuseByCode.set(code, prefab.code); - this.reuseById.set(id, prefab.id); + const num = this.tileStore.num(reuse); + if (isNil(num)) return; + this.reuseByCode.set(num, prefab.code); } compareWith(reference: ReadonlyMap>): void { @@ -223,13 +133,9 @@ export class EnemyManager implements IEnemyManager { const prefabCode = prefab.code; if (result !== prefab) { this.prefabByCode.set(result.code, result); - this.prefabById.set(result.id, result); if (result.code !== prefabCode) { this.prefabByCode.delete(prefabCode); } - if (result.id !== prefab.id) { - this.prefabById.delete(prefab.id); - } } this.updateDirty(result.code, result); } diff --git a/packages-user/data-base/src/enemy/special.ts b/packages-user/data-base/src/enemy/special.ts index 312f702..78a9f23 100644 --- a/packages-user/data-base/src/enemy/special.ts +++ b/packages-user/data-base/src/enemy/special.ts @@ -9,8 +9,6 @@ export interface ICommonSpecialConfig { getSpecialName: (special: ISpecial) => string; /** 获取特殊属性的描述 */ getDescription: (special: ISpecial) => string; - /** 从旧样板怪物对象获取此特殊属性对应的属性值 */ - fromLegacyEnemy: (enemy: Enemy) => T; } export class CommonSerializableSpecial implements ISpecial { @@ -36,10 +34,6 @@ export class CommonSerializableSpecial implements ISpecial { return this.config.getDescription(this); } - fromLegacyEnemy(enemy: Enemy): void { - this.value = this.config.fromLegacyEnemy(enemy); - } - clone(): ISpecial { return new CommonSerializableSpecial( this.code, @@ -86,19 +80,15 @@ export class NonePropertySpecial implements ISpecial { return this.config.getDescription(this); } - fromLegacyEnemy(_enemy: Enemy): void { - // unneeded - } - clone(): ISpecial { return new NonePropertySpecial(this.code, this.config); } - saveState(_compression: SaveCompression): void { + saveState(): void { return undefined; } - loadState(_state: void, _compression: SaveCompression): void { + loadState(): void { // 无属性,无需操作 } diff --git a/packages-user/data-base/src/enemy/types.ts b/packages-user/data-base/src/enemy/types.ts index a316d9b..faeefc3 100644 --- a/packages-user/data-base/src/enemy/types.ts +++ b/packages-user/data-base/src/enemy/types.ts @@ -55,12 +55,6 @@ export interface ISpecial extends ISaveableContent { */ getDescription(): string; - /** - * 从旧样板的怪物对象中导入此特殊属性 - * @param enemy 旧样板怪物对象 - */ - fromLegacyEnemy(enemy: Enemy): void; - /** * 深拷贝此特殊属性 */ @@ -162,14 +156,6 @@ export interface IEnemy export type SpecialCreation = (enemy: IEnemy) => ISpecial; -export interface IEnemyLegacyBridge { - /** - * 从旧样板的怪物对象中获取其属性 - * @param enemy 旧样板怪物对象 - */ - fromLegacyEnemy(enemy: Enemy, defaultValue: Partial): TAttr; -} - export interface IEnemyManager extends ISaveableContent< IEnemyManagerSaveState > { @@ -190,24 +176,11 @@ export interface IEnemyManager extends ISaveableContent< defaultValue: TAttr[K] ): void; - /** - * 根据旧样板怪物对象生成一个新的怪物对象 - * @param code 怪物数字 - * @param enemy 旧样板怪物对象 - */ - fromLegacyEnemy(code: number, enemy: Enemy): IEnemy; - /** * 创建怪物对象,如果对应数字的怪物不存在则会返回 `null` - * @param code 怪物图块数字 + * @param token 怪物图块数字或 id */ - createEnemy(code: number): IEnemy | null; - - /** - * 根据怪物的 `id` 创建怪物对象,如果对应的怪物不存在则会返回 `null` - * @param id 怪物 `id` - */ - createEnemyById(id: string): IEnemy | null; + createEnemy(token: number | string): IEnemy | null; /** * 添加怪物模板,如果 `id` 或 `code` 与已有的冲突,则不会做任何操作, @@ -216,45 +189,31 @@ export interface IEnemyManager extends ISaveableContent< */ addPrefab(enemy: IEnemy): void; - /** - * 从旧样板的怪物对象中添加怪物模板 - * @param code 怪物对象对应的图块数字 - * @param enemy 旧样板怪物对象 - */ - addPrefabFromLegacy(code: number, enemy: Enemy): void; - /** * 获取指定怪物的模板 - * @param code 怪物图块数字 + * @param token 怪物图块数字或id */ - getPrefab(code: number): IReadonlyEnemy | null; - - /** - * 根据怪物的 `id` 获取对应的怪物模板 - * @param id 怪物 `id` - */ - getPrefabById(id: string): IReadonlyEnemy | null; + getPrefab(token: number): IReadonlyEnemy | null; /** * 删除指定的怪物模板 - * @param code 怪物的图块数字或 `id` + * @param token 怪物的图块数字或 `id` */ - deletePrefab(code: number | string): void; + deletePrefab(token: number | string): void; /** * 修改一个已有的怪物模板,如果不存在则会新增 - * @param code 怪物的图块数字或 `id` + * @param token 怪物的图块数字或 `id` * @param enemy 新的怪物模板 */ - changePrefab(code: number | string, enemy: IEnemy): void; + changePrefab(token: number | string, enemy: IEnemy): void; /** * 让指定的怪物数字和怪物 id 复用指定的模板 * @param source 怪物模板源 - * @param code 复用怪物数字 - * @param id 复用怪物 id + * @param reuse 哪个怪物要复用此模板 */ - reusePrefab(source: number | string, code: number, id: string): void; + reusePrefab(source: number | string, reuse: number | string): void; /** * 设置参考快照,后续对模板的修改将与此比较以确定是否脏。 @@ -265,11 +224,11 @@ export interface IEnemyManager extends ISaveableContent< /** * 修改指定怪物模板的属性,修改完成后自动与参考模板比较并更新 dirty 集合 - * @param code 怪物的图块数字或 `id` + * @param token 怪物的图块数字或 `id` * @param modify 修改函数,传入可写怪物对象,返回修改后的对象 */ modifyPrefabAttribute( - code: number | string, + token: number | string, modify: (prefab: IEnemy) => IEnemy ): void;