Fix NPC prototype reloads (#13981)
This commit is contained in:
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.NPC.HTN;
|
using Content.Server.NPC.HTN;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ public sealed class NPCTest
|
|||||||
|
|
||||||
await server.WaitIdleAsync();
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
|
var htnSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<HTNSystem>();
|
||||||
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
||||||
|
|
||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
@@ -27,7 +29,7 @@ public sealed class NPCTest
|
|||||||
|
|
||||||
foreach (var compound in protoManager.EnumeratePrototypes<HTNCompoundTask>())
|
foreach (var compound in protoManager.EnumeratePrototypes<HTNCompoundTask>())
|
||||||
{
|
{
|
||||||
Count(compound, counts);
|
Count(compound, counts, htnSystem);
|
||||||
counts.Clear();
|
counts.Clear();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -35,11 +37,13 @@ public sealed class NPCTest
|
|||||||
await pool.CleanReturnAsync();
|
await pool.CleanReturnAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Count(HTNCompoundTask compound, Dictionary<string, int> counts)
|
private static void Count(HTNCompoundTask compound, Dictionary<string, int> 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)
|
if (task is HTNCompoundTask compoundTask)
|
||||||
{
|
{
|
||||||
@@ -48,7 +52,7 @@ public sealed class NPCTest
|
|||||||
|
|
||||||
Assert.That(count, Is.LessThan(50));
|
Assert.That(count, Is.LessThan(50));
|
||||||
counts[compound.ID] = count;
|
counts[compound.ID] = count;
|
||||||
Count(compoundTask, counts);
|
Count(compoundTask, counts, htnSystem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ public sealed class HTNBranch
|
|||||||
[DataField("preconditions")]
|
[DataField("preconditions")]
|
||||||
public List<HTNPrecondition> Preconditions = new();
|
public List<HTNPrecondition> Preconditions = new();
|
||||||
|
|
||||||
[ViewVariables] public List<HTNTask> Tasks = new();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Due to how serv3 works we need to defer getting the actual tasks until after they have all been serialized.
|
/// Due to how serv3 works we need to defer getting the actual tasks until after they have all been serialized.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace Content.Server.NPC.HTN;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class HTNPlanJob : Job<HTNPlan>
|
public sealed class HTNPlanJob : Job<HTNPlan>
|
||||||
{
|
{
|
||||||
|
private readonly HTNSystem _htn;
|
||||||
private readonly HTNCompoundTask _rootTask;
|
private readonly HTNCompoundTask _rootTask;
|
||||||
private NPCBlackboard _blackboard;
|
private NPCBlackboard _blackboard;
|
||||||
|
|
||||||
@@ -21,11 +22,13 @@ public sealed class HTNPlanJob : Job<HTNPlan>
|
|||||||
|
|
||||||
public HTNPlanJob(
|
public HTNPlanJob(
|
||||||
double maxTime,
|
double maxTime,
|
||||||
|
HTNSystem htn,
|
||||||
HTNCompoundTask rootTask,
|
HTNCompoundTask rootTask,
|
||||||
NPCBlackboard blackboard,
|
NPCBlackboard blackboard,
|
||||||
List<int>? branchTraversal,
|
List<int>? branchTraversal,
|
||||||
CancellationToken cancellationToken = default) : base(maxTime, cancellationToken)
|
CancellationToken cancellationToken = default) : base(maxTime, cancellationToken)
|
||||||
{
|
{
|
||||||
|
_htn = htn;
|
||||||
_rootTask = rootTask;
|
_rootTask = rootTask;
|
||||||
_blackboard = blackboard;
|
_blackboard = blackboard;
|
||||||
_branchTraversal = branchTraversal;
|
_branchTraversal = branchTraversal;
|
||||||
@@ -156,6 +159,8 @@ public sealed class HTNPlanJob : Job<HTNPlan>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private bool TryFindSatisfiedMethod(HTNCompoundTask compound, Queue<HTNTask> tasksToProcess, NPCBlackboard blackboard, ref int mtrIndex)
|
private bool TryFindSatisfiedMethod(HTNCompoundTask compound, Queue<HTNTask> tasksToProcess, NPCBlackboard blackboard, ref int mtrIndex)
|
||||||
{
|
{
|
||||||
|
var compBranches = _htn.CompoundBranches[compound];
|
||||||
|
|
||||||
for (var i = mtrIndex; i < compound.Branches.Count; i++)
|
for (var i = mtrIndex; i < compound.Branches.Count; i++)
|
||||||
{
|
{
|
||||||
var branch = compound.Branches[i];
|
var branch = compound.Branches[i];
|
||||||
@@ -173,7 +178,9 @@ public sealed class HTNPlanJob : Job<HTNPlan>
|
|||||||
if (!isValid)
|
if (!isValid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
foreach (var task in branch.Tasks)
|
var branchTasks = compBranches[i];
|
||||||
|
|
||||||
|
foreach (var task in branchTasks)
|
||||||
{
|
{
|
||||||
tasksToProcess.Enqueue(task);
|
tasksToProcess.Enqueue(task);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ public sealed class HTNSystem : EntitySystem
|
|||||||
|
|
||||||
private readonly HashSet<ICommonSession> _subscribers = new();
|
private readonly HashSet<ICommonSession> _subscribers = new();
|
||||||
|
|
||||||
|
// hngngghghgh
|
||||||
|
public IReadOnlyDictionary<HTNCompoundTask, List<HTNTask>[]> CompoundBranches => _compoundBranches;
|
||||||
|
private Dictionary<HTNCompoundTask, List<HTNTask>[]> _compoundBranches = new();
|
||||||
|
|
||||||
// Hierarchical Task Network
|
// Hierarchical Task Network
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -75,6 +79,8 @@ public sealed class HTNSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_compoundBranches.Clear();
|
||||||
|
|
||||||
// Add dependencies for all operators.
|
// Add dependencies for all operators.
|
||||||
// We put code on operators as I couldn't think of a clean way to put it on systems.
|
// 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<HTNCompoundTask>())
|
foreach (var compound in _prototypeManager.EnumeratePrototypes<HTNCompoundTask>())
|
||||||
@@ -111,21 +117,25 @@ public sealed class HTNSystem : EntitySystem
|
|||||||
|
|
||||||
private void UpdateCompound(HTNCompoundTask compound)
|
private void UpdateCompound(HTNCompoundTask compound)
|
||||||
{
|
{
|
||||||
foreach (var branch in compound.Branches)
|
var branchies = new List<HTNTask>[compound.Branches.Count];
|
||||||
|
_compoundBranches.Add(compound, branchies);
|
||||||
|
|
||||||
|
for (var i = 0; i < compound.Branches.Count; i++)
|
||||||
{
|
{
|
||||||
branch.Tasks.Clear();
|
var branch = compound.Branches[i];
|
||||||
branch.Tasks.EnsureCapacity(branch.TaskPrototypes.Count);
|
var brancho = new List<HTNTask>(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!
|
// 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)
|
foreach (var proto in branch.TaskPrototypes)
|
||||||
{
|
{
|
||||||
if (_prototypeManager.TryIndex<HTNCompoundTask>(proto, out var compTask))
|
if (_prototypeManager.TryIndex<HTNCompoundTask>(proto, out var compTask))
|
||||||
{
|
{
|
||||||
branch.Tasks.Add(compTask);
|
brancho.Add(compTask);
|
||||||
}
|
}
|
||||||
else if (_prototypeManager.TryIndex<HTNPrimitiveTask>(proto, out var primTask))
|
else if (_prototypeManager.TryIndex<HTNPrimitiveTask>(proto, out var primTask))
|
||||||
{
|
{
|
||||||
branch.Tasks.Add(primTask);
|
brancho.Add(primTask);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -330,6 +340,7 @@ public sealed class HTNSystem : EntitySystem
|
|||||||
|
|
||||||
var job = new HTNPlanJob(
|
var job = new HTNPlanJob(
|
||||||
0.02,
|
0.02,
|
||||||
|
this,
|
||||||
_prototypeManager.Index<HTNCompoundTask>(component.RootTask),
|
_prototypeManager.Index<HTNCompoundTask>(component.RootTask),
|
||||||
component.Blackboard.ShallowClone(), branchTraversal, cancelToken.Token);
|
component.Blackboard.ShallowClone(), branchTraversal, cancelToken.Token);
|
||||||
|
|
||||||
@@ -360,13 +371,17 @@ public sealed class HTNSystem : EntitySystem
|
|||||||
else if (task is HTNCompoundTask compound)
|
else if (task is HTNCompoundTask compound)
|
||||||
{
|
{
|
||||||
builder.AppendLine(buffer + $"Compound: {task.ID}");
|
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:");
|
builder.AppendLine(buffer + " branch:");
|
||||||
indent++;
|
indent++;
|
||||||
|
var branchTasks = compoundBranches[i];
|
||||||
|
|
||||||
foreach (var branchTask in branch.Tasks)
|
foreach (var branchTask in branchTasks)
|
||||||
{
|
{
|
||||||
AppendDomain(builder, branchTask, ref indent);
|
AppendDomain(builder, branchTask, ref indent);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user