mirror of
https://github.com/motajs/template.git
synced 2026-05-14 13:01:10 +08:00
318 lines
11 KiB
TypeScript
318 lines
11 KiB
TypeScript
import { ICoreState, ISaveableExecutor } from './types';
|
|
import {
|
|
DamageSystem,
|
|
EnemyContext,
|
|
EnemyManager,
|
|
HeroMover,
|
|
IEnemyContext,
|
|
IEnemyManager,
|
|
MapDamage,
|
|
HeroAttribute,
|
|
HeroState,
|
|
IHeroState,
|
|
IFlagSystem,
|
|
FlagSystem,
|
|
IMotaDataLoader,
|
|
MotaDataLoader,
|
|
loading,
|
|
IRoleFaceBinder,
|
|
RoleFaceBinder,
|
|
FaceDirection,
|
|
ISaveableContent,
|
|
SaveCompression,
|
|
IReadonlyEnemy,
|
|
IMapStore,
|
|
MapStore
|
|
} from '@user/data-base';
|
|
import {
|
|
CommonAuraConverter,
|
|
EnemyLegacyBridge,
|
|
GuardAuraConverter,
|
|
MainDamageCalculator,
|
|
MainEnemyFinalEffect,
|
|
MainMapDamageConverter,
|
|
MainMapDamageReducer,
|
|
registerSpecials,
|
|
MainEnemyComparer,
|
|
IEnemyAttr
|
|
} from './enemy';
|
|
import {
|
|
BG2_ZINDEX,
|
|
BG_ZINDEX,
|
|
EVENT_ZINDEX,
|
|
FG2_ZINDEX,
|
|
FG_ZINDEX,
|
|
HERO_DEFAULT_ATTRIBUTE,
|
|
TILE_HEIGHT,
|
|
TILE_WIDTH
|
|
} from './shared';
|
|
import { IHeroAttr } from './hero';
|
|
import { ILoadProgressTotal, LoadProgressTotal } from '@motajs/loader';
|
|
import { isNil } from 'lodash-es';
|
|
import { logger } from '@motajs/common';
|
|
import { ISaveSystem, SaveSystem } from './save';
|
|
|
|
export class CoreState implements ICoreState {
|
|
// 全局内容
|
|
readonly roleFace: IRoleFaceBinder;
|
|
readonly idNumberMap: Map<string, number>;
|
|
readonly numberIdMap: Map<number, string>;
|
|
|
|
// 可存档内容
|
|
readonly maps: IMapStore;
|
|
readonly hero: IHeroState<IHeroAttr>;
|
|
readonly enemyManager: IEnemyManager<IEnemyAttr>;
|
|
readonly flags: IFlagSystem;
|
|
|
|
// 状态内容
|
|
readonly loadProgress: ILoadProgressTotal;
|
|
readonly dataLoader: IMotaDataLoader;
|
|
readonly enemyContext: IEnemyContext<IEnemyAttr, IHeroAttr>;
|
|
readonly saveSystem: ISaveSystem;
|
|
|
|
/** 可存档对象映射 */
|
|
private readonly saveables: Map<string, ISaveableContent<any>> = new Map();
|
|
/** 所有已添加的可存档对象 */
|
|
private readonly addedSaveables: Set<ISaveableContent<any>> = new Set();
|
|
/** 已绑定的存档执行器 */
|
|
private readonly executors: Map<
|
|
ISaveableContent<any>,
|
|
ISaveableExecutor<any>
|
|
> = new Map();
|
|
|
|
constructor() {
|
|
this.maps = new MapStore();
|
|
this.roleFace = new RoleFaceBinder();
|
|
this.idNumberMap = new Map();
|
|
this.numberIdMap = new Map();
|
|
|
|
this.loadProgress = new LoadProgressTotal();
|
|
this.dataLoader = new MotaDataLoader(this.loadProgress);
|
|
|
|
//#region 勇士初始化
|
|
|
|
const heroMover = new HeroMover();
|
|
const heroAttribute = new HeroAttribute(HERO_DEFAULT_ATTRIBUTE);
|
|
const heroState = new HeroState(heroMover, heroAttribute);
|
|
this.hero = heroState;
|
|
|
|
//#endregion
|
|
|
|
//#region 怪物初始化
|
|
|
|
// 怪物管理器初始化
|
|
const comparer = new MainEnemyComparer();
|
|
const enemyManager = new EnemyManager(new EnemyLegacyBridge());
|
|
enemyManager.attachEnemyComparer(comparer);
|
|
enemyManager.setAttributeDefaults('hp', 0);
|
|
enemyManager.setAttributeDefaults('atk', 0);
|
|
enemyManager.setAttributeDefaults('def', 0);
|
|
enemyManager.setAttributeDefaults('exp', 0);
|
|
enemyManager.setAttributeDefaults('money', 0);
|
|
enemyManager.setAttributeDefaults('point', 0);
|
|
registerSpecials(enemyManager);
|
|
this.enemyManager = enemyManager;
|
|
// 怪物上下文初始化
|
|
const enemyContext = new EnemyContext<IEnemyAttr, IHeroAttr>();
|
|
const damageSystem = new DamageSystem(enemyContext);
|
|
const mapDamage = new MapDamage(enemyContext);
|
|
damageSystem.useCalculator(new MainDamageCalculator());
|
|
mapDamage.useReducer(new MainMapDamageReducer());
|
|
mapDamage.useConverter(new MainMapDamageConverter());
|
|
enemyContext.attachDamageSystem(damageSystem);
|
|
enemyContext.attachMapDamage(mapDamage);
|
|
enemyContext.registerAuraConverter(new CommonAuraConverter());
|
|
enemyContext.registerAuraConverter(new GuardAuraConverter());
|
|
enemyContext.registerFinalEffect(new MainEnemyFinalEffect());
|
|
enemyContext.resize(TILE_WIDTH, TILE_HEIGHT);
|
|
enemyContext.bindHero(heroAttribute);
|
|
this.enemyContext = enemyContext;
|
|
|
|
//#endregion
|
|
|
|
//#region 存档系统
|
|
|
|
this.saveSystem = new SaveSystem();
|
|
// 配置存档系统,一般情况下不建议动,除非你知道你在干什么
|
|
this.saveSystem.config({
|
|
autosaveLevel: SaveCompression.LowCompression,
|
|
commonSaveLevel: SaveCompression.HighCompression,
|
|
autosaveTimeTolerance: 50,
|
|
saveTimeTolerance: 100,
|
|
autosaveStackSize: 20
|
|
});
|
|
|
|
// 初始化存档数据库,不要动
|
|
loading.once('coreInit', () => {
|
|
this.saveSystem.init(`@game/${core.firstData.name}`);
|
|
});
|
|
|
|
//#endregion
|
|
|
|
//#region 其他初始化
|
|
|
|
this.flags = new FlagSystem();
|
|
|
|
// 加载先使用兼容层实现
|
|
loading.once('loaded', () => {
|
|
this.initEnemyManager(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80);
|
|
this.initMapStore(
|
|
core.floorIds,
|
|
core.floors as Record<FloorIds, ResolvedFloor>
|
|
);
|
|
});
|
|
|
|
this.addSaveableContent('@system/hero', this.hero);
|
|
this.addSaveableContent('@system/flags', this.flags);
|
|
this.addSaveableContent('@system/maps', this.maps);
|
|
this.addSaveableContent('@system/enemy', this.enemyManager);
|
|
|
|
//#endregion
|
|
}
|
|
|
|
/**
|
|
* 初始化怪物管理器对象
|
|
* @param data 旧样板怪物存储对象
|
|
*/
|
|
private initEnemyManager(data: Record<EnemyIds, Enemy>) {
|
|
// TODO: 修改怪物模板并存入存档,即 core.setEnemy
|
|
const manager = this.enemyManager;
|
|
const reference = new Map<number, IReadonlyEnemy<IEnemyAttr>>();
|
|
for (const [id, enemy] of Object.entries(structuredClone(data))) {
|
|
const num = this.idNumberMap.get(id);
|
|
if (isNil(num)) continue;
|
|
if (enemy.faceIds) {
|
|
// 有 faceId 的要把其他的也映射到当前怪物
|
|
const { left, up, right, down } = enemy.faceIds;
|
|
const leftCode = this.idNumberMap.get(left)!;
|
|
const upCode = this.idNumberMap.get(up)!;
|
|
const rightCode = this.idNumberMap.get(right)!;
|
|
const downCode = this.idNumberMap.get(down)!;
|
|
const prefab = manager.fromLegacyEnemy(downCode, enemy);
|
|
reference.set(downCode, prefab);
|
|
manager.addPrefab(prefab);
|
|
this.roleFace.malloc(downCode, FaceDirection.Down);
|
|
this.roleFace.bind(leftCode, downCode, FaceDirection.Left);
|
|
this.roleFace.bind(upCode, downCode, FaceDirection.Up);
|
|
this.roleFace.bind(rightCode, downCode, FaceDirection.Down);
|
|
manager.reusePrefab(num, leftCode, left);
|
|
manager.reusePrefab(num, upCode, up);
|
|
manager.reusePrefab(num, rightCode, right);
|
|
} else {
|
|
const prefab = manager.fromLegacyEnemy(num, enemy);
|
|
reference.set(num, prefab);
|
|
manager.addPrefab(prefab);
|
|
}
|
|
}
|
|
manager.compareWith(reference);
|
|
}
|
|
|
|
private initMapStore(
|
|
floors: FloorIds[],
|
|
data: Record<FloorIds, ResolvedFloor>
|
|
) {
|
|
const reference = new Map<string, Map<number, Uint32Array>>();
|
|
for (const id of floors) {
|
|
const floor = data[id];
|
|
const state = this.maps.createLayerState(
|
|
id,
|
|
floor.width,
|
|
floor.height
|
|
);
|
|
const bg = state.addLayer();
|
|
const bg2 = state.addLayer();
|
|
const event = state.addLayer();
|
|
const fg = state.addLayer();
|
|
const fg2 = state.addLayer();
|
|
bg.setZIndex(BG_ZINDEX);
|
|
bg2.setZIndex(BG2_ZINDEX);
|
|
event.setZIndex(EVENT_ZINDEX);
|
|
fg.setZIndex(FG_ZINDEX);
|
|
fg2.setZIndex(FG2_ZINDEX);
|
|
state.setLayerAlias(bg, 'bg');
|
|
state.setLayerAlias(bg2, 'bg2');
|
|
state.setLayerAlias(event, 'event');
|
|
state.setLayerAlias(fg, 'fg');
|
|
state.setLayerAlias(fg2, 'fg2');
|
|
state.setActiveStatus(false);
|
|
|
|
const size = floor.width * floor.height;
|
|
const ref = new Map<number, Uint32Array>();
|
|
|
|
if (floor.bgmap && floor.bgmap.length > 0) {
|
|
const arr = new Uint32Array(floor.bgmap.flat());
|
|
bg.setMapRef(arr);
|
|
ref.set(BG_ZINDEX, new Uint32Array(arr));
|
|
} else {
|
|
ref.set(BG_ZINDEX, new Uint32Array(size));
|
|
}
|
|
|
|
if (floor.bg2map && floor.bg2map.length > 0) {
|
|
const arr = new Uint32Array(floor.bg2map.flat());
|
|
bg2.setMapRef(arr);
|
|
ref.set(BG2_ZINDEX, new Uint32Array(arr));
|
|
} else {
|
|
ref.set(BG2_ZINDEX, new Uint32Array(size));
|
|
}
|
|
|
|
if (floor.map && floor.map.length > 0) {
|
|
const arr = new Uint32Array(floor.map.flat());
|
|
event.setMapRef(arr);
|
|
ref.set(EVENT_ZINDEX, new Uint32Array(arr));
|
|
} else {
|
|
ref.set(EVENT_ZINDEX, new Uint32Array(size));
|
|
}
|
|
|
|
if (floor.fgmap && floor.fgmap.length > 0) {
|
|
const arr = new Uint32Array(floor.fgmap.flat());
|
|
fg.setMapRef(arr);
|
|
ref.set(FG_ZINDEX, new Uint32Array(arr));
|
|
} else {
|
|
ref.set(FG_ZINDEX, new Uint32Array(size));
|
|
}
|
|
|
|
if (floor.fg2map && floor.fg2map.length > 0) {
|
|
const arr = new Uint32Array(floor.fg2map.flat());
|
|
fg2.setMapRef(arr);
|
|
ref.set(FG2_ZINDEX, new Uint32Array(arr));
|
|
} else {
|
|
ref.set(FG2_ZINDEX, new Uint32Array(size));
|
|
}
|
|
|
|
reference.set(id, ref);
|
|
}
|
|
this.maps.compareWith(reference);
|
|
}
|
|
|
|
addSaveableContent(id: string, content: ISaveableContent<unknown>): void {
|
|
if (this.saveables.has(id)) {
|
|
logger.warn(112, id);
|
|
return;
|
|
}
|
|
this.saveables.set(id, content);
|
|
this.addedSaveables.add(content);
|
|
}
|
|
|
|
getSaveableContent<T>(id: string): ISaveableContent<T> | null {
|
|
const content = this.saveables.get(id);
|
|
return (content as ISaveableContent<T>) ?? null;
|
|
}
|
|
|
|
bindSaveableExecuter<T>(
|
|
content: ISaveableContent<T> | string,
|
|
executor: ISaveableExecutor<T>
|
|
): void {
|
|
if (typeof content === 'string') {
|
|
const saveable = this.saveables.get(content);
|
|
if (!saveable) return;
|
|
this.executors.set(saveable, executor);
|
|
} else {
|
|
if (!this.addedSaveables.has(content)) {
|
|
logger.warn(113);
|
|
return;
|
|
}
|
|
this.executors.set(content, executor);
|
|
}
|
|
}
|
|
}
|