Author Topic: Crash in recursive projectile explosions  (Read 1898 times)

I wanted to write a system that lets projectiles spawn other projectiles when they explode.
Here's what I got:
Code: [Select]
//part of a package with tons of other stuff in it too.
function projectileData::onExplode(%this, %obj, %pos) {
if(isObject(%this.subProjectile)) {
%inheritVel = vectorScale(%obj.getVelocity(), %this.subProjectile.velInheritFactor);
if(%this.subProjectileCount $= "")
%this.subProjectileCount = 1;
for(%i = 0; %i < %this.subProjectileCount; %i++) {
%vel = mCos(mDegToRad(getRandom(0, 359))) SPC mSin(mDegToRad(getRandom(0, 359))) SPC mCos(mDegToRad(getRandom(0, 179)));
%vel = vectorNormalize(%vel);
%vel = vectorScale(%vel, %this.subProjectile.muzzleVelocity);
%vel = vectorAdd(%vel, %inheritVel);
%vel = vectorClampF(%vel, 0, 200);
%p = new projectile() {
dataBlock = %this.subProjectile.getID();
initialPosition = %pos;
initialVelocity = %vel;
sourceObject = %obj.sourceObject;
sourceSlot = %obj.sourceSlot;
client = %obj.client;
};
missionCleanup.add(%p);
}
%obj.delete();
return;
}
parent::onExplode(%this, %obj, %pos);
}

You can add projectileData.subProjectileC ount and projectileData.subProjectile and it works quite well.

When I have projectile1 explode to projectile2, and projectile2 explode to projectile1, the engine crashes. As far as I can tell, it's not just some simple infinite loop grabbing a ton of memory problem as it might seem at first.

So far it hasn't crashed the first time a projectile in the loop explodes though.

Traces show nothing odd, dumping the projectiles shows nothing odd, I really don't have any clue why the engine crashes.

Oh, and here's the vectorClampF() I wrote for limiting the projectile velocity to 200.
Code: [Select]
function vectorClampF(%vector, %min, %max) {
return vectorScale(vectorNormalize(%vector), mClampF(vectorLen(%vector), %min, %max));
}


Put echoes inside the loops and any other useful functions (e.g. projectiledata::onadd), post a traced console log of that.

How is this recursive?
Projectile spawns Projectile which spawns Projectile which spawns Projectile... ...which crashes BL.

Put echoes inside the loops and any other useful functions (e.g. projectiledata::onadd), post a traced console log of that.

In a brand new BL folder, with nothing but the standard HEGrenade (the latest version available on RTB) and the following script:
Code: [Select]
function vectorClampF(%vector, %min, %max) {
return vectorScale(vectorNormalize(%vector), mClampF(vectorLen(%vector), %min, %max));
}

package projectileStuff {
function projectileData::onExplode(%this, %obj, %pos) {
if(isObject(%this.subProjectile)) {
%inheritVel = vectorScale(%obj.getVelocity(), %this.subProjectile.velInheritFactor);
if(%this.subProjectileCount $= "")
%this.subProjectileCount = 1;
for(%i = 0; %i < %this.subProjectileCount; %i++) {
%vel = mCos(mDegToRad(getRandom(0, 359))) SPC mSin(mDegToRad(getRandom(0, 359))) SPC mCos(mDegToRad(getRandom(0, 179)));
%vel = vectorNormalize(%vel);
%vel = vectorScale(%vel, %this.subProjectile.muzzleVelocity);
%vel = vectorAdd(%vel, %inheritVel);
%vel = vectorClampF(%vel, 0, 200);
%p = new projectile() {
dataBlock = %this.subProjectile.getID();
initialPosition = %pos;
initialVelocity = %vel;
sourceObject = %obj.sourceObject;
sourceSlot = %obj.sourceSlot;
client = %obj.client;
};
missionCleanup.add(%p);
echo("NEW PROJECTILE #" @ %i + 1 @ " DUMP (onExplode)");
echo(%p.getID());
%p.dump();
}
echo("OLD PROJECTILE DUMP (onExplode)");
echo(%obj.getID());
%obj.dump();
%obj.delete();
return;
}
parent::onExplode(%this, %obj, %pos);
}
function projectileData::onCollision(%this, %obj, %col, %fade, %pos, %normal) {
echo("DUMP BEFORE COLLISION");
%obj.dump();
return parent::onCollision(%this, %obj, %col, %fade, %pos, %normal);
}
function projectile::onAdd(%this) {
%val = parent::onAdd(%this);
echo("DUMP AFTER ADD");
%this.dump();
return %val;
}
function projectile::onRemove(%this) {
echo("DUMP BEFORE REMOVE");
%this.dump();
return parent::onRemove(%this);
}
};
activatePackage(projectileStuff);

