FastEngine 0.9.3
A multiplayer oriented 2D engine made with Vulkan.
Loading...
Searching...
No Matches
C_server.inl
1/*
2 * Copyright 2024 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
17namespace fge::net
18{
19
20//FluxPacket
21
22inline FluxPacket::FluxPacket(Packet const& pck, Identity const& id, std::size_t fluxIndex, std::size_t fluxCount) :
23 ProtocolPacket(pck),
24 g_id(id),
25 g_timestamp(Client::getTimestamp_ms()),
26 g_fluxIndex(fluxIndex),
27 g_fluxCount(fluxCount)
28{}
29inline FluxPacket::FluxPacket(Packet&& pck, Identity const& id, std::size_t fluxIndex, std::size_t fluxCount) :
30 ProtocolPacket(std::move(pck)),
31 g_id(id),
32 g_timestamp(Client::getTimestamp_ms()),
33 g_fluxIndex(fluxIndex),
34 g_fluxCount(fluxCount)
35{}
36
37inline Timestamp FluxPacket::getTimeStamp() const
38{
39 return this->g_timestamp;
40}
41inline Identity const& FluxPacket::getIdentity() const
42{
43 return this->g_id;
44}
45
46//ServerSideNetUdp
47
48template<class TPacket>
49bool ServerSideNetUdp::start(Port bindPort, IpAddress const& bindIp, IpAddress::Types addressType)
50{
51 if (this->g_running)
52 {
53 return false;
54 }
55 this->g_socket.setAddressType(addressType);
56 if (this->g_socket.bind(bindPort, bindIp) == Socket::ERR_NOERROR)
57 {
58 this->g_running = true;
59
60 this->g_threadReception = std::make_unique<std::thread>(&ServerSideNetUdp::threadReception<TPacket>, this);
61 this->g_threadTransmission =
62 std::make_unique<std::thread>(&ServerSideNetUdp::threadTransmission<TPacket>, this);
63
64 return true;
65 }
66 return false;
67}
68template<class TPacket>
69bool ServerSideNetUdp::start(IpAddress::Types addressType)
70{
71 if (this->g_running)
72 {
73 return false;
74 }
75 this->g_socket.setAddressType(addressType);
76 if (this->g_socket.isValid())
77 {
78 this->g_running = true;
79
80 this->g_threadReception = std::make_unique<std::thread>(&ServerSideNetUdp::threadReception<TPacket>, this);
81 this->g_threadTransmission =
82 std::make_unique<std::thread>(&ServerSideNetUdp::threadTransmission<TPacket>, this);
83
84 return true;
85 }
86 return false;
87}
88
89template<class TPacket>
90void ServerSideNetUdp::threadReception()
91{
92 Identity idReceive;
93 TPacket pckReceive;
94 std::size_t pushingIndex = 0;
95
96 while (this->g_running)
97 {
98 if (this->g_socket.select(true, 500) == Socket::ERR_NOERROR)
99 {
100 if (this->g_socket.receiveFrom(pckReceive, idReceive._ip, idReceive._port) == Socket::ERR_NOERROR)
101 {
102#ifdef FGE_ENABLE_SERVER_NETWORK_RANDOM_LOST
103 if (fge::_random.range(0, 1000) <= 10)
104 {
105 continue;
106 }
107#endif
108
109 std::scoped_lock const lck(this->g_mutexServer);
110
111 if (pckReceive.getDataSize() < ProtocolPacket::HeaderSize)
112 { //Bad header, packet is dismissed
113 continue;
114 }
115
116 //Skip the header for reading
117 pckReceive.skip(ProtocolPacket::HeaderSize);
118 auto fluxPacket = std::make_unique<FluxPacket>(std::move(pckReceive), idReceive);
119
120 //Verify headerId
121 auto const header = fluxPacket->retrieveHeader().value();
122 if ((header & ~FGE_NET_HEADER_FLAGS_MASK) == FGE_NET_BAD_HEADERID ||
123 (header & FGE_NET_HEADER_LOCAL_REORDERED_FLAG) > 0)
124 { //Bad headerId, packet is dismissed
125 continue;
126 }
127
128 //Realm and countId is verified by the flux who have the corresponding client
129
130 if (this->g_fluxes.empty())
131 {
132 this->g_defaultFlux.pushPacket(std::move(fluxPacket));
133 continue;
134 }
135
136 //Try to push packet in a flux
137 for (std::size_t i = 0; i < this->g_fluxes.size(); ++i)
138 {
139 pushingIndex = (pushingIndex + 1) % this->g_fluxes.size();
140 fluxPacket->g_fluxIndex = pushingIndex;
141 if (this->g_fluxes[pushingIndex]->pushPacket(std::move(fluxPacket)))
142 { //Packet is correctly pushed
143 break;
144 }
145 }
146 //If every flux is busy, the new packet is dismissed
147 }
148 }
149 }
150}
151template<class TPacket>
152void ServerSideNetUdp::threadTransmission()
153{
154 std::unique_lock lckServer(this->g_mutexServer);
155
156 while (this->g_running)
157 {
158 this->g_transmissionNotifier.wait_for(lckServer, std::chrono::milliseconds(10));
159
160 //Checking fluxes
161 for (std::size_t i = 0; i < this->g_fluxes.size() + 1; ++i)
162 {
163 ClientList* clients{nullptr};
164 if (i == this->g_fluxes.size())
165 { //Doing the default flux
166 clients = &this->g_defaultFlux._clients;
167 }
168 else
169 {
170 clients = &this->g_fluxes[i]->_clients;
171 }
172
173 auto clientLock = clients->acquireLock();
174
175 for (auto itClient = clients->begin(clientLock); itClient != clients->end(clientLock); ++itClient)
176 {
177 if (itClient->second->isPendingPacketsEmpty())
178 {
179 continue;
180 }
181
182 if (itClient->second->getLastPacketElapsedTime() < itClient->second->getSTOCLatency_ms())
183 {
184 continue;
185 }
186
187 auto transmissionPacket = itClient->second->popPacket();
188
189 if (!transmissionPacket->packet() || !transmissionPacket->packet().haveCorrectHeaderSize())
190 { //Last verification of the packet
191 continue;
192 }
193
194 //Applying options
195 transmissionPacket->applyOptions(*itClient->second);
196
197 //Sending the packet
198 TPacket packet(transmissionPacket->packet());
199 this->g_socket.sendTo(packet, itClient->first._ip, itClient->first._port);
200 itClient->second->resetLastPacketTimePoint();
201 }
202 }
203
204 //Checking isolated transmission queue
205 while (!this->g_transmissionQueue.empty())
206 {
207 auto data = std::move(this->g_transmissionQueue.front());
208 this->g_transmissionQueue.pop();
209
210 if (!data.first->packet() || !data.first->packet().haveCorrectHeaderSize())
211 { //Last verification of the packet
212 continue;
213 }
214
215 //Sending the packet
216 TPacket packet(data.first->packet());
217 this->g_socket.sendTo(packet, data.second._ip, data.second._port);
218 }
219 }
220}
221
222//ClientSideNetUdp
223
224template<class TPacket>
225bool ClientSideNetUdp::start(Port bindPort,
226 IpAddress const& bindIp,
227 Port connectRemotePort,
228 IpAddress const& connectRemoteAddress,
229 IpAddress::Types addressType)
230{
231 if (this->g_running)
232 {
233 return false;
234 }
235 this->g_socket.setAddressType(addressType);
236 if (this->g_socket.bind(bindPort, bindIp) == Socket::ERR_NOERROR)
237 {
238 if (this->g_socket.connect(connectRemoteAddress, connectRemotePort) == Socket::ERR_NOERROR)
239 {
240 this->g_clientIdentity._ip = connectRemoteAddress;
241 this->g_clientIdentity._port = connectRemotePort;
242
243 this->g_running = true;
244
245 this->g_threadReception = std::make_unique<std::thread>(&ClientSideNetUdp::threadReception<TPacket>, this);
246 this->g_threadTransmission =
247 std::make_unique<std::thread>(&ClientSideNetUdp::threadTransmission<TPacket>, this);
248
249 return true;
250 }
251 }
252 this->g_socket.close();
253 return false;
254}
255
256template<class TPacket>
257void ClientSideNetUdp::threadReception()
258{
259 TPacket pckReceive;
260
261 while (this->g_running)
262 {
263 if (this->g_socket.select(true, 500) == Socket::ERR_NOERROR)
264 {
265 if (this->g_socket.receive(pckReceive) == Socket::ERR_NOERROR)
266 {
267#ifdef FGE_ENABLE_CLIENT_NETWORK_RANDOM_LOST
268 if (fge::_random.range(0, 1000) <= 10)
269 {
270 continue;
271 }
272#endif
273
274 if (pckReceive.getDataSize() < ProtocolPacket::HeaderSize)
275 { //Bad header, packet is dismissed
276 continue;
277 }
278
279 //Skip the header
280 pckReceive.skip(ProtocolPacket::HeaderSize);
281 auto fluxPacket = std::make_unique<FluxPacket>(std::move(pckReceive), this->g_clientIdentity);
282
283 //Verify headerId
284 auto const header = fluxPacket->retrieveHeader().value();
285 if ((header & ~FGE_NET_HEADER_FLAGS_MASK) == FGE_NET_BAD_HEADERID ||
286 (header & FGE_NET_HEADER_LOCAL_REORDERED_FLAG) > 0)
287 { //Bad headerId, packet is dismissed
288 continue;
289 }
290
291 this->pushPacket(std::move(fluxPacket));
292 this->g_receptionNotifier.notify_all();
293 }
294 }
295 }
296}
297template<class TPacket>
298void ClientSideNetUdp::threadTransmission()
299{
300 std::unique_lock lckServer(this->_g_mutexFlux);
301
302 while (this->g_running)
303 {
304 this->g_transmissionNotifier.wait_for(lckServer, std::chrono::milliseconds(10));
305
306 //Flux
307 if (!this->_client.isPendingPacketsEmpty())
308 {
309 if (this->_client.getLastPacketElapsedTime() >= this->_client.getCTOSLatency_ms())
310 { //Ready to send !
311 auto transmissionPacket = this->_client.popPacket();
312
313 if (!transmissionPacket->packet() || !transmissionPacket->packet().haveCorrectHeaderSize())
314 { //Last verification of the packet
315 continue;
316 }
317
318 //Applying options
319 transmissionPacket->applyOptions(this->_client);
320
321 //Sending the packet
322 TPacket packet = transmissionPacket->packet();
323 this->g_socket.send(packet);
324 this->_client.resetLastPacketTimePoint();
325 }
326 }
327 }
328}
329
330} // namespace fge::net
uint16_t Timestamp
An timestamp represent modulated current time in milliseconds.
Definition C_client.hpp:49
FGE_API fge::Random< std::mt19937_64 > _random
Default random number generator instance.