From fa29486af651e2b3aa900f035517a415bad54fd2 Mon Sep 17 00:00:00 2001 From: Hide_D Date: Sat, 9 Mar 2024 04:50:55 +0000 Subject: [PATCH] feat: LazyEntityUpdater --- @sammo/game_logic/src/City.ts | 18 ++++++++- @sammo/game_logic/src/CityEntity.ts | 7 ++++ @sammo/game_logic/src/General.ts | 45 +++++++++------------ @sammo/game_logic/src/LazyEntityUpdater.ts | 31 ++++++++++++++ @sammo/game_logic/src/Nation.ts | 29 ++++++++++--- @sammo/game_logic/src/NationEntity.ts | 9 +++++ @sammo/game_logic/src/ResourceController.ts | 15 +++++++ @sammo/game_logic/src/Troop.ts | 14 +++---- 8 files changed, 126 insertions(+), 42 deletions(-) create mode 100644 @sammo/game_logic/src/CityEntity.ts create mode 100644 @sammo/game_logic/src/LazyEntityUpdater.ts create mode 100644 @sammo/game_logic/src/NationEntity.ts diff --git a/@sammo/game_logic/src/City.ts b/@sammo/game_logic/src/City.ts index 0902ab0..7870fc1 100644 --- a/@sammo/game_logic/src/City.ts +++ b/@sammo/game_logic/src/City.ts @@ -1,8 +1,22 @@ +import type { ICityEntity } from "./CityEntity.js"; +import { LazyEntityUpdater } from "./LazyEntityUpdater.js"; +import type { IResourceController } from "./ResourceController.js"; import type { CityID } from "./defs.js"; -export class City{ +export class City extends LazyEntityUpdater{ + protected readonly _indirectNames: (keyof ICityEntity)[] = ["id", "nationID"]; + protected readonly _entityType = "City"; + protected readonly _raw: ICityEntity; + constructor( - public readonly id: CityID + raw: ICityEntity, + protected readonly resourceController: IResourceController ){ + super(); + this._raw = raw; + } + + get id(): CityID { + return this._raw.id; } } \ No newline at end of file diff --git a/@sammo/game_logic/src/CityEntity.ts b/@sammo/game_logic/src/CityEntity.ts new file mode 100644 index 0000000..9931731 --- /dev/null +++ b/@sammo/game_logic/src/CityEntity.ts @@ -0,0 +1,7 @@ +import type { CityID, CityName, NationID } from "./defs.js"; + +export interface ICityEntity{ + id: CityID; + name: CityName; + nationID: NationID; +} \ No newline at end of file diff --git a/@sammo/game_logic/src/General.ts b/@sammo/game_logic/src/General.ts index 4b33c0b..a40e937 100644 --- a/@sammo/game_logic/src/General.ts +++ b/@sammo/game_logic/src/General.ts @@ -6,21 +6,22 @@ import { DiplomaticPermission, type CityID, type GeneralID, type GeneralName, ty import { must } from "@sammo/util"; import { Nation } from "./Nation.js"; import { Troop } from "./Troop.js"; +import { LazyEntityUpdater } from "./LazyEntityUpdater.js"; -export class General { - private _raw: IGeneralEntity; - private _city: WeakRef; - private _troop: WeakRef | undefined; - private _nation: WeakRef; +export class General extends LazyEntityUpdater { + protected readonly _indirectNames: (keyof IGeneralEntity)[] = ["id", "nationID", "troopID", "nationID"]; + protected readonly _entityType = "General"; + protected readonly _raw: IGeneralEntity; - public get raw(): Readonly { - return this._raw; - } + protected _city: WeakRef; + protected _troop: WeakRef | undefined; + protected _nation: WeakRef; constructor( raw: IGeneralEntity, - private resourceController: IResourceController + protected readonly resourceController: IResourceController ){ + super(); this._raw = raw; this._city = new WeakRef(must(resourceController.getCity(raw.cityID))); this._nation = new WeakRef(must(resourceController.getNation(raw.nationID))); @@ -38,26 +39,16 @@ export class General { return this._raw.name; } - public update(callback: (oldRaw: IGeneralEntity) => void, force = false) { + public get city(): City { + return must(this._city.deref()); + } - const oldCityID = this._raw.cityID; - const oldTroopID = this._raw.troopID; - const oldNationID = this._raw.nationID; + public get troop(): Troop | undefined { + return this._troop?.deref(); + } - callback(this._raw); - - if(!force){ - if(oldCityID !== this._raw.cityID){ - throw new Error("City change by update() is not allowed"); - } - if(oldTroopID !== this._raw.troopID){ - throw new Error("Troop change by update() is not allowed"); - } - if(oldNationID !== this._raw.nationID){ - throw new Error("Nation change by update() is not allowed"); - } - } - this.resourceController.setDirtyGeneral(this._raw); + public get nation(): Nation { + return must(this._nation.deref()); } public changeCity(city: CityID | City){ diff --git a/@sammo/game_logic/src/LazyEntityUpdater.ts b/@sammo/game_logic/src/LazyEntityUpdater.ts new file mode 100644 index 0000000..c70b18f --- /dev/null +++ b/@sammo/game_logic/src/LazyEntityUpdater.ts @@ -0,0 +1,31 @@ +import type { IResourceController, ValidEntity, ValidEntityType } from "./ResourceController.js"; + +export abstract class LazyEntityUpdater{ + protected abstract readonly _indirectNames: (keyof Entity)[]; + protected abstract readonly _entityType: ValidEntityType; + + protected abstract readonly _raw: Entity; + + protected abstract readonly resourceController: IResourceController; + + public get raw(): Readonly { + return this._raw; + } + + public get entityType(): ValidEntityType { + return this._entityType; + } + + public update(callback: (oldRaw: Entity) => void, force = false) { + const oldRaw = { ...this._raw }; + callback(this._raw); + if (!force) { + for (const indirectName of this._indirectNames) { + if (oldRaw[indirectName] !== this._raw[indirectName]) { + throw new Error(`${String(indirectName)} change by update() is not allowed`); + } + } + } + this.resourceController.setDirty(this); + } +} \ No newline at end of file diff --git a/@sammo/game_logic/src/Nation.ts b/@sammo/game_logic/src/Nation.ts index a02bd67..64d518d 100644 --- a/@sammo/game_logic/src/Nation.ts +++ b/@sammo/game_logic/src/Nation.ts @@ -1,9 +1,26 @@ -import type { NationID, NationName, NationType } from "./defs.js"; +import { LazyEntityUpdater } from "./LazyEntityUpdater.js"; +import type { INationEntity } from "./NationEntity.js"; +import type { IResourceController } from "./ResourceController.js"; +import type { NationID, NationName } from "./defs.js"; + +export class Nation extends LazyEntityUpdater { + protected readonly _indirectNames: (keyof INationEntity)[] = ["id"]; + protected readonly _entityType = "Nation"; + protected readonly _raw: INationEntity; -export class Nation { constructor( - public readonly id: NationID, - public readonly name: NationName, - public readonly type: NationType, - ) { } + raw: INationEntity, + protected readonly resourceController: IResourceController + ){ + super(); + this._raw = raw; + } + + public get id(): NationID { + return this._raw.id; + } + + public get name(): NationName { + return this._raw.name; + } } \ No newline at end of file diff --git a/@sammo/game_logic/src/NationEntity.ts b/@sammo/game_logic/src/NationEntity.ts new file mode 100644 index 0000000..80df752 --- /dev/null +++ b/@sammo/game_logic/src/NationEntity.ts @@ -0,0 +1,9 @@ +import type { CityID, NationID, NationName, NationType } from "./defs.js"; + +export interface INationEntity{ + id: NationID; + name: NationName; + type: NationType; + + capitalID: CityID; +} \ No newline at end of file diff --git a/@sammo/game_logic/src/ResourceController.ts b/@sammo/game_logic/src/ResourceController.ts index 38ff14d..30554d4 100644 --- a/@sammo/game_logic/src/ResourceController.ts +++ b/@sammo/game_logic/src/ResourceController.ts @@ -6,6 +6,19 @@ import type { GameEnv } from "./GameEnv.js"; import type { IGeneralEntity } from "./GeneralEntity.js"; import type { Troop } from "./Troop.js"; import type { ITroopEntity } from "./TroopEntity.js"; +import type { LazyEntityUpdater } from "./LazyEntityUpdater.js"; +import type { ICityEntity } from "./CityEntity.js"; +import type { INationEntity } from "./NationEntity.js"; + +export type ValidEntityList = { + 'General': IGeneralEntity; + 'City': ICityEntity; + 'Nation': INationEntity; + 'Troop': ITroopEntity; +}; + +export type ValidEntity = ValidEntityList[keyof ValidEntityList]; +export type ValidEntityType = Entity extends ValidEntityList[infer T extends keyof ValidEntityList] ? T : never; export interface IResourceController{ addCity(city: City): boolean; @@ -38,6 +51,8 @@ export interface IResourceController{ setDirtyTroop(troop: Troop | TroopID): void; setDirtyNation(nation: Nation): void; + setDirty(entity: LazyEntityUpdater): void; + createGeneral(raw: IGeneralEntity): General; createTroop(raw: ITroopEntity): Troop; //createNation diff --git a/@sammo/game_logic/src/Troop.ts b/@sammo/game_logic/src/Troop.ts index 667e0df..1123519 100644 --- a/@sammo/game_logic/src/Troop.ts +++ b/@sammo/game_logic/src/Troop.ts @@ -3,20 +3,20 @@ import type { General } from "./General.js"; import type { IResourceController } from "./ResourceController.js"; import type { ITroopEntity } from "./TroopEntity.js"; import type { GeneralID } from "./defs.js"; +import { LazyEntityUpdater } from "./LazyEntityUpdater.js"; -export class Troop { - private _raw: ITroopEntity +export class Troop extends LazyEntityUpdater { + protected readonly _indirectNames: (keyof ITroopEntity)[] = ["id"]; + protected readonly _entityType = "Troop"; + protected readonly _raw: ITroopEntity; private _leader: WeakRef; private _members: Map>; - public get raw(): Readonly { - return this._raw; - } - constructor( raw: ITroopEntity, - private resourceController: IResourceController + protected resourceController: IResourceController ){ + super(); this._raw = raw; const members = resourceController.findGeneralByTroop(raw.id);