SimpleNetLib Project
Smooth performance with 4 players and over 12,000 dynamically replicated objects!
Introduction
The multiplayer/networking aspect of games has always fascinated me. It all began in my earlier days when I delved into developing plugins for Minecraft servers, an experience I thoroughly enjoyed. In fact, that's where my entire programming journey began. Therefore, when the time came to begin a new personal project, there was no question that this was the ideal choice.
Not only has it been a good challange but it has also been thoroughly enjoyable every step of the way.
Goal of project
The goal of this project was to develop a lightweight networking library designed to be user-friendly and straightforward to implement.
All things considered, I am proud of the outcome of the project. While there are areas that of course can be improved, overall, I believe it turned out well.
Implementation
To achieve my goals in this project, I implemented several systems aimed at simplifying usage and reducing complexity. For the demo project, I opted to utilize TGE as my engine of choice. TGE, the game engine employed at The Game Assembly, serves as the foundation to most of the projects at the school.
The choice of the engine was based on its simplicity and lack of cluttered features. This decision facilitated a quicker and simpler implementation of my demo. Moreover, it allows for a better showcasing of my library without interference.
Security
To ensure security, the client has no control over the server's actions. All interactions are input-based, meaning the client only provides parameters such as which keys are being pressed for example, which the server then responds to accordingly. This is being done to mitigate the risk of cheating.
Stability
The video showcases the stability of the library. Using the software "clumsy", a harsh network connection/environment is simulated. As can be seen, it performs quite well. To ensure smooth gameplay for the controlled character, a prediction system is being used.
Structure
Packet
Packets are what is being sent between the server and clients. They contain all the necessary data to facilitate communication between the server and client.
To maximize data transfer efficiency between the server and the recipient, I've implemented a system using packet components. Each component can be custom-created by the user of the library. These components are then stacked until the packet is full or the cycle is complete.
Packet Component
The packet component system was designed to simplify the implementation of new components and differentiate them from others.
They only need to be created and registered with the PacketComponentRegistry, and that's it
Example of a custom component.
Example of how to register a packet component for later use.
The PacketComponentAssociatedData defines the level of detail, type, overrides, and frequencies. This design choice was made to reduce bandwidth usage.
Packet Handling Observer System
For simplicity, I've implemented an observer system for my packet components. This system enables easy connection to any packet component type from anywhere, utilizing either static or dynamic delegates.
Dynamic Subscription
A dynamic subscription involves an object's instance function subscribing to a specific delegate.
Static Subscription
Code Example: Dynamic Subscription
Code Example: The Function Delegated To
Ways to send packet components
These are the currently implemented ways to send a packet component.
SendPacketComponentToParent: This only means sending upstream(usually to the server).
SendPacketComponent: This means sending to a target using the default settings provided.
SendPacketComponentWithLod: This involves sending the packet to a target with varying levels of detail (lower frequency) depending on the distance.
SendPacketComponentMulticast: Send to every target available.
SendPacketComponentMulticastWithLod: Send to every available target, but with varying levels of detail.
Example of Spawning an Entity
As seen, the system can easily send a packet component to the clients, which can then be handled on the clients' end. Only one function call is necessary once the component has been registered.
Example of Client recieving the Packet Component
This function is triggered when the client has received the packet component through an observer system. The component is then processed and proceeds to inform the server that it has been updated.
It's essential to clarify that "ClientHasReceivedSpawnEntityComponent" isn't an acknowledgment for the network library; it's specific to the demo project.