Repository navigation
[Network] Dimension specifications
The Dimension library is a UDP network library developed by mlargeot and MaxenceLgt. Initially designed for the RType project, this library is built to be generic and modular, allowing it to integrate network communication with a game engine as an external component and by using scripts.
Dimension operates using packet transfers, with packets that can be created and modified as needed. The library also provides a default list of packets to streamline development. Additionally, it supports Room management, enabling multiple game instances (multi-instance) within the same game environment. It provides essential features for server-client communication, including:
- Establishing and managing server-client connections
- Transferring data across the network.
In multiplayer gaming and other real-time applications, network communication must be both fast and efficient to maintain a smooth and responsive user experience. Choosing UDP as the communication protocol offers clear advantages by minimizing latency and reducing overhead from built-in reliability management. Originally developed for a specific project, this network library was designed to be independent, making it suitable for integration into various real-time game engines.
-
Minimal Latency and Enhanced Responsiveness: UDP enables data transmission without enforcing strict ordering or delivery verification, which avoids delays caused by retransmissions, common in TCP. This delay-free exchange is essential in real-time applications, where even slight lag can impact user experience and gameplay responsiveness.
-
Simplicity and Flexibility: By not handling guaranteed delivery or ordering as TCP does, UDP simplifies data flow management, enabling higher data throughput, which is especially valuable in data-heavy environments like gaming.
While UDP doesn’t provide built-in delivery guarantees, applications that require reliability for critical data can implement an optional acknowledgment system. This approach would add packet identifiers and confirmation responses to track essential data delivery without compromising overall performance. Adding this functionality can offer:
-
Selective Reliability: By targeting only critical packets for acknowledgment, this mechanism would limit retransmissions to essential data, maintaining the continuity of important information while keeping communication lightweight.
-
Flexible Implementation: This acknowledgment system can be enabled or adjusted based on the specific needs of the game engine or application, allowing adaptability according to tolerance for data loss.
By using UDP as the core protocol, this network library maximizes the speed of data exchanges in real-time applications while offering the potential for targeted reliability mechanisms, such as acknowledgments, to offset UDP’s limitations. This combination makes the library ideal for scenarios where performance is paramount while providing the flexibility to meet the unique needs of real-time gaming and other applications.
In our library, network communication between the server and client is a crucial aspect that must be both optimized and robust. One of the primary constraints is the requirement to use UDP communication between the server and client, as the library aims to integrate into the RType project. After researching potential C++ network libraries that support UDP, we initially considered RakNet, a cross-platform C++ library that provides TCP-like reliability features. However, due to project requirements and after discussions with the educational team, we decided to use Asio for this library (see Asio documentation).
Asio was selected for the following reasons:
- Project Requirements: While the RType requires the use of UDP, we are aware of scenarios where TCP might be practical, and Asio offers flexibility to implement both protocols. It’s important to note that implementing TCP may require thorough justification, so it will only be used if absolutely necessary.
- Cross-Platform Compatibility: Like RakNet, Asio is cross-platform, supporting Windows, macOS, and Linux, which aligns with our project's goal of being cross-platform.
- Lightweight and Efficient: Compared to other libraries like Boost.Asio, Asio provides the same core functionality in a more lightweight form, without the additional dependencies that can sometimes lead to performance overhead. Asio can fulfill our network requirements with reduced bloat, making it ideal for performance-sensitive applications such as real-time games.
- Core Functionality: Both libraries offer a robust foundation for asynchronous networking, with support for TCP and UDP protocols.
- Scalability and Flexibility: Both are designed with scalability in mind, making them suitable for applications that need to handle many concurrent connections, such as multiplayer games.
- Dependencies: Boost.Asio is a part of the larger Boost library, which requires incorporating a larger set of dependencies into the project. Asio, on the other hand, is available as a standalone library, making it a lighter option and better suited for projects where minimizing dependencies is a priority.
- Overhead: Boost.Asio can introduce additional overhead due to its integration with the broader Boost ecosystem. In contrast, Asio provides the core networking functionality we need with less overhead, which is ideal for real-time applications where performance is critical.
While Boost.Asio is feature-rich, Asio provides the exact functionality needed for this project without the additional weight of the entire Boost library. Asio’s leaner structure allows us to focus on optimizing our network code for the specific needs of a multiplayer gaming environment, particularly when UDP is mandated.
In summary, Asio was chosen for its lightweight design, support for both UDP and TCP, and ability to meet our project's cross-platform requirements. We will proceed with UDP as the primary protocol, carefully evaluating and justifying any potential inclusion of TCP based on specific project needs.
---
title: Dimension Architecture
---
flowchart TD
A[dimension] --> B[endpoint]
A --> C[packet]
A --> D[IdFactory.cpp//hpp]
B --> E[IEndpoint.hpp]
E --> F[AEndpoint.cpp//hpp]
F --> G[client]
F --> H[server]
F --> I[room]
G --> J[Client.cpp//hpp]
H --> K[AServer.cpp//hpp]
I --> L[Room.cpp//hpp]
C --> M[PacketFactory.cpp//hpp]
C --> N[PacketManager.cpp//hpp]
C --> O[APacket.cpp//hpp]
O --> P[basics]
P --> Q[HiServer
HiClient
AdiosServer
Ping
...]
In an ECS (Entity Component System), entity IDs may not necessarily be shared between the server and client, as the client might have graphical entities that the server does not manage.
To address this, network IDs can be implemented. The IdFactory facilitates the creation and assignment of these network IDs, ensuring proper management across the network.
The PacketManager is responsible for creating and managing different packet types, each derived from APacket, in the Dimension library. By utilizing both empty and deserialized packet instantiation, it enables efficient and flexible packet management for networking.
Key Features
-
Packet Registration: Using
registerPacket, new packet types are registered and assigned unique type IDs. This enables the factory to dynamically instantiate the right packet type when needed, with strict checks ensuring each type derives fromAPacket. -
Packet Creation for Sending:
createPacketToSendcreates an empty instance of a specified packet type. This method supports data preparation before transmission by dynamically retrieving the packet type through its type index. -
Deserialization of Packets:
createPacketFromBuffertakes a serialized buffer, extracts the packet type, and instantiates the correct packet by calling the appropriate constructor. Exception handling ensures robustness, with errors raised for incomplete or malformed data. -
Type Management:
getIndexFromTypeandgetTypeFromIndexmanage the mapping between packet types and indices, enabling easy packet identification and validation across different packet classes.
The PacketFactory is a core class in the Dimension library, designed to centrally create and manage various packet types using a Factory pattern. This enables dynamic creation of packets, whether empty or initialized from received data buffers.
Key Features
-
Packet Creation from Buffer:
createPacketFromBufferconverts a serialized buffer into a usable packet, with exception handling for invalid data. -
Creation of Empty Packets:
createEmptyPacketgenerates packet instances ready to be sent, without initial data. -
Packet Type Management: Methods
getIndexFromTypeandgetTypeFromIndexallow mapping of packet types, simplifying identification and management.
Packet Registration
Upon initialization, PacketFactory registers various packet types (HiServer, CreateEntity, etc.) with the PacketManager, making each type immediately accessible without further changes.
APacket is the abstract containing each packet common methods & attributes. All packet must inherit from APacket to be implemented and used correctly
APacket structure:
#pragma once
#include <chrono>
#include <cstdint>
#include <cstring>
#include <exception>
#include <string>
#include <vector>
namespace dimension
{
class APacket
{
public:
APacket(uint8_t type);
APacket(std::vector<char> &buffer);
virtual ~APacket() = default;
static uint32_t getPacketSizeFromBuffer(std::vector<char> &buffer);
static uint8_t getPacketTypeFromBuffer(std::vector<char> &buffer);
public:
std::vector<char> serialize() const;
std::vector<char> serializeHeader() const;
virtual std::vector<char> serializeData() const = 0;
public:
uint32_t getPacketSize() const;
uint8_t getPacketType() const;
uint64_t getPacketTimeStamp() const;
uint32_t getHeaderSize() const;
protected:
uint32_t _packetSize;
uint8_t _packetType;
uint64_t _packetTimeStamp;
uint16_t _packetDataSize;
};
} // namespace dimensionBasics directory contains all default packet provided by the Dimension library inheriting from APacket.
The Endpoint directory contains the main components handling network communication between the server, client, and rooms. These components share a common communication structure, managed through AEndpoint, which inherits from the IEndpoint interface. This abstract base class centralizes essential network operations, such as sending and receiving packets, to ensure a consistent approach across different endpoints.
-
Packet Transmission (
send):
Thesendmethod is responsible for transmitting packets to a specified endpoint.- Packets are serialized before transmission, with error handling for any serialization issues.
- If the packet is new, it’s added to a validation list to enable retries in case of delivery failure.
- Asynchronous sending via ASIO allows non-blocking operations, with error logging for any issues encountered during transmission.
-
Packet Reception (
receive):
Thereceivemethod listens for incoming data, managing asynchronous data retrieval.- On packet reception,
handleDataReceivedprocesses the data, identifying its type and determining the correct handling. - Received packets are pushed into a queue, allowing further processing by other components.
- On packet reception,
-
Packet Handling (
handleDataReceived):
When data arrives, it’s deserialized into a packet object through thePacketFactory.- Packet validation packets (e.g., acknowledgments) are processed directly by
deleteFromValidationListto update the validation status. - Other packets are enqueued for handling, with their types logged for monitoring purposes.
- Packet validation packets (e.g., acknowledgments) are processed directly by
-
Validation List and Resending Mechanism:
- The
resendValidationListmethod retries sending packets in the validation list if they haven’t been acknowledged within a specified timeframe. - This ensures reliable packet delivery by resending any packet that has not received confirmation.
- The
-
Packet Queue Management:
- The
popReceiveQueueandgetRcvQueuemethods allow other parts of the program to access and manage received packets, ensuring efficient processing of incoming data.
- The
Previous page: Dimension Documentation
Next page: Protocol
This project was developed and documented by the MarmotteurInc team.