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