static void CheckQueuedPackets(void) { int i; for (i=0; (unsigned)i<numqueuedpackets; i++) if (doom_ntohl(queuedpacket[i]->tic) <= gametic) switch (queuedpacket[i]->type) { case PKT_QUIT: // Player quit the game { int pn = *(byte*)(queuedpacket[i]+1); playeringame[pn] = false; doom_printf("Player %d left the game\n", pn); } break; case PKT_EXTRA: { int *p = (int*)(queuedpacket[i]+1); size_t len = LONG(*(p+2)); switch (LONG(*p)) { case nm_plcolour: G_ChangedPlayerColour(LONG(*(p+1)), LONG(*(p+3))); break; case nm_savegamename: if (len < SAVEDESCLEN) { memcpy(savedescription, p+3, len); // Force terminating 0 in case savedescription[len] = 0; } break; } } break; default: // Should not be queued break; } { // Requeue remaining packets int newnum = 0; packet_header_t **newqueue = NULL; for (i=0; (unsigned)i<numqueuedpackets; i++) if (doom_ntohl(queuedpacket[i]->tic) > gametic) { newqueue = Z_Realloc(newqueue, ++newnum * sizeof *newqueue, PU_STATIC, NULL); newqueue[newnum-1] = queuedpacket[i]; } else Z_Free(queuedpacket[i]); Z_Free(queuedpacket); numqueuedpackets = newnum; queuedpacket = newqueue; } }
void NetUpdate(void) { static int lastmadetic; if (isExtraDDisplay) return; if (server) { // Receive network packets size_t recvlen; packet_header_t *packet = Z_Malloc(10000, PU_STATIC, NULL); while ((recvlen = I_GetPacket(packet, 10000))) { switch(packet->type) { case PKT_TICS: { uint8_t *p = (void*)(packet+1); int tics = *p++; unsigned long ptic = doom_ntohl(packet->tic); if (ptic > (unsigned)remotetic) { // Missed some packet_set(packet, PKT_RETRANS, remotetic); *(uint8_t*)(packet+1) = consoleplayer; I_SendPacket(packet, sizeof(*packet)+1); } else { if (ptic + tics <= (unsigned)remotetic) break; // Will not improve things remotetic = ptic; while (tics--) { int players = *p++; while (players--) { int n = *p++; RawToTic(&netcmds[n][remotetic%BACKUPTICS], p); p += sizeof(ticcmd_t); } remotetic++; } } } break; case PKT_RETRANS: // Resend request remotesend = doom_ntohl(packet->tic); break; case PKT_DOWN: // Server downed { int j; for (j=0; j<MAXPLAYERS; j++) if (j != consoleplayer) playeringame[j] = FALSE; server = FALSE; doom_printf("Server is down\nAll other players are no longer in the game\n"); } break; case PKT_EXTRA: // Misc stuff case PKT_QUIT: // Player quit // Queue packet to be processed when its tic time is reached queuedpacket = Z_Realloc(queuedpacket, ++numqueuedpackets * sizeof *queuedpacket, PU_STATIC, NULL); queuedpacket[numqueuedpackets-1] = Z_Malloc(recvlen, PU_STATIC, NULL); memcpy(queuedpacket[numqueuedpackets-1], packet, recvlen); break; case PKT_BACKOFF: /* cph 2003-09-18 - * The server sends this when we have got ahead of the other clients. We should * stall the input side on this client, to allow other clients to catch up. */ lastmadetic++; break; default: // Other packet, unrecognised or redundant break; } } Z_Free(packet); } { // Build new ticcmds int newtics = I_GetTime() - lastmadetic; newtics = (newtics > 0 ? newtics : 0); lastmadetic += newtics; if (ffmap) newtics++; while (newtics--) { I_StartTic(); if (maketic - gametic > BACKUPTICS/2) break; G_BuildTiccmd(&localcmds[maketic%BACKUPTICS]); maketic++; } if (server && maketic > remotesend) { // Send the tics to the server int sendtics; remotesend -= xtratics; if (remotesend < 0) remotesend = 0; sendtics = maketic - remotesend; { size_t pkt_size = sizeof(packet_header_t) + 2 + sendtics * sizeof(ticcmd_t); packet_header_t *packet = Z_Malloc(pkt_size, PU_STATIC, NULL); packet_set(packet, PKT_TICC, maketic - sendtics); *(uint8_t*)(packet+1) = sendtics; *(((uint8_t*)(packet+1))+1) = consoleplayer; { void *tic = ((uint8_t*)(packet+1)) +2; while (sendtics--) { TicToRaw(tic, &localcmds[remotesend++%BACKUPTICS]); tic = (uint8_t *)tic + sizeof(ticcmd_t); } } I_SendPacket(packet, pkt_size); Z_Free(packet); } } } }
void udp_receive(int s) { size_t len = 1024; packet_header_t *p = malloc(len); int rc; rc = read(s,p,len); if (rc < 0) { fprintf(stderr,"read(udp): %s\n", strerror(errno)); exit(-2); } if (rc > 0) { switch (p->type) { case PKT_SETUP: { struct setup_packet_s *sinfo = (void*)(p+1); consoleplayer = sinfo->yourplayer; send_udp_packet(PKT_GO,0,NULL,0); write(ipxs,"\xff\xff\xff\xff\x00\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00",16); } break; case PKT_GO: { ipxpacket_t pkt; memset(&pkt,0,sizeof(pkt)); pkt.tic = ipxcounter++; pkt.u.d.player = consoleplayer^1; pkt.u.d.starttic = 0; pkt.u.d.numtics = 0; pkt.u.d.retransmitfrom = 0; pkt.u.d.checksum = NetbufferChecksum(&pkt.u.d.retransmitfrom, 4); write(ipxs,&pkt,16); } break; case PKT_TICS: { ipxpacket_t pkt; int tic = doom_ntohl(p->tic); byte *pp = (void*)(p+1); int tics = *pp++; memset(&pkt,0,sizeof(pkt)); size_t len; pkt.tic = ipxcounter++; pkt.u.d.starttic = tic; pkt.u.d.player = (consoleplayer == 0 ? 1 : 0); pkt.u.d.numtics = tics; for (int t=0; t<tics; t++) { int players = *pp++; for (int i=0; i<players; i++) { if (*pp++ == pkt.u.d.player) RawToTic(&pkt.u.d.cmds[t],pp); pp += sizeof(ticcmd_t); } } pkt.u.d.retransmitfrom = 0; len = 12+tics*sizeof(ticcmd_t); len = (len+7)&0xff8; // round up to next 16 pkt.u.d.checksum = NetbufferChecksum(&pkt.u.d.retransmitfrom, len-8); write(ipxs,&pkt,len); } } } }