feat: 渲染端配置加载

This commit is contained in:
unanmed 2026-09-21 10:09:20 +08:00
parent d65b107819
commit 50bd679fad
8 changed files with 75 additions and 41 deletions

View File

@ -1,5 +1,5 @@
import { CoreState } from '@user/data-state';
import { IClientCore } from './types';
import { IClientCore, IClientCoreConfig } from './types';
import {
IMotaAudioContext,
ISoundPlayer,
@ -60,7 +60,7 @@ export class ClientCore extends CoreState implements IClientCore {
readonly soundPlayer: ISoundPlayer<SoundIds>;
readonly bgmPlayer: IBGMPlayer<BgmIds>;
constructor() {
constructor(config: IClientCoreConfig) {
super({
loadStarter: new WebLoadStarter(),
coreURL: 'placeholder'
@ -128,6 +128,8 @@ export class ClientCore extends CoreState implements IClientCore {
});
//#endregion
this.loader.addCoreConfig('client', config.clientURL);
}
/**

View File

@ -1,21 +1,31 @@
import {
IMotaDataLoader,
IMotaDataLoaderHooks,
ICoreStateCoreConfig
} from '@user/data-state';
import { logger } from '@motajs/common';
import { IMotaDataLoader, IMotaDataLoaderHooks } from '@user/data-state';
import { IClientConfig } from '../common';
export class RenderLoaderHooks implements IMotaDataLoaderHooks {
constructor(readonly clientDir: string) {}
constructor() {}
awake(): void {}
destroy(): void {}
onCoreConfigLoaded?(
_: ICoreStateCoreConfig,
loader: IMotaDataLoader
): Promise<void> {
loader.addExtraConfig('client', this.clientDir);
onCoreConfigLoaded?(loader: IMotaDataLoader): Promise<void> {
const client = loader.getConfig<IClientConfig>('client');
if (!client) {
logger.error(69, 'Client');
return Promise.resolve();
}
const content = client.content;
loader.addExtraConfig('texture-list', content.textureListDir);
loader.addExtraConfig('audio-list', content.audioListDir);
loader.addExtraConfig('animation-list', content.animationListDir);
loader.addExtraConfig('font-list', content.fontListDir);
const defaults = content.defaults;
loader.addExtraConfig('texture-default', defaults.textureDefault);
loader.addExtraConfig('audio-default', defaults.audioDefault);
loader.addExtraConfig('animation-default', defaults.animationDefault);
loader.addExtraConfig('font-default', defaults.fontDefault);
return Promise.resolve();
}

View File

@ -2,6 +2,11 @@ import { IMapExtensionManager, IMapRenderer } from './render/map';
import { IClientBase } from '@user/client-base';
import { IExcitation, IExcitationDivider } from '@motajs/animate';
export interface IClientCoreConfig {
/** 渲染端数据配置文件路径,相对于 `src/content` */
readonly clientURL: string;
}
export interface IClientCore extends IClientBase {
/** 用于渲染系统的 Raf 激励源 */
readonly rafExcitation: IExcitation<number>;

View File

@ -203,12 +203,9 @@ export class CoreState implements ICoreState {
// 加载
this.loadManager = new LoadManager();
this.loader = new MotaDataLoader(
this.loadManager,
config.coreURL,
config.loadStarter
);
this.loader = new MotaDataLoader(this.loadManager, config.loadStarter);
this.loader.addHook(new DefaultDataLoaderHook());
this.loader.addCoreConfig('core', config.coreURL);
// 存档内容
this.addSaveableContent('@system/hero', this.hero);

View File

@ -1,3 +1,4 @@
import { logger } from '@motajs/common';
import { ICoreStateCoreConfig } from '../common';
import { IMotaDataLoader, IMotaDataLoaderHooks } from './types';
@ -6,10 +7,12 @@ export class DefaultDataLoaderHook implements IMotaDataLoaderHooks {
destroy(): void {}
onCoreConfigLoaded(
coreConfig: ICoreStateCoreConfig,
loader: IMotaDataLoader
): Promise<void> {
onCoreConfigLoaded(loader: IMotaDataLoader): Promise<void> {
const coreConfig = loader.getConfig<ICoreStateCoreConfig>('core');
if (!coreConfig) {
logger.error(69, 'Data');
return Promise.resolve();
}
const content = coreConfig.content;
loader.addExtraConfig('enemy', content.enemyDir);
loader.addExtraConfig('item', content.itemDir);

View File

@ -28,6 +28,8 @@ export class MotaDataLoader
/** 当前是否已经加载完毕 */
private dataLoaded: boolean = false;
/** 核心配置文件路径 */
private coreConfigs: Map<string, string> = new Map();
/** 额外配置对象的路径 */
private extraConfigs: Map<string, string> = new Map();
/** 配置文件列表 */
@ -38,7 +40,6 @@ export class MotaDataLoader
constructor(
readonly manager: ILoadManager,
readonly coreDir: string,
readonly starter: ILoadTaskStarter
) {
super();
@ -53,6 +54,10 @@ export class MotaDataLoader
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);
}
@ -83,23 +88,24 @@ export class MotaDataLoader
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);
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();
// 然后加载其他配置文件
const coreConfig = await coreTask.loaded();
this.configMap.set('core', coreConfig);
await Promise.all(
this.forEachHook(hook =>
hook.onCoreConfigLoaded?.(coreConfig, this)
)
this.forEachHook(hook => hook.onCoreConfigLoaded?.(this))
);
for (const [id, url] of this.extraConfigs) {

View File

@ -1,6 +1,5 @@
import { IHookable, IHookBase } from '@motajs/common';
import { ILoadManager, LoadDataType, LoadTask } from '@motajs/loader';
import { ICoreStateCoreConfig } from '../common';
export interface IMotaDataLoaderHooks extends IHookBase {
/**
@ -8,10 +7,7 @@ export interface IMotaDataLoaderHooks extends IHookBase {
* @param coreConfig 核心配置对象
* @param loader 数据端加载对象
*/
onCoreConfigLoaded?(
coreConfig: ICoreStateCoreConfig,
loader: IMotaDataLoader
): Promise<void>;
onCoreConfigLoaded?(loader: IMotaDataLoader): Promise<void>;
/**
* 当所有的额外配置对象加载完毕后执行,往往用于根据配置文件添加额外加载任务
@ -34,6 +30,19 @@ export interface IMotaDataLoader extends IHookable<IMotaDataLoaderHooks> {
*/
loaded(): Promise<void>;
/**
* 添加核心配置文件,仅允许在加载前调用,之后调用无效。
* 文件必须放在 `src/content` 下,并填写相对于 `src/content` 文件夹的路径,文件包含如下要求:
*
* - 文件必须为 `jsonc` 格式
* - 文件的注释必须全部集中在开头
* - 文件中的最后一行注释必须是 `// --- SYSTEM PREFIX END --- //`
*
* @param identifier 加载任务与配置文件的标识符
* @param url 核心配置文件路径
*/
addCoreConfig(identifier: string, url: string): void;
/**
* 添加额外配置文件,仅允许在 `onCoreConfigLoaded` 中调用或在加载前调用,加载中及加载后后调用无效。
* 文件必须放在 `src/content` 下,并填写相对于 `src/content` 文件夹的路径,文件包含如下要求:
@ -41,6 +50,7 @@ export interface IMotaDataLoader extends IHookable<IMotaDataLoaderHooks> {
* - 文件必须为 `jsonc` 格式
* - 文件的注释必须全部集中在开头
* - 文件中的最后一行注释必须是 `// --- SYSTEM PREFIX END --- //`
*
* @param identifier 加载任务与配置文件的标识符
* @param url 额外配置文件路径
*/

View File

@ -68,6 +68,7 @@
"66": "Load url '$1' error, since specified a prefixed jsonc parser, but no(or more than one) prefix split string '$2' found in response string.",
"67": "Load url '$1' error since the raw json string splitted by prefix split string cannot be parsed to a valid JavaScript object. Parse error info: $2",
"68": "Extra config identifier '$1' has conflicts. More than one extra config use this identifier, and the final load result is unpredictable since network decides which one to be loaded fast.",
"69": "$1 core config not loaded for the next loading phase.",
"2001": "Replay($1): Replay parameter count mismatch: expected $2, got $3.",
"2002": "Replay($1): Replay parameter type mismatch: index $2, expected $3, got $4.",
"2003": "Replay(move): Expected hero to be stopped before execute moving step.",