// resend the data if needed void Net_AckTicker(void) { #ifndef NONET INT32 i; for (i = 0; i < MAXACKPACKETS; i++) { const INT32 nodei = ackpak[i].destinationnode; node_t *node = &nodes[nodei]; #ifdef NEWPING if (ackpak[i].acknum && ackpak[i].senttime + NODETIMEOUT < I_GetTime()) #else if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime()) #endif { if (ackpak[i].resentnum > 10 && (node->flags & CLOSE)) { DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n", i, nodei)); Net_CloseConnection(nodei | FORCECLOSE); ackpak[i].acknum = 0; continue; } #ifdef NEWPING DEBFILE(va("Resend ack %d, %u<%d at %u\n", ackpak[i].acknum, ackpak[i].senttime, NODETIMEOUT, I_GetTime())); #else DEBFILE(va("Resend ack %d, %u<%d at %u\n", ackpak[i].acknum, ackpak[i].senttime, node->timeout, I_GetTime())); #endif M_Memcpy(netbuffer, ackpak[i].pak.raw, ackpak[i].length); ackpak[i].senttime = I_GetTime(); ackpak[i].resentnum++; ackpak[i].nextacknum = node->nextacknum; retransmit++; // for stat HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum, (size_t)(ackpak[i].length - BASEPACKETSIZE)); } } for (i = 1; i < MAXNETNODES; i++) { // this is something like node open flag if (nodes[i].firstacktosend) { // we haven't sent a packet for a long time // acknowledge packet if needed if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime()) Net_SendAcks(i); if (!(nodes[i].flags & CLOSE) && nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime()) { Net_ConnectionTimeout(i); } } } #endif }
// send special packet with only ack on it void Net_SendAcks(INT32 node) { #ifdef NONET (void)node; #else netbuffer->packettype = PT_NOTHING; M_Memcpy(netbuffer->u.textcmd, nodes[node].acktosend, MAXACKTOSEND); HSendPacket(node, false, 0, MAXACKTOSEND); #endif }
void NetUpdate (void) { int nowtime; int newtics; int i,j; int realstart; int gameticdiv; // check time nowtime = I_GetTime ()/ticdup; newtics = nowtime - gametime; gametime = nowtime; if (newtics <= 0) // nothing new to update goto listen; if (skiptics <= newtics) { newtics -= skiptics; skiptics = 0; } else { skiptics -= newtics; newtics = 0; } netbuffer->player = consoleplayer; // build new ticcmds for console player gameticdiv = gametic/ticdup; for (i=0 ; i<newtics ; i++) { I_StartTic (); D_ProcessEvents (); if (maketic - gameticdiv >= BACKUPTICS/2-1) break; // can't hold any more //printf ("mk:%i ",maketic); G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]); maketic++; } if (singletics) return; // singletic update is syncronous // send the packet to the other nodes for (i=0 ; i<doomcom->numnodes ; i++) if (nodeingame[i]) { netbuffer->starttic = realstart = resendto[i]; netbuffer->numtics = maketic - realstart; if (netbuffer->numtics > BACKUPTICS) I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS"); resendto[i] = maketic - doomcom->extratics; for (j=0 ; j< netbuffer->numtics ; j++) netbuffer->cmds[j] = localcmds[(realstart+j)%BACKUPTICS]; if (remoteresend[i]) { netbuffer->retransmitfrom = nettics[i]; HSendPacket (i, NCMD_RETRANSMIT); } else { netbuffer->retransmitfrom = 0; HSendPacket (i, 0); } } // listen for other packets listen: GetPackets (); }
void D_ArbitrateNetStart (void) { int i; boolean gotinfo[MAXNETNODES]; boolean gotClass[MAXNETNODES]; #ifdef __WATCOMC__ int nextTic; extern volatile int ticcount; nextTic = ticcount+8; #endif autostart = true; memset (gotClass,0,sizeof(gotClass)); memset (gotinfo,0,sizeof(gotinfo)); gotClass[doomcom->consoleplayer] = true; do { i = 0; CheckAbort(); while(HGetPacket()) { // Check for any incoming packets if(netbuffer->checksum&NCMD_SETUP && netbuffer->starttic >= 64) { PlayerClass[netbuffer->player] = netbuffer->starttic&0x3f; if(!gotClass[netbuffer->player]) { gotClass[netbuffer->player] = true; ST_NetProgress(); ST_Message("\n"); } if(netbuffer->retransmitfrom) { // that node has received info from all other nodes gotinfo[netbuffer->player] = true; } } } #ifdef __WATCOMC__ if(ticcount <= nextTic) { // only send packets every half second continue; } nextTic = ticcount+8; #endif // Keep sending out packets containing the console class for(i = 0; i < doomcom->numnodes; i++) { netbuffer->player = doomcom->consoleplayer; netbuffer->starttic = PlayerClass[doomcom->consoleplayer]+64; netbuffer->retransmitfrom = gotinfo[doomcom->consoleplayer]; netbuffer->numtics = 0; HSendPacket(i, NCMD_SETUP); } for(i = 0; i < doomcom->numnodes; i++) { // Make sure that all nodes have sent class info if (!gotClass[i]) { ST_Message("."); break; } } if(i < doomcom->numnodes) { continue; } else { // consoleplayer has received all player classes if(gotinfo[doomcom->consoleplayer]) { CheckAbort(); } else { gotinfo[doomcom->consoleplayer] = true; ST_Message("All player classes received, ready to proceed\n"); ST_NetDone(); } } for (i = 0; i < doomcom->numnodes; i++) { // Make sure that all nodes are ready to proceed if (!gotinfo[i]) { break; } } } while(i < doomcom->numnodes); memset (gotinfo,0,sizeof(gotinfo)); if (doomcom->consoleplayer) { // listen for setup info from key player // ST_Message ("listening for network start info...\n"); while (1) { CheckAbort (); if (!HGetPacket ()) continue; if(netbuffer->checksum & NCMD_SETUP && netbuffer->starttic < 64) { if (netbuffer->player != VERSION) I_Error ("Different HEXEN versions cannot play a net game!"); startskill = netbuffer->retransmitfrom & 15; deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6; nomonsters = (netbuffer->retransmitfrom & 0x20) > 0; respawnparm = (netbuffer->retransmitfrom & 0x10) > 0; startmap = netbuffer->starttic & 0x3f; startepisode = 1; return; } } } else { // key player, send the setup info // ST_Message ("sending network start info...\n"); do {