So I’ve been slowly implementing basic multiplayer to a demo project of mine, currently nothing special. I’ve made a few games in singleplayer and have a decent grasp on the engine in that regard, and so far things are going well with my demo project. Outside of Godot I have limited experience in networking, and often when studying multiplayer I read comments in regards on how some people will try to use games to compromise other users PC’s and it’s made me paranoid on continuing to learn how to develop multiplayer games.
Before I become dedicated in attempting to make a multiplayer game, I wanted to know some not-so-obvious do’s and don’ts you may have in regards to creating a multiplayer game? I understand you want to put as much as you can behind the server and to trust the client as little as possible, but is there more to it than that? What are some ways to avoid making a product that can compromise user’s computers? Are the official starter documentation guides to developing multiplayer games in Godot safe ways to begin a multiplayer project? I worry that because I am not savvy enough with networking that I will miss something fundamental and cause harm to hypothetical/potential players.
Thanks for any response
Actually I started a Multiplayer project quite some time ago (and never finished it to this day 🥲)
The tricky part about multiplayer in godot is not handling network connection stuff because this is done by Godot itself and you do not need to know anything about TCP or UDP and this technical stuff, although it does not hurt to know some background. So Godot is utilizing something called ENet-Protocol to implement Remote-Procedure-Calls (RPC).
That means you can call functions over the network in other instances of your game running. And from this 2 tricky things emerge. The first is that you need to construct those functions in a way that they cannot be exploited, not in an cheater manner and not in a system security manner (as long as you don’t have any file system access in those functions at least the security aspect should be very easy to fulfill)
The other tricky part begins when you want your network game to be played outside of a fast Local Area network (LAN) and be playable in the open world of the internet. Because not only will you be forced to provide some sort of infrastructure enabling your game instances communicating from within a players local network with another instance in another local network, additionally packet travel time is becoming significantly worst and data lost must be assumed. So you need to structure the interaction of the game instances in a way to handle this. Basically you will need to predict what will happen in clients before you will receive any a definitiv answer and then maybe addapt to this answer without the player noticing this…
The following articles I found very helpful for understanding problems some might encounter while make a multiplayer game: https://www.gabrielgambetta.com/client-server-game-architecture.html
Also this videos I think are usefull to understand the concept of RPC and Multiplayer in Godot better. Please note that a older Godot version is just in there and the syntax has slightly changed by now but the concepts remain the same: https://www.youtube.com/watch?v=d8QpnamQq1A https://www.youtube.com/watch?v=lnFN6YabFKg&t=1s
And like always the Documentation also has somthing to say about this: https://docs.godotengine.org/en/stable/tutorials/networking/high_level_multiplayer.html
Some more tips to get you started: If you not already using it consider the Godot CLI to setup multiple instances of your game for debugging this is quite handy. https://docs.godotengine.org/en/stable/tutorials/editor/command_line_tutorial.html
And of course you could just skip all this RPC/Enet stuff and start implementing your own network calls but I don’t think that this is really worth the trouble for 99.9% of the use cases.
Some technical decisions that a lot of people seem to miss:
- It is impossible to make TCP reliable, even if you encrypt everything. Random middleware will spam you with RSTs and break your client-server connections for no reason, and while you can tell your server firewall to ignore them, you can’t expect clients to.
- The internet backbone is designed mostly around TCP. Most UDP-based protocols do not gracefully degrade. Thus, your only reasonable choice is the one they have to deal with: QUIC/HTTP3. Use an existing library, don’t roll your own.
- Make sure your low-level UDP library is using
sendmmsg
/recvmmsg
, notsendmsg
/recvmsg
. Without that you often get performance worse than TCP. A lot of libraries are lacking here! Some OSes need other methods, or might not provide any way to get good performance; I’m only familiar with the Linux solution. - Define your (application-layer) packet layout using data (fed to some kind of code generator), not manually-written code. Make sure your basic packet structuring code doesn’t (i.e. make every packet declare its size, even if it’s logically fixed size and you’re absolutely sure that will never change). If you need multiple variable-sized fields, stick them all at the end and use indirection. To ensure compatibility, always ignore extra data and pad short packets with zeros (flexibility only at the end suffices). There are a lot of terrible serialization formats out there, even the ones used by major companies.
- Write for the IPv6 stack only, and turn the
IPV6_V6ONLY
sockopt off to transparently handle IPv4 as if it were IPv6 (although it defaults to off, the local administrator can change that, so always take care of it in your code). - Never have clients connect to multiple servers during the course of a connection (you can separate real HTTP server for ahead-of-time downloads). You should write a proxy-like server that forwards packets appropriate to the lobby, the actual game server, etc. and only let clients even know about that proxy.
- Note that internet routing is bad in parts of the world, so forward-only proxies are sometimes useful too!
Thank you so much for asking this question! More game devs should be asking, because it’s too easy to turn your game into dangerous malware for your players if you’re not careful.
So, implementing networking is a big topic. Networking is basically remotely sending instructions from one computer to another. This can happen either directly (Peer-To-Peer), or indirectly (Client-Server). Problems arise when a user can send instructions to another user’s machine that that the host does not want. These bad instructions can be extractive (the host computer exposes sensitive information) or destructive (the host computer deletes some critical information).
Unsafe games provide ways for malicious users to manipulate other users’ computers to do funky stuff. If you limit and control the type of signals the host machine receives and processes, you will have a more secure game.
Some common exploits include sharing user-generated content. Say, in your game, a user can upload an image for their avatar. This image is then propagated to the machines that the player plays a game with so that those users can see his avatar. A clever user can actually write a small program that can pretend it’s an image and can use an exploit in the software renderer to execute that program at soon as your game tries to load it into memory. Now they have remote code execution on that host’s machine. This is the reason why many multiplayer games don’t allow players to host images like avatars and graffiti tags anymore.
Another way you can improve application security is by taking care of the information you let a user propagate to all clients. Say a user needs to create an account in order to go online. They need to enter and verify some personal information to create that account. Some of that information might be critical to gameplay, like an IP address or geolocation or scoreboard, like an email or name and phone number might not be. But if you’re not careful you could broadcast each player the whole profile including sensitive information to all peers even if the client is not actively using that information. A clever user with access to profiling tools can scrape that sensitive information directly from memory.
Less harmful, but annoying consequences is dealing with DOS attacks, botting and cheating, performance and consistency. This is a problem for anonymous and real-time games or games that broadcast a full gamestate to all clients. There are plenty of resources on how that’s done historically.
You really need to be conscious of how your game can influence the host machine and what signals it can propegate.
undefined> Now they have remote code execution on that host’s machine. This is the reason why many multiplayer games don’t allow players to host images like avatars and graffiti tags anymore.
wow, thats actually really interesting. All of these comments have been great but I never knew THAT was why user generated avatars/tags dont exist in games anymore.
I think if you are just starting out this shouldn’t be a big concern (of course it’s still reasonable to keep it in mind). As long as you aren’t using
var2bytes
with object serialization enabled or directly send user scripts around you should be fine. If you are using Godot 4, I’d keep an eye on security updates, as the networking was also revamped.I don’t know a lot about networking. I’ve only attempted and failed to make some small multiplayer games. But, I think that if you were in a position to actually have users with compromised systems, you’d also be in a position to hire an expert to close the breach. Maybe I’m wrong. But to me it seems like worrying about licensing fees. If you actually need to pay them, you’re doing way better than the average indie and probably have the means to take care of them.
I really don’t think you should be too cavalier about it. Games aren’t websites that run in nice sandboxed browsers that handle all your application security. They run quite close to the host system and have some crazy access to files and memory. Some modern anti-cheat that ships with modern games is downright malware!
It’s not about doing thorough security auditing of every packet going over the wire but asking yourself what signals you want your users to send and receive. The modern networking models are so abstracted that devs usually don’t think about it, let alone have any control over it. Something as simple as sharing a save state can be a dangerous attack vector if you don’t know what you are doing.