refactor: Delete global loading & hook object

This commit is contained in:
unanmed 2026-09-30 12:30:42 +08:00
parent 7c155be5ce
commit d8fa4b8507
16 changed files with 33 additions and 978 deletions

View File

@ -1,4 +1,3 @@
export * from './load';
export * from './material';
export * from './save';

View File

@ -1,37 +0,0 @@
export const iconNames: string[] = [
'floor',
'lv',
'hpmax',
'hp',
'atk',
'def',
'mdef',
'money',
'exp',
'up',
'book',
'fly',
'toolbox',
'keyboard',
'shop',
'save',
'load',
'settings',
'play',
'pause',
'stop',
'speedDown',
'speedUp',
'rewind',
'equipbox',
'mana',
'skill',
'btn1',
'btn2',
'btn3',
'btn4',
'btn5',
'btn6',
'btn7',
'btn8'
];

View File

@ -1,3 +0,0 @@
export * from './data';
export * from './loader';
export * from './types';

View File

@ -1,515 +0,0 @@
import {
ILoadManager,
LoadDataType,
ILoadTask,
LoadTask,
ILoadTaskProcessor
} from '@motajs/loader';
import {
CompressedUsage,
CustomLoadFunc,
ICompressedMotaAssetsData,
ICompressedMotaAssetsLoadList,
IMotaAssetsLoader
} from './types';
import JSZip from 'jszip';
import {
LoadAudioProcessor,
LoadFontProcessor,
LoadImageProcessor,
LoadTextProcessor,
LoadZipProcessor
} from '@user/data-base';
import { IMotaAudioContext, ISoundPlayer } from '@motajs/audio';
import { loading } from '@user/data-base';
import { ITextureManager } from '../material';
import { ITextureSplitter, Texture, TextureRowSplitter } from '@motajs/render';
import { iconNames } from './data';
import { IMotaDataLoader } from '@user/data-base';
export class MotaAssetsLoader implements IMotaAssetsLoader {
/** 当前是否正在进行加载 */
loading: boolean = false;
/** 当前加载工作是否已经完成 */
loaded: boolean = false;
readonly imageProcessor: ILoadTaskProcessor<LoadDataType.Blob, ImageBitmap>;
readonly audioProcessor: ILoadTaskProcessor<
LoadDataType.Uint8Array,
AudioBuffer | null
>;
readonly fontProcessor: ILoadTaskProcessor<
LoadDataType.ArrayBuffer,
FontFace
>;
readonly textProcessor: ILoadTaskProcessor<LoadDataType.Text, string>;
readonly zipProcessor: ILoadTaskProcessor<LoadDataType.ArrayBuffer, JSZip>;
/** 素材索引 */
private materialsCounter: number = 0;
/** 贴图行分割器,用于处理遗留 `icons.png` */
private readonly rowSplitter: ITextureSplitter<number>;
constructor(
readonly progress: ILoadManager,
private readonly dataLoader: IMotaDataLoader,
private readonly ac: IMotaAudioContext,
private readonly sounds: ISoundPlayer<SoundIds>,
private readonly materials: ITextureManager
) {
this.imageProcessor = new LoadImageProcessor();
this.audioProcessor = new LoadAudioProcessor(ac);
this.fontProcessor = new LoadFontProcessor();
this.textProcessor = new LoadTextProcessor();
this.zipProcessor = new LoadZipProcessor();
this.rowSplitter = new TextureRowSplitter();
}
//#region 其他处理
private splitMaterialIcons(image: ImageBitmap) {
const tex = new Texture(image);
const splitted = [...this.rowSplitter.split(tex, 32)];
for (let i = 0; i < splitted.length; i++) {
const name = iconNames[i] ? `icon-${iconNames[i]}` : `icons-${i}`;
// todo: 早晚删除 icons.png
const index = this.materialsCounter++;
this.materials.imageStore.addTexture(index, splitted[i]);
this.materials.imageStore.alias(index, name);
}
}
//#region 加载后处理
/**
* 当字体加载完成后的操作
* @param font 字体名称
* @param fontFace 字体 `FontFace` 对象
*/
private fontLoaded(font: string, fontFace: FontFace) {
const suffix = font.lastIndexOf('.');
const family = font.slice(0, suffix);
fontFace.family = family;
document.fonts.add(fontFace);
return Promise.resolve();
}
/**
* 图片加载完成后的操作
* @param name 图片名称
* @param image 图片的 `ImageBitmap`
*/
private customImagesLoaded(name: ImageIds, image: ImageBitmap) {
core.material.images.images[name] = image;
this.materials.addImage(image, {
index: this.materialsCounter++,
alias: name
});
return Promise.resolve();
}
/**
* 音效加载完成后的操作
* @param name 音效名称
* @param buffer 音效解析完毕的 `AudioBuffer`
*/
private soundLoaded(name: SoundIds, buffer: AudioBuffer | null) {
if (buffer) {
this.sounds.add(name, buffer);
}
return Promise.resolve();
}
/**
* 当 tileset 加载完成后的操作
* @param name tileset 名称
* @param image 图片 `ImageBitmap`
*/
private tilesetLoaded(name: string, image: ImageBitmap) {
core.material.images.tilesets[name] = image;
// this.materials.addTileset(image, {
// index: this.materialsCounter++,
// alias: name
// });
return Promise.resolve();
}
/**
* 当自动元件加载完成后的操作
* @param autotiles 自动元件存储对象
* @param name 自动元件名称
* @param image 自动元件的 `ImageBitmap`
*/
private autotileLoaded(
autotiles: Partial<Record<AllIdsOf<'autotile'>, ImageBitmap>>,
name: AllIdsOf<'autotile'>,
image: ImageBitmap
) {
autotiles[name] = image;
loading.addAutotileLoaded();
loading.onAutotileLoaded(autotiles);
core.material.images.autotile[name] = image;
// const num = icon.autotile[name];
// this.materials.addAutotile(image, {
// id: name,
// num,
// cls: 'autotile'
// });
return Promise.resolve();
}
/**
* 当素材加载完成后的操作
* @param name 素材名称
* @param image 素材 `ImageBitmap`
*/
private materialLoaded(name: string, image: ImageBitmap) {
core.material.images[
name.slice(0, -4) as SelectKey<MaterialImages, ImageBitmap>
] = image;
if (name === 'icons.png') {
this.splitMaterialIcons(image);
}
return Promise.resolve();
}
/**
* 当动画加载完成后的操作
* @param animation 动画内容
*/
private animationLoaded(animation: string) {
const data = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d;
const rows = animation.split('@@@~~~###~~~@@@');
rows.forEach((value, i) => {
const id = data.main.animates[i];
if (value.length === 0) {
throw new Error(`Cannot find animate: '${id}'`);
}
core.material.animates[id] = core.loader._loadAnimate(value);
});
return Promise.resolve();
}
//#endregion
//#region 加载流程
/**
* 开发时的加载流程
*/
private developingLoad() {
const data = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d;
const icon = icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1;
// font
data.main.fonts.forEach(font => {
const url = `project/fonts/${font}`;
const task = new LoadTask<LoadDataType.ArrayBuffer, FontFace>({
url,
identifier: `@system-font/${font}`,
dataType: LoadDataType.ArrayBuffer,
// @ts-expect-error 需要重构
processor: this.fontProcessor,
progress: this.progress
});
task.setProcessor(this.fontProcessor);
this.addCustomLoadTask(task, data => this.fontLoaded(font, data));
});
// image
data.main.images.forEach(image => {
const url = `project/images/${image}`;
const task = new LoadTask<LoadDataType.Blob, ImageBitmap>({
url,
identifier: `@system-image/${image}`,
dataType: LoadDataType.Blob,
// @ts-expect-error 需要重构
processor: this.imageProcessor,
progress: this.progress
});
this.addCustomLoadTask(task, data =>
this.customImagesLoaded(image, data)
);
});
// sound
data.main.sounds.forEach(sound => {
const url = `project/sounds/${sound}`;
const task = new LoadTask<
LoadDataType.Uint8Array,
AudioBuffer | null
>({
url,
identifier: `@system-sound/${sound}`,
dataType: LoadDataType.Uint8Array,
// @ts-expect-error 需要重构
processor: this.audioProcessor,
progress: this.progress
});
this.addCustomLoadTask(task, data => this.soundLoaded(sound, data));
});
// tileset
data.main.tilesets.forEach(tileset => {
const url = `project/tilesets/${tileset}`;
const task = new LoadTask<LoadDataType.Blob, ImageBitmap>({
url,
identifier: `@system-tileset/${tileset}`,
dataType: LoadDataType.Blob,
// @ts-expect-error 需要重构
processor: this.imageProcessor,
progress: this.progress
});
this.addCustomLoadTask(task, data =>
this.tilesetLoaded(tileset, data)
);
});
// autotile
const autotiles: Partial<Record<AllIdsOf<'autotile'>, ImageBitmap>> =
{};
Object.keys(icon.autotile).forEach(key => {
const url = `project/autotiles/${key}.png`;
const task = new LoadTask<LoadDataType.Blob, ImageBitmap>({
url,
identifier: `@system-autotile/${key}`,
dataType: LoadDataType.Blob,
// @ts-expect-error 需要重构
processor: this.imageProcessor,
progress: this.progress
});
this.addCustomLoadTask(task, data =>
this.autotileLoaded(
autotiles,
key as AllIdsOf<'autotile'>,
data
)
);
});
// material
const materialImages = core.materials.slice() as SelectKey<
MaterialImages,
ImageBitmap
>[];
materialImages.push('keyboard');
materialImages
.map(v => `${v}.png`)
.forEach(materialName => {
const url = `project/materials/${materialName}`;
const task = new LoadTask<LoadDataType.Blob, ImageBitmap>({
url,
identifier: `@system-material/${materialName}`,
dataType: LoadDataType.Blob,
// @ts-expect-error 需要重构
processor: this.imageProcessor,
progress: this.progress
});
this.addCustomLoadTask(task, data =>
this.materialLoaded(materialName, data)
);
});
// animate
const animatesUrl = `all/__all_animates__?v=${main.version}&id=${data.main.animates.join(',')}`;
const animateTask = new LoadTask<LoadDataType.Text, string>({
url: animatesUrl,
identifier: '@system-animates',
dataType: LoadDataType.Text,
// @ts-expect-error 需要重构
processor: this.textProcessor,
progress: this.progress
});
this.addCustomLoadTask(animateTask, data => this.animationLoaded(data));
}
/**
* 获取 `JSZip` 读取方式
* @param type 加载类型
*/
private getZipOutputType(type: LoadDataType): JSZip.OutputType {
switch (type) {
case LoadDataType.Text:
case LoadDataType.JSON:
return 'string';
case LoadDataType.ArrayBuffer:
return 'arraybuffer';
case LoadDataType.Blob:
return 'blob';
case LoadDataType.Uint8Array:
return 'uint8array';
default:
return 'uint8array';
}
}
/**
* 根据应用方式获取其所在文件夹
* @param usage 压缩内容的应用方式
*/
private getZipFolderByUsage(usage: CompressedUsage): string {
switch (usage) {
case CompressedUsage.Image:
return 'image';
case CompressedUsage.Tileset:
return 'tileset';
case CompressedUsage.Autotile:
return 'autotile';
case CompressedUsage.Material:
return 'material';
case CompressedUsage.Font:
return 'font';
case CompressedUsage.Sound:
return 'sound';
case CompressedUsage.Animate:
return 'animate';
}
}
/**
* 处理压缩文件
* @param name 文件名称
* @param value 文件内容
* @param usage 文件的应用方式
*/
private async processZipFile(
name: string,
value: unknown,
usage: CompressedUsage
) {
switch (usage) {
case CompressedUsage.Image: {
const image = await createImageBitmap(value as Blob);
await this.customImagesLoaded(name as ImageIds, image);
break;
}
case CompressedUsage.Tileset: {
const image = await createImageBitmap(value as Blob);
await this.tilesetLoaded(name, image);
break;
}
case CompressedUsage.Material: {
const image = await createImageBitmap(value as Blob);
await this.materialLoaded(name, image);
break;
}
case CompressedUsage.Font: {
const fontFace = new FontFace(
name.slice(0, -4),
value as ArrayBuffer
);
await fontFace.load();
await this.fontLoaded(name, fontFace);
break;
}
case CompressedUsage.Sound: {
const buffer = await this.ac.decodeToAudioBuffer(
value as Uint8Array<ArrayBuffer>
);
await this.soundLoaded(name as SoundIds, buffer);
break;
}
case CompressedUsage.Animate: {
await this.animationLoaded(value as string);
break;
}
}
}
/**
* 处理单个压缩包
* @param list 当前压缩包中包含的内容
* @param zip 压缩包
*/
private async handleZip(list: ICompressedMotaAssetsData[], zip: JSZip) {
const autotiles: Partial<Record<AllIdsOf<'autotile'>, ImageBitmap>> =
{};
const materialImages = core.materials.slice() as SelectKey<
MaterialImages,
ImageBitmap
>[];
materialImages.push('keyboard');
const promises = list.map(async item => {
const { readAs, name, usage } = item;
const folder = this.getZipFolderByUsage(usage);
const file = zip.file(`${folder}/${name}`);
if (!file) return;
const value = await file.async(this.getZipOutputType(readAs));
if (usage === CompressedUsage.Autotile) {
const image = await createImageBitmap(value as Blob);
await this.autotileLoaded(
autotiles,
name.slice(0, -4) as AllIdsOf<'autotile'>,
image
);
}
await this.processZipFile(name, value, usage);
});
await Promise.all(promises);
}
/**
* 游戏中加载(压缩后)
*/
private async playingLoad() {
const loadListTask = new LoadTask<
LoadDataType.JSON,
ICompressedMotaAssetsLoadList
>({
url: `loadList.json`,
dataType: LoadDataType.JSON,
identifier: '@system-loadList',
// @ts-expect-error 需要重构
processor: this.dataLoader.jsonProcessor,
progress: { onProgress() {} }
});
loadListTask.start();
const loadList = await loadListTask.loaded();
const zipTask = new LoadTask<LoadDataType.ArrayBuffer, JSZip>({
url: loadList.file,
identifier: `@system-zip/${loadList.file}`,
dataType: LoadDataType.ArrayBuffer,
// @ts-expect-error 需要重构
processor: this.zipProcessor,
progress: this.progress
});
this.addCustomLoadTask(zipTask, zip => {
return this.handleZip(loadList.content, zip);
});
}
//#endregion
//#region 对外接口
initSystemLoadTask(): void {
if (import.meta.env.DEV) {
this.developingLoad();
} else {
this.playingLoad();
}
}
addCustomLoadTask<R>(
task: ILoadTask<LoadDataType, R>,
onLoaded: CustomLoadFunc<R>
): Promise<R> {
return this.dataLoader.addCustomLoadTask(task, onLoaded);
}
async load(): Promise<void> {
this.loading = true;
this.loaded = false;
await this.dataLoader.load();
this.loading = false;
this.loaded = true;
}
//#endregion
}

View File

@ -1,84 +0,0 @@
import {
ILoadManager,
ILoadTask,
ILoadTaskProcessor,
LoadDataType
} from '@motajs/loader';
import JSZip from 'jszip';
export type CustomLoadFunc<R> = (data: R) => Promise<void>;
export const enum CompressedUsage {
// ---- 系统加载内容,不可更改
Font,
Image,
Sound,
Tileset,
Autotile,
Material,
Animate
}
export interface ICompressedMotaAssetsData {
/** 此内容的名称 */
readonly name: string;
/** 此内容应该由什么方式读取 */
readonly readAs: LoadDataType;
/** 此内容的应用方式 */
readonly usage: CompressedUsage;
}
export interface ICompressedMotaAssetsLoadList {
/** 压缩文件名称 */
readonly file: string;
/** 压缩包所包含的内容 */
readonly content: ICompressedMotaAssetsData[];
}
export interface IMotaAssetsLoader {
/** 加载进度对象 */
readonly progress: ILoadManager;
/** 当前是否正在加载 */
readonly loading: boolean;
/** 当前是否已经加载完毕 */
readonly loaded: boolean;
/** 图片处理器 */
readonly imageProcessor: ILoadTaskProcessor<LoadDataType.Blob, ImageBitmap>;
/** 音频处理器 */
readonly audioProcessor: ILoadTaskProcessor<
LoadDataType.Uint8Array,
AudioBuffer | null
>;
/** 字体处理器 */
readonly fontProcessor: ILoadTaskProcessor<
LoadDataType.ArrayBuffer,
FontFace
>;
/** 文字处理器 */
readonly textProcessor: ILoadTaskProcessor<LoadDataType.Text, string>;
/** `zip` 压缩包处理器 */
readonly zipProcessor: ILoadTaskProcessor<LoadDataType.ArrayBuffer, JSZip>;
/**
* 初始化系统加载任务
*/
initSystemLoadTask(): void;
/**
* 添加自定义加载任务
* @param task 自定义加载任务
* @param onLoad 当任务加载完成时执行
* @returns 一个 `Promise`,当添加的任务加载完毕,且 `onLoad` 返回的 `Promise` 兑现后兑现
*/
addCustomLoadTask<R>(
task: ILoadTask<LoadDataType, R>,
onLoad: CustomLoadFunc<R>
): Promise<R>;
/**
* 开始所有加载任务的加载工作
* @returns 一个 `Promise`,当所有加载任务加载完成后兑现
*/
load(): Promise<void>;
}

View File

@ -11,9 +11,7 @@ import {
import { IRenderTreeRoot, MotaRenderer } from '@motajs/render';
import {
ITextureManager,
IAutotileProcessor,
TextureManager,
AutotileProcessor,
ISaveSystem,
SaveSystem
} from '@user/client-base';
@ -38,8 +36,6 @@ import {
MAIN_WIDTH,
VARIATOR_DEBUG_SPEED
} from './shared';
import { loading } from '@user/data-base';
import { fallbackLoad } from './fallback/load';
import { WebLoadStarter } from '@motajs/loader';
export class ClientCore extends CoreState implements IClientCore {
@ -90,10 +86,10 @@ export class ClientCore extends CoreState implements IClientCore {
//#endregion
// 兼容层
loading.once('loaded', () => {
fallbackLoad(this.materials);
loading.emit('assetBuilt');
});
// loading.once('loaded', () => {
// fallbackLoad(this.materials);
// loading.emit('assetBuilt');
// });
//#region 渲染系统
@ -126,9 +122,9 @@ export class ClientCore extends CoreState implements IClientCore {
this.mainMapExtension = new MapExtensionManager(this.mainMapRenderer);
// 兼容层
loading.once('assetBuilt', () => {
this.initMapExtensions();
});
// loading.once('assetBuilt', () => {
// this.initMapExtensions();
// });
//#endregion

View File

@ -1,13 +1,9 @@
import { loading } from '@user/data-base';
import { patchAll } from './fallback';
import { createGameRenderer, createRender } from './render';
import { createRender } from './render';
export function create() {
patchAll();
createRender();
loading.once('coreInit', () => {
createGameRenderer();
});
}
export * from './action';

View File

@ -1,13 +1,11 @@
import { Font } from '@motajs/render';
import { defineComponent } from 'vue';
import { DEFAULT_FONT, MAIN_HEIGHT, MAIN_WIDTH } from '../shared';
import { hook } from '@user/data-base';
import { createElements } from '@user/client-base';
import { mainRenderer } from './renderer';
import { createUI } from './ui';
import { createAction } from './action';
import { sceneController } from './scene';
import { GameTitleUI } from './ui/title';
import { createWeather } from './weather';
import { createApp } from './renderer';
import { LoadSceneUI } from './ui/load';
@ -34,10 +32,10 @@ export function createRender() {
createAction();
createWeather();
hook.on('restart', () => {
sceneController.closeAll();
sceneController.open(GameTitleUI, {});
});
// hook.on('restart', () => {
// sceneController.closeAll();
// sceneController.open(GameTitleUI, {});
// });
Font.setDefaults(DEFAULT_FONT);
}

View File

@ -23,7 +23,6 @@ import { transitioned } from '../use';
import { cosh, CurveMode, linear } from '@motajs/animate';
import { clamp } from 'lodash-es';
import { sleep } from '@motajs/common';
import { loading } from '@user/data-base';
import { GameTitleUI } from './title';
import { client } from '../../core';
@ -62,7 +61,6 @@ export const LoadScene = defineComponent<ILoadProps>(props => {
];
const loadEnd = async () => {
loading.emit('loaded');
alpha.set(0);
await sleep(400);
props.controller.closeAll();

View File

@ -26,7 +26,6 @@ import {
} from './statusBar';
import { ReplayingStatus } from './toolbar';
import { state } from '@user/data-state';
import { hook } from '@user/data-base';
import { mainUIController } from './controller';
import { isNil } from 'lodash-es';
import { using } from '../renderer';
@ -138,14 +137,19 @@ const MainScene = defineComponent(() => {
locked.value = core.status.lockControl;
};
// 监听状态栏更新事件
hook.on('statusBarUpdate', updateStatus);
hook.on('statusBarUpdate', updateDataFallback);
// 保留函数调用,避免被识别为未使用函数而报错
// 后续修改后需要删除
updateDataFallback();
updateStatus();
onUnmounted(() => {
hook.off('statusBarUpdate', updateStatus);
hook.off('statusBarUpdate', updateDataFallback);
});
// 监听状态栏更新事件
// hook.on('statusBarUpdate', updateStatus);
// hook.on('statusBarUpdate', updateDataFallback);
// onUnmounted(() => {
// hook.off('statusBarUpdate', updateStatus);
// hook.off('statusBarUpdate', updateDataFallback);
// });
//#region sprite 渲染

View File

@ -9,7 +9,6 @@ import {
import { logger } from '@motajs/common';
import { IRenderItem, IRenderTreeRoot } from '@motajs/render';
import { Hotkey, gameKey } from '@motajs/system';
import { loading } from '@user/data-base';
import {
ComponentInternalInstance,
getCurrentInstance,
@ -65,18 +64,6 @@ export function onOrientationChange(hook: OrientationHook) {
});
}
/**
* 当游戏加载完成时执行函数,如果调用此函数时游戏已经加载,那么会立刻调用传入的钩子函数
* @param hook 当游戏加载完成时执行的函数
*/
export function onLoaded(hook: () => void) {
if (!loading.loaded) {
loading.once('loaded', hook);
} else {
hook();
}
}
type KeyUsing = [Hotkey, symbol];
/**

View File

@ -1,273 +0,0 @@
import { EventEmitter } from 'eventemitter3';
import { IDamageEnemy, IEnemyCollection } from '@motajs/types';
// ----- 加载事件
interface GameLoadEvent {
/** 当核心脚本加载完毕时触发 */
coreLoaded: [];
/** 当自动元件加载完毕后触发 */
autotileLoaded: [];
/** 当核心类初始化完毕后触发 */
coreInit: [];
/** 当所有启动必要资源加载完毕后触发 */
loaded: [];
/** 当资源构建完毕后触发,后续需要用新的加载系统替代 */
assetBuilt: [];
/** 当客户端(渲染端)和数据端都挂载完毕后触发 */
registered: [];
/** 当数据端挂载完毕后触发 */
dataRegistered: [];
/** 当客户端(渲染端)挂载完毕后触发 */
clientRegistered: [];
}
class GameLoading extends EventEmitter<GameLoadEvent> {
private autotileLoaded: number = 0;
private autotileNum?: number;
private autotileListened: boolean = false;
loaded: boolean = false;
constructor() {
super();
this.once('coreInit', () => {
this.autotileNum = Object.keys(core.material.icons.autotile).length;
});
this.once('loaded', () => {
this.loaded = true;
});
}
addAutotileLoaded() {
this.autotileLoaded++;
if (this.autotileLoaded === this.autotileNum) {
this.emit('autotileLoaded');
}
}
/**
* 当自动元件加载完毕时
* @param autotiles 自动元件数组
*/
onAutotileLoaded(
autotiles: Partial<Record<AllIdsOf<'autotile'>, ImageBitmap>>
) {
if (this.autotileListened) return;
this.autotileListened = true;
this.on('autotileLoaded', () => {
const keys = Object.keys(
core.material.icons.autotile
) as AllIdsOf<'autotile'>[];
keys.forEach(v => {
core.material.images.autotile[v] = autotiles[v]!;
});
setTimeout(() => {
core.maps._makeAutotileEdges();
});
});
}
}
export const loading = new GameLoading();
if (typeof main !== 'undefined') {
main.loading = loading;
}
let clientRegistered = false;
let dataRegistered = false;
function checkRegistered() {
if (
typeof main !== 'undefined' &&
(main.replayChecking || main.mode === 'editor')
) {
clientRegistered = true;
}
if (clientRegistered && dataRegistered) {
loading.emit('registered');
}
}
loading.once('clientRegistered', () => {
clientRegistered = true;
checkRegistered();
});
loading.once('dataRegistered', () => {
dataRegistered = true;
checkRegistered();
});
export interface GameEvent {
/** 当游戏初始化时触发,Emitted in libs/events.js resetGame. */
reset: [];
/** 当游戏挂载完毕后触发,Emitted in src/App.vue setup. */
mounted: [];
/** 当状态栏更新时触发,Emitted in plugin/game/ui.ts updateStatusBar_update */
statusBarUpdate: [];
/** 当客户端(渲染端)加载完毕后触发,Emitted in core/index.ts */
renderLoaded: [];
/** 当捡拾道具后触发,Emitted in libs/events.js getItem */
afterGetItem: [
itemId: AllIdsOf<'items'>,
x: number,
y: number,
isGentleClick: boolean
];
/** 当开门后触发,Emitted in libs/events.js _openDoor_animate */
afterOpenDoor: [doorId: AllIdsOf<'animates'>, x: number, y: number];
/** 当楼层切换后触发,Emitted in project/functions.js afterChangeFloor */
afterChangeFloor: [floorId: FloorIds];
/** 勇士每移动一步时触发,Emitted in project/functions.js moveOneStep */
moveOneStep: [x: number, y: number, floorId: FloorIds];
/** 战斗后触发,Emitted in src/game/enemy/battle.ts afterBattle */
afterBattle: [enemy: IDamageEnemy, x?: number, y?: number];
/** 楼层切换中触发,具体时刻是楼层切换的正中间,刚刚执行完切换,Emitted in libs/events.js changingFloor */
changingFloor: [floorId: FloorIds, heroLoc: Loc];
/** 当某一个图块被设置时触发,Emitted in libs/maps.js setBlock */
setBlock: [
x: number,
y: number,
floorId: FloorIds,
newBlock: AllNumbers,
oldBlock: AllNumbers
];
/** 当怪物信息被解析时触发,Emitted in game/enemy/damage.ts */
enemyExtract: [col: IEnemyCollection];
/** 当从游戏中回到游戏标题界面时触发,Emitted in lib/events.js restart */
restart: [];
/** 当设置背景或前景图块时触发,Emitted in lib/maps.js setBgFgBlock */
setBgFgBlock: [
name: 'bg' | 'fg' | 'bg2' | 'fg2',
number: AllNumbers,
x: number,
y: number,
floorId: FloorIds
];
/** 当录像播放在暂停和播放状态间切换时触发,Emitted in lib/control.js */
replayStatus: [replaying: boolean];
/** 当加载存档时触发,Emitted in project/functions.js */
loadData: [];
/** 当重设 `core.status.hero` 时触发 */
resetHero: [hero: any];
}
export const hook = new EventEmitter<GameEvent>();
interface ListenerEvent {
// block
hoverBlock: [block: Block, ev: MouseEvent];
leaveBlock: [block: Block, ev: MouseEvent, leaveGame: boolean];
clickBlock: [block: Block, ev: MouseEvent];
// mouse
mouseMove: [ev: MouseEvent];
}
class GameListener extends EventEmitter<ListenerEvent> {
static num: number = 0;
num: number = GameListener.num++;
mouseX: number = -1;
mouseY: number = -1;
constructor() {
super();
if (typeof main === 'undefined' || main.replayChecking) return;
if (typeof window !== 'undefined' && window.core) {
this.init();
} else {
loading.once('coreInit', () => {
this.init();
});
}
}
private init() {
// ----- block
// const data = core.canvas.data.canvas;
// const getBlockLoc = (px: number, py: number, size: number) => {
// return [
// Math.floor(((px * 32) / size + core.bigmap.offsetX) / 32),
// Math.floor(((py * 32) / size + core.bigmap.offsetY) / 32)
// ];
// };
// // hover & leave & mouseMove
// data.addEventListener('mousemove', e => {
// if (
// core.status.lockControl ||
// !core.isPlaying() ||
// !core.status.floorId
// )
// return;
// this.emit('mouseMove', e);
// const {
// x: px,
// y: py,
// size
// } = core.actions._getClickLoc(e.offsetX, e.offsetY);
// const [bx, by] = getBlockLoc(px, py, size);
// const blocks = core.getMapBlocksObj();
// if (this.mouseX !== bx || this.mouseY !== by) {
// const lastBlock = blocks[`${this.mouseX},${this.mouseY}`];
// const block = blocks[`${bx},${by}`];
// if (lastBlock) {
// this.emit('leaveBlock', lastBlock, e, false);
// }
// if (block) {
// this.emit('hoverBlock', block, e);
// this.mouseX = bx;
// this.mouseY = by;
// } else {
// this.mouseX = -1;
// this.mouseY = -1;
// }
// }
// });
// data.addEventListener('mouseleave', e => {
// if (
// core.status.lockControl ||
// !core.isPlaying() ||
// !core.status.floorId
// )
// return;
// const blocks = core.getMapBlocksObj();
// const lastBlock = blocks[`${this.mouseX},${this.mouseY}`];
// if (lastBlock) {
// this.emit('leaveBlock', lastBlock, e, true);
// }
// this.mouseX = -1;
// this.mouseY = -1;
// });
// // click
// data.addEventListener('click', e => {
// if (
// core.status.lockControl ||
// !core.isPlaying() ||
// !core.status.floorId
// )
// return;
// const {
// x: px,
// y: py,
// size
// } = core.actions._getClickLoc(e.offsetX, e.offsetY);
// const [bx, by] = getBlockLoc(px, py, size);
// const blocks = core.getMapBlocksObj();
// const block = blocks[`${bx},${by}`];
// if (block) {
// this.emit('clickBlock', block, e);
// }
// });
// ----- mouse
}
}
/** @deprecated */
export const gameListener = new GameListener();
declare global {
interface Main {
loading: GameLoading;
}
}

View File

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

View File

@ -11,10 +11,9 @@ import * as ClientModules from '@user/client-modules';
import * as MutateAnimate from 'mutate-animate';
import * as Vue from 'vue';
import * as Lodash from 'lodash-es';
import { hook, loading } from '@user/data-base';
export function create() {
loading.once('registered', createModule);
// loading.once('registered', createModule);
Mota.register('@motajs/client', Client);
Mota.register('@motajs/client-base', ClientBase);
@ -29,14 +28,14 @@ export function create() {
Mota.register('Vue', Vue);
Mota.register('Lodash', Lodash);
loading.emit('clientRegistered');
// loading.emit('clientRegistered');
}
async function createModule() {
ClientModules.create();
LegacyUI.create();
// async function createModule() {
// ClientModules.create();
// LegacyUI.create();
await import('ant-design-vue/dist/antd.dark.css');
main.renderLoaded = true;
hook.emit('renderLoaded');
}
// await import('ant-design-vue/dist/antd.dark.css');
// main.renderLoaded = true;
// hook.emit('renderLoaded');
// }

View File

@ -13,6 +13,4 @@ export function create() {
Mota.register('@user/data-base', DataBase);
Mota.register('@user/data-system', DataSystem);
Mota.register('@user/data-state', DataState);
DataBase.loading.emit('dataRegistered');
}

View File

@ -1,7 +1,5 @@
import { createMota } from './mota';
import { create } from './create';
import { loading } from '@user/data-base';
import { Patch } from '@motajs/legacy-common';
import { logger } from '@motajs/common';
export function createData() {
@ -14,10 +12,6 @@ export function createData() {
`此时录像验证中可以看到完整正确的报错栈。调试完毕后,记得将它重新设为 false`
);
}
loading.once('coreInit', () => {
Patch.patchAll();
});
}
export * from './mota';