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; }
/* ======================= SV_SendMessageToClient Called by SV_SendClientSnapshot and SV_SendClientGameState ======================= */ void SV_SendMessageToClient( msg_s* msg, client_t* client ) { // 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 ); }
/* * SV_SendMessageToClient */ bool SV_SendMessageToClient( client_t *client, msg_t *msg ) { assert( client ); if( client->edict && ( client->edict->r.svflags & SVF_FAKECLIENT ) ) return true; // transmit the message data client->lastPacketSentTime = svs.realtime; return SV_Netchan_Transmit( &client->netchan, msg ); }
/* ======================= SV_SendMessageToClient Called by SV_SendClientSnapshot and SV_SendClientGameState ======================= */ __cdecl void SV_SendMessageToClient( msg_t *msg, client_t *client ) { int rateMsec; int len; *(int32_t*)0x13f39080 = *(int32_t*)msg->data; len = MSG_WriteBitsCompress( 0, msg->data + 4 ,(byte*)0x13f39084 , msg->cursize - 4); // SV_TrackHuffmanCompression(len, msg->cursize - 4); len += 4; if(client->delayDropMsg){ SV_DropClient(client, client->delayDropMsg); } if(client->demorecording && !client->demowaiting) SV_WriteDemoMessageForClient((byte*)0x13f39080, len, client); // record information about the message client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = len; client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = Sys_Milliseconds(); client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageAcked = 0xFFFFFFFF; // send the datagram SV_Netchan_Transmit( client, (byte*)0x13f39080, len ); // set nextSnapshotTime based on rate and requested number of updates // local clients get snapshots every frame // TTimo - show_bug.cgi?id=491 // added sv_lanForceRate check if(client->state == CS_ACTIVE && client->deltaMessage >= 0 && client->netchan.outgoingSequence - client->deltaMessage > 28){ client->nextSnapshotTime = svs.time + client->snapshotMsec * irand(); if(client->unknown6 +1 > 8) { client->unknown6 = 8; } } client->unknown6 = 0; 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 ); // TTimo - during a download, ignore the snapshotMsec // the update server on steroids, with this disabled and sv_fps 60, the download can reach 30 kb/s // on a regular server, we will still top at 20 kb/s because of sv_fps 20 if ( !*client->downloadName && 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 && !*client->downloadName) { // 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 if ( client->nextSnapshotTime < svs.time + 1000 ) { client->nextSnapshotTime = svs.time + 1000; } } sv.bpsTotalBytes += len ; }
/* ======================= 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 ); }