mirror of
https://github.com/motajs/template.git
synced 2026-10-18 04:20:17 +08:00
fix(03-10): restore compatibility loading path
- Remove Phase 3 legacy dependency and serialized loading adapters - Restore SaveSystem, converter, bridge, and loading callback assembly
This commit is contained in:
parent
4d094f988f
commit
e4e39f7b2b
@ -15,6 +15,7 @@ import {
|
|||||||
IHeroAttr,
|
IHeroAttr,
|
||||||
IEnemyAttr,
|
IEnemyAttr,
|
||||||
ISaveSystem,
|
ISaveSystem,
|
||||||
|
SaveSystem,
|
||||||
GameEventStore,
|
GameEventStore,
|
||||||
IGameEventStore,
|
IGameEventStore,
|
||||||
IItemStore,
|
IItemStore,
|
||||||
@ -22,7 +23,6 @@ import {
|
|||||||
IMapStore,
|
IMapStore,
|
||||||
MapStore,
|
MapStore,
|
||||||
IReplaySystem,
|
IReplaySystem,
|
||||||
IMapRawData,
|
|
||||||
ReplaySystem
|
ReplaySystem
|
||||||
} from '@user/data-common';
|
} from '@user/data-common';
|
||||||
import {
|
import {
|
||||||
@ -35,6 +35,7 @@ import {
|
|||||||
FlagSystem,
|
FlagSystem,
|
||||||
IMotaDataLoader,
|
IMotaDataLoader,
|
||||||
MotaDataLoader,
|
MotaDataLoader,
|
||||||
|
loading,
|
||||||
IReadonlyEnemy,
|
IReadonlyEnemy,
|
||||||
IMapState,
|
IMapState,
|
||||||
MapState
|
MapState
|
||||||
@ -51,6 +52,7 @@ import {
|
|||||||
} from '@user/data-system';
|
} from '@user/data-system';
|
||||||
import {
|
import {
|
||||||
CommonAuraConverter,
|
CommonAuraConverter,
|
||||||
|
EnemyLegacyBridge,
|
||||||
GuardAuraConverter,
|
GuardAuraConverter,
|
||||||
MainDamageCalculator,
|
MainDamageCalculator,
|
||||||
MainEnemyFinalEffect,
|
MainEnemyFinalEffect,
|
||||||
@ -70,12 +72,11 @@ import {
|
|||||||
TILE_WIDTH
|
TILE_WIDTH
|
||||||
} from './shared';
|
} from './shared';
|
||||||
import {
|
import {
|
||||||
createLegacyDependencies,
|
ItemLegacyBridge,
|
||||||
ILegacyLoadData,
|
LegacyItemData,
|
||||||
ILegacySerializedLoadData,
|
LegacyTileData,
|
||||||
LOAD_SERIALIZED_DATA
|
TileLegacyBridge
|
||||||
} from './legacy/dependencies';
|
} from './legacy';
|
||||||
import { registerSerializedEvents } from './legacy/events';
|
|
||||||
import { ILoadProgressTotal, LoadProgressTotal } from '@motajs/loader';
|
import { ILoadProgressTotal, LoadProgressTotal } from '@motajs/loader';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
import { DirectionMapper, IDirectionMapper, logger } from '@motajs/common';
|
import { DirectionMapper, IDirectionMapper, logger } from '@motajs/common';
|
||||||
@ -88,8 +89,8 @@ export class CoreState implements ICoreState {
|
|||||||
readonly saveSystem: ISaveSystem;
|
readonly saveSystem: ISaveSystem;
|
||||||
readonly roleFace: IRoleFaceBinder;
|
readonly roleFace: IRoleFaceBinder;
|
||||||
readonly faceManager: IFaceManager;
|
readonly faceManager: IFaceManager;
|
||||||
readonly tileStore: ITileStore;
|
readonly tileStore: ITileStore<LegacyTileData>;
|
||||||
readonly itemStore: IItemStore<IHeroAttr, unknown>;
|
readonly itemStore: IItemStore<IHeroAttr, LegacyItemData>;
|
||||||
readonly mapStore: IMapStore;
|
readonly mapStore: IMapStore;
|
||||||
readonly eventStore: IGameEventStore;
|
readonly eventStore: IGameEventStore;
|
||||||
readonly directionMapper: IDirectionMapper;
|
readonly directionMapper: IDirectionMapper;
|
||||||
@ -122,12 +123,10 @@ export class CoreState implements ICoreState {
|
|||||||
> = new Map();
|
> = new Map();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const legacy = createLegacyDependencies();
|
|
||||||
|
|
||||||
//#region L0 初始化
|
//#region L0 初始化
|
||||||
|
|
||||||
// 存档系统
|
// 存档系统
|
||||||
this.saveSystem = legacy.saveSystem;
|
this.saveSystem = new SaveSystem();
|
||||||
// 配置存档系统,一般情况下不建议动,除非你知道你在干什么
|
// 配置存档系统,一般情况下不建议动,除非你知道你在干什么
|
||||||
this.saveSystem.config({
|
this.saveSystem.config({
|
||||||
autosaveLevel: SaveCompression.LowCompression,
|
autosaveLevel: SaveCompression.LowCompression,
|
||||||
@ -148,17 +147,12 @@ export class CoreState implements ICoreState {
|
|||||||
this.faceManager.registerById('dir8', dir8);
|
this.faceManager.registerById('dir8', dir8);
|
||||||
|
|
||||||
// 图块
|
// 图块
|
||||||
const tileStore = new TileStore();
|
const tileStore = new TileStore<LegacyTileData>();
|
||||||
if (legacy.tileConverter) {
|
tileStore.attachLegacyConverter(new TileLegacyBridge());
|
||||||
tileStore.attachLegacyConverter(legacy.tileConverter);
|
|
||||||
}
|
|
||||||
this.tileStore = tileStore;
|
this.tileStore = tileStore;
|
||||||
// 道具
|
// 道具
|
||||||
const itemStore = new ItemStore();
|
const itemStore = new ItemStore<IHeroAttr, LegacyItemData>();
|
||||||
const itemConverter = legacy.createItemConverter(this);
|
itemStore.attachLegacyConverter(new ItemLegacyBridge(this));
|
||||||
if (itemConverter) {
|
|
||||||
itemStore.attachLegacyConverter(itemConverter);
|
|
||||||
}
|
|
||||||
this.itemStore = itemStore;
|
this.itemStore = itemStore;
|
||||||
// 地图
|
// 地图
|
||||||
const mapStore = new MapStore();
|
const mapStore = new MapStore();
|
||||||
@ -188,7 +182,7 @@ export class CoreState implements ICoreState {
|
|||||||
|
|
||||||
// 怪物管理器
|
// 怪物管理器
|
||||||
const comparer = new MainEnemyComparer();
|
const comparer = new MainEnemyComparer();
|
||||||
const enemyManager = new EnemyManager(legacy.enemyBridge);
|
const enemyManager = new EnemyManager(new EnemyLegacyBridge());
|
||||||
enemyManager.attachEnemyComparer(comparer);
|
enemyManager.attachEnemyComparer(comparer);
|
||||||
enemyManager.setAttributeDefaults('hp', 0);
|
enemyManager.setAttributeDefaults('hp', 0);
|
||||||
enemyManager.setAttributeDefaults('atk', 0);
|
enemyManager.setAttributeDefaults('atk', 0);
|
||||||
@ -235,9 +229,20 @@ export class CoreState implements ICoreState {
|
|||||||
this.addSaveableContent('@system/flags', this.flags);
|
this.addSaveableContent('@system/flags', this.flags);
|
||||||
this.addSaveableContent('@system/maps', this.maps);
|
this.addSaveableContent('@system/maps', this.maps);
|
||||||
this.addSaveableContent('@system/enemy', this.enemyManager);
|
this.addSaveableContent('@system/enemy', this.enemyManager);
|
||||||
// 旧样板初始化只能经由内部边界进入,Node 路径不会注册加载回调
|
// 初始化存档数据库,不要动
|
||||||
legacy.registerLoading(data => {
|
loading.once('coreInit', () => {
|
||||||
this.initLegacyData(data);
|
this.saveSystem.init(`@game/${core.firstData.name}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载初始化,先使用兼容层实现
|
||||||
|
loading.once('loaded', () => {
|
||||||
|
this.initTileStore(core.maps.blocksInfo);
|
||||||
|
this.initItemStore(core.items.items);
|
||||||
|
this.initEnemyManager(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80);
|
||||||
|
this.initMapState(
|
||||||
|
core.floorIds,
|
||||||
|
core.floors as Record<FloorIds, ResolvedFloor>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 勇士顶层初始化
|
// 勇士顶层初始化
|
||||||
@ -260,32 +265,11 @@ export class CoreState implements ICoreState {
|
|||||||
|
|
||||||
//#region 私有方法
|
//#region 私有方法
|
||||||
|
|
||||||
private initLegacyData(data: ILegacyLoadData): void {
|
|
||||||
this.initTileStore(data.tiles);
|
|
||||||
this.initItemStore(data.items);
|
|
||||||
this.initEnemyManager(data.enemies);
|
|
||||||
if (data.serialized) {
|
|
||||||
this[LOAD_SERIALIZED_DATA](data.serialized);
|
|
||||||
} else {
|
|
||||||
this.initMapState(data.floors, data.maps);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 经内部加载边界注册序列化事件并绑定原始地图事件 id */
|
|
||||||
[LOAD_SERIALIZED_DATA](data: ILegacySerializedLoadData): void {
|
|
||||||
registerSerializedEvents(
|
|
||||||
this.eventStore,
|
|
||||||
this.eventSystem.executor.interpreter,
|
|
||||||
data.events
|
|
||||||
);
|
|
||||||
this.initRawMapState(data.maps);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化图块存储对象
|
* 初始化图块存储对象
|
||||||
* @param data 旧样板图块定义对象
|
* @param data 旧样板图块定义对象
|
||||||
*/
|
*/
|
||||||
private initTileStore(data: ILegacyLoadData['tiles']) {
|
private initTileStore(data: typeof core.maps.blocksInfo) {
|
||||||
const entries = Object.entries(data);
|
const entries = Object.entries(data);
|
||||||
for (const [key, block] of entries) {
|
for (const [key, block] of entries) {
|
||||||
this.tileStore.fromLegacy(Number(key), block);
|
this.tileStore.fromLegacy(Number(key), block);
|
||||||
@ -316,7 +300,7 @@ export class CoreState implements ICoreState {
|
|||||||
* 初始化道具存储对象
|
* 初始化道具存储对象
|
||||||
* @param data 旧样板道具定义对象
|
* @param data 旧样板道具定义对象
|
||||||
*/
|
*/
|
||||||
private initItemStore(data: ILegacyLoadData['items']) {
|
private initItemStore(data: typeof core.items.items) {
|
||||||
const entries = Object.entries(data);
|
const entries = Object.entries(data);
|
||||||
for (const [id, legacy] of entries) {
|
for (const [id, legacy] of entries) {
|
||||||
const num = this.tileStore.idToNumber(id);
|
const num = this.tileStore.idToNumber(id);
|
||||||
@ -332,7 +316,7 @@ export class CoreState implements ICoreState {
|
|||||||
* 初始化怪物管理器对象
|
* 初始化怪物管理器对象
|
||||||
* @param data 旧样板怪物存储对象
|
* @param data 旧样板怪物存储对象
|
||||||
*/
|
*/
|
||||||
private initEnemyManager(data: ILegacyLoadData['enemies']) {
|
private initEnemyManager(data: Record<EnemyIds, Enemy>) {
|
||||||
const manager = this.enemyManager;
|
const manager = this.enemyManager;
|
||||||
const reference = new Map<number, IReadonlyEnemy<IEnemyAttr>>();
|
const reference = new Map<number, IReadonlyEnemy<IEnemyAttr>>();
|
||||||
for (const [id, enemy] of Object.entries(structuredClone(data))) {
|
for (const [id, enemy] of Object.entries(structuredClone(data))) {
|
||||||
@ -365,8 +349,8 @@ export class CoreState implements ICoreState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private initMapState(
|
private initMapState(
|
||||||
floors: ILegacyLoadData['floors'],
|
floors: FloorIds[],
|
||||||
data: ILegacyLoadData['maps']
|
data: Record<FloorIds, ResolvedFloor>
|
||||||
) {
|
) {
|
||||||
const reference = new Map<string, Map<number, Uint32Array>>();
|
const reference = new Map<string, Map<number, Uint32Array>>();
|
||||||
for (const id of floors) {
|
for (const id of floors) {
|
||||||
@ -438,20 +422,6 @@ export class CoreState implements ICoreState {
|
|||||||
this.maps.compareWith(reference);
|
this.maps.compareWith(reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initRawMapState(data: readonly IMapRawData[]): void {
|
|
||||||
const reference = new Map<string, Map<number, Uint32Array>>();
|
|
||||||
for (const raw of data) {
|
|
||||||
const state = this.maps.fromRaw(raw);
|
|
||||||
if (!state) continue;
|
|
||||||
const ref = new Map<number, Uint32Array>();
|
|
||||||
for (const [zIndex, map] of Object.entries(raw.map)) {
|
|
||||||
ref.set(Number(zIndex), new Uint32Array(map));
|
|
||||||
}
|
|
||||||
reference.set(raw.floorId, ref);
|
|
||||||
}
|
|
||||||
this.maps.compareWith(reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 存档方法
|
//#region 存档方法
|
||||||
|
|||||||
@ -1,88 +0,0 @@
|
|||||||
import {
|
|
||||||
IItemLegacyConverter,
|
|
||||||
IHeroAttr,
|
|
||||||
IEnemyAttr,
|
|
||||||
ISaveSystem,
|
|
||||||
ITileLegacyConverter,
|
|
||||||
IMapRawData,
|
|
||||||
MemorySaveSystem,
|
|
||||||
SaveSystem
|
|
||||||
} from '@user/data-common';
|
|
||||||
import { IEnemyLegacyBridge, loading } from '@user/data-base';
|
|
||||||
import { IStateSystem } from '@user/data-system';
|
|
||||||
import { EnemyLegacyBridge } from '../enemy/legacy';
|
|
||||||
import { ItemLegacyBridge, LegacyItemData } from './item';
|
|
||||||
import { LegacyTileData, TileLegacyBridge } from './tile';
|
|
||||||
import { ISerializedEventDefinitions } from './events';
|
|
||||||
|
|
||||||
/** CoreState 内部显式数据加载所需的序列化事件与原始地图 */
|
|
||||||
export interface ILegacySerializedLoadData {
|
|
||||||
readonly events: ISerializedEventDefinitions;
|
|
||||||
readonly maps: readonly IMapRawData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 仅供 CoreState 与 legacy 数据源之间使用的加载方法标识 */
|
|
||||||
export const LOAD_SERIALIZED_DATA = Symbol('loadSerializedData');
|
|
||||||
|
|
||||||
export interface ILegacyLoadData {
|
|
||||||
readonly tiles: typeof core.maps.blocksInfo;
|
|
||||||
readonly items: typeof core.items.items;
|
|
||||||
readonly enemies: Record<EnemyIds, Enemy>;
|
|
||||||
readonly floors: FloorIds[];
|
|
||||||
readonly maps: Record<FloorIds, ResolvedFloor>;
|
|
||||||
readonly serialized?: ILegacySerializedLoadData;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ILegacyDependencies {
|
|
||||||
readonly saveSystem: ISaveSystem;
|
|
||||||
readonly tileConverter: ITileLegacyConverter<LegacyTileData> | null;
|
|
||||||
readonly enemyBridge: IEnemyLegacyBridge<IEnemyAttr>;
|
|
||||||
createItemConverter(
|
|
||||||
state: IStateSystem
|
|
||||||
): IItemLegacyConverter<IHeroAttr, LegacyItemData> | null;
|
|
||||||
registerLoading(onLoaded: (data: ILegacyLoadData) => void): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasLegacyHost(): boolean {
|
|
||||||
return (
|
|
||||||
typeof main !== 'undefined' &&
|
|
||||||
typeof core !== 'undefined' &&
|
|
||||||
typeof window !== 'undefined' &&
|
|
||||||
typeof document !== 'undefined' &&
|
|
||||||
typeof indexedDB !== 'undefined'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createLegacyDependencies(): ILegacyDependencies {
|
|
||||||
if (!hasLegacyHost()) {
|
|
||||||
return {
|
|
||||||
saveSystem: new MemorySaveSystem(),
|
|
||||||
tileConverter: null,
|
|
||||||
enemyBridge: new EnemyLegacyBridge(),
|
|
||||||
createItemConverter: () => null,
|
|
||||||
registerLoading: () => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const saveSystem = new SaveSystem();
|
|
||||||
return {
|
|
||||||
saveSystem,
|
|
||||||
tileConverter: new TileLegacyBridge(),
|
|
||||||
enemyBridge: new EnemyLegacyBridge(),
|
|
||||||
createItemConverter: state => new ItemLegacyBridge(state),
|
|
||||||
registerLoading: onLoaded => {
|
|
||||||
loading.once('coreInit', () => {
|
|
||||||
saveSystem.init(`@game/${core.firstData.name}`);
|
|
||||||
});
|
|
||||||
loading.once('loaded', () => {
|
|
||||||
onLoaded({
|
|
||||||
tiles: core.maps.blocksInfo,
|
|
||||||
items: core.items.items,
|
|
||||||
enemies: enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80,
|
|
||||||
floors: core.floorIds,
|
|
||||||
maps: core.floors as Record<FloorIds, ResolvedFloor>
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
import { EventTrigger, GameEvent, IGameEventStore } from '@user/data-common';
|
|
||||||
import { AnonTokyoInterpreter, Statement } from 'anon-tokyo';
|
|
||||||
|
|
||||||
/** 旧样板内部加载边界使用的序列化事件定义 */
|
|
||||||
export interface ISerializedEventData {
|
|
||||||
readonly trigger: EventTrigger;
|
|
||||||
readonly rawEvent: Statement[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 事件 id 到序列化事件定义的映射 */
|
|
||||||
export interface ISerializedEventDefinitions {
|
|
||||||
readonly [id: string]: ISerializedEventData;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IRuntimeStatement {
|
|
||||||
readonly type?: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isStatement(value: unknown): value is Statement {
|
|
||||||
if (!value || typeof value !== 'object') return false;
|
|
||||||
const statement = value as IRuntimeStatement;
|
|
||||||
return (
|
|
||||||
typeof statement.type === 'number' &&
|
|
||||||
Number.isInteger(statement.type) &&
|
|
||||||
statement.type >= 0 &&
|
|
||||||
statement.type <= 10
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isEventTrigger(value: unknown): value is EventTrigger {
|
|
||||||
return (
|
|
||||||
typeof value === 'number' &&
|
|
||||||
Number.isInteger(value) &&
|
|
||||||
value >= EventTrigger.None &&
|
|
||||||
value <= EventTrigger.OnAfterChangeFloor
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSerializedEventData(value: unknown): value is ISerializedEventData {
|
|
||||||
if (!value || typeof value !== 'object') return false;
|
|
||||||
const data = value as ISerializedEventData;
|
|
||||||
return isEventTrigger(data.trigger) && Array.isArray(data.rawEvent)
|
|
||||||
? data.rawEvent.every(isStatement)
|
|
||||||
: false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 将内部序列化事件定义转换为带有统一解释器的游戏事件实例 */
|
|
||||||
export function registerSerializedEvents(
|
|
||||||
store: IGameEventStore,
|
|
||||||
interpreter: AnonTokyoInterpreter,
|
|
||||||
definitions: ISerializedEventDefinitions
|
|
||||||
): void {
|
|
||||||
if (!definitions || typeof definitions !== 'object') return;
|
|
||||||
for (const [id, data] of Object.entries(definitions)) {
|
|
||||||
if (!id || !isSerializedEventData(data)) continue;
|
|
||||||
const event = new GameEvent<
|
|
||||||
Record<string, any>,
|
|
||||||
Record<string, any>,
|
|
||||||
any
|
|
||||||
>(interpreter, data.rawEvent);
|
|
||||||
event.setTrigger(data.trigger);
|
|
||||||
store.addEvent(id, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user