D_NET.C 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. //**************************************************************************
  2. //**
  3. //** d_net.c : Heretic 2 : Raven Software, Corp.
  4. //**
  5. //** $RCSfile: d_net.c,v $
  6. //** $Revision: 1.16 $
  7. //** $Date: 96/01/01 03:39:44 $
  8. //** $Author: bgokey $
  9. //**
  10. //** This version has the fixed ticdup code.
  11. //**
  12. //**************************************************************************
  13. #include "h2def.h"
  14. #include "p_local.h"
  15. #include <stdlib.h> // for atoi()
  16. #define NCMD_EXIT 0x80000000
  17. #define NCMD_RETRANSMIT 0x40000000
  18. #define NCMD_SETUP 0x20000000
  19. #define NCMD_KILL 0x10000000 // kill game
  20. #define NCMD_CHECKSUM 0x0fffffff
  21. doomcom_t *doomcom;
  22. doomdata_t *netbuffer; // points inside doomcom
  23. /*
  24. ==============================================================================
  25. NETWORKING
  26. gametic is the tic about to (or currently being) run
  27. maketic is the tick that hasn't had control made for it yet
  28. nettics[] has the maketics for all players
  29. a gametic cannot be run until nettics[] > gametic for all players
  30. ==============================================================================
  31. */
  32. #define RESENDCOUNT 10
  33. #define PL_DRONE 0x80 // bit flag in doomdata->player
  34. ticcmd_t localcmds[BACKUPTICS];
  35. ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
  36. int nettics[MAXNETNODES];
  37. boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
  38. boolean remoteresend[MAXNETNODES]; // set when local needs tics
  39. int resendto[MAXNETNODES]; // set when remote needs tics
  40. int resendcount[MAXNETNODES];
  41. int nodeforplayer[MAXPLAYERS];
  42. int maketic;
  43. int lastnettic, skiptics;
  44. int ticdup;
  45. int maxsend; // BACKUPTICS/(2*ticdup)-1
  46. void H2_ProcessEvents (void);
  47. void G_BuildTiccmd (ticcmd_t *cmd);
  48. void H2_DoAdvanceDemo (void);
  49. extern void ST_NetProgress(void);
  50. extern void ST_NetDone(void);
  51. boolean reboundpacket;
  52. doomdata_t reboundstore;
  53. int NetbufferSize (void)
  54. {
  55. return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
  56. }
  57. unsigned NetbufferChecksum (void)
  58. {
  59. unsigned c;
  60. int i,l;
  61. c = 0x1234567;
  62. #if defined(NeXT) || defined(NORMALUNIX)
  63. return 0; // byte order problems
  64. #endif
  65. l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
  66. for (i=0 ; i<l ; i++)
  67. c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
  68. return c & NCMD_CHECKSUM;
  69. }
  70. int ExpandTics (int low)
  71. {
  72. int delta;
  73. delta = low - (maketic&0xff);
  74. if (delta >= -64 && delta <= 64)
  75. return (maketic&~0xff) + low;
  76. if (delta > 64)
  77. return (maketic&~0xff) - 256 + low;
  78. if (delta < -64)
  79. return (maketic&~0xff) + 256 + low;
  80. I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
  81. return 0;
  82. }
  83. //============================================================================
  84. /*
  85. ==============
  86. =
  87. = HSendPacket
  88. =
  89. ==============
  90. */
  91. void HSendPacket (int node, int flags)
  92. {
  93. netbuffer->checksum = NetbufferChecksum () | flags;
  94. if (!node)
  95. {
  96. reboundstore = *netbuffer;
  97. reboundpacket = true;
  98. return;
  99. }
  100. if (demoplayback)
  101. return;
  102. if (!netgame)
  103. I_Error ("Tried to transmit to another node");
  104. doomcom->command = CMD_SEND;
  105. doomcom->remotenode = node;
  106. doomcom->datalength = NetbufferSize ();
  107. if (debugfile)
  108. {
  109. int i;
  110. int realretrans;
  111. if (netbuffer->checksum & NCMD_RETRANSMIT)
  112. realretrans = ExpandTics (netbuffer->retransmitfrom);
  113. else
  114. realretrans = -1;
  115. fprintf (debugfile,"send (%i + %i, R %i) [%i] "
  116. ,ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
  117. for (i=0 ; i<doomcom->datalength ; i++)
  118. fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
  119. fprintf (debugfile,"\n");
  120. }
  121. I_NetCmd ();
  122. }
  123. //==========================================================================
  124. //
  125. // NET_SendFrags
  126. //
  127. //==========================================================================
  128. void NET_SendFrags(player_t *player)
  129. {
  130. int i;
  131. int frags;
  132. netbuffer->checksum = NetbufferChecksum();
  133. if (demoplayback)
  134. {
  135. return;
  136. }
  137. if (!netgame)
  138. {
  139. I_Error ("Tried to transmit to another node");
  140. }
  141. frags = 0;
  142. for(i = 0; i < MAXPLAYERS; i++)
  143. {
  144. frags += player->frags[i];
  145. }
  146. doomcom->command = CMD_FRAG;
  147. doomcom->remotenode = frags;
  148. doomcom->datalength = NetbufferSize ();
  149. I_NetCmd ();
  150. }
  151. /*
  152. ==============
  153. =
  154. = HGetPacket
  155. =
  156. = Returns false if no packet is waiting
  157. =
  158. ==============
  159. */
  160. boolean HGetPacket (void)
  161. {
  162. if (reboundpacket)
  163. {
  164. *netbuffer = reboundstore;
  165. doomcom->remotenode = 0;
  166. reboundpacket = false;
  167. return true;
  168. }
  169. if (!netgame)
  170. return false;
  171. if (demoplayback)
  172. return false;
  173. doomcom->command = CMD_GET;
  174. I_NetCmd ();
  175. if (doomcom->remotenode == -1)
  176. return false;
  177. if (doomcom->datalength != NetbufferSize ())
  178. {
  179. if (debugfile)
  180. fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
  181. return false;
  182. }
  183. if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
  184. {
  185. if (debugfile)
  186. fprintf (debugfile,"bad packet checksum\n");
  187. return false;
  188. }
  189. if (debugfile)
  190. {
  191. int realretrans;
  192. int i;
  193. if (netbuffer->checksum & NCMD_SETUP)
  194. fprintf (debugfile,"setup packet\n");
  195. else
  196. {
  197. if (netbuffer->checksum & NCMD_RETRANSMIT)
  198. realretrans = ExpandTics (netbuffer->retransmitfrom);
  199. else
  200. realretrans = -1;
  201. fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",doomcom->remotenode,
  202. ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
  203. for (i=0 ; i<doomcom->datalength ; i++)
  204. fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
  205. fprintf (debugfile,"\n");
  206. }
  207. }
  208. return true;
  209. }
  210. /*
  211. ===================
  212. =
  213. = GetPackets
  214. =
  215. ===================
  216. */
  217. char exitmsg[80];
  218. void GetPackets (void)
  219. {
  220. int netconsole;
  221. int netnode;
  222. ticcmd_t *src, *dest;
  223. int realend;
  224. int realstart;
  225. while (HGetPacket ())
  226. {
  227. if (netbuffer->checksum & NCMD_SETUP)
  228. continue; // extra setup packet
  229. netconsole = netbuffer->player & ~PL_DRONE;
  230. netnode = doomcom->remotenode;
  231. //
  232. // to save bytes, only the low byte of tic numbers are sent
  233. // Figure out what the rest of the bytes are
  234. //
  235. realstart = ExpandTics (netbuffer->starttic);
  236. realend = (realstart+netbuffer->numtics);
  237. //
  238. // check for exiting the game
  239. //
  240. if (netbuffer->checksum & NCMD_EXIT)
  241. {
  242. if (!nodeingame[netnode])
  243. continue;
  244. nodeingame[netnode] = false;
  245. playeringame[netconsole] = false;
  246. strcpy (exitmsg, "PLAYER 1 LEFT THE GAME");
  247. exitmsg[7] += netconsole;
  248. P_SetMessage(&players[consoleplayer], exitmsg, true);
  249. S_StartSound(NULL, SFX_CHAT);
  250. // players[consoleplayer].message = exitmsg;
  251. // if (demorecording)
  252. // G_CheckDemoStatus ();
  253. continue;
  254. }
  255. //
  256. // check for a remote game kill
  257. //
  258. if (netbuffer->checksum & NCMD_KILL)
  259. I_Error ("Killed by network driver");
  260. nodeforplayer[netconsole] = netnode;
  261. //
  262. // check for retransmit request
  263. //
  264. if ( resendcount[netnode] <= 0
  265. && (netbuffer->checksum & NCMD_RETRANSMIT) )
  266. {
  267. resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
  268. if (debugfile)
  269. fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
  270. resendcount[netnode] = RESENDCOUNT;
  271. }
  272. else
  273. resendcount[netnode]--;
  274. //
  275. // check for out of order / duplicated packet
  276. //
  277. if (realend == nettics[netnode])
  278. continue;
  279. if (realend < nettics[netnode])
  280. {
  281. if (debugfile)
  282. fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
  283. continue;
  284. }
  285. //
  286. // check for a missed packet
  287. //
  288. if (realstart > nettics[netnode])
  289. {
  290. // stop processing until the other system resends the missed tics
  291. if (debugfile)
  292. fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, realstart, nettics[netnode]);
  293. remoteresend[netnode] = true;
  294. continue;
  295. }
  296. //
  297. // update command store from the packet
  298. //
  299. {
  300. int start;
  301. remoteresend[netnode] = false;
  302. start = nettics[netnode] - realstart;
  303. src = &netbuffer->cmds[start];
  304. while (nettics[netnode] < realend)
  305. {
  306. dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
  307. nettics[netnode]++;
  308. *dest = *src;
  309. src++;
  310. }
  311. }
  312. }
  313. }
  314. /*
  315. =============
  316. =
  317. = NetUpdate
  318. =
  319. = Builds ticcmds for console player
  320. = sends out a packet
  321. =============
  322. */
  323. int gametime;
  324. void NetUpdate (void)
  325. {
  326. int nowtime;
  327. int newtics;
  328. int i,j;
  329. int realstart;
  330. int gameticdiv;
  331. //
  332. // check time
  333. //
  334. nowtime = I_GetTime ()/ticdup;
  335. newtics = nowtime - gametime;
  336. gametime = nowtime;
  337. if (newtics <= 0) // nothing new to update
  338. goto listen;
  339. if (skiptics <= newtics)
  340. {
  341. newtics -= skiptics;
  342. skiptics = 0;
  343. }
  344. else
  345. {
  346. skiptics -= newtics;
  347. newtics = 0;
  348. }
  349. netbuffer->player = consoleplayer;
  350. //
  351. // build new ticcmds for console player
  352. //
  353. gameticdiv = gametic/ticdup;
  354. for (i=0 ; i<newtics ; i++)
  355. {
  356. I_StartTic ();
  357. H2_ProcessEvents ();
  358. if (maketic - gameticdiv >= BACKUPTICS/2-1)
  359. break; // can't hold any more
  360. //printf ("mk:%i ",maketic);
  361. G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
  362. maketic++;
  363. }
  364. if (singletics)
  365. return; // singletic update is syncronous
  366. //
  367. // send the packet to the other nodes
  368. //
  369. for (i=0 ; i<doomcom->numnodes ; i++)
  370. if (nodeingame[i])
  371. {
  372. netbuffer->starttic = realstart = resendto[i];
  373. netbuffer->numtics = maketic - realstart;
  374. if (netbuffer->numtics > BACKUPTICS)
  375. I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
  376. resendto[i] = maketic - doomcom->extratics;
  377. for (j=0 ; j< netbuffer->numtics ; j++)
  378. netbuffer->cmds[j] =
  379. localcmds[(realstart+j)%BACKUPTICS];
  380. if (remoteresend[i])
  381. {
  382. netbuffer->retransmitfrom = nettics[i];
  383. HSendPacket (i, NCMD_RETRANSMIT);
  384. }
  385. else
  386. {
  387. netbuffer->retransmitfrom = 0;
  388. HSendPacket (i, 0);
  389. }
  390. }
  391. //
  392. // listen for other packets
  393. //
  394. listen:
  395. GetPackets ();
  396. }
  397. /*
  398. =====================
  399. =
  400. = CheckAbort
  401. =
  402. =====================
  403. */
  404. void CheckAbort (void)
  405. {
  406. event_t *ev;
  407. int stoptic;
  408. stoptic = I_GetTime () + 2;
  409. while (I_GetTime() < stoptic)
  410. I_StartTic ();
  411. I_StartTic ();
  412. for ( ; eventtail != eventhead
  413. ; eventtail = (++eventtail)&(MAXEVENTS-1) )
  414. {
  415. ev = &events[eventtail];
  416. if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
  417. I_Error ("Network game synchronization aborted.");
  418. }
  419. }
  420. /*
  421. =====================
  422. =
  423. = D_ArbitrateNetStart
  424. =
  425. =====================
  426. */
  427. void D_ArbitrateNetStart (void)
  428. {
  429. int i;
  430. boolean gotinfo[MAXNETNODES];
  431. boolean gotClass[MAXNETNODES];
  432. #ifdef __WATCOMC__
  433. int nextTic;
  434. extern volatile int ticcount;
  435. nextTic = ticcount+8;
  436. #endif
  437. autostart = true;
  438. memset (gotClass,0,sizeof(gotClass));
  439. memset (gotinfo,0,sizeof(gotinfo));
  440. gotClass[doomcom->consoleplayer] = true;
  441. do
  442. {
  443. i = 0;
  444. CheckAbort();
  445. while(HGetPacket())
  446. { // Check for any incoming packets
  447. if(netbuffer->checksum&NCMD_SETUP && netbuffer->starttic >= 64)
  448. {
  449. PlayerClass[netbuffer->player] = netbuffer->starttic&0x3f;
  450. if(!gotClass[netbuffer->player])
  451. {
  452. gotClass[netbuffer->player] = true;
  453. ST_NetProgress();
  454. ST_Message("\n");
  455. }
  456. if(netbuffer->retransmitfrom)
  457. { // that node has received info from all other nodes
  458. gotinfo[netbuffer->player] = true;
  459. }
  460. }
  461. }
  462. #ifdef __WATCOMC__
  463. if(ticcount <= nextTic)
  464. { // only send packets every half second
  465. continue;
  466. }
  467. nextTic = ticcount+8;
  468. #endif
  469. // Keep sending out packets containing the console class
  470. for(i = 0; i < doomcom->numnodes; i++)
  471. {
  472. netbuffer->player = doomcom->consoleplayer;
  473. netbuffer->starttic = PlayerClass[doomcom->consoleplayer]+64;
  474. netbuffer->retransmitfrom = gotinfo[doomcom->consoleplayer];
  475. netbuffer->numtics = 0;
  476. HSendPacket(i, NCMD_SETUP);
  477. }
  478. for(i = 0; i < doomcom->numnodes; i++)
  479. { // Make sure that all nodes have sent class info
  480. if (!gotClass[i])
  481. {
  482. ST_Message(".");
  483. break;
  484. }
  485. }
  486. if(i < doomcom->numnodes)
  487. {
  488. continue;
  489. }
  490. else
  491. { // consoleplayer has received all player classes
  492. if(gotinfo[doomcom->consoleplayer])
  493. {
  494. CheckAbort();
  495. }
  496. else
  497. {
  498. gotinfo[doomcom->consoleplayer] = true;
  499. ST_Message("All player classes received, ready to proceed\n");
  500. ST_NetDone();
  501. }
  502. }
  503. for (i = 0; i < doomcom->numnodes; i++)
  504. { // Make sure that all nodes are ready to proceed
  505. if (!gotinfo[i])
  506. {
  507. break;
  508. }
  509. }
  510. } while(i < doomcom->numnodes);
  511. memset (gotinfo,0,sizeof(gotinfo));
  512. if (doomcom->consoleplayer)
  513. { // listen for setup info from key player
  514. // ST_Message ("listening for network start info...\n");
  515. while (1)
  516. {
  517. CheckAbort ();
  518. if (!HGetPacket ())
  519. continue;
  520. if(netbuffer->checksum & NCMD_SETUP && netbuffer->starttic < 64)
  521. {
  522. if (netbuffer->player != VERSION)
  523. I_Error ("Different HEXEN versions cannot play a net game!");
  524. startskill = netbuffer->retransmitfrom & 15;
  525. deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6;
  526. nomonsters = (netbuffer->retransmitfrom & 0x20) > 0;
  527. respawnparm = (netbuffer->retransmitfrom & 0x10) > 0;
  528. startmap = netbuffer->starttic & 0x3f;
  529. startepisode = 1;
  530. return;
  531. }
  532. }
  533. }
  534. else
  535. { // key player, send the setup info
  536. // ST_Message ("sending network start info...\n");
  537. do
  538. {
  539. CheckAbort ();
  540. for (i=0 ; i<doomcom->numnodes ; i++)
  541. {
  542. netbuffer->retransmitfrom = startskill;
  543. if (deathmatch)
  544. netbuffer->retransmitfrom |= (deathmatch<<6);
  545. if (nomonsters)
  546. netbuffer->retransmitfrom |= 0x20;
  547. if (respawnparm)
  548. netbuffer->retransmitfrom |= 0x10;
  549. netbuffer->starttic = startmap&0x3f;
  550. netbuffer->player = VERSION;
  551. netbuffer->numtics = 0;
  552. HSendPacket (i, NCMD_SETUP);
  553. }
  554. #if 1
  555. for(i = 10 ; i && HGetPacket(); --i)
  556. {
  557. if((netbuffer->player&0x7f) < MAXNETNODES)
  558. gotinfo[netbuffer->player&0x7f] = true;
  559. }
  560. #else
  561. while (HGetPacket ())
  562. {
  563. gotinfo[netbuffer->player&0x7f] = true;
  564. }
  565. #endif
  566. for (i=1 ; i<doomcom->numnodes ; i++)
  567. if (!gotinfo[i])
  568. break;
  569. } while (i < doomcom->numnodes);
  570. }
  571. }
  572. /*
  573. ===================
  574. =
  575. = D_CheckNetGame
  576. =
  577. = Works out player numbers among the net participants
  578. ===================
  579. */
  580. extern int viewangleoffset;
  581. void D_CheckNetGame (void)
  582. {
  583. int i;
  584. int pClass;
  585. for (i=0 ; i<MAXNETNODES ; i++)
  586. {
  587. nodeingame[i] = false;
  588. nettics[i] = 0;
  589. remoteresend[i] = false; // set when local needs tics
  590. resendto[i] = 0; // which tic to start sending
  591. }
  592. // I_InitNetwork sets doomcom and netgame
  593. I_InitNetwork ();
  594. if (doomcom->id != DOOMCOM_ID)
  595. I_Error ("Doomcom buffer invalid!");
  596. netbuffer = &doomcom->data;
  597. consoleplayer = displayplayer = doomcom->consoleplayer;
  598. pClass = PCLASS_FIGHTER;
  599. if(i = M_CheckParm("-class"))
  600. {
  601. pClass = atoi(myargv[i+1]);
  602. if(pClass > PCLASS_MAGE || pClass < PCLASS_FIGHTER)
  603. {
  604. I_Error("Invalid player class: %d\n", pClass);
  605. }
  606. ST_Message("\nPlayer Class: %d\n", pClass);
  607. }
  608. PlayerClass[consoleplayer] = pClass;
  609. if (netgame)
  610. D_ArbitrateNetStart ();
  611. //ST_Message ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
  612. // read values out of doomcom
  613. ticdup = doomcom->ticdup;
  614. maxsend = BACKUPTICS/(2*ticdup)-1;
  615. if (maxsend<1)
  616. maxsend = 1;
  617. for (i=0 ; i<doomcom->numplayers ; i++)
  618. playeringame[i] = true;
  619. for (i=0 ; i<doomcom->numnodes ; i++)
  620. nodeingame[i] = true;
  621. //ST_Message ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
  622. }
  623. /*
  624. ==================
  625. =
  626. = D_QuitNetGame
  627. =
  628. = Called before quitting to leave a net game without hanging the
  629. = other players
  630. =
  631. ==================
  632. */
  633. void D_QuitNetGame (void)
  634. {
  635. int i, j;
  636. if (debugfile)
  637. fclose (debugfile);
  638. if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
  639. return;
  640. // send a bunch of packets for security
  641. netbuffer->player = consoleplayer;
  642. netbuffer->numtics = 0;
  643. for (i=0 ; i<4 ; i++)
  644. {
  645. for (j=1 ; j<doomcom->numnodes ; j++)
  646. if (nodeingame[j])
  647. HSendPacket (j, NCMD_EXIT);
  648. I_WaitVBL (1);
  649. }
  650. }
  651. /*
  652. ===============
  653. =
  654. = TryRunTics
  655. =
  656. ===============
  657. */
  658. int frametics[4], frameon;
  659. int frameskip[4];
  660. int oldnettics;
  661. extern boolean advancedemo;
  662. void TryRunTics (void)
  663. {
  664. int i;
  665. int lowtic;
  666. int entertic;
  667. static int oldentertics;
  668. int realtics, availabletics;
  669. int counts;
  670. int numplaying;
  671. //
  672. // get real tics
  673. //
  674. entertic = I_GetTime ()/ticdup;
  675. realtics = entertic - oldentertics;
  676. oldentertics = entertic;
  677. //
  678. // get available tics
  679. //
  680. NetUpdate ();
  681. lowtic = MAXINT;
  682. numplaying = 0;
  683. for (i=0 ; i<doomcom->numnodes ; i++)
  684. if (nodeingame[i])
  685. {
  686. numplaying++;
  687. if (nettics[i] < lowtic)
  688. lowtic = nettics[i];
  689. }
  690. availabletics = lowtic - gametic/ticdup;
  691. //
  692. // decide how many tics to run
  693. //
  694. if (realtics < availabletics-1)
  695. counts = realtics+1;
  696. else if (realtics < availabletics)
  697. counts = realtics;
  698. else
  699. counts = availabletics;
  700. if (counts < 1)
  701. counts = 1;
  702. frameon++;
  703. if (debugfile)
  704. fprintf (debugfile,"=======real: %i avail: %i game: %i\n",realtics, availabletics,counts);
  705. if (!demoplayback)
  706. {
  707. //=============================================================================
  708. //
  709. // ideally nettics[0] should be 1 - 3 tics above lowtic
  710. // if we are consistantly slower, speed up time
  711. //
  712. for (i=0 ; i<MAXPLAYERS ; i++)
  713. if (playeringame[i])
  714. break;
  715. if (consoleplayer == i)
  716. { // the key player does not adapt
  717. }
  718. else
  719. {
  720. if (nettics[0] <= nettics[nodeforplayer[i]])
  721. {
  722. gametime--;
  723. // printf ("-");
  724. }
  725. frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
  726. oldnettics = nettics[0];
  727. if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
  728. {
  729. skiptics = 1;
  730. // printf ("+");
  731. }
  732. }
  733. //=============================================================================
  734. } // demoplayback
  735. //
  736. // wait for new tics if needed
  737. //
  738. while (lowtic < gametic/ticdup + counts)
  739. {
  740. NetUpdate ();
  741. lowtic = MAXINT;
  742. for (i=0 ; i<doomcom->numnodes ; i++)
  743. if (nodeingame[i] && nettics[i] < lowtic)
  744. lowtic = nettics[i];
  745. if (lowtic < gametic/ticdup)
  746. I_Error ("TryRunTics: lowtic < gametic");
  747. // don't stay in here forever -- give the menu a chance to work
  748. if (I_GetTime ()/ticdup - entertic >= 20)
  749. {
  750. MN_Ticker ();
  751. return;
  752. }
  753. }
  754. //
  755. // run the count * ticdup dics
  756. //
  757. while (counts--)
  758. {
  759. for (i=0 ; i<ticdup ; i++)
  760. {
  761. if (gametic/ticdup > lowtic)
  762. I_Error ("gametic>lowtic");
  763. if (advancedemo)
  764. H2_DoAdvanceDemo ();
  765. MN_Ticker ();
  766. G_Ticker ();
  767. gametic++;
  768. //
  769. // modify command for duplicated tics
  770. //
  771. if (i != ticdup-1)
  772. {
  773. ticcmd_t *cmd;
  774. int buf;
  775. int j;
  776. buf = (gametic/ticdup)%BACKUPTICS;
  777. for (j=0 ; j<MAXPLAYERS ; j++)
  778. {
  779. cmd = &netcmds[j][buf];
  780. cmd->chatchar = 0;
  781. if (cmd->buttons & BT_SPECIAL)
  782. cmd->buttons = 0;
  783. }
  784. }
  785. }
  786. NetUpdate (); // check for new console commands
  787. }
  788. }