[Bug] PathTracer.Repair null reference exception when using Follower Entity and Behavior Designer

  • A* version: 5.3.1
  • Unity version: 6.0.32

Hi everyone, I discovered a non-game breaking null reference exception when using Astar that may be related to Behavior Designer’s Seek task. When using a simple agent with the Follower Entity and Seeker components and a Behavior Tree running a simple Seek task, in a simple scene with a Recast graph, at some point the following error pops up :

[Exception] NullReferenceException: Object reference not set to an instance of an object
PathTracer.Repair() at ./Packages/com.arongranberg.astar/Utilities/PathTracer.cs:575
 573:  if (isStart) {
 574:     partIndex = this.firstPartIndex;
--> 575:     currentIndexInPath = parts[partIndex].startIndex;
 576:     currentNode = nodes.GetAbsolute(currentIndexInPath);
 577:     samePoint = unclampedStartPoint == point;

PathTracer.UpdateStart() at ./Packages/com.arongranberg.astar/Utilities/PathTracer.cs:313
 311:  /// </summary>
 312:  public Vector3 UpdateStart (Vector3 position, RepairQuality quality, NativeMovementPlane movementPlane, ITraversalProvider traversalProvider, Path path) {
--> 313:     Repair(position, true, quality, movementPlane, traversalProvider, path);
 314:     return parts[firstPartIndex].startPoint;
 315:  }

FollowerEntity.SetPath() at ./Packages/com.arongranberg.astar/Core/AI/FollowerEntity.cs:1874
1872:  // This remaining part ensures that the path tracer is fully up to date immediately after the path has been assigned.
1873:  // So that things like GetRemainingPath, and various properties like reachedDestination are up to date immediately.
-->1874:  managedState.pathTracer.UpdateStart(localTransform.Position, PathTracer.RepairQuality.High, movementPlane.value, managedState.pathfindingSettings.traversalProvider, managedState.activePath);
1875:  managedState.pathTracer.UpdateEnd(destination.destination, PathTracer.RepairQuality.High, movementPlane.value, managedState.pathfindingSettings.traversalProvider, managedState.activePath);

FollowerEntity.SetPath() at ./Packages/com.arongranberg.astar/Core/AI/FollowerEntity.cs:1807
1805:  /// <param name="updateDestinationFromPath">If true, the \reflink{destination} property will be set to the end point of the path. If false, the previous destination value will be kept.
1806:  ///     If you pass a path which has no well defined destination before it is calculated (e.g. a MultiTargetPath or RandomPath), then the destination will be first be cleared, but once the path has been calculated, it will be set to the end point of the path.</param>
-->1807:  public void SetPath(Path path, bool updateDestinationFromPath = true) => SetPath(entity, path, updateDestinationFromPath);
1809:  /// <summary>

FollowerEntity.SearchPath() at ./Packages/com.arongranberg.astar/Core/AI/FollowerEntity.cs:1687
1685:     var path = ABPath.Construct(position, dest, null);
1686:     path.UseSettings(managedState.pathfindingSettings);
-->1687:     SetPath(path, false);
1688:  }

IAstarAIMovement.SetDestination() at /Behavior Designer Movement/Integrations/Astar Pathfinding Project/Tasks/IAstarAIMovement.cs:35
  33:      agent.canMove = true;
  34:      agent.destination = target;
-->  35:      agent.SearchPath();
  36:      return true;
  37:  }

Seek.OnStart() at /Behavior Designer Movement/Integrations/Astar Pathfinding Project/Tasks/Seek.cs:21
  19:      base.OnStart();
-->  21:      SetDestination(Target());
  22:  }

BehaviorManager.PushTask() at <eed7427f31054735b37e5687df728aa5>:0

BehaviorManager.RunTask() at <eed7427f31054735b37e5687df728aa5>:0

BehaviorManager.RunParentTask() at <eed7427f31054735b37e5687df728aa5>:0

BehaviorManager.RunTask() at <eed7427f31054735b37e5687df728aa5>:0

BehaviorManager.Tick() at <eed7427f31054735b37e5687df728aa5>:0

BehaviorManager.Tick() at <eed7427f31054735b37e5687df728aa5>:0

BehaviorManager.Update() at <eed7427f31054735b37e5687df728aa5>:0

I have not tested all of the possible combinations, but I’m positive that it happens when using this specific combination. So far I haven’t been able to reproduce the error when replacing the Behavior Tree by a simple script setting the destination in Update. Here is a video as always to show the issue :

https://youtu.be/ENSeMC50GqI?si=2DqImm_8Z4Y0TrK9

I hope this is useful and that this can be taken a look at, I’ll make the same post on the Opsive forum, thanks.

Thanks for that info! Feel free to also link your post from the Opsive forum as well :+1:

Hi, something is preventing me from posting on the Opsive forum but I have notified Justin of this. So far my only guess is that the issue may come from how BD is updated, but I’m really not sure about this. I’ll let you know if I find anything.

Hey, quoting Justin here "That code is giving an exception within A* so it does look like it is something related to that. The Movement Pack is setting the destination and then telling the agent to start to pathfind, so that code is pretty basic and I don’t believe there is another way to do that.

It could be the order of operations when the task runs versus within a different script."

I’ll try experimenting with different update types and script execution orders.

Hi

I think this might have been caused by a race condition: the path finishes its calculations during the execution of the SetPath method. I’ll include a fix for this in the next update.

I take it this error was pretty rare?

Btw. You can let Justin know that calling ai.SearchPath immediately after setting the destination is not optimal for performance, at least when using the FollowerEntity component. If users are setting the destination every frame, that could lead to a lot of path calculations.

Thanks Aron ! The error occurred irregularly, sometimes it happened quite soon, sometimes happened after a while or not at all, especially when trying to make recordings of it :smiling_face_with_tear:

I told Justin about this and made a note of this for my personal work, thanks.