I got the following output.

Code: [Select]
==>HEGrenadeProjectile.subProjectile=HEGrenadeProjectile;
==>trace(true);
   Console trace is on.
Leaving ConsoleEntry::eval() - return
Entering toggleConsole(1)
   Entering [CanvasCursor]GuiCanvas::popDialog(Canvas, ConsoleDlg)
      Entering [CanvasCursor]GuiCanvas::checkCursor(Canvas)
         Entering cursorOff()
         Leaving cursorOff() - return
         Entering [CanvasCursor]GuiCanvas::checkTabFocus(Canvas)
         Leaving [CanvasCursor]GuiCanvas::checkTabFocus() - return
      Leaving [CanvasCursor]GuiCanvas::checkCursor() - return
   Leaving [CanvasCursor]GuiCanvas::popDialog() - return
Leaving toggleConsole() - return
Entering toggleConsole(0)
Leaving toggleConsole() - return 0
Entering mouseFire(0)
Leaving mouseFire() - return 0
Entering Armor::onTrigger(44, 7006, 0, 0)
Leaving Armor::onTrigger() - return 7006
Entering hegrenadeImage::onFire(691, 7006, 0)
   Entering WeaponImage::onFire(691, 7006, 0)
      Entering [projectileStuff]Projectile::onAdd(7176)
         Entering Projectile::onAdd(7176)
         Leaving Projectile::onAdd() - return -49.1702 2.5118 2.48114
         DUMP AFTER ADD
         Member Fields:
           dataBlock = "hegrenadeProjectile"
           initialPosition = "-49.1702 2.5118 2.48114"
           initialVelocity = "29.2626 -5.39691 -3.81771"
           position = "-49.1702 2.5118 2.48114"
           rotation = "1 0 0 0"
           scale = "1 1 1"
           sourceObject = "7006"
           sourceSlot = "0"
         Tagged Fields:
           client = "6119"
           originPoint = "-49.1702 2.5118 2.48114"
         Methods:
           addScheduledEvent() -

... Standard projectile methods, we all know what they are, no need making this longer than it needs to be...

           ToggleEventEnabled() -
      Leaving [projectileStuff]Projectile::onAdd() - return -49.1702 2.5118 2.48114
   Leaving WeaponImage::onFire() - return 7176
   Entering messageClient(6119, 32, 65, 3, 0)
   Leaving messageClient() - return
   Entering ServerCmdUnUseTool(6119)
      Entering WeaponImage::onUnMount(691, 7006, 0)
      Leaving WeaponImage::onUnMount() - return 691
   Leaving ServerCmdUnUseTool() - return 691
Leaving hegrenadeImage::onFire() - return 691
Entering clientCmdServerMessage(32 MsgItemPickup, 65 , 3, 0)
   Entering defaultMessageCallback(32 MsgItemPickup, 65 , 3, 0, , , , , , , , )
      Entering onServerMessage()
      Leaving onServerMessage() - return
   Leaving defaultMessageCallback() - return
   Entering handleItemPickup(32 MsgItemPickup, 65 , 3, 0, )
   Leaving handleItemPickup() - return
