Repository navigation
[Holtzman Engine] Network
This section details the role of the network within the engine, covering its integration with the ECS (Entity-Component-System) as well as the choices made to manage communication and data processing. It also explains how network features are integrated into the engine through scripts, systems, and components.
The network integration within the Holtzman Engine uses a combination of systems, scripts, and components to establish seamless communication between clients and servers. The Dimension library enables networking capabilities in the engine through carefully structured ECS (Entity-Component-System) elements:
-
Network Components: Components, like
NetworkRoom, provide core network functionality and resources needed by systems and scripts. For instance,NetworkRoomstores network resources such as room instances, packet factories, and ID management from Dimension network library.
Here is a example of a network component in the ECS:
struct NetworkRoom
{
std::shared_ptr<dimension::Room> room = nullptr;
dimension::PacketFactory factory;
dimension::IdFactory idFactory;
NetworkRoom() {}
static constexpr const char* name = "NetworkRoom";
};-
Network Scripts: Scripts, such as
ComServer, are responsible for handling specific network-related behaviors within the ECS. These scripts update entities with network data, manage communication protocols, and interact with the core network components to synchronize game states.
Here is a example of a network script in the ECS:
class ComServer : public RType::ICppScript
{
public:
void update(mobs::Registry ®istry, GameContext &gameContext) override
{
...
}
static constexpr const char *name = "ComServer";
private:
};-
Network Systems: Systems like
RoomSystemcoordinate the initialization, processing, and updating of network-related components and scripts within the ECS. Systems provide the main processing loop for network events, handling tasks such as packet management, latency tracking, and room synchronization.
Here is a example of a network system in the ECS:
class RoomSystem : public ISystem
{
public:
RoomSystem() {}
~RoomSystem() {}
void load(mobs::Registry ®istry, GameContext &gameContext) override
{
...
}
private:
bool _loadedOnce = false;
};Together, these elements enable the Holtzman Engine to support dynamic, real-time networking by organizing network data flow and interactions in a modular, ECS-based approach. This integration allows for efficient handling of multiple clients, network scalability, and easy customization, essential for a robust multiplayer environment.
One of the main challenges in developing the ECS network with the Dimension library was determining which packets to send and when.
For example, in a basic UDP protocol, player movement might be handled by sending a packet every cycle, as shown below:

In this example, many packets are sent to ensure that if one is lost, the next packet will correct the movement issue.
However, in our development process, we aimed to minimize the number of packets sent to better handle a larger number of clients efficiently.
During development, we implemented two main strategies to minimize packet transmissions:
- Sending a single packet per action
For example, in player movement, the client first sends an event packet to the server to request starting the movement. The client only begins displaying the movement on its side once it receives an acknowledgment (ACK) with an Update packet from the server, confirming that the action is also being performed on the server. When the player stops moving, the client sends another event packet to stop the movement on the server’s side. The server then processes the stop event and calculates any necessary corrections to "rollback" the client’s position if needed. This approach emphasizes the importance of ACKs for all packets except for pings, ensuring synchronized actions between client and server.
Here is an illustration based on movement example:

- Establishing a minimum delay between pings
To avoid unnecessary network traffic, we set a delay of 50ms between each ping call, ensuring a balance between connection stability checks and network efficiency.
Together, these optimizations help ensure reliable gameplay with minimal packet usage, supporting efficient scaling for multiple clients.
Latency within the game engine is managed carefully to maintain consistency in packet transmission and reception. All packets are accepted as long as the sender's latency is under 600 milliseconds. Clients are regularly updated on the average latency for packet transmission to and from the room.
To determine this average latency, the system uses a bidirectional ping calculation:
- A ping packet is sent with both a creation timestamp and a reception timestamp.
- When the server or client receives this packet, it checks if the reception timestamp is set to
0. If it is, the receiving endpoint updates the timestamp and returns the packet to the sender. - When the packet is received back, the latency is calculated using the formula:
Latency = Current Timestamp - Creation Timestamp
This approach has the advantage of relying solely on the originating clock, as system clocks can vary between different machines, providing a reliable measure of round-trip latency.
An enhancement to this system could involve incorporating advanced time synchronization protocols, such as Network Time Protocol (NTP) or Precision Time Protocol (PTP). These protocols could help align the server and client clocks more precisely, especially useful in high-stress network environments where accurate timing is essential. By reducing time discrepancies across systems, this approach would further improve the accuracy of latency measurements, leading to a more consistent and smooth gameplay experience.
And more...
Previous page: Graphic
Next page: Accessibility
This project was developed and documented by the MarmotteurInc team.