diff --git a/packages-user/data-state/src/event/event.ts b/packages-user/data-state/src/event/event.ts index 02925de..73aab3f 100644 --- a/packages-user/data-state/src/event/event.ts +++ b/packages-user/data-state/src/event/event.ts @@ -4,45 +4,16 @@ import { IBlockEventParam, IGameEventExecutor, IGameEventInvocation, - IGameEventSystem, - BlockEventType + IGameEventSystem } from '@user/data-system'; -import { - FaceDirection, - EventTrigger, - IGameEventStore -} from '@user/data-common'; -import { - IStateBase, - IReadonlyTileBase as IReadonlyMapTileBase -} from '@user/data-base'; -import { getPossibleLayer } from './map'; +import { IGameEventStore } from '@user/data-common'; +import { IStateBase } from '@user/data-base'; import { EventBuiltinName, IInsertEventEventParam, - IInsertEventsEventParam, - ITouchFrontEventParam + IInsertEventsEventParam } from './types'; -type ControlEventBuiltinHandler = ( - param: TParam, - env: IBlockEventEnv -) => void | Promise; - -function createControlEventBuiltin( - name: EventBuiltinName, - handler: ControlEventBuiltinHandler -): BuiltInFunction { - return { name, func: handler as BuiltInFunction['func'] }; -} - -interface IEventSource { - readonly priority: number; - readonly id: string; - readonly type: BlockEventType; - readonly tile: IReadonlyMapTileBase | null; -} - interface IEventState extends IStateBase { readonly eventSystem: IGameEventSystem; } @@ -56,7 +27,7 @@ function hasEventSystem(state: IStateBase): state is IEventState { } /** 从环境获取事件执行器和事件存储器 */ -function getEventRuntime(env: IBlockEventEnv): { +export function getEventRuntime(env: IBlockEventEnv): { readonly executor: IGameEventExecutor; readonly store: IGameEventStore; } | null { @@ -69,103 +40,6 @@ function getEventRuntime(env: IBlockEventEnv): { }; } -/** 按坐标收集事件来源并保留其触发环境 */ -function collectInvocations( - env: IBlockEventEnv, - layer: NonNullable, - x: number, - y: number, - trigger: EventTrigger -): IGameEventInvocation[] { - const pointSources: IEventSource[] = []; - const tileSources: IEventSource[] = []; - const point = layer.getPointEvent(x, y); - const location = layer.getLocationData(x, y); - if (point) { - for (const [priority, id] of point) { - pointSources.push({ - priority, - id, - type: BlockEventType.PointEvent, - tile: null - }); - } - } - if (location) { - if (location.static) { - for (const [priority, id] of location.static.tileEvent().get()) { - tileSources.push({ - priority, - id, - type: BlockEventType.TileEvent, - tile: location.static - }); - } - } - for (const tile of location.dynamics) { - for (const [priority, id] of tile.tileEvent().get()) { - tileSources.push({ - priority, - id, - type: BlockEventType.TileEvent, - tile - }); - } - } - } - pointSources.sort((a, b) => b.priority - a.priority); - tileSources.sort((a, b) => b.priority - a.priority); - - const hero = env.state.hero.getLocation(); - const invocations: IGameEventInvocation[] = []; - for (const source of [...pointSources, ...tileSources]) { - const sourceEnv: IBlockEventEnv = { - state: env.state, - type: source.type, - trigger, - heroLocator: hero, - heroFloor: env.heroFloor, - triggerLocator: { x, y }, - tile: source.tile, - layer, - map: layer.map - }; - invocations.push({ id: source.id, env: sourceEnv }); - } - return invocations; -} - -/** 触发勇士正面的 onTouch 事件 */ -export async function eventTouchFront( - _param: ITouchFrontEventParam, - env: IBlockEventEnv -): Promise { - if (!env.state.hero) return; - const layer = getPossibleLayer(env); - if (!layer) return; - const runtime = getEventRuntime(env); - if (!runtime) return; - - const hero = env.state.hero.getLocation(); - const mover = env.state.hero.location.mover; - const direction = mover.tile.getCurrentFaceDirection(); - if (direction === FaceDirection.Unknown) return; - const movement = mover.faceHandler.movement(direction); - const x = hero.x + movement.x; - const y = hero.y + movement.y; - if (!layer.inMap(x, y)) return; - - const invocations = collectInvocations( - env, - layer, - x, - y, - EventTrigger.OnTouch - ); - if (invocations.length === 0) return; - await runtime.executor.execute(invocations, { custom: {} }); -} - /** 过滤存在的事件 id 并构造临时事件调用 */ function collectEventInvocations( ids: readonly string[], @@ -205,21 +79,6 @@ export async function eventInsertEvents( } } -/** 创建事件控制事件的内建函数注册项 */ -export function createControlEventBuiltinRegistrations(): ReadonlyArray { - return [ - createControlEventBuiltin(EventBuiltinName.TouchFront, eventTouchFront), - createControlEventBuiltin( - EventBuiltinName.InsertEvents, - eventInsertEvents - ), - createControlEventBuiltin( - EventBuiltinName.InsertEvent, - eventInsertEvent - ) - ]; -} - /** 临时直接执行一段事件语句 */ export async function eventInsertEvent( param: IInsertEventEventParam, @@ -239,3 +98,24 @@ export async function eventInsertEvent( eventInsertDepth.delete(env); } } + +export class InsertEventsEventRegistration implements BuiltInFunction { + readonly name: EventBuiltinName.InsertEvents = + EventBuiltinName.InsertEvents; + readonly func: BuiltInFunction['func'] = + eventInsertEvents as BuiltInFunction['func']; +} + +export class InsertEventEventRegistration implements BuiltInFunction { + readonly name: EventBuiltinName.InsertEvent = EventBuiltinName.InsertEvent; + readonly func: BuiltInFunction['func'] = + eventInsertEvent as BuiltInFunction['func']; +} + +/** 创建事件控制事件的内建函数注册项 */ +export function createControlEventBuiltinRegistrations(): ReadonlyArray { + return [ + new InsertEventsEventRegistration(), + new InsertEventEventRegistration() + ]; +} diff --git a/packages-user/data-state/src/event/hero.ts b/packages-user/data-state/src/event/hero.ts index 6b995dc..4031614 100644 --- a/packages-user/data-state/src/event/hero.ts +++ b/packages-user/data-state/src/event/hero.ts @@ -1,7 +1,19 @@ import { BuiltInFunction } from 'anon-tokyo'; -import { IBlockEventEnv } from '@user/data-system'; -import { IHeroLocation, IHeroMover } from '@user/data-base'; import { + BlockEventType, + IBlockEventEnv, + IGameEventInvocation +} from '@user/data-system'; +import { + IGameMap, + IHeroLocation, + IHeroMover, + IMapLayer, + IReadonlyTileBase as IReadonlyMapTileBase +} from '@user/data-base'; +import { + EventTrigger, + FaceDirection, IMoverController, IObjectMovable, IObjectMover, @@ -12,19 +24,30 @@ import { import { EventBuiltinName, IMoveHeroEventParam, - IMoveHeroStepEventParam + IMoveHeroStepEventParam, + ITouchFrontEventParam } from './types'; +import { getEventRuntime } from './event'; -type HeroEventBuiltinHandler = ( - param: TParam, - env: IBlockEventEnv -) => void | Promise; +/** 通过环境参量获取可能的地图对象 */ +export function getPossibleMap(env: IBlockEventEnv): IGameMap | null { + if (env.map) return env.map; + if (env.layer) return env.layer.map; -function createHeroEventBuiltin( - name: EventBuiltinName, - handler: HeroEventBuiltinHandler -): BuiltInFunction { - return { name, func: handler as BuiltInFunction['func'] }; + const map = env.state.maps.getMap(env.heroFloor); + if (map) return map; + + return null; +} + +/** 通过环境参量获取可能的事件图层 */ +export function getPossibleLayer(env: IBlockEventEnv): IMapLayer | null { + if (env.layer) return env.layer; + + const map = getPossibleMap(env); + if (map?.eventLayer) return map.eventLayer; + + return null; } /** 启动勇士移动并等待其完整结束 */ @@ -109,10 +132,134 @@ export async function eventMoveHeroStep( await controller.onEnd; } +interface IEventSource { + readonly priority: number; + readonly id: string; + readonly type: BlockEventType; + readonly tile: IReadonlyMapTileBase | null; +} + +/** 按坐标收集事件来源并保留其触发环境 */ +function collectInvocations( + env: IBlockEventEnv, + layer: NonNullable, + x: number, + y: number, + trigger: EventTrigger +): IGameEventInvocation[] { + const pointSources: IEventSource[] = []; + const tileSources: IEventSource[] = []; + const point = layer.getPointEvent(x, y); + const location = layer.getLocationData(x, y); + if (point) { + for (const [priority, id] of point) { + pointSources.push({ + priority, + id, + type: BlockEventType.PointEvent, + tile: null + }); + } + } + if (location) { + if (location.static) { + for (const [priority, id] of location.static.tileEvent().get()) { + tileSources.push({ + priority, + id, + type: BlockEventType.TileEvent, + tile: location.static + }); + } + } + for (const tile of location.dynamics) { + for (const [priority, id] of tile.tileEvent().get()) { + tileSources.push({ + priority, + id, + type: BlockEventType.TileEvent, + tile + }); + } + } + } + pointSources.sort((a, b) => b.priority - a.priority); + tileSources.sort((a, b) => b.priority - a.priority); + + const hero = env.state.hero.getLocation(); + const invocations: IGameEventInvocation[] = []; + for (const source of [...pointSources, ...tileSources]) { + const sourceEnv: IBlockEventEnv = { + state: env.state, + type: source.type, + trigger, + heroLocator: hero, + heroFloor: env.heroFloor, + triggerLocator: { x, y }, + tile: source.tile, + layer, + map: layer.map + }; + invocations.push({ id: source.id, env: sourceEnv }); + } + return invocations; +} + +/** 触发勇士正面的 onTouch 事件 */ +export async function eventTouchFront( + _param: ITouchFrontEventParam, + env: IBlockEventEnv +): Promise { + if (!env.state.hero) return; + const layer = getPossibleLayer(env); + if (!layer) return; + const runtime = getEventRuntime(env); + if (!runtime) return; + + const hero = env.state.hero.getLocation(); + const mover = env.state.hero.location.mover; + const direction = mover.tile.getCurrentFaceDirection(); + if (direction === FaceDirection.Unknown) return; + const movement = mover.faceHandler.movement(direction); + const x = hero.x + movement.x; + const y = hero.y + movement.y; + if (!layer.inMap(x, y)) return; + + const invocations = collectInvocations( + env, + layer, + x, + y, + EventTrigger.OnTouch + ); + if (invocations.length === 0) return; + await runtime.executor.execute(invocations, { custom: {} }); +} + +export class MoveHeroEventRegistration implements BuiltInFunction { + readonly name: EventBuiltinName.MoveHero = EventBuiltinName.MoveHero; + readonly func: BuiltInFunction['func'] = + eventMoveHero as BuiltInFunction['func']; +} + +export class MoveHeroStepEventRegistration implements BuiltInFunction { + readonly name: EventBuiltinName.MoveHeroStep = + EventBuiltinName.MoveHeroStep; + readonly func: BuiltInFunction['func'] = + eventMoveHeroStep as BuiltInFunction['func']; +} + +export class TouchFrontEventRegistration implements BuiltInFunction { + readonly name: EventBuiltinName.TouchFront = EventBuiltinName.TouchFront; + readonly func: BuiltInFunction['func'] = + eventTouchFront as BuiltInFunction['func']; +} + /** 创建勇士控制事件的内建函数注册项 */ export function createHeroEventBuiltinRegistrations(): ReadonlyArray { return [ - createHeroEventBuiltin(EventBuiltinName.MoveHero, eventMoveHero), - createHeroEventBuiltin(EventBuiltinName.MoveHeroStep, eventMoveHeroStep) + new MoveHeroEventRegistration(), + new MoveHeroStepEventRegistration(), + new TouchFrontEventRegistration() ]; } diff --git a/packages-user/data-state/src/event/map.ts b/packages-user/data-state/src/event/map.ts index a3c9afa..6150c36 100644 --- a/packages-user/data-state/src/event/map.ts +++ b/packages-user/data-state/src/event/map.ts @@ -1,51 +1,14 @@ import { BuiltInFunction } from 'anon-tokyo'; import { IBlockEventEnv } from '@user/data-system'; import { + EventBuiltinName, IDeleteBlockEventParam, IMoveBlockEventParam, ISetBlockEventParam } from './types'; import { isNil } from 'lodash-es'; import { logger } from '@motajs/common'; -import { IGameMap, IMapLayer } from '@user/data-base'; -import { appendMoveSteps } from './hero'; -import { EventBuiltinName } from './types'; - -type MapEventBuiltinHandler = ( - param: TParam, - env: IBlockEventEnv -) => void | Promise; - -function createMapEventBuiltin( - name: EventBuiltinName, - handler: MapEventBuiltinHandler -): BuiltInFunction { - return { name, func: handler as BuiltInFunction['func'] }; -} - -/** - * 通过环境参量获取可能的地图对象 - * @param env 事件环境变量 - */ -export function getPossibleMap(env: IBlockEventEnv): IGameMap | null { - if (env.map) return env.map; - if (env.layer) return env.layer.map; - - const map = env.state.maps.getMap(env.heroFloor); - if (map) return map; - - return null; -} - -/** 通过环境参量获取可能的事件图层 */ -export function getPossibleLayer(env: IBlockEventEnv): IMapLayer | null { - if (env.layer) return env.layer; - - const map = getPossibleMap(env); - if (map?.eventLayer) return map.eventLayer; - - return null; -} +import { appendMoveSteps, getPossibleLayer } from './hero'; export function eventSetBlock( param: ISetBlockEventParam, @@ -105,11 +68,29 @@ export async function eventDeleteBlock( } } +export class SetBlockEventRegistration implements BuiltInFunction { + readonly name: EventBuiltinName.SetBlock = EventBuiltinName.SetBlock; + readonly func: BuiltInFunction['func'] = + eventSetBlock as BuiltInFunction['func']; +} + +export class MoveBlockEventRegistration implements BuiltInFunction { + readonly name: EventBuiltinName.MoveBlock = EventBuiltinName.MoveBlock; + readonly func: BuiltInFunction['func'] = + eventMoveBlock as BuiltInFunction['func']; +} + +export class DeleteBlockEventRegistration implements BuiltInFunction { + readonly name: EventBuiltinName.DeleteBlock = EventBuiltinName.DeleteBlock; + readonly func: BuiltInFunction['func'] = + eventDeleteBlock as BuiltInFunction['func']; +} + /** 创建地图控制事件的内建函数注册项 */ export function createMapEventBuiltinRegistrations(): ReadonlyArray { return [ - createMapEventBuiltin(EventBuiltinName.SetBlock, eventSetBlock), - createMapEventBuiltin(EventBuiltinName.MoveBlock, eventMoveBlock), - createMapEventBuiltin(EventBuiltinName.DeleteBlock, eventDeleteBlock) + new SetBlockEventRegistration(), + new MoveBlockEventRegistration(), + new DeleteBlockEventRegistration() ]; }