Leaving clientCmdServerMessage() - return
Entering ServerCmdUseTool(6119, 3)
Leaving ServerCmdUseTool() - return 3
Entering hegrenadeProjectile::OnCollision(689, 7176, 6111, 1, -37.075539 0.281174 0.000001, 0.000000 0.000000 1.000000)
   Entering ServerPlay3D(hegrenadeBounceSound, -37.9334 0.439387 0.231595 1 0 0 0)
   Leaving ServerPlay3D() - return 7006
Leaving hegrenadeProjectile::OnCollision() - return 7006

...A ton more onCollisions just with different positions...

Entering hegrenadeProjectile::OnCollision(689, 7176, 6111, 1, -31.338066 -0.776994 0.000000, 0.000000 0.000000 1.000000)
   Entering ServerPlay3D(hegrenadeBounceSound, -31.3381 -0.776994 2.49594e-07 1 0 0 0)
   Leaving ServerPlay3D() - return -31.338066 -0.776994 0.000000
Leaving hegrenadeProjectile::OnCollision() - return -31.338066 -0.776994 0.000000
Entering [projectileStuff]ProjectileData::onExplode(689, 7176, -31.338066 -0.776994 0.010000)
   Entering vectorClampF(21.5871 -19.3492 7.72059, 0, 200)
   Leaving vectorClampF() - return 21.5871 -19.3492 7.72059
   Entering [projectileStuff]Projectile::onAdd(7178)
      Entering Projectile::onAdd(7178)
      Leaving Projectile::onAdd() - return -31.3381 -0.776994 0.01
      DUMP AFTER ADD
      Member Fields:
        dataBlock = "hegrenadeProjectile"
        initialPosition = "-31.3381 -0.776994 0.01"
        initialVelocity = "21.5871 -19.3492 7.72059"
        position = "-31.3381 -0.776994 0.01"
        rotation = "1 0 0 0"
        scale = "1 1 1"
        sourceObject = "7006"
        sourceSlot = "0"
      Tagged Fields:
        client = "6119"
        originPoint = "-31.3381 -0.776994 0.01"
      Methods:
        addScheduledEvent() -
...
        ToggleEventEnabled() -
   Leaving [projectileStuff]Projectile::onAdd() - return -31.3381 -0.776994 0.01
   NEW PROJECTILE #1 DUMP (onExplode)
   7178
   Member Fields:
     dataBlock = "hegrenadeProjectile"
     initialPosition = "-31.3381 -0.776994 0.01"
     initialVelocity = "21.5871 -19.3492 7.72059"
     position = "-31.3381 -0.776994 0.01"
     rotation = "1 0 0 0"
     scale = "1 1 1"
     sourceObject = "7006"
     sourceSlot = "0"
   Tagged Fields:
     client = "6119"
     originPoint = "-31.3381 -0.776994 0.01"
   Methods:
     addScheduledEvent() -
...
     ToggleEventEnabled() -
   OLD PROJECTILE DUMP (onExplode)
   7176
   Member Fields:
     dataBlock = "hegrenadeProjectile"
     initialPosition = "-31.3381 -0.776994 2.49594e-07"
     initialVelocity = "0 0 1"
     position = "-31.3381 -0.776994 2.49594e-07"
     rotation = "1 0 0 0"
     scale = "1 1 1"
     sourceObject = "7006"
     sourceSlot = "0"
   Tagged Fields:
     client = "6119"
     originPoint = "-49.1702 2.5118 2.48114"
   Methods:
     addScheduledEvent() -
...
     ToggleEventEnabled() -
   Entering [projectileStuff]Projectile::onRemove(7176)
      DUMP BEFORE REMOVE
      Member Fields:
        dataBlock = "hegrenadeProjectile"
        initialPosition = "-31.3381 -0.776994 2.49594e-07"
        initialVelocity = "0 0 1"
        position = "-31.3381 -0.776994 2.49594e-07"
        rotation = "1 0 0 0"
        scale = "1 1 1"
        sourceObject = "7006"
        sourceSlot = "0"
      Tagged Fields:
        client = "6119"
        originPoint = "-49.1702 2.5118 2.48114"
      Methods:
        addScheduledEvent() -
