Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Discussion DumbGOAP AI

Discussion in 'Entity Component System' started by Abbrew, Aug 7, 2023.

  1. Abbrew

    Abbrew

    Joined:
    Jan 1, 2018
    Posts:
    417
    A common approach to structuring AI with DOTS is Behavior Trees, which works well for very complex AIs. However, the tradeoff is a potentially non DOTS-friendly design where many different entities representing BT nodes must constantly be randomly accessed. An alternative design that provides performance while trading off a little readability and extensibility is a dumbed down version of GOAP, or DumbGOAP for short (I made this word up). The goal of DumbGOAP is to eliminate the unwieldiness of complex state machines while retaining the intelligent decisionmaking of Behavior Trees.

    In DumbGOAP, overall AI behavior is grouped into an ordered list of Plans. Each Plan consists of a Condition and an Action. These Plans' Conditions are evaluated only during Decisions, which happen for an Actor at the start of the game, and every time the Actor finishes executing its latest Action. A simple example of a DumbGOAP AI for a Total War-style RTS game is, in the form of (Condition) (Action):
    1. (If overly pressured by enemy) (Then flee the battlefield)
    2. (If enemy nearby but not in melee range) (Then move towards enemy)
    3. (If enemy in melee range) (Then attack enemy)
    4. (If out of formation) (Then adhere to formation)
    5. (By default) (Then stand around doing nothing)

    First, an important concept in DumbGOAP is that each Plans' Conditions are evaluated in order of priority. So in that example, once an actor is ready to evaluate, it will first check if it's pressured. If so, it flees. Otherwise, it checks the next Condition and so on. A beneficial side effect is that early termination can eliminate unneeded calculations.

    Second, once a Condition succeeds and its corresponding Action is chosen, the Decision logic won't run until the Action completes. In the case where the (Then attack enemy) Action is chosen in the example, the actor may spend 2 seconds in its attack animation, during which no costly Decision logic will run for it. The result is that unnecessary Decision calculations are avoided.

    Next, you may realize that several useful constructs to flesh out AI behavior are missing. They, and their solutions, are:
    1. Canceling an Action early: The solution is to have a Canceller execute every x seconds and if it succeeds, trigger another Decision immediately (make sure to run some cleanup logic on the cancelled Action!)
    2. Executing something during an Action: The solution is to have a Duration execute every x seconds.

    An example of an Action that can be enhanced by these two constructs is (Then flee the battlefield) from our example. There could be a Canceler (Cancel if no more enemies are nearby enough to threaten the actor) and a Duration (Constantly induce panic in your nearby allies). The result is a much more fleshed out Action.

    Finally, one may ask "how is this different than or better than a state machine?" The answer is that DumbGOAP is, on a high level, no different than a state machine, yet at the same time is much better in scalability. In state machines, state is driven by an enum that represents the Action the Actor will take. Once an Actor is in a certain state/Action, it can only move onto a different state/Action that must be explicitly coded. However, in DumbGOAP, state/Action is driven on the fly by calculations done on the environment (which consists of the state of the Actor, other Actors, environment obstacles, etc), and can "transition" onto any other state/Action if the Decision logic allows for it. As a result, there is effectively only one "state" in DumbGOAP, which completely eliminates transition logic, which is the bane of complex state machines.

    Now, you may have a few concerns about code implementation of this AI design. They are addressed thus:
    1. Spaghetti code: admittedly, having a giant chain of if/else (we can't use switch because we're calculating booleans on if the Plan's Condition allows the Action) reeks of sphagetti code that makes it easy to make mistakes, and hard to read. This could be mitigated by carefully collapsing each Action execution under a #region. Further, actual execution of an Action could be refactored into a helper method for readability and reusability.
    2. Parallelization: inevitably, within a single Actor entity, it will have to interact with other Actor entities which may involve Component/BufferLookups Read-Writes which in turn prevents parallelization. The solution is to relegate all Actor interactions to a separate single-threaded job that bears the brunt of all random access. To support this, the now-parallelizable Decision job will write to a NativeQueue<Damage/Stun/Intimidate/Buff>.ParallelWriter, and the Interaction job will process them with all the expensive Lookups it wants. Of course, this means that the parallelized Decision job will need support for common operations within itself. They are parallel pathfinding (you can nest NavMeshQuery inside of a NativeArray and access them with [NativeThreadIndex], provided that you label the NativeArray with [NativeDisableContainerSafetyRestriction] and [NativeDisableParallelForIForgotTheRest]) and querying for nearby other Actors (you can implement your own spatial partitioning)
    3. Long running Actions: say an Actor must execute (Then adhere to formation) because it's too far away from its formation, but by the time it gets there, the formation has moved 100 meters away because its leading officer has moved. This unrealistic behavior would also happen in other long-running Actions, many of which have to do with following long paths. A simple solution is to terminate all long-running and looping Actions within X seconds, so that another Evaluate is triggered. This way, the Actor can recalculate its destination with more regularity and up-to-date accuracy. If it ends up doing the exact same Action, then the only harm done is a wasted Decision (which are still quite infrequent and inconsequential). If it ends up doing something else, then that's value gained because that something else is always smarter Decision. Make sure to not early terminate these long-running/looping behaviors too often, or else Decisions will happen too frequently!

    In summary, DumbGOAP is suitable if:
    1. Your Actor's AI can be described as "I don't care about the long-term future, I'll just keep doing what makes sense in the moment". Most likely huge-scale RTS games with simple-minded soldiers
    2. The Actor interacts with other Actors based off of spatial queries (or any type of query that can be accessed from within a parallelized job), or by accessing its own components containing pre-defined Actor relationships

    It's unsuitable if:
    1. Your Actor's AI needs to follow careful long-term or multi-step schemes that necessitates storing complex state, in which case a state machine or even better a Behavior Tree is needed. Most suitable for small-scale RTS games where the less numerous Actors make up for it with much more complex and believable AI.
     
    rawna and exiguous like this.
  2. Abbrew

    Abbrew

    Joined:
    Jan 1, 2018
    Posts:
    417
    Here's a code dump of the singular parallelized Decision job, and the trick I used to get a parallel job to use NavMeshQuery. CritterInteractionInterface contains all the NativeQueue.ParallelWriter for interactions between Actors


    Code (CSharp):
    1.  
    2.     [UpdateAfter(typeof(PlayerMarionetteSystem))]
    3.     [UpdateInGroup(typeof(CollapseJobSystemGroup))]
    4.     [BurstCompile]
    5.     public partial struct CritterSystem : ISystem
    6.     {
    7.         private EnvironmentComponent _environment;
    8.  
    9.         private NativeArray<CritterPathFinder> _pathfinders;
    10.         private NavMeshQuery _navMeshQuery;
    11.  
    12.         private CritterInteractionInterface _interactions;
    13.  
    14.         [BurstCompile]
    15.         public void OnUpdate(ref SystemState state)
    16.         {
    17.             var world = state.WorldUnmanaged;
    18.             var playerMarionette = world.GetSystem<PlayerMarionetteSystem>();
    19.  
    20.             new CritterControlJob
    21.             {
    22.                 ViewDirection = playerMarionette.ViewDirection,
    23.                 OrderedToBeginRun = playerMarionette.OrderedToBeginRun,
    24.                 OrderedToContinueRun = playerMarionette.OrderedToContinueRun,
    25.                 RunDirection = playerMarionette.RunDirection,
    26.                 OrderedToMeleeAttack = playerMarionette.OrderedToMeleeAttack,
    27.                 OrderedToMeleeAttackWhileRunning = playerMarionette.OrderedToMeleeAttackWhileRunning,
    28.                 OrderedToDodge = playerMarionette.OrderedToDodge,
    29.                 OrderedToShove = playerMarionette.OrderedToShove,
    30.                 OrderedToShoveWhileRunning = playerMarionette.OrderedToShoveWhileRunning,
    31.                 OrderedToToggleMoveFormation = playerMarionette.OrderedToToggleMoveFormation,
    32.                 OrderedToRally = playerMarionette.OrderedToRally,
    33.                 OrderedToFlinchBreaker = playerMarionette.OrderedToFlinchBreaker,
    34.                 DeltaSeconds = SystemAPI.Time.DeltaTime,
    35.                 Interactions = _interactions
    36.             }.Schedule();
    37.  
    38.             new CritterBehaviorJob
    39.             {
    40.                 DeltaSeconds = SystemAPI.Time.DeltaTime,
    41.                 ElapsedSeconds = SystemAPI.Time.ElapsedTime,
    42.                 AppearanceTransforms = SystemAPI.GetSingletonBuffer<AppearanceTransformElement>(),
    43.                 AppearanceCumulativeIndices = SystemAPI.GetSingletonBuffer<AppearanceCumulativeIndexElement>(),
    44.                 Environment = _environment,
    45.                 TacticalPlaces = SystemAPI.GetSingletonBuffer<TacticalGeographyPlaceElement>(true),
    46.                 Proximities = SystemAPI.GetSingleton<CritterProximityGridComponent>().Data,
    47.                 Pathfinders = _pathfinders,
    48.                 NavMeshQuery = _navMeshQuery,
    49.                 CollisionWorld = SystemAPI.GetSingleton<PhysicsWorldSingleton>().PhysicsWorld.CollisionWorld,
    50.                 Interactions = _interactions
    51.             }.ScheduleParallel();
    52.  
    53.             NavMeshWorld.GetDefaultWorld().AddDependency(state.Dependency);
    54.         }
    55.  
    56.         [WithAll(typeof(CritterPlayerComponent))]
    57.         [BurstCompile]
    58.         private partial struct CritterControlJob : IJobEntity
    59.         {
    60.             public float2 ViewDirection;
    61.  
    62.             public bool OrderedToBeginRun;
    63.             public bool OrderedToContinueRun;
    64.             public float2 RunDirection;
    65.  
    66.             public bool OrderedToMeleeAttack;
    67.             public bool OrderedToMeleeAttackWhileRunning;
    68.  
    69.             public bool OrderedToDodge;
    70.  
    71.             public bool OrderedToShove;
    72.             public bool OrderedToShoveWhileRunning;
    73.  
    74.             public bool OrderedToToggleMoveFormation;
    75.  
    76.             public bool OrderedToRally;
    77.             public bool OrderedToFlinchBreaker;
    78.  
    79.             public float DeltaSeconds;
    80.  
    81.             [WriteOnly]
    82.             public CritterInteractionInterface Interactions;
    83.  
    84.             public void Execute(
    85.                 Entity critter,
    86.                 in LocalTransform transform,
    87.                 ref CritterStateComponent state,
    88.                 in CritterActionComponent action,
    89.                 ref CritterTimeRequiredComponent timeRequired,
    90.                 ref CritterPlayerOrderComponent orders,
    91.                 // Face Constantly
    92.                 ref CritterDurationFaceConstantlyConfigurationComponent durationFaceConstantlyConfig,
    93.                 // Formation Leader
    94.                 in CritterFormationFollowerComponent followerComponent,
    95.                 in DynamicBuffer<CritterFormationLeaderFollowerElement> followers
    96.             )
    97.             {
    98.                 #region Injected Configurations
    99.  
    100.                 CritterDurationFaceConstantlyActions.AdjustAt(
    101.                     ref durationFaceConstantlyConfig,
    102.                     orders.ViewDirection
    103.                 );
    104.  
    105.                 #endregion
    106.  
    107.                 #region Orders
    108.  
    109.                 var currentlyIdle =
    110.                     CritterActions.IsDoing(action, CritterAction.PlanIdle)
    111.                     & !CritterActions.IsDoing(action, CritterAction.DurationRun);
    112.                 var currentlyRunning = CritterActions.IsDoing(action, CritterAction.DurationRun);
    113.                 var currentlyMeleeAttacking = CritterActions.IsDoing(action, CritterAction.PlanMeleeAttack);
    114.  
    115.                 var orderedOtherThanRun =
    116.                     OrderedToMeleeAttack
    117.                     | OrderedToMeleeAttackWhileRunning;
    118.  
    119.                 orders.ViewDirection = ViewDirection;
    120.  
    121.                 var orderedToBeginRunDueToPendingContinueRun =
    122.                     OrderedToContinueRun
    123.                     & !orderedOtherThanRun
    124.                     & currentlyIdle;
    125.  
    126.                 orders.OrderedToBeginRun = OrderedToBeginRun
    127.                     | orderedToBeginRunDueToPendingContinueRun;
    128.  
    129.                 orders.OrderedToContinueRun =
    130.                     OrderedToContinueRun
    131.                     & currentlyRunning
    132.                     & !orderedToBeginRunDueToPendingContinueRun
    133.                     & !currentlyMeleeAttacking;
    134.  
    135.                 orders.RunDirection = RunDirection;
    136.  
    137.                 orders.OrderedToMeleeAttack = OrderedToMeleeAttack;
    138.                 orders.OrderedToMeleeAttackWhileRunning = OrderedToMeleeAttackWhileRunning;
    139.  
    140.                 orders.OrderedToDodge = OrderedToDodge;
    141.  
    142.                 orders.OrderedToShove =
    143.                     OrderedToShove
    144.                     & state.Command >= state.ShoveCommandCost;
    145.                 orders.OrderedToShoveWhileRunning =
    146.                     OrderedToShoveWhileRunning
    147.                     & state.Command >= state.ShoveCommandCost;
    148.  
    149.                 orders.OrderedToRally =
    150.                     OrderedToRally
    151.                     & state.Command >= state.RallyCommandCost;
    152.  
    153.                 orders.OrderedToFlinchBreaker =
    154.                     OrderedToFlinchBreaker
    155.                     & state.IsFlinching
    156.                     & state.Command >= state.FlinchBreakerCommandCost;
    157.  
    158.                 if (Hint.Unlikely(OrderedToToggleMoveFormation))
    159.                 {
    160.                     orders.OrderedToMoveFormation = !orders.OrderedToMoveFormation;
    161.                 }
    162.  
    163.                 state.CanVoluntarilyAct |= orders.OrderedToFlinchBreaker;
    164.  
    165.                 var orderedExplicitly =
    166.                     orders.OrderedToBeginRun
    167.                     | orders.OrderedToContinueRun
    168.                     | orders.OrderedToMeleeAttack
    169.                     | orders.OrderedToMeleeAttackWhileRunning
    170.                     | orders.OrderedToShove
    171.                     | orders.OrderedToShoveWhileRunning
    172.                     | orders.OrderedToFlinchBreaker
    173.                     | orders.OrderedToRally
    174.                     | orders.OrderedToDodge;
    175.  
    176.                 if (Hint.Unlikely(state.CanVoluntarilyAct & orderedExplicitly))
    177.                 {
    178.                     CritterActions.Restart(ref timeRequired);
    179.                 }
    180.  
    181.                 #endregion
    182.             }
    183.         }
    184.  
    185.         public void Initialize(ref SystemState state)
    186.         {
    187.             _environment = SystemAPI.GetSingleton<EnvironmentComponent>();
    188.  
    189.             var numThreads = JobsUtility.ThreadIndexCount;
    190.             _pathfinders = new NativeArray<CritterPathFinder>(numThreads, Allocator.Persistent);
    191.             for (var i = 0; i < numThreads; i++)
    192.             {
    193.                 _pathfinders[i] = new CritterPathFinder(_environment, Allocator.Persistent);
    194.             }
    195.  
    196.             _navMeshQuery = _environment.CreateNavMeshQuery();
    197.  
    198.             _interactions = state.WorldUnmanaged.GetSystem<CritterInteractionSystem>().Interface;
    199.         }
    200.  
    201.         public void OnDestroy(ref SystemState state)
    202.         {
    203.             foreach (var pathfinder in _pathfinders)
    204.             {
    205.                 pathfinder.Dispose();
    206.             }
    207.             _pathfinders.Dispose();
    208.  
    209.             _navMeshQuery.Dispose();
    210.         }
    211.     }
    212.  
    213.     [WithOptions(EntityQueryOptions.IgnoreComponentEnabledState)]
    214.     [BurstCompile]
    215.     public partial struct CritterBehaviorJob : IJobEntity
    216.     {
    217.         public float DeltaSeconds;
    218.  
    219.         public double ElapsedSeconds;
    220.  
    221.         [NativeSetThreadIndex]
    222.         public int ThreadIndex;
    223.  
    224.         [NativeDisableParallelForRestriction]
    225.         [WriteOnly]
    226.         public DynamicBuffer<AppearanceTransformElement> AppearanceTransforms;
    227.         [ReadOnly]
    228.         public DynamicBuffer<AppearanceCumulativeIndexElement> AppearanceCumulativeIndices;
    229.  
    230.         public EnvironmentComponent Environment;
    231.  
    232.         [ReadOnly]
    233.         public CollisionWorld CollisionWorld;
    234.  
    235.         [ReadOnly]
    236.         public DynamicBuffer<TacticalGeographyPlaceElement> TacticalPlaces;
    237.  
    238.         [ReadOnly]
    239.         public CritterProximityGrid Proximities;
    240.  
    241.         [NativeDisableParallelForRestriction]
    242.         [NativeDisableContainerSafetyRestriction]
    243.         public NativeArray<CritterPathFinder> Pathfinders;
    244.  
    245.         [ReadOnly]
    246.         public NavMeshQuery NavMeshQuery;
    247.  
    248.         [WriteOnly]
    249.         public CritterInteractionInterface Interactions;
    250.  
    251.         public void Execute(
    252.             // Critter
    253.             Entity critter,
    254.             ref LocalTransform transform,
    255.             ref CritterTimePassedComponent timePassed,
    256.             ref CritterTimeRequiredComponent timeRequired,
    257.             ref CritterPlayerOrderComponent orders,
    258.             ref CritterStateComponent state,
    259.             ref CritterActionComponent action,
    260.             ref CritterEventsRuntimeComponent eventsRuntime,
    261.             ref CritterTriggerComponent triggers,
    262.             // Diplomacy
    263.             in DiplomacySideComponent diplomacy,
    264.             // Appearance
    265.             in DynamicBuffer<CritterPartBodyElement> bodyParts,
    266.             in CritterPartBodyIdentifierPortalComponent identifierPortalPart,
    267.             in DynamicBuffer<CritterPartFormationVisualizerElement> formationVisualizerParts,
    268.             // Animation  
    269.             EnabledRefRW<AnimationPlayComponent> playToggle,
    270.             ref AnimationPlayClipComponent clip,
    271.             EnabledRefRW<AnimationAdjustComponent> adjustToggle,
    272.             ref AnimationAdjustSpeedComponent adjust,
    273.             // Formation
    274.             in DynamicBuffer<CritterFormationLeaderFollowerElement> formationFollowers,
    275.             in CritterFormationFollowerComponent formationFollower,
    276.             // Idle
    277.             // Melee Attack
    278.             ref CritterPlanMeleeAttackConfigurationComponent planMeleeAttackConfig,
    279.             ref CritterPlanMeleeAttackRuntimeComponent planMeleeAttackRuntime,
    280.             ref DynamicBuffer<CritterPlanMeleeAttackEventsTimestampElement> planMeleeAttackEventsTimestamps,
    281.             ref DynamicBuffer<CritterPlanMeleeAttackEventsRuntimeTimestampElement> planMeleeAttackRuntimeTimestamps,
    282.             // Dodge
    283.             ref DynamicBuffer<CritterPlanDodgeEventsTimestampElement> planDodgeEventsTimestamps,
    284.             ref DynamicBuffer<CritterPlanDodgeEventsRuntimeTimestampElement> planDodgeRuntimeTimestamps,
    285.             // Follow Path
    286.             ref CritterPlanFollowPathConfigurationComponent planFollowPathConfig,
    287.             ref CritterPlanFollowPathRuntimeComponent planFollowPathRuntime,
    288.             ref DynamicBuffer<CritterPlanFollowPathRuntimeWaypointElement> planFollowPathWaypoints,
    289.             // Lead Followers
    290.             // Face Constantly
    291.             ref CritterDurationFaceConstantlyConfigurationComponent durationFaceConstantlyConfig,
    292.             // Run
    293.             ref CritterDurationRunConfigurationComponent durationRunConfig,
    294.             ref CritterDurationRunRuntimeComponent durationRunRuntime,
    295.             // Canceler Enemies In Range
    296.             ref CritterCancelerCritterInRangeConfigurationComponent cancelerCritterInRangeConfig,
    297.             // Canceler If Ping Dodge
    298.             ref CritterCancelerIfPingDodgeConfigurationComponent cancelerIfPingDodgeConfig,
    299.             // Canceler Melee Enemy Is Dodging
    300.             ref CritterCancelerMeleeEnemyIsDodgingConfigurationComponent cancelerMeleeEnemyIsDodgingConfig,
    301.             // Canceler After Time PAssed
    302.             ref CritterCancelerAfterTimeConfigurationComponent cancelerAfterTimeConfig
    303.         )
    304.         {
    305.             #region Appearance
    306.  
    307.             #region Body Parts
    308.  
    309.             foreach (var bodyPart in bodyParts.AsNativeArray())
    310.             {
    311.                 var index = AppearanceCumulativeIndices[bodyPart.Part.PrototypeIndex].Value + bodyPart.Part.InstanceIndex;
    312.                 AppearanceTransforms[index] = new AppearanceTransformElement
    313.                 {
    314.                     Value = transform.ToMatrix()
    315.                 };
    316.             }
    317.  
    318.             #endregion
    319.  
    320.             #region Identifier Portal
    321.  
    322.             if (Hint.Likely(identifierPortalPart.Visible && !state.Dead))
    323.             {
    324.                 var index = AppearanceCumulativeIndices[identifierPortalPart.Part.PrototypeIndex].Value + identifierPortalPart.Part.InstanceIndex;
    325.                 AppearanceTransforms[index] = new AppearanceTransformElement
    326.                 {
    327.                     Value = transform.ToMatrix()
    328.                 };
    329.             }
    330.             else
    331.             {
    332.                 var index = AppearanceCumulativeIndices[identifierPortalPart.Part.PrototypeIndex].Value + identifierPortalPart.Part.InstanceIndex;
    333.                 AppearanceTransforms[index] = new AppearanceTransformElement
    334.                 {
    335.                     Value = float4x4.zero
    336.                 };
    337.             }
    338.  
    339.             #endregion
    340.  
    341.             #region Formation
    342.  
    343.             var numVisualizerParts = formationVisualizerParts.Length;
    344.             var followerRanks = new NativeList<float2>(Allocator.Temp);
    345.             CritterFormationActions.CreateRanks(formationFollower, followerRanks);
    346.             var followerRanksFast = followerRanks.AsArray();
    347.             var numRanks = followerRanks.Length;
    348.  
    349.             var numPartsToVisualize = math.min(numVisualizerParts, numRanks);
    350.  
    351.             var formationTransform = formationFollower.OfficerTransform;
    352.  
    353.             var visualizerPartsFast = formationVisualizerParts.AsNativeArray();
    354.  
    355.             for (var i = 0; i < numPartsToVisualize; i++)
    356.             {
    357.                 var part = visualizerPartsFast[i];
    358.                 var index = AppearanceCumulativeIndices[part.Part.PrototypeIndex].Value + part.Part.InstanceIndex;
    359.  
    360.                 var rankFormationLocation = followerRanksFast[i];
    361.                 var rankLocation = formationTransform.TransformPoint(rankFormationLocation.WithY()).RemoveY();
    362.                 EnvironmentQueries.WalkableHeightAt(Environment, CollisionWorld, rankLocation, out var raycastHit);
    363.                 var rankHeight = raycastHit.Position.y;
    364.                 var rankPosition = rankLocation.WithY(rankHeight);
    365.  
    366.                 AppearanceTransforms[index] = new AppearanceTransformElement
    367.                 {
    368.                     Value = formationTransform.WithPosition(rankPosition).ToMatrix()
    369.                 };
    370.             }
    371.  
    372.             for (var i = numPartsToVisualize; i < numVisualizerParts; i++)
    373.             {
    374.                 var part = visualizerPartsFast[i];
    375.                 var index = AppearanceCumulativeIndices[part.Part.PrototypeIndex].Value + part.Part.InstanceIndex;
    376.  
    377.                 AppearanceTransforms[index] = new AppearanceTransformElement
    378.                 {
    379.                     Value = float4x4.zero
    380.                 };
    381.             }
    382.  
    383.             #endregion
    384.  
    385.             #endregion
    386.  
    387.             #region Always
    388.  
    389.             if (Hint.Unlikely(state.IsOrderable & orders.OrderedToMoveFormation))
    390.             {
    391.                 ExecuteDurationLeadFollowers(
    392.                     critter,
    393.                     in transform,
    394.                     in formationFollower,
    395.                     in formationFollowers
    396.                 );
    397.             }
    398.  
    399.             #endregion
    400.  
    401.             #region Evaluation
    402.  
    403.             var random = this.Random(critter, ElapsedSeconds);
    404.  
    405.             if (Hint.Unlikely(timePassed.Seconds > timeRequired.Seconds))
    406.             {
    407.                 #region Mortality
    408.  
    409.                 if (Hint.Unlikely(state.Dead))
    410.                 {
    411.                     PrepareForPlan(
    412.                        ref action,
    413.                        ref state,
    414.                        ref timePassed,
    415.                        ref triggers
    416.                    );
    417.  
    418.                     ActivatePlanIdleDead(
    419.                         ref state,
    420.                         ref action,
    421.                         ref timeRequired,
    422.                         playToggle,
    423.                         ref clip,
    424.                         state.DeadPoseDuration
    425.                     );
    426.  
    427.                     goto execution;
    428.                 }
    429.  
    430.                 if (Hint.Unlikely(state.Health <= 0))
    431.                 {
    432.                     PrepareForPlan(
    433.                         ref action,
    434.                         ref state,
    435.                         ref timePassed,
    436.                         ref triggers
    437.                     );
    438.  
    439.                     ActivatePlanIdleDying(
    440.                         ref state,
    441.                         ref action,
    442.                         ref timeRequired,
    443.                         state.DyingDuration,
    444.                         playToggle,
    445.                         ref clip
    446.                     );
    447.  
    448.                     goto execution;
    449.                 }
    450.  
    451.  
    452.                 #endregion
    453.  
    454.                 #region Triggers
    455.  
    456.                 if (Hint.Unlikely(Triggered(triggers)))
    457.                 {
    458.                     var trigger = triggers.Data;
    459.  
    460.                     Reset(ref triggers);
    461.  
    462.                     if (trigger == CritterTrigger.Flinch)
    463.                     {
    464.                         PrepareForPlan(
    465.                             ref action,
    466.                             ref state,
    467.                             ref timePassed,
    468.                             ref triggers
    469.                         );
    470.  
    471.                         ActivatePlanFlinch(
    472.                             ref action,
    473.                             ref state,
    474.                             ref timeRequired,
    475.                             state.FlinchDuration,
    476.                             playToggle,
    477.                             ref clip,
    478.                             state.FlinchDuration
    479.                         );
    480.  
    481.                         goto execution;
    482.                     }
    483.  
    484.                     if (trigger == CritterTrigger.Knockback)
    485.                     {
    486.                         PrepareForPlan(
    487.                             ref action,
    488.                             ref state,
    489.                             ref timePassed,
    490.                             ref triggers
    491.                         );
    492.  
    493.                         ActivatePlanIdleKnockback(
    494.                             ref state,
    495.                             ref action,
    496.                             ref timeRequired,
    497.                             state.KnockbackDuration,
    498.                             playToggle,
    499.                             ref clip,
    500.                             state.KnockbackDuration
    501.                         );
    502.  
    503.                         ActivateDurationRunKnockback(
    504.                             transform,
    505.                             ref action,
    506.                             ref durationRunConfig,
    507.                             state.KnockbackSpeed,
    508.                             state.KnockbackSpeedRecurve,
    509.                             ref durationRunRuntime
    510.                         );
    511.  
    512.                         goto execution;
    513.                     }
    514.  
    515.                     if (trigger == CritterTrigger.Dodge)
    516.                     {
    517.                         PositionActions.RotateTo(
    518.                             ref transform,
    519.                             state.TriggerDodgeDirection
    520.                         );
    521.  
    522.                         PrepareForPlan(
    523.                             ref action,
    524.                             ref state,
    525.                             ref timePassed,
    526.                             ref triggers
    527.                         );
    528.  
    529.                         ActivatePlanDodge(
    530.                             ref action,
    531.                             ref eventsRuntime,
    532.                             ref timeRequired,
    533.                             state.DodgeInvulnerableLag,
    534.                             state.DodgeVulnerableLag,
    535.                             state.DodgeEndLag,
    536.                             ref planDodgeRuntimeTimestamps,
    537.                             playToggle,
    538.                             ref clip
    539.                         );
    540.  
    541.                         goto execution;
    542.                     }
    543.                 }
    544.  
    545.                 #endregion
    546.  
    547.                 #region Player
    548.  
    549.                 if (Hint.Unlikely(state.IsOrderable))
    550.                 {
    551.                     #region MeleeAttack
    552.  
    553.                     if (orders.OrderedToMeleeAttack)
    554.                     {
    555.                         PrepareForPlan(
    556.                             ref action,
    557.                             ref state,
    558.                             ref timePassed,
    559.                             ref triggers
    560.                         );
    561.  
    562.                         ActivatePlanMeleeAttackStrike(
    563.                             ref action,
    564.                             ref eventsRuntime,
    565.                             ref timeRequired,
    566.                             ref planMeleeAttackConfig,
    567.                             state.MeleeAttackDamage,
    568.                             state.MeleeAttackRange,
    569.                             state.MeleeAttackArc,
    570.                             state.MeleeTelegraphLag,
    571.                             state.MeleeCommitmentLag,
    572.                             state.MeleeStrikeLag,
    573.                             state.MeleeEndLag,
    574.                             ref planMeleeAttackRuntime,
    575.                             ref planMeleeAttackRuntimeTimestamps,
    576.                             playToggle,
    577.                             ref clip
    578.                         );
    579.  
    580.                         ActivateDurationFaceConstantlyAt(
    581.                             ref action,
    582.                             ref durationFaceConstantlyConfig
    583.                         );
    584.  
    585.                         goto execution;
    586.                     }
    587.  
    588.                     #endregion
    589.  
    590.                     #region MeleeAttackWhileRunning
    591.  
    592.                     if (orders.OrderedToMeleeAttackWhileRunning)
    593.                     {
    594.                         if (Hint.Unlikely(CritterSearchActions.FindNearbyEnemiesVulnerable(
    595.                             Proximities,
    596.                             critter,
    597.                             diplomacy.Data,
    598.                             transform.Location().Forward(state.MeleeAttackRange, transform.Rotation),
    599.                             state.MeleeAttackRange,
    600.                             out var enemiesInMeleeRange
    601.                         )))
    602.                         {
    603.                             #region Chasedown Attack
    604.  
    605.                             enemiesInMeleeRange.OrderedByClosestTo(transform.Location());
    606.  
    607.                             foreach (var enemyInMeleeRange in enemiesInMeleeRange)
    608.                             {
    609.                                 // Enemy is routing
    610.                                 if (Hint.Likely(enemyInMeleeRange.Routing))
    611.                                 {
    612.                                     PrepareForPlan(
    613.                                         ref action,
    614.                                         ref state,
    615.                                         ref timePassed,
    616.                                         ref triggers
    617.                                     );
    618.  
    619.                                     ActivatePlanMeleeAttackStrike(
    620.                                         ref action,
    621.                                         ref eventsRuntime,
    622.                                         ref timeRequired,
    623.                                         state.ChasedownDuration,
    624.                                         ref planMeleeAttackConfig,
    625.                                         state.MeleeAttackDamage,
    626.                                         state.MeleeAttackRange,
    627.                                         state.MeleeAttackArc,
    628.                                         ref planMeleeAttackRuntime,
    629.                                         ref planMeleeAttackRuntimeTimestamps,
    630.                                         playToggle,
    631.                                         ref clip
    632.                                     );
    633.  
    634.                                     var directionOfEnemy =
    635.                                         enemyInMeleeRange.Location
    636.                                         - transform.Location();
    637.  
    638.                                     ActivateDurationRun(
    639.                                         ref action,
    640.                                         ref durationRunConfig,
    641.                                         state.ChasedownAttackMoveSpeed,
    642.                                         state.ChasedownSpeedRecurve,
    643.                                         directionOfEnemy,
    644.                                         ref durationRunRuntime
    645.                                     );
    646.  
    647.                                     ActivateDurationFaceConstantlyTowards(
    648.                                         ref action,
    649.                                         ref durationFaceConstantlyConfig,
    650.                                         enemyInMeleeRange.Entity
    651.                                     );
    652.  
    653.                                     goto execution;
    654.                                 }
    655.                             }
    656.  
    657.                             #endregion
    658.                         }
    659.  
    660.                         #region Directioned Attack
    661.  
    662.                         PrepareForPlan(
    663.                             ref action,
    664.                             ref state,
    665.                             ref timePassed,
    666.                             ref triggers
    667.                         );
    668.  
    669.                         ActivatePlanMeleeAttackStrike(
    670.                             ref action,
    671.                             ref eventsRuntime,
    672.                             ref timeRequired,
    673.                             ref planMeleeAttackConfig,
    674.                             state.MeleeAttackDamage,
    675.                             state.MeleeAttackRange,
    676.                             state.MeleeAttackArc,
    677.                             state.MeleeTelegraphLag,
    678.                             state.MeleeCommitmentLag,
    679.                             state.MeleeStrikeLag,
    680.                             state.MeleeEndLag,
    681.                             ref planMeleeAttackRuntime,
    682.                             ref planMeleeAttackRuntimeTimestamps,
    683.                             playToggle,
    684.                             ref clip
    685.                         );
    686.  
    687.                         goto execution;
    688.  
    689.                         #endregion
    690.                     }
    691.  
    692.                     #endregion
    693.  
    694.                     #region Dodge
    695.  
    696.                     if (orders.OrderedToDodge)
    697.                     {
    698.                         PrepareForPlan(
    699.                             ref action,
    700.                             ref state,
    701.                             ref timePassed,
    702.                             ref triggers
    703.                         );
    704.  
    705.                         ActivatePlanDodge(
    706.                             ref action,
    707.                             ref eventsRuntime,
    708.                             ref timeRequired,
    709.                             state.DodgeInvulnerableLag,
    710.                             state.DodgeVulnerableLag,
    711.                             state.DodgeEndLag,
    712.                             ref planDodgeRuntimeTimestamps,
    713.                             playToggle,
    714.                             ref clip
    715.                         );
    716.  
    717.                         goto execution;
    718.                     }
    719.  
    720.                     #endregion
    721.  
    722.                     #region Shove
    723.  
    724.                     if (orders.OrderedToShove)
    725.                     {
    726.                         PrepareForPlan(
    727.                             ref action,
    728.                             ref state,
    729.                             ref timePassed,
    730.                             ref triggers
    731.                         );
    732.  
    733.                         ActivatePlanMeleeAttackShove(
    734.                             ref action,
    735.                             ref eventsRuntime,
    736.                             ref timeRequired,
    737.                             state.ShoveDuration,
    738.                             ref planMeleeAttackConfig,
    739.                             state.MeleeAttackDamage,
    740.                             state.MeleeAttackRange,
    741.                             state.MeleeAttackArc,
    742.                             ref planMeleeAttackRuntime,
    743.                             ref planMeleeAttackRuntimeTimestamps,
    744.                             playToggle,
    745.                             ref clip
    746.                         );
    747.  
    748.                         ActivateDurationFaceConstantlyAt(
    749.                             ref action,
    750.                             ref durationFaceConstantlyConfig
    751.                         );
    752.  
    753.                         goto execution;
    754.                     }
    755.  
    756.                     #endregion
    757.  
    758.                     #region ShoveWhileRunning
    759.  
    760.                     if (orders.OrderedToShoveWhileRunning)
    761.                     {
    762.                         PrepareForPlan(
    763.                             ref action,
    764.                             ref state,
    765.                             ref timePassed,
    766.                             ref triggers
    767.                         );
    768.  
    769.                         ActivatePlanMeleeAttackShove(
    770.                             ref action,
    771.                             ref eventsRuntime,
    772.                             ref timeRequired,
    773.                             state.ShoveDuration,
    774.                             ref planMeleeAttackConfig,
    775.                             state.MeleeAttackDamage,
    776.                             state.MeleeAttackRange,
    777.                             state.MeleeAttackArc,
    778.                             ref planMeleeAttackRuntime,
    779.                             ref planMeleeAttackRuntimeTimestamps,
    780.                             playToggle,
    781.                             ref clip
    782.                         );
    783.  
    784.                         goto execution;
    785.                     }
    786.  
    787.                     #endregion
    788.  
    789.                     #region Rally
    790.  
    791.                     if (orders.OrderedToRally)
    792.                     {
    793.                         PrepareForPlan(
    794.                             ref action,
    795.                             ref state,
    796.                             ref timePassed,
    797.                             ref triggers
    798.                         );
    799.  
    800.                         ActivatePlanIdleRally(
    801.                             critter,
    802.                             transform,
    803.                             ref state,
    804.                             ref action,
    805.                             ref timeRequired,
    806.                             state.RallyDuration,
    807.                             state.RallyCommandCost,
    808.                             state.RallyAllyBuffAmount,
    809.                             state.RallyAllyBuffRadius,
    810.                             state.RallyEnemyDebuffAmount,
    811.                             state.RallyEnemyDebuffRadius,
    812.                             diplomacy.Data,
    813.                             playToggle,
    814.                             ref clip
    815.                         );
    816.  
    817.                         goto execution;
    818.                     }
    819.  
    820.                     #endregion
    821.  
    822.                     #region FlinchBreaker
    823.  
    824.                     if (orders.OrderedToFlinchBreaker)
    825.                     {
    826.                         PrepareForPlan(
    827.                             ref action,
    828.                             ref state,
    829.                             ref timePassed,
    830.                             ref triggers
    831.                         );
    832.  
    833.                         ActivateIdleFlinchBreaker(
    834.                             critter,
    835.                             transform,
    836.                             ref state,
    837.                             ref action,
    838.                             ref timeRequired,
    839.                             state.FlinchBreakerDuration,
    840.                             state.FlinchBreakerRange,
    841.                             diplomacy.Data,
    842.                             playToggle,
    843.                             ref clip
    844.                         );
    845.                     }
    846.  
    847.                     #endregion
    848.  
    849.                     #region ContinueRun
    850.  
    851.                     if (orders.OrderedToContinueRun)
    852.                     {
    853.                         AdjustDurationRun(
    854.                             ref durationRunConfig,
    855.                             orders.RunDirection,
    856.                             ref durationRunRuntime,
    857.                             playToggle,
    858.                             ref clip,
    859.                             state.RunStrideDuration
    860.                         );
    861.  
    862.                         PositionActions.RotateTo(
    863.                             ref transform,
    864.                             orders.RunDirection
    865.                         );
    866.  
    867.                         ToggleDurationLeadFollowers(
    868.                             ref action,
    869.                             orders.OrderedToMoveFormation
    870.                         );
    871.  
    872.                         goto execution;
    873.                     }
    874.  
    875.                     #endregion
    876.  
    877.                     #region BeginRun
    878.  
    879.                     if (orders.OrderedToBeginRun)
    880.                     {
    881.                         PrepareForPlan(
    882.                             ref action,
    883.                             ref state,
    884.                             ref timePassed,
    885.                             ref triggers
    886.                         );
    887.  
    888.                         ActivatePlanIdleRun(
    889.                             ref action,
    890.                             ref timeRequired,
    891.                             playToggle,
    892.                             ref clip,
    893.                             state.RunStrideDuration
    894.                         );
    895.  
    896.                         ActivateDurationRun(
    897.                             ref action,
    898.                             ref durationRunConfig,
    899.                             state.RunSpeed,
    900.                             state.RunSpeedRecurve,
    901.                             orders.RunDirection,
    902.                             ref durationRunRuntime
    903.                         );
    904.  
    905.                         PositionActions.RotateTo(
    906.                             ref transform,
    907.                             orders.RunDirection
    908.                         );
    909.  
    910.                         ToggleDurationLeadFollowers(
    911.                             ref action,
    912.                             orders.OrderedToMoveFormation
    913.                         );
    914.  
    915.                         goto execution;
    916.                     }
    917.  
    918.                     #endregion
    919.  
    920.                     #region Idle
    921.  
    922.                     {
    923.                         PrepareForPlan(
    924.                             ref action,
    925.                             ref state,
    926.                             ref timePassed,
    927.                             ref triggers
    928.                         );
    929.  
    930.                         ActivatePlanIdleDillyDally(
    931.                             ref action,
    932.                             ref timeRequired,
    933.                             playToggle,
    934.                             ref clip,
    935.                             state.IdleDillyDallyDuration
    936.                         );
    937.  
    938.                         ActivateDurationFaceConstantlyAt(
    939.                             ref action,
    940.                             ref durationFaceConstantlyConfig
    941.                         );
    942.  
    943.                         goto execution;
    944.                     }
    945.  
    946.                     #endregion
    947.                 }
    948.  
    949.                 #endregion
    950.  
    951.                 #region AI
    952.  
    953.                 else
    954.                 {
    955.                     #region Rout/Traumatized If Panicked, Or Stop Rout If Far Away Enough
    956.  
    957.                     #region Check If Panicking
    958.  
    959.                     if (Hint.Likely(!state.Routing && !state.Traumatized))
    960.                     {
    961.                         var panic = 0f;
    962.  
    963.                         #region Outnumbered
    964.  
    965.                         CritterSearchActions.FindNearbyAllies(
    966.                             Proximities,
    967.                             critter,
    968.                             diplomacy.Data,
    969.                             transform.Location(),
    970.                             state.RoutPanicOutnumberedCheckRadius,
    971.                             out var outnumberingAllies
    972.                         );
    973.  
    974.                         CritterSearchActions.FindNearbyEnemies(
    975.                             Proximities,
    976.                             critter,
    977.                             diplomacy.Data,
    978.                             transform.Location(),
    979.                             state.RoutPanicOutnumberedCheckRadius,
    980.                             out var outnumberingEnemies
    981.                         );
    982.  
    983.                         panic +=
    984.                             (outnumberingEnemies.Length - outnumberingAllies.Length)
    985.                             * state.RoutPanicPerOutnumbered;
    986.  
    987.                         #endregion
    988.  
    989.                         if (Hint.Unlikely(panic > state.RoutPanicThreshold))
    990.                         {
    991.                             state.Routing =
    992.                                 !TacticalPlaces.GetOccupiedTacticalPlaceAt(
    993.                                     diplomacy.Data,
    994.                                     transform.Location(),
    995.                                     out var _
    996.                                 )
    997.                                 & TacticalPlaces.FindSuitableTacticalPlaceAt(
    998.                                     diplomacy.Data,
    999.                                     transform.Location(),
    1000.                                     out var suitablePlaceIndex
    1001.                                 );
    1002.  
    1003.                             state.RoutingPlaceIndex = suitablePlaceIndex;
    1004.  
    1005.                             state.Traumatized = !state.Routing;
    1006.                         }
    1007.                     }
    1008.  
    1009.                     #endregion
    1010.  
    1011.                     #region Rout If Possible, Traumatized Otherwise
    1012.  
    1013.                     if (Hint.Unlikely(state.Routing))
    1014.                     {
    1015.                         if(Hint.Unlikely(
    1016.                             !CritterSearchActions.FindNearbyEnemies(
    1017.                                 Proximities,
    1018.                                 critter,
    1019.                                 diplomacy.Data,
    1020.                                 transform.Location(),
    1021.                                 state.RoutSafetyRadius,
    1022.                                 out var _
    1023.                             )
    1024.                         ))
    1025.                         {
    1026.                             #region Stop Routing Because No Enemies Nearby
    1027.  
    1028.                             state.Routing = false;
    1029.  
    1030.                             #endregion
    1031.                         }
    1032.                         else
    1033.                         {
    1034.                             #region Attempt To Rout To Nearest Safe Place
    1035.  
    1036.                             if (Hint.Likely(
    1037.                                 // Path is available
    1038.                                 Pathfinders[ThreadIndex].Calculate(
    1039.                                     transform.Location(),
    1040.                                     TacticalPlaces[state.RoutingPlaceIndex].Location,
    1041.                                     out var numWaypoints,
    1042.                                     out var waypoints,
    1043.                                     out var initialDirection
    1044.                                 )
    1045.                                 // No enemies initially blocking the direction
    1046.                                 & !CritterSearchActions.FindNearbyEnemies(
    1047.                                     Proximities,
    1048.                                     critter,
    1049.                                     diplomacy.Data,
    1050.                                     transform.Location() + initialDirection.WithLength(state.BlockedForwardRadius),
    1051.                                     state.BlockedForwardRadius,
    1052.                                     out var _
    1053.                                 ))
    1054.                             )
    1055.                             {
    1056.                                 #region Continue Routing
    1057.  
    1058.                                 PrepareForPlan(
    1059.                                     ref action,
    1060.                                     ref state,
    1061.                                     ref timePassed,
    1062.                                     ref triggers
    1063.                                 );
    1064.  
    1065.                                 ActivatePlanFollowPath(
    1066.                                     ref action,
    1067.                                     ref state,
    1068.                                     ref timePassed,
    1069.                                     ref timeRequired,
    1070.                                     ref planFollowPathConfig,
    1071.                                     state.RoutSpeed,
    1072.                                     state.RoutSpeedRecurve,
    1073.                                     Critter.NO_STRIDE,
    1074.                                     ref planFollowPathRuntime,
    1075.                                     ref planFollowPathWaypoints,
    1076.                                     numWaypoints,
    1077.                                     waypoints,
    1078.                                     playToggle,
    1079.                                     ref clip,
    1080.                                     state.RoutStrideDuration
    1081.                                 );
    1082.  
    1083.                                 ActivateCancelerCritterInRangeForEnemy(
    1084.                                     ref action,
    1085.                                     ref cancelerCritterInRangeConfig,
    1086.                                     state.StoppingForwardRadius,
    1087.                                     state.StoppingCheckFrequency,
    1088.                                     offset: state.StoppingForwardRadius.AsY()
    1089.                                 );
    1090.  
    1091.                                 goto execution;
    1092.  
    1093.                                 #endregion
    1094.                             }
    1095.                             else
    1096.                             {
    1097.                                 #region Surrender Because Routing Blocked
    1098.  
    1099.                                 state.Routing = false;
    1100.  
    1101.                                 state.Traumatized = true;
    1102.  
    1103.                                 #endregion
    1104.                             }
    1105.  
    1106.                             #endregion
    1107.                         }
    1108.                     }
    1109.  
    1110.                     #endregion
    1111.  
    1112.                     #region Surrender Or Recover Because Traumatized
    1113.  
    1114.                     if (Hint.Unlikely(state.Traumatized))
    1115.                     {
    1116.                         if (Hint.Unlikely(
    1117.                             CritterSearchActions.FindNearbyEnemies(
    1118.                                 Proximities,
    1119.                                 critter,
    1120.                                 diplomacy.Data,
    1121.                                 transform.Location(),
    1122.                                 state.RoutSafetyRadius,
    1123.                                 out var _
    1124.                             )
    1125.                         ))
    1126.                         {
    1127.                             #region Surrender Because Enemies Nearby
    1128.  
    1129.                             PrepareForPlan(
    1130.                                 ref action,
    1131.                                 ref state,
    1132.                                 ref timePassed,
    1133.                                 ref triggers
    1134.                             );
    1135.  
    1136.                             ActivatePlanIdleWait(
    1137.                                 ref action,
    1138.                                 ref timeRequired,
    1139.                                 state.IdleDillyDallyDuration,
    1140.                                 playToggle,
    1141.                                 ref clip,
    1142.                                 state.IdleDillyDallyDuration
    1143.                             );
    1144.  
    1145.                             goto execution;
    1146.  
    1147.                             #endregion
    1148.                         }
    1149.                         else
    1150.                         {
    1151.                             #region Recover because no enemies nearby
    1152.  
    1153.                             state.Traumatized = false;
    1154.  
    1155.                             #endregion
    1156.                         }
    1157.                     }
    1158.  
    1159.                     #endregion
    1160.  
    1161.                     #endregion
    1162.  
    1163.                     #region Return To Formation If Too Far Away
    1164.  
    1165.                     if (Hint.Unlikely(
    1166.                         (state.IsFormationFollower | state.IsFormationLeader)
    1167.                         & !formationFollower.OutOfFormation(transform.Location())
    1168.                     ))
    1169.                     {
    1170.                         if (Hint.Unlikely(
    1171.                             // Path is available
    1172.                             Pathfinders[ThreadIndex].Calculate(
    1173.                                 transform.Location(),
    1174.                                 formationFollower.CenterLocation.DistanceAway(
    1175.                                     transform.Location(),
    1176.                                     formationFollower.FormationReturnWithinDistance
    1177.                                 ),
    1178.                                 out var numWaypoints,
    1179.                                 out var waypoints,
    1180.                                 out var initialDirection
    1181.                             )
    1182.                             // No enemies initially blocking the direction
    1183.                             & !CritterSearchActions.FindNearbyEnemies(
    1184.                                 Proximities,
    1185.                                 critter,
    1186.                                 diplomacy.Data,
    1187.                                 transform.Location() + initialDirection.WithLength(state.BlockedForwardRadius),
    1188.                                 state.BlockedForwardRadius,
    1189.                                 out var _
    1190.                             ))
    1191.                         )
    1192.                         {
    1193.                             PrepareForPlan(
    1194.                                 ref action,
    1195.                                 ref state,
    1196.                                 ref timePassed,
    1197.                                 ref triggers
    1198.                             );
    1199.  
    1200.                             ActivatePlanFollowPath(
    1201.                                 ref action,
    1202.                                 ref state,
    1203.                                 ref timePassed,
    1204.                                 ref timeRequired,
    1205.                                 ref planFollowPathConfig,
    1206.                                 state.RunSpeed,
    1207.                                 state.RunSpeedRecurve,
    1208.                                 state.RunStrideDistance,
    1209.                                 ref planFollowPathRuntime,
    1210.                                 ref planFollowPathWaypoints,
    1211.                                 numWaypoints,
    1212.                                 waypoints,
    1213.                                 playToggle,
    1214.                                 ref clip,
    1215.                                 state.RunStrideDuration
    1216.                             );
    1217.  
    1218.                             PositionActions.RotateTo(
    1219.                                 ref transform,
    1220.                                 initialDirection
    1221.                             );
    1222.  
    1223.                             ActivateCancelerCritterInRangeForEnemy(
    1224.                                 ref action,
    1225.                                 ref cancelerCritterInRangeConfig,
    1226.                                 state.StoppingForwardRadius,
    1227.                                 state.StoppingCheckFrequency,
    1228.                                 offset: state.StoppingForwardRadius.AsY()
    1229.                             );
    1230.  
    1231.                             goto execution;
    1232.                         }
    1233.                     }
    1234.  
    1235.                     #endregion
    1236.  
    1237.                     #region Melee Action Or Shove Because Vulnerable Enemy In Range
    1238.  
    1239.                     if (Hint.Unlikely(CritterSearchActions.FindNearbyEnemiesVulnerable(
    1240.                         Proximities,
    1241.                         critter,
    1242.                         diplomacy.Data,
    1243.                         transform.Location().Forward(state.MeleeAttackRange, transform.Rotation),
    1244.                         state.MeleeAttackRange,
    1245.                         out var enemiesInMeleeRange
    1246.                     )))
    1247.                     {
    1248.                         enemiesInMeleeRange.OrderedByClosestTo(transform.Location());
    1249.  
    1250.                         foreach(var enemyInMeleeRange in enemiesInMeleeRange)
    1251.                         {
    1252.                             // Enemy is not routing
    1253.                             if (Hint.Likely(!enemyInMeleeRange.Routing))
    1254.                             {
    1255.                                 // enemy cannot be dodging and is aware of attacker
    1256.                                 if (Hint.Likely(
    1257.                                     !enemyInMeleeRange.IsDodgingInvulnerable
    1258.                                 ))
    1259.                                 {
    1260.                                     #region Fair Combat
    1261.  
    1262.                                     if (Hint.Likely(CritterActions.WithinFieldOfVision(
    1263.                                         transform.Location(),
    1264.                                         enemyInMeleeRange.Rotation.ToDirection().RemoveY(),
    1265.                                         enemyInMeleeRange.Location,
    1266.                                         enemyInMeleeRange.MeleeAwarenessArc
    1267.                                     )))
    1268.                                     {
    1269.                                         #region Face To Face Combat
    1270.  
    1271.                                         if (Hint.Unlikely(state.Command >= state.ShoveCommandCost))
    1272.                                         {
    1273.                                             #region Shove
    1274.  
    1275.                                             PrepareForPlan(
    1276.                                                 ref action,
    1277.                                                 ref state,
    1278.                                                 ref timePassed,
    1279.                                                 ref triggers
    1280.                                             );
    1281.  
    1282.                                             ActivatePlanMeleeAttackShove(
    1283.                                                 ref action,
    1284.                                                 ref eventsRuntime,
    1285.                                                 ref timeRequired,
    1286.                                                 state.ShoveDuration,
    1287.                                                 ref planMeleeAttackConfig,
    1288.                                                 state.MeleeAttackDamage,
    1289.                                                 state.MeleeAttackRange,
    1290.                                                 state.MeleeAttackArc,
    1291.                                                 ref planMeleeAttackRuntime,
    1292.                                                 ref planMeleeAttackRuntimeTimestamps,
    1293.                                                 playToggle,
    1294.                                                 ref clip
    1295.                                             );
    1296.  
    1297.                                             ActivateDurationFaceConstantlyTowards(
    1298.                                                 ref action,
    1299.                                                 ref durationFaceConstantlyConfig,
    1300.                                                 enemyInMeleeRange.Entity
    1301.                                             );
    1302.  
    1303.                                             goto execution;
    1304.  
    1305.                                             #endregion
    1306.                                         }
    1307.                                         else
    1308.                                         {
    1309.                                             #region Attack
    1310.  
    1311.                                             var attackCumulativeProbability = state.MeleeAttackWeight;
    1312.                                             var bideCumulativeProbability = state.MeleeBideWeight + attackCumulativeProbability;
    1313.                                             var feintCumulativeProbability = state.MeleeFeintWeight + bideCumulativeProbability;
    1314.                                             var preemptiveDodgeCumulativeProbability = state.MeleePreemptiveDodgeWeight + feintCumulativeProbability;
    1315.  
    1316.                                             var meleeAttackRandom = random.NextFloat();
    1317.  
    1318.                                             if (meleeAttackRandom < attackCumulativeProbability)
    1319.                                             {
    1320.                                                 PrepareForPlan(
    1321.                                                     ref action,
    1322.                                                     ref state,
    1323.                                                     ref timePassed,
    1324.                                                     ref triggers
    1325.                                                 );
    1326.  
    1327.                                                 ActivatePlanMeleeAttackStrike(
    1328.                                                     ref action,
    1329.                                                     ref eventsRuntime,
    1330.                                                     ref timeRequired,
    1331.                                                     ref planMeleeAttackConfig,
    1332.                                                     state.MeleeAttackDamage,
    1333.                                                     state.MeleeAttackRange,
    1334.                                                     state.MeleeAttackArc,
    1335.                                                     state.MeleeTelegraphLag,
    1336.                                                     state.MeleeCommitmentLag,
    1337.                                                     state.MeleeStrikeLag,
    1338.                                                     state.MeleeEndLag,
    1339.                                                     ref planMeleeAttackRuntime,
    1340.                                                     ref planMeleeAttackRuntimeTimestamps,
    1341.                                                     playToggle,
    1342.                                                     ref clip
    1343.                                                 );
    1344.  
    1345.                                                 ActivateDurationFaceConstantlyTowards(
    1346.                                                     ref action,
    1347.                                                     ref durationFaceConstantlyConfig,
    1348.                                                     enemyInMeleeRange.Entity
    1349.                                                 );
    1350.  
    1351.                                                 ActivateCancelerMeleeEnemyIsDodging(
    1352.                                                     ref action,
    1353.                                                     ref cancelerMeleeEnemyIsDodgingConfig,
    1354.                                                     state.PullBackReactionTime,
    1355.                                                     state.MeleeAttackRange,
    1356.                                                     state.MeleeAttackArc
    1357.                                                 );
    1358.  
    1359.                                                 goto execution;
    1360.                                             }
    1361.  
    1362.                                             #endregion
    1363.  
    1364.                                             #region Bide
    1365.  
    1366.                                             if (meleeAttackRandom < bideCumulativeProbability)
    1367.                                             {
    1368.                                                 PrepareForPlan(
    1369.                                                    ref action,
    1370.                                                    ref state,
    1371.                                                    ref timePassed,
    1372.                                                    ref triggers
    1373.                                                );
    1374.  
    1375.                                                 ActivatePlanIdleWait(
    1376.                                                     ref action,
    1377.                                                     ref timeRequired,
    1378.                                                     state.MeleeBideDuration,
    1379.                                                     playToggle,
    1380.                                                     ref clip,
    1381.                                                     state.IdleDillyDallyDuration
    1382.                                                 );
    1383.  
    1384.                                                 ActivateCancelerIfPingDodge(
    1385.                                                     ref action,
    1386.                                                     ref cancelerIfPingDodgeConfig,
    1387.                                                     state.DodgeReactionTime
    1388.                                                 );
    1389.  
    1390.                                                 goto execution;
    1391.                                             }
    1392.  
    1393.                                             #endregion
    1394.  
    1395.                                             #region Feint
    1396.  
    1397.                                             if (meleeAttackRandom < feintCumulativeProbability)
    1398.                                             {
    1399.                                                 PrepareForPlan(
    1400.                                                     ref action,
    1401.                                                     ref state,
    1402.                                                     ref timePassed,
    1403.                                                     ref triggers
    1404.                                                 );
    1405.  
    1406.                                                 ActivatePlanMeleeAttackFeint(
    1407.                                                     ref action,
    1408.                                                     ref eventsRuntime,
    1409.                                                     ref timeRequired,
    1410.                                                     ref planMeleeAttackConfig,
    1411.                                                     state.MeleeTelegraphLag,
    1412.                                                     state.MeleeCommitmentLag,
    1413.                                                     state.MeleeStrikeLag,
    1414.                                                     state.MeleeEndLag,
    1415.                                                     ref planMeleeAttackRuntime,
    1416.                                                     ref planMeleeAttackRuntimeTimestamps,
    1417.                                                     playToggle,
    1418.                                                     ref clip
    1419.                                                 );
    1420.  
    1421.                                                 ActivateDurationFaceConstantlyTowards(
    1422.                                                     ref action,
    1423.                                                     ref durationFaceConstantlyConfig,
    1424.                                                     enemyInMeleeRange.Entity
    1425.                                                 );
    1426.  
    1427.                                                 ActivateCancelerIfPingDodge(
    1428.                                                     ref action,
    1429.                                                     ref cancelerIfPingDodgeConfig,
    1430.                                                     state.DodgeReactionTime
    1431.                                                 );
    1432.  
    1433.                                                 goto execution;
    1434.                                             }
    1435.  
    1436.                                             #endregion
    1437.  
    1438.                                             #region Preemptive Dodge
    1439.  
    1440.                                             if (meleeAttackRandom < preemptiveDodgeCumulativeProbability)
    1441.                                             {
    1442.                                                 PrepareForPlan(
    1443.                                                     ref action,
    1444.                                                     ref state,
    1445.                                                     ref timePassed,
    1446.                                                     ref triggers
    1447.                                                 );
    1448.  
    1449.                                                 ActivatePlanDodge(
    1450.                                                     ref action,
    1451.                                                     ref eventsRuntime,
    1452.                                                     ref timeRequired,
    1453.                                                     state.DodgeInvulnerableLag,
    1454.                                                     state.DodgeVulnerableLag,
    1455.                                                     state.DodgeEndLag,
    1456.                                                     ref planDodgeRuntimeTimestamps,
    1457.                                                     playToggle,
    1458.                                                     ref clip
    1459.                                                 );
    1460.  
    1461.                                                 goto execution;
    1462.                                             }
    1463.  
    1464.                                             #endregion
    1465.                                         }
    1466.  
    1467.                                         #endregion
    1468.                                     }
    1469.                                     else
    1470.                                     {
    1471.                                         #region Backstab
    1472.  
    1473.                                         PrepareForPlan(
    1474.                                             ref action,
    1475.                                             ref state,
    1476.                                             ref timePassed,
    1477.                                             ref triggers
    1478.                                         );
    1479.  
    1480.                                         ActivatePlanMeleeAttackStrike(
    1481.                                             ref action,
    1482.                                             ref eventsRuntime,
    1483.                                             ref timeRequired,
    1484.                                             ref planMeleeAttackConfig,
    1485.                                             state.MeleeAttackDamage,
    1486.                                             state.MeleeAttackRange,
    1487.                                             state.MeleeAttackArc,
    1488.                                             state.MeleeTelegraphLag,
    1489.                                             state.MeleeCommitmentLag,
    1490.                                             state.MeleeStrikeLag,
    1491.                                             state.MeleeEndLag,
    1492.                                             ref planMeleeAttackRuntime,
    1493.                                             ref planMeleeAttackRuntimeTimestamps,
    1494.                                             playToggle,
    1495.                                             ref clip
    1496.                                         );
    1497.  
    1498.                                         ActivateDurationFaceConstantlyTowards(
    1499.                                             ref action,
    1500.                                             ref durationFaceConstantlyConfig,
    1501.                                             enemyInMeleeRange.Entity
    1502.                                         );
    1503.  
    1504.                                         ActivateCancelerMeleeEnemyIsDodging(
    1505.                                             ref action,
    1506.                                             ref cancelerMeleeEnemyIsDodgingConfig,
    1507.                                             state.PullBackReactionTime,
    1508.                                             state.MeleeAttackRange,
    1509.                                             state.MeleeAttackArc
    1510.                                         );
    1511.  
    1512.                                         goto execution;
    1513.  
    1514.                                         #endregion
    1515.                                     }
    1516.  
    1517.                                     #endregion
    1518.                                 }
    1519.                                 // Enemy is dodging
    1520.                                 else
    1521.                                 {
    1522.                                     #region VS Dodger
    1523.  
    1524.                                     if (Hint.Likely(CritterActions.WithinFieldOfVision(
    1525.                                         transform.Location(),
    1526.                                         enemyInMeleeRange.Rotation.ToDirection().RemoveY(),
    1527.                                         enemyInMeleeRange.Location,
    1528.                                         enemyInMeleeRange.MeleeAwarenessArc
    1529.                                     )))
    1530.                                     {
    1531.                                         #region Bide Because Enemy Dodging
    1532.  
    1533.                                         PrepareForPlan(
    1534.                                             ref action,
    1535.                                             ref state,
    1536.                                             ref timePassed,
    1537.                                             ref triggers
    1538.                                         );
    1539.  
    1540.                                         ActivatePlanIdleWait(
    1541.                                             ref action,
    1542.                                             ref timeRequired,
    1543.                                             state.MeleeBideDuration,
    1544.                                             playToggle,
    1545.                                             ref clip,
    1546.                                             state.IdleDillyDallyDuration
    1547.                                         );
    1548.  
    1549.                                         ActivateCancelerIfPingDodge(
    1550.                                             ref action,
    1551.                                             ref cancelerIfPingDodgeConfig,
    1552.                                             state.DodgeReactionTime
    1553.                                         );
    1554.  
    1555.                                         goto execution;
    1556.  
    1557.                                         #endregion
    1558.                                     }
    1559.                                     else
    1560.                                     {
    1561.                                         #region Backstab
    1562.  
    1563.                                         PrepareForPlan(
    1564.                                             ref action,
    1565.                                             ref state,
    1566.                                             ref timePassed,
    1567.                                             ref triggers
    1568.                                         );
    1569.  
    1570.                                         ActivatePlanMeleeAttackStrike(
    1571.                                             ref action,
    1572.                                             ref eventsRuntime,
    1573.                                             ref timeRequired,
    1574.                                             ref planMeleeAttackConfig,
    1575.                                             state.MeleeAttackDamage,
    1576.                                             state.MeleeAttackRange,
    1577.                                             state.MeleeAttackArc,
    1578.                                             state.MeleeTelegraphLag,
    1579.                                             state.MeleeCommitmentLag,
    1580.                                             state.MeleeStrikeLag,
    1581.                                             state.MeleeEndLag,
    1582.                                             ref planMeleeAttackRuntime,
    1583.                                             ref planMeleeAttackRuntimeTimestamps,
    1584.                                             playToggle,
    1585.                                             ref clip
    1586.                                         );
    1587.  
    1588.                                         ActivateDurationFaceConstantlyTowards(
    1589.                                             ref action,
    1590.                                             ref durationFaceConstantlyConfig,
    1591.                                             enemyInMeleeRange.Entity
    1592.                                         );
    1593.  
    1594.                                         ActivateCancelerMeleeEnemyIsDodging(
    1595.                                             ref action,
    1596.                                             ref cancelerMeleeEnemyIsDodgingConfig,
    1597.                                             state.PullBackReactionTime,
    1598.                                             state.MeleeAttackRange,
    1599.                                             state.MeleeAttackArc
    1600.                                         );
    1601.  
    1602.                                         goto execution;
    1603.  
    1604.                                         #endregion
    1605.                                     }
    1606.  
    1607.                                     #endregion
    1608.                                 }
    1609.                             }
    1610.                             // Enemy is routing
    1611.                             else
    1612.                             {
    1613.                                 #region Chasedown Attack
    1614.  
    1615.                                 PrepareForPlan(
    1616.                                     ref action,
    1617.                                     ref state,
    1618.                                     ref timePassed,
    1619.                                     ref triggers
    1620.                                 );
    1621.  
    1622.                                 ActivatePlanMeleeAttackStrike(
    1623.                                     ref action,
    1624.                                     ref eventsRuntime,
    1625.                                     ref timeRequired,
    1626.                                     state.ChasedownDuration,
    1627.                                     ref planMeleeAttackConfig,
    1628.                                     state.MeleeAttackDamage,
    1629.                                     state.MeleeAttackRange,
    1630.                                     state.MeleeAttackArc,
    1631.                                     ref planMeleeAttackRuntime,
    1632.                                     ref planMeleeAttackRuntimeTimestamps,
    1633.                                     playToggle,
    1634.                                     ref clip
    1635.                                 );
    1636.  
    1637.                                 var directionOfEnemy =
    1638.                                     enemyInMeleeRange.Location
    1639.                                     - transform.Location();
    1640.  
    1641.                                 ActivateDurationRun(
    1642.                                     ref action,
    1643.                                     ref durationRunConfig,
    1644.                                     state.ChasedownAttackMoveSpeed,
    1645.                                     state.ChasedownSpeedRecurve,
    1646.                                     directionOfEnemy,
    1647.                                     ref durationRunRuntime
    1648.                                 );
    1649.  
    1650.                                 ActivateDurationFaceConstantlyTowards(
    1651.                                     ref action,
    1652.                                     ref durationFaceConstantlyConfig,
    1653.                                     enemyInMeleeRange.Entity
    1654.                                 );
    1655.  
    1656.                                 goto execution;
    1657.  
    1658.                                 #endregion
    1659.                             }
    1660.                         }
    1661.                     }
    1662.  
    1663.                     #endregion
    1664.  
    1665.                     #region Move To Enemy Or Backup Ally In Seek Range Within Melee Distance
    1666.  
    1667.                     if (CritterSearchActions.FindNearbyEnemies(
    1668.                         Proximities,
    1669.                         critter,
    1670.                         diplomacy.Data,
    1671.                         transform.Location().Forward(state.AggressionSeekForwardRadius, transform.Rotation),
    1672.                         state.AggressionSeekForwardRadius,
    1673.                         out var enemiesInRange
    1674.                     ))
    1675.                     {
    1676.                         foreach (var enemyInRange in enemiesInRange.OrderedByClosestTo(transform.Location()))
    1677.                         {
    1678.                             // Enemy is not too far away
    1679.                             if (Hint.Likely(formationFollower.MaxEnemySeekDistance.DistanceWithin(
    1680.                                 enemyInRange.Location,
    1681.                                 formationFollower.CenterLocation
    1682.                             )))
    1683.                             {
    1684.                                 // Path to within melee range of enemy exists
    1685.                                 if (Pathfinders[ThreadIndex].Calculate(
    1686.                                     transform.Location(),
    1687.                                     enemyInRange.Location.DistanceAway(transform.Location(), state.MeleeEngagementRange),
    1688.                                     out var numWaypoints,
    1689.                                     out var waypoints,
    1690.                                     out var initialDirection
    1691.                                 ))
    1692.                                 {
    1693.                                     // No one is in front
    1694.                                     if (!CritterSearchActions.FindAnyone(
    1695.                                         Proximities,
    1696.                                         critter,
    1697.                                         transform.Location() + initialDirection.WithLength(state.BlockedForwardRadius),
    1698.                                         state.BlockedForwardRadius,
    1699.                                         out var _
    1700.                                     ))
    1701.                                     {
    1702.                                         PrepareForPlan(
    1703.                                             ref action,
    1704.                                             ref state,
    1705.                                             ref timePassed,
    1706.                                             ref triggers
    1707.                                         );
    1708.  
    1709.                                         ActivatePlanFollowPath(
    1710.                                             ref action,
    1711.                                             ref state,
    1712.                                             ref timePassed,
    1713.                                             ref timeRequired,
    1714.                                             ref planFollowPathConfig,
    1715.                                             state.RunSpeed,
    1716.                                             state.RunSpeedRecurve,
    1717.                                             state.RunStrideDistance,
    1718.                                             ref planFollowPathRuntime,
    1719.                                             ref planFollowPathWaypoints,
    1720.                                             numWaypoints,
    1721.                                             waypoints,
    1722.                                             playToggle,
    1723.                                             ref clip,
    1724.                                             state.RunStrideDuration
    1725.                                         );
    1726.  
    1727.                                         PositionActions.RotateTo(
    1728.                                             ref transform,
    1729.                                             initialDirection
    1730.                                         );
    1731.  
    1732.                                         ActivateCancelerCritterInRangeForAnyone(
    1733.                                             ref action,
    1734.                                             ref cancelerCritterInRangeConfig,
    1735.                                             state.StoppingForwardRadius,
    1736.                                             state.StoppingCheckFrequency,
    1737.                                             offset: state.StoppingForwardRadius.AsY()
    1738.                                         );
    1739.  
    1740.                                         goto execution;
    1741.                                     }
    1742.                                     // Someone is in front blocking the way
    1743.                                     else if(Hint.Likely(
    1744.                                         state.AggressionAllyBackupRange.DistanceWithin(
    1745.                                             transform.Location(),
    1746.                                             enemyInRange.Location
    1747.                                         )
    1748.                                     ))
    1749.                                     {
    1750.                                         PrepareForPlan(
    1751.                                             ref action,
    1752.                                             ref state,
    1753.                                             ref timePassed,
    1754.                                             ref triggers
    1755.                                         );
    1756.  
    1757.                                         ActivatePlanIdleWait(
    1758.                                             ref action,
    1759.                                             ref timeRequired,
    1760.                                             state.IdleDillyDallyDuration,
    1761.                                             playToggle,
    1762.                                             ref clip,
    1763.                                             state.IdleDillyDallyDuration
    1764.                                         );
    1765.  
    1766.                                         AlignWithFormation(
    1767.                                             ref transform,
    1768.                                             formationFollower
    1769.                                         );
    1770.  
    1771.                                         goto execution;
    1772.                                     }
    1773.                                 }
    1774.                             }
    1775.                         }
    1776.                     }
    1777.  
    1778.                     #endregion
    1779.  
    1780.                     #region Move To And Chase Down Routing Enemy
    1781.  
    1782.                     if(Hint.Unlikely(CritterSearchActions.FindNearbyEnemiesRouting(
    1783.                         Proximities,
    1784.                         critter,
    1785.                         diplomacy.Data,
    1786.                         transform.Location().Forward(state.ChasedownForwardRadius, transform.Rotation),
    1787.                         state.ChasedownForwardRadius,
    1788.                         out var nearbyEnemyRouters
    1789.                     )))
    1790.                     {
    1791.                         nearbyEnemyRouters.OrderedByClosestTo(transform.Location());
    1792.  
    1793.                         foreach(var nearbyEnemyRouter in nearbyEnemyRouters)
    1794.                         {
    1795.                             // Enemy is not too far away
    1796.                             if (Hint.Unlikely(formationFollower.MaxEnemyChasedownDistance.DistanceWithin(
    1797.                                     nearbyEnemyRouter.Location,
    1798.                                     formationFollower.CenterLocation
    1799.                                 )
    1800.                                 // Path exists
    1801.                                 & Pathfinders[ThreadIndex].Calculate(
    1802.                                     transform.Location(),
    1803.                                     nearbyEnemyRouter.Location.DistanceAway(transform.Location(), state.MeleeEngagementRangeMovingTarget),
    1804.                                     out var numWaypoints,
    1805.                                     out var waypoints,
    1806.                                     out var initialDirection
    1807.                                 )
    1808.                                 // No one blocking the initial direction
    1809.                                 & !CritterSearchActions.FindAnyone(
    1810.                                     Proximities,
    1811.                                     critter,
    1812.                                     transform.Location() + initialDirection.WithLength(state.BlockedForwardRadius),
    1813.                                     state.BlockedForwardRadius,
    1814.                                     out var _
    1815.                                 )
    1816.                             ))
    1817.                             {
    1818.                                 PrepareForPlan(
    1819.                                     ref action,
    1820.                                     ref state,
    1821.                                     ref timePassed,
    1822.                                     ref triggers
    1823.                                 );
    1824.  
    1825.                                 ActivatePlanFollowPath(
    1826.                                     ref action,
    1827.                                     ref state,
    1828.                                     ref timePassed,
    1829.                                     ref timeRequired,
    1830.                                     ref planFollowPathConfig,
    1831.                                     state.ChasedownSpeed,
    1832.                                     state.ChasedownSpeedRecurve,
    1833.                                     state.ChasedownStrideDistance,
    1834.                                     ref planFollowPathRuntime,
    1835.                                     ref planFollowPathWaypoints,
    1836.                                     numWaypoints,
    1837.                                     waypoints,
    1838.                                     playToggle,
    1839.                                     ref clip,
    1840.                                     state.ChasedownStrideDuration
    1841.                                 );
    1842.  
    1843.                                 PositionActions.RotateTo(
    1844.                                     ref transform,
    1845.                                     initialDirection
    1846.                                 );
    1847.  
    1848.                                 ActivateCancelerCritterInRangeForAnyone(
    1849.                                     ref action,
    1850.                                     ref cancelerCritterInRangeConfig,
    1851.                                     state.StoppingForwardRadius,
    1852.                                     state.StoppingCheckFrequency,
    1853.                                     offset: state.StoppingForwardRadius.AsY()
    1854.                                 );
    1855.  
    1856.                                 goto execution;
    1857.                             }
    1858.                         }
    1859.                     }
    1860.  
    1861.                     #endregion
    1862.  
    1863.                     #region Return To Formation If No Ranks Nearby And Outside Of Combat
    1864.  
    1865.                     if (Hint.Unlikely(
    1866.                         // No occupied ranks nearby
    1867.                         !CritterFormationActions.OccupiedRank(
    1868.                             formationFollower,
    1869.                             transform.Location(),
    1870.                             out var _
    1871.                         )
    1872.                     ))
    1873.                     {
    1874.                         if (Hint.Unlikely(
    1875.                             // Path is available
    1876.                             Pathfinders[ThreadIndex].Calculate(
    1877.                                 transform.Location(),
    1878.                                 formationFollower.CenterLocation.DistanceAway(
    1879.                                     transform.Location(),
    1880.                                     formationFollower.FormationReturnWithinDistance
    1881.                                 ),
    1882.                                 out var numWaypoints,
    1883.                                 out var waypoints,
    1884.                                 out var initialDirection
    1885.                             )
    1886.                             // No enemy initially blocking the direction
    1887.                             & !CritterSearchActions.FindNearbyEnemies(
    1888.                                 Proximities,
    1889.                                 critter,
    1890.                                 diplomacy.Data,
    1891.                                 transform.Location() + initialDirection.WithLength(state.BlockedForwardRadius),
    1892.                                 state.BlockedForwardRadius,
    1893.                                 out var _
    1894.                             ))
    1895.                         )
    1896.                         {
    1897.                             PrepareForPlan(
    1898.                                 ref action,
    1899.                                 ref state,
    1900.                                 ref timePassed,
    1901.                                 ref triggers
    1902.                             );
    1903.  
    1904.                             ActivatePlanFollowPath(
    1905.                                 ref action,
    1906.                                 ref state,
    1907.                                 ref timePassed,
    1908.                                 ref timeRequired,
    1909.                                 ref planFollowPathConfig,
    1910.                                 state.RunSpeed,
    1911.                                 state.RunSpeedRecurve,
    1912.                                 state.RunStrideDistance,
    1913.                                 ref planFollowPathRuntime,
    1914.                                 ref planFollowPathWaypoints,
    1915.                                 numWaypoints,
    1916.                                 waypoints,
    1917.                                 playToggle,
    1918.                                 ref clip,
    1919.                                 state.RunStrideDuration
    1920.                             );
    1921.  
    1922.                             PositionActions.RotateTo(
    1923.                                 ref transform,
    1924.                                 initialDirection
    1925.                             );
    1926.  
    1927.                             ActivateCancelerCritterInRangeForEnemy(
    1928.                                 ref action,
    1929.                                 ref cancelerCritterInRangeConfig,
    1930.                                 state.StoppingForwardRadius,
    1931.                                 state.StoppingCheckFrequency,
    1932.                                 offset: state.StoppingForwardRadius.AsY()
    1933.                             );
    1934.  
    1935.                             goto execution;
    1936.                         }
    1937.                     }
    1938.  
    1939.                     #endregion
    1940.  
    1941.                     #region Move Forward In Rank if Available
    1942.  
    1943.                     // Calculate current rank priority
    1944.                     var isOccupyingRank = CritterFormationActions.OccupiedRank(
    1945.                         formationFollower,
    1946.                         transform.Location(),
    1947.                         out var occupiedRank
    1948.                     );
    1949.                     var priorityToBeat = math.select(int.MinValue, occupiedRank.Priority, isOccupyingRank);
    1950.  
    1951.                     // Other ranks in front
    1952.                     if (Hint.Likely(
    1953.                         state.IsFormationFollower
    1954.                         & CritterFormationActions.SearchForRanks(
    1955.                             formationFollower,
    1956.                             transform.Location().Forward(
    1957.                                 formationFollower.RankImprovementForwardRange,
    1958.                                 formationFollower.OfficerTransform.Rotation
    1959.                             ),
    1960.                             formationFollower.RankImprovementForwardRange.AsRadii(),
    1961.                             out var ranks
    1962.                         )
    1963.                     ))
    1964.                     {
    1965.                         foreach (var rank in ranks.OrderByPriorityDecreasing())
    1966.                         {
    1967.                             if (Hint.Unlikely(
    1968.                                 // Better priority
    1969.                                 rank.Priority > priorityToBeat
    1970.                                 // No allies occupying that rank
    1971.                                 & !CritterSearchActions.FindNearbyAllies(
    1972.                                     Proximities,
    1973.                                     critter,
    1974.                                     diplomacy.Data,
    1975.                                     rank.Location,
    1976.                                     formationFollower.RankImprovementOthersOccupancyRadius,
    1977.                                     out var _
    1978.                                 )
    1979.                             ))
    1980.                             {
    1981.                                 if (Hint.Unlikely(
    1982.                                     // Path is available
    1983.                                     Pathfinders[ThreadIndex].Calculate(
    1984.                                         transform.Location(),
    1985.                                         rank.Location,
    1986.                                         out var numWaypoints,
    1987.                                         out var waypoints,
    1988.                                         out var initialDirection
    1989.                                     )
    1990.                                     // No one initially blocking the direction
    1991.                                     & !CritterSearchActions.FindAnyone(
    1992.                                         Proximities,
    1993.                                         critter,
    1994.                                         transform.Location() + initialDirection.WithLength(state.BlockedForwardRadius),
    1995.                                         state.BlockedForwardRadius,
    1996.                                         out var _
    1997.                                     ))
    1998.                                 )
    1999.                                 {
    2000.                                     PrepareForPlan(
    2001.                                         ref action,
    2002.                                         ref state,
    2003.                                         ref timePassed,
    2004.                                         ref triggers
    2005.                                     );
    2006.  
    2007.                                     ActivatePlanFollowPath(
    2008.                                         ref action,
    2009.                                         ref state,
    2010.                                         ref timePassed,
    2011.                                         ref timeRequired,
    2012.                                         ref planFollowPathConfig,
    2013.                                         state.RunSpeed,
    2014.                                         state.RunSpeedRecurve,
    2015.                                         state.RunStrideDistance,
    2016.                                         ref planFollowPathRuntime,
    2017.                                         ref planFollowPathWaypoints,
    2018.                                         numWaypoints,
    2019.                                         waypoints,
    2020.                                         playToggle,
    2021.                                         ref clip,
    2022.                                         state.RunStrideDuration
    2023.                                     );
    2024.  
    2025.                                     PositionActions.RotateTo(
    2026.                                         ref transform,
    2027.                                         initialDirection
    2028.                                     );
    2029.  
    2030.                                     ActivateCancelerCritterInRangeForAnyone(
    2031.                                         ref action,
    2032.                                         ref cancelerCritterInRangeConfig,
    2033.                                         state.StoppingForwardRadius,
    2034.                                         state.StoppingCheckFrequency,
    2035.                                         offset: state.StoppingForwardRadius.AsY()
    2036.                                     );
    2037.  
    2038.                                     goto execution;
    2039.                                 }
    2040.                             }
    2041.                         }
    2042.                     }
    2043.  
    2044.                     #endregion
    2045.  
    2046.                     #region Move Backwards In Rank If Front Congested
    2047.  
    2048.                     isOccupyingRank = CritterFormationActions.OccupiedRank(
    2049.                         formationFollower,
    2050.                         transform.Location(),
    2051.                         out occupiedRank
    2052.                     );
    2053.                     var priorityToUndercut = math.select(int.MaxValue, occupiedRank.Priority, isOccupyingRank);
    2054.  
    2055.                     if (Hint.Likely(
    2056.                         state.IsFormationFollower
    2057.                         // There are ranks behind
    2058.                         & CritterFormationActions.SearchForRanks(
    2059.                             formationFollower,
    2060.                             transform.Location().Backward(
    2061.                                 formationFollower.RankRetreatIfCrowdedBackwardRange,
    2062.                                 formationFollower.OfficerTransform.Rotation
    2063.                             ),
    2064.                             formationFollower.RankRetreatIfCrowdedBackwardRange.AsRadii(),
    2065.                             out ranks
    2066.                         )
    2067.                         // Too many allies are around
    2068.                         & CritterSearchActions.FindNearbyAllies(
    2069.                             Proximities,
    2070.                             critter,
    2071.                             diplomacy.Data,
    2072.                             transform.Location(),
    2073.                             formationFollower.RankRetreatIfCrowdedCheckRange,
    2074.                             out var crowdingAllies
    2075.                         )
    2076.                         & crowdingAllies.Length > formationFollower.RankRetreatIfCrowdedThreshold
    2077.                     ))
    2078.                     {
    2079.                         foreach (var rank in ranks.OrderByPriorityDecreasing())
    2080.                         {
    2081.                             if (Hint.Unlikely(
    2082.                                 // Better priority
    2083.                                 rank.Priority > priorityToUndercut
    2084.                                 // No allies occupying that rank
    2085.                                 & !CritterSearchActions.FindNearbyAllies(
    2086.                                     Proximities,
    2087.                                     critter,
    2088.                                     diplomacy.Data,
    2089.                                     rank.Location,
    2090.                                     formationFollower.RankRetreatOthersOccupancyRadius,
    2091.                                     out var _
    2092.                                 )
    2093.                             ))
    2094.                             {
    2095.                                 if (Hint.Unlikely(
    2096.                                     // Path is available
    2097.                                     Pathfinders[ThreadIndex].Calculate(
    2098.                                         transform.Location(),
    2099.                                         rank.Location,
    2100.                                         out var numWaypoints,
    2101.                                         out var waypoints,
    2102.                                         out var initialDirection
    2103.                                     )
    2104.                                     // No enemies initially blocking the direction
    2105.                                     & !CritterSearchActions.FindAnyone(
    2106.                                         Proximities,
    2107.                                         critter,
    2108.                                         transform.Location() + initialDirection.WithLength(state.BlockedForwardRadius),
    2109.                                         state.BlockedForwardRadius,
    2110.                                         out var _
    2111.                                     ))
    2112.                                 )
    2113.                                 {
    2114.                                     PrepareForPlan(
    2115.                                         ref action,
    2116.                                         ref state,
    2117.                                         ref timePassed,
    2118.                                         ref triggers
    2119.                                     );
    2120.  
    2121.                                     ActivatePlanFollowPath(
    2122.                                         ref action,
    2123.                                         ref state,
    2124.                                         ref timePassed,
    2125.                                         ref timeRequired,
    2126.                                         ref planFollowPathConfig,
    2127.                                         state.RunSpeed,
    2128.                                         state.RunSpeedRecurve,
    2129.                                         state.RunStrideDistance,
    2130.                                         ref planFollowPathRuntime,
    2131.                                         ref planFollowPathWaypoints,
    2132.                                         numWaypoints,
    2133.                                         waypoints,
    2134.                                         playToggle,
    2135.                                         ref clip,
    2136.                                         state.RunStrideDuration
    2137.                                     );
    2138.  
    2139.                                     PositionActions.RotateTo(
    2140.                                         ref transform,
    2141.                                         initialDirection
    2142.                                     );
    2143.  
    2144.                                     ActivateCancelerCritterInRangeForAnyone(
    2145.                                         ref action,
    2146.                                         ref cancelerCritterInRangeConfig,
    2147.                                         state.StoppingForwardRadius,
    2148.                                         state.StoppingCheckFrequency,
    2149.                                         offset: state.StoppingForwardRadius.AsY()
    2150.                                     );
    2151.  
    2152.                                     goto execution;
    2153.                                 }
    2154.                             }
    2155.                         }
    2156.                     }
    2157.  
    2158.                     #endregion
    2159.  
    2160.                     #region Move Away From Ally If Crowded
    2161.  
    2162.                     if (CritterSearchActions.FindNearbyAllies(
    2163.                         Proximities,
    2164.                         critter,
    2165.                         diplomacy.Data,
    2166.                         transform.Location(),
    2167.                         state.PersonalSpaceIntrudedRadius,
    2168.                         out var alliesInPersonalSpace
    2169.                     ))
    2170.                     {
    2171.                         foreach (var allyInPersonalSpace in alliesInPersonalSpace.OrderedByClosestTo(transform.Location()))
    2172.                         {
    2173.                             var awayFromAlly = allyInPersonalSpace.Location.DistanceTowards(
    2174.                                 transform.Location(),
    2175.                                 state.PersonalSpaceMoveAwayDistance
    2176.                             );
    2177.  
    2178.                             if (Pathfinders[ThreadIndex].Calculate(
    2179.                                 transform.Location(),
    2180.                                 awayFromAlly,
    2181.                                 out var numWaypoints,
    2182.                                 out var waypoints,
    2183.                                 out var initialDirection
    2184.                             ))
    2185.                             {
    2186.                                 PrepareForPlan(
    2187.                                     ref action,
    2188.                                     ref state,
    2189.                                     ref timePassed,
    2190.                                     ref triggers
    2191.                                 );
    2192.  
    2193.                                 ActivatePlanFollowPath(
    2194.                                     ref action,
    2195.                                     ref state,
    2196.                                     ref timePassed,
    2197.                                     ref timeRequired,
    2198.                                     ref planFollowPathConfig,
    2199.                                     state.RunSpeed,
    2200.                                     state.RunSpeedRecurve,
    2201.                                     state.RunStrideDistance,
    2202.                                     ref planFollowPathRuntime,
    2203.                                     ref planFollowPathWaypoints,
    2204.                                     numWaypoints,
    2205.                                     waypoints,
    2206.                                     playToggle,
    2207.                                     ref clip,
    2208.                                     state.RunStrideDuration
    2209.                                 );
    2210.  
    2211.                                 PositionActions.RotateTo(
    2212.                                     ref transform,
    2213.                                     initialDirection
    2214.                                 );
    2215.  
    2216.                                 goto execution;
    2217.                             }
    2218.                         }
    2219.                     }
    2220.  
    2221.                     #endregion
    2222.  
    2223.                     #region Idle As Default
    2224.  
    2225.                     {
    2226.                         PrepareForPlan(
    2227.                             ref action,
    2228.                             ref state,
    2229.                             ref timePassed,
    2230.                             ref triggers
    2231.                         );
    2232.  
    2233.                         ActivatePlanIdleWait(
    2234.                             ref action,
    2235.                             ref timeRequired,
    2236.                             state.IdleDillyDallyDuration,
    2237.                             playToggle,
    2238.                             ref clip,
    2239.                             state.IdleDillyDallyDuration
    2240.                         );
    2241.  
    2242.                         AlignWithFormation(
    2243.                             ref transform,
    2244.                             formationFollower
    2245.                         );
    2246.  
    2247.                         goto execution;
    2248.                     }
    2249.  
    2250.                     #endregion
    2251.                 }
    2252.  
    2253.                 #endregion
    2254.             }
    2255.             else
    2256.             {
    2257.                 timePassed.Seconds += DeltaSeconds;
    2258.             }
    2259.  
    2260.         #endregion
    2261.  
    2262.             execution:
    2263.  
    2264.             #region Stats
    2265.  
    2266.             if (Hint.Unlikely(state.Rally != 0f))
    2267.             {
    2268.                 var rallyChange = (DeltaSeconds * math.select(state.MoraleRallyRecovery, -state.MoraleRallyUsage, state.Rally > 0));
    2269.                 var newRally = state.Rally + rallyChange;
    2270.                 state.Rally = math.select(newRally, 0, newRally * state.Rally < 0);
    2271.             }
    2272.  
    2273.             #endregion
    2274.  
    2275.             #region Plans
    2276.  
    2277.             if (CritterActions.IsDoing(action, CritterAction.PlanIdle))
    2278.             {
    2279.                 ExecutePlanIdle();
    2280.             }
    2281.             else if (CritterActions.IsDoing(action, CritterAction.PlanFollowPath))
    2282.             {
    2283.                 ExecutePlanFollowPath(
    2284.                     ref transform,
    2285.                     ref timeRequired,
    2286.                     in planFollowPathConfig,
    2287.                     ref planFollowPathRuntime,
    2288.                     ref planFollowPathWaypoints
    2289.                 );
    2290.             }
    2291.             else if (CritterActions.IsDoing(action, CritterAction.PlanMeleeAttack))
    2292.             {
    2293.                 ExecutePlanMeleeAttack(
    2294.                     critter,
    2295.                     in transform,
    2296.                     ref state,
    2297.                     ref eventsRuntime,
    2298.                     ref timeRequired,
    2299.                     in timePassed,
    2300.                     in diplomacy,
    2301.                     adjustToggle,
    2302.                     ref adjust,
    2303.                     in planMeleeAttackConfig,
    2304.                     in planMeleeAttackRuntime,
    2305.                     in planMeleeAttackEventsTimestamps,
    2306.                     in planMeleeAttackRuntimeTimestamps
    2307.                 );
    2308.             }
    2309.             else if (CritterActions.IsDoing(action, CritterAction.PlanDodge))
    2310.             {
    2311.                 ExecutePlanDodge(
    2312.                     ref state,
    2313.                     ref eventsRuntime,
    2314.                     in timePassed,
    2315.                     adjustToggle,
    2316.                     ref adjust,
    2317.                     in planDodgeEventsTimestamps,
    2318.                     in planDodgeRuntimeTimestamps
    2319.                 );
    2320.             }
    2321.             else if (CritterActions.IsDoing(action, CritterAction.PlanFlinch))
    2322.             {
    2323.                 ExecutePlanFlinch();
    2324.             }
    2325.  
    2326.             #endregion
    2327.  
    2328.             #region Duration
    2329.  
    2330.             if (Hint.Unlikely(CritterActions.IsDoing(action, CritterAction.DurationFaceConstantly)))
    2331.             {
    2332.                 ExecuteDurationFaceConstantly(
    2333.                     critter,
    2334.                     ref transform,
    2335.                     durationFaceConstantlyConfig
    2336.                 );
    2337.             }
    2338.  
    2339.             if (Hint.Unlikely(CritterActions.IsDoing(action, CritterAction.DurationLeadFollowers)))
    2340.             {
    2341.                 ExecuteDurationLeadFollowers(
    2342.                     critter,
    2343.                     in transform,
    2344.                     in formationFollower,
    2345.                     in formationFollowers
    2346.                 );
    2347.             }
    2348.            
    2349.             if (Hint.Unlikely(CritterActions.IsDoing(action, CritterAction.DurationRun)))
    2350.             {
    2351.                 ExecuteDurationRun(
    2352.                     ref transform,
    2353.                     in durationRunConfig,
    2354.                     ref durationRunRuntime
    2355.                 );
    2356.             }
    2357.  
    2358.             #endregion
    2359.  
    2360.             #region Canceler
    2361.  
    2362.             if (Hint.Unlikely(CritterActions.IsDoing(action, CritterAction.CancelerEnemyInRange)))
    2363.             {
    2364.                 ExecuteCancelerCritterEnemyRange(
    2365.                     critter,
    2366.                     in transform,
    2367.                     in timePassed,
    2368.                     ref timeRequired,
    2369.                     in diplomacy,
    2370.                     in cancelerCritterInRangeConfig
    2371.                 );
    2372.             }
    2373.  
    2374.             if (Hint.Unlikely(CritterActions.IsDoing(action, CritterAction.CancelerAllyInRange)))
    2375.             {
    2376.                 ExecuteCancelerCritterAllyInRange(
    2377.                     critter,
    2378.                     in transform,
    2379.                     in timePassed,
    2380.                     ref timeRequired,
    2381.                     in diplomacy,
    2382.                     in cancelerCritterInRangeConfig
    2383.                 );
    2384.             }
    2385.  
    2386.             if (Hint.Unlikely(CritterActions.IsDoing(action, CritterAction.CancelerAnyoneInRange)))
    2387.             {
    2388.                 ExecuteCancelerCritterAnyoneInRange(
    2389.                     critter,
    2390.                     in transform,
    2391.                     in timePassed,
    2392.                     ref timeRequired,
    2393.                     in cancelerCritterInRangeConfig
    2394.                 );
    2395.             }
    2396.  
    2397.             if (Hint.Unlikely(CritterActions.IsDoing(action, CritterAction.CancelerIfPingDodge)))
    2398.             {
    2399.                 ExecuteCancelerIfPingDodge(
    2400.                     in state,
    2401.                     ref triggers,
    2402.                     in timePassed,
    2403.                     ref timeRequired,
    2404.                     ref cancelerIfPingDodgeConfig
    2405.                 );
    2406.             }
    2407.  
    2408.             if (Hint.Unlikely(CritterActions.IsDoing(action, CritterAction.CancelerIfMeleeEnemyIsDodging)))
    2409.             {
    2410.                 ExecuteCancelerMeleeEnemyIsDodging(
    2411.                     critter,
    2412.                     in transform,
    2413.                     in timePassed,
    2414.                     ref timeRequired,
    2415.                     in diplomacy,
    2416.                     in cancelerMeleeEnemyIsDodgingConfig
    2417.                 );
    2418.             }
    2419.  
    2420.             if (Hint.Unlikely(CritterActions.IsDoing(action, CritterAction.CancelerAfterTime)))
    2421.             {
    2422.                 ExecuteCancelerAfterTime(
    2423.                     in timePassed,
    2424.                     ref timeRequired,
    2425.                     in cancelerAfterTimeConfig
    2426.                 );
    2427.             }
    2428.  
    2429.             #endregion
    2430.         }
    2431.  
    2432.  
    2433.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    2434.         private void Reset(
    2435.             ref CritterStateComponent state
    2436.         )
    2437.         {
    2438.             state.CanVoluntarilyAct = true;
    2439.             state.VulnerableToDamage = true;
    2440.             state.IsFlinching = false;
    2441.             state.IsDodgingInvulnerable = false;
    2442.             state.PingDodge = false;
    2443.             state.TriggerDodgeDirection = float2.zero;
    2444.         }
    2445.  
    2446.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    2447.         private void PrepareForPlan(
    2448.             ref CritterActionComponent action,
    2449.             ref CritterStateComponent state,
    2450.             ref CritterTimePassedComponent timePassed,
    2451.             ref CritterTriggerComponent triggers
    2452.         )
    2453.         {
    2454.             Reset(ref state);
    2455.  
    2456.             action.Doing = CritterAction.None;
    2457.  
    2458.             timePassed.Seconds = Critter.TIME_PASSED_BEGIN;
    2459.  
    2460.             Reset(ref triggers);
    2461.         }
    2462.  
    2463.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    2464.         private void ActivatePlan(
    2465.             ref CritterActionComponent actionComponent,
    2466.             CritterAction action,
    2467.             ref CritterTimeRequiredComponent timeRequired,
    2468.             float duration
    2469.         )
    2470.         {
    2471.             PerformAction(ref actionComponent, action);
    2472.  
    2473.             timeRequired.Seconds = duration;
    2474.         }
    2475.  
    2476.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    2477.         private void PerformAction(
    2478.             ref CritterActionComponent component,
    2479.             CritterAction action
    2480.         )
    2481.         {
    2482.             component.Doing |= action;
    2483.         }
    2484.  
    2485.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    2486.         private void PerformAction(
    2487.             ref CritterActionComponent component,
    2488.             CritterAction action,
    2489.             bool perform
    2490.         )
    2491.         {
    2492.             component.Doing |= (CritterAction)math.select(0, (int)action ,perform);
    2493.         }
    2494.  
    2495.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    2496.         private bool Triggered(CritterTriggerComponent triggers)
    2497.         {
    2498.             return triggers.Data != CritterTrigger.None;
    2499.         }
    2500.  
    2501.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    2502.         private void Reset(ref CritterTriggerComponent triggers)
    2503.         {
    2504.             triggers.Data = CritterTrigger.None;
    2505.         }
    2506.  
    2507.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    2508.         private void AlignWithFormation(
    2509.             ref LocalTransform transform,
    2510.             CritterFormationFollowerComponent formationFollower
    2511.         )
    2512.         {
    2513.             var officerYRotation = formationFollower.OfficerTransform.Rotation.YawDegrees();
    2514.             var thisYRotation = transform.Rotation.YawDegrees();
    2515.  
    2516.             if (Hint.Unlikely(
    2517.                officerYRotation.AngleDifferenceWithDegrees(thisYRotation)
    2518.                > formationFollower.AngleFromFormationBeforeAlignment
    2519.             ))
    2520.             {
    2521.                 PositionActions.RotateTo(
    2522.                     ref transform,
    2523.                     formationFollower.OfficerTransform.Rotation
    2524.                 );
    2525.             }
    2526.         }
    2527.     }
    2528.