From d911c1205d8bf60ae5b328334c82cd9ba8bb72a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=82=B0?= Date: Fri, 29 Aug 2025 11:35:22 +0900 Subject: [PATCH] =?UTF-8?q?=ED=83=80=EC=9E=84=20=EB=A6=AC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=20=EC=A0=9C=EC=9E=91,=20=EA=B7=B8=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EB=8A=94=20=EC=98=A4=EB=8D=94=20=EC=84=9C=EB=B8=8C?= =?UTF-8?q?=ED=8A=B8=EB=A6=AC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AI/Customer/Subtree/CustomerDefault.asset | 4 +- .../AI/Customer/Subtree/OrderSubtree.asset | 4 +- .../AI/Common/Decorator/TimeLimiter.cs | 120 ++++++++++++++++-- 3 files changed, 111 insertions(+), 17 deletions(-) diff --git a/Assets/_DDD/_Addressables/AI/Customer/Subtree/CustomerDefault.asset b/Assets/_DDD/_Addressables/AI/Customer/Subtree/CustomerDefault.asset index 82b1dc889..e27c56e57 100644 --- a/Assets/_DDD/_Addressables/AI/Customer/Subtree/CustomerDefault.asset +++ b/Assets/_DDD/_Addressables/AI/Customer/Subtree/CustomerDefault.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8cf20b556c79f13fe62788fd710d11e330f8ff35845fdb1205afdbe21bdf3530 -size 65015 +oid sha256:420b17e0ac254aee3beff94245c76fadbdd31a20bce709d76f5b52650747c243 +size 65013 diff --git a/Assets/_DDD/_Addressables/AI/Customer/Subtree/OrderSubtree.asset b/Assets/_DDD/_Addressables/AI/Customer/Subtree/OrderSubtree.asset index 6ff001db6..26d33033c 100644 --- a/Assets/_DDD/_Addressables/AI/Customer/Subtree/OrderSubtree.asset +++ b/Assets/_DDD/_Addressables/AI/Customer/Subtree/OrderSubtree.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28c1a3c2113f824ca9b3493aa71a73bffa3040160b830e2fde428b5c7bbe1610 -size 16553 +oid sha256:5193e6649c5835cd58152452f8f166e0e9678c87e98b437b80bdb35c5f173369 +size 20321 diff --git a/Assets/_DDD/_Scripts/Restaurant/Character/AI/Common/Decorator/TimeLimiter.cs b/Assets/_DDD/_Scripts/Restaurant/Character/AI/Common/Decorator/TimeLimiter.cs index 15c13cd29..4adb569c6 100644 --- a/Assets/_DDD/_Scripts/Restaurant/Character/AI/Common/Decorator/TimeLimiter.cs +++ b/Assets/_DDD/_Scripts/Restaurant/Character/AI/Common/Decorator/TimeLimiter.cs @@ -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().WithAllRW().WithAllRW().WithAll().Build(); + var query = SystemAPI.QueryBuilder().WithAllRW().WithAllRW() + .WithAllRW().WithAll().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 branchComponents, ref DynamicBuffer taskComponents, @@ -188,21 +192,24 @@ public void Execute(ref DynamicBuffer 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 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 branchComponents, } } } + + [NodeDescription("자식 태스크의 실행 시간을 제한합니다 (GameObject 워크플로우)")] + public class SharedTimeLimiter : DecoratorNode + { + [Tooltip("최대 실행 시간(초)")] + [SerializeField] private SharedVariable m_TimeLimit = 30f; + + [Tooltip("시간 초과 시 반환할 상태")] + [SerializeField] private TaskStatus m_TimeoutStatus = TaskStatus.Failure; + + public SharedVariable 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(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]; + } + } } \ No newline at end of file