OLDD_NET.C 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. // I_pcnet.m
  2. #include "DoomDef.h"
  3. #define NCMD_EXIT 0x80000000
  4. #define NCMD_RETRANSMIT 0x40000000
  5. #define NCMD_SETUP 0x20000000
  6. #define NCMD_CHECKSUM 0x0fffffff
  7. /*
  8. if more space needs to be crunched out of the protocol...
  9. 1 drone
  10. 2 player
  11. 8 tic
  12. 5 numtics
  13. #define NCMD_EXIT 0x80000000
  14. #define NCMD_RETRANSMIT 0x40000000 // a retransmit will have 0 tics
  15. #define NCMD_DRONE 0x20000000
  16. #define NCMD_PLAYER 0x18000000
  17. #define NCMD_PLAYERSHIFT 27
  18. #define NCMD_TIC 0x00ff0000
  19. #define NCMD_TICSHIFT 16
  20. #define NCMD_NUMTICS 0x0000ff00
  21. #define NCMD_NUMTICSSHIFT 8
  22. #define NCMD_CHECKSUM 0x000000ff
  23. */
  24. doomcom_t *doomcom;
  25. doomdata_t *netbuffer; // points inside doomcom
  26. /*
  27. ==============================================================================
  28. NETWORKING
  29. gametic is the tic about to (or currently being) run
  30. maketic is the tick that hasn't had control made for it yet
  31. nettics[] has the maketics for all players
  32. a gametic cannot be run until nettics[] > gametic for all players
  33. ==============================================================================
  34. */
  35. #define RESENDCOUNT 10
  36. #define PL_DRONE 0x80 // bit flag in doomdata->player
  37. ticcmd_t localcmds[BACKUPTICS];
  38. ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
  39. int nettics[MAXNETNODES];
  40. boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
  41. boolean remoteresend[MAXNETNODES]; // set when local needs tics
  42. int resendto[MAXNETNODES]; // set when remote needs tics
  43. int resendcount[MAXNETNODES];
  44. int nodeforplayer[MAXPLAYERS];
  45. int gametime;
  46. int maketic;
  47. int lastnettic, skiptics;
  48. int ticdup;
  49. void D_ProcessEvents (void);
  50. void G_BuildTiccmd (ticcmd_t *cmd);
  51. void D_DoAdvanceDemo (void);
  52. boolean reboundpacket;
  53. doomdata_t reboundstore;
  54. int NetbufferSize (void)
  55. {
  56. return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
  57. }
  58. unsigned NetbufferChecksum (void)
  59. {
  60. unsigned c;
  61. int i,l;
  62. c = 0x1234567;
  63. #ifdef NeXT
  64. return 0; // byte order problems
  65. #endif
  66. l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
  67. for (i=0 ; i<l ; i++)
  68. c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
  69. return c & NCMD_CHECKSUM;
  70. }
  71. int ExpandTics (int low)
  72. {
  73. int delta;
  74. delta = low - (maketic&0xff);
  75. if (delta >= -64 && delta <= 64)
  76. return (maketic&~0xff) + low;
  77. if (delta > 64)
  78. return (maketic&~0xff) - 256 + low;
  79. if (delta < -64)
  80. return (maketic&~0xff) + 256 + low;
  81. I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
  82. return 0;
  83. }
  84. //============================================================================
  85. /*
  86. ==============
  87. =
  88. = HSendPacket
  89. =
  90. ==============
  91. */
  92. void HSendPacket (int node, int flags)
  93. {
  94. netbuffer->checksum = NetbufferChecksum () | flags;
  95. if (!node)
  96. {
  97. reboundstore = *netbuffer;
  98. reboundpacket = true;
  99. return;
  100. }
  101. if (!netgame)
  102. I_Error ("Tried to transmit to another node");
  103. doomcom->command = CMD_SEND;
  104. doomcom->remotenode = node;
  105. doomcom->datalength = NetbufferSize ();
  106. if (debugfile)
  107. {
  108. int i;
  109. int realretrans;
  110. if (netbuffer->checksum & NCMD_RETRANSMIT)
  111. realretrans = ExpandTics (netbuffer->retransmitfrom);
  112. else
  113. realretrans = -1;
  114. fprintf (debugfile,"send (%i + %i, R %i) [%i] "
  115. ,ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
  116. for (i=0 ; i<doomcom->datalength ; i++)
  117. fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
  118. fprintf (debugfile,"\n");
  119. }
  120. I_NetCmd ();
  121. }
  122. /*
  123. ==============
  124. =
  125. = HGetPacket
  126. =
  127. = Returns false if no packet is waiting
  128. =
  129. ==============
  130. */
  131. boolean HGetPacket (void)
  132. {
  133. if (reboundpacket)
  134. {
  135. *netbuffer = reboundstore;
  136. doomcom->remotenode = 0;
  137. reboundpacket = false;
  138. return true;
  139. }
  140. if (!netgame)
  141. return false;
  142. doomcom->command = CMD_GET;
  143. I_NetCmd ();
  144. if (doomcom->remotenode == -1)
  145. return false;
  146. if (doomcom->datalength != NetbufferSize ())
  147. {
  148. if (debugfile)
  149. fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
  150. return false;
  151. }
  152. if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
  153. {
  154. if (debugfile)
  155. fprintf (debugfile,"bad packet checksum\n");
  156. return false;
  157. }
  158. if (debugfile)
  159. {
  160. int realretrans;
  161. int i;
  162. if (netbuffer->checksum & NCMD_SETUP)
  163. fprintf (debugfile,"setup packet\n");
  164. else
  165. {
  166. if (netbuffer->checksum & NCMD_RETRANSMIT)
  167. realretrans = ExpandTics (netbuffer->retransmitfrom);
  168. else
  169. realretrans = -1;
  170. fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",doomcom->remotenode,
  171. ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
  172. for (i=0 ; i<doomcom->datalength ; i++)
  173. fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
  174. fprintf (debugfile,"\n");
  175. }
  176. }
  177. return true;
  178. }
  179. /*
  180. ===================
  181. =
  182. = GetPackets
  183. =
  184. ===================
  185. */
  186. char exitmsg[80];
  187. void GetPackets (void)
  188. {
  189. int netconsole;
  190. int netnode;
  191. int netdrone;
  192. int j;
  193. ticcmd_t *src, *dest;
  194. int dupedstart, dupedend;
  195. int skiptics;
  196. int realstart;
  197. while (HGetPacket ())
  198. {
  199. if (netbuffer->checksum & NCMD_SETUP)
  200. continue; // extra setup packet
  201. netdrone = netbuffer->player & PL_DRONE;
  202. netconsole = netbuffer->player & ~PL_DRONE;
  203. netnode = doomcom->remotenode;
  204. //
  205. // to save bytes, only the low byte of tic numbers are sent
  206. // Figure out what the rest of the bytes are
  207. //
  208. realstart = ExpandTics (netbuffer->starttic);
  209. dupedstart = realstart*doomcom->ticdup;
  210. dupedend = (realstart+netbuffer->numtics)*doomcom->ticdup;
  211. //
  212. // check for exiting the game
  213. //
  214. if (netbuffer->checksum & NCMD_EXIT)
  215. {
  216. if (!nodeingame[netnode])
  217. continue;
  218. nodeingame[netnode] = false;
  219. if (!netdrone)
  220. {
  221. playeringame[netconsole] = false;
  222. strcpy (exitmsg, "Player 1 left the game");
  223. exitmsg[7] += netconsole;
  224. players[consoleplayer].message = exitmsg;
  225. }
  226. continue;
  227. }
  228. //
  229. // drone packets are just notifications
  230. //
  231. if (netdrone)
  232. {
  233. nettics[netnode] = dupedend;
  234. continue;
  235. }
  236. nodeforplayer[netconsole] = netnode;
  237. //
  238. // check for retransmit request
  239. //
  240. if ( resendcount[netnode] <= 0
  241. && (netbuffer->checksum & NCMD_RETRANSMIT) )
  242. {
  243. resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
  244. if (debugfile)
  245. fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
  246. resendcount[netnode] = RESENDCOUNT;
  247. }
  248. else
  249. resendcount[netnode]--;
  250. //
  251. // check for out of order / duplicated packet
  252. //
  253. if (dupedend == nettics[netnode])
  254. continue;
  255. if (dupedend < nettics[netnode])
  256. {
  257. if (debugfile)
  258. fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
  259. continue;
  260. }
  261. //
  262. // check for a missed packet
  263. //
  264. if (dupedstart > nettics[netnode])
  265. {
  266. // stop processing until the other system resends the missed tics
  267. if (debugfile)
  268. fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, dupedstart, nettics[netnode]);
  269. remoteresend[netnode] = true;
  270. continue;
  271. }
  272. //
  273. // update command store from the packet
  274. //
  275. remoteresend[netnode] = false;
  276. skiptics = nettics[netnode]/doomcom->ticdup - realstart;
  277. src = &netbuffer->cmds[skiptics];
  278. while (nettics[netnode] < dupedend)
  279. {
  280. for (j=0 ; j<doomcom->ticdup ; j++)
  281. {
  282. dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
  283. nettics[netnode]++;
  284. *dest = *src;
  285. src->chatchar = 0;
  286. if (src->buttons & BT_SPECIAL)
  287. src->buttons = 0;
  288. }
  289. src++;
  290. }
  291. }
  292. }
  293. /*
  294. =============
  295. =
  296. = NetUpdate
  297. =
  298. = Builds ticcmds for console player
  299. = sends out a packet
  300. =============
  301. */
  302. void NetUpdate (void)
  303. {
  304. int nowtime;
  305. int newtics;
  306. int i,j;
  307. int gameticdiv;
  308. int realstart;
  309. if (singletics)
  310. return; // singletic update is syncronous
  311. //
  312. // check time
  313. //
  314. nowtime = I_GetTime ()/doomcom->ticdup;
  315. newtics = nowtime - gametime;
  316. gametime = nowtime;
  317. if (newtics <= 0) // nothing new to update
  318. goto listen;
  319. if (skiptics <= newtics)
  320. {
  321. newtics -= skiptics;
  322. skiptics = 0;
  323. }
  324. else
  325. {
  326. skiptics -= newtics;
  327. newtics = 0;
  328. }
  329. netbuffer->player = consoleplayer;
  330. if (doomcom->drone)
  331. netbuffer->player |= PL_DRONE;
  332. //
  333. // drone packets
  334. //
  335. if (doomcom->drone)
  336. {
  337. I_StartTic ();
  338. D_ProcessEvents ();
  339. goto sendit;
  340. }
  341. //
  342. // build new ticcmds for console player
  343. //
  344. gameticdiv = (gametic+doomcom->ticdup-1)/doomcom->ticdup;
  345. for (i=0 ; i<newtics ; i++)
  346. {
  347. I_StartTic ();
  348. D_ProcessEvents ();
  349. if (maketic - gameticdiv >= BACKUPTICS/2 /* /doomcom->ticdup */- 1)
  350. {
  351. newtics = i;
  352. break; // can't hold any more
  353. }
  354. //printf ("mk:%i ",maketic);
  355. G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
  356. maketic++;
  357. }
  358. //
  359. // send the packet to the other nodes
  360. //
  361. sendit:
  362. for (i=0 ; i<doomcom->numnodes ; i++)
  363. if (nodeingame[i])
  364. {
  365. if (doomcom->drone)
  366. {
  367. netbuffer->starttic = realstart = maketic + BACKUPTICS/2;
  368. netbuffer->numtics = 0;
  369. }
  370. else
  371. {
  372. netbuffer->starttic = realstart = resendto[i];
  373. netbuffer->numtics = maketic - realstart;
  374. resendto[i] = maketic - doomcom->extratics;
  375. }
  376. if (netbuffer->numtics > BACKUPTICS)
  377. I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
  378. for (j=0 ; j< netbuffer->numtics ; j++)
  379. netbuffer->cmds[j] =
  380. localcmds[(realstart+j)%BACKUPTICS];
  381. if (remoteresend[i])
  382. {
  383. netbuffer->retransmitfrom = nettics[i]/doomcom->ticdup;
  384. HSendPacket (i, NCMD_RETRANSMIT);
  385. }
  386. else
  387. {
  388. netbuffer->retransmitfrom = 0;
  389. HSendPacket (i, 0);
  390. }
  391. }
  392. //
  393. // listen for other packets
  394. //
  395. listen:
  396. GetPackets ();
  397. }
  398. /*
  399. =====================
  400. =
  401. = CheckAbort
  402. =
  403. =====================
  404. */
  405. void CheckAbort (void)
  406. {
  407. event_t *ev;
  408. I_WaitVBL(2);
  409. I_StartTic ();
  410. for ( ; eventtail != eventhead
  411. ; eventtail = (++eventtail)&(MAXEVENTS-1) )
  412. {
  413. ev = &events[eventtail];
  414. if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
  415. I_Error ("Network game synchronization aborted.");
  416. }
  417. }
  418. /*
  419. =====================
  420. =
  421. = D_ArbitrateNetStart
  422. =
  423. =====================
  424. */
  425. void D_ArbitrateNetStart (void)
  426. {
  427. int i;
  428. boolean gotinfo[MAXNETNODES];
  429. autostart = true;
  430. memset (gotinfo,0,sizeof(gotinfo));
  431. if (doomcom->consoleplayer)
  432. { // listen for setup info from key player
  433. printf ("listening for network start info...\n");
  434. while (1)
  435. {
  436. CheckAbort ();
  437. if (!HGetPacket ())
  438. continue;
  439. if (netbuffer->checksum & NCMD_SETUP)
  440. {
  441. if (netbuffer->player != VERSION)
  442. I_Error ("Different DOOM versions cannot play a net game!");
  443. startskill = netbuffer->retransmitfrom & 15;
  444. deathmatch = (netbuffer->retransmitfrom & 0x80) > 0;
  445. nomonsters = (netbuffer->retransmitfrom & 0x40) > 0;
  446. respawnparm = (netbuffer->retransmitfrom & 0x20) > 0;
  447. startmap = netbuffer->starttic & 15;
  448. startepisode = netbuffer->starttic >> 4;
  449. return;
  450. }
  451. }
  452. }
  453. else
  454. { // key player, send the setup info
  455. printf ("sending network start info...\n");
  456. do
  457. {
  458. CheckAbort ();
  459. for (i=0 ; i<doomcom->numnodes ; i++)
  460. {
  461. netbuffer->retransmitfrom = startskill;
  462. if (deathmatch)
  463. netbuffer->retransmitfrom |= 0x80;
  464. if (nomonsters)
  465. netbuffer->retransmitfrom |= 0x40;
  466. if (respawnparm)
  467. netbuffer->retransmitfrom |= 0x20;
  468. netbuffer->starttic = startepisode * 16 + startmap;
  469. netbuffer->player = VERSION;
  470. netbuffer->numtics = 0;
  471. HSendPacket (i, NCMD_SETUP);
  472. }
  473. while (HGetPacket ())
  474. {
  475. gotinfo[netbuffer->player&0x7f] = true;
  476. }
  477. for (i=1 ; i<doomcom->numnodes ; i++)
  478. if (!gotinfo[i])
  479. break;
  480. } while (i < doomcom->numnodes);
  481. }
  482. }
  483. /*
  484. ===================
  485. =
  486. = D_CheckNetGame
  487. =
  488. = Works out player numbers among the net participants
  489. ===================
  490. */
  491. extern int viewangleoffset;
  492. void D_CheckNetGame (void)
  493. {
  494. int i;
  495. for (i=0 ; i<MAXNETNODES ; i++)
  496. {
  497. nodeingame[i] = false;
  498. nettics[i] = 0;
  499. remoteresend[i] = false; // set when local needs tics
  500. resendto[i] = 0; // which tic to start sending
  501. }
  502. // I_InitNetwork sets doomcom and netgame
  503. I_InitNetwork ();
  504. if (doomcom->id != DOOMCOM_ID)
  505. I_Error ("Doomcom buffer invalid!");
  506. netbuffer = &doomcom->data;
  507. consoleplayer = displayplayer = doomcom->consoleplayer;
  508. if (netgame)
  509. D_ArbitrateNetStart ();
  510. printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
  511. // read values out of doomcom
  512. ticdup = doomcom->ticdup;
  513. for (i=0 ; i<doomcom->numplayers ; i++)
  514. playeringame[i] = true;
  515. for (i=0 ; i<doomcom->numnodes ; i++)
  516. nodeingame[i] = true;
  517. printf ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
  518. }
  519. /*
  520. ==================
  521. =
  522. = D_QuitNetGame
  523. =
  524. = Called before quitting to leave a net game without hanging the
  525. = other players
  526. =
  527. ==================
  528. */
  529. void D_QuitNetGame (void)
  530. {
  531. int i, j;
  532. if (debugfile)
  533. fclose (debugfile);
  534. if (!netgame || !usergame || consoleplayer == -1)
  535. return;
  536. // send a bunch of packets for security
  537. netbuffer->player = consoleplayer;
  538. if (doomcom->drone)
  539. netbuffer->player |= PL_DRONE;
  540. netbuffer->numtics = 0;
  541. for (i=0 ; i<4 ; i++)
  542. {
  543. for (j=1 ; j<doomcom->numnodes ; j++)
  544. if (nodeingame[j])
  545. HSendPacket (j, NCMD_EXIT);
  546. I_WaitVBL (1);
  547. }
  548. }
  549. /*
  550. ===============
  551. =
  552. = TryRunTics
  553. =
  554. ===============
  555. */
  556. int frametics[4], frameon;
  557. int frameskip[4];
  558. int oldnettics;
  559. extern boolean advancedemo;
  560. void TryRunTics (void)
  561. {
  562. int i;
  563. int lowtic, nextlowest;
  564. int entertic;
  565. int static oldentertics;
  566. int realtics, availabletics;
  567. int counts;
  568. int numplaying;
  569. //
  570. // get real tics
  571. //
  572. entertic = I_GetTime ();
  573. realtics = entertic - oldentertics;
  574. oldentertics = entertic;
  575. //
  576. // get available tics
  577. //
  578. NetUpdate ();
  579. lowtic = nextlowest = MAXINT;
  580. numplaying = 0;
  581. for (i=0 ; i<doomcom->numnodes ; i++)
  582. if (nodeingame[i])
  583. {
  584. numplaying++;
  585. if (nettics[i] < lowtic)
  586. {
  587. nextlowest = lowtic;
  588. lowtic = nettics[i];
  589. }
  590. else if (nettics[i] < nextlowest)
  591. nextlowest = nettics[i];
  592. }
  593. availabletics = lowtic - gametic;
  594. //
  595. // decide how many tics to run
  596. //
  597. if (realtics < availabletics-1)
  598. counts = realtics+1;
  599. else if (realtics < availabletics)
  600. counts = realtics;
  601. else
  602. counts = availabletics;
  603. if (counts < 1)
  604. counts = 1;
  605. frameon++;
  606. if (debugfile)
  607. fprintf (debugfile,"=======real: %i avail: %i game: %i\n",realtics, availabletics,counts);
  608. //=============================================================================
  609. //
  610. // ideally nettics[0] should be 1 - 3 tics above lowtic
  611. // if we are consistantly slower, speed up time
  612. // drones should never hold up the other players
  613. //
  614. for (i=0 ; i<MAXPLAYERS ; i++)
  615. if (playeringame[i])
  616. break;
  617. if (consoleplayer == i)
  618. { // the key player does not adapt
  619. }
  620. else
  621. {
  622. if (nettics[0] <= nettics[nodeforplayer[i]])
  623. {
  624. gametime--;
  625. // printf ("-");
  626. }
  627. frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
  628. oldnettics = nettics[0];
  629. if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
  630. {
  631. skiptics = 1;
  632. // printf ("+");
  633. }
  634. }
  635. //=============================================================================
  636. //
  637. // wait for new tics if needed
  638. //
  639. while (lowtic < gametic + counts)
  640. {
  641. NetUpdate ();
  642. lowtic = MAXINT;
  643. for (i=0 ; i<doomcom->numnodes ; i++)
  644. if (nodeingame[i] && nettics[i] < lowtic)
  645. lowtic = nettics[i];
  646. if (lowtic < gametic)
  647. I_Error ("TryRunTics: lowtic < gametic");
  648. // don't stay in here forever -- give the menu a chance to work
  649. if (I_GetTime () - entertic >= 20)
  650. return;
  651. }
  652. //
  653. // run the tics
  654. //
  655. while (counts--)
  656. {
  657. G_Ticker ();
  658. NetUpdate (); // check for new console commands
  659. gametic++;
  660. }
  661. }