void SV_EndClientSnapshot(client_t *client, msg_t *msg) { if ( client->state != CS_ZOMBIE ) SV_WriteDownloadToClient(client, msg); MSG_WriteByte(msg, svc_EOF); if ( msg->overflowed == qtrue) { Com_PrintWarning( "WARNING: msg overflowed for %s, trying to recover\n", client->shortname); if ( client->state == CS_ACTIVE || client->state == CS_ZOMBIE ) { SV_ShowClientUnAckCommands(client); MSG_Clear( msg ); MSG_WriteLong(msg, client->lastClientCommand); SV_UpdateServerCommandsToClientRecover( client, msg ); MSG_WriteByte(msg, svc_EOF); } if ( msg->overflowed == qtrue) { Com_PrintWarning("WARNING: client disconnected for msg overflow: %s\n", client->shortname); NET_OutOfBandPrint(NS_SERVER, &client->netchan.remoteAddress, "disconnect"); SV_DropClient(client, "EXE_SERVERMESSAGEOVERFLOW"); } } SV_SendMessageToClient(msg, client); }
int SV_SendDownloadMessages(void) { int i, numDLs = 0, retval; client_t *cl; msg_t msg; byte msgBuffer[MAX_MSGLEN]; for(i=0; i < sv_maxclients->integer; i++) { cl = &svs.clients[i]; if(cl->state && *cl->downloadName) { MSG_Init(&msg, msgBuffer, sizeof(msgBuffer)); MSG_WriteLong(&msg, cl->lastClientCommand); retval = SV_WriteDownloadToClient(cl, &msg); if(retval) { MSG_WriteByte(&msg, svc_EOF); SV_Netchan_Transmit(cl, &msg); numDLs += retval; } } } return numDLs; }
int SV_SendDownloadMessages(void) { int i, numDLs = 0; client_t *cl; msg_t msg; byte msgBuffer[MAX_MSGLEN]; for(i=0; i < sv_maxclients->integer; i++) { cl = &svs.clients[i]; if(cl->state && *cl->downloadName) { int basesize; MSG_Init(&msg, msgBuffer, sizeof(msgBuffer)); MSG_WriteLong(&msg, cl->lastClientCommand); basesize = msg.cursize; SV_WriteDownloadToClient(cl, &msg); if (msg.cursize != basesize) { SV_SendMessageToClient(&msg, cl); numDLs++; } } } return numDLs; }
/* ======================= SV_SendMessageToClient Called by SV_SendClientSnapshot and SV_SendClientGameState ======================= */ void SV_SendMessageToClient( msg_t *msg, client_t *client ) { int rateMsec; // MW - my attempt to fix illegible server message errors caused by // packet fragmentation of initial snapshot. while(client->state&&client->netchan.unsentFragments) { // send additional message fragments if the last message // was too large to send at once Com_Printf ("[ISM]SV_SendClientGameState() [1] for %s, writing out old fragments\n", client->name); SV_Netchan_TransmitNextFragment(&client->netchan); } // record information about the message client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = msg->cursize; client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = svs.time; client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageAcked = -1; // send the datagram SV_Netchan_Transmit( client, msg ); //msg->cursize, msg->data ); // set nextSnapshotTime based on rate and requested number of updates // local clients get snapshots every frame if ( client->netchan.remoteAddress.type == NA_LOOPBACK || Sys_IsLANAddress (client->netchan.remoteAddress) ) { client->nextSnapshotTime = svs.time - 1; return; } // normal rate / snapshotMsec calculation rateMsec = SV_RateMsec( client, msg->cursize ); if ( rateMsec < client->snapshotMsec ) { // never send more packets than this, no matter what the rate is at rateMsec = client->snapshotMsec; client->rateDelayed = qfalse; } else { client->rateDelayed = qtrue; } client->nextSnapshotTime = svs.time + rateMsec; // don't pile up empty snapshots while connecting if ( client->state != CS_ACTIVE ) { // a gigantic connection message may have already put the nextSnapshotTime // more than a second away, so don't shorten it // do shorten if client is downloading #ifdef _XBOX // No downloads on Xbox if ( client->nextSnapshotTime < svs.time + 1000 ) { #else if ( !*client->downloadName && client->nextSnapshotTime < svs.time + 1000 ) { #endif client->nextSnapshotTime = svs.time + 1000; } } } /* ======================= SV_SendClientSnapshot Also called by SV_FinalMessage ======================= */ extern cvar_t *fs_gamedirvar; void SV_SendClientSnapshot( client_t *client ) { byte msg_buf[MAX_MSGLEN]; msg_t msg; if (!client->sentGamedir) { //rww - if this is the case then make sure there is an svc_setgame sent before this snap int i = 0; MSG_Init (&msg, msg_buf, sizeof(msg_buf)); //have to include this for each message. MSG_WriteLong( &msg, client->lastClientCommand ); MSG_WriteByte (&msg, svc_setgame); while (fs_gamedirvar->string[i]) { MSG_WriteByte(&msg, fs_gamedirvar->string[i]); i++; } MSG_WriteByte(&msg, 0); // MW - my attempt to fix illegible server message errors caused by // packet fragmentation of initial snapshot. //rww - reusing this code here while(client->state&&client->netchan.unsentFragments) { // send additional message fragments if the last message // was too large to send at once Com_Printf ("[ISM]SV_SendClientGameState() [1] for %s, writing out old fragments\n", client->name); SV_Netchan_TransmitNextFragment(&client->netchan); } // record information about the message client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = msg.cursize; client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = svs.time; client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageAcked = -1; // send the datagram SV_Netchan_Transmit( client, &msg ); //msg->cursize, msg->data ); client->sentGamedir = qtrue; } // build the snapshot SV_BuildClientSnapshot( client ); // bots need to have their snapshots build, but // the query them directly without needing to be sent if ( client->gentity && client->gentity->r.svFlags & SVF_BOT ) { return; } MSG_Init (&msg, msg_buf, sizeof(msg_buf)); msg.allowoverflow = qtrue; // NOTE, MRE: all server->client messages now acknowledge // let the client know which reliable clientCommands we have received MSG_WriteLong( &msg, client->lastClientCommand ); // (re)send any reliable server commands SV_UpdateServerCommandsToClient( client, &msg ); // send over all the relevant entityState_t // and the playerState_t SV_WriteSnapshotToClient( client, &msg ); // Add any download data if the client is downloading #ifndef _XBOX // No downloads on Xbox SV_WriteDownloadToClient( client, &msg ); #endif // check for overflow if ( msg.overflowed ) { Com_Printf ("WARNING: msg overflowed for %s\n", client->name); MSG_Clear (&msg); } SV_SendMessageToClient( &msg, client ); }