mirror of
https://github.com/motajs/template.git
synced 2026-05-02 12:23:13 +08:00
refactor: manager 的复用方案 & fix: 类型错误
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
2ce50bf23e
commit
476f735adc
@ -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 {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { IMapLayer } from '@user/data-state';
|
||||
import { IMapLayer } from '@user/data-base';
|
||||
import {
|
||||
IBlockData,
|
||||
IBlockSplitter,
|
||||
|
||||
@ -24,6 +24,10 @@ export class EnemyManager<TAttr> implements IEnemyManager<TAttr> {
|
||||
private readonly prefabById: Map<string, IEnemy<TAttr>> = new Map();
|
||||
/** 旧样板怪物 id 到 code 的映射,用于 fromLegacyEnemy 快速查找已有模板 */
|
||||
private readonly legacyIdToCode: Map<string, number> = new Map();
|
||||
/** 复用映射,reusedCode -> sourceCode */
|
||||
private readonly reuseByCode: Map<number, number> = new Map();
|
||||
/** 复用映射,reusedId -> sourceId */
|
||||
private readonly reuseById: Map<string, string> = new Map();
|
||||
/** 脏模板集合,存储发生了变化的模板 code */
|
||||
private readonly dirtySet: Set<number> = new Set();
|
||||
/** 参考快照,code -> IReadonlyEnemy,由 compareWith 提供 */
|
||||
@ -124,9 +128,11 @@ export class EnemyManager<TAttr> implements IEnemyManager<TAttr> {
|
||||
|
||||
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<TAttr> implements IEnemyManager<TAttr> {
|
||||
}
|
||||
|
||||
getPrefab(code: number): IReadonlyEnemy<TAttr> | null {
|
||||
return this.prefabByCode.get(code) ?? null;
|
||||
const sourceCode = this.reuseByCode.get(code) ?? code;
|
||||
return this.prefabByCode.get(sourceCode) ?? null;
|
||||
}
|
||||
|
||||
getPrefabById(id: string): IReadonlyEnemy<TAttr> | 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<TAttr> implements IEnemyManager<TAttr> {
|
||||
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<number, IReadonlyEnemy<TAttr>>): void {
|
||||
|
||||
@ -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<EnemyIds, Enemy>) {
|
||||
// TODO: 修改怪物模板并存入存档,即 core.setEnemy
|
||||
const manager = this.enemyManager;
|
||||
const reference = new Map<number, IReadonlyEnemy<IEnemyAttr>>();
|
||||
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<unknown>): void {
|
||||
|
||||
31
packages-user/data-state/src/enemy/comparer.ts
Normal file
31
packages-user/data-state/src/enemy/comparer.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { IEnemyComparer, IReadonlyEnemy } from '@user/data-base';
|
||||
import { IEnemyAttr } from './types';
|
||||
|
||||
export class MainEnemyComparer implements IEnemyComparer<IEnemyAttr> {
|
||||
compare(
|
||||
enemyA: IReadonlyEnemy<IEnemyAttr>,
|
||||
enemyB: IReadonlyEnemy<IEnemyAttr>
|
||||
): 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;
|
||||
}
|
||||
}
|
||||
@ -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: 转身功能
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user