refactor(behavior-tree)!: 迁移到 Runtime 执行器架构 (#196)

* refactor(behavior-tree)!: 迁移到 Runtime 执行器架构

* fix(behavior-tree): 修复LogAction中的ReDoS安全漏洞

* feat(behavior-tree): 完善行为树核心功能并修复类型错误
This commit is contained in:
YHH
2025-10-31 17:27:38 +08:00
committed by GitHub
parent c58e3411fd
commit 61813e67b6
113 changed files with 7795 additions and 10564 deletions

View File

@@ -1,179 +1,92 @@
import { Entity } from '@esengine/ecs-framework';
import { BehaviorTreeNode } from './Components/BehaviorTreeNode';
import { ActiveNode } from './Components/ActiveNode';
import { TaskStatus } from './Types/TaskStatus';
import { Entity, Core } from '@esengine/ecs-framework';
import { BehaviorTreeData } from './Runtime/BehaviorTreeData';
import { BehaviorTreeRuntimeComponent } from './Runtime/BehaviorTreeRuntimeComponent';
import { BehaviorTreeAssetManager } from './Runtime/BehaviorTreeAssetManager';
/**
* 行为树启动/停止辅助类
* 行为树启动辅助类
*
* 提供便捷方法来启动、停止和暂停行为树
* 提供便捷方法来启动、停止行为树
*/
export class BehaviorTreeStarter {
/**
* 启动行为树
*
* 给根节点添加 ActiveNode 组件,使行为树开始执行
*
* @param rootEntity 行为树根节点实体
*
* @example
* ```typescript
* const aiRoot = scene.createEntity('aiRoot');
* // ... 构建行为树结构
* BehaviorTreeStarter.start(aiRoot);
* ```
* @param entity 游戏实体
* @param treeData 行为树数据
* @param autoStart 是否自动开始执行
*/
static start(rootEntity: Entity): void {
if (!rootEntity.hasComponent(BehaviorTreeNode)) {
throw new Error('Entity must have BehaviorTreeNode component');
static start(entity: Entity, treeData: BehaviorTreeData, autoStart: boolean = true): void {
const assetManager = Core.services.resolve(BehaviorTreeAssetManager);
assetManager.loadAsset(treeData);
let runtime = entity.getComponent(BehaviorTreeRuntimeComponent);
if (!runtime) {
runtime = new BehaviorTreeRuntimeComponent();
entity.addComponent(runtime);
}
if (!rootEntity.hasComponent(ActiveNode)) {
rootEntity.addComponent(new ActiveNode());
runtime.treeAssetId = treeData.id;
runtime.autoStart = autoStart;
if (treeData.blackboardVariables) {
for (const [key, value] of treeData.blackboardVariables.entries()) {
runtime.setBlackboardValue(key, value);
}
}
if (autoStart) {
runtime.isRunning = true;
}
}
/**
* 停止行为树
*
* 移除所有节点的 ActiveNode 组件,停止执行
*
* @param rootEntity 行为树根节点实体
*
* @example
* ```typescript
* BehaviorTreeStarter.stop(aiRoot);
* ```
* @param entity 游戏实体
*/
static stop(rootEntity: Entity): void {
this.stopRecursive(rootEntity);
}
/**
* 递归停止所有子节点
*/
private static stopRecursive(entity: Entity): void {
// 移除活跃标记
if (entity.hasComponent(ActiveNode)) {
entity.removeComponentByType(ActiveNode);
}
// 重置节点状态
const node = entity.getComponent(BehaviorTreeNode);
if (node) {
node.reset();
}
// 递归处理子节点
for (const child of entity.children) {
this.stopRecursive(child);
static stop(entity: Entity): void {
const runtime = entity.getComponent(BehaviorTreeRuntimeComponent);
if (runtime) {
runtime.isRunning = false;
runtime.resetAllStates();
}
}
/**
* 暂停行为树
*
* 移除 ActiveNode 但保留节点状态,可以恢复执行
*
* @param rootEntity 行为树根节点实体
*
* @example
* ```typescript
* // 暂停
* BehaviorTreeStarter.pause(aiRoot);
*
* // 恢复
* BehaviorTreeStarter.resume(aiRoot);
* ```
* @param entity 游戏实体
*/
static pause(rootEntity: Entity): void {
this.pauseRecursive(rootEntity);
}
/**
* 递归暂停所有子节点
*/
private static pauseRecursive(entity: Entity): void {
// 只移除活跃标记,不重置状态
if (entity.hasComponent(ActiveNode)) {
entity.removeComponentByType(ActiveNode);
}
// 递归处理子节点
for (const child of entity.children) {
this.pauseRecursive(child);
static pause(entity: Entity): void {
const runtime = entity.getComponent(BehaviorTreeRuntimeComponent);
if (runtime) {
runtime.isRunning = false;
}
}
/**
* 恢复行为树执行
* 恢复行为树
*
* 从暂停状态恢复,重新添加 ActiveNode 到之前正在执行的节点
*
* @param rootEntity 行为树根节点实体
*
* @example
* ```typescript
* BehaviorTreeStarter.resume(aiRoot);
* ```
* @param entity 游戏实体
*/
static resume(rootEntity: Entity): void {
this.resumeRecursive(rootEntity);
}
/**
* 递归恢复所有正在执行的节点
*/
private static resumeRecursive(entity: Entity): void {
const node = entity.getComponent(BehaviorTreeNode);
if (!node) {
return;
}
// 如果节点状态是 Running恢复活跃标记
if (node.status === TaskStatus.Running) {
if (!entity.hasComponent(ActiveNode)) {
entity.addComponent(new ActiveNode());
}
}
// 递归处理子节点
for (const child of entity.children) {
this.resumeRecursive(child);
static resume(entity: Entity): void {
const runtime = entity.getComponent(BehaviorTreeRuntimeComponent);
if (runtime) {
runtime.isRunning = true;
}
}
/**
* 重启行为树
*
* 停止并重置所有节点,然后重新启动
*
* @param rootEntity 行为树根节点实体
*
* @example
* ```typescript
* BehaviorTreeStarter.restart(aiRoot);
* ```
* @param entity 游戏实体
*/
static restart(rootEntity: Entity): void {
this.stop(rootEntity);
this.start(rootEntity);
}
/**
* 检查行为树是否正在运行
*
* @param rootEntity 行为树根节点实体
* @returns 是否正在运行
*
* @example
* ```typescript
* if (BehaviorTreeStarter.isRunning(aiRoot)) {
* console.log('AI is active');
* }
* ```
*/
static isRunning(rootEntity: Entity): boolean {
return rootEntity.hasComponent(ActiveNode);
static restart(entity: Entity): void {
const runtime = entity.getComponent(BehaviorTreeRuntimeComponent);
if (runtime) {
runtime.resetAllStates();
runtime.isRunning = true;
}
}
}