1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 Nuke.YKT
5 
6 This file is part of NBlood.
7 
8 NBlood is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License version 2
10 as published by the Free Software Foundation.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 */
22 //-------------------------------------------------------------------------
23 #include "build.h"
24 #include "mmulti.h"
25 #include "pragmas.h"
26 #ifndef NETCODE_DISABLE
27 #include "enet.h"
28 #endif
29 #include "compat.h"
30 #include "config.h"
31 #include "controls.h"
32 #include "globals.h"
33 #include "network.h"
34 #include "menu.h"
35 #include "player.h"
36 #include "seq.h"
37 #include "sound.h"
38 #include "view.h"
39 
40 char packet[576];
41 bool gStartNewGame = 0;
42 PACKETMODE gPacketMode = PACKETMODE_1;
43 ClockTicks gNetFifoClock = 0;
44 int gNetFifoTail = 0;
45 int gNetFifoHead[8];
46 int gPredictTail = 0;
47 int gNetFifoMasterTail = 0;
48 GINPUT gFifoInput[256][8];
49 int myMinLag[8];
50 int otherMinLag = 0;
51 int myMaxLag = 0;
52 unsigned int gChecksum[4];
53 unsigned int gCheckFifo[256][8][4];
54 int gCheckHead[8];
55 int gSendCheckTail = 0;
56 int gCheckTail = 0;
57 int gInitialNetPlayers = 0;
58 int gBufferJitter = 1;
59 int gPlayerReady[8];
60 bool bNoResend = true;
61 bool gRobust = false;
62 bool bOutOfSync = false;
63 bool ready2send = false;
64 
65 NETWORKMODE gNetMode = NETWORK_NONE;
66 char gNetAddress[32];
67 // PORT-TODO: Use different port?
68 int gNetPort = kNetDefaultPort;
69 
70 const short word_1328AC = 0x214;
71 
72 PKT_STARTGAME gPacketStartGame;
73 
74 #ifndef NETCODE_DISABLE
75 ENetAddress gNetENetAddress;
76 ENetHost *gNetENetServer;
77 ENetHost *gNetENetClient;
78 ENetPeer *gNetENetPeer;
79 ENetPeer *gNetPlayerPeer[kMaxPlayers];
80 bool gNetENetInit = false;
81 
82 #define kENetFifoSize 2048
83 
84 //ENetPacket *gNetServerPacketFifo[kENetFifoSize];
85 //int gNetServerPacketHead, gNetServerPacketTail;
86 ENetPacket *gNetPacketFifo[kENetFifoSize];
87 int gNetPacketHead, gNetPacketTail;
88 
89 enum BLOOD_ENET_CHANNEL {
90     BLOOD_ENET_SERVICE = 0,
91     BLOOD_ENET_GAME,
92     BLOOD_ENET_CHANNEL_MAX
93 };
94 
95 enum BLOOD_SERVICE {
96     BLOOD_SERVICE_CONNECTINFO = 0,
97     BLOOD_SERVICE_CONNECTID,
98     BLOOD_SERVICE_SENDTOID,
99 };
100 
101 struct PKT_CONNECTINFO {
102     short numplayers;
103     short connecthead;
104     short connectpoint2[kMaxPlayers];
105 };
106 
netServerDisconnect(void)107 void netServerDisconnect(void)
108 {
109     ENetEvent event;
110     if (gNetMode != NETWORK_SERVER)
111         return;
112     for (int p = 0; p < kMaxPlayers; p++)
113         if (gNetPlayerPeer[p])
114         {
115             bool bDisconnectStatus = false;
116             enet_peer_disconnect_later(gNetPlayerPeer[p], 0);
117             if (enet_host_service(gNetENetServer, &event, 3000) > 0)
118             {
119                 switch (event.type)
120                 {
121                 case ENET_EVENT_TYPE_DISCONNECT:
122                     bDisconnectStatus = true;
123                     break;
124                 default:
125                     break;
126                 }
127             }
128             if (!bDisconnectStatus)
129                 enet_peer_reset(gNetPlayerPeer[p]);
130             gNetPlayerPeer[p] = NULL;
131         }
132 }
133 
netClientDisconnect(void)134 void netClientDisconnect(void)
135 {
136     ENetEvent event;
137     if (gNetMode != NETWORK_CLIENT || gNetENetPeer == NULL)
138         return;
139     enet_peer_disconnect_later(gNetENetPeer, 0);
140     bool bDisconnectStatus = false;
141     if (enet_host_service(gNetENetClient, &event, 3000) > 0)
142     {
143         switch (event.type)
144         {
145         case ENET_EVENT_TYPE_DISCONNECT:
146             bDisconnectStatus = true;
147             break;
148         default:
149             break;
150         }
151     }
152     if (!bDisconnectStatus)
153         enet_peer_reset(gNetENetPeer);
154     gNetENetPeer = NULL;
155 }
156 #endif
157 
netResetToSinglePlayer(void)158 void netResetToSinglePlayer(void)
159 {
160     myconnectindex = connecthead = 0;
161     gInitialNetPlayers = gNetPlayers = numplayers = 1;
162     connectpoint2[0] = -1;
163     gGameOptions.nGameType = 0;
164     gNetMode = NETWORK_NONE;
165     UpdateNetworkMenus();
166 }
167 
netSendPacket(int nDest,char * pBuffer,int nSize)168 void netSendPacket(int nDest, char *pBuffer, int nSize)
169 {
170 #ifndef NETCODE_DISABLE
171     if (gNetMode == NETWORK_NONE)
172         return;
173     netUpdate();
174 
175     if (gNetMode == NETWORK_SERVER)
176     {
177         if (gNetPlayerPeer[nDest] != NULL)
178         {
179             ENetPacket *pNetPacket = enet_packet_create(NULL, nSize + 1, ENET_PACKET_FLAG_RELIABLE);
180             char *pPBuffer = (char*)pNetPacket->data;
181             PutPacketByte(pPBuffer, myconnectindex);
182             PutPacketBuffer(pPBuffer, pBuffer, nSize);
183             enet_peer_send(gNetPlayerPeer[nDest], BLOOD_ENET_GAME, pNetPacket);
184             enet_host_service(gNetENetServer, NULL, 0);
185         }
186     }
187     else
188     {
189         if (nDest == 0)
190         {
191             ENetPacket *pNetPacket = enet_packet_create(NULL, nSize + 1, ENET_PACKET_FLAG_RELIABLE);
192             char *pPBuffer = (char*)pNetPacket->data;
193             PutPacketByte(pPBuffer, myconnectindex);
194             PutPacketBuffer(pPBuffer, pBuffer, nSize);
195             enet_peer_send(gNetENetPeer, BLOOD_ENET_GAME, pNetPacket);
196         }
197         else
198         {
199             ENetPacket *pNetPacket = enet_packet_create(NULL, nSize + 3, ENET_PACKET_FLAG_RELIABLE);
200             char *pPBuffer = (char*)pNetPacket->data;
201             PutPacketByte(pPBuffer, BLOOD_SERVICE_SENDTOID);
202             PutPacketByte(pPBuffer, nDest);
203             PutPacketByte(pPBuffer, myconnectindex);
204             PutPacketBuffer(pPBuffer, pBuffer, nSize);
205             enet_peer_send(gNetENetPeer, BLOOD_ENET_SERVICE, pNetPacket);
206         }
207         enet_host_service(gNetENetClient, NULL, 0);
208     }
209 
210     netUpdate();
211 #endif
212 }
213 
netSendPacketAll(char * pBuffer,int nSize)214 void netSendPacketAll(char *pBuffer, int nSize)
215 {
216     for (int p = connecthead; p >= 0; p = connectpoint2[p])
217         if (p != myconnectindex)
218             netSendPacket(p, pBuffer, nSize);
219 }
220 
sub_79760(void)221 void sub_79760(void)
222 {
223     gNetFifoClock = gFrameClock = totalclock = 0;
224     gNetFifoMasterTail = 0;
225     gPredictTail = 0;
226     gNetFifoTail = 0;
227     memset(gNetFifoHead, 0, sizeof(gNetFifoHead));
228     memset(gCheckFifo, 0, sizeof(gCheckFifo));
229     memset(myMinLag, 0, sizeof(myMinLag));
230     otherMinLag = 0;
231     myMaxLag = 0;
232     memset(gCheckHead, 0, sizeof(gCheckHead));
233     gSendCheckTail = 0;
234     gCheckTail = 0;
235     bOutOfSync = 0;
236     gBufferJitter = 1;
237 }
238 
CalcGameChecksum(void)239 void CalcGameChecksum(void)
240 {
241     memset(gChecksum, 0, sizeof(gChecksum));
242     gChecksum[0] = wrand();
243     for (int p = connecthead; p >= 0; p = connectpoint2[p])
244     {
245         int *pBuffer = &gPlayer[p].used1;
246         int sum = 0;
247         int length = ((char*)&gPlayer[p+1]-(char*)pBuffer)/4;
248         while (length--)
249         {
250             sum += *pBuffer++;
251         }
252         gChecksum[1] ^= sum;
253         pBuffer = (int*)gPlayer[p].pSprite;
254         sum = 0;
255         length = sizeof(spritetype)/4;
256         while (length--)
257         {
258             sum += *pBuffer++;
259         }
260         gChecksum[2] ^= sum;
261         pBuffer = (int*)gPlayer[p].pXSprite;
262         sum = 0;
263         length = sizeof(XSPRITE)/4;
264         while (length--)
265         {
266             sum += *pBuffer++;
267         }
268         gChecksum[3] ^= sum;
269     }
270 }
271 
netCheckSync(void)272 void netCheckSync(void)
273 {
274     char buffer[80];
275     if (gGameOptions.nGameType == 0)
276         return;
277     if (numplayers == 1)
278         return;
279     if (bOutOfSync)
280         return;
281     while (1)
282     {
283         for (int p = connecthead; p >= 0; p = connectpoint2[p])
284         {
285             if (gCheckTail >= gCheckHead[p])
286                 return;
287         }
288 
289         for (int p = connecthead; p >= 0; p = connectpoint2[p])
290         {
291             if (p != myconnectindex)
292             {
293                 int status = memcmp(gCheckFifo[gCheckTail&255][p], gCheckFifo[gCheckTail&255][connecthead], 16);
294                 if (status)
295                 {
296                     sprintf(buffer, "OUT OF SYNC (%d)", p);
297                     char *pBuffer = buffer + strlen(buffer);
298                     for (unsigned int i = 0; i < 4; i++)
299                     {
300                         if (gCheckFifo[gCheckTail&255][p][i] != gCheckFifo[gCheckTail&255][connecthead][i])
301                             pBuffer += sprintf(pBuffer, " %d", i);
302                     }
303                     viewSetErrorMessage(buffer);
304                     bOutOfSync = 1;
305                 }
306             }
307         }
308         gCheckTail++;
309     }
310 }
311 
netGetPacket(short * pSource,char * pMessage)312 short netGetPacket(short *pSource, char *pMessage)
313 {
314 #ifndef NETCODE_DISABLE
315     if (gNetMode == NETWORK_NONE)
316         return 0;
317     netUpdate();
318     if (gNetPacketTail != gNetPacketHead)
319     {
320         ENetPacket *pEPacket = gNetPacketFifo[gNetPacketTail];
321         gNetPacketTail = (gNetPacketTail+1)%kENetFifoSize;
322         char *pPacket = (char*)pEPacket->data;
323         *pSource = GetPacketByte(pPacket);
324         int nSize = pEPacket->dataLength-1;
325         memcpy(pMessage, pPacket, nSize);
326         enet_packet_destroy(pEPacket);
327         netUpdate();
328         return nSize;
329     }
330     netUpdate();
331 #endif
332     return 0;
333 }
334 
netGetPackets(void)335 void netGetPackets(void)
336 {
337     short nPlayer;
338     short nSize;
339     char buffer[128];
340     while ((nSize = netGetPacket(&nPlayer, packet)) > 0)
341     {
342         char *pPacket = packet;
343         switch (GetPacketByte(pPacket))
344         {
345         case 0: // From master
346             for (int p = connecthead; p >= 0; p = connectpoint2[p])
347             {
348                 if (p != myconnectindex)
349                 {
350                     GINPUT *pInput = &gFifoInput[gNetFifoHead[p]&255][p];
351                     memset(pInput, 0, sizeof(GINPUT));
352                     pInput->syncFlags.byte = GetPacketByte(pPacket);
353                     pInput->forward = GetPacketWord(pPacket);
354                     pInput->q16turn = GetPacketDWord(pPacket);
355                     pInput->strafe = GetPacketWord(pPacket);
356                     if (pInput->syncFlags.buttonChange)
357                         pInput->buttonFlags.byte = GetPacketByte(pPacket);
358                     if (pInput->syncFlags.keyChange)
359                         pInput->keyFlags.word = GetPacketWord(pPacket);
360                     if (pInput->syncFlags.useChange)
361                         pInput->useFlags.byte = GetPacketByte(pPacket);
362                     if (pInput->syncFlags.weaponChange)
363                         pInput->newWeapon = GetPacketByte(pPacket);
364                     if (pInput->syncFlags.mlookChange)
365                         pInput->q16mlook = GetPacketDWord(pPacket);
366                     gNetFifoHead[p]++;
367                 }
368                 else
369                 {
370                     SYNCFLAGS syncFlags;
371                     syncFlags.byte = GetPacketByte(pPacket);
372                     pPacket += 2+4+2;
373                     if (syncFlags.buttonChange)
374                         pPacket++;
375                     if (syncFlags.keyChange)
376                         pPacket+=2;
377                     if (syncFlags.useChange)
378                         pPacket++;
379                     if (syncFlags.weaponChange)
380                         pPacket++;
381                     if (syncFlags.mlookChange)
382                         pPacket+=4;
383                 }
384             }
385             if (((gNetFifoHead[connecthead]-1)&15)==0)
386             {
387                 for (int p = connectpoint2[connecthead]; p >= 0; p = connectpoint2[p])
388                 {
389                     int nLag = (signed char)GetPacketByte(pPacket);
390                     if (p == myconnectindex)
391                         otherMinLag = nLag;
392                 }
393             }
394             while (pPacket < packet+nSize)
395             {
396                 int checkSum[4];
397                 GetPacketBuffer(pPacket, checkSum, sizeof(checkSum));
398                 for (int p = connecthead; p >= 0; p = connectpoint2[p])
399                 {
400                     if (p != myconnectindex)
401                     {
402                         memcpy(gCheckFifo[gCheckHead[p]&255][p], checkSum, sizeof(checkSum));
403                         gCheckHead[p]++;
404                     }
405                 }
406             }
407             break;
408         case 1: // From slave
409         {
410             GINPUT *pInput = &gFifoInput[gNetFifoHead[nPlayer]&255][nPlayer];
411             memset(pInput, 0, sizeof(GINPUT));
412             pInput->syncFlags.byte = GetPacketByte(pPacket);
413             pInput->forward = GetPacketWord(pPacket);
414             pInput->q16turn = GetPacketDWord(pPacket);
415             pInput->strafe = GetPacketWord(pPacket);
416             if (pInput->syncFlags.buttonChange)
417                 pInput->buttonFlags.byte = GetPacketByte(pPacket);
418             if (pInput->syncFlags.keyChange)
419                 pInput->keyFlags.word = GetPacketWord(pPacket);
420             if (pInput->syncFlags.useChange)
421                 pInput->useFlags.byte = GetPacketByte(pPacket);
422             if (pInput->syncFlags.weaponChange)
423                 pInput->newWeapon = GetPacketByte(pPacket);
424             if (pInput->syncFlags.mlookChange)
425                 pInput->q16mlook = GetPacketDWord(pPacket);
426             gNetFifoHead[nPlayer]++;
427             while (pPacket < packet+nSize)
428             {
429                 int checkSum[4];
430                 GetPacketBuffer(pPacket, checkSum, sizeof(checkSum));
431                 memcpy(gCheckFifo[gCheckHead[nPlayer]&255][nPlayer], checkSum, sizeof(checkSum));
432                 gCheckHead[nPlayer]++;
433             }
434             break;
435         }
436         case 2:
437         {
438             if (nPlayer == connecthead && (gNetFifoHead[nPlayer]&15) == 0)
439             {
440                 for (int p = connectpoint2[connecthead]; p >= 0; p = connectpoint2[p])
441                 {
442                     int nLag = (signed char)GetPacketByte(pPacket);
443                     if (p == myconnectindex)
444                         otherMinLag = nLag;
445                 }
446             }
447             GINPUT *pInput = &gFifoInput[gNetFifoHead[nPlayer]&255][nPlayer];
448             memset(pInput, 0, sizeof(GINPUT));
449             pInput->syncFlags.byte = GetPacketByte(pPacket);
450             pInput->forward = GetPacketWord(pPacket);
451             pInput->q16turn = GetPacketDWord(pPacket);
452             pInput->strafe = GetPacketWord(pPacket);
453             if (pInput->syncFlags.buttonChange)
454                 pInput->buttonFlags.byte = GetPacketByte(pPacket);
455             if (pInput->syncFlags.keyChange)
456                 pInput->keyFlags.word = GetPacketWord(pPacket);
457             if (pInput->syncFlags.useChange)
458                 pInput->useFlags.byte = GetPacketByte(pPacket);
459             if (pInput->syncFlags.weaponChange)
460                 pInput->newWeapon = GetPacketByte(pPacket);
461             if (pInput->syncFlags.mlookChange)
462                 pInput->q16mlook = GetPacketDWord(pPacket);
463             gNetFifoHead[nPlayer]++;
464             while (pPacket < packet+nSize)
465             {
466                 int checkSum[4];
467                 GetPacketBuffer(pPacket, checkSum, sizeof(checkSum));
468                 memcpy(gCheckFifo[gCheckHead[nPlayer]&255][nPlayer], checkSum, sizeof(checkSum));
469                 gCheckHead[nPlayer]++;
470             }
471             break;
472         }
473         case 3:
474             pPacket += 4;
475             if (*pPacket != '/' || (*pPacket == 0 && *(pPacket+1) == 0) || (*(pPacket+1) >= '1' && *(pPacket+1) <= '8' && *(pPacket+1)-'1' == myconnectindex))
476             {
477                 sprintf(buffer, VanillaMode() ? "%s : %s" : "%s: %s", gProfile[nPlayer].name, pPacket);
478                 viewSetMessage(buffer, VanillaMode() ? 0 : 10); // 10: dark blue
479                 sndStartSample("DMRADIO", 128, -1);
480             }
481             break;
482         case 4:
483             sndStartSample(4400+GetPacketByte(pPacket), 128, 1, 0);
484             break;
485         case 7:
486             nPlayer = GetPacketDWord(pPacket);
487             dassert(nPlayer != myconnectindex);
488             netWaitForEveryone(0);
489             netPlayerQuit(nPlayer);
490             netWaitForEveryone(0);
491             break;
492         case 249:
493             nPlayer = GetPacketDWord(pPacket);
494             dassert(nPlayer != myconnectindex);
495             netPlayerQuit(nPlayer);
496             netWaitForEveryone(0);
497             break;
498         case 250:
499             gPlayerReady[nPlayer]++;
500             break;
501         case 251:
502             memcpy(&gProfile[nPlayer], pPacket, sizeof(PROFILE));
503             break;
504         case 252:
505             pPacket += 4;
506             memcpy(&gPacketStartGame, pPacket, sizeof(PKT_STARTGAME));
507             if (gPacketStartGame.version != word_1328AC)
508                 ThrowError("\nThese versions of Blood cannot play together.\n");
509             gStartNewGame = 1;
510             break;
511         case 255:
512             keystatus[1] = 1;
513             break;
514         }
515     }
516 }
517 
netBroadcastPlayerLogoff(int nPlayer)518 void netBroadcastPlayerLogoff(int nPlayer)
519 {
520     if (numplayers < 2)
521         return;
522     netWaitForEveryone(0);
523     netPlayerQuit(nPlayer);
524     if (nPlayer != myconnectindex)
525         netWaitForEveryone(0);
526 }
527 
netBroadcastMyLogoff(bool bRestart)528 void netBroadcastMyLogoff(bool bRestart)
529 {
530     if (numplayers < 2)
531         return;
532     char *pPacket = packet;
533     PutPacketByte(pPacket, 7);
534     PutPacketDWord(pPacket, myconnectindex);
535     netSendPacketAll(packet, pPacket - packet);
536     netWaitForEveryone(0);
537     ready2send = 0;
538     gQuitGame = true;
539     if (bRestart)
540         gRestartGame = true;
541     netDeinitialize();
542     netResetToSinglePlayer();
543 }
544 
netBroadcastPlayerInfo(int nPlayer)545 void netBroadcastPlayerInfo(int nPlayer)
546 {
547     PROFILE *pProfile = &gProfile[nPlayer];
548     strcpy(pProfile->name, szPlayerName);
549     pProfile->skill = gSkill;
550     pProfile->nAutoAim = gAutoAim;
551     pProfile->nWeaponSwitch = gWeaponSwitch;
552     if (numplayers < 2)
553         return;
554     char *pPacket = packet;
555     PutPacketByte(pPacket, 251);
556     PutPacketBuffer(pPacket, pProfile, sizeof(PROFILE));
557     netSendPacketAll(packet, pPacket-packet);
558 }
559 
netBroadcastNewGame(void)560 void netBroadcastNewGame(void)
561 {
562     if (numplayers < 2)
563         return;
564     gPacketStartGame.version = word_1328AC;
565     char *pPacket = packet;
566     PutPacketByte(pPacket, 252);
567     PutPacketDWord(pPacket, myconnectindex);
568     PutPacketBuffer(pPacket, &gPacketStartGame, sizeof(PKT_STARTGAME));
569     netSendPacketAll(packet, pPacket-packet);
570 }
571 
netBroadcastTaunt(int nPlayer,int nTaunt)572 void netBroadcastTaunt(int nPlayer, int nTaunt)
573 {
574     UNREFERENCED_PARAMETER(nPlayer);
575     if (numplayers > 1)
576     {
577         char *pPacket = packet;
578         PutPacketByte(pPacket, 4);
579         PutPacketByte(pPacket, nTaunt);
580         netSendPacketAll(packet, pPacket-packet);
581     }
582     sndStartSample(4400+nTaunt, 128, 1, 0);
583 }
584 
netBroadcastMessage(int nPlayer,const char * pzMessage)585 void netBroadcastMessage(int nPlayer, const char *pzMessage)
586 {
587     if (numplayers > 1)
588     {
589         int nSize = strlen(pzMessage);
590         char *pPacket = packet;
591         PutPacketByte(pPacket, 3);
592         PutPacketDWord(pPacket, nPlayer);
593         PutPacketBuffer(pPacket, pzMessage, nSize+1);
594         netSendPacketAll(packet, pPacket-packet);
595     }
596 }
597 
netWaitForEveryone(char a1)598 void netWaitForEveryone(char a1)
599 {
600     if (numplayers < 2)
601         return;
602     char *pPacket = packet;
603     PutPacketByte(pPacket, 250);
604     netSendPacketAll(packet, pPacket-packet);
605     gPlayerReady[myconnectindex]++;
606     int p;
607     do
608     {
609         if (keystatus[sc_Escape] && a1)
610             exit(0);
611         gameHandleEvents();
612         faketimerhandler();
613         for (p = connecthead; p >= 0; p = connectpoint2[p])
614             if (gPlayerReady[p] < gPlayerReady[myconnectindex])
615                 break;
616         if (gRestartGame || gNetPlayers <= 1)
617             break;
618     } while (p >= 0);
619 }
620 
sub_7AC28(const char * pzString)621 void sub_7AC28(const char *pzString)
622 {
623     if (numplayers < 2)
624         return;
625     if (pzString)
626     {
627         int nLength = strlen(pzString);
628         if (nLength > 0)
629         {
630             char *pPacket = packet;
631             PutPacketByte(pPacket, 5);
632             PutPacketBuffer(pPacket, pzString, nLength+1);
633             netSendPacketAll(packet, pPacket-packet);
634         }
635     }
636 }
637 
netSendEmptyPackets(void)638 void netSendEmptyPackets(void)
639 {
640     ClockTicks nClock = totalclock;
641     char *pPacket = packet;
642     PutPacketByte(pPacket, 254);
643     for (int i = 0; i < 8; i++)
644     {
645         if (nClock <= totalclock)
646         {
647             nClock = totalclock+4;
648             netSendPacketAll(packet, pPacket-packet);
649         }
650     }
651 }
652 
netMasterUpdate(void)653 void netMasterUpdate(void)
654 {
655     if (myconnectindex != connecthead)
656         return;
657     char v4 = 0;
658     do
659     {
660         for (int p = connecthead; p >= 0; p = connectpoint2[p])
661             if (gNetFifoMasterTail >= gNetFifoHead[p])
662             {
663                 if (v4)
664                     return;
665                 char *pPacket = packet;
666                 PutPacketByte(pPacket, 254);
667                 for (; p >= 0; p = connectpoint2[p])
668                     netSendPacket(p, packet, pPacket-packet);
669                 return;
670             }
671         v4 = 1;
672         char *pPacket = packet;
673         PutPacketByte(pPacket, 0);
674         for (int p = connecthead; p >= 0; p = connectpoint2[p])
675         {
676             GINPUT *pInput = &gFifoInput[gNetFifoMasterTail&255][p];
677             if (pInput->buttonFlags.byte)
678                 pInput->syncFlags.buttonChange = 1;
679             if (pInput->keyFlags.word)
680                 pInput->syncFlags.keyChange = 1;
681             if (pInput->useFlags.byte)
682                 pInput->syncFlags.useChange = 1;
683             if (pInput->newWeapon)
684                 pInput->syncFlags.weaponChange = 1;
685             if (pInput->q16mlook)
686                 pInput->syncFlags.mlookChange = 1;
687             PutPacketByte(pPacket, pInput->syncFlags.byte);
688             PutPacketWord(pPacket, pInput->forward);
689             PutPacketDWord(pPacket, pInput->q16turn);
690             PutPacketWord(pPacket, pInput->strafe);
691             if (pInput->syncFlags.buttonChange)
692                 PutPacketByte(pPacket, pInput->buttonFlags.byte);
693             if (pInput->syncFlags.keyChange)
694                 PutPacketWord(pPacket, pInput->keyFlags.word);
695             if (pInput->syncFlags.useChange)
696                 PutPacketByte(pPacket, pInput->useFlags.byte);
697             if (pInput->syncFlags.weaponChange)
698                 PutPacketByte(pPacket, pInput->newWeapon);
699             if (pInput->syncFlags.mlookChange)
700                 PutPacketDWord(pPacket, pInput->q16mlook);
701         }
702         if ((gNetFifoMasterTail&15) == 0)
703         {
704             for (int p = connectpoint2[connecthead]; p >= 0; p = connectpoint2[p])
705                 PutPacketByte(pPacket, ClipRange(myMinLag[p], -128, 127));
706             for (int p = connecthead; p >= 0; p = connectpoint2[p])
707                 myMinLag[p] = 0x7fffffff;
708         }
709         while (gSendCheckTail != gCheckHead[myconnectindex])
710         {
711             PutPacketBuffer(pPacket, gCheckFifo[gSendCheckTail&255][myconnectindex], 16);
712             gSendCheckTail++;
713         }
714         for (int p = connectpoint2[connecthead]; p >= 0; p = connectpoint2[p])
715             netSendPacket(p, packet, pPacket-packet);
716         gNetFifoMasterTail++;
717     } while (1);
718 }
719 
netGetInput(void)720 void netGetInput(void)
721 {
722     if (numplayers > 1)
723         netGetPackets();
724     for (int p = connecthead; p >= 0; p = connectpoint2[p])
725         if (gNetFifoHead[myconnectindex]-200 > gNetFifoHead[p])
726             return;
727     GINPUT &input = gFifoInput[gNetFifoHead[myconnectindex]&255][myconnectindex];
728     input = gNetInput;
729     gNetFifoHead[myconnectindex]++;
730     if (gGameOptions.nGameType == 0 || numplayers == 1)
731     {
732         for (int p = connecthead; p >= 0; p = connectpoint2[p])
733         {
734             if (p != myconnectindex)
735             {
736                 GINPUT *pInput1 = &gFifoInput[(gNetFifoHead[p]-1)&255][p];
737                 GINPUT *pInput2 = &gFifoInput[gNetFifoHead[p]&255][p];
738                 memcpy(pInput2, pInput1, sizeof(GINPUT));
739                 gNetFifoHead[p]++;
740             }
741         }
742         return;
743     }
744     for (int p = connecthead; p >= 0; p = connectpoint2[p])
745     {
746         if (p != myconnectindex)
747         {
748             int nLag = gNetFifoHead[myconnectindex]-1-gNetFifoHead[p];
749             myMinLag[p] = ClipHigh(nLag, myMinLag[p]);
750             myMaxLag = ClipLow(nLag, myMaxLag);
751         }
752     }
753     if (((gNetFifoHead[myconnectindex]-1)&15) == 0)
754     {
755         int t = myMaxLag-gBufferJitter;
756         myMaxLag = 0;
757         if (t > 0)
758             gBufferJitter += (3+t)>>2;
759         else if (t < 0)
760             gBufferJitter -= (1-t)>>2;
761     }
762     if (gPacketMode == PACKETMODE_2)
763     {
764         char *pPacket = packet;
765         PutPacketByte(pPacket, 2);
766         if (((gNetFifoHead[myconnectindex]-1)&15) == 0)
767         {
768             if (myconnectindex == connecthead)
769             {
770                 for (int p = connectpoint2[connecthead]; p >= 0; p = connectpoint2[p])
771                     PutPacketByte(pPacket, ClipRange(myMinLag[p], -128, 127));
772             }
773             else
774             {
775                 int t = myMinLag[connecthead]-otherMinLag;
776                 if (klabs(t) > 2)
777                 {
778                     if (klabs(t) > 8)
779                     {
780                         if (t < 0)
781                             t++;
782                         t >>= 1;
783                     }
784                     else
785                         t = ksgn(t);
786                     totalclock -= t<<2;
787                     otherMinLag += t;
788                     myMinLag[connecthead] -= t;
789                 }
790             }
791             for (int p = connecthead; p >= 0; p = connectpoint2[p])
792                 myMinLag[p] = 0x7fffffff;
793         }
794         if (input.buttonFlags.byte)
795             input.syncFlags.buttonChange = 1;
796         if (input.keyFlags.word)
797             input.syncFlags.keyChange = 1;
798         if (input.useFlags.byte)
799             input.syncFlags.useChange = 1;
800         if (input.newWeapon)
801             input.syncFlags.weaponChange = 1;
802         if (input.q16mlook)
803             input.syncFlags.mlookChange = 1;
804         PutPacketByte(pPacket, input.syncFlags.byte);
805         PutPacketWord(pPacket, input.forward);
806         PutPacketDWord(pPacket, input.q16turn);
807         PutPacketWord(pPacket, input.strafe);
808         if (gInput.syncFlags.buttonChange)
809             PutPacketByte(pPacket, input.buttonFlags.byte);
810         if (gInput.syncFlags.keyChange)
811             PutPacketWord(pPacket, input.keyFlags.word);
812         if (gInput.syncFlags.useChange)
813             PutPacketByte(pPacket, input.useFlags.byte);
814         if (gInput.syncFlags.weaponChange)
815             PutPacketByte(pPacket, input.newWeapon);
816         if (gInput.syncFlags.mlookChange)
817             PutPacketDWord(pPacket, input.q16mlook);
818         while (gSendCheckTail != gCheckHead[myconnectindex])
819         {
820             unsigned int *checkSum = gCheckFifo[gSendCheckTail&255][myconnectindex];
821             PutPacketBuffer(pPacket, checkSum, 16);
822             gSendCheckTail++;
823         }
824         netSendPacketAll(packet, pPacket-packet);
825         return;
826     }
827     if (myconnectindex != connecthead)
828     {
829         char *pPacket = packet;
830         PutPacketByte(pPacket, 1);
831         if (input.buttonFlags.byte)
832             input.syncFlags.buttonChange = 1;
833         if (input.keyFlags.word)
834             input.syncFlags.keyChange = 1;
835         if (input.useFlags.byte)
836             input.syncFlags.useChange = 1;
837         if (input.newWeapon)
838             input.syncFlags.weaponChange = 1;
839         if (input.q16mlook)
840             input.syncFlags.mlookChange = 1;
841         PutPacketByte(pPacket, input.syncFlags.byte);
842         PutPacketWord(pPacket, input.forward);
843         PutPacketDWord(pPacket, input.q16turn);
844         PutPacketWord(pPacket, input.strafe);
845         if (input.syncFlags.buttonChange)
846             PutPacketByte(pPacket, input.buttonFlags.byte);
847         if (input.syncFlags.keyChange)
848             PutPacketWord(pPacket, input.keyFlags.word);
849         if (input.syncFlags.useChange)
850             PutPacketByte(pPacket, input.useFlags.byte);
851         if (input.syncFlags.weaponChange)
852             PutPacketByte(pPacket, input.newWeapon);
853         if (input.syncFlags.mlookChange)
854             PutPacketDWord(pPacket, input.q16mlook);
855         if (((gNetFifoHead[myconnectindex]-1)&15) == 0)
856         {
857             int t = myMinLag[connecthead]-otherMinLag;
858             if (klabs(t) > 2)
859             {
860                 if (klabs(t) > 8)
861                 {
862                     if (t < 0)
863                         t++;
864                     t >>= 1;
865                 }
866                 else
867                     t = ksgn(t);
868                 totalclock -= t<<2;
869                 otherMinLag += t;
870                 myMinLag[connecthead] -= t;
871             }
872             for (int p = connecthead; p >= 0; p = connectpoint2[p])
873                 myMinLag[p] = 0x7fffffff;
874         }
875         while (gSendCheckTail != gCheckHead[myconnectindex])
876         {
877             PutPacketBuffer(pPacket, gCheckFifo[gSendCheckTail&255][myconnectindex], 16);
878             gSendCheckTail++;
879         }
880         netSendPacket(connecthead, packet, pPacket-packet);
881         return;
882     }
883     netMasterUpdate();
884 }
885 
netInitialize(bool bConsole)886 void netInitialize(bool bConsole)
887 {
888     netDeinitialize();
889     memset(gPlayerReady, 0, sizeof(gPlayerReady));
890     sub_79760();
891 #ifndef NETCODE_DISABLE
892     char buffer[128];
893     gNetENetServer = gNetENetClient = NULL;
894     //gNetServerPacketHead = gNetServerPacketTail = 0;
895     gNetPacketHead = gNetPacketTail = 0;
896     if (gNetMode == NETWORK_NONE)
897     {
898         netResetToSinglePlayer();
899         return;
900     }
901     if (enet_initialize() != 0)
902     {
903         initprintf("An error occurred while initializing ENet.\n");
904         netResetToSinglePlayer();
905         return;
906     }
907     if (gNetMode == NETWORK_SERVER)
908     {
909         memset(gNetPlayerPeer, 0, sizeof(gNetPlayerPeer));
910         ENetEvent event;
911         gNetENetAddress.host = ENET_HOST_ANY;
912         gNetENetAddress.port = gNetPort;
913         gNetENetServer = enet_host_create(&gNetENetAddress, 8, BLOOD_ENET_CHANNEL_MAX, 0, 0);
914         if (!gNetENetServer)
915         {
916             initprintf("An error occurred while trying to create an ENet server host.\n");
917             netDeinitialize();
918             netResetToSinglePlayer();
919             return;
920         }
921 
922         numplayers = 1;
923         // Wait for clients
924         if (!bConsole)
925         {
926             char buffer[128];
927             sprintf(buffer, "Waiting for players (%i\\%i)", numplayers, gNetPlayers);
928             viewLoadingScreen(2518, "Network Game", NULL, buffer);
929             videoNextPage();
930         }
931         while (numplayers < gNetPlayers)
932         {
933             handleevents();
934             if (quitevent)
935             {
936                 netServerDisconnect();
937                 QuitGame();
938             }
939             if (!bConsole && KB_KeyPressed(sc_Escape))
940             {
941                 netServerDisconnect();
942                 netDeinitialize();
943                 netResetToSinglePlayer();
944                 return;
945             }
946             enet_host_service(gNetENetServer, NULL, 0);
947             if (enet_host_check_events(gNetENetServer, &event) > 0)
948             {
949                 switch (event.type)
950                 {
951                 case ENET_EVENT_TYPE_CONNECT:
952                 {
953                     char ipaddr[32];
954 
955                     enet_address_get_host_ip(&event.peer->address, ipaddr, sizeof(ipaddr));
956                     initprintf("Client connected: %s:%u\n", ipaddr, event.peer->address.port);
957                     numplayers++;
958                     for (int i = 1; i < kMaxPlayers; i++)
959                     {
960                         if (gNetPlayerPeer[i] == NULL)
961                         {
962                             gNetPlayerPeer[i] = event.peer;
963                             break;
964                         }
965                     }
966                     if (!bConsole)
967                     {
968                         char buffer[128];
969                         sprintf(buffer, "Waiting for players (%i\\%i)", numplayers, gNetPlayers);
970                         viewLoadingScreen(2518, "Network Game", NULL, buffer);
971                         videoNextPage();
972                     }
973                     break;
974                 }
975                 case ENET_EVENT_TYPE_DISCONNECT:
976                 {
977                     char ipaddr[32];
978 
979                     enet_address_get_host_ip(&event.peer->address, ipaddr, sizeof(ipaddr));
980                     initprintf("Client disconnected: %s:%u\n", ipaddr, event.peer->address.port);
981                     numplayers--;
982                     for (int i = 1; i < kMaxPlayers; i++)
983                     {
984                         if (gNetPlayerPeer[i] == event.peer)
985                         {
986                             gNetPlayerPeer[i] = NULL;
987                             for (int j = kMaxPlayers-1; j > i; j--)
988                             {
989                                 if (gNetPlayerPeer[j])
990                                 {
991                                     gNetPlayerPeer[i] = gNetPlayerPeer[j];
992                                     gNetPlayerPeer[j] = NULL;
993                                     break;
994                                 }
995                             }
996                         }
997                     }
998                     if (!bConsole)
999                     {
1000                         char buffer[128];
1001                         sprintf(buffer, "Waiting for players (%i\\%i)", numplayers, gNetPlayers);
1002                         viewLoadingScreen(2518, "Network Game", NULL, buffer);
1003                         videoNextPage();
1004                     }
1005                     break;
1006                 }
1007                 default:
1008                     break;
1009                 }
1010             }
1011             enet_host_service(gNetENetServer, NULL, 0);
1012         }
1013         initprintf("All clients connected\n");
1014 
1015         dassert(numplayers >= 1);
1016 
1017         gInitialNetPlayers = gNetPlayers = numplayers;
1018         connecthead = 0;
1019         for (int i = 0; i < numplayers-1; i++)
1020             connectpoint2[i] = i+1;
1021         connectpoint2[numplayers-1] = -1;
1022 
1023         enet_host_service(gNetENetServer, NULL, 0);
1024 
1025         // Send connect info
1026         char *pPacket = packet;
1027         PutPacketByte(pPacket, BLOOD_SERVICE_CONNECTINFO);
1028         PKT_CONNECTINFO connectinfo;
1029         connectinfo.numplayers = numplayers;
1030         connectinfo.connecthead = connecthead;
1031         for (int i = 0; i < numplayers; i++)
1032             connectinfo.connectpoint2[i] = connectpoint2[i];
1033         PutPacketBuffer(pPacket, &connectinfo, sizeof(connectinfo));
1034         ENetPacket *pEPacket = enet_packet_create(packet, pPacket-packet, ENET_PACKET_FLAG_RELIABLE);
1035         enet_host_broadcast(gNetENetServer, BLOOD_ENET_SERVICE, pEPacket);
1036         //enet_packet_destroy(pEPacket);
1037 
1038         enet_host_service(gNetENetServer, NULL, 0);
1039 
1040         // Send id
1041         myconnectindex = 0;
1042         for (int i = 1; i < numplayers; i++)
1043         {
1044             if (!gNetPlayerPeer[i])
1045                 continue;
1046             char *pPacket = packet;
1047             PutPacketByte(pPacket, BLOOD_SERVICE_CONNECTID);
1048             PutPacketByte(pPacket, i);
1049             ENetPacket *pEPacket = enet_packet_create(packet, pPacket-packet, ENET_PACKET_FLAG_RELIABLE);
1050             enet_peer_send(gNetPlayerPeer[i], BLOOD_ENET_SERVICE, pEPacket);
1051 
1052             enet_host_service(gNetENetServer, NULL, 0);
1053         }
1054 
1055         enet_host_service(gNetENetServer, NULL, 0);
1056     }
1057     else if (gNetMode == NETWORK_CLIENT)
1058     {
1059         ENetEvent event;
1060         sprintf(buffer, "Connecting to %s:%u", gNetAddress, gNetPort);
1061         initprintf("%s\n", buffer);
1062         if (!bConsole)
1063         {
1064             viewLoadingScreen(2518, "Network Game", NULL, buffer);
1065             videoNextPage();
1066         }
1067         gNetENetClient = enet_host_create(NULL, 1, BLOOD_ENET_CHANNEL_MAX, 0, 0);
1068         enet_address_set_host(&gNetENetAddress, gNetAddress);
1069         gNetENetAddress.port = gNetPort;
1070         gNetENetPeer = enet_host_connect(gNetENetClient, &gNetENetAddress, BLOOD_ENET_CHANNEL_MAX, 0);
1071         if (!gNetENetPeer)
1072         {
1073             initprintf("No available peers for initiating an ENet connection.\n");
1074             netDeinitialize();
1075             netResetToSinglePlayer();
1076             return;
1077         }
1078         if (enet_host_service(gNetENetClient, &event, 5000) > 0 && event.type == ENET_EVENT_TYPE_CONNECT)
1079             initprintf("Connected to %s:%i\n", gNetAddress, gNetPort);
1080         else
1081         {
1082             initprintf("Could not connect to %s:%i\n", gNetAddress, gNetPort);
1083             netDeinitialize();
1084             return;
1085         }
1086         bool bWaitServer = true;
1087         if (!bConsole)
1088         {
1089             viewLoadingScreen(2518, "Network Game", NULL, "Waiting for server response");
1090             videoNextPage();
1091         }
1092         while (bWaitServer)
1093         {
1094             handleevents();
1095             if (quitevent)
1096             {
1097                 netClientDisconnect();
1098                 QuitGame();
1099             }
1100             if (!bConsole && KB_KeyPressed(sc_Escape))
1101             {
1102                 netClientDisconnect();
1103                 netDeinitialize();
1104                 netResetToSinglePlayer();
1105                 return;
1106             }
1107             enet_host_service(gNetENetClient, NULL, 0);
1108             if (enet_host_check_events(gNetENetClient, &event) > 0)
1109             {
1110                 switch (event.type)
1111                 {
1112                 case ENET_EVENT_TYPE_DISCONNECT:
1113                     initprintf("Lost connection to server\n");
1114                     netDeinitialize();
1115                     netResetToSinglePlayer();
1116                     return;
1117                 case ENET_EVENT_TYPE_RECEIVE:
1118                     //initprintf("NETEVENT\n");
1119                     if (event.channelID == BLOOD_ENET_SERVICE)
1120                     {
1121                         char *pPacket = (char*)event.packet->data;
1122                         switch (GetPacketByte(pPacket))
1123                         {
1124                         case BLOOD_SERVICE_CONNECTINFO:
1125                         {
1126                             PKT_CONNECTINFO *connectinfo = (PKT_CONNECTINFO*)pPacket;
1127                             gInitialNetPlayers = gNetPlayers = numplayers = connectinfo->numplayers;
1128                             connecthead = connectinfo->connecthead;
1129                             for (int i = 0; i < numplayers; i++)
1130                                 connectpoint2[i] = connectinfo->connectpoint2[i];
1131                             //initprintf("BLOOD_SERVICE_CONNECTINFO\n");
1132                             break;
1133                         }
1134                         case BLOOD_SERVICE_CONNECTID:
1135                             dassert(numplayers > 1);
1136                             myconnectindex = GetPacketByte(pPacket);
1137                             bWaitServer = false;
1138                             //initprintf("BLOOD_SERVICE_CONNECTID\n");
1139                             break;
1140                         }
1141                     }
1142                     enet_packet_destroy(event.packet);
1143                     break;
1144                 default:
1145                     break;
1146                 }
1147             }
1148         }
1149         enet_host_service(gNetENetClient, NULL, 0);
1150         initprintf("Successfully connected to server\n");
1151     }
1152     gNetENetInit = true;
1153     gGameOptions.nGameType = 2;
1154 #else
1155     netResetToSinglePlayer();
1156 #endif
1157 }
1158 
netDeinitialize(void)1159 void netDeinitialize(void)
1160 {
1161 #ifndef NETCODE_DISABLE
1162     if (!gNetENetInit)
1163         return;
1164     gNetENetInit = false;
1165     if (gNetMode != NETWORK_NONE)
1166     {
1167         if (gNetENetServer)
1168         {
1169             netServerDisconnect();
1170             enet_host_destroy(gNetENetServer);
1171         }
1172         else if (gNetENetClient)
1173         {
1174             netClientDisconnect();
1175             enet_host_destroy(gNetENetClient);
1176         }
1177         enet_deinitialize();
1178     }
1179     gNetENetServer = gNetENetClient = NULL;
1180 #endif
1181 }
1182 
1183 #ifndef NETCODE_DISABLE
netPostEPacket(ENetPacket * pEPacket)1184 void netPostEPacket(ENetPacket *pEPacket)
1185 {
1186     //static int number;
1187     //initprintf("netPostEPacket %i\n", number++);
1188     gNetPacketFifo[gNetPacketHead] = pEPacket;
1189     gNetPacketHead = (gNetPacketHead+1)%kENetFifoSize;
1190 }
1191 #endif
1192 
netUpdate(void)1193 void netUpdate(void)
1194 {
1195 #ifndef NETCODE_DISABLE
1196     ENetEvent event;
1197     if (gNetMode == NETWORK_NONE)
1198         return;
1199 
1200     if (gNetENetServer)
1201     {
1202         enet_host_service(gNetENetServer, NULL, 0);
1203         while (enet_host_check_events(gNetENetServer, &event) > 0)
1204         {
1205             switch (event.type)
1206             {
1207             case ENET_EVENT_TYPE_DISCONNECT:
1208             {
1209                 int nPlayer;
1210                 for (nPlayer = connectpoint2[connecthead]; nPlayer >= 0; nPlayer = connectpoint2[nPlayer])
1211                     if (gNetPlayerPeer[nPlayer] == event.peer)
1212                         break;
1213 
1214                 for (int p = 0; p < kMaxPlayers; p++)
1215                     if (gNetPlayerPeer[p] == event.peer)
1216                         gNetPlayerPeer[p] = NULL;
1217                 if (nPlayer >= 0)
1218                 {
1219                     // TODO: Game most likely will go out of sync here...
1220                     char *pPacket = packet;
1221                     PutPacketByte(pPacket, 249);
1222                     PutPacketDWord(pPacket, nPlayer);
1223                     netSendPacketAll(packet, pPacket - packet);
1224                     netPlayerQuit(nPlayer);
1225                     netWaitForEveryone(0);
1226                 }
1227                 if (gNetPlayers <= 1)
1228                 {
1229                     netDeinitialize();
1230                     netResetToSinglePlayer();
1231                     return;
1232                 }
1233                 break;
1234             }
1235             case ENET_EVENT_TYPE_RECEIVE:
1236                 switch (event.channelID)
1237                 {
1238                 case BLOOD_ENET_SERVICE:
1239                 {
1240                     char *pPacket = (char*)event.packet->data;
1241                     if (GetPacketByte(pPacket) != BLOOD_SERVICE_SENDTOID)
1242                         ThrowError("Packet error\n");
1243                     int nDest = GetPacketByte(pPacket);
1244                     int nSource = GetPacketByte(pPacket);
1245                     int nSize = event.packet->dataLength-3;
1246                     if (gNetPlayerPeer[nDest] != NULL)
1247                     {
1248                         ENetPacket *pNetPacket = enet_packet_create(NULL, nSize + 1, ENET_PACKET_FLAG_RELIABLE);
1249                         char *pPBuffer = (char*)pNetPacket->data;
1250                         PutPacketByte(pPBuffer, nSource);
1251                         PutPacketBuffer(pPBuffer, pPacket, nSize);
1252                         enet_peer_send(gNetPlayerPeer[nDest], BLOOD_ENET_GAME, pNetPacket);
1253                         enet_host_service(gNetENetServer, NULL, 0);
1254                     }
1255                     enet_packet_destroy(event.packet);
1256                     break;
1257                 }
1258                 case BLOOD_ENET_GAME:
1259                     netPostEPacket(event.packet);
1260                     break;
1261                 }
1262             default:
1263                 break;
1264             }
1265             enet_host_service(gNetENetServer, NULL, 0);
1266         }
1267         enet_host_service(gNetENetServer, NULL, 0);
1268     }
1269     else if (gNetENetClient)
1270     {
1271         enet_host_service(gNetENetClient, NULL, 0);
1272         while (enet_host_check_events(gNetENetClient, &event) > 0)
1273         {
1274             switch (event.type)
1275             {
1276             case ENET_EVENT_TYPE_DISCONNECT:
1277                 initprintf("Lost connection to server\n");
1278                 netDeinitialize();
1279                 netResetToSinglePlayer();
1280                 gQuitGame = gRestartGame = true;
1281                 return;
1282             case ENET_EVENT_TYPE_RECEIVE:
1283                 switch (event.channelID)
1284                 {
1285                 case BLOOD_ENET_SERVICE:
1286                 {
1287                     ThrowError("Packet error\n");
1288                     break;
1289                 }
1290                 case BLOOD_ENET_GAME:
1291                     netPostEPacket(event.packet);
1292                     break;
1293                 }
1294             default:
1295                 break;
1296             }
1297             enet_host_service(gNetENetClient, NULL, 0);
1298         }
1299         enet_host_service(gNetENetClient, NULL, 0);
1300     }
1301 #endif
1302 }
1303 
faketimerhandler(void)1304 void faketimerhandler(void)
1305 {
1306 #ifndef NETCODE_DISABLE
1307     if (gNetMode != NETWORK_NONE && gNetENetInit)
1308         netUpdate();
1309 #if 0
1310     if (gGameClock >= gNetFifoClock && ready2send)
1311     {
1312         gNetFifoClock += 4;
1313         netGetInput();
1314     }
1315 #endif
1316 #endif
1317     //if (gNetMode != NETWORK_NONE && gNetENetInit)
1318     //    enet_host_service(gNetMode == NETWORK_SERVER ? gNetENetServer : gNetENetClient, NULL, 0);
1319 }
1320 
netPlayerQuit(int nPlayer)1321 void netPlayerQuit(int nPlayer)
1322 {
1323     char buffer[128];
1324     sprintf(buffer, "%s left the game with %d frags.", gProfile[nPlayer].name, gPlayer[nPlayer].fragCount);
1325     viewSetMessage(buffer);
1326     if (gGameStarted)
1327     {
1328         seqKill(3, gPlayer[nPlayer].pSprite->extra);
1329         actPostSprite(gPlayer[nPlayer].nSprite, kStatFree);
1330         if (nPlayer == gViewIndex)
1331             gViewIndex = myconnectindex;
1332         gView = &gPlayer[gViewIndex];
1333     }
1334     if (nPlayer == connecthead)
1335     {
1336         connecthead = connectpoint2[connecthead];
1337         //if (gPacketMode == PACKETMODE_1)
1338         {
1339             //byte_27B2CC = 1;
1340             gQuitGame = true;
1341             gRestartGame = true;
1342             gNetPlayers = 1;
1343             //gQuitRequest = 1;
1344         }
1345     }
1346     else
1347     {
1348         for (int p = connecthead; p >= 0; p = connectpoint2[p])
1349         {
1350             if (connectpoint2[p] == nPlayer)
1351                 connectpoint2[p] = connectpoint2[nPlayer];
1352         }
1353 #ifndef NETCODE_DISABLE
1354         gNetPlayerPeer[nPlayer] = NULL;
1355 #endif
1356     }
1357     gNetPlayers--;
1358     numplayers = ClipLow(numplayers-1, 1);
1359     if (gNetPlayers <= 1)
1360     {
1361         netDeinitialize();
1362         netResetToSinglePlayer();
1363     }
1364 }
1365