feat: LazyEntityUpdater

This commit is contained in:
2024-03-09 04:50:55 +00:00
parent a38f72fa46
commit fa29486af6
8 changed files with 126 additions and 42 deletions
+16 -2
View File
@@ -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<ICityEntity>{
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;
}
}
+7
View File
@@ -0,0 +1,7 @@
import type { CityID, CityName, NationID } from "./defs.js";
export interface ICityEntity{
id: CityID;
name: CityName;
nationID: NationID;
}
+18 -27
View File
@@ -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<City>;
private _troop: WeakRef<Troop> | undefined;
private _nation: WeakRef<Nation>;
export class General extends LazyEntityUpdater<IGeneralEntity> {
protected readonly _indirectNames: (keyof IGeneralEntity)[] = ["id", "nationID", "troopID", "nationID"];
protected readonly _entityType = "General";
protected readonly _raw: IGeneralEntity;
public get raw(): Readonly<IGeneralEntity> {
return this._raw;
}
protected _city: WeakRef<City>;
protected _troop: WeakRef<Troop> | undefined;
protected _nation: WeakRef<Nation>;
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){
@@ -0,0 +1,31 @@
import type { IResourceController, ValidEntity, ValidEntityType } from "./ResourceController.js";
export abstract class LazyEntityUpdater<Entity extends ValidEntity>{
protected abstract readonly _indirectNames: (keyof Entity)[];
protected abstract readonly _entityType: ValidEntityType<Entity>;
protected abstract readonly _raw: Entity;
protected abstract readonly resourceController: IResourceController;
public get raw(): Readonly<Entity> {
return this._raw;
}
public get entityType(): ValidEntityType<Entity> {
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);
}
}
+23 -6
View File
@@ -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<INationEntity> {
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;
}
}
+9
View File
@@ -0,0 +1,9 @@
import type { CityID, NationID, NationName, NationType } from "./defs.js";
export interface INationEntity{
id: NationID;
name: NationName;
type: NationType;
capitalID: CityID;
}
@@ -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> = 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<any>): void;
createGeneral(raw: IGeneralEntity): General;
createTroop(raw: ITroopEntity): Troop;
//createNation
+7 -7
View File
@@ -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<ITroopEntity> {
protected readonly _indirectNames: (keyof ITroopEntity)[] = ["id"];
protected readonly _entityType = "Troop";
protected readonly _raw: ITroopEntity;
private _leader: WeakRef<General>;
private _members: Map<GeneralID, WeakRef<General>>;
public get raw(): Readonly<ITroopEntity> {
return this._raw;
}
constructor(
raw: ITroopEntity,
private resourceController: IResourceController
protected resourceController: IResourceController
){
super();
this._raw = raw;
const members = resourceController.findGeneralByTroop(raw.id);