thread_comms.md 1.8 KB

Render/tick thread communication

The rendering thread (from Godot) is separate from the game logic thread(s). There can't be any (long-held) locks between these threads as otherwise we could get horrible frame lag and other hiccups and instability.

Player input is also received on the render thread. We have to submit player input to the game logic thread and update the screen immediately. Perhaps if a tick wasn't currently executing we could lock the world state, insert the player action into the log for the next tick, and continue with the frame. But this would lead to stutters if the tick was executing when it came time to run the frame logic.

So the plan is to have a local view into the world that we can treat as stale at any given point in time. This is maintained on the render thread side. There's two communication channels between the render thread and the main tick thread. Every frame, we eagerly consume all messages sent to the render thread and process them. If there's a new tick, we throw away the stale state and start looking at the new clean state that the tick thread produced.

If the player gave some input in a frame, we try to write what we can to this stale copy. It may be too expensive to do this for all actions, and it shouldn't process all the way through to downstream message handling, but we can do immediate block updates and other interactions. Then we also submit it on the channel for it to be consumed first when the next tick actually happens. Some work may get duplicated here, but we can try to keep that cost minimal and it only happens when the player actually does something.

The history tracking should already be built around a nonblocking thread-safe data structure, so we shouldn't need any large copies sending data over the channels like this.