#Missile Laser Painter does not clear hit when all hits are laser painters within 5m

1 messages · Page 1 of 1 (latest)

polar garden
#

[Edit: see latest message patch to fix issue]

After hitting a target and then moving away, there seems to be a chance for a missile laser painter to become "sticky" for anywhere from a couple frames to over a minute

When this happens, the laser pointer will

  • visually display that it's hitting a target regardless of where it's pointed vs the target location
  • visually display the laser ending/hitting in thin air at a fixed range from the pointer
  • report the fixed range and that it's hitting a target to any present GBGs

Other notes

  • duration and the fixed range seem to be somewhat random
  • multiple laser painters used at the same time will frequently (but not always) have the same sticky duration and similar range values
  • range can extend well past the target and does not seem to be correlated with the aim point distance
  • occurs both with and without mods enabled

Image showing bug occuring - AtsLuaEditor used to display phantom hit locations visually (shown in red)

#

Lua box also logs duration and range -
Sample showing different but similar durations and one > 80s

polar garden
polar garden
#

Missile Laser Painter getting phantom/sticky hits in midair

polar garden
#

Update: have discovered that this only happens if the laser intersects with another laser pointer block

Also fairly sure I found the root cause by looking at the decompiled dll (edit: this was indeed the cause):
LaserBeamThingHit.DoCasting() does not setBeamLength or clear ThingHit if the only thing(s) the laser hit was MissileBlockLaser as there's no check for this - it just assumes one of the hits was a non-laser-painter.
This means that if only laser painters are hit, BeamLength and ThingHit are never cleared because the if clause still triggers if the only hit(s) was laser painters (which are skipped, so nothing happens).

devout vale
#

wrote a tiny patch to fix this. works on my end :) it essentially replaces the for-loop with a List<T>.TrueForAll(). unzip as a folder into Mods/.

static bool Prefix(LaserBeamThingHit __instance)
{
    /* ... */
    if (gridCastReturn.HitSomething) {

        /* check for *all* instead of just the first painter encountered */
        if (gridCastReturn.SortedHits.TrueForAll(hit => !is_bad_painter(hit))) {
            /* assume first, i guess */
            GridCastHit hit = gridCastReturn.SortedHits[0];
            BeamLength = hit.TotalLengthOfRay + 1f);
            ThingHit = hit.ConstructInvolved);
        } else     /* ... */
    }
    /* ... */
    return false; /* prefix only */
}

private static bool is_bad_painter(GridCastHit gc_hit)
{
    Block blockHit = gc_hit.BlockHit;
    return blockHit != null
        && blockHit.item.Code.ClassName == "MissileBlockLaser"
        && gc_hit.TotalLengthOfRay >= 5f;
}
#

i called it Teflon because it, uh, un-sticks. your script still leaves single dots after each sweep, but i'm blaming that on your code because i'm lazy.

#

(before)

polar garden
#

Missile Laser Painter does not clear hit when all hits are laser painters within 5m

polar garden
devout vale
#

good luck!

polar garden
#

hell yeah first try letsgo

#

correction was pretty simple, just switched out is_bad_painter for TryGetGoodHit and put that right in the initial check

if (gridCastReturn.HitSomething && TryGetGoodHit(gridCastReturn, out GridCastHit goodHit))
private static bool TryGetGoodHit(GridCastReturn gridCastReturn, out GridCastHit goodHit)
{
    goodHit = gridCastReturn.SortedHits.FirstOrDefault(hit => hit.BlockHit != null && !(hit.BlockHit.item.Code.ClassName == "MissileBlockLaser" && hit.TotalLengthOfRay < 5f));
    if (goodHit != null)
    {
        return true;
    }
    goodHit = null!;
    return false;
}
devout vale
#

bump