Spaces:
Runtime error
Runtime error
File size: 5,157 Bytes
00437a9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
using System;
namespace Quantum
{
public unsafe abstract partial class BTNode
{
[BotSDKHidden] public String Label;
[BotSDKHidden] public Int32 Id;
[NonSerialized] internal BTNode Parent;
[NonSerialized] internal Int32 ParentIndex;
public abstract BTNodeType NodeType { get; }
/// <summary>
/// Called once, for every Node, when the BT is being initialized
/// </summary>
public virtual void Init(Frame frame, AIBlackboardComponent* blackboard, BTAgent* agent)
{
var statusList = frame.ResolveList(agent->NodesStatus);
statusList.Add(0);
}
// -- STATUS --
public BTStatus GetStatus(Frame frame, BTAgent* agent)
{
var nodesAndStatus = frame.ResolveList(agent->NodesStatus);
return (BTStatus)nodesAndStatus[Id];
}
public void SetStatus(Frame frame, BTStatus status, BTAgent* agent)
{
var nodesAndStatus = frame.ResolveList(agent->NodesStatus);
nodesAndStatus[Id] = (Byte)status;
}
/// <summary>
/// Called whenever the BT execution includes this node as part of the current context
/// </summary>
/// <param name="btParams"></param>
public virtual void OnEnter(BTParams btParams) { }
public virtual void OnEnterRunning(BTParams btParams) { }
/// <summary>
/// Called when traversing the tree upwards and the node is already finished with its job.
/// Used by Composites and Leafs to remove their Services from the list of active services
/// as it is not anymore part of the current subtree.
/// Dynamic Composites also remove themselves
/// </summary>
/// <param name="btParams"></param>
public virtual void OnExit(BTParams btParams) { }
public virtual void OnAbort(BTParams btParams)
{
}
/// <summary>
/// Called when getting out of a sub-branch and this node is being discarded
/// </summary>
/// <param name="btParams"></param>
public unsafe virtual void OnReset(BTParams btParams)
{
SetStatus(btParams.Frame, BTStatus.Inactive, btParams.Agent);
}
public void EvaluateAbortNode(BTParams btParams)
{
if (btParams.Agent->AbortNodeId == Id)
{
btParams.Agent->AbortNodeId = 0;
}
}
public BTStatus RunUpdate(BTParams btParams, bool continuingAbort = false)
{
var oldStatus = GetStatus(btParams.Frame, btParams.Agent);
if (oldStatus == BTStatus.Success || oldStatus == BTStatus.Failure)
{
return oldStatus;
}
if (oldStatus == BTStatus.Abort)
{
if (btParams.Agent->IsAborting == true)
{
EvaluateAbortNode(btParams);
}
return oldStatus;
}
// If this node was inactive, this means that we're entering on it for the first time, so we call OnEnter
// An exception from this rule is when we chose this node to continue an abort process. In that case,
// we already executed OnEnter before, so we don't repeat it
if (oldStatus == BTStatus.Inactive && continuingAbort == false)
{
OnEnter(btParams);
}
var newStatus = BTStatus.Failure;
try
{
newStatus = OnUpdate(btParams);
if (btParams.Agent->IsAborting)
{
newStatus = BTStatus.Abort;
}
// Used for debugging purposes
if (newStatus == BTStatus.Success)
{
BTManager.OnNodeSuccess?.Invoke(btParams.Entity, Guid.Value);
BTManager.OnNodeExit?.Invoke(btParams.Entity, Guid.Value);
}
if (newStatus == BTStatus.Failure)
{
BTManager.OnNodeFailure?.Invoke(btParams.Entity, Guid.Value);
BTManager.OnNodeExit?.Invoke(btParams.Entity, Guid.Value);
}
}
catch (Exception e)
{
Log.Error("Exception in Behaviour Tree node '{0}' ({1}) - setting node status to Failure", Label, Guid);
Log.Exception(e);
}
SetStatus(btParams.Frame, newStatus, btParams.Agent);
if ((newStatus == BTStatus.Running || newStatus == BTStatus.Success) &&
(oldStatus == BTStatus.Failure || oldStatus == BTStatus.Inactive))
{
OnEnterRunning(btParams);
}
if (newStatus == BTStatus.Running && NodeType == BTNodeType.Leaf)
{
// If we are a leaf, we can store the current node
// We know that there has only one leaf node running at any time, no parallel branches possible
// The Run() method also return a tuple <BTStatus, BTNode(CurrentNode)>
btParams.Agent->Current = this;
}
return newStatus;
}
/// <summary>
/// Used by Decorators to evaluate if a condition succeeds or not.
/// Upon success, allow the flow to continue.
/// Upon failure, blocks the execution so another path is taken
/// </summary>
/// <param name="btParams"></param>
/// <returns></returns>
public virtual Boolean DryRun(BTParams btParams)
{
return false;
}
public virtual Boolean OnDynamicRun(BTParams btParams)
{
return true;
}
/// <summary>
/// Called every tick while this Node is part of the current sub-tree.
/// Returning "Success/Failure" will make the tree continue its execution.
/// Returning "Running" will store this Node as the Current Node and re-execute it on the next frame
/// unless something else interrputs
/// </summary>
/// <param name="btParams"></param>
/// <returns></returns>
protected abstract BTStatus OnUpdate(BTParams btParams);
}
} |