Fractal Softworks Forum

Please login or register.

Login with username, password and session length

Author Topic: MissileAPI's don't return a valid getDamageTarget()  (Read 2760 times)

xenoargh

  • Admiral
  • *****
  • Posts: 5078
  • naively breaking things!
    • View Profile
MissileAPI's don't return a valid getDamageTarget()
« on: May 12, 2016, 11:03:20 PM »

...ever, apparently.  It's always null, even when they've just detonated.  Weird.
Logged
Please check out my SS projects :)
Xeno's Mod Pack

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24128
    • View Profile
Re: MissileAPI's don't return a valid getDamageTarget()
« Reply #1 on: May 12, 2016, 11:27:02 PM »

Thanks for the report - are you sure? Looking at the code, it seems like they properly have that set - seems near impossible to end up with didDamage() returning true without a valid getDamageTarget() being set. However, missiles get removed from the engine on the frame that they do damage, so one would have to keep track of seen missiles and then compare that to the currently-in-engine missiles to find which ones have despawned and so might've done damage that frame.

If you're certain, I'll take a closer look tomorrow.
Logged

xenoargh

  • Admiral
  • *****
  • Posts: 5078
  • naively breaking things!
    • View Profile
Re: MissileAPI's don't return a valid getDamageTarget()
« Reply #2 on: May 12, 2016, 11:40:07 PM »

They don't return didDamage(), either.

Example code that fails:

Code
for(DamagingProjectileAPI projectile : engine.getProjectiles()){
if(projectile.getWeapon() == null) continue;
if(projectile.getWeapon().getShip() == null) continue;
int power = Math.min(200,Math.max(1,Math.round(projectile.getWeapon().getDerivedStats().getDamagePerShot() / 15)));

CombatEntityAPI dTarg = projectile.getDamageTarget();
//PROJECTILE EXPLOSION HANDLER
if(dTarg != null){ //DO STUFF
}
}
Logged
Please check out my SS projects :)
Xeno's Mod Pack

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24128
    • View Profile
Re: MissileAPI's don't return a valid getDamageTarget()
« Reply #3 on: May 13, 2016, 09:16:34 AM »

This part:
for(DamagingProjectileAPI projectile : engine.getProjectiles()){


Makes me think this is the issue:
However, missiles get removed from the engine on the frame that they do damage, so one would have to keep track of seen missiles and then compare that to the currently-in-engine missiles to find which ones have despawned and so might've done damage that frame.

If you're only iterating over in-engine projectiles, missiles will *never* return didDamage() == true. Other types of projectiles do because they have some fadeout time after being destroyed, due to having tails and the like.
Logged

xenoargh

  • Admiral
  • *****
  • Posts: 5078
  • naively breaking things!
    • View Profile
Re: MissileAPI's don't return a valid getDamageTarget()
« Reply #4 on: May 13, 2016, 11:58:44 AM »

Ah, OK.  That's a non-trivial situation with a lot of edge-cases, though.  I'll look into it.
Logged
Please check out my SS projects :)
Xeno's Mod Pack

Nick XR

  • Admiral
  • *****
  • Posts: 713
    • View Profile
Re: MissileAPI's don't return a valid getDamageTarget()
« Reply #5 on: January 06, 2017, 02:07:26 PM »

In case anyone else runs into this, here's the interesting parts of the code I used to solve this in an EveryFrameCombatPlugin:

Code: java
    private static HashSet<MissileAPI> seenMissiles = new HashSet<>(100);
    public void advance(float amount, List events)
    {
        CombatEngineAPI engine;

        // get the missiles in this frame
        HashSet<MissileAPI> activeMissiles = new HashSet<>();
        activeMissiles.addAll(engine.getMissiles());

        // the difference between the missiles in the last frame to this frame are those that *could* have done damage
        seenMissiles.removeAll(activeMissiles);
        for(MissileAPI missile : seenMissiles){
            if(missile.didDamage()){
                // do something
            }
        }

        // set our missiles for the next frame
        seenMissiles = activeMissiles;
    }

If you're perf crazy about this, replacing the HashSets with Arrays and doing a brute force lookup might be faster for array sizes smaller than 20 or so.  Would have to test to know where the cutoff is.

Having missiles behave like all of the other projectiles they are lumped in with probably makes the most sense IMO.
« Last Edit: January 09, 2017, 10:04:18 AM by XRsyst »
Logged

xenoargh

  • Admiral
  • *****
  • Posts: 5078
  • naively breaking things!
    • View Profile
Re: MissileAPI's don't return a valid getDamageTarget()
« Reply #6 on: April 08, 2017, 09:23:09 PM »

I've found a simpler method that saves some significant CPU:

Code: java
        // get the missiles in this frame, to use next frame
        HashSet<MissileAPI> activeMissiles = new HashSet<>(); 
        activeMissiles.addAll(engine.getMissiles()); 
 
        //We're just doing a boolean check per missile here; cheap
        for(MissileAPI missile : seenMissiles){ 
            if(missile.didDamage()){ 
                //Do Stuff
            } 
        } 

        // set our missiles for the next frame 
        seenMissiles = activeMissiles;

It eats quite a lot of CPU to do removeAll() when we're talking about big data-sets; it turned out to be far cheaper, on average, to simply check last frame's MissileAPIs for didDamage().   
Logged
Please check out my SS projects :)
Xeno's Mod Pack