Help with debugging an engine crash...
by Kirby Webber · in Torque Game Engine · 12/31/2005 (10:56 am) · 7 replies
I'll get straight to it.
Caveats:
Engine: Torque version 1.4 (modified)
OS: Windows XP Home
Compiler: MS Visual Studio.net 2003
Working from a heavily modified version of Starter.Racing
Player Objects are Hovers
========================================
The issue(s):
I've been noticing some strange behaviors with my game currently.
The first indication that something wasn't quite right was the occasional multiple calls to gameConnection::onDeath() in the server/scripts/game.cs file (I'll post my particular version in a moment.)
When the player dies, the vehicles' ::damage() function makes a call to ::onDeath(), which is the ONLY reference to this function anywhere in the scrits.
You can imagine my suprise when it seemd to get called 2 and in some cases, even 3 times!
The function seems to execute properly, increminting/ decrementing scores and sending messages to the clients, but just does so more than it should.
Here's the script code for HoverVehicle::Damage() and gameBase::onDeath():
HoverVehicle::damage()
gameBase::onDeath()
Caveats:
Engine: Torque version 1.4 (modified)
OS: Windows XP Home
Compiler: MS Visual Studio.net 2003
Working from a heavily modified version of Starter.Racing
Player Objects are Hovers
========================================
The issue(s):
I've been noticing some strange behaviors with my game currently.
The first indication that something wasn't quite right was the occasional multiple calls to gameConnection::onDeath() in the server/scripts/game.cs file (I'll post my particular version in a moment.)
When the player dies, the vehicles' ::damage() function makes a call to ::onDeath(), which is the ONLY reference to this function anywhere in the scrits.
You can imagine my suprise when it seemd to get called 2 and in some cases, even 3 times!
The function seems to execute properly, increminting/ decrementing scores and sending messages to the clients, but just does so more than it should.
Here's the script code for HoverVehicle::Damage() and gameBase::onDeath():
HoverVehicle::damage()
function HoverVehicleData::damage(%this, %obj, %sourceObject, %position, %damage, %damageType)
{
%obj.applyDamage(%damage);
// Deal with client callbacks here because we don't have this
// information in the onDamage or onDisable methods
%client = %obj.client;
%sourceClient = %sourceObject ? %sourceObject.client : 0;
//if player is dead, kill him!
if (%obj.getDamageLevel() $= %this.maxDamage)
{
//change the player state to "Destroyed
%obj.setDamageState(Destoryed);
// Release the main weapon trigger
%obj.setTrigger(0,false); //<------ this is a problem ***************
//Inform the server that the client is dead
%client.onDeath(%sourceObject, %sourceClient, %damageType, %location);
// Schedule corpse, turret and trigger removal.
%obj.mountedTurret1.schedule(100, "startFade", 400, 0, true);
%obj.mountedTurret2.schedule(100, "startFade", 400, 0, true);
%obj.schedule(100, "startFade", 400, 0, true);
//delete the trigger objects from the turrets
%trigger1 = %obj.mountedTurret1.getTrigger();
%trigger2 = %obj.mountedTurret2.getTrigger();
%trigger1.schedule(500, "delete");
//%trigger2.schedule(500, "delete");
//delete the turret
%obj.mountedTurret1.schedule(500, "delete");
%obj.mountedTurret2.schedule(500, "delete");
//delete the bike
%obj.schedule(1000, "delete");
//clear the user HUD
userDisplay.visible = false;
}
}note: I have implemented Paul Dana's turret resource in 1.4 - the turret % trigger references apply to AITurrets that are mounted to the vehicles, though this behavior predates their inclusion and has happened in engine versions predating 1.3 (just never got around to it - the engine crashes (outlined below) didn't happen though, so it may be relevant.)gameBase::onDeath()
function GameConnection::onDeath(%this, %sourceObject, %sourceClient, %damageType)
{
// Clear out the name on the corpse
%this.bike.setShapeName("");
// Switch the client over to the death cam and unhook the player object.
if (isObject(%this.camera) && isObject(%this.bike)) {
%this.camera.setMode("Corpse",%this.bike);
%this.setControlObject(%this.camera);
}
%this.bike = 0;
// Assign points and display an appropriate message
if (%damageType $= "Suicide" || %sourceClient == %this) {
%this.incScore(-1);
messageAll('MsgClientKilled','%1 needs training wheels.',%this.name);
}
else {
messageAll('MsgClientKilled','%1 gets nailed by %2!',%this.name,%sourceClient.name);
if (%sourceClient.score >= $Game::EndGameScore)
cycleGame();
}
}
#2
I just realized that, by default, 1.4 is configured to compile a release build, which is why my debugging attempts have not been more fruitful.
Strange, seems that previous versions were setup to complile debug by default.
Oh well... back to the drawing board.
12/31/2005 (11:21 am)
~=\I just realized that, by default, 1.4 is configured to compile a release build, which is why my debugging attempts have not been more fruitful.
Strange, seems that previous versions were setup to complile debug by default.
Oh well... back to the drawing board.
#3
First, I set the VS config to compile a debug build... which didn't work out well for me.
Evertime I tried to step into debug mode, I got an error stating that it couldn't locate the canvas. =\
Ah well.
It did occur to me though, that if the problem were in the source code, it should be happening in the starter.fps as well, which it isn't.
That led me back to script... and I thought it was about time to start using the telnetDebugger in all it's glory.
I installed Torsion (yeah, yeah, I know NOW that I've been scripting with one are tied behind my back, but I can be thick sometimes) and got to debugging.
Turns out, my comment in my ::damage() script was dead on.
Turns out, that line was causing the crash, or at least seems to have been.
I replaced it with this:
DUH! I'm not mounting a weapon image to the vehicle, rather two AITurrt OBJECTS that needed to be addressed explicitly.
So far, testing is proving that this works - although I still get the occasional double ::onDeath() call.
If I find a fix, I'll post it... I know I'm not the only one who's had (or is having) this particular problem. =)
~Cheers
12/31/2005 (12:53 pm)
Working through it all step by step and posting results for posterity - you never know when this kind of thing could be helpful in a forum search a year from now. (C;First, I set the VS config to compile a debug build... which didn't work out well for me.
Evertime I tried to step into debug mode, I got an error stating that it couldn't locate the canvas. =\
Ah well.
It did occur to me though, that if the problem were in the source code, it should be happening in the starter.fps as well, which it isn't.
That led me back to script... and I thought it was about time to start using the telnetDebugger in all it's glory.
I installed Torsion (yeah, yeah, I know NOW that I've been scripting with one are tied behind my back, but I can be thick sometimes) and got to debugging.
Turns out, my comment in my ::damage() script was dead on.
// Release the main weapon trigger
%obj.setTrigger(0,false); //<------ this is a problem ***************Turns out, that line was causing the crash, or at least seems to have been.
I replaced it with this:
// Release the main weapon triggers
%obj.mountedTurret1.setImageTrigger(0, false);
%obj.mountedTurret2.setImageTrigger(0, false);DUH! I'm not mounting a weapon image to the vehicle, rather two AITurrt OBJECTS that needed to be addressed explicitly.
So far, testing is proving that this works - although I still get the occasional double ::onDeath() call.
If I find a fix, I'll post it... I know I'm not the only one who's had (or is having) this particular problem. =)
~Cheers
#4
12/31/2005 (6:52 pm)
Cool, I'm glad you found a resolution. :)
#5
01/01/2006 (1:29 pm)
Well, there are still a few bugs, particularly when it comes time to delete the corpses, but at this point I'm pretty sure it has something to do with syntax and the order in which I delete the objetcs (since I have two AITurret objects mounted) but I'll get it figured out. (=
#6
Fixed multiple ::onDeath() calls by extending the test criteria for the ::Damage() function...
changed to:
Basically, anytime a second impact immediately after the imapct that killed the plaeyr object, it registered a new call to ::onDeath() - testing for the damage state as well as damage level resolves this. =)
01/03/2006 (9:35 am)
Update:Fixed multiple ::onDeath() calls by extending the test criteria for the ::Damage() function...
if (%obj.getDamageLevel() $= %this.maxDamage)
changed to:
if (%obj.getDamageLevel() $= %this.maxDamage && %obj.getDamageState $= "Enabled")
Basically, anytime a second impact immediately after the imapct that killed the plaeyr object, it registered a new call to ::onDeath() - testing for the damage state as well as damage level resolves this. =)
#7
I realized that I was being a bit heavy handed in my approach to handling the turrets on killing off the player entity.
Basically, I already had functions in the turret.cs file built to deal with all of this.
By removing all fade, delete and MissionCleanup.add calls from my vehicle scripts, I saw an end to the engine crashes as well as error free execution in the console. (Still had to release the triggers though. =)
I hope this helps someone else someday.
01/04/2006 (10:27 am)
Thought I'd polish this thread off for posterity.I realized that I was being a bit heavy handed in my approach to handling the turrets on killing off the player entity.
Basically, I already had functions in the turret.cs file built to deal with all of this.
By removing all fade, delete and MissionCleanup.add calls from my vehicle scripts, I saw an end to the engine crashes as well as error free execution in the console. (Still had to release the triggers though. =)
I hope this helps someone else someday.
Torque Owner Kirby Webber
From there, I set out to find out why and began a process of organized testing, whihc is when I discovered that the issues plaguing my project currently, run a bit deeper than script - or at least, think they do.
During a series of tests, I began to encounter engine crashes.
At first, they appeared to have no discernable rhyme or reason, but further testing proved otherwise. (Or, again, at least I think... heh.)
When I recieved the error prompt (from Windows XP), I selected debug which promptly gave me the following error:
... so like a good programmer, I told it to break (since 'continue' only reverted to the same error.
Looking through the dissasembly, VS flagged the following line, in keeping with the previous error:
Now, EAX immediately screamed sound in my head, so I figured this was something to do with OpenAL and the sounds I was running.
In order to be thorough, I commented out all of the sounds I was using.
To be clear, the profiles and datablocks are still there, I just commented out any calls to them from my vehicle datablocks.
The next test surprised me... perfectly quiet, no sound, and still a crash! Furthermore, selecting debug revealed the exact same error!?
WTF?!
Ahhh, but the plot thickens...
Here's my testing data:
First round of testing
============================
First Death: no vehicle triggers active
-------------------------------------------------
gameBase::onDeath() called once [correct]
Second Death: no vehicle triggers active
-------------------------------------------------
gameBase::onDeath() called once [correct]
Third Death: no vehicle triggers active
-------------------------------------------------
gameBase::onDeath() called once [correct]
Fourth Death: Jet Trigger ACTIVE!<---------------
-------------------------------------------------
gameBase::onDeath() called once [correct]
Engine Crashed <<------------------------
Dissassembly:
0058535E call dword ptr [eax+100h]
Second round of testing
============================
First Death: no vehicle triggers active
-------------------------------------------------
gameBase::onDeath() called once [correct]
Second Death: no vehicle triggers active
-------------------------------------------------
gameBase::onDeath() called once [correct]
Third Death: Jet Trigger ACTIVE!<----------------
-------------------------------------------------
gameBase::onDeath() called once [correct]
Engine Crashed <<------------------------
Dissassembly:
0058535E call dword ptr [eax+100h]
Third round of testing
============================
>> Turend Off ALL Sound <<
First Death: Jet Trigger ACTIVE!<----------------
-------------------------------------------------
gameBase::onDeath() called twice!
Second Death: Jet Trigger ACTIVE!<---------------
-------------------------------------------------
gameBase::onDeath() called once [correct]
Third Death: Jet Trigger ACTIVE!<----------------
-------------------------------------------------
Engine Crashed <<------------------------
Dissassembly:
0058535E call dword ptr [eax+100h]
Fourth round of testing
===========================
First Death: no vehicle triggers active
-------------------------------------------------
gameBase::onDeath() called once [correct]
Second Death: no vehicle triggers active
-------------------------------------------------
gameBase::onDeath() called once [correct]
Third Death: no vehicle triggers active
-------------------------------------------------
Engine Crashed <<------------------------
Dissassembly:
0058535E call dword ptr [eax+100h]
Noticnng a trend here? I did! With the sole excpetion of the first round, all of the crashes happened on my third death?!
Any insights would be greatly appreciated.