Game Dev in Rust: Networking Edition
This is the third instalment of a multi-part series that aims to outline our development of an open source MMORPG using the Rust programming language. (See previous posts here)
With regards to an MMORPG, It turns out that the “Massively Multiplayer Online” is quite tricky. To distill this into one sentence: synchronization of the game state between clients and servers.
- Clients: The application running on a players computer.
- Server: The application running on a machine elsewhere.
- State: What’s happening in the game, player positions, health, items, etc…
The clients send messages containing requests for actions to the server, the server reacts to the messages and changes the state accordingly. The server then relays that state to all other connected clients. The server is responsible for building consensus on the network even if the clients act with malice intent.
The issue of a client misbehaving is even more of a threat in an open source game. Hackers don’t even have to break into the distributed binary to inject illegal moves, they can just change the source and recompile it.
An example of this would be: in our game your character can’t walk through walls. The client side checks and rejects movement actions that would send a “move north” action if there a wall to the north. However this isn’t enough, it is easy to change some code and just send the “move north” action regardless. It is now the server’s job to check for walls and, if it’s an illegal move, disallow it and maintain the state from before the attempted illegal move. Possibly kick/ban the player.
Our high level goal is synchronisation of state. Luckily for us, the game engine we chose had some networking capabilities built in called Amethyst Network: an implementation of Laminar.
Laminar is for game development, so we didn’t have to reinvent the wheel, just read the docs! These provided great advice for networking in gaming!
One big aspect before you start is to decide between TCP (Transmission Control Protocol) or UDP (User Datagram Protocol). These are networking protocols that let computers talk to each other over the internet. They each offer their own advantages and can both be used for gaming. When choosing a protocol, you need to ask yourself: what are the latency requirements? In this context, I’m calling latency the time between the client sending a message and the server synchronising the state between all the other clients.
Latency is everything. If you’re building an FPS, you’re going to want UDP. If you’re building a chess game, TCP will work fine. UDP is basically a thin layer on top of IP, making it ideal for games requiring/demanding low latency.
We chose UDP, but unlike TCP it’s a connectionless protocol. In order for the server to manage all the connections Laminar uses heartbeat packets. This means the client will send a “ping” to the server at a regular cadence, if the pings stop, the client is dropped and considered to be disconnected.
Our game currently supports synchronisation of several players’ positions in game, meaning we can all run around together. So without further ado…
Join us Monday February 3rd, 6PM PST for the pre-alpha release where I’ll drop an IP address and we can all run around together in game! Link to event! Join #realm.one on freenode for more info!
Contributing: We are looking for people who are interested to help out. No commitment required and any skill level is welcome. Please reach out if interested!