FastEngine 0.9.5
A multiplayer oriented 2D engine made with Vulkan.
Loading...
Searching...
No Matches
C_server.hpp
1/*
2 * Copyright 2026 Guillaume Guillet
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _FGE_C_SERVER_HPP_INCLUDED
18#define _FGE_C_SERVER_HPP_INCLUDED
19
20#include "FastEngine/fge_extern.hpp"
21#include "C_socket.hpp"
22#include "FastEngine/C_flag.hpp"
23#include "FastEngine/network/C_clientList.hpp"
24#include "FastEngine/network/C_netCommand.hpp"
25#include "FastEngine/network/C_packet.hpp"
26#include "FastEngine/network/C_protocol.hpp"
27#include <condition_variable>
28#include <future>
29#include <memory>
30#include <mutex>
31#include <queue>
32#include <thread>
33
34
35#if defined(FGE_ENABLE_SERVER_NETWORK_RANDOM_LOST) || defined(FGE_ENABLE_CLIENT_NETWORK_RANDOM_LOST)
36 #include "FastEngine/C_random.hpp"
37#endif
38
39#define FGE_SERVER_DEFAULT_MAXPACKET 200
40#define FGE_SERVER_MAX_TIME_DIFFERENCE_REALM \
41 std::chrono::milliseconds \
42 { \
43 2000 \
44 }
45
46#define FGE_SERVER_PACKET_RECEPTION_TIMEOUT_MS 250
47#define FGE_SERVER_CLIENTS_MAP_GC_DELAY_MS 5000
48
49namespace fge
50{
51using ObjectSid = uint32_t;
52} // namespace fge
53
54namespace fge::net
55{
56
59
60enum class FluxProcessResults
61{
62 USER_RETRIEVABLE,
63
64 INTERNALLY_HANDLED,
65 INTERNALLY_DISCARDED,
66
67 NONE_AVAILABLE
68};
69
70enum class ReturnEvents
71{
72 REVT_SIMPLE,
73 REVT_OBJECT,
74 REVT_ASK_FULL_UPDATE,
75 REVT_COMPLEX
76};
77
78class FGE_API ReturnPacketHandler
79{
80public:
81 ReturnPacketHandler() = default;
82 virtual ~ReturnPacketHandler() = default;
83
84 [[nodiscard]] std::optional<Error>
85 handleReturnPacket(ClientSharedPtr const& refClient, ClientContext& clientContext, ReceivedPacketPtr& packet) const;
86
88 _onClientReturnPacket;
90 _onClientReturnEvent;
92 mutable UniqueCallbackHandler<ClientSharedPtr const&,
93 Identity const&,
94 uint16_t,
95 ObjectSid,
96 ObjectSid,
97 ReceivedPacketPtr const&>
98 _onClientObjectReturnEvent;
100};
101
113class FGE_API NetFluxUdp
114{
115public:
116 NetFluxUdp(bool defaultFlux);
117 NetFluxUdp(NetFluxUdp const& r) = delete;
118 NetFluxUdp(NetFluxUdp&& r) noexcept = delete;
119 virtual ~NetFluxUdp();
120
121 NetFluxUdp& operator=(NetFluxUdp const& r) = delete;
122 NetFluxUdp& operator=(NetFluxUdp&& r) noexcept = delete;
123
124 void clearPackets();
125 [[nodiscard]] ReceivedPacketPtr popNextPacket();
126
127 [[nodiscard]] std::size_t getPacketsSize() const;
128 [[nodiscard]] bool isEmpty() const;
129
130 void setMaxPackets(std::size_t n);
131 [[nodiscard]] std::size_t getMaxPackets() const;
132
133 [[nodiscard]] bool isDefaultFlux() const;
134
135protected:
136 bool pushPacket(ReceivedPacketPtr&& fluxPck);
137 void forcePushPacket(ReceivedPacketPtr fluxPck);
138 void forcePushPacketFront(ReceivedPacketPtr fluxPck);
139
140 mutable std::mutex _g_mutexFlux;
141 std::deque<ReceivedPacketPtr> _g_packets;
142 std::size_t _g_remainingPackets{0};
143
144private:
145 std::size_t g_maxPackets = FGE_SERVER_DEFAULT_MAXPACKET;
146 bool g_isDefaultFlux{false};
147
148 friend class ServerSideNetUdp;
149 friend class PacketReorderer;
150};
151
152class FGE_API ServerNetFluxUdp : public NetFluxUdp, public ReturnPacketHandler
153{
154public:
155 ServerNetFluxUdp(ServerSideNetUdp& server, bool defaultFlux);
156 ~ServerNetFluxUdp() override = default;
157
158 void processClients();
159 [[nodiscard]] FluxProcessResults process(ClientSharedPtr& refClient, ReceivedPacketPtr& packet);
160
161 void disconnectAllClients(std::chrono::milliseconds delay = std::chrono::milliseconds(0)) const;
162
163 ClientList _clients;
164
167
172
173private:
174 [[nodiscard]] bool verifyRealm(ClientSharedPtr const& refClient, ReceivedPacketPtr const& packet);
175
176 [[nodiscard]] FluxProcessResults processUnknownClient(ClientSharedPtr& refClient, ReceivedPacketPtr& packet);
177
178 ServerSideNetUdp* const g_server{nullptr};
179 std::chrono::milliseconds g_commandsUpdateTick{0};
180 std::chrono::steady_clock::time_point g_lastCommandUpdateTimePoint{std::chrono::steady_clock::now()};
181};
182
196class FGE_API ServerSideNetUdp
197{
198public:
199 explicit ServerSideNetUdp(IpAddress::Types addressType = IpAddress::Types::Ipv4);
200 ServerSideNetUdp(ServerSideNetUdp const& r) = delete;
201 ServerSideNetUdp(ServerSideNetUdp&& r) noexcept = delete;
202 ~ServerSideNetUdp();
203
204 ServerSideNetUdp& operator=(ServerSideNetUdp const& r) = delete;
205 ServerSideNetUdp& operator=(ServerSideNetUdp&& r) noexcept = delete;
206
207 void setVersioningString(std::string_view versioningString);
208 [[nodiscard]] std::string const& getVersioningString() const;
209
210 [[nodiscard]] bool
211 start(Port bindPort, IpAddress const& bindIp, IpAddress::Types addressType = IpAddress::Types::None);
212 [[nodiscard]] bool start(IpAddress::Types addressType = IpAddress::Types::None);
213 void stop();
214
230 [[nodiscard]] ServerNetFluxUdp* newFlux();
231
232 [[nodiscard]] ServerNetFluxUdp* getFlux(std::size_t index);
233 [[nodiscard]] ServerNetFluxUdp* getDefaultFlux();
234
235 [[nodiscard]] std::size_t getFluxSize() const;
236
237 [[nodiscard]] IpAddress::Types getAddressType() const;
238
239 void closeFlux(NetFluxUdp* flux);
240 void closeAllFlux();
241
242 void repushPacket(ReceivedPacketPtr&& packet);
243
252 [[nodiscard]] bool isRunning() const;
253
254 [[nodiscard]] bool announceNewClient(Identity const& identity, ClientSharedPtr const& client);
255
256 void sendTo(TransmitPacketPtr& pck, Client const& client, Identity const& id);
257 void sendTo(TransmitPacketPtr& pck, Identity const& id);
258
259 [[nodiscard]] void* getCryptContext() const;
260
261private:
262 void threadReception();
263 void threadTransmission();
264
265 std::unique_ptr<std::thread> g_threadReception;
266 std::unique_ptr<std::thread> g_threadTransmission;
267
268 std::condition_variable g_transmissionNotifier;
269
270 mutable std::mutex g_mutexServer;
271
272 std::vector<std::unique_ptr<ServerNetFluxUdp>> g_fluxes;
273 ServerNetFluxUdp g_defaultFlux;
274 std::queue<std::pair<TransmitPacketPtr, Identity>> g_transmissionQueue;
275
276 std::unordered_map<Identity, std::weak_ptr<Client>, IdentityHash> g_clientsMap;
277
278 SocketUdp g_socket;
279 bool g_running;
280
281 void* g_crypt_ctx;
282
283 std::string g_versioningString;
284};
285
293class FGE_API ClientSideNetUdp : public NetFluxUdp
294{
295public:
296 explicit ClientSideNetUdp(IpAddress::Types addressType = IpAddress::Types::Ipv4);
297 ClientSideNetUdp(ClientSideNetUdp const& r) = delete;
298 ClientSideNetUdp(ClientSideNetUdp&& r) noexcept = delete;
299 ~ClientSideNetUdp() override;
300
301 ClientSideNetUdp& operator=(ClientSideNetUdp const& r) = delete;
302 ClientSideNetUdp& operator=(ClientSideNetUdp&& r) noexcept = delete;
303
304 [[nodiscard]] bool start(Port bindPort,
305 IpAddress const& bindIp,
306 Port connectRemotePort,
307 IpAddress const& connectRemoteAddress,
308 IpAddress::Types addressType = IpAddress::Types::None);
309 void stop();
310
311 void notifyTransmission();
312 [[nodiscard]] bool isRunning() const;
313
314 [[nodiscard]] std::future<uint16_t> retrieveMTU();
315 [[nodiscard]] std::future<bool> connect(std::string_view versioningString = std::string_view{});
316 [[nodiscard]] std::future<void> disconnect();
317
318 [[nodiscard]] IpAddress::Types getAddressType() const;
319
320 [[nodiscard]] std::size_t waitForPackets(std::chrono::milliseconds time_ms);
321
322 [[nodiscard]] Identity const& getClientIdentity() const;
323
324 template<class TPacket = Packet>
325 void sendTo(TransmitPacketPtr& pck, Identity const& id);
326
327 enum ProcessOptions : uint32_t
328 {
329 OPTION_NONE = 0,
330 OPTION_NO_TIMEOUT = 1 << 0,
331 OPTION_ONE_SHOT = 1 << 1
332 };
333 [[nodiscard]] FluxProcessResults process(ReceivedPacketPtr& packet,
334 EnumFlags<ProcessOptions> options = OPTION_NONE);
335
336 void resetReturnPacket();
337 [[nodiscard]] TransmitPacketPtr& startComplexReturnEvent(uint16_t id);
338 TransmitPacketPtr& startObjectReturnEvent(uint16_t commandIndex, ObjectSid parentSid, ObjectSid targetSid);
339 void endReturnEvent();
340
341 void simpleReturnEvent(uint16_t id);
342 bool askFullUpdateReturnEvent();
343
344 void enableReturnPacket(bool enable);
345 [[nodiscard]] bool isReturnPacketEnabled() const;
346
347 [[nodiscard]] TransmitPacketPtr prepareAndRetrieveReturnPacket();
348 [[nodiscard]] std::optional<Error> loopbackReturnPacket(ReturnPacketHandler const& handler);
349
350 Client _client; //But it is the server :O
351
352 CallbackHandler<ClientSideNetUdp&> _onClientTimeout;
353 CallbackHandler<ClientSideNetUdp&> _onClientDisconnected;
354
356
357private:
358 void threadReception();
359 void threadTransmission();
360
361 TransmitPacketPtr& startReturnEvent(ReturnEvents event);
362
363 std::unique_ptr<std::thread> g_threadReception;
364 std::unique_ptr<std::thread> g_threadTransmission;
365
366 std::condition_variable g_transmissionNotifier;
367 std::condition_variable g_receptionNotifier;
368
369 SocketUdp g_socket;
370 bool g_running{false};
371
372 Identity g_clientIdentity;
373
374 std::recursive_mutex g_mutexCommands;
375
376 bool g_returnPacketEnabled{false};
377 TransmitPacketPtr g_returnPacket;
378 bool g_returnPacketEventStarted{false};
379 std::size_t g_returnPacketStartPosition{0};
380 bool g_isAskingFullUpdate{false};
381 uint16_t g_returnPacketEventCount{0};
382 std::chrono::steady_clock::time_point g_returnPacketTimePoint;
383
384 void* g_crypt_ctx{nullptr};
385};
386
387} // namespace fge::net
388
389#include "C_server.inl"
390
391#endif // _FGE_C_SERVER_HPP_INCLUDED
This class is used to handle callbacks in a safe way.
Definition C_callback.hpp:244
A class to handle "flags" for an enum type.
Definition C_flag.hpp:106
This class is used for cases where only one callback is needed.
Definition C_callback.hpp:422
A list of clients used by a server.
Definition C_clientList.hpp:42
A client side network manager.
Definition C_server.hpp:294
void sendTo(TransmitPacketPtr &pck, Identity const &id)
Definition C_server.inl:23
Class that represent the identity of a client.
Definition C_client.hpp:239
A class to represent an IP address.
Definition C_ipAddress.hpp:57
A network flux.
Definition C_server.hpp:114
Definition C_server.hpp:79
Definition C_server.hpp:153
A server side network manager.
Definition C_server.hpp:197
void notifyTransmission()
Notify the transmission thread.
ServerNetFluxUdp * newFlux()
Create a new flux.
A wrapper for UDP sockets inheriting from Socket.
Definition C_socket.hpp:355
Definition C_client.hpp:173
A class to hash an Identity (useful for std::unordered_map or other containers).
Definition C_identity.hpp:52
A class to represent a client or server identity with an IP address and a port.
Definition C_identity.hpp:31