Files
esengine/packages/behavior-tree/src/Runtime/Executors/RepeaterExecutor.ts
T
YHH 61813e67b6 refactor(behavior-tree)!: 迁移到 Runtime 执行器架构 (#196)
* refactor(behavior-tree)!: 迁移到 Runtime 执行器架构

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

* feat(behavior-tree): 完善行为树核心功能并修复类型错误
2025-10-31 17:27:38 +08:00

77 lines
2.3 KiB
TypeScript

import { TaskStatus, NodeType } from '../../Types/TaskStatus';
import { INodeExecutor, NodeExecutionContext, BindingHelper } from '../NodeExecutor';
import { NodeExecutorMetadata } from '../NodeMetadata';
/**
* 重复装饰器执行器
*
* 重复执行子节点指定次数
*/
@NodeExecutorMetadata({
implementationType: 'Repeater',
nodeType: NodeType.Decorator,
displayName: '重复',
description: '重复执行子节点指定次数',
category: 'Decorator',
configSchema: {
repeatCount: {
type: 'number',
default: 1,
description: '重复次数(-1表示无限循环)',
supportBinding: true
},
endOnFailure: {
type: 'boolean',
default: false,
description: '子节点失败时是否结束'
}
}
})
export class RepeaterExecutor implements INodeExecutor {
execute(context: NodeExecutionContext): TaskStatus {
const { nodeData, state, runtime } = context;
const repeatCount = BindingHelper.getValue<number>(context, 'repeatCount', 1);
const endOnFailure = BindingHelper.getValue<boolean>(context, 'endOnFailure', false);
if (!nodeData.children || nodeData.children.length === 0) {
return TaskStatus.Success;
}
const childId = nodeData.children[0]!;
if (!state.repeatCount) {
state.repeatCount = 0;
}
const status = context.executeChild(childId);
if (status === TaskStatus.Running) {
return TaskStatus.Running;
}
if (status === TaskStatus.Failure && endOnFailure) {
state.repeatCount = 0;
return TaskStatus.Failure;
}
state.repeatCount++;
runtime.resetNodeState(childId);
const shouldContinue = (repeatCount === -1) || (state.repeatCount < repeatCount);
if (shouldContinue) {
return TaskStatus.Running;
} else {
state.repeatCount = 0;
return TaskStatus.Success;
}
}
reset(context: NodeExecutionContext): void {
delete context.state.repeatCount;
if (context.nodeData.children && context.nodeData.children.length > 0) {
context.runtime.resetNodeState(context.nodeData.children[0]!);
}
}
}