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:
unanmed 2026-09-11 13:52:54 +08:00
parent 4d094f988f
commit e4e39f7b2b
3 changed files with 35 additions and 217 deletions

View File

@ -15,6 +15,7 @@ import {
IHeroAttr,
IEnemyAttr,
ISaveSystem,
SaveSystem,
GameEventStore,
IGameEventStore,
IItemStore,
@ -22,7 +23,6 @@ import {
IMapStore,
MapStore,
IReplaySystem,
IMapRawData,
ReplaySystem
} from '@user/data-common';
import {
@ -35,6 +35,7 @@ import {
FlagSystem,
IMotaDataLoader,
MotaDataLoader,
loading,
IReadonlyEnemy,
IMapState,
MapState
@ -51,6 +52,7 @@ import {
} from '@user/data-system';
import {
CommonAuraConverter,
EnemyLegacyBridge,
GuardAuraConverter,
MainDamageCalculator,
MainEnemyFinalEffect,
@ -70,12 +72,11 @@ import {
TILE_WIDTH
} from './shared';
import {
createLegacyDependencies,
ILegacyLoadData,
ILegacySerializedLoadData,
LOAD_SERIALIZED_DATA
} from './legacy/dependencies';
import { registerSerializedEvents } from './legacy/events';
ItemLegacyBridge,
LegacyItemData,
LegacyTileData,
TileLegacyBridge
} from './legacy';
import { ILoadProgressTotal, LoadProgressTotal } from '@motajs/loader';
import { isNil } from 'lodash-es';
import { DirectionMapper, IDirectionMapper, logger } from '@motajs/common';
@ -88,8 +89,8 @@ export class CoreState implements ICoreState {
readonly saveSystem: ISaveSystem;
readonly roleFace: IRoleFaceBinder;
readonly faceManager: IFaceManager;
readonly tileStore: ITileStore;
readonly itemStore: IItemStore<IHeroAttr, unknown>;
readonly tileStore: ITileStore<LegacyTileData>;
readonly itemStore: IItemStore<IHeroAttr, LegacyItemData>;
readonly mapStore: IMapStore;
readonly eventStore: IGameEventStore;
readonly directionMapper: IDirectionMapper;
@ -122,12 +123,10 @@ export class CoreState implements ICoreState {
> = new Map();
constructor() {
const legacy = createLegacyDependencies();
//#region L0 初始化
// 存档系统
this.saveSystem = legacy.saveSystem;
this.saveSystem = new SaveSystem();
// 配置存档系统,一般情况下不建议动,除非你知道你在干什么
this.saveSystem.config({
autosaveLevel: SaveCompression.LowCompression,
@ -148,17 +147,12 @@ export class CoreState implements ICoreState {
this.faceManager.registerById('dir8', dir8);
// 图块
const tileStore = new TileStore();
if (legacy.tileConverter) {
tileStore.attachLegacyConverter(legacy.tileConverter);
}
const tileStore = new TileStore<LegacyTileData>();
tileStore.attachLegacyConverter(new TileLegacyBridge());
this.tileStore = tileStore;
// 道具
const itemStore = new ItemStore();
const itemConverter = legacy.createItemConverter(this);
if (itemConverter) {
itemStore.attachLegacyConverter(itemConverter);
}
const itemStore = new ItemStore<IHeroAttr, LegacyItemData>();
itemStore.attachLegacyConverter(new ItemLegacyBridge(this));
this.itemStore = itemStore;
// 地图
const mapStore = new MapStore();
@ -188,7 +182,7 @@ export class CoreState implements ICoreState {
// 怪物管理器
const comparer = new MainEnemyComparer();
const enemyManager = new EnemyManager(legacy.enemyBridge);
const enemyManager = new EnemyManager(new EnemyLegacyBridge());
enemyManager.attachEnemyComparer(comparer);
enemyManager.setAttributeDefaults('hp', 0);
enemyManager.setAttributeDefaults('atk', 0);
@ -235,9 +229,20 @@ export class CoreState implements ICoreState {
this.addSaveableContent('@system/flags', this.flags);
this.addSaveableContent('@system/maps', this.maps);
this.addSaveableContent('@system/enemy', this.enemyManager);
// 旧样板初始化只能经由内部边界进入Node 路径不会注册加载回调
legacy.registerLoading(data => {
this.initLegacyData(data);
// 初始化存档数据库,不要动
loading.once('coreInit', () => {
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 私有方法
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
*/
private initTileStore(data: ILegacyLoadData['tiles']) {
private initTileStore(data: typeof core.maps.blocksInfo) {
const entries = Object.entries(data);
for (const [key, block] of entries) {
this.tileStore.fromLegacy(Number(key), block);
@ -316,7 +300,7 @@ export class CoreState implements ICoreState {
*
* @param data
*/
private initItemStore(data: ILegacyLoadData['items']) {
private initItemStore(data: typeof core.items.items) {
const entries = Object.entries(data);
for (const [id, legacy] of entries) {
const num = this.tileStore.idToNumber(id);
@ -332,7 +316,7 @@ export class CoreState implements ICoreState {
*
* @param data
*/
private initEnemyManager(data: ILegacyLoadData['enemies']) {
private initEnemyManager(data: Record<EnemyIds, Enemy>) {
const manager = this.enemyManager;
const reference = new Map<number, IReadonlyEnemy<IEnemyAttr>>();
for (const [id, enemy] of Object.entries(structuredClone(data))) {
@ -365,8 +349,8 @@ export class CoreState implements ICoreState {
}
private initMapState(
floors: ILegacyLoadData['floors'],
data: ILegacyLoadData['maps']
floors: FloorIds[],
data: Record<FloorIds, ResolvedFloor>
) {
const reference = new Map<string, Map<number, Uint32Array>>();
for (const id of floors) {
@ -438,20 +422,6 @@ export class CoreState implements ICoreState {
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
//#region 存档方法

View File

@ -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>
});
});
}
};
}

View File

@ -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);
}
}