T3D 1.1 Final - zoneRemove Crash
by Nathan Bowhay - ESAL · in Torque 3D Professional · 06/27/2011 (1:54 pm) · 6 replies
I have a custom class I made that is client side only and inherits from StaticShape. I use it much like a camera. Only it isn't part of the mission.
It is loaded in clientStartMission and if they already exist they aren't created again. I also make sure they aren't added to the mission cleanup. Basically there is no point in removing them since they need to be consistent across missions.
When I close torque though (after the upgrade from T3D Beta 3 to T3D 1.1) it crashes when calling _zoneRemove on line 442 of sceneZoneSpaceManager.cpp when it passes in one of the custom class objects. In Vector<T>::remove when begin() is called is exactly where it happens.
Is there any special thing I need to do to remove an object with the new zone system? I don't think this needs to be added to it and am not sure if it is or isn't.
If you need anymore details I can give them. I am going to debug it some more, but always like to post here first just in case someone is having the same issue or someone has some incite into it.
Note: This is most likely just some issue with the way I am handling the creation and removal of the objects so I'm not posting this as a bug in T3D 1.1, but who knows it could be one.
It is loaded in clientStartMission and if they already exist they aren't created again. I also make sure they aren't added to the mission cleanup. Basically there is no point in removing them since they need to be consistent across missions.
When I close torque though (after the upgrade from T3D Beta 3 to T3D 1.1) it crashes when calling _zoneRemove on line 442 of sceneZoneSpaceManager.cpp when it passes in one of the custom class objects. In Vector<T>::remove when begin() is called is exactly where it happens.
Is there any special thing I need to do to remove an object with the new zone system? I don't think this needs to be added to it and am not sure if it is or isn't.
If you need anymore details I can give them. I am going to debug it some more, but always like to post here first just in case someone is having the same issue or someone has some incite into it.
Note: This is most likely just some issue with the way I am handling the creation and removal of the objects so I'm not posting this as a bug in T3D 1.1, but who knows it could be one.
#2
To make sure that everything is deleted. I call that on the head SimSet and then call delete on the head SimSet so it is removed. After doing this in onExit I still have the crash. I wasn't sure if that was the appropriate place to put it, but I can't put it in any of the clientEndMission calls cause that happens every time a mission is loaded.
The objects are created in script and just executes a script file, much like a mission file (using new) and the only real change in engine is the flags so it's client side only:
As for it being added and remove from the scene, I call the parent methods in onAdd and onRemove:
So Static shape should be called and taking care of that, so I don't think there is any need to use the module system?
Only real change I do to make sure it isn't added to the mission group is call pushInstantGroup(); and popInstantGroup(); with the exec call in the middle.
Lastly, here is the call stack:
06/28/2011 (11:54 am)
It is removed onExit() in gamescriptsmain.cs before the destroyServer and disconnect call is made. At first they weren't being removed at all by any of my code and either torque was taking care of it or something because there was no issue in (T3D 1.1 Beta 3). After running into this issue in the upgrade I figure it should probably be removed. They are all added to SimSets (categories) and then those are added to a SimSet. I was just going to call delete on the head SimSet, but it doesn't look like that deletes the children. Neither does clear (anymore). So I just made a script function:function SimSet::deleteRecursive(%this)
{
for(%i = 0; %i < %this.getCount(); %i++)
{
%obj = %this.getObject(%i);
if(%obj.isClass("SimSet"))
{
%obj.deleteRecursive();
}
%obj.delete();
}
}To make sure that everything is deleted. I call that on the head SimSet and then call delete on the head SimSet so it is removed. After doing this in onExit I still have the crash. I wasn't sure if that was the appropriate place to put it, but I can't put it in any of the clientEndMission calls cause that happens every time a mission is loaded.
The objects are created in script and just executes a script file, much like a mission file (using new) and the only real change in engine is the flags so it's client side only:
mNetFlags.clear(Ghostable | ScopeAlways); mNetFlags.set(IsGhost);So I'm like 99.9% sure it's registered just like any other StaticShape.
As for it being added and remove from the scene, I call the parent methods in onAdd and onRemove:
bool ESALGameBase::onAdd()
{
if(mDataBlock)
if (isClientObject())
if (!onNewDataBlock(mDataBlock, true))
return false;
if(!Parent::onAdd() || !mDataBlock)
return false;
Con::executef(mDataBlock, "onAdd", getIdString());
return true;
}
void ESALGameBase::onRemove()
{
if ( !isRemoved() && mDataBlock )
Con::executef(mDataBlock, "onRemove", getIdString());
Parent::onRemove();
}So Static shape should be called and taking care of that, so I don't think there is any need to use the module system?
Only real change I do to make sure it isn't added to the mission group is call pushInstantGroup(); and popInstantGroup(); with the exec call in the middle.
Lastly, here is the call stack:
> ESALVis_DEBUG.dll!Vector<SceneObject *>::begin() Line 524 + 0x3 bytes C++ ESALVis_DEBUG.dll!Vector<SceneObject *>::remove(SceneObject * const & x=0x0e70f508) Line 392 + 0x8 bytes C++ ESALVis_DEBUG.dll!SceneZoneSpaceManager::unregisterObject(SceneObject * object=0x0e70f508) Line 442 C++ ESALVis_DEBUG.dll!SceneManager::removeObjectFromScene(SceneObject * obj=0x0e70f508) Line 535 C++ ESALVis_DEBUG.dll!SceneObject::removeFromScene() Line 330 C++ ESALVis_DEBUG.dll!StaticShape::onRemove() Line 202 C++ ESALVis_DEBUG.dll!ESALGameBase::onRemove() Line 65 C++ ESALVis_DEBUG.dll!ViewportProfile::onRemove() Line 122 C++ ESALVis_DEBUG.dll!SimObject::unregisterObject() Line 544 C++ ESALVis_DEBUG.dll!SimObject::_destroySelf() Line 578 C++ ESALVis_DEBUG.dll!EngineObject::destroySelf() Line 85 C++ ESALVis_DEBUG.dll!SimObject::deleteObject() Line 564 C++ ESALVis_DEBUG.dll!SimGroup::clear() Line 759 C++ ESALVis_DEBUG.dll!SimGroup::onRemove() Line 735 C++ ESALVis_DEBUG.dll!SimObject::unregisterObject() Line 544 C++ ESALVis_DEBUG.dll!SimObject::_destroySelf() Line 578 C++ ESALVis_DEBUG.dll!EngineObject::destroySelf() Line 85 C++ ESALVis_DEBUG.dll!SimObject::deleteObject() Line 564 C++ ESALVis_DEBUG.dll!Sim::shutdownRoot() Line 290 C++ ESALVis_DEBUG.dll!Sim::shutdown() Line 557 C++ ESALVis_DEBUG.dll!`anonymous namespace'::_Sim::_ModuleInst::shutdown() Line 30 C++ ESALVis_DEBUG.dll!ModuleManager::shutdownSystem() Line 354 C++ ESALVis_DEBUG.dll!StandardMainLoop::shutdown() Line 298 C++ ESALVis_DEBUG.dll!torque_engineshutdown() Line 136 C++ ESALVis_DEBUG.dll!TorqueMain(int argc=1, const char * * argv=0x02811ea0) Line 413 C++ ESALVis_DEBUG.dll!torque_winmain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * __formal=0x00000000, char * lpszCmdLine=0x006640c6, HINSTANCE__ * __formal=0x00000000) Line 481 + 0x17 bytes C++ ESALVis_DEBUG.exe!WinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, char * lpszCmdLine=0x006640c6, int nCommandShow=1) Line 48 + 0x16 bytes C++ ESALVis_DEBUG.exe!__tmainCRTStartup() Line 275 + 0x2c bytes C ESALVis_DEBUG.exe!WinMainCRTStartup() Line 189 C kernel32.dll!BaseThreadInitThunk() + 0xe bytes [Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll] ntdll.dll!RtlCreateUserProcess() + 0x8c bytes ntdll.dll!RtlCreateProcessParameters() + 0x4e bytes
#3
That's correct behavior. SimSets actually do not own their objects, SimGroups do (i.e. they will delete stuff when you call clear() or when they are themselves deleted).
That's actually not correct :) Iteration over SimSets isn't stable, so if you delete objects while you iterate over the set, object indices will shift around behind your back. In essence, you're skipping every other object. Use
instead.
So this one's painting a different picture actually :)
From the stack trace, it's clear that your object is still around when the engine shuts down and is cleaned up as part of the "Sim" system shutdown, i.e. when RootGroup is deleted. At that point, the scene and zoning systems have already been shut down, so you get a crash.
06/30/2011 (12:21 am)
Sorry, for the delay. Forgot about this for a moment.Quote:I was just going to call delete on the head SimSet, but it doesn't look like that deletes the children. Neither does clear (anymore).
That's correct behavior. SimSets actually do not own their objects, SimGroups do (i.e. they will delete stuff when you call clear() or when they are themselves deleted).
Quote:
function SimSet::deleteRecursive(%this)
{
for(%i = 0; %i < %this.getCount(); %i++)
{
%obj = %this.getObject(%i);
if(%obj.isClass("SimSet"))
{
%obj.deleteRecursive();
}
%obj.delete();
}
}
That's actually not correct :) Iteration over SimSets isn't stable, so if you delete objects while you iterate over the set, object indices will shift around behind your back. In essence, you're skipping every other object. Use
while( %this.getCount() > 0 )
{
%obj = %this.getObject( 0 );
/* ... */;
%obj.delete();
}instead.
Quote:Lastly, here is the call stack:
So this one's painting a different picture actually :)
From the stack trace, it's clear that your object is still around when the engine shuts down and is cleaned up as part of the "Sim" system shutdown, i.e. when RootGroup is deleted. At that point, the scene and zoning systems have already been shut down, so you get a crash.
#4
So if I remove the objects in the beginning of onExit will those systems have been shut down already?
If so where would you recommend doing it?
07/11/2011 (4:10 pm)
yeah should have thought about my delete. Stupid mistake :)So if I remove the objects in the beginning of onExit will those systems have been shut down already?
If so where would you recommend doing it?
#5
"onExit" will be called before the engine really starts shutting down, so you're just fine there.
07/11/2011 (4:17 pm)
Quote:So if I remove the objects in the beginning of onExit will those systems have been shut down already?
If so where would you recommend doing it?
"onExit" will be called before the engine really starts shutting down, so you're just fine there.
#6
Also good to know why it didn't cause any issues before, and does now.
Removing the SimSets sitting around before the systems may be better than after. Not sure though, may be some good reasoning behind doing it after. Also it is probably best to remove them manually like I am (clean up is good).
07/12/2011 (12:10 pm)
Ok that fixed it. As always, thanks for the help!Also good to know why it didn't cause any issues before, and does now.
Removing the SimSets sitting around before the systems may be better than after. Not sure though, may be some good reasoning behind doing it after. Also it is probably best to remove them manually like I am (clean up is good).
Associate Rene Damm
A StaticShape will automatically add itself to the scene when registered (onAdd()) and automatically remove itself when unregistered (onRemove()). If the latter thing happens before scene system shutdown runs, things should be fine. The easiest way to ensure that for stuff that is permanently injected into scenes is via the module system. See decalManager.cpp for an example.
Lastly, could you post a quick snapshot of the stack when it comes down?