Stumbled on a sneaky bug in Shmeppy’s undo logic. Basically undo sometimes wouldn’t work (since a couple weeks ago when the bug was introduced), and potentially make Shmeppy inoperable until reloaded, but now it works again!
The Full Story
I’ll explain this bug in case anyone’s interested. It touches on some cool internals of Shmeppy.
The Lifecyle of an Operation
Shmeppy stores the “map state” as a list of operations. So if you fill the center cell with red, it’s essentially recording fillCell(0, 0, "red")
into a big ever-expanding list.
Except the story is slightly more complicated than that, really there’s a sort of “lifecycle of an operation” happening. First an operation is “pended”, becoming the “currently pending operation”. So, for example, if you’re Shift+Dragging with the fill tool, the pending operation is some fillRectangle(...)
operation.
After you’re done dragging, the pending operation is added to an “uncommitted” operations list. This is a list of operations that are waiting to be accepted by Shmeppy’s servers. At this point, you can see the change you made on your computer, but your players can’t yet. And if your computer crashed, your work would be lost. (At this point, it would say “Saving…” on the bottom right of your screen).
However, once Shmeppy’s servers say “ok, got it”, the operation is moved into the “committed” list. At this point, that operation isn’t going anywhere, and your players will be able to see your changes (if their connection is good… Shmeppy’s servers send the new operation to all your players as soon as it recorded it).
Undoing
Now, to undo an operation, Shmeppy needs to compute the “inverse” of that operation, and then put it into the uncommitted list.
So if the center cell is currently yellow, and then you fill it with red (ie: fillCell(0, 0, "red")
), and want to undo it, Shmeppy is going to create a fillCell(0, 0, "yellow")
operation and add it to the uncommitted list.
Oftentimes the operation that you want to undo is in the “uncommitted operations” or “committed operations” lists. But sometimes the operation you want to undo is still just a pending operation.
A common example of this is if you hit undo while editing the palette in the color chooser: not until you close the color chooser or navigate to a different color is the pending “update the palette” operation actually added to the uncommitted operation list.
In this case of undoing a pending operation, Shmeppy first computes the inverse of the pending operation, and then adds the pending operation and the inverse of that pending operation to the uncommitted list.
THIS particular case is the case that was broken. Because of a typo in my code, (essentially) garbage was added to the uncommitted list in this case, and Shmeppy would break in weird ways.
Hopefully it didn’t catch too many people. It must’ve been quite the weird bug… I’m not actually sure how users would fully experience it.