refac: bootstrap()

- 각 클래스가 WeakRef로 상호 참조한다면, construct 시점엔 불가
- bootstrap() 함수로 이후 참조
This commit is contained in:
2024-03-14 16:26:40 +00:00
parent 3e4129c3f1
commit b4b00e1983
14 changed files with 335 additions and 59 deletions
+4
View File
@@ -16,6 +16,10 @@ export class City extends LazyEntityUpdater<ICityEntity>{
this._raw = raw;
}
public bootstrap(){
//do nothing;
}
get id(): CityID {
return this._raw.id;
}
@@ -1,3 +1,5 @@
import type { IntYear, IntYearMonth } from "@/defs.js";
export type UnitedGameState = 'onGame' | 'united' | 'onEvent' | 'endEvent';
export interface IGameEnvEntity {
@@ -10,8 +12,9 @@ export interface IGameEnvEntity {
gameStartYear: number;
gameStartMonth: number;
year: number;
month: number;
year: IntYear;
month: IntYearMonth;
yearMonth: IntYearMonth;
secondsPerTurn: number;
@@ -1,4 +1,4 @@
import type { CityID, DiplomaticPermission, FractionalRange, GeneralID, GeneralName, IntMonth, IntYear, ItemID, ItemKeyType, NationID, NpcType, OfficerLevel, PersonalityType, SpecialityDomesticType, SpecialityWarType, SquadID, URILike, UserID, UserName } from "../defs.js";
import type { CityID, DiplomaticPermission, FractionalRange, GeneralID, GeneralName, IntMonth, IntYear, IntYearMonth, ItemID, ItemKeyType, NationID, NpcType, OfficerLevel, PersonalityType, SpecialityDomesticType, SpecialityWarType, SquadID, URILike, UserID, UserName } from "../defs.js";
export interface IGeneralEntity {
id: GeneralID;
@@ -49,7 +49,7 @@ export interface IGeneralEntity {
age: IntYear;
startAge: IntYear;
nationJoinedRelYear: IntYear;
nationJoinedYearMonth: IntYearMonth;
betray: number;
@@ -69,4 +69,9 @@ export interface IGeneralEntity {
bornyear: number;
deadyear: number;
}
aux: {
lastBattleDate?: Date;
lastBattleYearMonth?: IntYearMonth;
}
}
@@ -51,6 +51,9 @@ export interface INationEntity{
availableWarSettingCnt?: number;
prevIncomeGold: number;
prevIncomeRice: number;
lastBattleDate?: Date;
lastBattleYearMonth?: IntYearMonth;
}
//TODO: 타입 정의
+6
View File
@@ -0,0 +1,6 @@
export class LogicError extends Error {
constructor(message?: string) {
super(message);
this.name = 'LogicError';
}
}
+3
View File
@@ -17,4 +17,7 @@ export class GameEnv extends LazyEntityUpdater<IGameEnvEntity>{
this._raw = raw;
}
public bootstrap(){
//do nothing;
}
}
+36 -10
View File
@@ -2,7 +2,7 @@ import { InvalidArgument } from "@sammo/util";
import { City } from "./City.js";
import type { IGeneralEntity } from "./Entity/GeneralEntity.js";
import type { IResourceController } from "./IResourceController.js";
import { DiplomaticPermission, type CityID, type GeneralID, type GeneralName, type NationID, OfficerLevel, type SquadID } from "./defs.js";
import { DiplomaticPermission, type CityID, type GeneralID, type GeneralName, type NationID, OfficerLevel, type SquadID, NpcType, StaffLevel, CityOfficerLevel } from "./defs.js";
import { must } from "@sammo/util";
import { Nation } from "./Nation.js";
import { Squad } from "./Squad.js";
@@ -17,11 +17,11 @@ export class General extends LazyEntityUpdater<IGeneralEntity> {
protected readonly _entityType = "General";
protected readonly _raw: IGeneralEntity;
protected _city: WeakRef<City>;
protected _squad: WeakRef<Squad> | undefined;
protected _nation: WeakRef<Nation>;
protected _city!: WeakRef<City>;
protected _squad!: WeakRef<Squad> | undefined;
protected _nation!: WeakRef<Nation>;
protected readonly iActionHandlers: Map<IActionKey, IAction>;
protected readonly iActionHandlers = new Map<IActionKey, IAction>;
constructor(
raw: IGeneralEntity,
@@ -29,6 +29,11 @@ export class General extends LazyEntityUpdater<IGeneralEntity> {
){
super();
this._raw = raw;
}
public bootstrap(){
const rsc = this.rsc;
const raw = this._raw;
this._city = new WeakRef(must(rsc.city(raw.cityID)));
this._nation = new WeakRef(must(rsc.nation(raw.nationID)));
@@ -36,8 +41,7 @@ export class General extends LazyEntityUpdater<IGeneralEntity> {
this._squad = new WeakRef(must(rsc.squad(raw.squadID, raw.nationID)));
}
//TODO: iAction 처리해야함
this.iActionHandlers = new Map();
//TODO: iActionHandlers 초기화
}
public get id(): GeneralID {
@@ -60,6 +64,28 @@ export class General extends LazyEntityUpdater<IGeneralEntity> {
return must(this._nation.deref());
}
public get isUser(): boolean {
return this._raw.npcType <= NpcType.user_borrowed_npc;
}
public get staffLevel(): StaffLevel | undefined {
if(this._raw.officerLevel < OfficerLevel.staffIntel3){
return undefined;
}
return this._raw.officerLevel as number as StaffLevel;
}
public get cityOfficerLevel(): CityOfficerLevel | undefined {
if(this._raw.officerLevel >= OfficerLevel.staffIntel3){
return undefined;
}
if(this._raw.officerLevel < OfficerLevel.cityLeadership){
return undefined;
}
return this._raw.officerLevel as number as CityOfficerLevel;
}
public changeCity(city: CityID | City){
const cityObj: City = (()=>{
if(city instanceof City){
@@ -86,7 +112,7 @@ export class General extends LazyEntityUpdater<IGeneralEntity> {
const squad = must(this._squad.deref());
if(squad.leader.id === this._raw.id){
squad.destructSquad(false);
squad.destroySquad(false);
}
else{
squad.members.delete(this._raw.id);
@@ -142,12 +168,12 @@ export class General extends LazyEntityUpdater<IGeneralEntity> {
else{
raw.officerLevel = OfficerLevel.normal;
}
raw.nationJoinedRelYear = 0;
raw.nationJoinedYearMonth = this.rsc.gameEnv.raw.yearMonth;
});
}
public updateTurnTime(){
const secondsPerTurn = this.rsc.gameEnv().raw.secondsPerTurn;
const secondsPerTurn = this.rsc.gameEnv.raw.secondsPerTurn;
this.forceUpdate((raw) => {
raw.turnTime = addSeconds(raw.turnTime, secondsPerTurn);
+5 -14
View File
@@ -22,21 +22,12 @@ export interface IResourceController {
popGeneralTurnTimeQueue(): General | undefined;
insertGeneralTurnTimeQueue(general: General, maybeTail: boolean): void;
gameEnv(): GameEnv;
readonly gameEnv: GameEnv;
allNations(): Map<NationID, Nation>;
allCities(): Map<CityID, City>;
allCitiesByNation(): Map<NationID, Map<CityID, City>>;
allSquads(): Map<NationID, Map<SquadID, Squad>>;
allGenerals(): Map<GeneralID, General>;
generalByNation(id: NationID): Map<GeneralID, General>;
generalByCity(id: CityID, nationID?: NationID): Map<GeneralID, General>;
generalBySquad(id: SquadID): Map<GeneralID, General>;
cityByNation(id: NationID): Map<CityID, City>;
squadByNation(id: NationID): Map<SquadID, Squad>;
readonly nationList: Map<NationID, Nation>;
readonly cityList: Map<CityID, City>;
readonly squadList: Map<SquadID, Squad>;
readonly generalList: Map<GeneralID, General>;
//----Insert, Update, Delete
@@ -9,6 +9,8 @@ export abstract class LazyEntityUpdater<Entity extends ValidEntity>{
protected abstract readonly rsc: IResourceController;
public abstract bootstrap(): void;
public get raw(): Readonly<Entity> {
return this._raw;
}
@@ -0,0 +1,20 @@
import type { General } from "@/General.js";
import { NotYetImplemented } from "@sammo/util";
const battleMonthThreshold = 12;
export function categorizeGeneral(general: General): 'war' | 'domestic' {
const nationLastBattle = general.nation.raw.aux.lastBattleYearMonth;
const lastBattle = general.raw.aux.lastBattleYearMonth;
if(lastBattle !== undefined && nationLastBattle !== undefined){
if(lastBattle >= nationLastBattle - battleMonthThreshold){
return 'war';
}
}
throw new NotYetImplemented();
return 'domestic';
}
+142 -2
View File
@@ -1,21 +1,101 @@
import { LazyEntityUpdater } from "./LazyEntityUpdater.js";
import type { INationEntity } from "./Entity/NationEntity.js";
import type { IResourceController } from "./IResourceController.js";
import type { NationID, NationName } from "./defs.js";
import { StaffLevel, type CityID, type GeneralID, type NationID, type NationName, type SquadID } from "./defs.js";
import type { City } from "./City.js";
import { General } from "./General.js";
import { must } from "@sammo/util";
import type { Squad } from "./Squad.js";
import { LogicError } from "./Errors.js";
import { categorizeGeneral } from "./LogicFunc/categorizeGeneral.js";
export class Nation extends LazyEntityUpdater<INationEntity> {
protected readonly _indirectNames: (keyof INationEntity)[] = ["id"];
protected readonly _entityType = "Nation";
protected readonly _raw: INationEntity;
protected readonly categorizedNPCGeneralList = {
war: new Map<GeneralID, WeakRef<General>>(),
domestic: new Map<GeneralID, WeakRef<General>>()
};
protected readonly categorizedUserGeneralList = {
war: new Map<GeneralID, WeakRef<General>>(),
domestic: new Map<GeneralID, WeakRef<General>>()
};
protected readonly cityList = new Map<CityID, WeakRef<City>>;
protected readonly generalList = new Map<GeneralID, WeakRef<General>>;
protected readonly squadList = new Map<SquadID, WeakRef<Squad>>;
protected readonly npcGeneralList = new Map<GeneralID, WeakRef<General>>();
protected readonly userGeneralList = new Map<GeneralID, WeakRef<General>>();
protected readonly warNPCGeneralList = new Map<GeneralID, WeakRef<General>>();
protected readonly warUserGeneralList = new Map<GeneralID, WeakRef<General>>();
protected readonly domesticNPCGeneralList = new Map<GeneralID, WeakRef<General>>();
protected readonly domesticUserGeneralList = new Map<GeneralID, WeakRef<General>>();
protected readonly staffList = new Map<StaffLevel, WeakRef<General>>();
constructor(
raw: INationEntity,
protected readonly rsc: IResourceController
){
) {
super();
this._raw = raw;
}
bootstrap() {
const rsc = this.rsc;
const raw = this._raw;
//raw값만 읽을것
for (const city of rsc.cityList.values()) {
if (city.raw.nationID !== raw.id) {
continue;
}
this.cityList.set(city.id, new WeakRef(city));
}
for (const squad of rsc.squadList.values()) {
if (squad.raw.nationID !== raw.id) {
continue;
}
this.squadList.set(squad.id, new WeakRef(squad));
}
for (const general of rsc.generalList.values()) {
if (general.raw.nationID !== raw.id) {
continue;
}
this.generalList.set(general.id, new WeakRef(general));
if (general.isUser) {
this.userGeneralList.set(general.id, new WeakRef(general));
if (categorizeGeneral(general) === "war") {
this.warUserGeneralList.set(general.id, new WeakRef(general));
}
else {
this.domesticUserGeneralList.set(general.id, new WeakRef(general));
}
} else {
this.npcGeneralList.set(general.id, new WeakRef(general));
if (categorizeGeneral(general) === "war") {
this.warNPCGeneralList.set(general.id, new WeakRef(general));
}
else {
this.domesticNPCGeneralList.set(general.id, new WeakRef(general));
}
}
const staffLevel = general.staffLevel;
if (staffLevel !== undefined) {
this.staffList.set(staffLevel, new WeakRef(general));
}
}
}
public get id(): NationID {
return this._raw.id;
}
@@ -23,4 +103,64 @@ export class Nation extends LazyEntityUpdater<INationEntity> {
public get name(): NationName {
return this._raw.name;
}
public _kickGeneral(general: General | GeneralID) {
//국가에서 장수가 빠져나가는 경우, class내 변수에 대한 처리.
if (!(general instanceof General)) {
general = must(this.generalList.get(general)?.deref());
}
const generalID = general.id;
this.generalList.delete(generalID);
if (general.isUser) {
this.userGeneralList.delete(generalID);
this.warUserGeneralList.delete(generalID);
this.domesticUserGeneralList.delete(generalID);
} else {
this.npcGeneralList.delete(generalID);
this.warNPCGeneralList.delete(generalID);
this.domesticNPCGeneralList.delete(generalID);
}
const staffLevel = general.staffLevel;
if (staffLevel !== undefined) {
this.staffList.delete(staffLevel);
if (staffLevel === StaffLevel.lord) {
throw new LogicError(`Lord is kicked: nationID=${this.id}`);
}
}
if (general.squad) {
general.quitSquad();
}
}
public notifyDestroySquad(squad: Squad) {
this.squadList.delete(squad.id);
}
public _joinGeneral(general: General | GeneralID) {
//국가에 장수가 들어오는 경우, class내 변수에 대한 처리.
if (!(general instanceof General)) {
general = must(this.rsc.general(general));
}
const generalID = general.id;
if (general.isUser) {
this.userGeneralList.set(generalID, new WeakRef(general));
} else {
this.npcGeneralList.set(generalID, new WeakRef(general));
}
const staffLevel = general.staffLevel;
if (staffLevel !== undefined) {
this.staffList.set(staffLevel, new WeakRef(general));
}
}
}
+17 -9
View File
@@ -9,21 +9,27 @@ export class Squad extends LazyEntityUpdater<ISquadEntity> {
protected readonly _indirectNames: (keyof ISquadEntity)[] = ["id"];
protected readonly _entityType = "Squad";
protected readonly _raw: ISquadEntity;
private _leader: WeakRef<General>;
private _members: Map<GeneralID, WeakRef<General>>;
private _leader!: WeakRef<General>;
private _members!: Map<GeneralID, WeakRef<General>>;
constructor(
raw: ISquadEntity,
protected rsc: IResourceController
protected rsc: IResourceController,
private _rawMembers: GeneralID[]
){
super();
this._raw = raw;
}
const members = rsc.generalBySquad(raw.id);
const leaderID: GeneralID = raw.id as GeneralID;
this._leader = new WeakRef(must(members.get(leaderID)));
members.delete(leaderID);
this._members = new Map([...members].map(([k,v])=>[k, new WeakRef(v)]));
public bootstrap(){
this._members = new Map(this._rawMembers.map((id)=>{
return [id, new WeakRef(must(this.rsc.general(id)))];
}));
const leaderID = this._raw.id as GeneralID;
this._leader = must(this._members.get(leaderID));
this._members.delete(leaderID);
}
public get id(){
@@ -38,7 +44,7 @@ export class Squad extends LazyEntityUpdater<ISquadEntity> {
return this._members;
}
public destructSquad(withLeader = true){
public destroySquad(withLeader = true){
this._members.forEach((member)=>{
const general = must(member.deref());
general.quitSquad();
@@ -47,6 +53,8 @@ export class Squad extends LazyEntityUpdater<ISquadEntity> {
this.leader.quitSquad();
}
this.leader.nation.notifyDestroySquad(this);
this.rsc.reserveDelete(this);
}