mirror of
https://github.com/motajs/template.git
synced 2026-10-11 15:10:17 +08:00
152 lines
4.5 KiB
TypeScript
152 lines
4.5 KiB
TypeScript
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 coreConfigs: Map<string, string> = new Map();
|
|
/** 额外配置对象的路径 */
|
|
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 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);
|
|
}
|
|
|
|
addCoreConfig(identifier: string, url: string): void {
|
|
this.coreConfigs.set(identifier, url);
|
|
}
|
|
|
|
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 --- //'
|
|
);
|
|
for (const [id, url] of this.coreConfigs) {
|
|
const coreTask = new LoadTask<
|
|
LoadDataType.Text,
|
|
ICoreStateCoreConfig
|
|
>({
|
|
identifier: id,
|
|
url: this.resolveURL(url),
|
|
dataType: LoadDataType.Text
|
|
});
|
|
coreTask.setProcessor(processor);
|
|
coreTask.setStarter(this.starter);
|
|
this.manager.addTask(coreTask);
|
|
}
|
|
yield* this.manager.load();
|
|
|
|
// 然后加载其他配置文件
|
|
await Promise.all(
|
|
this.forEachHook(hook => hook.onCoreConfigLoaded?.(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;
|
|
}
|
|
}
|