From 6b6c6b1c9f6504ee75671e080330cc67f2eb743f Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 8 Feb 2023 08:27:34 +1100 Subject: [PATCH] Fix NPC prototype reloads (#13981) --- Content.IntegrationTests/Tests/NPC/NPCTest.cs | 14 +++++---- Content.Server/NPC/HTN/HTNBranch.cs | 2 -- Content.Server/NPC/HTN/HTNPlanJob.cs | 9 +++++- Content.Server/NPC/HTN/HTNSystem.cs | 29 ++++++++++++++----- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/Content.IntegrationTests/Tests/NPC/NPCTest.cs b/Content.IntegrationTests/Tests/NPC/NPCTest.cs index 96e7f752a4..08df5f98a2 100644 --- a/Content.IntegrationTests/Tests/NPC/NPCTest.cs +++ b/Content.IntegrationTests/Tests/NPC/NPCTest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Content.Server.NPC.HTN; using NUnit.Framework; +using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -19,6 +20,7 @@ public sealed class NPCTest await server.WaitIdleAsync(); + var htnSystem = server.ResolveDependency().GetEntitySystem(); var protoManager = server.ResolveDependency(); await server.WaitAssertion(() => @@ -27,7 +29,7 @@ public sealed class NPCTest foreach (var compound in protoManager.EnumeratePrototypes()) { - Count(compound, counts); + Count(compound, counts, htnSystem); counts.Clear(); } }); @@ -35,11 +37,13 @@ public sealed class NPCTest await pool.CleanReturnAsync(); } - private static void Count(HTNCompoundTask compound, Dictionary counts) + private static void Count(HTNCompoundTask compound, Dictionary counts, HTNSystem htnSystem) { - foreach (var branch in compound.Branches) + var compoundBranches = htnSystem.CompoundBranches[compound]; + + for (var i = 0; i < compound.Branches.Count; i++) { - foreach (var task in branch.Tasks) + foreach (var task in compoundBranches[i]) { if (task is HTNCompoundTask compoundTask) { @@ -48,7 +52,7 @@ public sealed class NPCTest Assert.That(count, Is.LessThan(50)); counts[compound.ID] = count; - Count(compoundTask, counts); + Count(compoundTask, counts, htnSystem); } } } diff --git a/Content.Server/NPC/HTN/HTNBranch.cs b/Content.Server/NPC/HTN/HTNBranch.cs index 88a39aaabf..96645b2906 100644 --- a/Content.Server/NPC/HTN/HTNBranch.cs +++ b/Content.Server/NPC/HTN/HTNBranch.cs @@ -12,8 +12,6 @@ public sealed class HTNBranch [DataField("preconditions")] public List Preconditions = new(); - [ViewVariables] public List Tasks = new(); - /// /// Due to how serv3 works we need to defer getting the actual tasks until after they have all been serialized. /// diff --git a/Content.Server/NPC/HTN/HTNPlanJob.cs b/Content.Server/NPC/HTN/HTNPlanJob.cs index 580803cca7..f5ba3e8fd9 100644 --- a/Content.Server/NPC/HTN/HTNPlanJob.cs +++ b/Content.Server/NPC/HTN/HTNPlanJob.cs @@ -11,6 +11,7 @@ namespace Content.Server.NPC.HTN; /// public sealed class HTNPlanJob : Job { + private readonly HTNSystem _htn; private readonly HTNCompoundTask _rootTask; private NPCBlackboard _blackboard; @@ -21,11 +22,13 @@ public sealed class HTNPlanJob : Job public HTNPlanJob( double maxTime, + HTNSystem htn, HTNCompoundTask rootTask, NPCBlackboard blackboard, List? branchTraversal, CancellationToken cancellationToken = default) : base(maxTime, cancellationToken) { + _htn = htn; _rootTask = rootTask; _blackboard = blackboard; _branchTraversal = branchTraversal; @@ -156,6 +159,8 @@ public sealed class HTNPlanJob : Job /// private bool TryFindSatisfiedMethod(HTNCompoundTask compound, Queue tasksToProcess, NPCBlackboard blackboard, ref int mtrIndex) { + var compBranches = _htn.CompoundBranches[compound]; + for (var i = mtrIndex; i < compound.Branches.Count; i++) { var branch = compound.Branches[i]; @@ -173,7 +178,9 @@ public sealed class HTNPlanJob : Job if (!isValid) continue; - foreach (var task in branch.Tasks) + var branchTasks = compBranches[i]; + + foreach (var task in branchTasks) { tasksToProcess.Enqueue(task); } diff --git a/Content.Server/NPC/HTN/HTNSystem.cs b/Content.Server/NPC/HTN/HTNSystem.cs index b112d7696c..9b84dc6515 100644 --- a/Content.Server/NPC/HTN/HTNSystem.cs +++ b/Content.Server/NPC/HTN/HTNSystem.cs @@ -27,6 +27,10 @@ public sealed class HTNSystem : EntitySystem private readonly HashSet _subscribers = new(); + // hngngghghgh + public IReadOnlyDictionary[]> CompoundBranches => _compoundBranches; + private Dictionary[]> _compoundBranches = new(); + // Hierarchical Task Network public override void Initialize() { @@ -75,6 +79,8 @@ public sealed class HTNSystem : EntitySystem } } + _compoundBranches.Clear(); + // Add dependencies for all operators. // We put code on operators as I couldn't think of a clean way to put it on systems. foreach (var compound in _prototypeManager.EnumeratePrototypes()) @@ -111,21 +117,25 @@ public sealed class HTNSystem : EntitySystem private void UpdateCompound(HTNCompoundTask compound) { - foreach (var branch in compound.Branches) + var branchies = new List[compound.Branches.Count]; + _compoundBranches.Add(compound, branchies); + + for (var i = 0; i < compound.Branches.Count; i++) { - branch.Tasks.Clear(); - branch.Tasks.EnsureCapacity(branch.TaskPrototypes.Count); + var branch = compound.Branches[i]; + var brancho = new List(branch.TaskPrototypes.Count); + branchies[i] = brancho; // Didn't do this in a typeserializer because we can't recursively grab our own prototype during it, woohoo! foreach (var proto in branch.TaskPrototypes) { if (_prototypeManager.TryIndex(proto, out var compTask)) { - branch.Tasks.Add(compTask); + brancho.Add(compTask); } else if (_prototypeManager.TryIndex(proto, out var primTask)) { - branch.Tasks.Add(primTask); + brancho.Add(primTask); } else { @@ -330,6 +340,7 @@ public sealed class HTNSystem : EntitySystem var job = new HTNPlanJob( 0.02, + this, _prototypeManager.Index(component.RootTask), component.Blackboard.ShallowClone(), branchTraversal, cancelToken.Token); @@ -360,13 +371,17 @@ public sealed class HTNSystem : EntitySystem else if (task is HTNCompoundTask compound) { builder.AppendLine(buffer + $"Compound: {task.ID}"); + var compoundBranches = CompoundBranches[compound]; - foreach (var branch in compound.Branches) + for (var i = 0; i < compound.Branches.Count; i++) { + var branch = compound.Branches[i]; + builder.AppendLine(buffer + " branch:"); indent++; + var branchTasks = compoundBranches[i]; - foreach (var branchTask in branch.Tasks) + foreach (var branchTask in branchTasks) { AppendDomain(builder, branchTask, ref indent); } -- 2.52.0