...
        ToggleEventEnabled() -
      Add-Ons/Script_ProjectileStuff/server.cs (0): Unknown command onRemove.
   Leaving [projectileStuff]Projectile::onRemove() - return
That is the log from the time I added the subProjectile field to the HEGrenadeProjectile datablock, to the time the server crashed.
« Last Edit: January 11, 2010, 06:52:59 PM by BobAndRob »

This isn't recursive... I don't even see how the "subProjectile" can spawn another projectile when it explodes unless you set the subProjectile's subProjectile to itself.

Schedule the obj.delete() method call by 1ms, your console log does not look like a crash caused by a forever loop.

This isn't recursive... I don't even see how the "subProjectile" can spawn another projectile when it explodes unless you set the subProjectile's subProjectile to itself.
Code: [Select]
==>HEGrenadeProjectile.subProjectile=HEGrenadeProjectile;

Schedule the obj.delete() method call by 1ms,
But then wouldn't the projectile would still spawn it's explosion, instead of exclusively spawning more projectiles? The entire point is to avoid that.

your console log does not look like a crash caused by a forever loop.
As far as I can tell, it's not just some simple infinite loop grabbing a ton of memory problem as it might seem at first.

Did you read the thread?

What are you expecting to happen if the sub explosions spawn more sub explosions? You really aren't explaining your logic very well here.

Did you read the thread?

Not really. 99% of the time in Coding Help the poster is just being handicapped and not thinking things through.

That is the log from the time I added the subProjectile field to the HEGrenadeProjectile datablock, to the time the server crashed.
What did you set that field to and how many sub-projectiles did you set it to spawn?

What are you expecting to happen if the sub explosions spawn more sub explosions? You really aren't explaining your logic very well here.
Oh, excuse me, I assumed the word sub-projectiles was self explanatory. When a projectile explodes, instead of spawning an explosion, I want it to spawn more projectiles. For now they are spawning evenly in a sphere around the exploding projectile's position. This is one potential application in which I would have one initial projectile, which, on collision or timed death, would simply disappear without an explosion, and would subsequently spawn a bunch of bomb fragments in it's place.

The problem I am running into now, is when I have a projectile spawn another projectile with the same datablock. It should just "jump" around by simply being deleted before it can spawn an explosion, and another projectile being created, originating from the same point that the other one was deleted at, but with a different velocity. This would go on forever, or until some outside force interrupts that loop. However there is no reason that this loop would be the cause of the crash, as there is a great delay in time between the explosions of these projectiles.

99% of the time in Coding Help the poster is just being handicapped and not thinking things through.

1. That is why half the time I think I'm better off posting my questions on the GG forums, and explaining the few quirks about Blockland that my whatever relies on.

2. I don't start a topic here unless I've been struggling with/thinking about my problem without making any progress at all for over at least a week as a rule of thumb. The forums are a last resort because I really appreciate the time people take to answer my questions when I do ask them, and I don't want to abuse of that by wasting their time with something I can solve myself.



What did you set that field to and how many sub-projectiles did you set it to spawn?

The very first line of the trace I posted:
Code: [Select]
==>HEGrenadeProjectile.subProjectile=HEGrenadeProjectile;

I never set .subProjectileCount, I just let this happen:
Code: [Select]
if(%this.subProjectileCount $= "")
%this.subProjectileCount = 1;

Did you read the thread?
« Last Edit: January 13, 2010, 09:33:36 PM by BobAndRob »

You're deleting the projectile object as it explodes, where the engine will probably be using that and its data for things like the particle effects. (ProjectileData::onExplode is a callback from the engine, not where the actual explosion is created)

Try removing the "%obj.delete();" and "return;" lines. You may also need to return the values of the packaged functions.