Network Subsystem

Overview

The Network Subsystem is a critical part responsible for managing the network communication of the game engine. Leveraging the Asio and ReflectCPP libraries, this subsystem handles several key responsibilities:

  • Network initialization

  • Connection management

  • Data transmission

  • Packet processing

  • Error handling

Protocol

The network subsystem uses a custom protocol to manage communication between the server and clients. The protocol is designed to be the most user-friendly and efficient as possible, that’s why we’re using ReflectCPP to serialize packets with bson.

Packet Structure

Each packet is double serialized, first with the data you want to send, and then with the packet header.

The packet header has the following structure:

#pragma once

#include <vector>
#include <cstdint>
#include <rfl/Bytestring.hpp>

namespace BBOC
{
    struct Packet
    {
        std::size_t type;
        std::int32_t order;
        std::uint8_t index;
        std::uint8_t count;
        std::uint32_t checksum;
        rfl::Bytestring data;
    };
}
  • type: The type of the packet used to recognize the packet.

  • order: The order of the packet in the sequence.

  • index: The index of the packet in the fragment.

  • count: The total count of the packet in the fragment.

  • checksum: The checksum of the packet for error or corruption detection.

  • data: The compressed serialized data.

Packet Fragmentation

To avoid packet loss, we use packet fragmentation. If the packet is too big, we split it into smaller packets and send them separately.

Packet Recovery

If a packet is lost, we send a missing packet request to the sender to resend the lost packets.

Packet compression

To reduce the size of the packet, we compress the serialized data with the Zlib library.

Packet Types

Client

Type

Packet ID

Description

ClientConnectionDto

000

Connection request

ClientDisconnectionDto

001

Disconnection request

ClientInputPressedDto

002

Input pressed

ClientInputReleasedDto

003

Input released

ClientJoystickMoveDto

004

Joystick move

Server

Type

Packet ID

Description

ServerUpdateActorDto

100

Update actor properties

ServerRemoveActorDto

101

Remove actor

ServerUpdateCameraDto

102

Update camera properties

ServerChangeWorldDto

103

Change world

ServerGameSynchronizeDto

104

Game synchronize

Meta

Type

Packet ID

Description

PingDto

200

Ping request

MissingPacketDto

201

Missing packet

Packet Definitions

Client

Client Connection

Send a connection request to the server.
Packet Id: 000

Packet Structure
#pragma once
namespace BBOC
{
    struct ClientConnectionDto
    {
    };
} // BBOC
Client Disconnection

Send a disconnection request to the server.
Packet Id: 001

Packet Structure
#pragma once
namespace BBOC
{
    struct ClientDisconnectionDto
    {
    };
} // BBOC
Client Input Pressed

Send a pressed input to the server.
Packet Id: 002

Packet Structure
#pragma once
namespace BBOC
{
    struct ClientInputPressedDto
    {
        int key;
    };
}
Client Input Released

Send a released input to the server.
Packet Id: 003

Packet Structure
#pragma once
namespace BBOC
{
    struct ClientInputReleasedDto
    {
        int key;
    };
} // BBOC
Client Joystick Move

Send a joystick move to the server.
Packet Id: 004

Packet Structure
#pragma once
namespace BBOC
{
    struct ClientJoystickMoveDto
    {
        int joystickId;
        int axis;
        float position;
    };
} // BBOC

Server

Server Update Actor

Update actor properties.
Packet Id: 100

Packet Structure
#pragma once

#include "bboc/engine/subsystem/network/dto/server/ServerUpdateComponentDto.hpp"

#include "bboc/engine/util/UID.hpp"
#include "rfl/Bytestring.hpp"

#include <vector>
#include <optional>

namespace BBOC
{
    struct ServerUpdateActorDto
    {
        UID id;
        UID worldId;
        UID actorType;
        double positionX;
        double positionY;
        double scaleX;
        double scaleY;
        double rotation;

        bool followCamera;

        std::vector<ServerUpdateComponentDto> componentsData;
        std::optional<rfl::Bytestring> actorData;
    };
} // BBOC
  • actorType: The type of the actor defined by the registered actor order in the game.

  • componentsData: The serialized components data see Component Handling for more information.

  • actorData: The serialized actor data see Component Handling for more information.

Server Remove Actor

Remove actor.
Packet Id: 101

Packet Structure
#pragma once

#include "bboc/engine/util/UID.hpp"

namespace BBOC
{
    struct ServerRemoveActorDto
    {
        UID id;
        UID worldId;
    };
} // BBOC
Server Update Camera

Update camera properties.
Packet Id: 102

Packet Structure
#pragma once
namespace BBOC
{
    struct ServerUpdateCameraDto
    {
        double positionX;
        double positionY;
        double sizeX;
        double sizeY;
    };
} // BBOC
Server Change World

Change world.
Packet Id: 103

Packet Structure
#pragma once

#include "bboc/engine/util/UID.hpp"

namespace BBOC {
    struct ServerChangeWorldDto {
        UID worldId;
        UID worldType;
    };
}
Server Game Synchronize

Game synchronize.
Packet Id: 104

Packet Structure
#pragma once

#include "bboc/engine/util/UID.hpp"

#include <rfl/Bytestring.hpp>

namespace BBOC {
    struct ServerGameSynchronizeDto {
        UID worldId;
        UID worldType;

        rfl::Bytestring gameData;
        rfl::Bytestring worldData;
    };
}

Meta

Ping

Ping request.
Packet Id: 200

Packet Structure
#pragma once
namespace BBOC
{
    struct PingDto
    {
    };
} // BBOC
Missing Packet

Missing packet.
Packet Id: 201

Packet Structure
#pragma once

#include <vector>
#include <cstdint>

namespace BBOC {
    struct PacketFragmentDto
    {
        std::int32_t packetId;
        std::int32_t fragmentId;
    };

    struct MissingPacketDto
    {
        std::vector<PacketFragmentDto> missingPackets;
        uint32_t lastReceivedPacket;
    };
}

Packet Serialization

To serialize packets, we use the ReflectCPP library. This library allows us to serialize and deserialize packets with ease. But this library has limitations when it comes to serializing complex data structures, so we use basic structures to serialize packets.

Example

struct ClientInputPressedDto
{
    int key;
};

Network Schema

We made a schema to help us understand the network subsystem’s structure and how interactions client-server are actually working.

Network Schema

Component Handling

If you want to create a new component that uses the network subsystem, you need to inherit from the SynchronizedComponent class.

Check the SynchronizedComponent class in the network_subsystem_component.md file for more information.