d_net.c (11791B)
1 #include <limits.h> 2 3 #include "m_menu.h" 4 #include "i_system.h" 5 #include "i_video.h" 6 #include "i_net.h" 7 #include "g_game.h" 8 #include "doomdef.h" 9 #include "doomstat.h" 10 11 #define NCMD_EXIT 0x80000000 12 #define NCMD_RETRANSMIT 0x40000000 13 #define NCMD_SETUP 0x20000000 14 #define NCMD_KILL 0x10000000 15 #define NCMD_CHECKSUM 0x0fffffff 16 #define RESENDCOUNT 10 17 #define PL_DRONE 0x80 18 19 doomcom_t* doomcom; 20 doomdata_t* netbuffer; 21 ticcmd_t localcmds[BACKUPTICS]; 22 ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; 23 int nettics[MAXNETNODES]; 24 boolean nodeingame[MAXNETNODES]; 25 boolean remoteresend[MAXNETNODES]; 26 int resendto[MAXNETNODES]; 27 int resendcount[MAXNETNODES]; 28 int nodeforplayer[MAXPLAYERS]; 29 int maketic; 30 int lastnettic; 31 int skiptics; 32 int ticdup; 33 int maxsend; 34 35 void D_ProcessEvents (); 36 void G_BuildTiccmd (ticcmd_t *cmd); 37 void D_DoAdvanceDemo (); 38 39 boolean reboundpacket; 40 doomdata_t reboundstore; 41 42 long 43 NetbufferSize() 44 { 45 return (long)&(((doomdata_t*)0)->cmds[netbuffer->numtics]); 46 } 47 48 uint 49 NetbufferChecksum() 50 { 51 long i, l; 52 uint c; 53 54 c = 0x1234567; 55 return 0; /*Linux, fixme. Endianess?*/ 56 l = (NetbufferSize() - (long)&(((doomdata_t *)0)->retransmitfrom))/4; 57 for (i = 0; i < l; ++i) 58 c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1); 59 return c & NCMD_CHECKSUM; 60 } 61 62 int 63 ExpandTics(int low) 64 { 65 int delta; 66 67 delta = low - (maketic & 0xff); 68 if (delta >= -64 && delta <= 64) 69 return (maketic&~0xff) + low; 70 if (delta > 64) 71 return (maketic&~0xff) - 256 + low; 72 if (delta < -64) 73 return (maketic&~0xff) + 256 + low; 74 I_Error("ExpandTics: strange value %i at maketic %i",low,maketic); 75 return 0; 76 } 77 78 void 79 HSendPacket(int node, int flags) 80 { 81 int i, realretrans; 82 83 netbuffer->checksum = NetbufferChecksum() | flags; 84 if (!node) { 85 reboundstore = *netbuffer; 86 reboundpacket = true; 87 return; 88 } 89 if (demoplayback) 90 return; 91 if (!netgame) 92 I_Error("Tried to transmit to another node"); 93 doomcom->command = CMD_SEND; 94 doomcom->remotenode = node; 95 doomcom->datalength = NetbufferSize (); 96 if (debugfile) { 97 if (netbuffer->checksum & NCMD_RETRANSMIT) 98 realretrans = ExpandTics(netbuffer->retransmitfrom); 99 else 100 realretrans = -1; 101 fprintf (debugfile,"send (%i + %i, R %i) [%i] ", ExpandTics(netbuffer->starttic), netbuffer->numtics, realretrans, doomcom->datalength); 102 for (i = 0; i < doomcom->datalength; ++i) 103 fprintf(debugfile,"%i ",((byte *)netbuffer)[i]); 104 fprintf(debugfile,"\n"); 105 } 106 I_NetCmd(); 107 } 108 109 boolean 110 HGetPacket() 111 { 112 int i, realretrans; 113 114 if (reboundpacket) { 115 *netbuffer = reboundstore; 116 doomcom->remotenode = 0; 117 reboundpacket = false; 118 return true; 119 } 120 if (!netgame) 121 return false; 122 if (demoplayback) 123 return false; 124 doomcom->command = CMD_GET; 125 I_NetCmd(); 126 if (doomcom->remotenode == -1) 127 return false; 128 if (doomcom->datalength != NetbufferSize ()) { 129 if (debugfile) 130 fprintf (debugfile,"bad packet length %i\n",doomcom->datalength); 131 return false; 132 } 133 if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM)) { 134 if (debugfile) 135 fprintf (debugfile,"bad packet checksum\n"); 136 return false; 137 } 138 if (debugfile) { 139 if (netbuffer->checksum & NCMD_SETUP) 140 fprintf (debugfile,"setup packet\n"); 141 else { 142 if (netbuffer->checksum & NCMD_RETRANSMIT) 143 realretrans = ExpandTics (netbuffer->retransmitfrom); 144 else 145 realretrans = -1; 146 fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ", doomcom->remotenode, ExpandTics(netbuffer->starttic), netbuffer->numtics, realretrans, doomcom->datalength); 147 for (i = 0; i < doomcom->datalength; ++i) 148 fprintf (debugfile,"%i ",((byte *)netbuffer)[i]); 149 fprintf (debugfile,"\n"); 150 } 151 } 152 return true; 153 } 154 155 char exitmsg[80]; 156 157 void 158 GetPackets() 159 { 160 ticcmd_t *src, *dest; 161 int realend, realstart, netconsole, netnode, start; 162 163 while (HGetPacket()) { 164 if (netbuffer->checksum & NCMD_SETUP) 165 continue; 166 netconsole = netbuffer->player & ~PL_DRONE; 167 netnode = doomcom->remotenode; 168 realstart = ExpandTics (netbuffer->starttic); 169 realend = (realstart+netbuffer->numtics); 170 if (netbuffer->checksum & NCMD_EXIT) { 171 if (!nodeingame[netnode]) 172 continue; 173 nodeingame[netnode] = false; 174 playeringame[netconsole] = false; 175 strcpy(exitmsg, "Player 1 left the game"); 176 exitmsg[7] += netconsole; 177 players[consoleplayer].message = exitmsg; 178 if (demorecording) 179 G_CheckDemoStatus(); 180 continue; 181 } 182 if (netbuffer->checksum & NCMD_KILL) 183 I_Error("Killed by network driver"); 184 nodeforplayer[netconsole] = netnode; 185 if (resendcount[netnode] <= 0 && (netbuffer->checksum & NCMD_RETRANSMIT)) { 186 resendto[netnode] = ExpandTics(netbuffer->retransmitfrom); 187 if (debugfile) 188 fprintf (debugfile,"retransmit from %i\n", resendto[netnode]); 189 resendcount[netnode] = RESENDCOUNT; 190 } else 191 --resendcount[netnode]; 192 if (realend == nettics[netnode]) 193 continue; 194 if (realend < nettics[netnode]) { 195 if (debugfile) 196 fprintf (debugfile, "out of order packet (%i + %i)\n", realstart, netbuffer->numtics); 197 continue; 198 } 199 if (realstart > nettics[netnode]) { 200 if (debugfile) 201 fprintf (debugfile, "missed tics from %i (%i - %i)\n", netnode, realstart, nettics[netnode]); 202 remoteresend[netnode] = true; 203 continue; 204 } 205 206 remoteresend[netnode] = false; 207 start = nettics[netnode] - realstart; 208 src = &netbuffer->cmds[start]; 209 while (nettics[netnode] < realend) { 210 dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS]; 211 ++nettics[netnode]; 212 *dest = *src; 213 ++src; 214 } 215 } 216 } 217 218 int gametime; 219 220 void 221 NetUpdate() 222 { 223 int nowtime, newtics, i, j, realstart, gameticdiv; 224 225 nowtime = I_GetTime()/ticdup; 226 newtics = nowtime - gametime; 227 gametime = nowtime; 228 if (newtics <= 0) 229 goto listen; 230 if (skiptics <= newtics) { 231 newtics -= skiptics; 232 skiptics = 0; 233 } else { 234 skiptics -= newtics; 235 newtics = 0; 236 } 237 netbuffer->player = consoleplayer; 238 gameticdiv = gametic/ticdup; 239 for (i = 0; i < newtics; ++i) { 240 I_StartTic(); 241 D_ProcessEvents(); 242 if (maketic - gameticdiv >= BACKUPTICS/2-1) 243 break; 244 G_BuildTiccmd(&localcmds[maketic%BACKUPTICS]); 245 ++maketic; 246 } 247 if (singletics) 248 return; 249 for (i = 0; i < doomcom->numnodes; ++i) 250 if (nodeingame[i]) { 251 netbuffer->starttic = realstart = resendto[i]; 252 netbuffer->numtics = maketic - realstart; 253 if (netbuffer->numtics > BACKUPTICS) 254 I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS"); 255 resendto[i] = maketic - doomcom->extratics; 256 for (j = 0; j < netbuffer->numtics; ++j) 257 netbuffer->cmds[j] = localcmds[(realstart+j)%BACKUPTICS]; 258 if (remoteresend[i]) { 259 netbuffer->retransmitfrom = nettics[i]; 260 HSendPacket (i, NCMD_RETRANSMIT); 261 } else { 262 netbuffer->retransmitfrom = 0; 263 HSendPacket (i, 0); 264 } 265 } 266 listen: 267 GetPackets(); 268 } 269 270 void 271 CheckAbort() 272 { 273 event_t *ev; 274 int stoptic; 275 276 stoptic = I_GetTime() + 2; 277 while (I_GetTime() < stoptic) 278 I_StartTic(); 279 I_StartTic(); 280 for (; eventtail != eventhead; eventtail = (eventtail+1)&(MAXEVENTS-1)) { 281 ev = &events[eventtail]; 282 if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE) 283 I_Error("Network game synchronization aborted."); 284 } 285 } 286 287 void 288 D_ArbitrateNetStart() 289 { 290 int i; 291 uchar gotinfo[MAXNETNODES]; 292 293 autostart = true; 294 memset(gotinfo, 0, sizeof(gotinfo)); 295 if (doomcom->consoleplayer) { 296 printf ("listening for network start info...\n"); 297 for (;;) { 298 CheckAbort(); 299 if (!HGetPacket()) 300 continue; 301 if (netbuffer->checksum & NCMD_SETUP) { 302 if (netbuffer->player != VERSION) 303 I_Error("Different DOOM versions cannot play a net game!"); 304 startskill = netbuffer->retransmitfrom & 15; 305 deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6; 306 nomonsters = (netbuffer->retransmitfrom & 0x20) > 0; 307 respawnparm = (netbuffer->retransmitfrom & 0x10) > 0; 308 startmap = netbuffer->starttic & 0x3f; 309 startepisode = netbuffer->starttic >> 6; 310 return; 311 } 312 } 313 } else { 314 printf("sending network start info...\n"); 315 do { 316 CheckAbort(); 317 for (i = 0; i < doomcom->numnodes; ++i) { 318 netbuffer->retransmitfrom = startskill; 319 if (deathmatch) 320 netbuffer->retransmitfrom |= (deathmatch<<6); 321 if (nomonsters) 322 netbuffer->retransmitfrom |= 0x20; 323 if (respawnparm) 324 netbuffer->retransmitfrom |= 0x10; 325 netbuffer->starttic = startepisode * 64 + startmap; 326 netbuffer->player = VERSION; 327 netbuffer->numtics = 0; 328 HSendPacket(i, NCMD_SETUP); 329 } 330 for(i = 10; i && HGetPacket(); --i) 331 if((netbuffer->player&0x7f) < MAXNETNODES) 332 gotinfo[netbuffer->player&0x7f] = true; 333 for (i = 1; i < doomcom->numnodes; ++i) 334 if (!gotinfo[i]) 335 break; 336 } while (i < doomcom->numnodes); 337 } 338 } 339 340 extern int viewangleoffset; 341 342 void 343 D_CheckNetGame() 344 { 345 int i; 346 347 for (i = 0; i < MAXNETNODES; ++i) { 348 nodeingame[i] = false; 349 nettics[i] = 0; 350 remoteresend[i] = false; 351 resendto[i] = 0; 352 } 353 I_InitNetwork(); 354 if (doomcom->id != DOOMCOM_ID) 355 I_Error ("Doomcom buffer invalid!"); 356 netbuffer = &doomcom->data; 357 consoleplayer = displayplayer = doomcom->consoleplayer; 358 if (netgame) 359 D_ArbitrateNetStart(); 360 printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode); 361 ticdup = doomcom->ticdup; 362 maxsend = BACKUPTICS/(2 * ticdup) - 1; 363 if (maxsend < 1) 364 maxsend = 1; 365 for (i = 0; i < doomcom->numplayers; ++i) 366 playeringame[i] = true; 367 for (i = 0; i < doomcom->numnodes; ++i) 368 nodeingame[i] = true; 369 printf("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes); 370 } 371 372 void 373 D_QuitNetGame() 374 { 375 int i, j; 376 377 if (debugfile) 378 fclose(debugfile); 379 if (!netgame || !usergame || consoleplayer == -1 || demoplayback) 380 return; 381 netbuffer->player = consoleplayer; 382 netbuffer->numtics = 0; 383 for (i = 0; i < 4; ++i) { 384 for (j = 1; j < doomcom->numnodes; ++j) 385 if (nodeingame[j]) 386 HSendPacket(j, NCMD_EXIT); 387 I_WaitVBL(1); 388 } 389 } 390 391 int frametics[4]; 392 int frameon; 393 int frameskip[4]; 394 int oldnettics; 395 extern boolean advancedemo; 396 397 void 398 TryRunTics() 399 { 400 static int oldentertics; 401 ticcmd_t *cmd; 402 int i, j, lowtic, entertic, realtics, availabletics, counts, numplaying, buf; 403 404 entertic = I_GetTime() / ticdup; 405 realtics = entertic - oldentertics; 406 oldentertics = entertic; 407 NetUpdate(); 408 lowtic = INT_MAX; 409 numplaying = 0; 410 for (i = 0; i < doomcom->numnodes; ++i) { 411 if (nodeingame[i]) { 412 ++numplaying; 413 if (nettics[i] < lowtic) 414 lowtic = nettics[i]; 415 } 416 } 417 availabletics = lowtic - gametic/ticdup; 418 if (realtics < availabletics-1) 419 counts = realtics+1; 420 else if (realtics < availabletics) 421 counts = realtics; 422 else 423 counts = availabletics; 424 if (counts < 1) 425 counts = 1; 426 ++frameon; 427 if (debugfile) 428 fprintf (debugfile, "=======real: %i avail: %i game: %i\n", realtics, availabletics,counts); 429 if (!demoplayback) { 430 for (i = 0; i < MAXPLAYERS; ++i) 431 if (playeringame[i]) 432 break; 433 if (consoleplayer != i) { 434 if (nettics[0] <= nettics[nodeforplayer[i]]) 435 --gametime; 436 frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]); 437 oldnettics = nettics[0]; 438 if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3]) 439 skiptics = 1; 440 } 441 } 442 while (lowtic < gametic/ticdup + counts) { 443 NetUpdate(); 444 lowtic = INT_MAX; 445 for (i = 0; i < doomcom->numnodes; ++i) 446 if (nodeingame[i] && nettics[i] < lowtic) 447 lowtic = nettics[i]; 448 if (lowtic < gametic/ticdup) 449 I_Error("TryRunTics: lowtic < gametic"); 450 if (I_GetTime ()/ticdup - entertic >= 20) { 451 M_Ticker(); 452 return; 453 } 454 } 455 while (--counts) { 456 for (i = 0; i < ticdup; ++i) { 457 if (gametic/ticdup > lowtic) 458 I_Error("gametic>lowtic"); 459 if (advancedemo) 460 D_DoAdvanceDemo(); 461 M_Ticker(); 462 G_Ticker(); 463 ++gametic; 464 if (i != ticdup-1) { 465 buf = (gametic/ticdup) % BACKUPTICS; 466 for (j = 0; j < MAXPLAYERS; ++j) { 467 cmd = &netcmds[j][buf]; 468 cmd->chatchar = 0; 469 if (cmd->buttons & BT_SPECIAL) 470 cmd->buttons = 0; 471 } 472 } 473 } 474 NetUpdate(); 475 } 476 }