R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
ENetHost.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** Created by IamSwan on 06/12/2025.
4** File description:
5** ENetHost.cpp
6*/
7
8#include "ENetHost.hpp"
9#include <stdexcept>
10#include <string>
11#include "ENetAddress.hpp"
12#include "ENetPacket.hpp"
13#include "ENetPeer.hpp"
14
15// Client constructor
16ENetHostWrapper::ENetHostWrapper(size_t maxConnections, size_t maxChannels, uint32_t incomingBandwidth,
17 uint32_t outgoingBandwidth) {
18 _host = enet_host_create(nullptr, maxConnections, maxChannels, incomingBandwidth, outgoingBandwidth);
19 if (!_host) {
20 throw std::runtime_error("Failed to create ENet client host");
21 }
22 // Enable built-in range coder compression for bandwidth reduction
23 enet_host_compress_with_range_coder(_host);
24}
25
26// Server constructor
27ENetHostWrapper::ENetHostWrapper(const IAddress &address, size_t maxConnections, size_t maxChannels,
28 uint32_t incomingBandwidth, uint32_t outgoingBandwidth) {
29 const auto *enetAddr = dynamic_cast<const ENetAddressWrapper *>(&address);
30 if (!enetAddr) {
31 throw std::invalid_argument("Address must be an ENetAddressWrapper");
32 }
33
34 const ENetAddress &nativeAddr = enetAddr->getNativeAddress();
35 _host = enet_host_create(&nativeAddr, maxConnections, maxChannels, incomingBandwidth, outgoingBandwidth);
36 if (!_host) {
37 // ENet doesn't provide specific error codes, but provide helpful context
38 uint16_t port = ENET_NET_TO_HOST_16(nativeAddr.port);
39 std::string errorMsg =
40 "Failed to create ENet server host on port " + std::to_string(port) + ". Possible causes:\n" +
41 " - Port already in use (another server instance running?)\n" +
42 " - Insufficient permissions (try a port > 1024)\n" + " - Invalid network configuration";
43 throw std::runtime_error(errorMsg);
44 }
45 // Enable built-in range coder compression for bandwidth reduction
46 enet_host_compress_with_range_coder(_host);
47}
48
50 if (_host) {
51 enet_host_destroy(_host);
52 }
53}
54
55IPeer *ENetHostWrapper::connect(const IAddress &address, size_t channelCount, uint32_t data) {
56 const auto *enetAddr = dynamic_cast<const ENetAddressWrapper *>(&address);
57 if (!enetAddr) {
58 throw std::invalid_argument("Address must be an ENetAddressWrapper");
59 }
60
61 const ENetAddress &nativeAddr = enetAddr->getNativeAddress();
62 ENetPeer *peer = enet_host_connect(_host, &nativeAddr, channelCount, data);
63 if (!peer) {
64 throw std::runtime_error("Failed to connect to host");
65 }
66
67 // Store peer wrapper
68 auto peerWrapper = std::make_unique<ENetPeerWrapper>(peer);
69 IPeer *result = peerWrapper.get();
70 _peers[peer] = std::move(peerWrapper);
71
72 return result;
73}
74
75std::optional<HostNetworkEvent> ENetHostWrapper::service(uint32_t timeout) {
76 ENetEvent event;
77 int result = enet_host_service(_host, &event, timeout);
78
79 if (result > 0) {
80 HostNetworkEvent netEvent;
81 netEvent.channelID = event.channelID;
82
83 switch (event.type) {
84 case ENET_EVENT_TYPE_CONNECT:
86 // Create peer wrapper if not exists
87 if (_peers.find(event.peer) == _peers.end()) {
88 auto peerWrapper = std::make_unique<ENetPeerWrapper>(event.peer);
89 netEvent.peer = peerWrapper.get();
90 _peers[event.peer] = std::move(peerWrapper);
91
92 // Configure peer timeout for faster disconnect detection
93 // limit: max number of unacknowledged packets before disconnect
94 // minimum: min timeout in milliseconds (1000ms = 1s)
95 // maximum: max timeout in milliseconds (3000ms = 3s)
96 enet_peer_timeout(event.peer, 5, 1000, 3000);
97 } else {
98 netEvent.peer = _peers[event.peer].get();
99 }
100 break;
101
102 case ENET_EVENT_TYPE_DISCONNECT:
104 if (_peers.find(event.peer) != _peers.end()) {
105 netEvent.peer = _peers[event.peer].get();
106 }
107 break;
108
109 case ENET_EVENT_TYPE_RECEIVE:
111 if (_peers.find(event.peer) != _peers.end()) {
112 netEvent.peer = _peers[event.peer].get();
113 }
114 netEvent.packet = std::make_unique<ENetPacketWrapper>(event.packet);
115 break;
116
117 default:
118 return std::nullopt;
119 }
120
121 return netEvent;
122 }
123
124 return std::nullopt;
125}
126
127void ENetHostWrapper::broadcast(std::unique_ptr<IPacket> packet, uint8_t channelID) {
128 if (!packet) {
129 return;
130 }
131
132 auto *enetPacket = dynamic_cast<ENetPacketWrapper *>(packet.get());
133 if (!enetPacket) {
134 throw std::invalid_argument("Packet must be an ENetPacketWrapper");
135 }
136
137 ENetPacket *nativePacket = enetPacket->getNativePacket();
138 enet_host_broadcast(_host, channelID, nativePacket);
139
140 (void)packet.release(); // ENet owns the packet now
141}
142
144 if (_host) {
145 enet_host_flush(_host);
146 }
147}
148
150 return _host ? _host->connectedPeers : 0;
151}
152
154 if (!_host) {
155 throw std::runtime_error("Host is null");
156 }
157
158 // Create and cache the address wrapper in member variable
159 // This ensures thread-safety and correct address for this specific host
160 if (!_cachedAddress) {
161 _cachedAddress = std::make_unique<ENetAddressWrapper>(_host->address);
162 }
163 return *_cachedAddress;
164}
@ RECEIVE
A packet was received.
@ CONNECT
A peer has connected.
@ DISCONNECT
A peer has disconnected.
std::map< ENetPeer *, std::unique_ptr< ENetPeerWrapper > > _peers
Definition ENetHost.hpp:43
void broadcast(std::unique_ptr< IPacket > packet, uint8_t channelID) override
Broadcast a packet to all connected peers.
Definition ENetHost.cpp:127
IPeer * connect(const IAddress &address, size_t channelCount, uint32_t data) override
Connect to a remote host.
Definition ENetHost.cpp:55
std::optional< HostNetworkEvent > service(uint32_t timeout) override
Service the host, processing network events.
Definition ENetHost.cpp:75
const IAddress & getAddress() const override
Get the address this host is bound to.
Definition ENetHost.cpp:153
~ENetHostWrapper() override
Definition ENetHost.cpp:49
std::unique_ptr< ENetAddressWrapper > _cachedAddress
Definition ENetHost.hpp:44
void flush() override
Send all queued packets immediately.
Definition ENetHost.cpp:143
ENetHostWrapper(size_t maxConnections=1, size_t maxChannels=2, uint32_t incomingBandwidth=0, uint32_t outgoingBandwidth=0)
Definition ENetHost.cpp:16
ENetHost * _host
Definition ENetHost.hpp:42
size_t getPeerCount() const override
Get the number of connected peers.
Definition ENetHost.cpp:149
Interface representing a network address (IP + port).
Definition IAddress.hpp:21
Interface representing a remote peer in the network.
Definition IPeer.hpp:40
Represents a network event (connection, disconnection, or received data).
Definition IHost.hpp:32
NetworkEventType type
Type of the event.
Definition IHost.hpp:33
std::unique_ptr< IPacket > packet
Packet received (only for RECEIVE events).
Definition IHost.hpp:35
IPeer * peer
Peer associated with the event.
Definition IHost.hpp:34
uint8_t channelID
Channel on which the event occurred.
Definition IHost.hpp:36