
Custom levels now support rewind! It requires a slightly different structure for the level code.
To enable rewind support:
- The script must call the new
EnableRewind()function inside_Setup(). Once called, the engine will run the script with rewind support enabled. - The
_Update()function should now return a patch object rather than modifying script variables directly. - You’ll need to implement two additional functions:
_Forward(patch)and_Backward(patch), which are responsible for modifying the script variables.
The idea is that, instead of mutating level variables directly inside _Update(), you return a “patch” object from it. This object is then passed to _Forward() during normal playback, or to _Backward() during rewind, to apply the actual changes.
Example 1: The Basics
For example, let’s say you have a simple cycle counter in Lua. Without rewind, you’d implement it like this:
function _Setup() CYCLE_PORT = AddPortOut(5, 'cycle')endfunction _Start() cycle = 0endfunction _Update() WritePort(CYCLE_PORT, cycle) cycle = cycle + 1endfunction _Draw() end
With rewind enabled, the code would look something like this:
function _Setup() CYCLE_PORT = AddPortOut(5, 'cycle') EnableRewind()endfunction _Start() cycle = 0endfunction _Update() WritePort(CYCLE_PORT, cycle) -- Needs to return something, otherwise the -- _Forward() won't be called. return {}endfunction _Forward(patch) cycle = cycle + 1endfunction _Backward(patch) cycle = cycle - 1endfunction _Draw() end
Example 2: Variable Counter
Now let’s say you have a second counter that increments a value based on an output from the circuit. For this, you’ll need to pass information from _Update() to _Forward(), which you can do via the patch object:
function _Setup() CYCLE_PORT = AddPortOut(5, 'cycle') COUNTER_PORT = AddPortOut(10, 'counter') INC_PORT = AddPortIn(5, 'inc') EnableRewind()endfunction _Start() cycle = 0 counter = 0endfunction _Update() WritePort(CYCLE_PORT, cycle) WritePort(COUNTER_PORT, counter) local inc = ReadPort(INC_PORT) return {inc=inc}endfunction _Forward(patch) cycle = cycle + 1 counter = counter + patch.incendfunction _Backward(patch) cycle = cycle - 1 counter = counter - patch.incendfunction _Draw() end

Counter example running
How it Works
Under the hood, the engine stores the patch objects and calls _Forward() when time moves forward, and _Backward() when rewinding. Patch objects are not stored in Lua — they are serialized by value using msgpack. This means patch objects should be kept small, otherwise memory issues may arise. It also means Lua references are not supported: any value placed in a patch object will be copied by value, not by reference.
For things like memory emulation, you’ll want to pass only the values that actually change, rather than dumping the entire memory state into the patch — for example, a triple (address, valueBefore, valueAfter).
Conclusion
Players can now write levels with rewind support, which was not available in the previous release. A simple commented example has also been added to the examples/ folder of the game.
It requires a slightly different code structure, but this can be made easier with some dedicated helper data structures.

Leave a Reply