NokiMo
Megan Fox
Megan Fox

patreon


Execution Order Woes

So, first we'll do the usual update stuff:

The big news is that I finished ANOTHER level. Office! You might remember some of the geometry from waaay back years ago, in one of the demos we released. It's also in the Nintendo trailer. The map is quite a bit evolved from that, though. Very significantly evolved. What we did is kind of plonk the old Office level down in the middle of a much larger, Bedroom-sized space, and went... well, ok, how can we make this not suck. I started by widening the desk area by about 1.5x, and then rebuilding the back wall so that you can go back and forth through it, making it all one giant skateable space with just enough division to make it feel distinct.

Then we drew the rest of the owl, as it were. Went big, added a CEO office, did some cool stuff on top of that waaaay up high, figured out how to make much cooler desks with cool stuff to do on them, we even added a cool vent-based access route to the next level (and a whole series of missions to set it up). Not sure if every level will have a load zone directly into the next one, but maybe? It's pretty cool. That in the can, I moved on to the next level in the pipe... rooftops! (and that'll be the work for this month)

I think that's about it? We're rolling into launch year now, so we'll be gradually stepping up with some announcements. Might have a thing happening next month. No it isn't the game launch, but, you'll probably like it anyways :D

... and then...

Execution Order Is Awful

So this isn't an example of how to do something, more specifically how NOT to do something. Everyone gets the code post this month, because you really, truly do not want the code here. Heh.

It was a real jerk of a bug that appeared in my code, iteratively. It went something like this.

First, I wrote a Coroutine-based system for the stateful movement associated with tricks. It makes sense, given that they're atomic states that have essentially full control over the movement of the board during the trick, and then they restore control to the more general systems. The bug appeared (much) later in the grind code, so pay attention to the arrow here.

These chunks of atomic movement logic essentially warn the rest of the code away when they're in operation, based on playingGrind / playingManual / playingTrickKeys being non-null. If they're non-null, that means the Coroutine is working, so hands off. Easy! <cough>

So then, later I added the concept of transfer grinds. They're a special kind of grind that limits some features of regular grinds - they're of a fixed speed, and don't accelerate you as you pop out the other end. They're how I do those Tony Hawk-style perfect arc transfers over ramp spines.

Sometime after that, I realized that the IsPlayingTransfer function should PROBABLY only report true if you're actually grinding. I wasn't 100% sure if grindingWithTrick could be valid after playingGrind went NULL, and since they're both public, it just make logical sense right? Transfers are a subset of grinds, therefore, shouldn't ever report true if you're not grinding.

So here's the problem. Do you see it yet?

The problem has to do with execution order. Way back at the start, we assigned a coroutine into a tracking variable, whose null-state we use to determine whether activity is taking place. Coroutines are NOT threaded, meaning that assignment to the tracking variable IS STILL HAPPENING until we actually yield the coroutine the first time.

That means that for this big stretch of code here...

... playingGrind = null still. Therefore the reasonably-updated IsPlayingTransfer would always return false in that section. Therefore, I'd totally broken my grind code's ability to know the rail in question was a grind rail.

Woops!

This is extremely bad, and was the source of a lot of increasingly odd and buggy behavior in transfers. Which I then fixed in other ways, but I kept coming back to stuff related to this, and scratching my head. "How are you going through a transfer THAT fast, so fast it causes a bug?!" I'd ask, desperately staring at the code meant to prevent that.

Ah. Ah. So anyways, yes. Hopefully this has burned one of the dangers of coroutines into your head. They're scary. They work well enough, but their not-actually-threaded nature opens them to bugs like this. In the case of an actual thread, this kind of thing would be nearly impossible. You lock/gate variable access either way, and order of operations is clear, if difficult to envision, but that's the point - it's weird so you plan for it to be weird. This, meanwhile, is subtle and creepy.


Related Creators