* refactor: reorganize package structure and decouple framework packages ## Package Structure Reorganization - Reorganized 55 packages into categorized subdirectories: - packages/framework/ - Generic framework (Laya/Cocos compatible) - packages/engine/ - ESEngine core modules - packages/rendering/ - Rendering modules (WASM dependent) - packages/physics/ - Physics modules - packages/streaming/ - World streaming - packages/network-ext/ - Network extensions - packages/editor/ - Editor framework and plugins - packages/rust/ - Rust WASM engine - packages/tools/ - Build tools and SDK ## Framework Package Decoupling - Decoupled behavior-tree and blueprint packages from ESEngine dependencies - Created abstracted interfaces (IBTAssetManager, IBehaviorTreeAssetContent) - ESEngine-specific code moved to esengine/ subpath exports - Framework packages now usable with Cocos/Laya without ESEngine ## CI Configuration - Updated CI to only type-check and lint framework packages - Added type-check:framework and lint:framework scripts ## Breaking Changes - Package import paths changed due to directory reorganization - ESEngine integrations now use subpath imports (e.g., '@esengine/behavior-tree/esengine') * fix: update es-engine file path after directory reorganization * docs: update README to focus on framework over engine * ci: only build framework packages, remove Rust/WASM dependencies * fix: remove esengine subpath from behavior-tree and blueprint builds ESEngine integration code will only be available in full engine builds. Framework packages are now purely engine-agnostic. * fix: move network-protocols to framework, build both in CI * fix: update workflow paths from packages/core to packages/framework/core * fix: exclude esengine folder from type-check in behavior-tree and blueprint * fix: update network tsconfig references to new paths * fix: add test:ci:framework to only test framework packages in CI * fix: only build core and math npm packages in CI * fix: exclude test files from CodeQL and fix string escaping security issue
498 lines
12 KiB
TypeScript
498 lines
12 KiB
TypeScript
/**
|
|
* @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
|
|
});
|
|
}
|