mirror of
https://github.com/motajs/template.git
synced 2026-09-13 02:08:50 +08:00
refactor(03-18): own event registrations as explicit classes
- Replace generic per-invocation registration factories with explicit SetBlock/MoveBlock/DeleteBlock, MoveHero/MoveHeroStep/TouchFront, and InsertEvents/InsertEvent registration classes - Move eventTouchFront, invocation collection, and target resolution into the hero event layer while keeping awaited OnTouch behavior - Keep map and control modules limited to their own registration ownership
This commit is contained in:
parent
febdcdc967
commit
cb716f699e
@ -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<TParam> = (
|
||||
param: TParam,
|
||||
env: IBlockEventEnv
|
||||
) => void | Promise<void>;
|
||||
|
||||
function createControlEventBuiltin<TParam>(
|
||||
name: EventBuiltinName,
|
||||
handler: ControlEventBuiltinHandler<TParam>
|
||||
): 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<IBlockEventEnv['layer']>,
|
||||
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<void> {
|
||||
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<void>(invocations, { custom: {} });
|
||||
}
|
||||
|
||||
/** 过滤存在的事件 id 并构造临时事件调用 */
|
||||
function collectEventInvocations(
|
||||
ids: readonly string[],
|
||||
@ -205,21 +79,6 @@ export async function eventInsertEvents(
|
||||
}
|
||||
}
|
||||
|
||||
/** 创建事件控制事件的内建函数注册项 */
|
||||
export function createControlEventBuiltinRegistrations(): ReadonlyArray<BuiltInFunction> {
|
||||
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<BuiltInFunction> {
|
||||
return [
|
||||
new InsertEventsEventRegistration(),
|
||||
new InsertEventEventRegistration()
|
||||
];
|
||||
}
|
||||
|
||||
@ -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<TParam> = (
|
||||
param: TParam,
|
||||
env: IBlockEventEnv
|
||||
) => void | Promise<void>;
|
||||
/** 通过环境参量获取可能的地图对象 */
|
||||
export function getPossibleMap(env: IBlockEventEnv): IGameMap | null {
|
||||
if (env.map) return env.map;
|
||||
if (env.layer) return env.layer.map;
|
||||
|
||||
function createHeroEventBuiltin<TParam>(
|
||||
name: EventBuiltinName,
|
||||
handler: HeroEventBuiltinHandler<TParam>
|
||||
): 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<IBlockEventEnv['layer']>,
|
||||
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<void> {
|
||||
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<void>(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<BuiltInFunction> {
|
||||
return [
|
||||
createHeroEventBuiltin(EventBuiltinName.MoveHero, eventMoveHero),
|
||||
createHeroEventBuiltin(EventBuiltinName.MoveHeroStep, eventMoveHeroStep)
|
||||
new MoveHeroEventRegistration(),
|
||||
new MoveHeroStepEventRegistration(),
|
||||
new TouchFrontEventRegistration()
|
||||
];
|
||||
}
|
||||
|
||||
@ -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<TParam> = (
|
||||
param: TParam,
|
||||
env: IBlockEventEnv
|
||||
) => void | Promise<void>;
|
||||
|
||||
function createMapEventBuiltin<TParam>(
|
||||
name: EventBuiltinName,
|
||||
handler: MapEventBuiltinHandler<TParam>
|
||||
): 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<BuiltInFunction> {
|
||||
return [
|
||||
createMapEventBuiltin(EventBuiltinName.SetBlock, eventSetBlock),
|
||||
createMapEventBuiltin(EventBuiltinName.MoveBlock, eventMoveBlock),
|
||||
createMapEventBuiltin(EventBuiltinName.DeleteBlock, eventDeleteBlock)
|
||||
new SetBlockEventRegistration(),
|
||||
new MoveBlockEventRegistration(),
|
||||
new DeleteBlockEventRegistration()
|
||||
];
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user