타임 리미터 제작, 그에 맞는 오더 서브트리 변경

This commit is contained in:
김산 2025-08-29 11:35:22 +09:00
parent 447335ef20
commit d911c1205d
3 changed files with 111 additions and 17 deletions

Binary file not shown.

Binary file not shown.

View File

@ -3,6 +3,7 @@
using Opsive.BehaviorDesigner.Runtime.Tasks;
using Opsive.BehaviorDesigner.Runtime.Tasks.Decorators;
using Opsive.GraphDesigner.Runtime;
using Opsive.GraphDesigner.Runtime.Variables;
using Opsive.Shared.Utility;
using Unity.Burst;
using Unity.Entities;
@ -140,7 +141,9 @@ public struct TimeLimiterComponent : IBufferElementData
public TaskStatus TimeoutStatus;
}
public struct TimeLimiterTag : IComponentData, IEnableableComponent { }
public struct TimeLimiterTag : IComponentData, IEnableableComponent
{
}
[DisableAutoCreation]
public partial struct TimeLimiterTaskSystem : ISystem
@ -148,18 +151,19 @@ public partial struct TimeLimiterTaskSystem : ISystem
[BurstCompile]
private void OnUpdate(ref SystemState state)
{
var query = SystemAPI.QueryBuilder().WithAllRW<BranchComponent>().WithAllRW<TaskComponent>().WithAllRW<TimeLimiterComponent>().WithAll<TimeLimiterTag, EvaluationComponent>().Build();
var query = SystemAPI.QueryBuilder().WithAllRW<BranchComponent>().WithAllRW<TaskComponent>()
.WithAllRW<TimeLimiterComponent>().WithAll<TimeLimiterTag, EvaluationComponent>().Build();
state.Dependency = new TimeLimiterJob()
{
CurrentTime = (float)SystemAPI.Time.ElapsedTime
}.ScheduleParallel(query, state.Dependency);
}
[BurstCompile]
private partial struct TimeLimiterJob : IJobEntity
{
public float CurrentTime;
[BurstCompile]
public void Execute(ref DynamicBuffer<BranchComponent> branchComponents,
ref DynamicBuffer<TaskComponent> taskComponents,
@ -188,21 +192,24 @@ public void Execute(ref DynamicBuffer<BranchComponent> branchComponents,
branchComponents[taskComponent.BranchIndex] = branchComponent;
continue;
}
if (taskComponent.Status != TaskStatus.Running)
{
continue;
}
if (timeLimiterComponent.StartTime >= 0f &&
CurrentTime - timeLimiterComponent.StartTime >= timeLimiterComponent.TimeLimit) {
if (timeLimiterComponent.StartTime >= 0f &&
CurrentTime - timeLimiterComponent.StartTime >= timeLimiterComponent.TimeLimit)
{
// 시간 초과
taskComponent.Status = timeLimiterComponent.TimeoutStatus;
taskComponents[taskComponent.Index] = taskComponent;
// 자식 태스크가 실행 중이면 중단
childTaskComponent = taskComponents[taskComponent.Index + 1];
if (childTaskComponent.Status == TaskStatus.Running ||
childTaskComponent.Status == TaskStatus.Queued) {
if (childTaskComponent.Status == TaskStatus.Running ||
childTaskComponent.Status == TaskStatus.Queued)
{
childTaskComponent.Status = timeLimiterComponent.TimeoutStatus;
taskComponents[taskComponent.Index + 1] = childTaskComponent;
}
@ -211,14 +218,15 @@ public void Execute(ref DynamicBuffer<BranchComponent> branchComponents,
branchComponents[taskComponent.BranchIndex] = branchComponent;
continue;
}
childTaskComponent = taskComponents[taskComponent.Index + 1];
if (childTaskComponent.Status == TaskStatus.Queued ||
childTaskComponent.Status == TaskStatus.Running) {
if (childTaskComponent.Status == TaskStatus.Queued ||
childTaskComponent.Status == TaskStatus.Running)
{
// The child should keep running.
continue;
}
taskComponent.Status = childTaskComponent.Status;
taskComponents[taskComponent.Index] = taskComponent;
@ -228,4 +236,90 @@ public void Execute(ref DynamicBuffer<BranchComponent> branchComponents,
}
}
}
[NodeDescription("자식 태스크의 실행 시간을 제한합니다 (GameObject 워크플로우)")]
public class SharedTimeLimiter : DecoratorNode
{
[Tooltip("최대 실행 시간(초)")]
[SerializeField] private SharedVariable<float> m_TimeLimit = 30f;
[Tooltip("시간 초과 시 반환할 상태")]
[SerializeField] private TaskStatus m_TimeoutStatus = TaskStatus.Failure;
public SharedVariable<float> TimeLimit
{
get => m_TimeLimit;
set => m_TimeLimit = value;
}
public TaskStatus TimeoutStatus
{
get => m_TimeoutStatus;
set => m_TimeoutStatus = value;
}
private float m_StartTime;
private float m_PauseTime = -1f;
public override void OnStart()
{
base.OnStart();
m_StartTime = Time.time;
}
public override TaskStatus OnUpdate()
{
var taskComponents = m_BehaviorTree.World.EntityManager.GetBuffer<TaskComponent>(m_BehaviorTree.Entity);
ref var child = ref taskComponents.ElementAt(Index + 1);
if (Time.time - m_StartTime >= m_TimeLimit.Value)
{
if (child.Status == TaskStatus.Running || child.Status == TaskStatus.Queued)
{
child.Status = m_TimeoutStatus;
taskComponents[Index + 1] = child;
}
return m_TimeoutStatus;
}
if (child.Status == TaskStatus.Success || child.Status == TaskStatus.Failure)
{
return child.Status;
}
return TaskStatus.Running;
}
public override void OnBehaviorTreeStopped(bool paused)
{
base.OnBehaviorTreeStopped(paused);
if (paused) m_PauseTime = Time.time;
}
public override void OnBehaviorTreeStarted()
{
base.OnBehaviorTreeStarted();
if (m_PauseTime >= 0f)
{
m_StartTime += (Time.time - m_PauseTime);
m_PauseTime = -1f;
}
}
public override MemberVisibility GetSaveReflectionType(int index) => MemberVisibility.None;
public override object Save(World world, Entity entity)
{
// [제한 시간, 경과 시간] 저장
return new object[] { m_TimeLimit.Value, Time.time - m_StartTime };
}
public override void Load(object saveData, World world, Entity entity)
{
var data = (object[])saveData;
m_TimeLimit.Value = (float)data[0];
m_StartTime = Time.time - (float)data[1];
}
}
}