Triggered traps & lix in transit

Started by Simon, August 17, 2016, 05:59:06 AM

Previous topic - Next topic

0 Members and 2 Guests are viewing this topic.

Simon

IchoTolot: ah ok the bug front :P
Simon: the bug front is exciting
Simon: I love bugs, everybody should report bugs against every software


Long and technical post, programming.

Github bug #132: Walker bypasses trap, faller is killed, found by Ramon. Equivalent to a bug in C++ Lix, Fast flinging through traps, found by geoo. I want to find the best solution to this.

What happens? When you enter and leave triggered traps, the game scans for traps only at your final position. The game knows that you went through a trap somewhere, but it doesn't remember where you encountered a hungry trap. Whenever you somehow went through a hungry or already-eating trap, the game sets a flag. If this flag is set, then after your full motion, the game scans for hungry traps at your final position.

Compare this with our fire solution: When you enter and leave fire within the same frame, the game still remembers that you went through fire, and kills you. You got to perform your full motion and affect the environment, but after that, you die.

Desired instead: When you move through a hungry trap, then leave it during the same frame, this trap kills you. I don't know whether you should move away or not before the trap kills you.

Sketch of call stack

single lix performs physics update:
    perform job:
        some work
        move ahead:
            if encounter trap:
                set flag
        more work
    if flag:
        feed trap
        die


I don't know whether "more work" should execute when we are going to die. "More work" can easily move you somewhere else, and then it could be harder to determine the correct trap.

Idea #1: throw exception

Have moveAhead throw on trap encounter, and catch this exception in singleLixPerformsPhysicsUpdate. The intention is to stop performJob early.

Benefit: Program flow mimicks what we see and expect. We die immediately.

Disadvantage: I use the exception in a non-exceptional case. This may happen several times per second. In effect, it's a goto that jumps between methods of different classes.

And exceptions produce the slowest code. Throwing may be idiomatic in Python, you even throw when your iterated range is empty. This isn't Python, exceptions are slow. I had file-searching code that relied on exceptions internally, it became 10 times faster after rewriting internals to return success or fail. You don't want exceptions flying everywhere in a multiplayer game.

Maybe it's not a huge performance dent and I should profile.

Also, are exceptions designed for this? Exceptions are for when you encounter non-bug problems with your input or environment, and you don't know how to handle. But I know exactly how to handle traps. My desire is to stop the outside logic, not to inform the outside logic.

Idea #2: disable movement

Once we touch a hungry trap, disable further movement.

Advantage: Relies on encounter flags (did we touch water, fire, trap, steam, etc.) like every other encounter.

Disadvantage: We don't die immediately. The movement-calling code, "perform job" in the call stack above, contiues to happily call moveAhead, and yet we don't move ahead.

Idea #3: remember reference to trap

Once we touch a hungry trap, remember a reference until the end of performJob.

Advantage: We know the correct trap 100 % of the time, instead of deducing which one it was after the fact. We don't ever remember references to already-eating traps, even though we moved through their area. When the job calls moveAhead, we will still move ahead, even if we die afterwards.

Disadvantage: Extra mutable state. We don't die immediately.

Hmm.

I like #3 best, then #1, then #2. (Completing the motion after seeing the trap) shouldn't be problematic. Lixes never affect each other with traps: One lix performs at a time, traps snap immediately before the next lix performs.

-- Simon

Simon

I've begun implementing #3 = remember reference to trap. The ADmiral has ranked #3 best, then #2, then #1. Reasoning: Lixes in traps are nothing exceptional.

This brings subtle replay fails in LasRanas and Endeavor. LasRanas, I have no idea why it fails, the frogs never eat too much. I'll have to watch both game versions in slow-motion alongside each other.

In Endeavor, lix stay in the steam for longer: They are affected at the beginning of the steam-leaving frame now. They remember the steam, and reuse its propulsion at the end of the frame. Before, they'd fly out of the steam with their old speed, then check for steam, nothing here, so no extra propulsion.

No idea what's best. Only remember triggered flingers? But see attached picture: When you have very high speed towards the right, you can bypass the upwards-blowing steam.

Or accept the physics change, which will break levels with carefully-aligned long-range steam cannons?

-- Simon

Simon

In IRC, we discussed Builder creates terrain behind herself, and I said this:

The only reason it's implemented like move-ahead, check-some, move-more, check-more, ..., is historical. A better code would do all checks at once, then issue one move command at the end. That move command kings, i.e., finds a shortest route with chess king moves, with fixed tiebreaking rules. The king path is then examined for traps.

I'll have to think about corner cases like: We move some, then turn at a wall during tumbling, then continue to move. Should that be allowed? Nepster sent inconsistent splat height examples when it's not allowed.

What happens when we hit, during the same physics update, first steam, then a wall? If we do all terrain checks first, we will find the wall first. But when steam should be active mid-motion, then we can never find the wall. I wanna call my mom. :lix-cry:

-- Simon

Simon

This feature bug issue is on the backburner, like all physics issues.

Brain dump: Each lix maintains a list of gadgets that satisfy a) she is inside the TA, and b) the gadget has already affected her. A lix is immune to gadgets in her list. When you leave a TA, the gadget reference is removed from your list, and you can use the gadget on your next re-entry. Using gadgets interrupts whatever else you are doing. Diagonal moves (kinging) allowed?

There should be special conditions that empty the entire list: Hitting terrain during tumbling, getting hit by batter. But not hitting another steam. Everything that affects Lix in a moderately well-defined way, but does not affect via TAs, should empty the list.

-- Simon