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 { BaseProps, TagDefine } from '@motajs/render-vue';
|
||||||
import { ERenderItemEvent, SizedCanvasImageSource } from '@motajs/render';
|
import { ERenderItemEvent, SizedCanvasImageSource } from '@motajs/render';
|
||||||
import { ILayerState } from '@user/data-state';
|
import { ILayerState } from '@user/data-base';
|
||||||
import { IMapExtensionManager, IMapRenderer } from '../map';
|
import { IMapExtensionManager, IMapRenderer } from '../map';
|
||||||
|
|
||||||
export interface IconProps extends BaseProps {
|
export interface IconProps extends BaseProps {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { MotaOffscreenCanvas2D, RenderItem } from '@motajs/render';
|
import { MotaOffscreenCanvas2D, RenderItem } from '@motajs/render';
|
||||||
import { ILayerState } from '@user/data-state';
|
import { ILayerState } from '@user/data-base';
|
||||||
import { IMapRenderer } from './types';
|
import { IMapRenderer } from './types';
|
||||||
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
import { ElementNamespace, ComponentInternalInstance } from 'vue';
|
||||||
import { CELL_HEIGHT, CELL_WIDTH, MAP_HEIGHT, MAP_WIDTH } from '../../shared';
|
import { CELL_HEIGHT, CELL_WIDTH, MAP_HEIGHT, MAP_WIDTH } from '../../shared';
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import {
|
|||||||
IMapLayer,
|
IMapLayer,
|
||||||
IMapLayerHookController,
|
IMapLayerHookController,
|
||||||
IMapLayerHooks
|
IMapLayerHooks
|
||||||
} from '@user/data-state';
|
} from '@user/data-base';
|
||||||
import { IMapDoorRenderer } from './types';
|
import { IMapDoorRenderer } from './types';
|
||||||
import { IMapRenderer } from '../types';
|
import { IMapRenderer } from '../types';
|
||||||
import { sleep } from 'mutate-animate';
|
import { sleep } from 'mutate-animate';
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import {
|
|||||||
IHeroMovingHooks,
|
IHeroMovingHooks,
|
||||||
nextFaceDirection
|
nextFaceDirection
|
||||||
} from '@user/data-base';
|
} from '@user/data-base';
|
||||||
import { IMapLayer, state } from '@user/data-state';
|
import { IMapLayer } from '@user/data-base';
|
||||||
import { IMapRenderer, IMapRendererTicker, IMovingBlock } from '../types';
|
import { IMapRenderer, IMapRendererTicker, IMovingBlock } from '../types';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
import { IHookController, logger } from '@motajs/common';
|
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 { ITexture, ITextureSplitter, TextureRowSplitter } from '@motajs/render';
|
||||||
import { IMapHeroRenderer } from './types';
|
import { IMapHeroRenderer } from './types';
|
||||||
import { TimingFn } from 'mutate-animate';
|
import { TimingFn } from 'mutate-animate';
|
||||||
|
import { state } from '@user/data-state';
|
||||||
|
|
||||||
/** 默认的移动时长 */
|
/** 默认的移动时长 */
|
||||||
const DEFAULT_TIME = 100;
|
const DEFAULT_TIME = 100;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { IHeroMover } from '@user/data-base';
|
import { IHeroMover } from '@user/data-base';
|
||||||
import { IMapLayer } from '@user/data-state';
|
import { IMapLayer } from '@user/data-base';
|
||||||
import {
|
import {
|
||||||
IMapDoorRenderer,
|
IMapDoorRenderer,
|
||||||
IMapExtensionManager,
|
IMapExtensionManager,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {
|
|||||||
HeroAnimateDirection,
|
HeroAnimateDirection,
|
||||||
IHeroMover
|
IHeroMover
|
||||||
} from '@user/data-base';
|
} from '@user/data-base';
|
||||||
import { IMapLayer } from '@user/data-state';
|
import { IMapLayer } from '@user/data-base';
|
||||||
|
|
||||||
import { IMapRenderResult } from '../types';
|
import { IMapRenderResult } from '../types';
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { linear, TimingFn } from 'mutate-animate';
|
|||||||
import { IMapRenderer, IMapVertexGenerator, IMovingBlock } from './types';
|
import { IMapRenderer, IMapVertexGenerator, IMovingBlock } from './types';
|
||||||
import { IMaterialFramedData, IMaterialManager } from '@user/client-base';
|
import { IMaterialFramedData, IMaterialManager } from '@user/client-base';
|
||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { IMapLayer } from '@user/data-state';
|
import { IMapLayer } from '@user/data-base';
|
||||||
import { DynamicBlockStatus } from './status';
|
import { DynamicBlockStatus } from './status';
|
||||||
|
|
||||||
export interface IMovingRenderer {
|
export interface IMovingRenderer {
|
||||||
|
|||||||
@ -30,7 +30,7 @@ import {
|
|||||||
MapTileBehavior,
|
MapTileBehavior,
|
||||||
MapTileSizeTestMode
|
MapTileSizeTestMode
|
||||||
} from './types';
|
} 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 { IHookController, logger } from '@motajs/common';
|
||||||
import { compileProgramWith } from '@motajs/client-base';
|
import { compileProgramWith } from '@motajs/client-base';
|
||||||
import { isNil, maxBy } from 'lodash-es';
|
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';
|
import { IBlockStatus, IMapVertexStatus } from './types';
|
||||||
|
|
||||||
export class StaticBlockStatus implements IBlockStatus {
|
export class StaticBlockStatus implements IBlockStatus {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import {
|
|||||||
IMaterialManager,
|
IMaterialManager,
|
||||||
ITrackedAssetData
|
ITrackedAssetData
|
||||||
} from '@user/client-base';
|
} from '@user/client-base';
|
||||||
import { ILayerState, IMapLayer } from '@user/data-state';
|
import { ILayerState, IMapLayer } from '@user/data-base';
|
||||||
import { TimingFn } from 'mutate-animate';
|
import { TimingFn } from 'mutate-animate';
|
||||||
|
|
||||||
export const enum MapBackgroundRepeat {
|
export const enum MapBackgroundRepeat {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { IMapLayer } from '@user/data-state';
|
import { IMapLayer } from '@user/data-base';
|
||||||
import {
|
import {
|
||||||
IBlockData,
|
IBlockData,
|
||||||
IBlockSplitter,
|
IBlockSplitter,
|
||||||
|
|||||||
@ -24,6 +24,10 @@ export class EnemyManager<TAttr> implements IEnemyManager<TAttr> {
|
|||||||
private readonly prefabById: Map<string, IEnemy<TAttr>> = new Map();
|
private readonly prefabById: Map<string, IEnemy<TAttr>> = new Map();
|
||||||
/** 旧样板怪物 id 到 code 的映射,用于 fromLegacyEnemy 快速查找已有模板 */
|
/** 旧样板怪物 id 到 code 的映射,用于 fromLegacyEnemy 快速查找已有模板 */
|
||||||
private readonly legacyIdToCode: Map<string, number> = new Map();
|
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 */
|
/** 脏模板集合,存储发生了变化的模板 code */
|
||||||
private readonly dirtySet: Set<number> = new Set();
|
private readonly dirtySet: Set<number> = new Set();
|
||||||
/** 参考快照,code -> IReadonlyEnemy,由 compareWith 提供 */
|
/** 参考快照,code -> IReadonlyEnemy,由 compareWith 提供 */
|
||||||
@ -124,9 +128,11 @@ export class EnemyManager<TAttr> implements IEnemyManager<TAttr> {
|
|||||||
|
|
||||||
private internalGetPrefab(code: number | string) {
|
private internalGetPrefab(code: number | string) {
|
||||||
if (typeof code === 'number') {
|
if (typeof code === 'number') {
|
||||||
return this.prefabByCode.get(code) ?? null;
|
const sourceCode = this.reuseByCode.get(code) ?? code;
|
||||||
|
return this.prefabByCode.get(sourceCode) ?? null;
|
||||||
} else {
|
} 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 {
|
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 {
|
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 {
|
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 {
|
reusePrefab(source: number | string, code: number, id: string): void {
|
||||||
const prefab = this.internalGetPrefab(source);
|
const prefab = this.internalGetPrefab(source);
|
||||||
if (!prefab) return;
|
if (!prefab) return;
|
||||||
this.prefabByCode.set(code, prefab);
|
this.reuseByCode.set(code, prefab.code);
|
||||||
this.prefabById.set(id, prefab);
|
this.reuseById.set(id, prefab.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
compareWith(reference: ReadonlyMap<number, IReadonlyEnemy<TAttr>>): void {
|
compareWith(reference: ReadonlyMap<number, IReadonlyEnemy<TAttr>>): void {
|
||||||
|
|||||||
@ -22,7 +22,8 @@ import {
|
|||||||
FaceDirection,
|
FaceDirection,
|
||||||
ISaveableContent,
|
ISaveableContent,
|
||||||
IStateSaveData,
|
IStateSaveData,
|
||||||
SaveCompression
|
SaveCompression,
|
||||||
|
IReadonlyEnemy
|
||||||
} from '@user/data-base';
|
} from '@user/data-base';
|
||||||
import { IEnemyAttr } from './enemy';
|
import { IEnemyAttr } from './enemy';
|
||||||
import {
|
import {
|
||||||
@ -42,6 +43,7 @@ import { isNil } from 'lodash-es';
|
|||||||
import { logger } from '@motajs/common';
|
import { logger } from '@motajs/common';
|
||||||
import { ISaveSystem } from './save';
|
import { ISaveSystem } from './save';
|
||||||
import { SaveSystem } from './save/system';
|
import { SaveSystem } from './save/system';
|
||||||
|
import { MainEnemyComparer } from './enemy/comparer';
|
||||||
|
|
||||||
export class CoreState implements ICoreState {
|
export class CoreState implements ICoreState {
|
||||||
// 全局内容
|
// 全局内容
|
||||||
@ -92,7 +94,9 @@ export class CoreState implements ICoreState {
|
|||||||
//#region 怪物初始化
|
//#region 怪物初始化
|
||||||
|
|
||||||
// 怪物管理器初始化
|
// 怪物管理器初始化
|
||||||
|
const comparer = new MainEnemyComparer();
|
||||||
const enemyManager = new EnemyManager(new EnemyLegacyBridge());
|
const enemyManager = new EnemyManager(new EnemyLegacyBridge());
|
||||||
|
enemyManager.attachEnemyComparer(comparer);
|
||||||
enemyManager.setAttributeDefaults('hp', 0);
|
enemyManager.setAttributeDefaults('hp', 0);
|
||||||
enemyManager.setAttributeDefaults('atk', 0);
|
enemyManager.setAttributeDefaults('atk', 0);
|
||||||
enemyManager.setAttributeDefaults('def', 0);
|
enemyManager.setAttributeDefaults('def', 0);
|
||||||
@ -159,6 +163,7 @@ export class CoreState implements ICoreState {
|
|||||||
private initEnemyManager(data: Record<EnemyIds, Enemy>) {
|
private initEnemyManager(data: Record<EnemyIds, Enemy>) {
|
||||||
// TODO: 修改怪物模板并存入存档,即 core.setEnemy
|
// TODO: 修改怪物模板并存入存档,即 core.setEnemy
|
||||||
const manager = this.enemyManager;
|
const manager = this.enemyManager;
|
||||||
|
const reference = new Map<number, IReadonlyEnemy<IEnemyAttr>>();
|
||||||
for (const [id, enemy] of Object.entries(structuredClone(data))) {
|
for (const [id, enemy] of Object.entries(structuredClone(data))) {
|
||||||
const num = this.idNumberMap.get(id);
|
const num = this.idNumberMap.get(id);
|
||||||
if (isNil(num)) continue;
|
if (isNil(num)) continue;
|
||||||
@ -169,7 +174,9 @@ export class CoreState implements ICoreState {
|
|||||||
const upCode = this.idNumberMap.get(up)!;
|
const upCode = this.idNumberMap.get(up)!;
|
||||||
const rightCode = this.idNumberMap.get(right)!;
|
const rightCode = this.idNumberMap.get(right)!;
|
||||||
const downCode = this.idNumberMap.get(down)!;
|
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.malloc(downCode, FaceDirection.Down);
|
||||||
this.roleFace.bind(leftCode, downCode, FaceDirection.Left);
|
this.roleFace.bind(leftCode, downCode, FaceDirection.Left);
|
||||||
this.roleFace.bind(upCode, downCode, FaceDirection.Up);
|
this.roleFace.bind(upCode, downCode, FaceDirection.Up);
|
||||||
@ -178,9 +185,12 @@ export class CoreState implements ICoreState {
|
|||||||
manager.reusePrefab(num, upCode, up);
|
manager.reusePrefab(num, upCode, up);
|
||||||
manager.reusePrefab(num, rightCode, right);
|
manager.reusePrefab(num, rightCode, right);
|
||||||
} else {
|
} 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 {
|
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 EventEmitter from 'eventemitter3';
|
||||||
import { backDir, toDir } from './utils';
|
import { backDir, toDir } from './utils';
|
||||||
import { loading } from '@user/data-base';
|
import { fromDirectionString, loading } from '@user/data-base';
|
||||||
import type { RenderAdapter } from '@motajs/render';
|
|
||||||
import type { HeroKeyMover } from '@user/client-modules';
|
import type { HeroKeyMover } from '@user/client-modules';
|
||||||
import { sleep } from '@motajs/common';
|
import { sleep } from '@motajs/common';
|
||||||
import { fromDirectionString, state } from '..';
|
import { state } from '..';
|
||||||
|
|
||||||
// todo: 转身功能
|
// todo: 转身功能
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,6 @@
|
|||||||
import type { TimingFn } from 'mutate-animate';
|
import type { TimingFn } from 'mutate-animate';
|
||||||
import {
|
import { heroMoveCollection, MoveStep, state } from '@user/data-state';
|
||||||
fromDirectionString,
|
import { fromDirectionString, hook, loading } from '@user/data-base';
|
||||||
heroMoveCollection,
|
|
||||||
MoveStep,
|
|
||||||
state
|
|
||||||
} from '@user/data-state';
|
|
||||||
import { hook, loading } from '@user/data-base';
|
|
||||||
import { Patch, PatchClass } from '@motajs/legacy-common';
|
import { Patch, PatchClass } from '@motajs/legacy-common';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
|
|
||||||
@ -59,8 +54,6 @@ export function initFallback() {
|
|||||||
|
|
||||||
Mota.r(() => {
|
Mota.r(() => {
|
||||||
// ----- 引入
|
// ----- 引入
|
||||||
const { mainRenderer } = Mota.require('@user/client-modules');
|
|
||||||
const Animation = Mota.require('MutateAnimate');
|
|
||||||
|
|
||||||
const patch = new Patch(PatchClass.Control);
|
const patch = new Patch(PatchClass.Control);
|
||||||
const patch2 = new Patch(PatchClass.Events);
|
const patch2 = new Patch(PatchClass.Events);
|
||||||
|
|||||||
@ -29,8 +29,10 @@ export function getDetailedEnemy(
|
|||||||
return typeof func === 'string' ? func : func(enemy);
|
return typeof func === 'string' ? func : func(enemy);
|
||||||
};
|
};
|
||||||
const special: [string, string, string][] = [...enemy.info.special]
|
const special: [string, string, string][] = [...enemy.info.special]
|
||||||
|
// @ts-expect-error 之后修
|
||||||
.filter(v => !enemy.info.specialHalo?.includes(v))
|
.filter(v => !enemy.info.specialHalo?.includes(v))
|
||||||
.map(vv => {
|
.map(vv => {
|
||||||
|
// @ts-expect-error 之后修
|
||||||
const s = Mota.require('@user/data-state').specials[vv];
|
const s = Mota.require('@user/data-state').specials[vv];
|
||||||
return [
|
return [
|
||||||
fromFunc(s.name, enemy.info),
|
fromFunc(s.name, enemy.info),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user