Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Bug / Crash  Destroying objects improperly?
#1
Edit: I consistently crash now even before I destroy any of the objects I describe below, so there must be something else (or additional) going on. See next post as well.
----------------------

I'm trying to use the Obi Cloth asset for simulations on two different objects in my game.

One of them is statically created in the editor and built directly into the scene.  I'm really happy with how these look so far, and I had no problem at that point.

However, one of them is dynamically created, and when I started trying to run my game after I got it set up to use Obi Cloth for this object, it started crashing my game, seemingly at random.

I've been chasing this down for about 3 days: I've updated Unity, updated Visual Studio, rebooted several times, read through your forums, looked at log files from Unity and the crashes, and so on.  I've come to believe the problem has to do with destroying one of these dynamically instantiated prefabs.

I've got this prefab set up with everything my static objects have except for the Obi Solver, which I assign when the object is created.  The solver in the gameMaster singleton is the same one I am using for the static objects:

Code:
protected void Start()
{
   obiCloth = GetComponentInChildren<ObiCloth>();
   obiCloth.Solver = gameMaster.obiSolver;
}



Several of the Unity logs right before the crash have references to the \Obi\Scripts\Actors\ObiActor.cs script at line 474:
Code:
// check if any of the involved transforms has changed since last time:
if (!transform.hasChanged && !Solver.transform.hasChanged)
   return;


When I found this, I thought, okay, maybe this is as simple as just some kind of object destruction race condition and I can fix it with a couple easy changes.  I turned the previous code into this: 

Code:
if (null == Solver || null == transform || null == Solver.transform) {
   return;
}

// check if any of the involved transforms has changed since last time:
if (!transform.hasChanged && !Solver.transform.hasChanged)
   return;

and then added this to top of the OnDestroy() call on the object being destroyed:
Code:
obiCloth.RemoveFromSolver(null);
obiCloth.Solver = null;



However, I'm still getting crashes, so I wonder if there is something I am missing about the proper methodology for destroying an actively simulated ObiActor.  I've looked around on the tutorials page and don't see anything about destroying objects, even though there is information about spawning them.  I looked around in the API docs, but they're not very helpful - for instance, what are the (object item) parameters I see in there?  I had to google "obi removefromsolver" to find out I could just pass null to the ObiActor.RemoveFromSolver() function by looking at some other piece of sample code you have on the site.

Here is the error that I'm sure is precipitating the latest crash I had that is still referencing the null checks I added in the code block above.  See the 5th line, the first call to Obi.ObiActor.OnSolverStepBegin() line 473:
Code:
NullReferenceException: Object reference not set to an instance of an object
 at UnityEngine.Object.IsNativeObjectAlive (UnityEngine.Object o) [0x0001d] in C:\buildslave\unity\build\Runtime\Export\UnityEngineObject.bindings.cs:179
 at UnityEngine.Object.CompareBaseObjects (UnityEngine.Object lhs, UnityEngine.Object rhs) [0x0003a] in C:\buildslave\unity\build\Runtime\Export\UnityEngineObject.bindings.cs:141
 at UnityEngine.Object.op_Equality (UnityEngine.Object x, UnityEngine.Object y) [0x00003] in C:\buildslave\unity\build\Runtime\Export\UnityEngineObject.bindings.cs:401
 at Obi.ObiActor.OnSolverStepBegin () [0x00019] in D:\unity\projects\Tapestry\Tapestry\Assets\Obi\Scripts\Actors\ObiActor.cs:473
 at Obi.ObiCloth.OnSolverStepBegin () [0x00014] in D:\unity\projects\Tapestry\Tapestry\Assets\Obi\Scripts\Actors\ObiCloth.cs:564
 at Obi.ObiSolver.SimulateStep (System.Single stepTime) [0x00052] in D:\unity\projects\Tapestry\Tapestry\Assets\Obi\Scripts\Solver\ObiSolver.cs:545
 at Obi.ObiSolver.LateUpdate () [0x00056] in D:\unity\projects\Tapestry\Tapestry\Assets\Obi\Scripts\Solver\ObiSolver.cs:775

I'm not sure what sorcery goes on in the manipulation of your backend C++ objects in the Unity C# code, but that "IsNativeObjectAlive" call sure looks like there's something going wrong in the destruction of this object that isn't letting the ObiSolver know that it can forgo simulating the object in this frame when it's about to die.  The crash always immediately follows this NullReferenceException error in OnSolverStepBegin().

The question is: Am I doing something wrong in how I'm either allocating or destroying the gameobject which is causing this, or is it a bug in the ObiCloth/ObiActor/ObiSolver code somewhere?

While we're on the topic, I have a question about when I'm instantiating the object and getting it to run.  In the same ObiActor code, it looks like the object gets added to the Obi Solver here:
Code:
public virtual void Start(){
   if (Application.isPlaying)
       AddToSolver(null);
}

I don't see anywhere else when the solver gets assigned that this would happen:
Code:
public ObiSolver Solver{
   get{return solver;}
   set{
       if (solver != value){
           RemoveFromSolver(null);
           solver = value;
       }
   }
}

So I'm probably just getting lucky that this race condition between my object's Start() and the ObiCloth() start hasn't bitten me.  It looks like my code should actually be:

Code:
protected void Start()
{
   obiCloth = GetComponentInChildren<ObiCloth>();
   obiCloth.Solver = gameMaster.obiSolver;            
   obiCloth.AddToSolver(null);
}

Correct?


Thanks ahead of time for your help!

Quick edit: Everything works fine until the game crashes - the dynamically instantiated object is simulated the way I expect it to be, the static ones are still working, etc. The game sometimes crashes in 15 seconds, sometimes in 10 minutes, and everywhere in between. This is why I suspect a race condition.
Reply
#2
The plot thickens.  I've started playing around with adding ObiColliders to some of my colliders, and now I can consistently get a crash even before I destroy any of the dynamically allocated objects...  which means my original notion can't be right (or at least, that can't be the *only* thing going wrong here).

Now I can look at the output log file from the crash and it's filled with these errors right before it crashes:

Code:
NullReferenceException
 at (wrapper managed-to-native) UnityEngine.Transform.get_worldToLocalMatrix_Injected(UnityEngine.Transform,UnityEngine.Matrix4x4&)
 at UnityEngine.Transform.get_worldToLocalMatrix () [0x00000] in <92788fe27a4c4d2ea20688e1a1d667c8>:0
 at Obi.ObiCloth.get_ActorWorldToLocalMatrix () [0x00012] in D:\unity\projects\Tapestry\Tapestry\Assets\Obi\Scripts\Actors\ObiCloth.cs:71
 at Obi.ObiClothBase.OnSolverPreInterpolation () [0x00008] in D:\unity\projects\Tapestry\Tapestry\Assets\Obi\Scripts\Actors\ObiClothBase.cs:168
 at Obi.ObiSolver.EndFrame (System.Single stepTime) [0x0001c] in D:\unity\projects\Tapestry\Tapestry\Assets\Obi\Scripts\Solver\ObiSolver.cs:566
 at Obi.ObiSolver.LateUpdate () [0x00091] in D:\unity\projects\Tapestry\Tapestry\Assets\Obi\Scripts\Solver\ObiSolver.cs:786

Another interesting note:

When I add a new ObiSolver to the prefab so that I don't have to do the ObiSolver assignment myself once the object is instantiated, I no longer seem to crash.
Reply