import { HeroAttribute } from './attribute'; import { HeroFollowersController } from './follower'; import { HeroLocation } from './location'; import { HeroRendering } from './rendering'; import { IHeroAttribute, IHeroFollowersController, IHeroLocation, IHeroModifier, IHeroRendering, IHeroState, IHeroStateSave, IModifierStateSave, IReadonlyHeroAttribute } from './types'; import { FaceDirection, IDataCommon, IFaceHandler, SaveCompression } from '@user/data-common'; import { IFacedTileLocator, logger } from '@motajs/common'; export class HeroState implements IHeroState { /** 修饰器工厂函数注册表 */ private readonly registry: Map< string, () => IHeroModifier > = new Map(); readonly location: IHeroLocation; readonly rendering: IHeroRendering; readonly followers: IHeroFollowersController; constructor( state: IDataCommon, faceHandler: IFaceHandler, public attribute: IHeroAttribute ) { this.rendering = new HeroRendering(state); const defaultLoc: IFacedTileLocator = { x: 0, y: 0, direction: FaceDirection.Down }; this.location = new HeroLocation(state, defaultLoc, faceHandler); this.followers = new HeroFollowersController( state, this.location, faceHandler ); } attachAttribute(attribute: IHeroAttribute): void { this.attribute = attribute; } getLocation(): IFacedTileLocator { return { x: this.location.x, y: this.location.y, direction: this.location.mover.faceDirection }; } getModifiableAttribute(): IHeroAttribute { return this.attribute; } getAttribute(): IReadonlyHeroAttribute { return this.attribute; } getIsolatedAttribute(): IHeroAttribute { return this.attribute.getModifiableClone(); } registerModifier( type: string, cons: () => IHeroModifier ): void { this.registry.set(type, cons); } createModifier(type: string): IHeroModifier | null { const cons = this.registry.get(type); if (!cons) { logger.warn(116, type); return null; } return cons() as IHeroModifier; } createAndInsertModifier( type: string, name: K ): IHeroModifier | null { const modifier = this.createModifier(type); if (!modifier) return null; this.attribute.addModifier(name, modifier); return modifier; } saveState(compression: SaveCompression): IHeroStateSave { const modifiers: IModifierStateSave[] = []; for (const [name, modifier] of this.attribute.iterateModifiers()) { modifiers.push({ name: name as keyof THero, type: modifier.type, state: modifier.saveState(compression) }); } const followerSaves = this.followers .getAllFollowers() .map(v => v.saveState(compression)); return { attribute: this.attribute.toStructured(), location: this.location.saveState(compression), rendering: this.rendering.saveState(compression), followers: followerSaves, modifiers }; } loadState( state: IHeroStateSave, compression: SaveCompression ): void { const newAttribute = new HeroAttribute(state.attribute); for (const save of state.modifiers) { const cons = this.registry.get(save.type); if (!cons) continue; const modifier = cons(); modifier.loadState(save.state, compression); newAttribute.addModifier(save.name, modifier); } this.attribute = newAttribute; this.location.loadState(state.location, compression); this.rendering.loadState(state.rendering, compression); void this.followers.removeAllFollowers(); for (const save of state.followers) { const follower = this.followers.addFollower(save.num); follower.loadState(save, compression); } } }