From 370f285964aff3a7a9f9e7adf0c72466d61154d5 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Sun, 17 May 2026 23:56:40 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=88=A0=E9=99=A4=E6=B1=A1?= =?UTF-8?q?=E6=9F=93=E4=B8=A5=E9=87=8D=E7=9A=84=20TEnemy=20=E5=92=8C=20THe?= =?UTF-8?q?ro=EF=BC=8C=E4=BB=85=E5=9C=A8=E6=88=98=E6=96=97=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E4=B8=AD=E5=8C=85=E5=90=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages-user/data-base/src/enemy/manager.ts | 66 ++++---- packages-user/data-base/src/types.ts | 17 +- packages-user/data-common/src/types.ts | 41 +++++ packages-user/data-state/src/core.ts | 18 +- packages-user/data-state/src/enemy/aura.ts | 5 +- .../data-state/src/enemy/calculator.ts | 12 +- .../data-state/src/enemy/comparer.ts | 2 +- packages-user/data-state/src/enemy/final.ts | 3 +- packages-user/data-state/src/enemy/legacy.ts | 2 +- .../data-state/src/enemy/mapDamage.ts | 4 +- packages-user/data-state/src/enemy/special.ts | 2 +- packages-user/data-state/src/enemy/types.ts | 6 +- packages-user/data-state/src/hero/types.ts | 23 +-- packages-user/data-state/src/shared.ts | 2 +- packages-user/data-state/src/types.ts | 8 +- .../data-system/src/combat/context.ts | 10 +- .../data-system/src/combat/damage.ts | 10 +- .../data-system/src/combat/mapDamage.ts | 3 +- packages-user/data-system/src/combat/types.ts | 156 ++++++++++-------- .../data-system/src/trigger/collection.ts | 29 ++-- .../data-system/src/trigger/collector.ts | 21 +-- .../data-system/src/trigger/registry.ts | 16 +- .../data-system/src/trigger/types.ts | 61 +++---- packages-user/data-system/src/types.ts | 13 +- packages/common/src/logger.json | 3 +- 25 files changed, 276 insertions(+), 257 deletions(-) diff --git a/packages-user/data-base/src/enemy/manager.ts b/packages-user/data-base/src/enemy/manager.ts index 2cdff49..de12685 100644 --- a/packages-user/data-base/src/enemy/manager.ts +++ b/packages-user/data-base/src/enemy/manager.ts @@ -12,16 +12,18 @@ import { } from './types'; import { SaveCompression } from '@user/data-common'; -export class EnemyManager implements IEnemyManager { +export class EnemyManager implements IEnemyManager { /** 特殊属性注册表,code -> 创建函数 */ - private readonly specialRegistry: Map> = - new Map(); + private readonly specialRegistry: Map< + number, + SpecialCreation + > = new Map(); /** 自定义怪物属性注册表,name -> 默认值 */ - private readonly attributeRegistry: Map = new Map(); + private readonly attributeRegistry: Map = new Map(); /** 怪物模板表,code -> IEnemy */ - private readonly prefabByCode: Map> = new Map(); + private readonly prefabByCode: Map> = new Map(); /** 怪物模板表,id -> IEnemy */ - private readonly prefabById: Map> = new Map(); + private readonly prefabById: Map> = new Map(); /** 旧样板怪物 id 到 code 的映射,用于 fromLegacyEnemy 快速查找已有模板 */ private readonly legacyIdToCode: Map = new Map(); /** 复用映射,reusedCode -> sourceCode */ @@ -31,21 +33,21 @@ export class EnemyManager implements IEnemyManager { /** 脏模板集合,存储发生了变化的模板 code */ private readonly dirtySet: Set = new Set(); /** 参考快照,code -> IReadonlyEnemy,由 compareWith 提供 */ - private referenceByCode: Map> = new Map(); + private referenceByCode: Map> = new Map(); /** 当前附加的怪物比较器 */ - private comparer: IEnemyComparer | null = null; + private comparer: IEnemyComparer | null = null; /** 是否已首次调用 compareWith */ private hasReference: boolean = false; - constructor(readonly bridge: IEnemyLegacyBridge) {} + constructor(readonly bridge: IEnemyLegacyBridge) {} - registerSpecial(code: number, cons: SpecialCreation): void { + registerSpecial(code: number, cons: SpecialCreation): void { this.specialRegistry.set(code, cons); } - setAttributeDefaults( + setAttributeDefaults( name: K, - defaultValue: TAttr[K] + defaultValue: TEnemy[K] ): void { if ( typeof defaultValue === 'function' || @@ -59,7 +61,7 @@ export class EnemyManager implements IEnemyManager { this.attributeRegistry.set(name, defaultValue); } - fromLegacyEnemy(code: number, enemy: Enemy): IEnemy { + fromLegacyEnemy(code: number, enemy: Enemy): IEnemy { // 如果该旧样板怪物已经通过 addPrefabFromLegacy 注册为模板,直接克隆模板 const existingCode = this.legacyIdToCode.get(enemy.id); if (existingCode) { @@ -76,15 +78,15 @@ export class EnemyManager implements IEnemyManager { * 根据旧样板怪物与注册过的默认属性构造属性对象 * @param enemy 旧样板怪物对象 */ - private createAttributes(enemy: Enemy): TAttr { - const attrs: Partial = {}; + 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 TAttr; + return attrs as TEnemy; } /** @@ -92,9 +94,9 @@ export class EnemyManager implements IEnemyManager { * @param code 怪物图块数字 * @param enemy 旧样板怪物对象 */ - private convertLegacyEnemy(code: number, enemy: Enemy): IEnemy { + private convertLegacyEnemy(code: number, enemy: Enemy): IEnemy { const attrs = this.createAttributes(enemy); - const result = new EnemyImpl( + const result = new EnemyImpl( enemy.id, code, structuredClone(attrs) @@ -114,13 +116,13 @@ export class EnemyManager implements IEnemyManager { return result; } - createEnemy(code: number): IEnemy | null { + createEnemy(code: number): IEnemy | null { const prefab = this.prefabByCode.get(code); if (!prefab) return null; return prefab.clone(); } - createEnemyById(id: string): IEnemy | null { + createEnemyById(id: string): IEnemy | null { const prefab = this.prefabById.get(id); if (!prefab) return null; return prefab.clone(); @@ -136,7 +138,7 @@ export class EnemyManager implements IEnemyManager { } } - addPrefab(enemy: IEnemy): void { + addPrefab(enemy: IEnemy): void { if ( this.prefabByCode.has(enemy.code) || this.prefabById.has(enemy.id) @@ -160,12 +162,12 @@ export class EnemyManager implements IEnemyManager { this.updateDirty(code, prefab); } - getPrefab(code: number): IReadonlyEnemy | null { + getPrefab(code: number): IReadonlyEnemy | null { const sourceCode = this.reuseByCode.get(code) ?? code; return this.prefabByCode.get(sourceCode) ?? null; } - getPrefabById(id: string): IReadonlyEnemy | null { + getPrefabById(id: string): IReadonlyEnemy | null { const sourceId = this.reuseById.get(id) ?? id; return this.prefabById.get(sourceId) ?? null; } @@ -177,7 +179,7 @@ export class EnemyManager implements IEnemyManager { this.prefabById.delete(prefab.id); } - changePrefab(code: number | string, enemy: IEnemy): void { + changePrefab(code: number | string, enemy: IEnemy): void { // 先删除旧的模板(如果存在) this.deletePrefab(code); // 再添加新的模板 @@ -193,7 +195,7 @@ export class EnemyManager implements IEnemyManager { this.reuseById.set(id, prefab.id); } - compareWith(reference: ReadonlyMap>): void { + compareWith(reference: ReadonlyMap>): void { const isSubsequentCall = this.hasReference; if (isSubsequentCall) { logger.warn(117); @@ -211,7 +213,7 @@ export class EnemyManager implements IEnemyManager { modifyPrefabAttribute( code: number | string, - modify: (prefab: IEnemy) => IEnemy + modify: (prefab: IEnemy) => IEnemy ): void { const prefab = this.internalGetPrefab(code); if (!prefab) return; @@ -230,16 +232,16 @@ export class EnemyManager implements IEnemyManager { this.updateDirty(result.code, result); } - attachEnemyComparer(comparer: IEnemyComparer): void { + attachEnemyComparer(comparer: IEnemyComparer): void { this.comparer = comparer; } - getEnemyComparer(): IEnemyComparer | null { + getEnemyComparer(): IEnemyComparer | null { return this.comparer; } - saveState(compression: SaveCompression): IEnemyManagerSaveState { - const modified: Map> = new Map(); + saveState(compression: SaveCompression): IEnemyManagerSaveState { + const modified: Map> = new Map(); for (const code of this.dirtySet) { const prefab = this.prefabByCode.get(code); if (!prefab) continue; @@ -249,7 +251,7 @@ export class EnemyManager implements IEnemyManager { } loadState( - state: IEnemyManagerSaveState, + state: IEnemyManagerSaveState, compression: SaveCompression ): void { for (const [code, enemyState] of state.modified) { @@ -269,7 +271,7 @@ export class EnemyManager implements IEnemyManager { * @param code 怪物图块数字 * @param current 当前模板对象 */ - private updateDirty(code: number, current: IEnemy): void { + private updateDirty(code: number, current: IEnemy): void { if (!this.hasReference) return; if (!this.comparer) { logger.warn(118); diff --git a/packages-user/data-base/src/types.ts b/packages-user/data-base/src/types.ts index 796a4b6..5ac7cc1 100644 --- a/packages-user/data-base/src/types.ts +++ b/packages-user/data-base/src/types.ts @@ -2,21 +2,26 @@ import { IHeroFollower, IHeroState } from './hero'; import { IEnemyManager } from './enemy'; import { IFlagSystem } from './flag'; import { IMapStore } from './map'; -import { IDataCommon, ISaveableContent } from '@user/data-common'; +import { + IDataCommon, + IEnemyAttr, + IHeroAttr, + ISaveableContent +} from '@user/data-common'; export interface IStateSaveData { /** 跟随者列表 */ readonly followers: readonly IHeroFollower[]; } -export interface IStateBase extends IDataCommon { +export interface IStateBase extends IDataCommon { /** 地图状态 */ readonly maps: IMapStore; /** 勇士状态 */ - readonly hero: IHeroState; + readonly hero: IHeroState; /** 怪物管理器 */ - readonly enemyManager: IEnemyManager; + readonly enemyManager: IEnemyManager; /** Flag 系统 */ readonly flags: IFlagSystem; @@ -35,7 +40,7 @@ export interface IStateBase extends IDataCommon { getSaveableContent(id: string): ISaveableContent | null; } -export interface IStateBaseExtended { +export interface IStateBaseExtended { /** 当前对象对应的数据层对象(Layer 1 对象) */ - readonly state: IStateBase; + readonly state: IStateBase; } diff --git a/packages-user/data-common/src/types.ts b/packages-user/data-common/src/types.ts index dffe3f9..75efc3c 100644 --- a/packages-user/data-common/src/types.ts +++ b/packages-user/data-common/src/types.ts @@ -1,6 +1,47 @@ +import { ITileLocator } from '@motajs/common'; import { IFaceManager, IRoleFaceBinder } from './common'; import { ITileStore } from './store'; +export interface IEnemyAttr { + /** 怪物生命值 */ + hp: number; + /** 怪物攻击力 */ + atk: number; + /** 怪物防御力 */ + def: number; + /** 怪物金币 */ + money: number; + /** 怪物经验值 */ + exp: number; + /** 怪物加点量 */ + point: number; + /** 支援来源怪物坐标索引列表 */ + guard: Set; +} + +export interface IHeroAttr { + /** 勇士名称 */ + name: string; + /** 勇士生命值 */ + hp: number; + /** 勇士生命值上限 */ + hpmax: number; + /** 勇士攻击力 */ + atk: number; + /** 勇士防御力 */ + def: number; + /** 勇士护盾 */ + mdef: number; + /** 勇士魔法值 */ + mana: number; + /** 勇士魔法上限 */ + manamax: number; + /** 勇士拥有的金币 */ + money: number; + /** 勇士拥有的经验 */ + exp: number; +} + export interface IDataCommon { /** 图块定义存储 */ readonly tileStore: ITileStore>; diff --git a/packages-user/data-state/src/core.ts b/packages-user/data-state/src/core.ts index 01e7093..37aefd2 100644 --- a/packages-user/data-state/src/core.ts +++ b/packages-user/data-state/src/core.ts @@ -11,7 +11,9 @@ import { Dir4FaceHandler, Dir8FaceHandler, FaceGroup, - FaceDirection + FaceDirection, + IHeroAttr, + IEnemyAttr } from '@user/data-common'; import { EnemyManager, @@ -48,8 +50,7 @@ import { MainMapDamageConverter, MainMapDamageReducer, registerSpecials, - MainEnemyComparer, - IEnemyAttr + MainEnemyComparer } from './enemy'; import { BG2_ZINDEX, @@ -61,7 +62,6 @@ import { TILE_HEIGHT, TILE_WIDTH } from './shared'; -import { IHeroAttr } from './hero'; import { LegacyTileData, TileLegacyBridge } from './legacy'; import { ILoadProgressTotal, LoadProgressTotal } from '@motajs/loader'; import { isNil } from 'lodash-es'; @@ -82,8 +82,8 @@ export class CoreState implements ICoreState { // Layer 2 执行层,游戏逻辑对象都在这 readonly enemyContext: IEnemyContext; - readonly triggerRegistry: ITriggerRegistry; - readonly triggerCollector: ITriggerCollector; + readonly triggerRegistry: ITriggerRegistry; + readonly triggerCollector: ITriggerCollector; // 用户层内容,也就是最顶层的内容,一般仅用于初始化 readonly loadProgress: ILoadProgressTotal; @@ -171,10 +171,8 @@ export class CoreState implements ICoreState { this.enemyContext = enemyContext; // 触发器注册与收集器 - const triggerRegistry = new TriggerRegistry( - this - ); - const triggerCollector = new TriggerCollector(); + const triggerRegistry = new TriggerRegistry(this); + const triggerCollector = new TriggerCollector(); triggerCollector.attachRegistry(triggerRegistry); this.triggerRegistry = triggerRegistry; this.triggerCollector = triggerCollector; diff --git a/packages-user/data-state/src/enemy/aura.ts b/packages-user/data-state/src/enemy/aura.ts index eae1149..f3c4f64 100644 --- a/packages-user/data-state/src/enemy/aura.ts +++ b/packages-user/data-state/src/enemy/aura.ts @@ -18,8 +18,7 @@ import { } from '@user/data-system'; import { IReadonlyEnemy, ISpecial } from '@user/data-base'; import { IHaloValue } from './special'; -import { IEnemyAttr } from './types'; -import { IHeroAttr } from '../hero'; +import { IHeroAttr, IEnemyAttr } from '@user/data-common'; const FULL_RANGE = new FullRange(); const RECT_RANGE = new RectRange(); @@ -176,7 +175,7 @@ export class GuardAura implements IEnemyAuraView< if (locator.x === this.locator.x && locator.y === this.locator.y) { return; } - enemy.getAttribute('guard').add(this.sourceView); + enemy.getAttribute('guard').add(this.locator); } applySpecial(): IEnemySpecialModifier | null { diff --git a/packages-user/data-state/src/enemy/calculator.ts b/packages-user/data-state/src/enemy/calculator.ts index 3d67f08..edd5bb5 100644 --- a/packages-user/data-state/src/enemy/calculator.ts +++ b/packages-user/data-state/src/enemy/calculator.ts @@ -4,10 +4,10 @@ import { IEnemyDamageInfo, IReadonlyEnemyHandler } from '@user/data-system'; -import { IEnemyAttr } from './types'; +import { IEnemyAttr, IHeroAttr } from '@user/data-common'; import { IVampireValue } from './special'; -import { IHeroAttr } from '../hero'; import { state } from '../ins'; +import { logger } from '@motajs/common'; export class MainDamageCalculator implements IDamageCalculator< IEnemyAttr, @@ -87,8 +87,14 @@ export class MainDamageCalculator implements IDamageCalculator< // 因此回合数需要加上打支援怪的回合数 for (const guard of guards) { // 直接把 enemy 传过去,因此支援的 enemy 会吃到其原本所在位置的光环加成 + const view = handler.context.getEnemyByLocator(guard); + if (!view) { + logger.warn(137, guard.x.toString(), guard.y.toString()); + continue; + } const extraInfo = this.calculate({ - enemy: guard.getComputedEnemy(), + enemy: view.getComputedEnemy(), + context: handler.context, locator, hero, data: handler.data diff --git a/packages-user/data-state/src/enemy/comparer.ts b/packages-user/data-state/src/enemy/comparer.ts index a04bef7..21260b7 100644 --- a/packages-user/data-state/src/enemy/comparer.ts +++ b/packages-user/data-state/src/enemy/comparer.ts @@ -1,5 +1,5 @@ import { IEnemyComparer, IReadonlyEnemy } from '@user/data-base'; -import { IEnemyAttr } from './types'; +import { IEnemyAttr } from '@user/data-common'; export class MainEnemyComparer implements IEnemyComparer { compare( diff --git a/packages-user/data-state/src/enemy/final.ts b/packages-user/data-state/src/enemy/final.ts index dbd3e01..2ec0fbb 100644 --- a/packages-user/data-state/src/enemy/final.ts +++ b/packages-user/data-state/src/enemy/final.ts @@ -1,6 +1,5 @@ import { IEnemyFinalEffect, IEnemyHandler } from '@user/data-system'; -import { IEnemyAttr } from './types'; -import { IHeroAttr } from '../hero'; +import { IEnemyAttr, IHeroAttr } from '@user/data-common'; export class MainEnemyFinalEffect implements IEnemyFinalEffect< IEnemyAttr, diff --git a/packages-user/data-state/src/enemy/legacy.ts b/packages-user/data-state/src/enemy/legacy.ts index 60ddb52..3c4aca6 100644 --- a/packages-user/data-state/src/enemy/legacy.ts +++ b/packages-user/data-state/src/enemy/legacy.ts @@ -1,5 +1,5 @@ import { IEnemyLegacyBridge } from '@user/data-base'; -import { IEnemyAttr } from './types'; +import { IEnemyAttr } from '@user/data-common'; export class EnemyLegacyBridge implements IEnemyLegacyBridge { fromLegacyEnemy( diff --git a/packages-user/data-state/src/enemy/mapDamage.ts b/packages-user/data-state/src/enemy/mapDamage.ts index b0659e8..ca10d4f 100644 --- a/packages-user/data-state/src/enemy/mapDamage.ts +++ b/packages-user/data-state/src/enemy/mapDamage.ts @@ -24,8 +24,8 @@ import { IReadonlyEnemy } from '@user/data-base'; import { IZoneValue } from './special'; -import { IEnemyAttr, MapDamageType } from './types'; -import { IHeroAttr } from '../hero'; +import { MapDamageType } from './types'; +import { IHeroAttr, IEnemyAttr } from '@user/data-common'; import { IFaceHandler, FaceGroup } from '@user/data-common'; const RECT_RANGE = new RectRange(); diff --git a/packages-user/data-state/src/enemy/special.ts b/packages-user/data-state/src/enemy/special.ts index 650dea4..bf5959c 100644 --- a/packages-user/data-state/src/enemy/special.ts +++ b/packages-user/data-state/src/enemy/special.ts @@ -4,7 +4,7 @@ import { IEnemyManager } from '@user/data-base'; import { getHeroStatusOn } from '../legacy/hero'; -import { IEnemyAttr } from './types'; +import { IEnemyAttr } from '@user/data-common'; //#region 复合属性值类型 diff --git a/packages-user/data-state/src/enemy/types.ts b/packages-user/data-state/src/enemy/types.ts index 59a2d32..1c55277 100644 --- a/packages-user/data-state/src/enemy/types.ts +++ b/packages-user/data-state/src/enemy/types.ts @@ -1,5 +1,3 @@ -import { IEnemyView } from '@user/data-system'; - export interface IEnemyAttr { /** 怪物生命值 */ hp: number; @@ -13,8 +11,8 @@ export interface IEnemyAttr { exp: number; /** 怪物加点量 */ point: number; - /** 支援来源怪物视图列表 */ - guard: Set>; + /** 支援来源怪物坐标索引列表 */ + guard: Set; } export const enum MapDamageType { diff --git a/packages-user/data-state/src/hero/types.ts b/packages-user/data-state/src/hero/types.ts index 98147da..138051c 100644 --- a/packages-user/data-state/src/hero/types.ts +++ b/packages-user/data-state/src/hero/types.ts @@ -1,26 +1,5 @@ //#region 勇士属性 -export interface IHeroAttr { - /** 勇士名称 */ - name: string; - /** 勇士生命值 */ - hp: number; - /** 勇士生命值上限 */ - hpmax: number; - /** 勇士攻击力 */ - atk: number; - /** 勇士防御力 */ - def: number; - /** 勇士护盾 */ - mdef: number; - /** 勇士魔法值 */ - mana: number; - /** 勇士魔法上限 */ - manamax: number; - /** 勇士拥有的金币 */ - money: number; - /** 勇士拥有的经验 */ - exp: number; -} +export interface IHeroAttr {} //#endregion diff --git a/packages-user/data-state/src/shared.ts b/packages-user/data-state/src/shared.ts index 0f4b609..8a3206a 100644 --- a/packages-user/data-state/src/shared.ts +++ b/packages-user/data-state/src/shared.ts @@ -1,4 +1,4 @@ -import { IHeroAttr } from './hero'; +import { IHeroAttr } from '@user/data-common'; //#region 地图相关 diff --git a/packages-user/data-state/src/types.ts b/packages-user/data-state/src/types.ts index 73de768..b1cd795 100644 --- a/packages-user/data-state/src/types.ts +++ b/packages-user/data-state/src/types.ts @@ -1,21 +1,19 @@ import { IMotaDataLoader, IStateBase } from '@user/data-base'; -import { IEnemyAttr } from './enemy'; -import { IHeroAttr } from './hero'; import { ILoadProgressTotal } from '@motajs/loader'; import { ISaveSystem } from './save'; import { IStateSystem } from '@user/data-system'; import { ISaveableContent } from '@user/data-common'; -export interface ISaveableExecutor { +export interface ISaveableExecutor { /** * 当数据读取后执行的函数,允许对其他存档对象进行读取 * @param data 对应可存档对象的存档数据 * @param state 当前的基础状态 */ - afterLoad(data: T, state: IStateBase): void; + afterLoad(data: T, state: IStateBase): void; } -export interface ICoreState extends IStateSystem { +export interface ICoreState extends IStateSystem { /** 加载进度对象 */ readonly loadProgress: ILoadProgressTotal; /** 数据端加载对象 */ diff --git a/packages-user/data-system/src/combat/context.ts b/packages-user/data-system/src/combat/context.ts index 22dbb4f..af6746d 100644 --- a/packages-user/data-system/src/combat/context.ts +++ b/packages-user/data-system/src/combat/context.ts @@ -100,7 +100,7 @@ export class EnemyContext implements IEnemyContext< width: number = 0; height: number = 0; - constructor(readonly dataState: IStateBase) {} + constructor(readonly dataState: IStateBase) {} resize(width: number, height: number): void { this.clear(); @@ -210,7 +210,13 @@ export class EnemyContext implements IEnemyContext< enemy: IEnemy, locator: ITileLocator ): IEnemyHandler { - return { enemy, locator, hero: this.bindedHero!, data: this.dataState }; + return { + enemy, + context: this, + locator, + hero: this.bindedHero!, + data: this.dataState + }; } getEnemyLocator(enemy: IEnemy): Readonly | null { diff --git a/packages-user/data-system/src/combat/damage.ts b/packages-user/data-system/src/combat/damage.ts index 2b83a7e..423ac6d 100644 --- a/packages-user/data-system/src/combat/damage.ts +++ b/packages-user/data-system/src/combat/damage.ts @@ -34,7 +34,7 @@ export class DamageContext implements IDamageContext< /** 当前勇士属性 */ protected heroStatus: IReadonlyHeroAttribute | null; - readonly dataState: IStateBase; + readonly dataState: IStateBase; constructor( readonly context: IEnemyContext, @@ -57,7 +57,13 @@ export class DamageContext implements IDamageContext< locator: ITileLocator, hero: IReadonlyHeroAttribute ): IReadonlyEnemyHandler { - return { enemy, locator, hero, data: this.dataState }; + return { + enemy, + context: this.context, + locator, + hero, + data: this.dataState + }; } getDamageInfo(enemy: IEnemyView): IEnemyDamageInfo | null { diff --git a/packages-user/data-system/src/combat/mapDamage.ts b/packages-user/data-system/src/combat/mapDamage.ts index e68249a..6cfb22d 100644 --- a/packages-user/data-system/src/combat/mapDamage.ts +++ b/packages-user/data-system/src/combat/mapDamage.ts @@ -64,7 +64,7 @@ export class MapDamage implements IMapDamage { /** 坐标索引对象 */ private readonly indexer: ILocationHelper; - readonly dataState: IStateBase; + readonly dataState: IStateBase; constructor(readonly context: IEnemyContext) { this.indexer = context.indexer; @@ -89,6 +89,7 @@ export class MapDamage implements IMapDamage { if (!hero) return null; return { enemy: view.getComputedEnemy(), + context: this.context, locator, hero, data: this.context.dataState diff --git a/packages-user/data-system/src/combat/types.ts b/packages-user/data-system/src/combat/types.ts index 044cafe..171d58f 100644 --- a/packages-user/data-system/src/combat/types.ts +++ b/packages-user/data-system/src/combat/types.ts @@ -14,23 +14,27 @@ import { ILocationHelper } from '@user/data-common'; export interface IEnemyHandler { /** 怪物属性信息 */ readonly enemy: IEnemy; + /** 怪物上下文 */ + readonly context: IEnemyContext; /** 怪物定位符 */ readonly locator: ITileLocator; /** 勇士属性信息 */ readonly hero: IReadonlyHeroAttribute; /** 当前全局状态对象 */ - readonly data: IStateBase; + readonly data: IStateBase; } export interface IReadonlyEnemyHandler { /** 怪物属性信息 */ readonly enemy: IReadonlyEnemy; + /** 怪物上下文 */ + readonly context: IReadonlyEnemyContext; /** 怪物定位符 */ readonly locator: ITileLocator; /** 勇士属性信息 */ readonly hero: IReadonlyHeroAttribute; /** 当前全局状态对象 */ - readonly data: IStateBase; + readonly data: IStateBase; } //#endregion @@ -282,7 +286,7 @@ export interface IMapDamage { /** 当前绑定的怪物上下文 */ readonly context: IEnemyContext; /** 地图伤害系统绑定的全局状态对象 */ - readonly dataState: IStateBase; + readonly dataState: IStateBase; /** * 设置地图伤害转换器,并基于当前上下文重建所有地图伤害视图 @@ -398,7 +402,7 @@ export interface IDamageCalculator { export interface IDamageContext { /** 伤害上下文所属的全局状态对象 */ - readonly dataState: IStateBase; + readonly dataState: IStateBase; /** * 获取战斗伤害信息 @@ -479,7 +483,7 @@ export interface IDamageSystem extends IDamageContext< //#region 上下文 -export interface IEnemyContext { +export interface IReadonlyEnemyContext { /** 怪物上下文宽度 */ readonly width: number; /** 怪物上下文高度 */ @@ -487,7 +491,84 @@ export interface IEnemyContext { /** 此上下文使用的索引对象 */ readonly indexer: ILocationHelper; /** 当前怪物上下文绑定的全局状态对象 */ - readonly dataState: IStateBase; + readonly dataState: IStateBase; + + /** + * 获取当前绑定的勇士属性对象 + */ + getBindedHero(): IReadonlyHeroAttribute | null; + + /** + * 获取指定怪物对象当前所在位置 + * @param enemy 怪物对象 + */ + getEnemyLocator(enemy: IEnemy): Readonly | null; + + /** + * 获取指定怪物视图当前所在位置 + * @param view 怪物视图 + */ + getEnemyLocatorByView( + view: IEnemyView + ): Readonly | null; + + /** + * 根据定位符获取怪物视图 + * @param locator 地图定位符 + */ + getEnemyByLocator(locator: ITileLocator): IEnemyView | null; + + /** + * 根据坐标获取怪物视图 + * @param x 横坐标 + * @param y 纵坐标 + */ + getEnemyByLoc(x: number, y: number): IEnemyView | null; + + /** + * 根据计算后怪物对象反查怪物视图 + * @param enemy 计算后怪物对象 + */ + getViewByComputed(enemy: IReadonlyEnemy): IEnemyView | null; + + /** + * 扫描指定范围内的怪物视图 + * @param range 范围对象 + * @param param 范围参数 + */ + scanRange( + range: IRange, + param: T + ): Iterable<[ITileLocator, IEnemyView]>; + + /** + * 迭代上下文中的全部怪物 + */ + iterateEnemy(): Iterable<[ITileLocator, IEnemyView]>; + + /** + * 获取当前绑定的地图伤害管理器 + */ + getMapDamage(): IMapDamage | null; + + /** + * 获取当前绑定的伤害计算系统 + */ + getDamageSystem(): IDamageSystem | null; +} + +export interface IEnemyContext extends IReadonlyEnemyContext< + TEnemy, + THero +> { + /** 怪物上下文宽度 */ + readonly width: number; + /** 怪物上下文高度 */ + readonly height: number; + /** 此上下文使用的索引对象 */ + readonly indexer: ILocationHelper; + /** 当前怪物上下文绑定的全局状态对象 */ + readonly dataState: IStateBase; /** * 调整上下文尺寸,并清空当前上下文中的所有怪物与状态 @@ -572,44 +653,6 @@ export interface IEnemyContext { */ bindHero(hero: IReadonlyHeroAttribute | null): void; - /** - * 获取当前绑定的勇士属性对象 - */ - getBindedHero(): IReadonlyHeroAttribute | null; - - /** - * 获取指定怪物对象当前所在位置 - * @param enemy 怪物对象 - */ - getEnemyLocator(enemy: IEnemy): Readonly | null; - - /** - * 获取指定怪物视图当前所在位置 - * @param view 怪物视图 - */ - getEnemyLocatorByView( - view: IEnemyView - ): Readonly | null; - - /** - * 根据定位符获取怪物视图 - * @param locator 地图定位符 - */ - getEnemyByLocator(locator: ITileLocator): IEnemyView | null; - - /** - * 根据坐标获取怪物视图 - * @param x 横坐标 - * @param y 纵坐标 - */ - getEnemyByLoc(x: number, y: number): IEnemyView | null; - - /** - * 根据计算后怪物对象反查怪物视图 - * @param enemy 计算后怪物对象 - */ - getViewByComputed(enemy: IReadonlyEnemy): IEnemyView | null; - /** * 在指定位置放置一个怪物对象 * @param locator 地图定位符 @@ -623,21 +666,6 @@ export interface IEnemyContext { */ deleteEnemy(locator: ITileLocator): void; - /** - * 扫描指定范围内的怪物视图 - * @param range 范围对象 - * @param param 范围参数 - */ - scanRange( - range: IRange, - param: T - ): Iterable<[ITileLocator, IEnemyView]>; - - /** - * 迭代上下文中的全部怪物 - */ - iterateEnemy(): Iterable<[ITileLocator, IEnemyView]>; - /** * 添加一个全局光环视图 * @param aura 光环视图 @@ -656,22 +684,12 @@ export interface IEnemyContext { */ attachMapDamage(damage: IMapDamage | null): void; - /** - * 获取当前绑定的地图伤害管理器 - */ - getMapDamage(): IMapDamage | null; - /** * 绑定伤害计算系统 * @param system 伤害系统 */ attachDamageSystem(system: IDamageSystem | null): void; - /** - * 获取当前绑定的伤害计算系统 - */ - getDamageSystem(): IDamageSystem | null; - /** * 重建当前上下文中的全部怪物计算结果 * diff --git a/packages-user/data-system/src/trigger/collection.ts b/packages-user/data-system/src/trigger/collection.ts index 005a245..a1fe3cd 100644 --- a/packages-user/data-system/src/trigger/collection.ts +++ b/packages-user/data-system/src/trigger/collection.ts @@ -1,13 +1,10 @@ import { ITrigger, ITriggerCollection, ITriggerHandler } from './types'; -export class TriggerCollection< - TEnemy = unknown, - THero = unknown -> implements ITriggerCollection { +export class TriggerCollection implements ITriggerCollection { /** 当前集合内部维护的触发器列表 */ - private readonly triggerList: ITrigger[]; + private readonly triggerList: ITrigger[]; - constructor(triggers: Iterable>) { + constructor(triggers: Iterable) { this.triggerList = [...triggers]; } @@ -15,19 +12,15 @@ export class TriggerCollection< return this.triggerList.length; } - async trigger(handler: ITriggerHandler): Promise { + async trigger(handler: ITriggerHandler): Promise { for (const trigger of this.triggerList) { await trigger.trigger(handler); } } async *triggerIter( - handler: ITriggerHandler - ): AsyncGenerator< - ITrigger, - void, - ITriggerHandler | null - > { + handler: ITriggerHandler + ): AsyncGenerator { let currentHandler = handler; for (const trigger of this.triggerList) { await trigger.trigger(currentHandler); @@ -40,21 +33,19 @@ export class TriggerCollection< } } - iterate(): Iterable> { + iterate(): Iterable { return this.triggerList.values(); } - push(trigger: ITrigger): void { + push(trigger: ITrigger): void { this.triggerList.push(trigger); } - unshift(trigger: ITrigger): void { + unshift(trigger: ITrigger): void { this.triggerList.unshift(trigger); } - concat( - ...others: ITriggerCollection[] - ): ITriggerCollection { + concat(...others: ITriggerCollection[]): ITriggerCollection { const merged = [...this.triggerList]; for (const other of others) { merged.push(...other.iterate()); diff --git a/packages-user/data-system/src/trigger/collector.ts b/packages-user/data-system/src/trigger/collector.ts index 5be8589..94b13e6 100644 --- a/packages-user/data-system/src/trigger/collector.ts +++ b/packages-user/data-system/src/trigger/collector.ts @@ -8,18 +8,11 @@ import { import { logger } from '@motajs/common'; import { TriggerCollection } from './collection'; -export class TriggerCollector< - TEnemy = unknown, - THero = unknown -> implements ITriggerCollector { +export class TriggerCollector implements ITriggerCollector { /** 当前收集器使用的注册对象 */ - private registry: ITriggerRegistry | null = null; + private registry: ITriggerRegistry | null = null; - collect( - x: number, - y: number, - layer: IMapLayer - ): ITriggerCollection { + collect(x: number, y: number, layer: IMapLayer): ITriggerCollection { if (!this.registry) { logger.warn(135); return new TriggerCollection([]); @@ -62,8 +55,8 @@ export class TriggerCollector< const duplicate = new Set(); if (staticTrigger) { // 有静态触发器 - const lessTriggers: ITrigger[] = []; - const greaterTriggers: ITrigger[] = []; + const lessTriggers: ITrigger[] = []; + const greaterTriggers: ITrigger[] = []; // 先收集所有的触发器,并记录重复情况 for (const tile of layer.dynamicLayer.getDynamicTilesAt(x, y)) { const trigger = this.registry.create(tile.triggerType); @@ -92,7 +85,7 @@ export class TriggerCollector< return new TriggerCollection(arr); } else { // 没有静态触发器 - const triggers: ITrigger[] = []; + const triggers: ITrigger[] = []; for (const tile of layer.dynamicLayer.getDynamicTilesAt(x, y)) { const trigger = this.registry.create(tile.triggerType); if (trigger) { @@ -113,7 +106,7 @@ export class TriggerCollector< } } - attachRegistry(registry: ITriggerRegistry | null): void { + attachRegistry(registry: ITriggerRegistry | null): void { this.registry = registry; } } diff --git a/packages-user/data-system/src/trigger/registry.ts b/packages-user/data-system/src/trigger/registry.ts index 3b161b7..87db139 100644 --- a/packages-user/data-system/src/trigger/registry.ts +++ b/packages-user/data-system/src/trigger/registry.ts @@ -2,28 +2,24 @@ import { logger } from '@motajs/common'; import { ITrigger, ITriggerRegistry, TriggerFactory } from './types'; import { IStateBase } from '@user/data-base'; -export class TriggerRegistry< - TEnemy = unknown, - THero = unknown -> implements ITriggerRegistry { +export class TriggerRegistry implements ITriggerRegistry { /** 数字类型到触发器工厂的映射 */ - private readonly typeMap: Map> = - new Map(); + private readonly typeMap: Map = new Map(); - constructor(public readonly state: IStateBase) {} + constructor(public readonly state: IStateBase) {} - register(type: number, factory: TriggerFactory): void { + register(type: number, factory: TriggerFactory): void { if (this.typeMap.has(type)) { logger.warn(132, 'type', type.toString()); } this.typeMap.set(type, factory); } - get(type: number): TriggerFactory | null { + get(type: number): TriggerFactory | null { return this.typeMap.get(type) ?? null; } - create(num: number): ITrigger | null { + create(num: number): ITrigger | null { const factory = this.get(num); if (!factory) return null; return factory(num, this.state); diff --git a/packages-user/data-system/src/trigger/types.ts b/packages-user/data-system/src/trigger/types.ts index db4bcff..ee25119 100644 --- a/packages-user/data-system/src/trigger/types.ts +++ b/packages-user/data-system/src/trigger/types.ts @@ -6,9 +6,9 @@ import { IStateBaseExtended } from '@user/data-base'; -export interface ITriggerHandler { +export interface ITriggerHandler { /** 当前全局状态对象 */ - readonly state: IStateBase; + readonly state: IStateBase; /** 当前楼层状态对象 */ readonly layer?: ILayerState; /** 当前参与触发的图层对象 */ @@ -17,15 +17,9 @@ export interface ITriggerHandler { readonly locator?: ITileLocator; } -export type TriggerFactory = ( - type: number, - state: IStateBase -) => ITrigger; +export type TriggerFactory = (type: number, state: IStateBase) => ITrigger; -export interface ITrigger< - TEnemy = unknown, - THero = unknown -> extends IStateBaseExtended { +export interface ITrigger extends IStateBaseExtended { /** 触发器类型标识 */ readonly type: number; /** 触发器优先级 */ @@ -35,39 +29,36 @@ export interface ITrigger< * 使用给定上下文触发当前触发器 * @param handler 触发上下文对象 */ - trigger(handler: ITriggerHandler): Promise; + trigger(handler: ITriggerHandler): Promise; /** * 将当前触发器包装为单元素触发器集合 */ - collection(): ITriggerCollection; + collection(): ITriggerCollection; } -export interface ITriggerRegistry< - TEnemy = unknown, - THero = unknown -> extends IStateBaseExtended { +export interface ITriggerRegistry extends IStateBaseExtended { /** * 注册一个按类型创建的触发器工厂 * @param type 触发器类型 * @param factory 触发器工厂函数 */ - register(type: number, factory: TriggerFactory): void; + register(type: number, factory: TriggerFactory): void; /** * 获取指定类型的触发器工厂 * @param type 触发器类型 */ - get(type: number): TriggerFactory | null; + get(type: number): TriggerFactory | null; /** * 根据触发器类型创建一个触发器实例,如果对应工厂不存在则返回 `null` * @param num 触发器类型 */ - create(num: number): ITrigger | null; + create(num: number): ITrigger | null; } -export interface ITriggerCollection { +export interface ITriggerCollection { /** * 当前集合中的触发器数量 */ @@ -77,62 +68,52 @@ export interface ITriggerCollection { * 顺序触发当前集合中的所有触发器 * @param handler 初始触发上下文对象 */ - trigger(handler: ITriggerHandler): Promise; + trigger(handler: ITriggerHandler): Promise; /** * 逐个触发当前集合中的触发器,并允许为下一次推进提供新上下文 * @param handler 初始触发上下文对象 */ triggerIter( - handler: ITriggerHandler - ): AsyncGenerator< - ITrigger, - void, - ITriggerHandler | null - >; + handler: ITriggerHandler + ): AsyncGenerator; /** * 迭代当前集合中的所有触发器 */ - iterate(): Iterable>; + iterate(): Iterable; /** * 向集合末尾追加一个触发器 * @param trigger 要追加的触发器 */ - push(trigger: ITrigger): void; + push(trigger: ITrigger): void; /** * 向集合头部插入一个触发器 * @param trigger 要插入的触发器 */ - unshift(trigger: ITrigger): void; + unshift(trigger: ITrigger): void; /** * 将当前集合与其他集合顺序拼接为一个新集合 * @param others 要拼接的其他集合 */ - concat( - ...others: ITriggerCollection[] - ): ITriggerCollection; + concat(...others: ITriggerCollection[]): ITriggerCollection; } -export interface ITriggerCollector { +export interface ITriggerCollector { /** * 收集指定图层中某一点的所有触发器 * @param x 横坐标 * @param y 纵坐标 * @param layer 目标图层 */ - collect( - x: number, - y: number, - layer: IMapLayer - ): ITriggerCollection; + collect(x: number, y: number, layer: IMapLayer): ITriggerCollection; /** * 绑定或清除当前 collector 使用的注册表 * @param registry 触发器注册表 */ - attachRegistry(registry: ITriggerRegistry | null): void; + attachRegistry(registry: ITriggerRegistry | null): void; } diff --git a/packages-user/data-system/src/types.ts b/packages-user/data-system/src/types.ts index 60f075c..2854eea 100644 --- a/packages-user/data-system/src/types.ts +++ b/packages-user/data-system/src/types.ts @@ -1,17 +1,18 @@ import { IStateBase } from '@user/data-base'; import { IEnemyContext } from './combat'; import { ITriggerCollector, ITriggerRegistry } from './trigger'; +import { IEnemyAttr, IHeroAttr } from '@user/data-common'; -export interface IStateSystem extends IStateBase { +export interface IStateSystem extends IStateBase { /** 怪物上下文 */ - readonly enemyContext: IEnemyContext; + readonly enemyContext: IEnemyContext; /** 触发器注册 */ - readonly triggerRegistry: ITriggerRegistry; + readonly triggerRegistry: ITriggerRegistry; /** 触发器收集器 */ - readonly triggerCollector: ITriggerCollector; + readonly triggerCollector: ITriggerCollector; } -export interface IStateSystemExtended { +export interface IStateSystemExtended { /** 当前对象对应的执行层对象(Layer 2 对象) */ - readonly state: IStateSystem; + readonly state: IStateSystem; } diff --git a/packages/common/src/logger.json b/packages/common/src/logger.json index 520470b..4bffa98 100644 --- a/packages/common/src/logger.json +++ b/packages/common/src/logger.json @@ -193,6 +193,7 @@ "133": "TileStore.addTile: tile number $1 already exists (id: '$2'), old tile data will be overridden.", "134": "TileStore.addTile: tile id '$1' already maps to number $2, old tile data will be overridden.", "135": "Expected a trigger registry attched before collect triggers.", - "136": "Unexpected duplicate trigger priority $1, which may cause trigger executed in an unexpected order." + "136": "Unexpected duplicate trigger priority $1, which may cause trigger executed in an unexpected order.", + "137": "Unknown guard enemy at locator '$1,$2'." } }