mirror of
https://github.com/motajs/template.git
synced 2026-11-14 07:24:30 +08:00
refactor: 加载系统重构
This commit is contained in:
1 parent
d12790280a
commit
cc434a6c66
27 files changed
+409
-266
No files matched your search
@@ -0,0 +1,26 @@
|
||||
import { ICoreStateCoreConfig } from '../common';
|
||||
import { IMotaDataLoader, IMotaDataLoaderHooks } from './types';
|
||||
|
||||
export class DefaultDataLoaderHook implements IMotaDataLoaderHooks {
|
||||
awake(): void {}
|
||||
|
||||
destroy(): void {}
|
||||
|
||||
onCoreConfigLoaded(
|
||||
coreConfig: ICoreStateCoreConfig,
|
||||
loader: IMotaDataLoader
|
||||
): Promise<void> {
|
||||
const content = coreConfig.content;
|
||||
loader.addExtraConfig('enemy', content.enemyDir);
|
||||
loader.addExtraConfig('item', content.itemDir);
|
||||
loader.addExtraConfig('map-list', content.mapListDir);
|
||||
loader.addExtraConfig('tile', content.tileDir);
|
||||
const defaults = content.defaults;
|
||||
loader.addExtraConfig('enemy-default', defaults.enemyDefault);
|
||||
loader.addExtraConfig('item-default', defaults.itemDefault);
|
||||
loader.addExtraConfig('map-default', defaults.mapDefault);
|
||||
loader.addExtraConfig('tile-default', defaults.tileDefault);
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,29 @@
|
||||
import { logger } from '@motajs/common';
|
||||
import { ILoadTask, ILoadTaskProcessor, LoadDataType } from '@motajs/loader';
|
||||
|
||||
export class PrefixedJSONCProcessor<T> implements ILoadTaskProcessor<
|
||||
LoadDataType.Text,
|
||||
T
|
||||
> {
|
||||
constructor(readonly prefixSplit: string) {}
|
||||
|
||||
process(
|
||||
response: string,
|
||||
task: ILoadTask<LoadDataType.Text, T>
|
||||
): Promise<T> {
|
||||
const splitted = response.split(this.prefixSplit);
|
||||
if (splitted.length !== 2) {
|
||||
logger.error(66, task.url, this.prefixSplit);
|
||||
return Promise.resolve({} as T);
|
||||
}
|
||||
|
||||
const raw = splitted[1];
|
||||
try {
|
||||
const obj = JSON.parse(raw);
|
||||
return Promise.resolve(obj as T);
|
||||
} catch (e) {
|
||||
logger.error(67, task.url, String(e));
|
||||
return Promise.resolve({} as T);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
import {
|
||||
ILoadManager,
|
||||
ILoadTask,
|
||||
ILoadTaskStarter,
|
||||
LoadDataType,
|
||||
LoadTask
|
||||
} from '@motajs/loader';
|
||||
import { IMotaDataLoader, IMotaDataLoaderHooks } from './types';
|
||||
import { PrefixedJSONCProcessor } from './jsoncProcessor';
|
||||
import { ICoreStateCoreConfig } from '../common';
|
||||
import {
|
||||
Hookable,
|
||||
HookController,
|
||||
IHookController,
|
||||
logger
|
||||
} from '@motajs/common';
|
||||
|
||||
export class MotaDataLoader
|
||||
extends Hookable<IMotaDataLoaderHooks>
|
||||
implements IMotaDataLoader
|
||||
{
|
||||
/** 加载完毕时兑现的 `Promise` */
|
||||
private loadedPromise: Promise<void>;
|
||||
/** 调用以使 `loadedPromise` 兑现 */
|
||||
private loadResolve: () => void;
|
||||
/** 当前是否正在加载 */
|
||||
private loading: boolean = false;
|
||||
/** 当前是否已经加载完毕 */
|
||||
private dataLoaded: boolean = false;
|
||||
|
||||
/** 额外配置对象的路径 */
|
||||
private extraConfigs: Map<string, string> = new Map();
|
||||
/** 配置文件列表 */
|
||||
private configMap: Map<string, any> = new Map();
|
||||
|
||||
/** 自定义加载任务 */
|
||||
private customTask: Set<ILoadTask<LoadDataType, unknown>> = new Set();
|
||||
|
||||
constructor(
|
||||
readonly manager: ILoadManager,
|
||||
readonly coreDir: string,
|
||||
readonly starter: ILoadTaskStarter
|
||||
) {
|
||||
super();
|
||||
const { promise, resolve } = Promise.withResolvers<void>();
|
||||
this.loadedPromise = promise;
|
||||
this.loadResolve = resolve;
|
||||
}
|
||||
|
||||
protected createController(
|
||||
hook: Partial<IMotaDataLoaderHooks>
|
||||
): IHookController<IMotaDataLoaderHooks> {
|
||||
return new HookController(this, hook);
|
||||
}
|
||||
|
||||
addExtraConfig(identifier: string, url: string): void {
|
||||
this.extraConfigs.set(identifier, url);
|
||||
}
|
||||
|
||||
addCustomTask<T>(task: LoadTask<LoadDataType, T>): Promise<T> {
|
||||
this.customTask.add(task);
|
||||
return task.loaded();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析加载路径,根据运行环境确认应当使用什么路径格式
|
||||
* @param url 加载路径
|
||||
*/
|
||||
private resolveURL(url: string) {
|
||||
if (import.meta.env.DEV) {
|
||||
// 开发时 content 文件都在 src 文件夹下,因此前置 src
|
||||
return `${import.meta.env.BASE_URL}src/${url}`;
|
||||
} else {
|
||||
// 而构建后就会把文件移动至游戏根目录下,因此不需要前置 src
|
||||
return `${import.meta.env.BASE_URL}${url}`;
|
||||
}
|
||||
}
|
||||
|
||||
async *start(): AsyncIterable<number> {
|
||||
if (this.loading || this.dataLoaded) return;
|
||||
|
||||
// 首先加载核心配置
|
||||
const processor = new PrefixedJSONCProcessor<ICoreStateCoreConfig>(
|
||||
'// --- SYSTEM PREFIX END --- //'
|
||||
);
|
||||
const coreTask = new LoadTask<LoadDataType.Text, ICoreStateCoreConfig>({
|
||||
identifier: 'data-core-config',
|
||||
url: this.resolveURL(this.coreDir),
|
||||
dataType: LoadDataType.Text
|
||||
});
|
||||
coreTask.setProcessor(processor);
|
||||
coreTask.setStarter(this.starter);
|
||||
this.manager.addTask(coreTask);
|
||||
yield* this.manager.load();
|
||||
|
||||
// 然后加载其他配置文件
|
||||
const coreConfig = await coreTask.loaded();
|
||||
this.configMap.set('core', coreConfig);
|
||||
await Promise.all(
|
||||
this.forEachHook(hook =>
|
||||
hook.onCoreConfigLoaded?.(coreConfig, this)
|
||||
)
|
||||
);
|
||||
|
||||
for (const [id, url] of this.extraConfigs) {
|
||||
const task = new LoadTask({
|
||||
identifier: id,
|
||||
url: this.resolveURL(`content/${url}`),
|
||||
dataType: LoadDataType.Text
|
||||
});
|
||||
task.setProcessor(processor);
|
||||
task.setStarter(this.starter);
|
||||
this.manager.addTask(task);
|
||||
task.loaded().then(obj => {
|
||||
if (this.configMap.has(id)) {
|
||||
logger.error(68, id);
|
||||
return;
|
||||
}
|
||||
this.configMap.set(id, obj);
|
||||
});
|
||||
}
|
||||
|
||||
yield* this.manager.load();
|
||||
|
||||
await Promise.all(
|
||||
this.forEachHook(hook => hook.onExtraConfigLoaded?.(this))
|
||||
);
|
||||
|
||||
for (const task of this.customTask) {
|
||||
this.manager.addTask(task);
|
||||
}
|
||||
|
||||
yield* this.manager.load();
|
||||
|
||||
this.loadResolve();
|
||||
}
|
||||
|
||||
getConfig<T>(identifier: string): T | null {
|
||||
return this.configMap.get(identifier) ?? null;
|
||||
}
|
||||
|
||||
loaded(): Promise<void> {
|
||||
return this.loadedPromise;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { IHookable, IHookBase } from '@motajs/common';
|
||||
import { ILoadManager, LoadDataType, LoadTask } from '@motajs/loader';
|
||||
import { ICoreStateCoreConfig } from '../common';
|
||||
|
||||
export interface IMotaDataLoaderHooks extends IHookBase {
|
||||
/**
|
||||
* 当核心配置对象加载完毕时触发,往往用于添加自定义配置文件
|
||||
* @param coreConfig 核心配置对象
|
||||
* @param loader 数据端加载对象
|
||||
*/
|
||||
onCoreConfigLoaded?(
|
||||
coreConfig: ICoreStateCoreConfig,
|
||||
loader: IMotaDataLoader
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* 当所有的额外配置对象加载完毕后执行,往往用于根据配置文件添加额外加载任务
|
||||
* @param loader 数据端加载对象
|
||||
*/
|
||||
onExtraConfigLoaded?(loader: IMotaDataLoader): Promise<void>;
|
||||
}
|
||||
|
||||
export interface IMotaDataLoader extends IHookable<IMotaDataLoaderHooks> {
|
||||
/** 当前使用的加载管理器 */
|
||||
readonly manager: ILoadManager;
|
||||
|
||||
/**
|
||||
* 开始执行加载
|
||||
*/
|
||||
start(): AsyncIterable<number>;
|
||||
|
||||
/**
|
||||
* 获取当加载执行完毕时兑现的 `Promise`
|
||||
*/
|
||||
loaded(): Promise<void>;
|
||||
|
||||
/**
|
||||
* 添加额外配置文件,仅允许在 `onCoreConfigLoaded` 中调用或在加载前调用,加载中及加载后后调用无效。
|
||||
* 文件必须放在 `src/content` 下,并填写相对于 `src/content` 文件夹的路径,文件包含如下要求:
|
||||
*
|
||||
* - 文件必须为 `jsonc` 格式
|
||||
* - 文件的注释必须全部集中在开头
|
||||
* - 文件中的最后一行注释必须是 `// --- SYSTEM PREFIX END --- //`
|
||||
* @param identifier 加载任务与配置文件的标识符
|
||||
* @param url 额外配置文件路径
|
||||
*/
|
||||
addExtraConfig(identifier: string, url: string): void;
|
||||
|
||||
/**
|
||||
* 添加自定义加载任务,仅允许在 `onCoreConfigLoaded` 和 `onExtraConfigLoaded` 中调用或在加载前调用,
|
||||
* 加载中及加载后后调用无效。所有的自定义加载任务都会在配置文件加载完毕后开始加载。
|
||||
* @param task 自定义加载任务实例
|
||||
* @returns 任务加载完毕后兑现,兑现值为经过加载处理器处理后的值
|
||||
*/
|
||||
addCustomTask<T>(task: LoadTask<LoadDataType, T>): Promise<T>;
|
||||
|
||||
/**
|
||||
* 获取指定配置文件,例如核心配置文件是 `core`,怪物配置文件是 `enemy` 等等
|
||||
* @param identifier 配置文件标识符
|
||||
*/
|
||||
getConfig<T>(identifier: string): T | null;
|
||||
}
|
||||
Reference in new issue
Block a user