1 /*
2  *  This file is part of Dune Legacy.
3  *
4  *  Dune Legacy is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Dune Legacy is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Dune Legacy.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <Network/NetworkManager.h>
19 
20 #include <Network/ENetHelper.h>
21 
22 #include <GameInitSettings.h>
23 
24 #include <misc/exceptions.h>
25 
26 #include <globals.h>
27 
28 #include <stdio.h>
29 #include <string.h>
30 
31 #include <algorithm>
32 
NetworkManager(int port,const std::string & metaserver)33 NetworkManager::NetworkManager(int port, const std::string& metaserver) {
34 
35     if(enet_initialize() != 0) {
36         THROW(std::runtime_error, "NetworkManager: An error occurred while initializing ENet.");
37     }
38 
39     ENetAddress address;
40     address.host = ENET_HOST_ANY;
41     address.port = port;
42 
43     host = enet_host_create(&address, 32, 2, 0, 0);
44     if(host == nullptr) {
45         enet_deinitialize();
46         THROW(std::runtime_error, "NetworkManager: An error occurred while trying to create a server host.");
47     }
48 
49     if(enet_host_compress_with_range_coder(host) < 0) {
50         enet_deinitialize();
51         THROW(std::runtime_error, "NetworkManager: Cannot activate range coder.");
52     }
53 
54     try {
55         pLANGameFinderAndAnnouncer = new LANGameFinderAndAnnouncer();
56     } catch (...) {
57         enet_deinitialize();
58         throw;
59     }
60 
61     try {
62         pMetaServerClient = new MetaServerClient(metaserver);
63     } catch (...) {
64         delete pLANGameFinderAndAnnouncer;
65         enet_deinitialize();
66         throw;
67     }
68 }
69 
70 
~NetworkManager()71 NetworkManager::~NetworkManager() {
72     delete pMetaServerClient;
73     delete pLANGameFinderAndAnnouncer;
74     enet_host_destroy(host);
75     enet_deinitialize();
76 }
77 
startServer(bool bLANServer,const std::string & serverName,const std::string & playerName,GameInitSettings * pGameInitSettings,int numPlayers,int maxPlayers)78 void NetworkManager::startServer(bool bLANServer, const std::string& serverName, const std::string& playerName, GameInitSettings* pGameInitSettings, int numPlayers, int maxPlayers) {
79     if(bLANServer == true) {
80         if(pLANGameFinderAndAnnouncer != nullptr) {
81             pLANGameFinderAndAnnouncer->startAnnounce(serverName, host->address.port, pGameInitSettings->getFilename(), numPlayers, maxPlayers);
82         }
83     } else {
84         if(pMetaServerClient != nullptr) {
85             pMetaServerClient->startAnnounce(serverName, host->address.port, pGameInitSettings->getFilename(), numPlayers, maxPlayers);
86         }
87     }
88 
89     bIsServer = true;
90     this->bLANServer = bLANServer;
91     this->numPlayers = numPlayers;
92     this->maxPlayers = maxPlayers;
93     this->playerName = playerName;
94     this->pGameInitSettings = pGameInitSettings;
95 }
96 
updateServer(int numPlayers)97 void NetworkManager::updateServer(int numPlayers) {
98     if(bLANServer == true) {
99         if(pLANGameFinderAndAnnouncer != nullptr) {
100             pLANGameFinderAndAnnouncer->updateAnnounce(numPlayers);
101         }
102     } else {
103         if(pMetaServerClient != nullptr) {
104             pMetaServerClient->updateAnnounce(numPlayers);
105         }
106     }
107 
108     this->numPlayers = numPlayers;
109 }
110 
stopServer()111 void NetworkManager::stopServer() {
112     if(bLANServer == true) {
113         if(pLANGameFinderAndAnnouncer != nullptr) {
114             pLANGameFinderAndAnnouncer->stopAnnounce();
115         }
116     } else {
117         if(pMetaServerClient != nullptr) {
118             pMetaServerClient->stopAnnounce();
119         }
120     }
121 
122     bIsServer = false;
123     bLANServer = false;
124     pGameInitSettings = nullptr;
125 }
126 
connect(const std::string & hostname,int port,const std::string & playerName)127 void NetworkManager::connect(const std::string& hostname, int port, const std::string& playerName) {
128     ENetAddress address;
129 
130     if(enet_address_set_host(&address, hostname.c_str()) < 0) {
131         THROW(std::runtime_error, "NetworkManager: Resolving hostname '" + hostname + "' failed!");
132     }
133     address.port = port;
134 
135     connect(address, playerName);
136 }
137 
connect(ENetAddress address,const std::string & playerName)138 void NetworkManager::connect(ENetAddress address, const std::string& playerName) {
139     debugNetwork("Connecting to %s:%d\n", Address2String(address).c_str(), address.port);
140 
141     connectPeer = enet_host_connect(host, &address, 2, 0);
142     if(connectPeer == nullptr) {
143         THROW(std::runtime_error, "NetworkManager: No available peers for initiating a connection.");
144     }
145 
146     this->playerName = playerName;
147 
148     connectPeer->data = new PeerData(connectPeer, PeerData::PeerState::WaitingForConnect);
149     awaitingConnectionList.push_back(connectPeer);
150 }
151 
disconnect()152 void NetworkManager::disconnect() {
153     for(ENetPeer* pAwaitingConnectionPeer : awaitingConnectionList) {
154         enet_peer_disconnect_later(pAwaitingConnectionPeer, NETWORKDISCONNECT_QUIT);
155     }
156     for(ENetPeer* pCurrentPeer : peerList) {
157         enet_peer_disconnect_later(pCurrentPeer, NETWORKDISCONNECT_QUIT);
158     }
159 }
160 
update()161 void NetworkManager::update()
162 {
163     if(pLANGameFinderAndAnnouncer != nullptr) {
164         pLANGameFinderAndAnnouncer->update();
165     }
166 
167     if(pMetaServerClient != nullptr) {
168         pMetaServerClient->update();
169     }
170 
171     if(bIsServer) {
172         // Check for timeout of one client
173         if(awaitingConnectionList.empty() == false) {
174             ENetPeer* pCurrentPeer = awaitingConnectionList.front();
175             PeerData* peerData = static_cast<PeerData*>(pCurrentPeer->data);
176 
177             if(peerData->peerState == PeerData::PeerState::ReadyForOtherPeersToConnect) {
178                 if(numPlayers >= maxPlayers) {
179                     enet_peer_disconnect_later(pCurrentPeer, NETWORKDISCONNECT_GAME_FULL);
180                 } else {
181                     // only one peer should be in state 'PeerState::WaitingForOtherPeersToConnect'
182                     peerData->peerState = PeerData::PeerState::WaitingForOtherPeersToConnect;
183                     peerData->timeout = SDL_GetTicks() + AWAITING_CONNECTION_TIMEOUT;
184                     peerData->notYetConnectedPeers = peerList;
185 
186                     if(peerData->notYetConnectedPeers.empty()) {
187                         // first client on this server
188                         // => change immediately to connected
189 
190                         // get change event list first
191                         ChangeEventList changeEventList = pGetChangeEventListForNewPlayerCallback(peerData->name);
192 
193                         debugNetwork("Moving '%s' from awaiting connection list to peer list\n", peerData->name.c_str());
194                         peerList.push_back(pCurrentPeer);
195                         peerData->peerState = PeerData::PeerState::Connected;
196                         peerData->timeout = 0;
197                         awaitingConnectionList.remove(pCurrentPeer);
198 
199                         // send peer game settings
200                         ENetPacketOStream packetOStream2(ENET_PACKET_FLAG_RELIABLE);
201                         packetOStream2.writeUint32(NETWORKPACKET_SENDGAMEINFO);
202                         pGameInitSettings->save(packetOStream2);
203 
204                         changeEventList.save(packetOStream2);
205 
206                         sendPacketToPeer(pCurrentPeer, packetOStream2);
207                     } else {
208                         // instruct all connected peers to connect
209 
210                         ENetPacketOStream packetOStream(ENET_PACKET_FLAG_RELIABLE);
211                         packetOStream.writeUint32(NETWORKPACKET_CONNECT);
212                         packetOStream.writeUint32(SDL_SwapBE32(pCurrentPeer->address.host));
213                         packetOStream.writeUint16(pCurrentPeer->address.port);
214                         packetOStream.writeString(peerData->name);
215 
216                         sendPacketToAllConnectedPeers(packetOStream);
217                     }
218                 }
219             }
220 
221             if(peerData->timeout > 0 && SDL_GetTicks() > peerData->timeout) {
222                 // timeout
223                 switch(peerData->peerState) {
224                     case PeerData::PeerState::WaitingForName: {
225                         // nothing to do
226                     } break;
227 
228                     case PeerData::PeerState::WaitingForOtherPeersToConnect: {
229                         // the client awaiting connection has timed out => send everyone a disconnect message
230                         ENetPacketOStream packetStream(ENET_PACKET_FLAG_RELIABLE);
231                         packetStream.writeUint32(NETWORKPACKET_DISCONNECT);
232                         packetStream.writeUint32(SDL_SwapBE32(pCurrentPeer->address.host));
233                         packetStream.writeUint16(pCurrentPeer->address.port);
234 
235                         sendPacketToAllConnectedPeers(packetStream);
236 
237                         enet_peer_disconnect(pCurrentPeer, NETWORKDISCONNECT_TIMEOUT);
238 
239                         awaitingConnectionList.pop_front();
240                     } break;
241 
242                     case PeerData::PeerState::Connected:
243                     default: {
244                         // should never happen
245                     } break;
246                 }
247             }
248         }
249     }
250 
251     ENetEvent event;
252     while(enet_host_service(host, &event, 0) > 0) {
253 
254         ENetPeer* peer = event.peer;
255 
256         switch(event.type) {
257             case ENET_EVENT_TYPE_CONNECT: {
258                 if(bIsServer) {
259                     // Server
260                     debugNetwork("NetworkManager: %s:%u connected.\n", Address2String(peer->address).c_str(), peer->address.port);
261 
262                     PeerData* newPeerData = new PeerData(peer, PeerData::PeerState::WaitingForName);
263                     newPeerData->timeout = SDL_GetTicks() + AWAITING_CONNECTION_TIMEOUT;
264                     peer->data = newPeerData;
265 
266                     debugNetwork("Adding '%s' to awaiting connection list\n", newPeerData->name.c_str());
267                     awaitingConnectionList.push_back(peer);
268 
269                     // Send name
270                     ENetPacketOStream packetStream(ENET_PACKET_FLAG_RELIABLE);
271                     packetStream.writeUint32(NETWORKPACKET_SENDNAME);
272                     packetStream.writeString(playerName);
273 
274                     sendPacketToPeer(peer, packetStream);
275                 } else if(connectPeer != nullptr) {
276                     // Client
277                     PeerData* peerData = static_cast<PeerData*>(peer->data);
278 
279                     if(peer == connectPeer) {
280                         ENetPacketOStream packetStream(ENET_PACKET_FLAG_RELIABLE);
281                         packetStream.writeUint32(NETWORKPACKET_SENDNAME);
282                         packetStream.writeString(playerName);
283 
284                         sendPacketToHost(packetStream);
285 
286                         peerData->peerState = PeerData::PeerState::WaitingForOtherPeersToConnect;
287                         peerData->timeout = 0;
288                     } else {
289                         debugNetwork("NetworkManager: %s:%u connected.\n", Address2String(peer->address).c_str(), peer->address.port);
290 
291                         PeerData* pConnectPeerData = static_cast<PeerData*>(connectPeer->data);
292 
293                         if(pConnectPeerData->peerState == PeerData::PeerState::WaitingForOtherPeersToConnect) {
294                             if(peerData == nullptr) {
295                                 peerData = new PeerData(peer, PeerData::PeerState::Connected);
296                                 peer->data = peerData;
297 
298                                 debugNetwork("Adding '%s' to awaiting connection list\n", peerData->name.c_str());
299                                 awaitingConnectionList.push_back(peer);
300                             }
301                         } else {
302                             ENetPacketOStream packetStream1(ENET_PACKET_FLAG_RELIABLE);
303                             packetStream1.writeUint32(NETWORKPACKET_PEER_CONNECTED);
304                             packetStream1.writeUint32(SDL_SwapBE32(peer->address.host));
305                             packetStream1.writeUint16(peer->address.port);
306 
307                             sendPacketToHost(packetStream1);
308 
309                             ENetPacketOStream packetStream2(ENET_PACKET_FLAG_RELIABLE);
310                             packetStream2.writeUint32(NETWORKPACKET_SENDNAME);
311                             packetStream2.writeString(playerName);
312 
313                             sendPacketToPeer(peer, packetStream2);
314                         }
315                     }
316                 } else {
317                     enet_peer_disconnect(peer, NETWORKDISCONNECT_TIMEOUT);
318                 }
319             } break;
320 
321             case ENET_EVENT_TYPE_RECEIVE: {
322                 //debugNetwork("NetworkManager: A packet of length %u was received from %s:%u on channel %u on this server.\n",
323                 //                (unsigned int) event.packet->dataLength, Address2String(peer->address).c_str(), peer->address.port, event.channelID);
324 
325                 ENetPacketIStream packetStream(event.packet);
326 
327                 handlePacket(peer, packetStream);
328             } break;
329 
330             case ENET_EVENT_TYPE_DISCONNECT: {
331                 PeerData* peerData = static_cast<PeerData*>(peer->data);
332 
333                 int disconnectCause = event.data;
334 
335                 debugNetwork("NetworkManager: %s:%u (%s) disconnected (%d).\n", Address2String(peer->address).c_str(), peer->address.port, (peerData != nullptr) ? peerData->name.c_str() : "unknown", disconnectCause);
336 
337                 if(std::find(awaitingConnectionList.begin(), awaitingConnectionList.end(), peer) != awaitingConnectionList.end()) {
338                     if(peerData->peerState == PeerData::PeerState::WaitingForOtherPeersToConnect) {
339                         ENetPacketOStream packetStream(ENET_PACKET_FLAG_RELIABLE);
340                         packetStream.writeUint32(NETWORKPACKET_DISCONNECT);
341                         packetStream.writeUint32(SDL_SwapBE32(peer->address.host));
342                         packetStream.writeUint16(peer->address.port);
343 
344                         sendPacketToAllConnectedPeers(packetStream);
345                     }
346 
347                     debugNetwork("Removing '%s' from awaiting connection list\n", peerData->name.c_str());
348                     awaitingConnectionList.remove(peer);
349                 }
350 
351 
352                 if(std::find(peerList.begin(), peerList.end(), peer) != peerList.end()) {
353                     debugNetwork("Removing '%s' from peer list\n", peerData->name.c_str());
354                     peerList.remove(peer);
355 
356                     ENetPacketOStream packetStream(ENET_PACKET_FLAG_RELIABLE);
357                     packetStream.writeUint32(NETWORKPACKET_DISCONNECT);
358                     packetStream.writeUint32(SDL_SwapBE32(peer->address.host));
359                     packetStream.writeUint16(peer->address.port);
360 
361                     sendPacketToAllConnectedPeers(packetStream);
362 
363                     if(pOnPeerDisconnected) {
364                         pOnPeerDisconnected(peerData->name, (peer == connectPeer), disconnectCause);
365                     }
366                 } else {
367                     if(peer == connectPeer) {
368                         // host disconnected while establishing connection
369                         if(pOnPeerDisconnected) {
370                             pOnPeerDisconnected(peerData->name, true, disconnectCause);
371                         }
372                     }
373                 }
374 
375                 // delete peer data
376                 delete peerData;
377                 peer->data = nullptr;
378 
379                 if(peer == connectPeer) {
380                     connectPeer = nullptr;
381                 }
382 
383             } break;
384 
385             default: {
386 
387             } break;
388         }
389     }
390 }
391 
handlePacket(ENetPeer * peer,ENetPacketIStream & packetStream)392 void NetworkManager::handlePacket(ENetPeer* peer, ENetPacketIStream& packetStream)
393 {
394     try {
395         Uint32 packetType = packetStream.readUint32();
396 
397         switch(packetType) {
398             case NETWORKPACKET_CONNECT: {
399 
400                 if(bIsServer == false) {
401                     ENetAddress address;
402 
403                     address.host = SDL_SwapBE32(packetStream.readUint32());
404                     address.port = packetStream.readUint16();
405 
406                     debugNetwork("Connecting to %s:%d\n", Address2String(address).c_str(), address.port);
407 
408                     ENetPeer *newPeer = enet_host_connect(host, &address, 2, 0);
409                     if(newPeer == nullptr) {
410                         debugNetwork("NetworkManager: No available peers for initiating a connection.");
411                     } else {
412                         PeerData* peerData = new PeerData(newPeer, PeerData::PeerState::WaitingForOtherPeersToConnect);
413                         peerData->name = packetStream.readString();
414 
415                         newPeer->data = peerData;
416                         debugNetwork("Adding '%s' to awaiting connection list\n", peerData->name.c_str());
417                         awaitingConnectionList.push_back(newPeer);
418                     }
419                 }
420             } break;
421 
422             case NETWORKPACKET_DISCONNECT: {
423                 ENetAddress address;
424 
425                 address.host = SDL_SwapBE32(packetStream.readUint32());
426                 address.port = packetStream.readUint16();
427 
428                 for(ENetPeer* pCurrentPeer : peerList) {
429                     if((pCurrentPeer->address.host == address.host) && (pCurrentPeer->address.port == address.port)) {
430                         enet_peer_disconnect_later(pCurrentPeer, NETWORKDISCONNECT_QUIT);
431                         break;
432                     }
433                 }
434 
435                 for(ENetPeer* pAwaitingConnectionPeer : awaitingConnectionList) {
436                     if((pAwaitingConnectionPeer->address.host == address.host) && (pAwaitingConnectionPeer->address.port == address.port)) {
437                         enet_peer_disconnect_later(pAwaitingConnectionPeer, NETWORKDISCONNECT_QUIT);
438                         break;
439                     }
440                 }
441 
442             } break;
443 
444             case NETWORKPACKET_PEER_CONNECTED: {
445 
446                 ENetAddress address;
447 
448                 address.host = SDL_SwapBE32(packetStream.readUint32());
449                 address.port = packetStream.readUint16();
450 
451                 if(isServer()) {
452 
453                     if(awaitingConnectionList.empty() == false) {
454                         ENetPeer* pCurrentPeer = awaitingConnectionList.front();
455                         PeerData* peerData = static_cast<PeerData*>(pCurrentPeer->data);
456 
457                         if((pCurrentPeer->address.host == address.host) && (pCurrentPeer->address.port == address.port)) {
458 
459                             peerData->notYetConnectedPeers.remove(peer);
460 
461                             if(peerData->notYetConnectedPeers.empty()) {
462                                 // send connected to all peers (excluding the new one)
463                                 ENetPacketOStream packetOStream(ENET_PACKET_FLAG_RELIABLE);
464                                 packetOStream.writeUint32(NETWORKPACKET_PEER_CONNECTED);
465                                 packetOStream.writeUint32(SDL_SwapBE32(pCurrentPeer->address.host));
466                                 packetOStream.writeUint16(pCurrentPeer->address.port);
467 
468                                 sendPacketToAllConnectedPeers(packetOStream);
469 
470                                 // get change event list first
471                                 ChangeEventList changeEventList = pGetChangeEventListForNewPlayerCallback(peerData->name);
472 
473                                 // move peer to peer list
474                                 debugNetwork("Moving '%s' from awaiting connection list to peer list\n", peerData->name.c_str());
475                                 peerList.push_back(pCurrentPeer);
476                                 peerData->peerState = PeerData::PeerState::Connected;
477                                 peerData->timeout = 0;
478                                 awaitingConnectionList.remove(pCurrentPeer);
479 
480                                 // send peer game settings
481                                 ENetPacketOStream packetOStream2(ENET_PACKET_FLAG_RELIABLE);
482                                 packetOStream2.writeUint32(NETWORKPACKET_SENDGAMEINFO);
483                                 pGameInitSettings->save(packetOStream2);
484 
485                                 changeEventList.save(packetOStream2);
486 
487                                 sendPacketToPeer(pCurrentPeer, packetOStream2);
488                             }
489                         }
490                     }
491                 } else {
492                     for(auto iter = awaitingConnectionList.begin(); iter != awaitingConnectionList.end(); ++iter) {
493                         ENetPeer* pCurrentPeer = *iter;
494 
495                         if((pCurrentPeer->address.host == address.host) && (pCurrentPeer->address.port == address.port)) {
496                             PeerData* peerData = static_cast<PeerData*>(pCurrentPeer->data);
497                             debugNetwork("Moving '%s' from awaiting connection list to peer list\n", peerData->name.c_str());
498                             peerList.push_back(pCurrentPeer);
499                             peerData->peerState = PeerData::PeerState::Connected;
500                             peerData->timeout = 0;
501                             awaitingConnectionList.erase(iter);
502                             break;
503                         }
504                     }
505                 }
506 
507             } break;
508 
509             case NETWORKPACKET_SENDGAMEINFO: {
510                 PeerData* peerData = static_cast<PeerData*>(connectPeer->data);
511 
512                 peerList = awaitingConnectionList;
513                 peerData->peerState = PeerData::PeerState::Connected;
514                 peerData->timeout = 0;
515                 awaitingConnectionList.clear();
516 
517                 GameInitSettings gameInitSettings(packetStream);
518                 ChangeEventList changeEventList(packetStream);
519 
520                 if(pOnReceiveGameInfo) {
521                     pOnReceiveGameInfo(gameInitSettings, changeEventList);
522                 }
523             } break;
524 
525             case NETWORKPACKET_SENDNAME: {
526                 PeerData* peerData = static_cast<PeerData*>(peer->data);
527 
528                 std::string newName = packetStream.readString();
529                 bool bFoundName = false;
530 
531                 //check if name already exists
532                 if(bIsServer) {
533                     if(playerName == newName) {
534                         enet_peer_disconnect_later(peer, NETWORKDISCONNECT_PLAYER_EXISTS);
535                         bFoundName = true;
536                     }
537 
538                     if(bFoundName == false) {
539                         for(ENetPeer* pCurrentPeer : peerList) {
540                             PeerData* pCurrentPeerData = static_cast<PeerData*>(pCurrentPeer->data);
541                             if(pCurrentPeerData->name == newName) {
542                                 enet_peer_disconnect_later(peer, NETWORKDISCONNECT_PLAYER_EXISTS);
543                                 bFoundName = true;
544                                 break;
545                             }
546                         }
547                     }
548 
549                     if(bFoundName == false) {
550                         for(ENetPeer* pAwaitingConnectionPeer : awaitingConnectionList) {
551                             PeerData* pAwaitingConnectionPeerData = static_cast<PeerData*>(pAwaitingConnectionPeer->data);
552                             if(pAwaitingConnectionPeerData->name == newName) {
553                                 enet_peer_disconnect_later(peer, NETWORKDISCONNECT_PLAYER_EXISTS);
554                                 bFoundName = true;
555                                 break;
556                             }
557                         }
558                     }
559                 }
560 
561                 if(bFoundName == false) {
562                     peerData->name = newName;
563 
564                     if(peerData->peerState == PeerData::PeerState::WaitingForName) {
565                         peerData->peerState = PeerData::PeerState::ReadyForOtherPeersToConnect;
566                     }
567                 }
568             } break;
569 
570             case NETWORKPACKET_CHATMESSAGE: {
571                 PeerData* peerData = static_cast<PeerData*>(peer->data);
572 
573                 std::string message = packetStream.readString();
574                 if(pOnReceiveChatMessage) {
575                     pOnReceiveChatMessage(peerData->name, message);
576                 }
577             } break;
578 
579             case NETWORKPACKET_CHANGEEVENTLIST: {
580                 ChangeEventList changeEventList(packetStream);
581 
582                 if(pOnReceiveChangeEventList) {
583                     pOnReceiveChangeEventList(changeEventList);
584                 }
585             } break;
586 
587             case NETWORKPACKET_STARTGAME: {
588                 Uint32 timeLeft = packetStream.readUint32();
589 
590                 if(pOnStartGame) {
591                     pOnStartGame(timeLeft);
592                 }
593             } break;
594 
595             case NETWORKPACKET_COMMANDLIST: {
596                 PeerData* peerData = static_cast<PeerData*>(peer->data);
597 
598                 CommandList commandList(packetStream);
599 
600                 if(pOnReceiveCommandList) {
601                     pOnReceiveCommandList(peerData->name, commandList);
602                 }
603             } break;
604 
605             case NETWORKPACKET_SELECTIONLIST: {
606                 PeerData* peerData = static_cast<PeerData*>(peer->data);
607 
608                 int groupListIndex = packetStream.readSint32();
609                 std::set<Uint32> selectedList = packetStream.readUint32Set();
610 
611                 if(pOnReceiveSelectionList) {
612                     pOnReceiveSelectionList(peerData->name, selectedList, groupListIndex);
613                 }
614             } break;
615 
616             default: {
617                 SDL_Log("NetworkManager: Unknown packet type %d", packetType);
618             };
619         }
620 
621     } catch (InputStream::eof&) {
622         SDL_Log("NetworkManager: Received packet is too small");
623         return;
624     } catch (std::exception& e) {
625         SDL_Log("NetworkManager: %s", e.what());
626     }
627 }
628 
629 
sendPacketToHost(ENetPacketOStream & packetStream,int channel)630 void NetworkManager::sendPacketToHost(ENetPacketOStream& packetStream, int channel) {
631     if(connectPeer == nullptr) {
632         SDL_Log("NetworkManager: sendPacketToHost() called on server!");
633         return;
634     }
635 
636     ENetPacket* enetPacket = packetStream.getPacket();
637 
638     if(enet_peer_send(connectPeer, channel, enetPacket) < 0) {
639         SDL_Log("NetworkManager: Cannot send packet!");
640     }
641 }
642 
sendPacketToPeer(ENetPeer * peer,ENetPacketOStream & packetStream,int channel)643 void NetworkManager::sendPacketToPeer(ENetPeer* peer, ENetPacketOStream& packetStream, int channel) {
644     ENetPacket* enetPacket = packetStream.getPacket();
645 
646     if(enet_peer_send(peer, channel, enetPacket) < 0) {
647         SDL_Log("NetworkManager: Cannot send packet!");
648     }
649 
650     if(enetPacket->referenceCount == 0) {
651         enet_packet_destroy(enetPacket);
652     }
653 }
654 
655 
sendPacketToAllConnectedPeers(ENetPacketOStream & packetStream,int channel)656 void NetworkManager::sendPacketToAllConnectedPeers(ENetPacketOStream& packetStream, int channel) {
657     ENetPacket* enetPacket = packetStream.getPacket();
658 
659     for(ENetPeer* pCurrentPeer : peerList) {
660         if(enet_peer_send(pCurrentPeer, channel, enetPacket) < 0) {
661             SDL_Log("NetworkManager: Cannot send packet!");
662             continue;
663         }
664     }
665 
666     if(enetPacket->referenceCount == 0) {
667         enet_packet_destroy(enetPacket);
668     }
669 }
670 
671 
sendChatMessage(const std::string & message)672 void NetworkManager::sendChatMessage(const std::string& message)
673 {
674     ENetPacketOStream packetStream(ENET_PACKET_FLAG_RELIABLE);
675     packetStream.writeUint32(NETWORKPACKET_CHATMESSAGE);
676     packetStream.writeString(message);
677 
678     sendPacketToAllConnectedPeers(packetStream);
679 }
680 
sendChangeEventList(const ChangeEventList & changeEventList)681 void NetworkManager::sendChangeEventList(const ChangeEventList& changeEventList)
682 {
683     ENetPacketOStream packetStream(ENET_PACKET_FLAG_RELIABLE);
684     packetStream.writeUint32(NETWORKPACKET_CHANGEEVENTLIST);
685     changeEventList.save(packetStream);
686 
687     if(bIsServer) {
688         sendPacketToAllConnectedPeers(packetStream);
689     } else {
690         sendPacketToHost(packetStream);
691     }
692 }
693 
sendStartGame(unsigned int timeLeft)694 void NetworkManager::sendStartGame(unsigned int timeLeft) {
695     for(ENetPeer* pCurrentPeer : peerList) {
696         ENetPacketOStream packetStream(ENET_PACKET_FLAG_RELIABLE);
697         packetStream.writeUint32(NETWORKPACKET_STARTGAME);
698 
699         packetStream.writeUint32(timeLeft - pCurrentPeer->roundTripTime/2);
700 
701         sendPacketToPeer(pCurrentPeer, packetStream);
702     }
703 }
704 
sendCommandList(const CommandList & commandList)705 void NetworkManager::sendCommandList(const CommandList& commandList) {
706     ENetPacketOStream packetStream(ENET_PACKET_FLAG_UNSEQUENCED);
707     packetStream.writeUint32(NETWORKPACKET_COMMANDLIST);
708     commandList.save(packetStream);
709 
710     sendPacketToAllConnectedPeers(packetStream, 1);
711 }
712 
sendSelectedList(const std::set<Uint32> & selectedList,int groupListIndex)713 void NetworkManager::sendSelectedList(const std::set<Uint32>& selectedList, int groupListIndex) {
714     ENetPacketOStream packetStream(ENET_PACKET_FLAG_RELIABLE);
715     packetStream.writeUint32(NETWORKPACKET_SELECTIONLIST);
716     packetStream.writeSint32(groupListIndex);
717     packetStream.writeUint32Set(selectedList);
718 
719     sendPacketToAllConnectedPeers(packetStream, 0);
720 }
721 
getMaxPeerRoundTripTime()722 int NetworkManager::getMaxPeerRoundTripTime() {
723     int maxPeerRTT = 0;
724 
725     for(ENetPeer* pCurrentPeer : peerList) {
726         maxPeerRTT = std::max(maxPeerRTT, (int) (pCurrentPeer->roundTripTime));
727     }
728 
729     return maxPeerRTT;
730 }
731 
debugNetwork(const char * fmt,...)732 void NetworkManager::debugNetwork(const char* fmt, ...) {
733     if(settings.network.debugNetwork) {
734         va_list args;
735         va_start(args, fmt);
736         vfprintf(stderr, fmt, args);
737         va_end(args);
738     }
739 }
740