Building SocketSnake: A Multiplayer TUI Game Written in Rust
Github repository: SocketSnake
Why snake
I started this Rust project days ago before my assignment for computer networks was due. And also, I though that I shall practice coding after reading half through the book Programming Rust by Jim Blandy, Jason Orendorff. Then the snake was born out of nowhere.
The project is build for personal practice, especially around networks and rust features. Nevertheless, We shall consider if someone would acually play it, right? Or a step forward, if somebody would learn from the project? Thus I write this blog in case of oblivion.
The structure of the project
Everything starts from a easy ground. For building a local version of
the game, while considering that it may be migrated to a networked
version, we implements a Client
thread and a
Server
thread. The Client
thread is
responsible for listening a keyboard action, and convert then into a
Ctrl
signal (which is a enum
type), and send
it to the Server
with a std::mpsc
channel; The
Server
thread will host an instance of the game
(YardSim
), and push the screen buffer YardBuf
(which is a Vec<Vec<TUIBlock>>
) to the
Client
, who is in charge of rendering the game.
graph TB subgraph Client Renderer(Render) Keyboard(KeyboarCtrlListener) end subgraph Server YardSim(YardSim)--BufferPipe-->Renderer Keyboard--CtrlPipe-->YardSim end
Moreover, to implement the multiplayer game via network, we shall
develop more modules. The ServerWrapper
thread consists the
Server
thread, so do the ClientWrapper
do.
graph TB subgraph ClientWrapper1 subgraph Client Renderer(Render) Keyboard(KeyboarCtrlListener) end Keyboard--CtrlPipe-->TCPSocket1(TCPSocket) UDPSocket1(UDPSocket)--BufferPipe-->Renderer end subgraph ClientWrapper2 TCPSocket2(TCPSocket) UDPSocket2(UDPSocket) end subgraph ClientWrapperN TCPSocketN(TCPSocket) UDPSocketN(UDPSocket) end subgraph ServerWrapper TCPSocket1-.Connect.-TCPListener(TCPListener) TCPSocket2-.Connect.-TCPListener TCPSocketN-.Connect.-TCPListener TCPListener-.FireUp.-ClientHandler1 TCPListener-.FireUp.-ClientHandler2 TCPListener-.FireUp.-ClientHandlerN TCPSocket1==TCPStream==>ClientHandler1 TCPSocket2==TCPStream==>ClientHandler2 TCPSocketN==TCPStream==>ClientHandlerN ClientHandler1[ClientHandler1]--CtrlPipe-->YardSim ClientHandler2[ClientHandler2]--CtrlPipe-->YardSim ClientHandlerN[ClientHandlerN]--CtrlPipe-->YardSim subgraph Server YardSim(YardSim) end ServerUDPSocket(UDPSocket Multicast)==Buffer==>UDPSocket1 ServerUDPSocket==Buffer==>UDPSocket2 ServerUDPSocket==Buffer==>UDPSocketN YardSim--BufferPipe-->ServerUDPSocket end
In the diagram, the squared blocks are threads, and round-cornered
squares are objects. The bol lines are network channels, and the regular
lines are inter-thread channels. The server wrapper has a
TCPListener
: whenever the server listened a connection
request, it launches a ClientHadler
thread to deal with the
TCP stream, and send the control signals to the server backend through a
channel. The client then receive the buffer through UDP, and send it for
rendering.
The chioce of a mixure of TCP and UDP is due to the different demands: the control signals need to be sent losslessly and orderly, but the buffer cares more about latency than loosing packets.
Files
The files implementing the project are listed below.
1 | SocketSnake |