PGE API 0.4
PR00F's Game Engine full documentation
|
PGE uses the Valve's GameNetworkingSockets networking library.
When it was time to add multiplayer support to my game engine, I browsed the internet for already existing solutions I could integrate, because the networking topic itself on its own contains lots of challenges.
I didn't want to reinvent the wheel, for me it was enough to read about the problems and possible solutions in this area, and to use an existing solution instead of implementing my own.
Establishing communication between computers behind NAT devices, handling different endianness of computers, or lag compensation are just a few examples of the challenges in this area.
For lists of networking libraries, check these pages:
During my research, I checked the following 3 popular libraries from a closer perspective:
All 3 libs offer features like message encryption between players, packet fragmentation and reassembly, cross-platform support, traffic statistics.
So I don't need to implement any such low-level features, I can more concentrate on higher-level network-related features.
Unfortunately, yojimbo doesn't have NAT punch-through support, for which I decided not to use it, because I don't want to implement / or use additional library for this purpose.
Both GNS and SLN offer sophisticated connection establish between computers that are NOT connected directly to the internet, this is not in yojimbo.
Although the codebase of SLN hasn't changed since 2019, it has a solid base: it is a fork of RakNet which was developed for more than a decade, and it was also used by Unity engine (maybe it is still used under the hood).
In theory, SLN fixes some IPv6-related bugs of RakNet but I don't know if it has become really bug-free.
Comparing GNS and SLN today is more difficult than it used to be in ~2019 because since then GNS added some missing features already available in SLN.
Both libs provide:
SLN offers support for game object serialization and data compression, I don't see much support for these in GNS as of June 2022 with version 1.4.0.
It also has some other fancy stuff like game lobby, autopatcher, etc.
It also has much less dependencies and easier to build.
GNS on the other hand, is still actively maintained by Valve, used by Dota and CSGO.
Because of this, I opted for GNS.
Here is a small game project utilizing GNS: https://github.com/David-Elle-Jack-Oisin/TeamProject/tree/main/src/network
I'm implementing the client-server networking model in the engine because it sounds suitable for my future projects and hopefully easier to implement than P2P.
In this model, there is always exactly 1 machine with server role, and some clients connected to the server.
There is no communication between clients, server keeps all clients updated about game state.
PGE provides networking functionality through the PgeNetwork class instance in pge_network namespace, that can be accessed by PGE::getNetwork() function.
This PgeNetwork instance must be initialized before networking functionality can be used, however PGE initializes it automatically upon startup.
It will be either a client or server instance based on the value of CVAR_NET_SERVER.
Common functions can be accessed through PgeNetwork::getServerClientInstance(), more specifics are accessed through either PgeNetwork::getClient() or PgeNetwork::getServer() functions.
TODO: ask doxygen to insert value of CVAR_NET_SERVER above!
TODO: make a separate page explaining CVARs!
Server and client instances communicate by sending and receiving PgePacket structs that encapsulate single messages.
As of PGE v0.4 there can be only 1 message within a PgePacket, and there is only 3 different kind of messages:
An application can define its custom messages, all those will be MsgApp kind.
TODO: make link to tag PGE v0.4 above!
TODO: should we use pge_network namespace everywhere explicitly?
In order to be able to receive messages over the network, the messages need to be explicitly allowlisted, otherwise they are ignored.
By default server instance is allowed to receive MsgApp messages only, client instance is allowed to receive MsgUserDisconnected and MsgApp messages.
Server also processes MsgUserConnected and MsgUserDisconnected, however it just self-injects these, that is why it is NOT allowed to receive these over network.
It is very important to understand that even though MsgApp is allowed for both client and server, by default any kind of custom message inside MsgApp will be ignored.
Application MUST explicitly allowlist its custom messages separately for both client and server.
This can be done by adding the allowed custom messages to the container accessed by PgeNetwork::getServerClientInstance().getAllowListedAppMessages().
The Low-level networking topics for me are usually those topics which I found very fundamental to understand and use BUT I don't want to implement.
For example, packet fragmentation and reassembly: it is good to know why it is needed and I want to have it by using the already existing implementation in the chosen library instead of implementing it by myself.
Packet Basics:
Floating Point Determinism:
NAT Punch-through:
Importance of backend services:
Security Issues of Online Gaming:
The High-level networking topics for me are usually those topics which I also want/have to implement in my software.
For example, scheduling of sending packets, tick rate, etc.
Client-server vs P2P model:
Client-side prediction, interpolation, latency mitigation, etc:
Misc: