mirror of
https://github.com/motajs/template.git
synced 2026-11-02 15:04:30 +08:00
1 parent
ec59a44efc
commit
8c1becc9f1
19 files changed
+1112
-54
No files matched your search
@@ -52,3 +52,31 @@ export interface IRoleFaceBinder {
|
||||
*/
|
||||
getMainFace(identifier: number): IFaceData | null;
|
||||
}
|
||||
|
||||
//#region 功能接口
|
||||
|
||||
export const enum SaveCompression {
|
||||
/** 不进行压缩,仅提取必要数据 */
|
||||
NoCompression,
|
||||
/** 进行小幅度压缩,以性能为主要考虑目标 */
|
||||
LowCompression,
|
||||
/** 进行大幅度压缩,以体积为主要考虑目标 */
|
||||
HighCompression
|
||||
}
|
||||
|
||||
export interface ISaveableContent<T> {
|
||||
/**
|
||||
* 保存对象状态,返回的对象应该经过深拷贝(即 `structuedClone`)
|
||||
* @param compression 压缩级别
|
||||
*/
|
||||
saveState(compression: SaveCompression): T;
|
||||
|
||||
/**
|
||||
* 读取对象状态
|
||||
* @param state 状态对象
|
||||
* @param compression 压缩级别
|
||||
*/
|
||||
loadState(state: T, compression: SaveCompression): void;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@@ -2,7 +2,7 @@ import { IFlagCommonField, IFlagSystem, IFlagSystemSave } from './types';
|
||||
import { FlagCommonField } from './field';
|
||||
|
||||
export class FlagSystem implements IFlagSystem {
|
||||
private readonly fieldMap: Map<PropertyKey, FlagCommonField<any>> =
|
||||
private readonly fieldMap: Map<PropertyKey, IFlagCommonField<any>> =
|
||||
new Map();
|
||||
|
||||
occupied(field: PropertyKey): boolean {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
//#region 字段
|
||||
|
||||
import { ISaveableContent } from '../common';
|
||||
|
||||
export interface IFlagCommonField<T> {
|
||||
/** 此字段所处的 Flag 系统 */
|
||||
readonly system: IFlagSystem;
|
||||
@@ -42,7 +44,7 @@ export interface IFlagSystemSave {
|
||||
readonly fields: Map<PropertyKey, any>;
|
||||
}
|
||||
|
||||
export interface IFlagSystem {
|
||||
export interface IFlagSystem extends ISaveableContent<IFlagSystemSave> {
|
||||
/**
|
||||
* 判断一个字段是否被占用,类似于旧样板的 `core.hasFlag`
|
||||
* @param field 字段名称
|
||||
@@ -131,17 +133,6 @@ export interface IFlagSystem {
|
||||
* @param defaultValue 字段默认值
|
||||
*/
|
||||
getFieldValueDefaults<T>(field: PropertyKey, defaultValue: T): T;
|
||||
|
||||
/**
|
||||
* 对 Flag 系统进行结构化复制,形成存档对象
|
||||
*/
|
||||
saveState(): IFlagSystemSave;
|
||||
|
||||
/**
|
||||
* 从指定存档对象读取信息
|
||||
* @param state 存档对象
|
||||
*/
|
||||
loadState(state: IFlagSystemSave): void;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@@ -1,7 +1,9 @@
|
||||
import { logger } from '@motajs/common';
|
||||
import { SaveCompression } from '../common';
|
||||
import { IHeroAttribute, IHeroModifier } from './types';
|
||||
|
||||
export abstract class BaseHeroModifier<T, V> implements IHeroModifier<T, V> {
|
||||
export abstract class BaseHeroModifier<T, V> implements IHeroModifier<T, V, V> {
|
||||
abstract readonly type: string;
|
||||
abstract readonly priority: number;
|
||||
|
||||
owner: IHeroAttribute<unknown> | null = null;
|
||||
@@ -25,6 +27,14 @@ export abstract class BaseHeroModifier<T, V> implements IHeroModifier<T, V> {
|
||||
this.owner = attribute;
|
||||
}
|
||||
|
||||
saveState(_compression: SaveCompression): V {
|
||||
return this.currentValue;
|
||||
}
|
||||
|
||||
loadState(state: V, _compression: SaveCompression): void {
|
||||
this.setValue(state);
|
||||
}
|
||||
|
||||
abstract modify(value: T, baseValue: T, name: string): T;
|
||||
|
||||
abstract clone(): IHeroModifier<T, V>;
|
||||
@@ -161,4 +171,14 @@ export class HeroAttribute<THero> implements IHeroAttribute<THero> {
|
||||
getModifiableClone(): IHeroAttribute<THero> {
|
||||
return this.clone();
|
||||
}
|
||||
|
||||
toStructured(): THero {
|
||||
return structuredClone(this.attribute);
|
||||
}
|
||||
|
||||
*iterateModifiers(): IterableIterator<[keyof THero, IHeroModifier]> {
|
||||
for (const [modifier, name] of this.modifierName) {
|
||||
yield [name, modifier];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,20 @@
|
||||
import { HeroAttribute } from './attribute';
|
||||
import {
|
||||
IHeroAttribute,
|
||||
IHeroModifier,
|
||||
IHeroMover,
|
||||
IHeroState,
|
||||
IHeroStateSave,
|
||||
IModifierStateSave,
|
||||
IReadonlyHeroAttribute
|
||||
} from './types';
|
||||
import { SaveCompression } from '../common';
|
||||
import { logger } from '@motajs/common';
|
||||
|
||||
export class HeroState<THero> implements IHeroState<THero> {
|
||||
/** 修饰器工厂函数注册表 */
|
||||
private readonly registry: Map<string, () => IHeroModifier> = new Map();
|
||||
|
||||
constructor(
|
||||
public mover: IHeroMover,
|
||||
public attribute: IHeroAttribute<THero>
|
||||
@@ -34,4 +43,74 @@ export class HeroState<THero> implements IHeroState<THero> {
|
||||
getIsolatedAttribute(): IHeroAttribute<THero> {
|
||||
return this.attribute.getModifiableClone();
|
||||
}
|
||||
|
||||
registerModifier(type: string, cons: () => IHeroModifier): void {
|
||||
this.registry.set(type, cons);
|
||||
}
|
||||
|
||||
createModifier<T, V>(type: string): IHeroModifier<T, V> | null {
|
||||
const cons = this.registry.get(type);
|
||||
if (!cons) {
|
||||
logger.warn(116, type);
|
||||
return null;
|
||||
} else {
|
||||
return cons() as IHeroModifier<T, V>;
|
||||
}
|
||||
}
|
||||
|
||||
createAndInsertModifier<K extends keyof THero, V>(
|
||||
type: string,
|
||||
name: K
|
||||
): IHeroModifier<THero[K], V> | null {
|
||||
const modifier = this.createModifier<THero[K], V>(type);
|
||||
if (!modifier) return null;
|
||||
this.attribute.addModifier(name, modifier);
|
||||
return modifier;
|
||||
}
|
||||
|
||||
saveState(compression: SaveCompression): IHeroStateSave<THero> {
|
||||
const modifiers: IModifierStateSave[] = [];
|
||||
for (const [name, modifier] of this.attribute.iterateModifiers()) {
|
||||
modifiers.push({
|
||||
name,
|
||||
type: modifier.type,
|
||||
state: modifier.saveState(compression)
|
||||
});
|
||||
}
|
||||
return {
|
||||
attribute: this.attribute.toStructured(),
|
||||
locator: {
|
||||
x: this.mover.x,
|
||||
y: this.mover.y,
|
||||
direction: this.mover.direction
|
||||
},
|
||||
followers: structuredClone(this.mover.followers),
|
||||
modifiers
|
||||
};
|
||||
}
|
||||
|
||||
loadState(
|
||||
state: IHeroStateSave<THero>,
|
||||
compression: SaveCompression
|
||||
): void {
|
||||
const newAttribute = new HeroAttribute<THero>(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 as never, compression);
|
||||
newAttribute.addModifier(
|
||||
save.name as keyof THero,
|
||||
modifier as unknown as IHeroModifier<THero[keyof THero]>
|
||||
);
|
||||
}
|
||||
this.attribute = newAttribute;
|
||||
this.mover.setPosition(state.locator.x, state.locator.y);
|
||||
this.mover.turn(state.locator.direction);
|
||||
this.mover.removeAllFollowers();
|
||||
state.followers.forEach(follower => {
|
||||
this.mover.addFollower(follower.num, follower.identifier);
|
||||
this.mover.setFollowerAlpha(follower.identifier, follower.alpha);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
import { IHookBase, IHookable } from '@motajs/common';
|
||||
import { FaceDirection } from '@user/data-state';
|
||||
import { IFacedTileLocator, IHookBase, IHookable } from '@motajs/common';
|
||||
import { FaceDirection, ISaveableContent } from '../common';
|
||||
|
||||
//#region 勇士属性
|
||||
|
||||
export interface IHeroModifier<T = unknown, V = unknown> {
|
||||
export interface IHeroModifier<
|
||||
T = unknown,
|
||||
V = unknown,
|
||||
S = unknown
|
||||
> extends ISaveableContent<S> {
|
||||
/** 修饰器类型 */
|
||||
readonly type: string;
|
||||
/** 修饰器优先级 */
|
||||
readonly priority: number;
|
||||
/** 修饰器参数值 */
|
||||
@@ -42,6 +48,15 @@ export interface IHeroModifier<T = unknown, V = unknown> {
|
||||
clone(): IHeroModifier<T, V>;
|
||||
}
|
||||
|
||||
export interface IModifierStateSave {
|
||||
/** 属性名称 */
|
||||
readonly name: PropertyKey;
|
||||
/** 修饰器类型 */
|
||||
readonly type: string;
|
||||
/** 修饰器存档数据 */
|
||||
readonly state: unknown;
|
||||
}
|
||||
|
||||
export interface IReadonlyHeroAttribute<THero> {
|
||||
/**
|
||||
* 获取勇士的基础属性,即未经过任何 Buff 或装备等加成的属性
|
||||
@@ -77,6 +92,16 @@ export interface IReadonlyHeroAttribute<THero> {
|
||||
* 获取此勇士属性对象的可修改副本
|
||||
*/
|
||||
getModifiableClone(): IHeroAttribute<THero>;
|
||||
|
||||
/**
|
||||
* 转换为结构化对象
|
||||
*/
|
||||
toStructured(): THero;
|
||||
|
||||
/**
|
||||
* 遍历所有已挂载的属性修饰器
|
||||
*/
|
||||
iterateModifiers(): Iterable<[PropertyKey, IHeroModifier]>;
|
||||
}
|
||||
|
||||
export interface IHeroAttribute<THero> extends IReadonlyHeroAttribute<THero> {
|
||||
@@ -332,7 +357,20 @@ export interface IHeroMover extends IHookable<IHeroMovingHooks> {
|
||||
|
||||
//#region 勇士状态
|
||||
|
||||
export interface IHeroState<THero> {
|
||||
export interface IHeroStateSave<THero> {
|
||||
/** 勇士属性状态 */
|
||||
readonly attribute: THero;
|
||||
/** 勇士当前位置 */
|
||||
readonly locator: IFacedTileLocator;
|
||||
/** 勇士当前的跟随者 */
|
||||
readonly followers: readonly Readonly<IHeroFollower>[];
|
||||
/** 勇士属性修饰器状态 */
|
||||
readonly modifiers: readonly IModifierStateSave[];
|
||||
}
|
||||
|
||||
export interface IHeroState<THero> extends ISaveableContent<
|
||||
IHeroStateSave<THero>
|
||||
> {
|
||||
/** 勇士移动对象 */
|
||||
readonly mover: IHeroMover;
|
||||
/** 勇士属性对象 */
|
||||
@@ -369,6 +407,29 @@ export interface IHeroState<THero> {
|
||||
* 获取独立勇士属性对象,修改此对象不会影响勇士本身的属性
|
||||
*/
|
||||
getIsolatedAttribute(): IHeroAttribute<THero>;
|
||||
|
||||
/**
|
||||
* 注册一个修饰器工厂函数
|
||||
* @param type 修饰器类型
|
||||
* @param cons 工厂函数
|
||||
*/
|
||||
registerModifier(type: string, cons: () => IHeroModifier): void;
|
||||
|
||||
/**
|
||||
* 创建指定类型的修饰器实例
|
||||
* @param type 修饰器类型
|
||||
*/
|
||||
createModifier<T, V>(type: string): IHeroModifier<T, V> | null;
|
||||
|
||||
/**
|
||||
* 创建指定类型的修饰器实例并插入至勇士属性对象
|
||||
* @param type 修饰器类型
|
||||
* @param name 属性名称
|
||||
*/
|
||||
createAndInsertModifier<K extends keyof THero, V>(
|
||||
type: string,
|
||||
name: K
|
||||
): IHeroModifier<THero[K], V> | null;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@@ -1,9 +1,7 @@
|
||||
import { IMotaDataLoader } from './load';
|
||||
import { ILoadProgressTotal } from '@motajs/loader';
|
||||
import { IHeroFollower, IHeroState } from './hero';
|
||||
import { IEnemyContext, IEnemyManager } from './enemy';
|
||||
import { IEnemyManager } from './enemy';
|
||||
import { IFlagSystem } from './flag';
|
||||
import { IRoleFaceBinder } from './common';
|
||||
import { IRoleFaceBinder, ISaveableContent } from './common';
|
||||
import { ILayerState } from './map';
|
||||
|
||||
export interface IStateSaveData {
|
||||
@@ -19,11 +17,6 @@ export interface IStateBase<TEnemy, THero> {
|
||||
/** 图块数字到 id 的映射 */
|
||||
readonly numberIdMap: Map<number, string>;
|
||||
|
||||
/** 加载进度对象 */
|
||||
readonly loadProgress: ILoadProgressTotal;
|
||||
/** 数据端加载对象 */
|
||||
readonly dataLoader: IMotaDataLoader;
|
||||
|
||||
/** 地图状态 */
|
||||
readonly layer: ILayerState;
|
||||
/** 勇士状态 */
|
||||
@@ -31,20 +24,20 @@ export interface IStateBase<TEnemy, THero> {
|
||||
|
||||
/** 怪物管理器 */
|
||||
readonly enemyManager: IEnemyManager<TEnemy>;
|
||||
/** 怪物上下文 */
|
||||
readonly enemyContext: IEnemyContext<TEnemy, THero>;
|
||||
|
||||
/** Flag 系统 */
|
||||
readonly flags: IFlagSystem;
|
||||
|
||||
/**
|
||||
* 保存当前状态
|
||||
* 添加可存档对象,添加后系统将会自动在存档时将对象存储
|
||||
* @param id 可存档对象的 id
|
||||
* @param content 可存档对象
|
||||
*/
|
||||
saveState(): IStateSaveData;
|
||||
addSaveableContent(id: string, content: ISaveableContent<unknown>): void;
|
||||
|
||||
/**
|
||||
* 加载状态
|
||||
* @param state 状态对象
|
||||
* 根据 id 获取对应的可存档对象
|
||||
* @param id 可存档对象的 id
|
||||
*/
|
||||
loadState(state: IStateSaveData): void;
|
||||
getSaveableContent<T>(id: string): ISaveableContent<T> | null;
|
||||
}
|
||||
Reference in new issue
Block a user