Files
esengine/packages/framework/blueprint/src/triggers/BlueprintTrigger.ts

498 lines
12 KiB
TypeScript
Raw Normal View History

/**
* @zh
* @en Blueprint Trigger
*
* @zh
* @en Defines core trigger implementation
*/
import type { TriggerType, ITriggerContext } from './TriggerTypes';
import type { ITriggerCondition } from './TriggerCondition';
import { AlwaysTrueCondition } from './TriggerCondition';
// =============================================================================
// 触发器接口 | Trigger Interface
// =============================================================================
/**
* @zh
* @en Trigger callback function type
*/
export type TriggerCallback = (context: ITriggerContext) => void;
/**
* @zh
* @en Blueprint trigger interface
*/
export interface IBlueprintTrigger {
/**
* @zh
* @en Trigger unique identifier
*/
readonly id: string;
/**
* @zh
* @en Trigger type
*/
readonly type: TriggerType;
/**
* @zh
* @en Trigger conditions
*/
readonly condition: ITriggerCondition;
/**
* @zh
* @en Is enabled
*/
enabled: boolean;
/**
* @zh
* @en Priority (higher executes first)
*/
readonly priority: number;
/**
* @zh
* @en Check if should fire
*/
shouldFire(context: ITriggerContext): boolean;
/**
* @zh
* @en Execute trigger
*/
fire(context: ITriggerContext): void;
}
/**
* @zh
* @en Trigger configuration
*/
export interface TriggerConfig {
/**
* @zh ID
* @en Trigger ID
*/
id?: string;
/**
* @zh
* @en Trigger type
*/
type: TriggerType;
/**
* @zh
* @en Trigger condition
*/
condition?: ITriggerCondition;
/**
* @zh
* @en Is enabled
*/
enabled?: boolean;
/**
* @zh
* @en Priority
*/
priority?: number;
/**
* @zh
* @en Callback function
*/
callback?: TriggerCallback;
}
// =============================================================================
// 触发器实现 | Trigger Implementation
// =============================================================================
let _triggerId = 0;
/**
* @zh ID
* @en Generate unique trigger ID
*/
function generateTriggerId(): string {
return `trigger_${++_triggerId}`;
}
/**
* @zh
* @en Blueprint trigger implementation
*/
export class BlueprintTrigger implements IBlueprintTrigger {
readonly id: string;
readonly type: TriggerType;
readonly condition: ITriggerCondition;
readonly priority: number;
enabled: boolean;
private readonly _callback?: TriggerCallback;
private readonly _callbacks: Set<TriggerCallback> = new Set();
constructor(config: TriggerConfig) {
this.id = config.id ?? generateTriggerId();
this.type = config.type;
this.condition = config.condition ?? new AlwaysTrueCondition();
this.priority = config.priority ?? 0;
this.enabled = config.enabled ?? true;
this._callback = config.callback;
}
/**
* @zh
* @en Check if should fire
*/
shouldFire(context: ITriggerContext): boolean {
if (!this.enabled) {
return false;
}
if (context.type !== this.type && this.type !== 'custom') {
return false;
}
return this.condition.evaluate(context);
}
/**
* @zh
* @en Execute trigger
*/
fire(context: ITriggerContext): void {
if (this._callback) {
this._callback(context);
}
for (const callback of this._callbacks) {
callback(context);
}
}
/**
* @zh
* @en Add callback
*/
addCallback(callback: TriggerCallback): void {
this._callbacks.add(callback);
}
/**
* @zh
* @en Remove callback
*/
removeCallback(callback: TriggerCallback): void {
this._callbacks.delete(callback);
}
/**
* @zh
* @en Clear all callbacks
*/
clearCallbacks(): void {
this._callbacks.clear();
}
}
// =============================================================================
// 触发器注册表 | Trigger Registry
// =============================================================================
/**
* @zh
* @en Trigger registry interface
*/
export interface ITriggerRegistry {
/**
* @zh
* @en Register trigger
*/
register(trigger: IBlueprintTrigger): void;
/**
* @zh
* @en Unregister trigger
*/
unregister(triggerId: string): boolean;
/**
* @zh
* @en Get trigger
*/
get(triggerId: string): IBlueprintTrigger | undefined;
/**
* @zh
* @en Get all triggers
*/
getAll(): IBlueprintTrigger[];
/**
* @zh
* @en Get triggers by type
*/
getByType(type: TriggerType): IBlueprintTrigger[];
/**
* @zh
* @en Clear all triggers
*/
clear(): void;
}
/**
* @zh
* @en Trigger registry implementation
*/
export class TriggerRegistry implements ITriggerRegistry {
private readonly _triggers: Map<string, IBlueprintTrigger> = new Map();
private readonly _triggersByType: Map<TriggerType, Set<string>> = new Map();
/**
* @zh
* @en Register trigger
*/
register(trigger: IBlueprintTrigger): void {
if (this._triggers.has(trigger.id)) {
console.warn(`Trigger ${trigger.id} already registered, overwriting`);
}
this._triggers.set(trigger.id, trigger);
if (!this._triggersByType.has(trigger.type)) {
this._triggersByType.set(trigger.type, new Set());
}
this._triggersByType.get(trigger.type)!.add(trigger.id);
}
/**
* @zh
* @en Unregister trigger
*/
unregister(triggerId: string): boolean {
const trigger = this._triggers.get(triggerId);
if (!trigger) {
return false;
}
this._triggers.delete(triggerId);
const typeSet = this._triggersByType.get(trigger.type);
if (typeSet) {
typeSet.delete(triggerId);
}
return true;
}
/**
* @zh
* @en Get trigger
*/
get(triggerId: string): IBlueprintTrigger | undefined {
return this._triggers.get(triggerId);
}
/**
* @zh
* @en Get all triggers
*/
getAll(): IBlueprintTrigger[] {
return Array.from(this._triggers.values());
}
/**
* @zh
* @en Get triggers by type
*/
getByType(type: TriggerType): IBlueprintTrigger[] {
const typeSet = this._triggersByType.get(type);
if (!typeSet) {
return [];
}
const triggers: IBlueprintTrigger[] = [];
for (const id of typeSet) {
const trigger = this._triggers.get(id);
if (trigger) {
triggers.push(trigger);
}
}
return triggers.sort((a, b) => b.priority - a.priority);
}
/**
* @zh
* @en Clear all triggers
*/
clear(): void {
this._triggers.clear();
this._triggersByType.clear();
}
/**
* @zh
* @en Get trigger count
*/
get count(): number {
return this._triggers.size;
}
}
// =============================================================================
// 工厂函数 | Factory Functions
// =============================================================================
/**
* @zh
* @en Create trigger
*/
export function createTrigger(config: TriggerConfig): BlueprintTrigger {
return new BlueprintTrigger(config);
}
/**
* @zh Tick
* @en Create tick trigger
*/
export function createTickTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'tick',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh
* @en Create input trigger
*/
export function createInputTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'input',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh
* @en Create collision trigger
*/
export function createCollisionTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'collision',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh
* @en Create message trigger
*/
export function createMessageTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'message',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh
* @en Create timer trigger
*/
export function createTimerTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'timer',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh
* @en Create state enter trigger
*/
export function createStateEnterTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'stateEnter',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh 退
* @en Create state exit trigger
*/
export function createStateExitTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'stateExit',
condition: options?.condition,
priority: options?.priority,
callback
});
}
/**
* @zh
* @en Create custom trigger
*/
export function createCustomTrigger(
callback?: TriggerCallback,
options?: { id?: string; condition?: ITriggerCondition; priority?: number }
): BlueprintTrigger {
return new BlueprintTrigger({
id: options?.id,
type: 'custom',
condition: options?.condition,
priority: options?.priority,
callback
});
}