EntityAccess throws Assertions if reference to FollowerEntity gets anything called on a destroyed GameObject

Due to nature of the way Unity destroys an Entity in ECS versus MonoBehaviours, the EntityStorageInfo property “storage” within FollowerEntity can throw an AssertionException if the GameObject the FollowerEntity script was attached to was already destroyed.

The exact assertion is here, in the specific case of SetDestination being called after Destroy was called on the object. This is only one of several methods that have the same issue. Anytime a script with a reference to the FollowerEntity calls SetDestination, SetPath etcetera, the same frame or later the GameObject was called in Destroy, it will throw something like this. AssertionException: out-of-range indexInArchetype passed to GetChangeVersionArra - Pastebin.com

We have done a thorough investigation and eventually understood a workaround that we implemented in our own codebase and thought it best to let you know you may need to implement it as well.

This exception can get thrown by methods that access storage such as:
SetDestination (line 947 as of 5.1.1)
SetPath (line 1567 as of 5.1.1)

and anything else using an EntityAccess to run its functions.

The workaround considers if the EntityAccess still exists, as when the GameObject is destroyed, if some other script calls to the function, it could be the ECS had already unloaded all of the Components on the Archetype first, even though a reference in some other MonoBehaviour still has FollowerEntity hooked. This allows FollowerEntity to always get index out of range anytime it tries to call a component in the context of the ECS, as the Archetype returned empty. We need to avoid this by checking the components still exist before attempting an access.

Our workaround was to insert a line such as this to make sure the function doesn’t try to call if the component no longer exists on the entity. But we believe your codebase should be able to come up with something more usable than this, and something more knowledgable of object destruction, such as writing your own DestroyThis method instead of letting unity do it, which we recommend, as it seems we’re thread racing ECS at the moment.

if (destinationPointAccessRW.HasComponent(storage))
return;

seemed to work for us but the problem is, this error gets thrown literally anywhere EntityAccess tries to GetComponent at random times, as it seems ECS removes components on a totally different thread. we could choose from any RW at this point, as long as the check for one component of any access aborts before assertion.

Sorry for all the edits. All the info is here for you now. Hope to hear from you soon.

We’ve ended up having to change how objects with BehaviourDesigner integration get destroyed before changing Scenes, as the Assertions seem to be crashing build. We didn’t think BehaviourDesigner integration had anything to do with it before but now we seem to believe this.

The idea is, BehaviourDesigner gets destroyed too late. The Archetype in ECS World might already be destroyed before the integration package tries to SetPath(null), or SearchPath().

These still should be avoided by making sure these methods for EntityAccess are thread safe, and null safe. But for now we’re working around it by making sure BehaviourTrees are all stopped and disabled before changing scenes

I’ve the same setup (a* follower with BD and topdownengine).
I’ve an error (not an assert exception) in BD that try to call setpath but the target Is null. I’ve just changed bd action to check if the value Is null before setpath.
But i’m glad to not be able to reproduce your error…however to be safe i’ll make a check as your

We can confirm that the assertions were causing the crashes in build due to DLL processes. We would appreciate this getting fixed.

We also have an EXCEPTION_ACCESS_VIOLATION related to the issue on the method for ClearPath in the FollowerEntity. Something over the fact BD runs on its own DLL process, so it absolutely must be a thread race condition.

We have some issues like this too - it is due to the Stop of the behavior tree task being called when the scene is being turned down, etc.

So the exception gets thrown when setting path or disabling rotation but the exception is not fatal. So we just ended up wrapping it in try/catch to silence the exception