You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
6.5 KiB
C#
187 lines
6.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using FluidHTN.Conditions;
|
|
using FluidHTN.Debug;
|
|
using FluidHTN.Factory;
|
|
|
|
namespace FluidHTN.Contexts
|
|
{
|
|
public abstract class BaseContext : IContext
|
|
{
|
|
// ========================================================= PROPERTIES
|
|
|
|
public bool IsInitialized { get; protected set; } = false;
|
|
public bool IsDirty { get; set; }
|
|
public ContextState ContextState { get; set; } = ContextState.Executing;
|
|
public int CurrentDecompositionDepth { get; set; } = 0;
|
|
public abstract IFactory Factory { get; set; }
|
|
public List<int> MethodTraversalRecord { get; set; } = new List<int>();
|
|
public List<int> LastMTR { get; } = new List<int>();
|
|
public abstract List<string> MTRDebug { get; set; }
|
|
public abstract List<string> LastMTRDebug { get; set; }
|
|
public abstract bool DebugMTR { get; }
|
|
public abstract Queue<IBaseDecompositionLogEntry> DecompositionLog { get; set; }
|
|
public abstract bool LogDecomposition { get; }
|
|
public Queue<PartialPlanEntry> PartialPlanQueue { get; set; } = new Queue<PartialPlanEntry>();
|
|
public bool HasPausedPartialPlan { get; set; } = false;
|
|
|
|
public abstract byte[] WorldState { get; }
|
|
|
|
public Stack<KeyValuePair<EffectType, byte>>[] WorldStateChangeStack { get; protected set; }
|
|
|
|
// ========================================================= INITIALIZATION
|
|
|
|
public virtual void Init()
|
|
{
|
|
if (WorldStateChangeStack == null)
|
|
{
|
|
WorldStateChangeStack = new Stack<KeyValuePair<EffectType, byte>>[WorldState.Length];
|
|
for (var i = 0; i < WorldState.Length; i++)
|
|
WorldStateChangeStack[i] = new Stack<KeyValuePair<EffectType, byte>>();
|
|
}
|
|
|
|
if (DebugMTR)
|
|
{
|
|
if (MTRDebug == null) MTRDebug = new List<string>();
|
|
if (LastMTRDebug == null) LastMTRDebug = new List<string>();
|
|
}
|
|
|
|
if (LogDecomposition)
|
|
{
|
|
if (DecompositionLog == null) DecompositionLog = new Queue<IBaseDecompositionLogEntry>();
|
|
}
|
|
|
|
IsInitialized = true;
|
|
}
|
|
|
|
// ========================================================= STATE HANDLING
|
|
|
|
public bool HasState(int state, byte value)
|
|
{
|
|
return GetState(state) == value;
|
|
}
|
|
|
|
public byte GetState(int state)
|
|
{
|
|
if (ContextState == ContextState.Executing) return WorldState[state];
|
|
|
|
if (WorldStateChangeStack[state].Count == 0) return WorldState[state];
|
|
|
|
return WorldStateChangeStack[state].Peek().Value;
|
|
}
|
|
|
|
public virtual void SetState(int state, byte value, bool setAsDirty = true, EffectType e = EffectType.Permanent)
|
|
{
|
|
if (ContextState == ContextState.Executing)
|
|
{
|
|
// Prevent setting the world state dirty if we're not changing anything.
|
|
if (WorldState[state] == value)
|
|
return;
|
|
|
|
WorldState[state] = value;
|
|
if (setAsDirty)
|
|
IsDirty = true; // When a state change during execution, we need to mark the context dirty for replanning!
|
|
}
|
|
else
|
|
{
|
|
WorldStateChangeStack[state].Push(new KeyValuePair<EffectType, byte>(e, value));
|
|
}
|
|
}
|
|
|
|
// ========================================================= STATE STACK HANDLING
|
|
|
|
public int[] GetWorldStateChangeDepth(IFactory factory)
|
|
{
|
|
var stackDepth = factory.CreateArray<int>(WorldStateChangeStack.Length);
|
|
for (var i = 0; i < WorldStateChangeStack.Length; i++) stackDepth[i] = WorldStateChangeStack[i]?.Count ?? 0;
|
|
|
|
return stackDepth;
|
|
}
|
|
|
|
public void TrimForExecution()
|
|
{
|
|
if (ContextState == ContextState.Executing)
|
|
throw new Exception("Can not trim a context when in execution mode");
|
|
|
|
foreach (var stack in WorldStateChangeStack)
|
|
while (stack.Count != 0 && stack.Peek().Key != EffectType.Permanent)
|
|
stack.Pop();
|
|
}
|
|
|
|
public void TrimToStackDepth(int[] stackDepth)
|
|
{
|
|
if (ContextState == ContextState.Executing)
|
|
throw new Exception("Can not trim a context when in execution mode");
|
|
|
|
for (var i = 0; i < stackDepth.Length; i++)
|
|
{
|
|
var stack = WorldStateChangeStack[i];
|
|
while (stack.Count > stackDepth[i]) stack.Pop();
|
|
}
|
|
}
|
|
|
|
// ========================================================= STATE RESET
|
|
|
|
public virtual void Reset()
|
|
{
|
|
MethodTraversalRecord?.Clear();
|
|
LastMTR?.Clear();
|
|
|
|
if (DebugMTR)
|
|
{
|
|
MTRDebug?.Clear();
|
|
LastMTRDebug?.Clear();
|
|
}
|
|
|
|
IsInitialized = false;
|
|
}
|
|
|
|
// ========================================================= DECOMPOSITION LOGGING
|
|
|
|
public void Log(string name, string description, int depth, ITask task, ConsoleColor color = ConsoleColor.White)
|
|
{
|
|
if (LogDecomposition == false)
|
|
return;
|
|
|
|
DecompositionLog.Enqueue(new DecomposedCompoundTaskEntry
|
|
{
|
|
Name = name,
|
|
Description = description,
|
|
Entry = task,
|
|
Depth = depth,
|
|
Color = color,
|
|
});
|
|
}
|
|
|
|
public void Log(string name, string description, int depth, ICondition condition, ConsoleColor color = ConsoleColor.DarkGreen)
|
|
{
|
|
if (LogDecomposition == false)
|
|
return;
|
|
|
|
DecompositionLog.Enqueue(new DecomposedConditionEntry
|
|
{
|
|
Name = name,
|
|
Description = description,
|
|
Entry = condition,
|
|
Depth = depth,
|
|
Color = color
|
|
});
|
|
}
|
|
|
|
public void Log(string name, string description, int depth, IEffect effect, ConsoleColor color = ConsoleColor.DarkYellow)
|
|
{
|
|
if (LogDecomposition == false)
|
|
return;
|
|
|
|
DecompositionLog.Enqueue(new DecomposedEffectEntry
|
|
{
|
|
Name = name,
|
|
Description = description,
|
|
Entry = effect,
|
|
Depth = depth,
|
|
Color = color,
|
|
});
|
|
}
|
|
}
|
|
}
|