var count = counts.GetOrNew(compound.ID);
count++;
+ // Compound tasks marked with AllowRecursion are only evaluated once
+ if (counts.ContainsKey(compound.ID) && compound.AllowRecursion)
+ continue;
+
Assert.That(count, Is.LessThan(50));
counts[compound.ID] = count;
Count(protoManager.Index<HTNCompoundPrototype>(compoundTask.Task), counts, htnSystem, protoManager);
[DataField("branches", required: true)]
public List<HTNBranch> Branches = new();
+
+ /// <summary>
+ /// Exclude this compound task from the CompoundRecursion integration test.
+ /// </summary>
+ [DataField]
+ public bool AllowRecursion = false;
}
// How many primitive tasks we've added since last record.
var primitiveCount = 0;
+ int tasksProcessed = 0;
+
while (tasksToProcess.TryDequeue(out var currentTask))
{
+ if (tasksProcessed++ > _rootTask.MaximumTasks)
+ throw new Exception("HTN Planner exceeded maximum tasks");
+
switch (currentTask)
{
case HTNCompoundTask compound:
[ImplicitDataDefinitionForInheritors]
public abstract partial class HTNTask
{
+ /// <summary>
+ /// Limit the amount of tasks the planner considers. Exceeding this value sleeps the NPC and throws an exception.
+ /// The expected way to hit this limit is with badly written recursive tasks.
+ /// </summary>
+ [DataField]
+ public int MaximumTasks = 1000;
}