refactor: 将 Layer 0 单独放到一个包

This commit is contained in:
unanmed 2026-05-17 21:32:23 +08:00
parent bf781c5ee8
commit 8f4c4b7df2
48 changed files with 159 additions and 97 deletions

11
dev.md
View File

@ -128,8 +128,9 @@
**Layer 2 — 执行层**:直接引用 Layer 1负责产生影响游戏进程的动作如玩家控制、战斗计算等。本层内容不会进入存档仅通过修改 Layer 1 的数据来影响游戏状态,并通过统一接口 `ICoreState` 对外暴露执行能力。
| 包 | 层级 | 说明 |
| ------------------- | ----------------- | ------------------------------------------------------------------------------- |
| `@user/data-base` | Layer 0 / Layer 1 | 公共层与数据层,定义 `IStateBase` 及各类游戏数据(地图、怪物、玩家属性等) |
| `@user/data-state` | — | 数据端的顶层模块,指导 Layer 2 的执行行为,不直接参与执行 |
| `@user/data-system` | Layer 2 | 执行层,定义 `ICoreState`,依赖数据层实现玩家控制、战斗计算等影响游戏进程的动作 |
| 包 | 层级 | 说明 |
| ------------------- | ------- | ------------------------------------------------------------------------------- |
| `@user/data-common | Layer 0 | 公共层,定义 `IDataCommon` 及公共无依赖接口 |
| `@user/data-base` | Layer 1 | 数据层,定义 `IStateBase` 及可存档游戏数据(地图、怪物、玩家属性等) |
| `@user/data-system` | Layer 2 | 执行层,定义 `ICoreState`,依赖数据层实现玩家控制、战斗计算等影响游戏进程的动作 |
| `@user/data-state` | — | 数据端的顶层模块,指导 Layer 2 的执行行为,不直接参与执行 |

View File

@ -1,6 +1,7 @@
{
"name": "@user/data-base",
"dependencies": {
"@user/data-common": "workspace:*",
"@motajs/common": "workspace:*",
"@motajs/types": "workspace:*",
"@motajs/loader": "workspace:*"

View File

@ -1,5 +1,5 @@
import { logger } from '@motajs/common';
import { SaveCompression } from '../common';
import { SaveCompression } from '@user/data-common';
import { IEnemy, IEnemySaveState, IReadonlyEnemy, ISpecial } from './types';
export class Enemy<TAttr> implements IEnemy<TAttr> {

View File

@ -10,7 +10,7 @@ import {
SpecialCreation,
IEnemySaveState
} from './types';
import { SaveCompression } from '../common';
import { SaveCompression } from '@user/data-common';
export class EnemyManager<TAttr> implements IEnemyManager<TAttr> {
/** 特殊属性注册表code -> 创建函数 */

View File

@ -1,5 +1,5 @@
import { isEqual } from 'lodash-es';
import { SaveCompression } from '../common';
import { SaveCompression } from '@user/data-common';
import { ISpecial, SpecialCreation } from './types';
// TODO: 颜色参数

View File

@ -1,4 +1,4 @@
import { ISaveableContent } from '../common';
import { ISaveableContent } from '@user/data-common';
//#region 怪物基础

View File

@ -1,6 +1,6 @@
//#region 字段
import { ISaveableContent } from '../common';
import { ISaveableContent } from '@user/data-common';
export interface IFlagCommonField<T> {
/** 此字段所处的 Flag 系统 */

View File

@ -1,5 +1,5 @@
import { logger } from '@motajs/common';
import { SaveCompression } from '../common';
import { SaveCompression } from '@user/data-common';
import { IHeroAttribute, IHeroModifier } from './types';
export abstract class BaseHeroModifier<T, V> implements IHeroModifier<T, V, V> {

View File

@ -1,8 +1,8 @@
import { Hookable, HookController, IHookController } from '@motajs/common';
import { isNil } from 'lodash-es';
import { getFaceMovement, nextFaceDirection } from '../common/utils';
import { getFaceMovement, nextFaceDirection } from '@user/data-common';
import { IHeroFollower, IHeroMover, IHeroMovingHooks } from './types';
import { FaceDirection } from '../common';
import { FaceDirection } from '@user/data-common';
const DEFAULT_HERO_IMAGE: ImageIds = 'hero.png';

View File

@ -8,7 +8,7 @@ import {
IModifierStateSave,
IReadonlyHeroAttribute
} from './types';
import { SaveCompression } from '../common';
import { SaveCompression } from '@user/data-common';
import { logger } from '@motajs/common';
export class HeroState<THero> implements IHeroState<THero> {

View File

@ -1,5 +1,5 @@
import { IFacedTileLocator, IHookBase, IHookable } from '@motajs/common';
import { FaceDirection, ISaveableContent } from '../common';
import { FaceDirection, ISaveableContent } from '@user/data-common';
//#region 勇士属性

View File

@ -1,10 +1,8 @@
export * from './common';
export * from './enemy';
export * from './flag';
export * from './hero';
export * from './load';
export * from './map';
export * from './store';
export * from './game';
export * from './types';

View File

@ -11,13 +11,15 @@ import {
IDynamicTile,
IMapLayer
} from './types';
import { FaceDirection, degradeFace } from '../common';
import { FaceDirection, IDataCommon, degradeFace } from '@user/data-common';
import { DynamicTile } from './dynamicTile';
export class DynamicLayer
extends Hookable<IDynamicLayerHooks>
implements IDynamicLayer
{
readonly state: IDataCommon;
/** 坐标到动态图块集合的映射,外层 key = y内层 key = x不使用 index 是为了支持地图外图块 */
private readonly tilePosMap: Map<number, Map<number, Set<IDynamicTile>>> =
new Map();
@ -26,6 +28,7 @@ export class DynamicLayer
constructor(public readonly layer: IMapLayer) {
super();
this.state = layer.state;
}
protected createController(

View File

@ -1,14 +1,16 @@
import { isNil } from 'lodash-es';
import {
FaceDirection,
IDataCommon,
IMoverController,
IObjectMover,
IRoleFaceBinder
} from '../common';
} from '@user/data-common';
import { IDynamicLayer, IDynamicTile } from './types';
import { DynamicTileMover } from './mover';
export class DynamicTile implements IDynamicTile {
readonly state: IDataCommon;
readonly mover: IObjectMover<IDynamicTile>;
triggerType: number;
@ -21,6 +23,7 @@ export class DynamicTile implements IDynamicTile {
public y: number,
public readonly layer: IDynamicLayer
) {
this.state = layer.state;
this.mover = new DynamicTileMover(this);
this.triggerType = -1;
}

View File

@ -11,7 +11,7 @@ import {
IMapLayerHookController,
IMapLayerHooks
} from './types';
import { ITileStore } from '../store';
import { IDataCommon, ITileStore } from '@user/data-common';
import { MapLayer } from './mapLayer';
export class LayerState
@ -39,6 +39,7 @@ export class LayerState
private dirty: boolean = false;
constructor(
public readonly state: IDataCommon,
public readonly tileStore: ITileStore,
public width: number,
public height: number
@ -52,6 +53,7 @@ export class LayerState
array,
this.width,
this.height,
this,
this.tileStore
);
this.layerList.add(layer);

View File

@ -1,6 +1,7 @@
import { isNil } from 'lodash-es';
import {
IDynamicLayer,
ILayerState,
IMapLayer,
IMapLayerData,
IMapLayerHookController,
@ -8,7 +9,7 @@ import {
} from './types';
import { Hookable, HookController, logger } from '@motajs/common';
import { DynamicLayer } from './dynamicLayer';
import { ITileStore } from '../store';
import { IDataCommon, ITileStore } from '@user/data-common';
// todo: 提供 core.setBlock 等方法的替代方法,同时添加 setBlockList以及前景背景的接口
@ -16,6 +17,8 @@ export class MapLayer
extends Hookable<IMapLayerHooks, IMapLayerHookController>
implements IMapLayer
{
readonly state: IDataCommon;
width: number;
height: number;
empty: boolean = true;
@ -34,9 +37,11 @@ export class MapLayer
array: Uint32Array,
width: number,
height: number,
public readonly layerState: ILayerState,
private readonly tileStore: ITileStore
) {
super();
this.state = layerState.state;
this.width = width;
this.height = height;
const area = width * height;

View File

@ -1,6 +1,6 @@
import { logger } from '@motajs/common';
import { SaveCompression } from '../common';
import { ITileStore } from '../store';
import { IDataCommon, SaveCompression } from '@user/data-common';
import { ITileStore } from '@user/data-common';
import {
ILayerState,
ILayerStateSave,
@ -32,7 +32,10 @@ export class MapStore implements IMapStore {
/** 自动分区激活器开关 */
private autoActivitorEnabled: boolean = false;
constructor(private readonly tileStore: ITileStore) {}
constructor(
private readonly tileStore: ITileStore,
public readonly state: IDataCommon
) {}
//#region 楼层管理
@ -42,7 +45,7 @@ export class MapStore implements IMapStore {
} else {
this.maps.push(id);
}
const state = new LayerState(this.tileStore, width, height);
const state = new LayerState(this.state, this.tileStore, width, height);
// 若 refData 已存在,新楼层直接视为全脏
if (this.refData !== null) {
state.setDirty(true);

View File

@ -4,8 +4,9 @@ import {
ObjectMover,
ObjectMoveStep,
ObjectMoveStepType
} from '../common';
} from '@user/data-common';
import { IDynamicTile } from './types';
import { DYNAMIC_MOVER_FACE } from '../shared';
//#region 动态图块
@ -16,7 +17,8 @@ const enum DynamicMoveCode {
export class DynamicTileMover extends ObjectMover<IDynamicTile> {
constructor(public readonly tile: IDynamicTile) {
super();
const face = tile.state.faceManager;
super(face.get(DYNAMIC_MOVER_FACE)!);
}
protected onMoveStart(): Promise<void> {

View File

@ -1,13 +1,14 @@
import { IHookable, IHookBase, IHookController } from '@motajs/common';
import {
FaceDirection,
IDataCommonExtended,
IMoverController,
IObjectMovable,
IObjectMover,
IRoleFaceBinder,
ISaveableContent
} from '../common';
import { ITileStore } from '../store';
} from '@user/data-common';
import { ITileStore } from '@user/data-common';
//#region 静态图层
@ -69,10 +70,10 @@ export interface IMapLayerHookController extends IHookController<IMapLayerHooks>
getMapData(): Readonly<IMapLayerData>;
}
export interface IMapLayer extends IHookable<
IMapLayerHooks,
IMapLayerHookController
> {
export interface IMapLayer
extends
IHookable<IMapLayerHooks, IMapLayerHookController>,
IDataCommonExtended {
/** 地图宽度 */
readonly width: number;
/** 地图高度 */
@ -85,6 +86,8 @@ export interface IMapLayer extends IHookable<
/** 图层纵深 */
readonly zIndex: number;
/** 当前图层所属的地图状态对象 */
readonly layerState: ILayerState;
/** 此图层对应的动态图块图层z 层级与静态图块一致 */
readonly dynamicLayer: IDynamicLayer;
@ -261,7 +264,8 @@ export interface ILayerStateHooks extends IHookBase {
onResizeLayer(layer: IMapLayer, width: number, height: number): void;
}
export interface ILayerState extends IHookable<ILayerStateHooks> {
export interface ILayerState
extends IHookable<ILayerStateHooks>, IDataCommonExtended {
/** 地图列表 */
readonly layerList: Set<IMapLayer>;
/** 当前楼层共享的图块定义 store */
@ -395,7 +399,8 @@ export interface IMapAreaInterval {
export type MapArea = IMapAreaInterval[];
export interface IMapStore extends ISaveableContent<IMapStoreSave> {
export interface IMapStore
extends ISaveableContent<IMapStoreSave>, IDataCommonExtended {
/** 所有楼层的 id 有序数组 */
readonly maps: ReadonlyArray<string>;
@ -524,7 +529,8 @@ export interface IDynamicLayerHooks extends IHookBase {
onUpdateTilePosition(tile: IDynamicTile, layer: IDynamicLayer): void;
}
export interface IDynamicLayer extends IHookable<IDynamicLayerHooks> {
export interface IDynamicLayer
extends IHookable<IDynamicLayerHooks>, IDataCommonExtended {
/** 当前动态图层所属的静态图层 */
readonly layer: IMapLayer;
@ -598,7 +604,7 @@ export interface IDynamicLayer extends IHookable<IDynamicLayerHooks> {
updateDynamicTile(tile: IDynamicTile): void;
}
export interface IDynamicTile extends IObjectMovable {
export interface IDynamicTile extends IObjectMovable, IDataCommonExtended {
/** 当前图块数字 */
readonly num: number;
/** 当前动态图块携带的触发器类型,-1 表示无触发器 */

View File

@ -0,0 +1,4 @@
import { FaceGroup } from '@user/data-common';
/** 动态图块所使用的默认移动组,不知道干什么的就别动 */
export const DYNAMIC_MOVER_FACE = FaceGroup.Dir8;

View File

@ -1,23 +1,15 @@
import { IHeroFollower, IHeroState } from './hero';
import { IEnemyManager } from './enemy';
import { IFlagSystem } from './flag';
import { IFaceManager, IRoleFaceBinder, ISaveableContent } from './common';
import { IMapStore } from './map';
import { ITileStore } from './store';
import { IDataCommon, ISaveableContent } from '@user/data-common';
export interface IStateSaveData {
/** 跟随者列表 */
readonly followers: readonly IHeroFollower[];
}
export interface IStateBase<TEnemy, THero> {
/** 朝向绑定 */
readonly roleFace: IRoleFaceBinder;
/** 朝向管理 */
readonly faceManager: IFaceManager;
/** 图块定义存储 */
readonly tileStore: ITileStore;
export interface IStateBase<TEnemy, THero> extends IDataCommon {
/** 地图状态 */
readonly maps: IMapStore;
/** 勇士状态 */

View File

@ -0,0 +1,6 @@
{
"name": "@user/data-common",
"dependencies": {
"@motajs/common": "workspace:*"
}
}

View File

@ -1,5 +1,5 @@
import { logger } from '@motajs/common';
import { IFaceData, IRoleFaceBinder } from './types';
import { IFaceData, IRoleFaceBinder } from '../common';
import { isNil } from 'lodash-es';
import { FaceDirection } from '.';

View File

@ -2,7 +2,7 @@ import { FaceDirection } from './types';
//#region 接口与枚举
export const enum InternalFaceGroup {
export const enum FaceGroup {
/** 四方向(上下左右) */
Dir4,
/** 八方向(上下左右+斜向) */

View File

@ -0,0 +1,4 @@
export * from './common';
export * from './store';
export * from './types';

View File

@ -0,0 +1,16 @@
import { IFaceManager, IRoleFaceBinder } from './common';
import { ITileStore } from './store';
export interface IDataCommon {
/** 图块定义存储 */
readonly tileStore: ITileStore<MapDataOf<keyof NumberToId>>;
/** 朝向绑定 */
readonly roleFace: IRoleFaceBinder;
/** 朝向管理 */
readonly faceManager: IFaceManager;
}
export interface IDataCommonExtended {
/** 当前对象对应的基本数据端对象Layer 0 对象) */
readonly state: IDataCommon;
}

View File

@ -3,6 +3,7 @@
"dependencies": {
"@motajs/types": "workspace:*",
"@motajs/common": "workspace:*",
"@user/data-common": "workspace:*",
"@user/data-base": "workspace:*",
"@user/data-system": "workspace:*",
"@user/data-utils": "workspace:*"

View File

@ -1,4 +1,18 @@
import { ICoreState, ISaveableExecutor } from './types';
import {
IRoleFaceBinder,
IFaceManager,
ITileStore,
ISaveableContent,
TileStore,
SaveCompression,
RoleFaceBinder,
FaceManager,
Dir4FaceHandler,
Dir8FaceHandler,
FaceGroup,
FaceDirection
} from '@user/data-common';
import {
EnemyManager,
HeroMover,
@ -11,22 +25,16 @@ import {
IMotaDataLoader,
MotaDataLoader,
loading,
IRoleFaceBinder,
RoleFaceBinder,
FaceDirection,
ISaveableContent,
SaveCompression,
IReadonlyEnemy,
IMapStore,
MapStore,
IFaceManager,
FaceManager,
InternalFaceGroup,
Dir4FaceHandler,
Dir8FaceHandler,
ITileStore,
TileStore
MapStore
} from '@user/data-base';
import {
DamageSystem,
EnemyContext,
IEnemyContext,
MapDamage
} from '@user/data-system';
import {
CommonAuraConverter,
EnemyLegacyBridge,
@ -55,29 +63,25 @@ import { ILoadProgressTotal, LoadProgressTotal } from '@motajs/loader';
import { isNil } from 'lodash-es';
import { logger } from '@motajs/common';
import { ISaveSystem, SaveSystem } from './save';
import {
DamageSystem,
EnemyContext,
IEnemyContext,
MapDamage
} from '@user/data-system';
export class CoreState implements ICoreState {
// 全局内容
// Layer 0 内容
readonly roleFace: IRoleFaceBinder;
readonly faceManager: IFaceManager;
readonly tileStore: ITileStore<LegacyTileData>;
// 可存档内容
// Layer 1 内容
readonly maps: IMapStore;
readonly hero: IHeroState<IHeroAttr>;
readonly enemyManager: IEnemyManager<IEnemyAttr>;
readonly flags: IFlagSystem;
// 状态内容
// Layer 2 内容
readonly enemyContext: IEnemyContext<IEnemyAttr, IHeroAttr>;
// 用户层内容
readonly loadProgress: ILoadProgressTotal;
readonly dataLoader: IMotaDataLoader;
readonly enemyContext: IEnemyContext<IEnemyAttr, IHeroAttr>;
readonly saveSystem: ISaveSystem;
/** 可存档对象映射 */
@ -94,7 +98,7 @@ export class CoreState implements ICoreState {
const tileStore = new TileStore<LegacyTileData>();
tileStore.attachLegacyConverter(new TileLegacyBridge());
this.tileStore = tileStore;
this.maps = new MapStore(tileStore);
this.maps = new MapStore(tileStore, this);
this.loadProgress = new LoadProgressTotal();
this.dataLoader = new MotaDataLoader(this.loadProgress);
@ -166,9 +170,9 @@ export class CoreState implements ICoreState {
this.faceManager = new FaceManager();
const dir4 = new Dir4FaceHandler();
const dir8 = new Dir8FaceHandler();
this.faceManager.register(InternalFaceGroup.Dir4, dir4);
this.faceManager.register(FaceGroup.Dir4, dir4);
this.faceManager.registerById('dir4', dir4);
this.faceManager.register(InternalFaceGroup.Dir8, dir8);
this.faceManager.register(FaceGroup.Dir8, dir8);
this.faceManager.registerById('dir8', dir8);
this.flags = new FlagSystem();

View File

@ -19,15 +19,14 @@ import {
IMapDamageView
} from '@user/data-system';
import {
IFaceHandler,
ISpecial,
IReadonlyHeroAttribute,
IReadonlyEnemy,
InternalFaceGroup
IReadonlyEnemy
} from '@user/data-base';
import { IZoneValue } from './special';
import { IEnemyAttr, MapDamageType } from './types';
import { IHeroAttr } from '../hero';
import { IFaceHandler, FaceGroup } from '@user/data-common';
const RECT_RANGE = new RectRange();
const MANHATTAN_RANGE = new ManhattanRange();
@ -312,7 +311,7 @@ export class MainMapDamageConverter implements IMapDamageConverter<
const laser = enemy.getSpecial<number>(24);
if (laser) {
const face = handler.data.faceManager.get(InternalFaceGroup.Dir4)!;
const face = handler.data.faceManager.get(FaceGroup.Dir4)!;
views.push(new LaserDamageView(context, locator, laser, face));
}

View File

@ -1,9 +1,10 @@
import EventEmitter from 'eventemitter3';
import { backDir, toDir } from './utils';
import { fromDirectionString, loading } from '@user/data-base';
import { loading } from '@user/data-base';
import type { HeroKeyMover } from '@user/client-modules';
import { sleep } from '@motajs/common';
import { state } from '..';
import { fromDirectionString } from '@user/data-common';
// todo: 转身功能

View File

@ -1,4 +1,8 @@
import { ITileLegacyConverter, ITileRawData, TileType } from '@user/data-base';
import {
ITileLegacyConverter,
ITileRawData,
TileType
} from '@user/data-common';
export type LegacyTileData = MapDataOf<keyof NumberToId>;

View File

@ -6,7 +6,7 @@ import {
ISaveSystem,
ISaveSystemConfig
} from './types';
import { ISaveableContent, SaveCompression } from '@user/data-base';
import { ISaveableContent, SaveCompression } from '@user/data-common';
import { isNil } from 'lodash-es';
interface ISaveRecord {

View File

@ -1,4 +1,4 @@
import { ISaveableContent, SaveCompression } from '@user/data-base';
import { ISaveableContent, SaveCompression } from '@user/data-common';
import { Dexie, Table } from 'dexie';
export interface IGlobalTrasaction {

View File

@ -1,13 +1,10 @@
import {
IEnemyContext,
IMotaDataLoader,
ISaveableContent,
IStateBase
} from '@user/data-base';
import { IMotaDataLoader, IStateBase } from '@user/data-base';
import { IEnemyAttr } from './enemy';
import { IHeroAttr } from './hero';
import { ILoadProgressTotal } from '@motajs/loader';
import { ISaveSystem } from './save';
import { IEnemyContext } from '@user/data-system';
import { ISaveableContent } from '@user/data-common';
export interface ISaveableExecutor<T, TEnemy = IEnemyAttr, THero = IHeroAttr> {
/**

View File

@ -19,11 +19,10 @@ import {
IEnemy,
IReadonlyEnemy,
ISpecial,
IStateBase,
ILocationIndexer,
MapLocIndexer
IStateBase
} from '@user/data-base';
import { EnemyView } from './enemy';
import { ILocationIndexer, MapLocIndexer } from '@user/data-common';
export class EnemyContext<TEnemy, THero> implements IEnemyContext<
TEnemy,

View File

@ -9,7 +9,8 @@ import {
IMapDamageReducer,
IMapDamageView
} from './types';
import { ILocationHelper, IStateBase } from '@user/data-base';
import { IStateBase } from '@user/data-base';
import { ILocationHelper } from '@user/data-common';
interface IPointInfo {
/** 该点所有的地图伤害 */

View File

@ -5,9 +5,9 @@ import {
ISpecial,
IReadonlyHeroAttribute,
IHeroAttribute,
IStateBase,
ILocationHelper
IStateBase
} from '@user/data-base';
import { ILocationHelper } from '@user/data-common';
//#region 辅助接口

View File

@ -1,8 +1,9 @@
import type { TimingFn } from 'mutate-animate';
import { heroMoveCollection, MoveStep, state } from '@user/data-state';
import { fromDirectionString, hook, loading } from '@user/data-base';
import { hook, loading } from '@user/data-base';
import { Patch, PatchClass } from '@motajs/legacy-common';
import { isNil } from 'lodash-es';
import { fromDirectionString } from '@user/data-common';
// 向后兼容用,会充当两个版本间过渡的作用

View File

@ -1,4 +1,4 @@
import { FaceDirection } from '@user/data-base';
import { FaceDirection } from '@user/data-common';
export interface ISearchable4Dir {
/** 获取上侧元素 */

View File

@ -288,6 +288,15 @@ importers:
'@motajs/types':
specifier: workspace:*
version: link:../../packages/types
'@user/data-common':
specifier: workspace:*
version: link:../data-common
packages-user/data-common:
dependencies:
'@motajs/common':
specifier: workspace:*
version: link:../../packages/common
packages-user/data-fallback:
dependencies: