From ebaa35ea5b9162345b5fe37d7d621553cded4fa7 Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Tue, 18 Nov 2025 21:12:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=9C=B0=E5=9B=BE=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E5=99=A8=E6=94=B9=E4=B8=BA=E4=B8=8E=20LayerState=20?= =?UTF-8?q?=E7=BB=91=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client-base/src/material/autotile.ts | 3 +- .../src/render/elements/index.ts | 11 +- .../src/render/elements/props.ts | 4 +- .../client-modules/src/render/map/element.ts | 61 ++--- .../client-modules/src/render/map/renderer.ts | 234 ++++++++---------- .../client-modules/src/render/map/types.ts | 60 ++--- .../client-modules/src/render/map/vertex.ts | 22 +- .../client-modules/src/render/ui/main.tsx | 30 +-- .../data-state/src/core/layerState.ts | 100 +++++++- packages-user/data-state/src/core/types.ts | 89 ++++++- packages-user/data-state/src/map/mapLayer.ts | 101 +++----- packages-user/data-state/src/map/types.ts | 65 ++--- packages/common/src/hook.ts | 82 ++++++ packages/common/src/index.ts | 1 + packages/common/src/logger.json | 3 +- packages/common/src/types.ts | 82 ++++++ public/project/functions.js | 3 + 17 files changed, 564 insertions(+), 387 deletions(-) create mode 100644 packages/common/src/hook.ts diff --git a/packages-user/client-base/src/material/autotile.ts b/packages-user/client-base/src/material/autotile.ts index 0c50c51..7d691f9 100644 --- a/packages-user/client-base/src/material/autotile.ts +++ b/packages-user/client-base/src/material/autotile.ts @@ -225,9 +225,10 @@ export class AutotileProcessor implements IAutotileProcessor { const size = texture.height === 32 * 48 ? 32 : 48; const index = distinctConnectionMap.get(connection); if (isNil(index)) return null; + const { rect } = texture.render(); return { source: texture.source, - rect: { x: 0, y: size * index, w: size, h: size } + rect: { x: rect.x, y: rect.y + size * index, w: size, h: size } }; } diff --git a/packages-user/client-modules/src/render/elements/index.ts b/packages-user/client-modules/src/render/elements/index.ts index be001be..0681631 100644 --- a/packages-user/client-modules/src/render/elements/index.ts +++ b/packages-user/client-modules/src/render/elements/index.ts @@ -8,6 +8,7 @@ import { Animate } from './animate'; import { createItemDetail } from './itemDetail'; import { logger } from '@motajs/common'; import { MapRender } from '../map/element'; +import { state } from '@user/data-state'; export function createElements() { createCache(); @@ -71,14 +72,14 @@ export function createElements() { tagMap.register('map-render', (_0, _1, props) => { if (!props) { logger.error(42); - return new MapRender([]); + return new MapRender(state.layer); } - const { layerList } = props; - if (!layerList) { + const { layerState } = props; + if (!layerState) { logger.error(42); - return new MapRender([]); + return new MapRender(state.layer); } - return new MapRender(layerList); + return new MapRender(layerState); }); } diff --git a/packages-user/client-modules/src/render/elements/props.ts b/packages-user/client-modules/src/render/elements/props.ts index fc70e42..f510f0a 100644 --- a/packages-user/client-modules/src/render/elements/props.ts +++ b/packages-user/client-modules/src/render/elements/props.ts @@ -11,7 +11,7 @@ import { import { EAnimateEvent } from './animate'; import { EIconEvent, EWinskinEvent } from './misc'; import { IEnemyCollection } from '@motajs/types'; -import { IRenderLayerData } from '../map/element'; +import { ILayerState } from '@user/data-state'; export interface AnimateProps extends BaseProps {} @@ -62,7 +62,7 @@ export interface LayerProps extends BaseProps { } export interface MapRenderProps extends BaseProps { - layerList: Iterable; + layerState: ILayerState; } declare module 'vue/jsx-runtime' { diff --git a/packages-user/client-modules/src/render/map/element.ts b/packages-user/client-modules/src/render/map/element.ts index b55d9ac..ad96947 100644 --- a/packages-user/client-modules/src/render/map/element.ts +++ b/packages-user/client-modules/src/render/map/element.ts @@ -3,26 +3,13 @@ import { RenderItem, Transform } from '@motajs/render-core'; -import { IMapLayer } from '@user/data-state'; -import { - IMapRenderer, - IMapRendererExtends, - MapTileAlign, - MapTileBehavior -} from './types'; +import { ILayerState, state } from '@user/data-state'; +import { IMapRenderer, IMapRendererHooks } from './types'; import { MapRenderer } from './renderer'; import { materials } from '@user/client-base'; import { ElementNamespace, ComponentInternalInstance } from 'vue'; import { CELL_HEIGHT, CELL_WIDTH, MAP_HEIGHT, MAP_WIDTH } from '../shared'; - -export interface IRenderLayerData { - /** 图层对象 */ - readonly layer: IMapLayer; - /** 图层纵深 */ - readonly zIndex: number; - /** 图层别名 */ - readonly alias?: string; -} +import { IHookController } from '@motajs/common'; export class MapRender extends RenderItem { /** 地图渲染器 */ @@ -35,43 +22,31 @@ export class MapRender extends RenderItem { /** 画布上下文 */ readonly gl: WebGL2RenderingContext; - constructor(layerList: Iterable) { + private rendererHook: IHookController; + + constructor(readonly layerState: ILayerState) { super('static'); this.canvas = document.createElement('canvas'); const gl = this.canvas.getContext('webgl2')!; this.gl = gl; - this.renderer = new MapRenderer(materials, this.gl, this.camera); - for (const layer of layerList) { - this.renderer.addLayer(layer.layer, layer.alias); - this.renderer.setZIndex(layer.layer, layer.zIndex); - } + this.renderer = new MapRenderer( + materials, + this.gl, + this.camera, + state.layer + ); + this.renderer.setLayerState(layerState); this.renderer.useAsset(materials.trackedAsset); - this.renderer.addExtends(new MapUpdateExtends(this)); - - this.renderer.setTileBackground(1); - + this.rendererHook = this.renderer.addHook(new RendererUpdateHook(this)); + this.rendererHook.load(); this.renderer.setCellSize(CELL_WIDTH, CELL_HEIGHT); this.renderer.setRenderSize(MAP_WIDTH, MAP_HEIGHT); gl.viewport(0, 0, this.canvas.width, this.canvas.height); } - /** - * 更新图层列表 - * @param layerList 图层列表 - */ - updateLayerList(layerList: Iterable) { - this.renderer - .getSortedLayer() - .forEach(v => this.renderer.removeLayer(v)); - for (const layer of layerList) { - this.renderer.addLayer(layer.layer, layer.alias); - this.renderer.setZIndex(layer.layer, layer.zIndex); - } - } - private sizeGL(width: number, height: number) { const ratio = this.highResolution ? devicePixelRatio : 1; const scale = ratio * this.scale; @@ -115,8 +90,8 @@ export class MapRender extends RenderItem { parentComponent?: ComponentInternalInstance | null ): void { switch (key) { - case 'layerList': { - this.updateLayerList(nextValue); + case 'layerState': { + this.renderer.setLayerState(nextValue); break; } } @@ -124,7 +99,7 @@ export class MapRender extends RenderItem { } } -class MapUpdateExtends implements IMapRendererExtends { +class RendererUpdateHook implements Partial { constructor(readonly element: MapRender) {} onUpdate(): void { diff --git a/packages-user/client-modules/src/render/map/renderer.ts b/packages-user/client-modules/src/render/map/renderer.ts index c9713e9..a5191b1 100644 --- a/packages-user/client-modules/src/render/map/renderer.ts +++ b/packages-user/client-modules/src/render/map/renderer.ts @@ -17,7 +17,7 @@ import { IMapBackgroundConfig, IMapRenderConfig, IMapRenderer, - IMapRendererExtends, + IMapRendererHooks, IMapVertexGenerator, IMapViewportController, IMovingBlock, @@ -26,13 +26,13 @@ import { MapTileBehavior, MapTileSizeTestMode } from './types'; +import { ILayerState, ILayerStateHooks, IMapLayer } from '@user/data-state'; import { - IMapLayer, - IMapLayerData, - IMapLayerExtends, - IMapLayerExtendsController -} from '@user/data-state'; -import { logger } from '@motajs/common'; + Hookable, + HookController, + IHookController, + logger +} from '@motajs/common'; import { compileProgramWith } from '@motajs/client-base'; import { isNil, maxBy } from 'lodash-es'; import { IMapDataGetter, MapVertexGenerator } from './vertex'; @@ -57,23 +57,8 @@ const enum BackgroundType { Tile } -interface ILayerRenderData { - /** 顶点数组,与总的数组共享 ArrayBuffer */ - readonly vertexArray: Float32Array; - /** 偏移数组,与总的数组共享 ArrayBuffer */ - readonly offsetArray: Int16Array; - - /** 顶点数组在原数组的起始索引值 */ - readonly vertexStart: number; - /** 顶点数组在原数组的终止索引值 */ - readonly vertexEnd: number; - /** 偏移数组在原数组的起始索引值 */ - readonly offsetStart: number; - /** 偏移数组在原数组的终止索引值 */ - readonly offsetEnd: number; -} - export class MapRenderer + extends Hookable implements IMapRenderer, IMovingRenderer, @@ -99,17 +84,10 @@ export class MapRenderer assetWidth: number = 4096; assetHeight: number = 4096; - /** 拓展列表 */ - private readonly extendList: Set = new Set(); + layerState: ILayerState; + /** 地图状态钩子控制器 */ + private layerStateHook: IHookController; - /** 这个渲染器添加的图层 */ - readonly layers: Set = new Set(); - /** 图层的 zIndex 映射 */ - private layerZIndex: Map = new Map(); - /** 图层的别名 */ - private layerAlias: Map = new Map(); - /** 图层到其对应别名的映射 */ - private layerAliasInv: Map = new Map(); /** 排序后的图层 */ private sortedLayers: IMapLayer[] = []; /** 图层到排序索引的映射 */ @@ -171,14 +149,12 @@ export class MapRenderer /** 是否应该更新偏移池 uniform */ private needUpdateOffsetPool: boolean = true; - /** 地图渲染数据 */ - private layerData: Map = new Map(); - /** 地图拓展映射 */ - private layerController: Map; /** 顶点数组的图层列表是否需要更新 */ - private layerDirty: boolean = false; + private layerListDirty: boolean = false; /** 顶点数组的图层的尺寸是否需要更新 */ private layerSizeDirty: boolean = false; + /** 是否整个地图都需要更新,一般只有在地图尺寸等发生变动时才会执行 */ + private layerAllDirty: boolean = false; /** 所有正在移动的图块 */ private movingBlock: Set = new Set(); @@ -223,8 +199,15 @@ export class MapRenderer constructor( readonly manager: IMaterialManager, readonly gl: WebGL2RenderingContext, - readonly transform: Transform + readonly transform: Transform, + layerState: ILayerState ) { + super(); + this.layerState = layerState; + this.layerStateHook = layerState.addHook( + new RendererLayerStateHook(this) + ); + this.layerStateHook.load(); // 上下文初始化要依赖于 offsetPool,因此提前调用 const offsetPool = this.getOffsetPool(); this.offsetPool = offsetPool; @@ -233,7 +216,6 @@ export class MapRenderer v => v / data.tileTextureWidth ); this.contextData = data; - this.layerController = new Map(); this.vertex = new MapVertexGenerator(this, data); this.autotile = new AutotileProcessor(manager); this.tick = this.tick.bind(this); @@ -242,6 +224,7 @@ export class MapRenderer this.viewport.bindTransform(this.transform); this.tileAnimater = new TextureColumnAnimater(); this.initVertexPointer(gl, data); + layerState.addHook(new RendererLayerStateHook(this)); } /** @@ -314,6 +297,12 @@ export class MapRenderer gl.bindVertexArray(null); } + protected createController( + hook: Partial + ): IHookController { + return new HookController(this, hook); + } + //#endregion //#region 图层处理 @@ -322,82 +311,58 @@ export class MapRenderer * 图层排序 */ private sortLayer() { - this.sortedLayers = [...this.layers].sort((a, b) => { - const za = this.layerZIndex.get(a) ?? -1; - const zb = this.layerZIndex.get(b) ?? -1; - return za - zb; + this.sortedLayers = [...this.layerState.layerList].sort((a, b) => { + return a.zIndex - b.zIndex; }); this.sortedLayers.forEach((v, i) => this.layerIndexMap.set(v, i)); + this.forEachHook((hook, controller) => { + hook.onUpdate?.(controller); + }); + this.layerListDirty = true; } - addLayer(layer: IMapLayer, identifier?: string): void { - this.layers.add(layer); - this.layerZIndex.set(layer, 0); - if (identifier) { - this.layerAlias.set(identifier, layer); - } - const ex = new MapRendererExtends(this); - const controller = layer.addExtends(ex); - controller.load(); - this.layerController.set(layer, controller); - this.sortLayer(); - this.layerDirty = true; - this.layerCount = this.layers.size; - this.resizeLayer(); + private updateAllLayers() { + this.layerState.layerList.forEach(v => { + this.vertex.updateArea(v, 0, 0, v.width, v.height); + }); } - removeLayer(layer: IMapLayer): void { - this.layers.delete(layer); - this.layerData.delete(layer); - this.layerZIndex.delete(layer); - const ex = this.layerController.get(layer); - if (ex) { - ex.unload(); - } - this.layerController.delete(layer); - const alias = this.layerAliasInv.get(layer); - if (!isNil(alias)) { - this.layerAlias.delete(alias); - } - this.layerAliasInv.delete(layer); + updateLayerList() { this.sortLayer(); - this.layerDirty = true; - this.layerCount = this.layers.size; this.resizeLayer(); + this.layerCount = this.layerState.layerList.size; + this.layerAllDirty = true; + } + + setLayerState(layerState: ILayerState): void { + this.layerStateHook.unload(); + this.layerState = layerState; + this.layerStateHook = layerState.addHook( + new RendererLayerStateHook(this) + ); + this.layerStateHook.load(); + this.sortLayer(); + this.resizeLayer(); + this.layerCount = layerState.layerList.size; + this.layerAllDirty = true; } getLayer(identifier: string): IMapLayer | null { - return this.layerAlias.get(identifier) ?? null; + return this.layerState.getLayerByAlias(identifier) ?? null; } hasLayer(layer: IMapLayer): boolean { - return this.layers.has(layer); + return this.layerState.hasLayer(layer); } getSortedLayer(): IMapLayer[] { return this.sortedLayers.slice(); } - setZIndex(layer: IMapLayer, zIndex: number): void { - this.layerZIndex.set(layer, zIndex); - this.sortLayer(); - this.layerDirty = true; - } - - getZIndex(layer: IMapLayer): number | undefined { - return this.layerZIndex.get(layer); - } - getLayerIndex(layer: IMapLayer): number { return this.layerIndexMap.get(layer) ?? -1; } - getMapLayerData(layer: IMapLayer): Readonly | null { - const ex = this.layerController.get(layer); - const data = ex?.getMapData(); - return data ?? null; - } - /** * 重新适应新的图层大小 */ @@ -409,13 +374,13 @@ export class MapRenderer } this.mapWidth = maxWidth; this.mapHeight = maxHeight; - this.layerDirty = true; this.updateBackgroundVertex( this.gl, this.contextData, this.contextData.backgroundWidth, this.contextData.backgroundHeight ); + this.layerAllDirty = true; } //#endregion @@ -699,9 +664,9 @@ export class MapRenderer tileTextureWidth: 4096, tileTextureHeight: 4096, tileTextureDepth: 1, - backgroundWidth: 32, - backgroundHeight: 32, - backgroundDepth: 1, + backgroundWidth: 0, + backgroundHeight: 0, + backgroundDepth: 0, tileTextureMark: Symbol(), vertexMark: Symbol() }; @@ -789,7 +754,6 @@ export class MapRenderer data.tileTextureMark = this.assetData.mark(); gl.bindTexture(gl.TEXTURE_2D_ARRAY, tile); this.checkTextureArraySize(gl, data, sourceArray); - console.time('texture-upload'); source.forEach((v, i) => { gl.texSubImage3D( gl.TEXTURE_2D_ARRAY, @@ -817,7 +781,6 @@ export class MapRenderer gl.TEXTURE_MIN_FILTER, gl.NEAREST ); - console.timeEnd('texture-upload'); } else { const dirty = this.assetData.dirtySince(data.tileTextureMark); if (dirty.size === 0) return; @@ -829,7 +792,6 @@ export class MapRenderer data, sourceArray ); - console.time('texture-upload'); if (sizeChanged) { // 尺寸变化,需要全部重新传递 source.forEach((v, i) => { @@ -866,7 +828,6 @@ export class MapRenderer ); }); } - console.timeEnd('texture-upload'); } } @@ -1226,8 +1187,10 @@ export class MapRenderer gl.NEAREST ); this.backgroundPending = false; - this.extendList.forEach(v => v.onUpdate?.()); gl.bindTexture(gl.TEXTURE_2D_ARRAY, null); + this.forEachHook((hook, controller) => { + hook.onUpdate?.(controller); + }); } render(): void { @@ -1260,14 +1223,18 @@ export class MapRenderer console.time('layer-check'); // 图层检查 - if (this.layerDirty) { - this.vertex.updateLayerArray(); - this.layerDirty = false; - } if (this.layerSizeDirty) { this.vertex.resizeMap(); this.layerSizeDirty = false; } + if (this.layerListDirty) { + this.vertex.updateLayerArray(); + this.layerListDirty = false; + } + if (this.layerAllDirty) { + this.updateAllLayers(); + this.layerAllDirty = false; + } this.vertex.checkRebuild(); console.timeEnd('layer-check'); @@ -1352,9 +1319,6 @@ export class MapRenderer // 由于 WebGL2 没有 glDrawArraysInstancedBaseInstance,只能每次渲染的时候临时修改 VBO 读取方式 const stride = INSTANCED_COUNT * 4; gl.bindBuffer(gl.ARRAY_BUFFER, instancedBuffer); - - console.log(area); - area.render.forEach(v => { const s = v.startIndex * INSTANCED_COUNT; const o1 = s + 0; @@ -1393,7 +1357,9 @@ export class MapRenderer h: number ) { this.vertex.updateArea(layer, x, y, w, h); - this.extendList.forEach(v => v.onUpdate?.()); + this.forEachHook((hook, controller) => { + hook.onUpdate?.(controller); + }); } /** @@ -1405,7 +1371,9 @@ export class MapRenderer */ updateLayerBlock(layer: IMapLayer, block: number, x: number, y: number) { this.vertex.updateBlock(layer, block, x, y); - this.extendList.forEach(v => v.onUpdate?.()); + this.forEachHook((hook, controller) => { + hook.onUpdate?.(controller); + }); } //#endregion @@ -1570,48 +1538,50 @@ export class MapRenderer updateTransform(): void { this.needUpdateTransform = true; - this.extendList.forEach(v => v.onUpdate?.()); - } - - addExtends(ex: IMapRendererExtends): void { - this.extendList.add(ex); - } - - close(): void { - this.layers.clear(); - this.layerAlias.clear(); - this.layerZIndex.clear(); - this.extendList.clear(); + this.forEachHook((hook, controller) => { + hook.onUpdate?.(controller); + }); } //#endregion } -class MapRendererExtends implements IMapLayerExtends { - readonly id: string = 'map-render'; - +class RendererLayerStateHook implements Partial { constructor(readonly renderer: MapRenderer) {} - onResize(): void { + onChangeBackground( + _: IHookController, + tile: number + ): void { + this.renderer.setTileBackground(tile); + } + + onResizeLayer(): void { this.renderer.resizeLayer(); } - onUpdateArea( - controller: IMapLayerExtendsController, + onUpdateLayer(): void { + this.renderer.updateLayerList(); + } + + onUpdateLayerArea( + _: IHookController, + layer: IMapLayer, x: number, y: number, width: number, height: number ): void { - this.renderer.updateLayerArea(controller.layer, x, y, width, height); + this.renderer.updateLayerArea(layer, x, y, width, height); } - onUpdateBlock( - controller: IMapLayerExtendsController, + onUpdateLayerBlock( + _: IHookController, + layer: IMapLayer, block: number, x: number, y: number ): void { - this.renderer.updateLayerBlock(controller.layer, block, x, y); + this.renderer.updateLayerBlock(layer, block, x, y); } } diff --git a/packages-user/client-modules/src/render/map/types.ts b/packages-user/client-modules/src/render/map/types.ts index 4e7cb90..67ed1ba 100644 --- a/packages-user/client-modules/src/render/map/types.ts +++ b/packages-user/client-modules/src/render/map/types.ts @@ -1,4 +1,10 @@ -import { IDirtyMark, IDirtyTracker } from '@motajs/common'; +import { + IDirtyMark, + IDirtyTracker, + IHookable, + IHookBase, + IHookController +} from '@motajs/common'; import { ITextureRenderable } from '@motajs/render-assets'; import { Transform } from '@motajs/render-core'; import { @@ -7,7 +13,7 @@ import { IMaterialManager, ITrackedAssetData } from '@user/client-base'; -import { IMapLayer } from '@user/data-state'; +import { ILayerState, IMapLayer } from '@user/data-state'; import { TimingFn } from 'mutate-animate'; export const enum MapBackgroundRepeat { @@ -221,14 +227,14 @@ export interface IMovingBlock { destroy(): void; } -export interface IMapRendererExtends { +export interface IMapRendererHooks extends IHookBase { /** * 当需要更新画面时执行 */ - onUpdate?(): void; + onUpdate(controller: IHookController): void; } -export interface IMapRenderer { +export interface IMapRenderer extends IHookable { /** 地图渲染器使用的资源管理器 */ readonly manager: IMaterialManager; /** 画布渲染上下文 */ @@ -242,6 +248,8 @@ export interface IMapRenderer { readonly viewport: IMapViewportController; /** 顶点数组生成器 */ readonly vertex: IMapVertexGenerator; + /** 使用的地图状态对象 */ + readonly layerState: ILayerState; /** 地图宽度 */ readonly mapWidth: number; @@ -268,12 +276,6 @@ export interface IMapRenderer { */ useAsset(asset: ITrackedAssetData): void; - /** - * 添加地图渲染拓展 - * @param ex 拓展对象 - */ - addExtends(ex: IMapRendererExtends): void; - /** * 摧毁此地图渲染器,表示当前渲染器不会再被使用到 */ @@ -286,17 +288,10 @@ export interface IMapRenderer { render(gl: WebGL2RenderingContext): void; /** - * 添加地图图层 - * @param layer 地图图层 - * @param identifier 图层的标识符,可以用于 {@link getLayer} 获取图层 + * 设置渲染器使用的地图状态 + * @param layerState 地图状态 */ - addLayer(layer: IMapLayer, identifier?: string): void; - - /** - * 移除指定图层 - * @param layer 要移除的图层 - */ - removeLayer(layer: IMapLayer): void; + setLayerState(layerState: ILayerState): void; /** * 根据标识符获取图层 @@ -315,19 +310,6 @@ export interface IMapRenderer { */ getSortedLayer(): IMapLayer[]; - /** - * 设置当前渲染器中指定图层的纵深 - * @param layer 要设置的图层 - * @param zIndex 目标纵深 - */ - setZIndex(layer: IMapLayer, zIndex: number): void; - - /** - * 获取指定图层的纵深 - * @param layer 要获取的图层 - */ - getZIndex(layer: IMapLayer): number | undefined; - /** * 获取指定图层排序后的索引位置 * @param layer 要获取的图层 @@ -394,11 +376,6 @@ export interface IMapRenderer { */ setCellSize(width: number, height: number): void; - /** - * 获取变换矩阵 - */ - getTransform(): Transform; - /** * 添加一个移动图块 * @param layer 图块所属的图层 @@ -449,11 +426,6 @@ export interface IMapRenderer { * @param y 图块纵坐标 */ setTileAlpha(layer: IMapLayer, alpha: number, x: number, y: number): void; - - /** - * 结束此渲染器的使用,释放所有相关资源 - */ - close(): void; } export interface IMapVertexArray { diff --git a/packages-user/client-modules/src/render/map/vertex.ts b/packages-user/client-modules/src/render/map/vertex.ts index 56feb29..1360be8 100644 --- a/packages-user/client-modules/src/render/map/vertex.ts +++ b/packages-user/client-modules/src/render/map/vertex.ts @@ -1,4 +1,4 @@ -import { IMapLayer, IMapLayerData } from '@user/data-state'; +import { IMapLayer } from '@user/data-state'; import { IBlockData, IBlockSplitter, @@ -24,8 +24,6 @@ import { BlockCls, IMaterialFramedData } from '@user/client-base'; import { IRect, SizedCanvasImageSource } from '@motajs/render-assets'; import { INSTANCED_COUNT } from './constant'; -// todo: 潜在优化点:顶点数组的 z 坐标以及纹理的 z 坐标可以换为实例化绘制 - export interface IMapDataGetter { /** 图块缩小行为,即图块比格子大时应该如何处理 */ readonly tileMinifyBehavior: MapTileBehavior; @@ -38,12 +36,6 @@ export interface IMapDataGetter { /** 图块大小与格子大小判断方式 */ readonly tileTestMode: MapTileSizeTestMode; - /** - * 获取指定图层的图块信息,是对内部存储的直接引用 - * @param layer 地图图层 - */ - getMapLayerData(layer: IMapLayer): Readonly | null; - /** * 根据图集的图像源获取其索引 * @param source 图像源 @@ -593,8 +585,8 @@ export class MapVertexGenerator const block = this.block.getBlockByDataLoc(x, y); if (!block) return; const vertex = block.data.getLayerData(layer); - const data = this.renderer.getMapLayerData(layer); - if (!vertex || !data) return; + const data = layer.getMapRef(); + if (!vertex) return; const { array } = data; const dx = x - block.dataX; const dy = y - block.dataY; @@ -789,8 +781,8 @@ export class MapVertexGenerator if (!dirty || !dirty.dirty) return; block.data.updated(); const vertex = block.data.getLayerData(layer); - const mapData = this.renderer.getMapLayerData(layer); - if (!vertex || !mapData) return; + const mapData = layer.getMapRef(); + if (!vertex) return; const { array } = mapData; const { dirtyLeft, dirtyTop, dirtyRight, dirtyBottom } = dirty; for (let nx = dirtyLeft; nx < dirtyRight; nx++) { @@ -823,9 +815,9 @@ export class MapVertexGenerator //#region 图块配置 enableStaticFrameAnimate(layer: IMapLayer, x: number, y: number): void { - const data = this.renderer.getMapLayerData(layer); + const data = layer.getMapRef(); const block = this.block.getBlockByDataLoc(x, y); - if (!data || !block) return; + if (!block) return; const vertexArray = block.data.getLayerInstanced(layer); if (!vertexArray) return; const mapIndex = y * this.mapWidth + x; diff --git a/packages-user/client-modules/src/render/ui/main.tsx b/packages-user/client-modules/src/render/ui/main.tsx index 843402e..969bfbd 100644 --- a/packages-user/client-modules/src/render/ui/main.tsx +++ b/packages-user/client-modules/src/render/ui/main.tsx @@ -48,37 +48,9 @@ import { mainUIController } from './controller'; import { LayerGroup } from '../elements'; import { isNil } from 'lodash-es'; import { materials } from '@user/client-base'; -import { IRenderLayerData } from '../map/element'; const MainScene = defineComponent(() => { //#region 基本定义 - const layerList: IRenderLayerData[] = [ - { - layer: state.layer.getLayerByAlias('bg')!, - zIndex: 10, - alias: 'bg' - }, - { - layer: state.layer.getLayerByAlias('bg2')!, - zIndex: 20, - alias: 'bg2' - }, - { - layer: state.layer.getLayerByAlias('event')!, - zIndex: 30, - alias: 'event' - }, - { - layer: state.layer.getLayerByAlias('fg')!, - zIndex: 40, - alias: 'fg' - }, - { - layer: state.layer.getLayerByAlias('fg2')!, - zIndex: 50, - alias: 'fg2' - } - ]; const mainTextboxProps: Props = { text: '', @@ -312,7 +284,7 @@ const MainScene = defineComponent(() => { onMove={moveMap} > diff --git a/packages-user/data-state/src/core/layerState.ts b/packages-user/data-state/src/core/layerState.ts index ac2272f..5ba4661 100644 --- a/packages-user/data-state/src/core/layerState.ts +++ b/packages-user/data-state/src/core/layerState.ts @@ -1,18 +1,43 @@ -import { logger } from '@motajs/common'; -import { IMapLayer, MapLayer } from '../map'; -import { ILayerState } from './types'; +import { + Hookable, + HookController, + IHookController, + logger +} from '@motajs/common'; +import { + IMapLayer, + IMapLayerHookController, + IMapLayerHooks, + MapLayer +} from '../map'; +import { ILayerState, ILayerStateHooks } from './types'; -export class LayerState implements ILayerState { - readonly layerList: WeakSet = new WeakSet(); +export class LayerState + extends Hookable + implements ILayerState +{ + readonly layerList: Set = new Set(); /** 图层到图层别名映射 */ readonly layerAliasMap: WeakMap = new WeakMap(); /** 图层别名到图层的映射 */ readonly aliasLayerMap: Map = new Map(); + /** 背景图块 */ + private backgroundTile: number = 0; + + /** 图层钩子映射 */ + private layerHookMap: Map = new Map(); + addLayer(width: number, height: number): IMapLayer { const array = new Uint32Array(width * height); const layer = new MapLayer(array, width, height); this.layerList.add(layer); + this.forEachHook((hook, controller) => { + hook.onUpdateLayer?.(controller, this.layerList); + }); + const controller = layer.addHook(new StateMapLayerHook(this)); + this.layerHookMap.set(layer, controller); + controller.load(); return layer; } @@ -24,6 +49,17 @@ export class LayerState implements ILayerState { this.aliasLayerMap.delete(symbol); this.layerAliasMap.delete(layer); } + this.forEachHook((hook, controller) => { + hook.onUpdateLayer?.(controller, this.layerList); + }); + const controller = this.layerHookMap.get(layer); + if (!controller) return; + controller.unload(); + this.layerHookMap.delete(layer); + } + + hasLayer(layer: IMapLayer): boolean { + return this.layerList.has(layer); } setLayerAlias(layer: IMapLayer, alias: string): void { @@ -57,4 +93,58 @@ export class LayerState implements ILayerState { layer.resize2(width, height); } } + + setBackground(tile: number): void { + this.backgroundTile = tile; + this.forEachHook((hook, controller) => { + hook.onChangeBackground?.(controller, tile); + }); + } + + getBackground(): number { + return this.backgroundTile; + } + + protected createController( + hook: Partial + ): IHookController { + return new HookController(this, hook); + } +} + +class StateMapLayerHook implements Partial { + constructor(readonly state: LayerState) {} + + onUpdateArea( + controller: IMapLayerHookController, + x: number, + y: number, + width: number, + height: number + ): void { + this.state.forEachHook((hook, c) => { + hook.onUpdateLayerArea?.(c, controller.layer, x, y, width, height); + }); + } + + onUpdateBlock( + controller: IMapLayerHookController, + block: number, + x: number, + y: number + ): void { + this.state.forEachHook((hook, c) => { + hook.onUpdateLayerBlock?.(c, controller.layer, block, x, y); + }); + } + + onResize( + controller: IMapLayerHookController, + width: number, + height: number + ): void { + this.state.forEachHook((hook, c) => { + hook.onResizeLayer?.(c, controller.layer, width, height); + }); + } } diff --git a/packages-user/data-state/src/core/types.ts b/packages-user/data-state/src/core/types.ts index cb75458..60ec491 100644 --- a/packages-user/data-state/src/core/types.ts +++ b/packages-user/data-state/src/core/types.ts @@ -1,8 +1,76 @@ +import { IHookable, IHookBase, IHookController } from '@motajs/common'; import { IMapLayer } from '../map'; -export interface ILayerState { +export interface ILayerStateHooks extends IHookBase { + /** + * 当设置背景图块时执行,如果设置的背景图块与原先一样,则不会执行 + * @param controller 钩子控制器 + * @param tile 背景图块 + */ + onChangeBackground(controller: IHookController, tile: number): void; + + /** + * 当地图列表发生变化时执行 + * @param controller 钩子控制器 + * @param layerList 地图图层列表 + */ + onUpdateLayer( + controller: IHookController, + layerList: Set + ): void; + + /** + * 当地图状态对象的某个图层发生区域更新时执行 + * @param controller 钩子控制器 + * @param layer 触发更新的地图图层对象 + * @param x 更新区域左上角横坐标 + * @param y 更新区域左上角纵坐标 + * @param width 更新区域宽度 + * @param height 更新区域高度 + */ + onUpdateLayerArea( + controller: IHookController, + layer: IMapLayer, + x: number, + y: number, + width: number, + height: number + ): void; + + /** + * 当地图状态对象的某个图层设置图块时执行,如果设置的图块与原先一样则不会触发 + * @param controller 钩子控制器 + * @param layer 触发更新的地图图层对象 + * @param block 设置为的图块 + * @param x 图块横坐标 + * @param y 图块纵坐标 + */ + onUpdateLayerBlock( + controller: IHookController, + layer: IMapLayer, + block: number, + x: number, + y: number + ): void; + + /** + * 当地图状态对象的某个图层大小发生变化时执行 + * @param controller 钩子控制器 + * @param layer 触发更新的地图图层对象 + * @param width 地图的新宽度 + * @param height 地图的新高度 + */ + onResizeLayer( + controller: IHookController, + layer: IMapLayer, + width: number, + height: number + ): void; +} + +export interface ILayerState extends IHookable { /** 地图列表 */ - readonly layerList: WeakSet; + readonly layerList: Set; /** * 添加图层 @@ -17,6 +85,12 @@ export interface ILayerState { */ removeLayer(layer: IMapLayer): void; + /** + * 当前地图状态对象是否包含指定图层对象 + * @param layer 图层对象 + */ + hasLayer(layer: IMapLayer): boolean; + /** * 设置图层别名 * @param layer 图层对象 @@ -49,6 +123,17 @@ export interface ILayerState { height: number, keepBlock?: boolean ): void; + + /** + * 设置背景图块 + * @param tile 背景图块数字 + */ + setBackground(tile: number): void; + + /** + * 获取背景图块数字,如果没有设置过,则返回 0 + */ + getBackground(): number; } export interface ICoreState { diff --git a/packages-user/data-state/src/map/mapLayer.ts b/packages-user/data-state/src/map/mapLayer.ts index 67585e1..d17073e 100644 --- a/packages-user/data-state/src/map/mapLayer.ts +++ b/packages-user/data-state/src/map/mapLayer.ts @@ -2,25 +2,19 @@ import { isNil } from 'lodash-es'; import { IMapLayer, IMapLayerData, - IMapLayerExtends, - IMapLayerExtendsController + IMapLayerHookController, + IMapLayerHooks } from './types'; -import { logger } from '@motajs/common'; +import { Hookable, HookController, logger } from '@motajs/common'; -interface IExtendsData { - readonly ex: IMapLayerExtends; - readonly controller: IMapLayerExtendsController; -} - -export class MapLayer implements IMapLayer { +export class MapLayer + extends Hookable + implements IMapLayer +{ width: number; height: number; empty: boolean = true; - - /** 已经加载完毕的图层拓展 */ - private loadedExtends: Set = new Set(); - /** 添加的图层拓展 */ - private addedExtends: Map = new Map(); + zIndex: number = 0; /** 地图图块数组 */ private mapArray: Uint32Array; @@ -28,6 +22,7 @@ export class MapLayer implements IMapLayer { private mapData: IMapLayerData; constructor(array: Uint32Array, width: number, height: number) { + super(); this.width = width; this.height = height; const area = width * height; @@ -42,9 +37,6 @@ export class MapLayer implements IMapLayer { resize(width: number, height: number): void { if (this.width === width && this.height === height) { - this.loadedExtends.forEach(v => { - v.ex.onResize?.(v.controller, width, height); - }); return; } this.mapData.expired = true; @@ -78,17 +70,14 @@ export class MapLayer implements IMapLayer { expired: false, array: this.mapArray }; - this.loadedExtends.forEach(v => { - v.ex.onResize?.(v.controller, width, height); + this.forEachHook((hook, controller) => { + hook.onResize?.(controller, width, height); }); } resize2(width: number, height: number): void { if (this.width === width && this.height === height) { this.mapArray.fill(0); - this.loadedExtends.forEach(v => { - v.ex.onResize?.(v.controller, width, height); - }); return; } this.mapData.expired = true; @@ -99,17 +88,18 @@ export class MapLayer implements IMapLayer { expired: false, array: this.mapArray }; - this.loadedExtends.forEach(v => { - v.ex.onResize?.(v.controller, width, height); - }); this.empty = true; + this.forEachHook((hook, controller) => { + hook.onResize?.(controller, width, height); + }); } setBlock(block: number, x: number, y: number): void { const index = y * this.width + x; + if (block === this.mapArray[index]) return; this.mapArray[index] = block; - this.loadedExtends.forEach(v => { - v.ex.onUpdateBlock?.(v.controller, block, x, y); + this.forEachHook((hook, controller) => { + hook.onUpdateBlock?.(controller, block, x, y); }); if (block !== 0) { this.empty = false; @@ -131,8 +121,8 @@ export class MapLayer implements IMapLayer { const height = Math.ceil(array.length / width); if (width === this.width && height === this.height) { this.mapArray.set(array); - this.loadedExtends.forEach(v => { - v.ex.onUpdateArea?.(v.controller, x, y, width, height); + this.forEachHook((hook, controller) => { + hook.onUpdateArea?.(controller, x, y, width, height); }); return; } @@ -159,8 +149,8 @@ export class MapLayer implements IMapLayer { } this.mapArray.set(array.subarray(start, start + nw), offset); } - this.loadedExtends.forEach(v => { - v.ex.onUpdateArea?.(v.controller, x, y, width, height); + this.forEachHook((hook, controller) => { + hook.onUpdateArea?.(controller, x, y, width, height); }); this.empty &&= empty; } @@ -213,51 +203,32 @@ export class MapLayer implements IMapLayer { return this.mapData; } - loadExtends(ex: IMapLayerExtends): boolean { - if (!this.addedExtends.has(ex.id)) return false; - ex.awake?.(); - const data = this.addedExtends.get(ex.id)!; - this.loadedExtends.add(data); - return true; + protected createController( + hook: Partial + ): IMapLayerHookController { + return new MapLayerHookController(this, hook); } - addExtends(ex: IMapLayerExtends): IMapLayerExtendsController { - const controller = new MapLayerExtendsController(this, ex); - this.addedExtends.set(ex.id, { - ex, - controller - }); - return controller; - } - - removeExtends(ex: IMapLayerExtends | string): void { - const id = typeof ex === 'string' ? ex : ex.id; - const data = this.addedExtends.get(id); - if (!data) return; - data.ex.destroy?.(); - this.addedExtends.delete(id); - this.loadedExtends.delete(data); + setZIndex(zIndex: number): void { + this.zIndex = zIndex; } } -class MapLayerExtendsController implements IMapLayerExtendsController { - loaded: boolean = false; +class MapLayerHookController + extends HookController + implements IMapLayerHookController +{ + hookable: MapLayer; constructor( readonly layer: MapLayer, - readonly ex: IMapLayerExtends - ) {} - - load(): void { - this.loaded = this.layer.loadExtends(this.ex); + hook: Partial + ) { + super(layer, hook); + this.hookable = layer; } getMapData(): Readonly { return this.layer.getMapRef(); } - - unload(): void { - this.layer.removeExtends(this.ex); - this.loaded = false; - } } diff --git a/packages-user/data-state/src/map/types.ts b/packages-user/data-state/src/map/types.ts index 0b3eff9..3830f17 100644 --- a/packages-user/data-state/src/map/types.ts +++ b/packages-user/data-state/src/map/types.ts @@ -1,3 +1,5 @@ +import { IHookable, IHookBase, IHookController } from '@motajs/common'; + export interface IMapLayerData { /** 当前引用是否过期,当地图图层内部的地图数组引用更新时,此项会变为 `true` */ expired: boolean; @@ -5,26 +7,15 @@ export interface IMapLayerData { array: Uint32Array; } -export interface IMapLayerHooks { +export interface IMapLayerHooks extends IHookBase { /** - * 当钩子准备完毕时执行,会自动分析依赖,并把依赖实例作为参数传入,遵循依赖列表的顺序 - * @param dependencies 依赖列表 - */ - awake(): void; - - /** - * 当拓展被移除之前执行,可以用来清理相关内容 - */ - destroy(): void; - - /** - * 当地图大小发生变化时执行 + * 当地图大小发生变化时执行,如果调用了地图的 `resize` 方法,但是地图大小没变,则不会触发 * @param controller 拓展控制器 * @param width 地图宽度 * @param height 地图高度 */ onResize( - controller: IMapLayerExtendsController, + controller: IMapLayerHookController, width: number, height: number ): void; @@ -38,7 +29,7 @@ export interface IMapLayerHooks { * @param height 更新区域高度 */ onUpdateArea( - controller: IMapLayerExtendsController, + controller: IMapLayerHookController, x: number, y: number, width: number, @@ -53,47 +44,37 @@ export interface IMapLayerHooks { * @param y 更新点纵坐标 */ onUpdateBlock( - controller: IMapLayerExtendsController, + controller: IMapLayerHookController, block: number, x: number, y: number ): void; } -export interface IMapLayerExtends extends Partial { - /** 这个拓展对象的标识符 */ - readonly id: string; -} - -export interface IMapLayerExtendsController { - /** 当前图层拓展是否已经被加载 */ - readonly loaded: boolean; +export interface IMapLayerHookController + extends IHookController { /** 拓展所属的图层对象 */ readonly layer: IMapLayer; - /** - * 加载此图层拓展,如果拓展依赖了其他拓展并且已经添加,将会自动加载其他拓展 - */ - load(): void; - /** * 获取地图数据,是对内部存储的直接引用 */ getMapData(): Readonly; - - /** - * 结束此拓展的生命周期,释放相关资源 - */ - unload(): void; } -export interface IMapLayer { +export interface IMapLayer + extends IHookable { /** 地图宽度 */ readonly width: number; /** 地图高度 */ readonly height: number; - /** 地图是否全部空白,此值具有保守性,即如果其为 `true`,则地图一定空白,但是如果其为 `false`,那么地图也有可能空白 */ + /** + * 地图是否全部空白,此值具有充分性,但不具有必要性, + * 即如果其为 `true`,则地图一定空白,但是如果其为 `false`,那么地图也有可能空白 + */ readonly empty: boolean; + /** 图层纵深 */ + readonly zIndex: number; /** * 调整地图尺寸,维持原有图块。如果尺寸变大,那么会补零,如果尺寸变小,那么会将当前数组裁剪 @@ -153,15 +134,13 @@ export interface IMapLayer { ): Uint32Array; /** - * 添加图层拓展,使用一系列钩子与图层本身通讯。不同图层拓展没有顺序关系。 - * @param ex 图层拓展对象 - * @returns 图层拓展控制对象,可以通过它来控制拓展的生命周期,也可以用于获取图层内的一些数据 + * 获取整个地图的地图数组,是对内部数组的直接引用 */ - addExtends(ex: IMapLayerExtends): IMapLayerExtendsController; + getMapRef(): IMapLayerData; /** - * 移除指定的图层拓展对象 - * @param ex 要移除的图层拓展对象,也可以填拓展对象的标识符 + * 设置地图纵深,会影响渲染的遮挡顺序 + * @param zIndex 纵深 */ - removeExtends(ex: IMapLayerExtends | string): void; + setZIndex(zIndex: number): void; } diff --git a/packages/common/src/hook.ts b/packages/common/src/hook.ts new file mode 100644 index 0000000..a653342 --- /dev/null +++ b/packages/common/src/hook.ts @@ -0,0 +1,82 @@ +import { logger } from './logger'; +import { IHookable, IHookBase, IHookController, IHookObject } from './types'; + +export abstract class Hookable< + H extends IHookBase = IHookBase, + C extends IHookController = IHookController +> implements IHookable +{ + /** 加载完成的钩子列表 */ + protected readonly loadedList: Set> = new Set(); + + /** 钩子列表 */ + private readonly hookList: Set> = new Set(); + /** 钩子对象到钩子存储对象的映射 */ + private readonly hookMap: Map, IHookObject> = new Map(); + /** 钩子控制器到钩子存储对象的映射 */ + private readonly controllerMap: Map> = new Map(); + + /** + * 创建钩子对象的控制器 + * @param hook 钩子对象 + */ + protected abstract createController(hook: Partial): C; + + addHook(hook: Partial): C { + const controller = this.createController(hook); + const obj: IHookObject = { hook, controller }; + this.hookMap.set(hook, obj); + this.controllerMap.set(controller, obj); + this.hookList.add(obj); + return controller; + } + + loadHook(hook: Partial): void { + const obj = this.hookMap.get(hook); + if (!obj) { + logger.warn(85); + return; + } + hook.awake?.(obj.controller); + this.loadedList.add(obj); + } + + removeHook(hook: Partial): void { + const obj = this.hookMap.get(hook); + if (!obj) return; + obj.hook.destroy?.(obj.controller); + this.hookList.delete(obj); + this.loadedList.delete(obj); + this.hookMap.delete(hook); + this.controllerMap.delete(obj.controller); + } + + removeHookByController(hook: C): void { + const obj = this.controllerMap.get(hook); + if (!obj) return; + obj.hook.destroy?.(obj.controller); + this.hookList.delete(obj); + this.loadedList.delete(obj); + this.controllerMap.delete(hook); + this.hookMap.delete(obj.hook); + } + + forEachHook(fn: (hook: Partial, controller: C) => void): void { + this.loadedList.forEach(v => fn(v.hook, v.controller)); + } +} + +export class HookController implements IHookController { + constructor( + readonly hookable: IHookable>, + readonly hook: Partial + ) {} + + load(): void { + this.hookable.loadHook(this.hook); + } + + unload(): void { + this.hookable.removeHookByController(this); + } +} diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 7133d2a..605e235 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -1,4 +1,5 @@ export * from './dirtyTracker'; +export * from './hook'; export * from './logger'; export * from './utils'; export * from './types'; diff --git a/packages/common/src/logger.json b/packages/common/src/logger.json index b3b272b..4bb3a1e 100644 --- a/packages/common/src/logger.json +++ b/packages/common/src/logger.json @@ -41,7 +41,7 @@ "39": "Offset pool size exceeds WebGL2 limitation, ensure size type of your big image is less than $1.", "40": "Material used by map block $1 is not found in built asset. Please ensure you have pack it into asset.", "41": "You are trying to use a texture on moving block whose offset is not in the offset pool, please build it into asset after loading.", - "42": "The layerList property of map-render element is required.", + "42": "The layerState property of map-render element is required.", "1101": "Shadow extension needs 'floor-hero' extension as dependency.", "1201": "Floor-damage extension needs 'floor-binder' extension as dependency.", "1301": "Portal extension need 'floor-binder' extension as dependency.", @@ -132,6 +132,7 @@ "82": "Big image offset size is larger than 64. Considier reduce big image offset bucket.", "83": "It seems that you call '$1' too frequently. This will extremely affect game's performance, so considering integrate them into one 'updateArea' or 'updateBlockList' call.", "84": "Cannot set alias '$1' for layer, since '$1' is already an alias for another layer.", + "85": "Hook to load does not belong to current hookable object.", "1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency.", "1101": "Cannot add new effect to point effect instance, for there's no more reserve space for it. Please increase the max count of the instance." } diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts index eff83ea..6093188 100644 --- a/packages/common/src/types.ts +++ b/packages/common/src/types.ts @@ -1,3 +1,5 @@ +//#region 脏标记 + export interface IDirtyMarker { /** * 标记为脏,即进行了一次更新 @@ -32,3 +34,83 @@ export interface IDirtyTracker { */ hasMark(symbol: IDirtyMark): boolean; } + +//#endregion + +//#region 钩子 + +export interface IHookObject< + H extends IHookBase, + C extends IHookController +> { + /** 钩子对象 */ + readonly hook: Partial; + /** 钩子控制器 */ + readonly controller: C; +} + +export interface IHookController { + /** 控制器的钩子对象 */ + readonly hook: Partial; + + /** + * 加载此控制器对应的钩子对象 + */ + load(): void; + + /** + * 卸载此控制器对应的钩子对象,之后此钩子将不会再被触发 + */ + unload(): void; +} + +export interface IHookBase { + /** + * 加载此钩子对象 + * @param controller 钩子控制器对象 + */ + awake(controller: IHookController): void; + + /** + * 摧毁此钩子对象 + * @param controller 钩子控制器对象 + */ + destroy(controller: IHookController): void; +} + +export interface IHookable< + H extends IHookBase = IHookBase, + C extends IHookController = IHookController +> { + /** + * 添加钩子对象,返回控制该钩子对象的控制器 + * @param hook 钩子对象 + */ + addHook(hook: Partial): C; + + /** + * 加载指定的钩子对象 + * @param hook 钩子对象 + */ + loadHook(hook: Partial): void; + + /** + * 移除钩子对象,会调用钩子对象的 `destroy` 方法 + * @param hook 钩子对象 + */ + removeHook(hook: Partial): void; + + /** + * 传入钩子控制器,移除对应的钩子对象 + * @param hook 钩子控制器 + */ + removeHookByController(hook: C): void; + + /** + * 遍历每个钩子 + * @param fn 对每个钩子执行的函数 + */ + forEachHook(fn: (hook: Partial, controller: C) => void): void; +} + +//#endregion diff --git a/public/project/functions.js b/public/project/functions.js index 043f790..4b16998 100644 --- a/public/project/functions.js +++ b/public/project/functions.js @@ -199,6 +199,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { const array = new Uint32Array(fg2.flat()); fg2Layer.putMapData(array, 0, 0, width); } + const back = core.floors[floorId].defaultGround; + const id = core.maps.getNumberById(back); + state.layer.setBackground(id); // 设置勇士的位置 heroLoc.direction = core.turnDirection(heroLoc.direction);