diff --git a/packages-user/client-modules/src/render/elements/props.ts b/packages-user/client-modules/src/render/elements/props.ts index ce4da18..a3c7a7d 100644 --- a/packages-user/client-modules/src/render/elements/props.ts +++ b/packages-user/client-modules/src/render/elements/props.ts @@ -1,6 +1,6 @@ import { BaseProps, TagDefine } from '@motajs/render-vue'; import { ERenderItemEvent, SizedCanvasImageSource } from '@motajs/render'; -import { ILayerState } from '@user/data-state'; +import { ILayerState } from '@user/data-base'; import { IMapExtensionManager, IMapRenderer } from '../map'; export interface IconProps extends BaseProps { diff --git a/packages-user/client-modules/src/render/map/element.ts b/packages-user/client-modules/src/render/map/element.ts index 11487d8..a2352dd 100644 --- a/packages-user/client-modules/src/render/map/element.ts +++ b/packages-user/client-modules/src/render/map/element.ts @@ -1,5 +1,5 @@ import { MotaOffscreenCanvas2D, RenderItem } from '@motajs/render'; -import { ILayerState } from '@user/data-state'; +import { ILayerState } from '@user/data-base'; import { IMapRenderer } from './types'; import { ElementNamespace, ComponentInternalInstance } from 'vue'; import { CELL_HEIGHT, CELL_WIDTH, MAP_HEIGHT, MAP_WIDTH } from '../../shared'; diff --git a/packages-user/client-modules/src/render/map/extension/door.ts b/packages-user/client-modules/src/render/map/extension/door.ts index ce08fc5..7420ddc 100644 --- a/packages-user/client-modules/src/render/map/extension/door.ts +++ b/packages-user/client-modules/src/render/map/extension/door.ts @@ -2,7 +2,7 @@ import { IMapLayer, IMapLayerHookController, IMapLayerHooks -} from '@user/data-state'; +} from '@user/data-base'; import { IMapDoorRenderer } from './types'; import { IMapRenderer } from '../types'; import { sleep } from 'mutate-animate'; diff --git a/packages-user/client-modules/src/render/map/extension/hero.ts b/packages-user/client-modules/src/render/map/extension/hero.ts index 039ed77..e28d05a 100644 --- a/packages-user/client-modules/src/render/map/extension/hero.ts +++ b/packages-user/client-modules/src/render/map/extension/hero.ts @@ -7,7 +7,7 @@ import { IHeroMovingHooks, nextFaceDirection } from '@user/data-base'; -import { IMapLayer, state } from '@user/data-state'; +import { IMapLayer } from '@user/data-base'; import { IMapRenderer, IMapRendererTicker, IMovingBlock } from '../types'; import { isNil } from 'lodash-es'; import { IHookController, logger } from '@motajs/common'; @@ -15,6 +15,7 @@ import { BlockCls, IMaterialFramedData } from '@user/client-base'; import { ITexture, ITextureSplitter, TextureRowSplitter } from '@motajs/render'; import { IMapHeroRenderer } from './types'; import { TimingFn } from 'mutate-animate'; +import { state } from '@user/data-state'; /** 默认的移动时长 */ const DEFAULT_TIME = 100; diff --git a/packages-user/client-modules/src/render/map/extension/manager.ts b/packages-user/client-modules/src/render/map/extension/manager.ts index 41c6481..4a01b30 100644 --- a/packages-user/client-modules/src/render/map/extension/manager.ts +++ b/packages-user/client-modules/src/render/map/extension/manager.ts @@ -1,5 +1,5 @@ import { IHeroMover } from '@user/data-base'; -import { IMapLayer } from '@user/data-state'; +import { IMapLayer } from '@user/data-base'; import { IMapDoorRenderer, IMapExtensionManager, diff --git a/packages-user/client-modules/src/render/map/extension/types.ts b/packages-user/client-modules/src/render/map/extension/types.ts index 82577d0..bd685cc 100644 --- a/packages-user/client-modules/src/render/map/extension/types.ts +++ b/packages-user/client-modules/src/render/map/extension/types.ts @@ -4,7 +4,7 @@ import { HeroAnimateDirection, IHeroMover } from '@user/data-base'; -import { IMapLayer } from '@user/data-state'; +import { IMapLayer } from '@user/data-base'; import { IMapRenderResult } from '../types'; diff --git a/packages-user/client-modules/src/render/map/moving.ts b/packages-user/client-modules/src/render/map/moving.ts index 8c89b9b..ea464cb 100644 --- a/packages-user/client-modules/src/render/map/moving.ts +++ b/packages-user/client-modules/src/render/map/moving.ts @@ -2,7 +2,7 @@ import { linear, TimingFn } from 'mutate-animate'; import { IMapRenderer, IMapVertexGenerator, IMovingBlock } from './types'; import { IMaterialFramedData, IMaterialManager } from '@user/client-base'; import { logger } from '@motajs/common'; -import { IMapLayer } from '@user/data-state'; +import { IMapLayer } from '@user/data-base'; import { DynamicBlockStatus } from './status'; export interface IMovingRenderer { diff --git a/packages-user/client-modules/src/render/map/renderer.ts b/packages-user/client-modules/src/render/map/renderer.ts index df54f0d..6292c82 100644 --- a/packages-user/client-modules/src/render/map/renderer.ts +++ b/packages-user/client-modules/src/render/map/renderer.ts @@ -30,7 +30,7 @@ import { MapTileBehavior, MapTileSizeTestMode } from './types'; -import { ILayerState, ILayerStateHooks, IMapLayer } from '@user/data-state'; +import { ILayerState, ILayerStateHooks, IMapLayer } from '@user/data-base'; import { IHookController, logger } from '@motajs/common'; import { compileProgramWith } from '@motajs/client-base'; import { isNil, maxBy } from 'lodash-es'; diff --git a/packages-user/client-modules/src/render/map/status.ts b/packages-user/client-modules/src/render/map/status.ts index 922b14b..979abaa 100644 --- a/packages-user/client-modules/src/render/map/status.ts +++ b/packages-user/client-modules/src/render/map/status.ts @@ -1,4 +1,4 @@ -import { IMapLayer } from '@user/data-state'; +import { IMapLayer } from '@user/data-base'; import { IBlockStatus, IMapVertexStatus } from './types'; export class StaticBlockStatus implements IBlockStatus { diff --git a/packages-user/client-modules/src/render/map/types.ts b/packages-user/client-modules/src/render/map/types.ts index 8b93aa0..438586c 100644 --- a/packages-user/client-modules/src/render/map/types.ts +++ b/packages-user/client-modules/src/render/map/types.ts @@ -10,7 +10,7 @@ import { IMaterialManager, ITrackedAssetData } from '@user/client-base'; -import { ILayerState, IMapLayer } from '@user/data-state'; +import { ILayerState, IMapLayer } from '@user/data-base'; import { TimingFn } from 'mutate-animate'; export const enum MapBackgroundRepeat { diff --git a/packages-user/client-modules/src/render/map/vertex.ts b/packages-user/client-modules/src/render/map/vertex.ts index e9bb9a5..a8ca1af 100644 --- a/packages-user/client-modules/src/render/map/vertex.ts +++ b/packages-user/client-modules/src/render/map/vertex.ts @@ -1,4 +1,4 @@ -import { IMapLayer } from '@user/data-state'; +import { IMapLayer } from '@user/data-base'; import { IBlockData, IBlockSplitter, diff --git a/packages-user/data-base/src/enemy/manager.ts b/packages-user/data-base/src/enemy/manager.ts index 210f601..915bd56 100644 --- a/packages-user/data-base/src/enemy/manager.ts +++ b/packages-user/data-base/src/enemy/manager.ts @@ -24,6 +24,10 @@ export class EnemyManager implements IEnemyManager { 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 提供 */ @@ -124,9 +128,11 @@ export class EnemyManager implements IEnemyManager { private internalGetPrefab(code: number | string) { if (typeof code === 'number') { - return this.prefabByCode.get(code) ?? null; + const sourceCode = this.reuseByCode.get(code) ?? code; + return this.prefabByCode.get(sourceCode) ?? null; } else { - return this.prefabById.get(code) ?? null; + const sourceId = this.reuseById.get(code) ?? code; + return this.prefabById.get(sourceId) ?? null; } } @@ -155,11 +161,13 @@ export class EnemyManager implements IEnemyManager { } getPrefab(code: number): IReadonlyEnemy | null { - return this.prefabByCode.get(code) ?? null; + const sourceCode = this.reuseByCode.get(code) ?? code; + return this.prefabByCode.get(sourceCode) ?? null; } getPrefabById(id: string): IReadonlyEnemy | null { - return this.prefabById.get(id) ?? null; + const sourceId = this.reuseById.get(id) ?? id; + return this.prefabById.get(sourceId) ?? null; } deletePrefab(code: number | string): void { @@ -181,8 +189,8 @@ export class EnemyManager implements IEnemyManager { reusePrefab(source: number | string, code: number, id: string): void { const prefab = this.internalGetPrefab(source); if (!prefab) return; - this.prefabByCode.set(code, prefab); - this.prefabById.set(id, prefab); + this.reuseByCode.set(code, prefab.code); + this.reuseById.set(id, prefab.id); } compareWith(reference: ReadonlyMap>): void { diff --git a/packages-user/data-state/src/core.ts b/packages-user/data-state/src/core.ts index 47135f2..d1eaa10 100644 --- a/packages-user/data-state/src/core.ts +++ b/packages-user/data-state/src/core.ts @@ -22,7 +22,8 @@ import { FaceDirection, ISaveableContent, IStateSaveData, - SaveCompression + SaveCompression, + IReadonlyEnemy } from '@user/data-base'; import { IEnemyAttr } from './enemy'; import { @@ -42,6 +43,7 @@ import { isNil } from 'lodash-es'; import { logger } from '@motajs/common'; import { ISaveSystem } from './save'; import { SaveSystem } from './save/system'; +import { MainEnemyComparer } from './enemy/comparer'; export class CoreState implements ICoreState { // 全局内容 @@ -92,7 +94,9 @@ export class CoreState implements ICoreState { //#region 怪物初始化 // 怪物管理器初始化 + const comparer = new MainEnemyComparer(); const enemyManager = new EnemyManager(new EnemyLegacyBridge()); + enemyManager.attachEnemyComparer(comparer); enemyManager.setAttributeDefaults('hp', 0); enemyManager.setAttributeDefaults('atk', 0); enemyManager.setAttributeDefaults('def', 0); @@ -159,6 +163,7 @@ export class CoreState implements ICoreState { private initEnemyManager(data: Record) { // TODO: 修改怪物模板并存入存档,即 core.setEnemy const manager = this.enemyManager; + const reference = new Map>(); for (const [id, enemy] of Object.entries(structuredClone(data))) { const num = this.idNumberMap.get(id); if (isNil(num)) continue; @@ -169,7 +174,9 @@ export class CoreState implements ICoreState { const upCode = this.idNumberMap.get(up)!; const rightCode = this.idNumberMap.get(right)!; const downCode = this.idNumberMap.get(down)!; - manager.addPrefabFromLegacy(downCode, enemy); + const prefab = manager.fromLegacyEnemy(downCode, enemy); + reference.set(downCode, prefab); + manager.addPrefab(prefab); this.roleFace.malloc(downCode, FaceDirection.Down); this.roleFace.bind(leftCode, downCode, FaceDirection.Left); this.roleFace.bind(upCode, downCode, FaceDirection.Up); @@ -178,9 +185,12 @@ export class CoreState implements ICoreState { manager.reusePrefab(num, upCode, up); manager.reusePrefab(num, rightCode, right); } else { - manager.addPrefabFromLegacy(num, enemy); + const prefab = manager.fromLegacyEnemy(num, enemy); + reference.set(num, prefab); + manager.addPrefab(prefab); } } + manager.compareWith(reference); } addSaveableContent(id: string, content: ISaveableContent): void { diff --git a/packages-user/data-state/src/enemy/comparer.ts b/packages-user/data-state/src/enemy/comparer.ts new file mode 100644 index 0000000..a04bef7 --- /dev/null +++ b/packages-user/data-state/src/enemy/comparer.ts @@ -0,0 +1,31 @@ +import { IEnemyComparer, IReadonlyEnemy } from '@user/data-base'; +import { IEnemyAttr } from './types'; + +export class MainEnemyComparer implements IEnemyComparer { + compare( + enemyA: IReadonlyEnemy, + enemyB: IReadonlyEnemy + ): boolean { + // 比较基本属性 + if ( + enemyA.getAttribute('hp') !== enemyB.getAttribute('hp') || + enemyA.getAttribute('atk') !== enemyB.getAttribute('atk') || + enemyA.getAttribute('def') !== enemyB.getAttribute('def') || + enemyA.getAttribute('money') !== enemyB.getAttribute('money') || + enemyA.getAttribute('exp') !== enemyB.getAttribute('exp') || + enemyA.getAttribute('point') !== enemyB.getAttribute('point') + ) { + return false; + } + + // 比较特殊属性 + const specialsA = [...enemyA.iterateSpecials()]; + const specialsB = [...enemyB.iterateSpecials()]; + if (specialsA.length !== specialsB.length) return false; + for (const special of specialsA) { + const other = enemyB.getSpecial(special.code); + if (!other || !special.deepEqualsTo(other)) return false; + } + return true; + } +} diff --git a/packages-user/data-state/src/legacy/move.ts b/packages-user/data-state/src/legacy/move.ts index 51e4509..48c3aa3 100644 --- a/packages-user/data-state/src/legacy/move.ts +++ b/packages-user/data-state/src/legacy/move.ts @@ -1,10 +1,9 @@ import EventEmitter from 'eventemitter3'; import { backDir, toDir } from './utils'; -import { loading } from '@user/data-base'; -import type { RenderAdapter } from '@motajs/render'; +import { fromDirectionString, loading } from '@user/data-base'; import type { HeroKeyMover } from '@user/client-modules'; import { sleep } from '@motajs/common'; -import { fromDirectionString, state } from '..'; +import { state } from '..'; // todo: 转身功能 diff --git a/packages-user/legacy-plugin-data/src/fallback.ts b/packages-user/legacy-plugin-data/src/fallback.ts index 8519db7..1271d38 100644 --- a/packages-user/legacy-plugin-data/src/fallback.ts +++ b/packages-user/legacy-plugin-data/src/fallback.ts @@ -1,11 +1,6 @@ import type { TimingFn } from 'mutate-animate'; -import { - fromDirectionString, - heroMoveCollection, - MoveStep, - state -} from '@user/data-state'; -import { hook, loading } from '@user/data-base'; +import { heroMoveCollection, MoveStep, state } from '@user/data-state'; +import { fromDirectionString, hook, loading } from '@user/data-base'; import { Patch, PatchClass } from '@motajs/legacy-common'; import { isNil } from 'lodash-es'; @@ -59,8 +54,6 @@ export function initFallback() { Mota.r(() => { // ----- 引入 - const { mainRenderer } = Mota.require('@user/client-modules'); - const Animation = Mota.require('MutateAnimate'); const patch = new Patch(PatchClass.Control); const patch2 = new Patch(PatchClass.Events); diff --git a/packages/legacy-ui/src/tools/fixed.ts b/packages/legacy-ui/src/tools/fixed.ts index 2383108..ba05235 100644 --- a/packages/legacy-ui/src/tools/fixed.ts +++ b/packages/legacy-ui/src/tools/fixed.ts @@ -29,8 +29,10 @@ export function getDetailedEnemy( return typeof func === 'string' ? func : func(enemy); }; const special: [string, string, string][] = [...enemy.info.special] + // @ts-expect-error 之后修 .filter(v => !enemy.info.specialHalo?.includes(v)) .map(vv => { + // @ts-expect-error 之后修 const s = Mota.require('@user/data-state').specials[vv]; return [ fromFunc(s.name, enemy.info),