static void demoFramePack( msg_t *msg, const demoFrame_t *newFrame, const demoFrame_t *oldFrame ) { int i; /* Full or delta frame marker */ MSG_WriteBits( msg, oldFrame ? 0 : 1, 1 ); MSG_WriteLong( msg, newFrame->serverTime ); /* Add the config strings */ for (i = 0;i<MAX_CONFIGSTRINGS;i++) { const char *oldString = !oldFrame ? "" : &oldFrame->string.data[oldFrame->string.offsets[i]]; const char *newString = newFrame->string.data + newFrame->string.offsets[i]; if (strcmp( oldString, newString)) { MSG_WriteShort( msg, i ); MSG_WriteBigString( msg, newString ); } } MSG_WriteShort( msg, MAX_CONFIGSTRINGS ); /* Add the playerstates */ for (i=0; i<MAX_CLIENTS; i++) { const playerState_t *oldPlayer, *newPlayer; if (!newFrame->clientData[i]) continue; oldPlayer = (!oldFrame || !oldFrame->clientData[i]) ? &demoNullPlayerState : &oldFrame->clients[i]; newPlayer = &newFrame->clients[i]; MSG_WriteByte( msg, i ); MSG_WriteDeltaPlayerstate( msg, oldPlayer, newPlayer ); } MSG_WriteByte( msg, MAX_CLIENTS ); /* Add the entities */ for (i=0; i<MAX_GENTITIES-1; i++) { const entityState_t *oldEntity, *newEntity; newEntity = &newFrame->entities[i]; if (oldFrame) { oldEntity = &oldFrame->entities[i]; if (oldEntity->number == (MAX_GENTITIES -1)) oldEntity = 0; } else { oldEntity = 0; } if (newEntity->number != i || newEntity->number >= (MAX_GENTITIES -1)) { newEntity = 0; } else { if (!oldEntity) { oldEntity = &demoNullEntityState; } } MSG_WriteDeltaEntity( msg, oldEntity, newEntity, qfalse ); } MSG_WriteBits( msg, (MAX_GENTITIES-1), GENTITYNUM_BITS ); /* Add the area mask */ MSG_WriteByte( msg, newFrame->areaUsed ); MSG_WriteData( msg, newFrame->areamask, newFrame->areaUsed ); /* Add the command string data */ MSG_WriteLong( msg, newFrame->commandUsed ); MSG_WriteData( msg, newFrame->commandData, newFrame->commandUsed ); }
/* ================== SV_WriteSnapshotToClient ================== */ static void SV_WriteSnapshotToClient(client_t *client, msg_t *msg) { clientSnapshot_t *frame, *oldframe; int lastframe; int i; int snapFlags; // this is the snapshot we are creating frame = &client->frames[client->netchan.outgoingSequence & PACKET_MASK]; // try to use a previous frame as the source for delta compressing the snapshot if (client->deltaMessage <= 0 || client->state != CS_ACTIVE) { // client is asking for a retransmit oldframe = NULL; lastframe = 0; } else if (client->netchan.outgoingSequence - client->deltaMessage >= (PACKET_BACKUP - 3)) { // client hasn't gotten a good message through in a long time Com_DPrintf("%s: Delta request from out of date packet.\n", client->name); oldframe = NULL; lastframe = 0; } else { // we have a valid snapshot to delta from oldframe = &client->frames[client->deltaMessage & PACKET_MASK]; lastframe = client->netchan.outgoingSequence - client->deltaMessage; // the snapshot's entities may still have rolled off the buffer, though if (oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities) { Com_DPrintf("%s: Delta request from out of date entities.\n", client->name); oldframe = NULL; lastframe = 0; } } MSG_WriteByte(msg, svc_snapshot); // NOTE, MRE: now sent at the start of every message from server to client // let the client know which reliable clientCommands we have received // MSG_WriteLong( msg, client->lastClientCommand ); // send over the current server time so the client can drift // its view of time to try to match if (client->oldServerTime) { // The server has not yet got an acknowledgement of the // new gamestate from this client, so continue to send it // a time as if the server has not restarted. Note from // the client's perspective this time is strictly speaking // incorrect, but since it'll be busy loading a map at // the time it doesn't really matter. MSG_WriteLong(msg, sv.time + client->oldServerTime); } else { MSG_WriteLong(msg, sv.time); } // what we are delta'ing from MSG_WriteByte(msg, lastframe); snapFlags = svs.snapFlagServerBit; if (client->rateDelayed) { snapFlags |= SNAPFLAG_RATE_DELAYED; } if (client->state != CS_ACTIVE) { snapFlags |= SNAPFLAG_NOT_ACTIVE; } MSG_WriteByte(msg, snapFlags); // send over the areabits MSG_WriteByte(msg, frame->areabytes); MSG_WriteData(msg, frame->areabits, frame->areabytes); // delta encode the playerstate if (oldframe) { MSG_WriteDeltaPlayerstate(client->netchan.alternateProtocol, msg, &oldframe->ps, &frame->ps); } else { MSG_WriteDeltaPlayerstate(client->netchan.alternateProtocol, msg, NULL, &frame->ps); } // delta encode the entities SV_EmitPacketEntities(client->netchan.alternateProtocol, oldframe, frame, msg); // padding for rate debugging if (sv_padPackets->integer) { for (i = 0; i < sv_padPackets->integer; i++) { MSG_WriteByte(msg, svc_nop); } } }
__cdecl void SV_WriteSnapshotToClient(client_t* client, msg_t* msg){ snapshotInfo_t snapInfo; int lastframe; int from_num_entities; int newindex, oldindex, newnum, oldnum; clientState_ts *newcs, *oldcs; entityState_t *newent, *oldent; clientSnapshot_t *frame, *oldframe; int i; int snapFlags; int var_x, from_first_entity, from_num_clients, from_first_client; snapInfo.clnum = client - svsHeader.clients; snapInfo.cl = (void*)client; snapInfo.var_01 = 0; snapInfo.var_02 = 0; snapInfo.var_03 = 0; frame = &client->frames[client->netchan.outgoingSequence & PACKET_MASK]; frame->var_03 = svsHeader.time; if(client->deltaMessage <= 0 || client->state != CS_ACTIVE) { oldframe = NULL; lastframe = 0; var_x = 0; } else if(client->netchan.outgoingSequence - client->deltaMessage >= PACKET_BACKUP - 3) { Com_DPrintf("%s: Delta request from out of date packet.\n", client->name); oldframe = NULL; lastframe = 0; var_x = 0; } else if(client->demoDeltaFrameCount <= 0 && client->demorecording){ oldframe = NULL; lastframe = 0; var_x = 0; client->demowaiting = qfalse; Com_DPrintf("Force a nondelta frame for %s for demo recording\n", client->name); if(client->demoMaxDeltaFrames < 1024) { client->demoMaxDeltaFrames <<= 1; } client->demoDeltaFrameCount = client->demoMaxDeltaFrames; } else { oldframe = &client->frames[client->deltaMessage & PACKET_MASK]; lastframe = client->netchan.outgoingSequence - client->deltaMessage; var_x = oldframe->var_03; client->demoDeltaFrameCount--; if(oldframe->first_entity < svsHeader.nextSnapshotEntities - svsHeader.numSnapshotEntities) { Com_PrintWarning("%s: Delta request from out of date entities - delta against entity %i, oldest is %i, current is %i. Their old snapshot had %i entities in it\n", client->name, oldframe->first_entity, svs.nextSnapshotEntities - svs.numSnapshotEntities, svs.nextSnapshotEntities, oldframe->num_entities ); oldframe = NULL; lastframe = 0; var_x = 0; } else if(oldframe->first_client < svsHeader.nextSnapshotClients - svsHeader.numSnapshotClients) { Com_PrintWarning("%s: Delta request from out of date clients - delta against client %i, oldest is %i, current is %i. Their old snapshot had %i clients in it\n", client->name, oldframe->first_client, svs.nextSnapshotClients - svs.numSnapshotClients, svs.nextSnapshotClients, oldframe->num_clients); oldframe = NULL; lastframe = 0; var_x = 0; } } MSG_WriteByte(msg, svc_snapshot); MSG_WriteLong(msg, svsHeader.time); MSG_WriteByte(msg, lastframe); snapInfo.var_01 = var_x; snapFlags = svsHeader.snapFlagServerBit; if(client->rateDelayed){ snapFlags |= 1; } if(client->state == CS_ACTIVE) { client->unksnapshotvar = 1; } else { if(client->state != CS_ZOMBIE){ client->unksnapshotvar = 0; } } if(!client->unksnapshotvar){ snapFlags |= 2; } MSG_WriteByte(msg, snapFlags); if(oldframe) { MSG_WriteDeltaPlayerstate( &snapInfo, msg, svsHeader.time, &oldframe->ps, &frame->ps); from_num_entities = oldframe->num_entities; from_first_entity = oldframe->first_entity; from_num_clients = oldframe->num_clients; from_first_client = oldframe->first_client; } else { MSG_WriteDeltaPlayerstate( &snapInfo, msg, svsHeader.time, 0, &frame->ps); from_num_entities = 0; from_first_entity = 0; from_num_clients = 0; from_first_client = 0; } MSG_ClearLastReferencedEntity(msg); newindex = 0; oldindex = 0; // Com_Printf("\nDelta client: %i:\n", snapInfo.clnum); while ( newindex < frame->num_entities || oldindex < from_num_entities){ if ( newindex >= frame->num_entities ) { newnum = 9999; newent = NULL; } else { newent = &svsHeader.snapshotEntities[( frame->first_entity + newindex ) % svsHeader.numSnapshotEntities]; newnum = newent->number; } if ( oldindex >= from_num_entities ) { oldnum = 9999; oldent = NULL; } else { oldent = &svsHeader.snapshotEntities[( from_first_entity + oldindex ) % svsHeader.numSnapshotEntities]; oldnum = oldent->number; } if ( newnum == oldnum ) { // delta update from old position // because the force parm is qfalse, this will not result // in any bytes being emited if the entity has not changed at all // if(newent->number < 64 || oldent->number < 64) // Com_Printf(" Delta Update Entity - New delta: %i, %x Old delta: %i, %x\n", newent->number, newent, oldent->number, oldent); MSG_WriteDeltaEntity( &snapInfo, msg, svsHeader.time, oldent, newent, qfalse ); oldindex++; newindex++; continue; } if ( newnum < oldnum ) { // this is a new entity, send it from the baseline snapInfo.var_02 = 1; // if(newent->number < 64) // Com_Printf(" Delta Add Entity: %i, %x\n", newent->number, newent); MSG_WriteDeltaEntity( &snapInfo, msg, svsHeader.time, &svsHeader.svEntities[newnum].baseline, newent, qtrue ); snapInfo.var_02 = 0; newindex++; continue; } if ( newnum > oldnum ) { // the old entity isn't present in the new message // if(oldent->number < 64) // Com_Printf(" Delta Remove Entity: %i, %x\n", oldent->number, oldent); MSG_WriteDeltaEntity( &snapInfo, msg, svsHeader.time, oldent, NULL, qtrue ); oldindex++; continue; } } MSG_WriteEntityIndex(&snapInfo, msg, ( MAX_GENTITIES - 1 ), GENTITYNUM_BITS); MSG_ClearLastReferencedEntity(msg); newindex = 0; oldindex = 0; while(newindex < frame->num_clients || oldindex < from_num_clients){ if(newindex >= frame->num_clients){ newnum = 9999; newcs = NULL; }else{ newcs = &svsHeader.snapshotClients[(frame->first_client + newindex) % svsHeader.numSnapshotClients]; newnum = newcs->number; } if(oldindex >= from_num_clients){ oldnum = 9999; oldcs = NULL; }else{ oldcs = &svsHeader.snapshotClients[(from_first_client + oldindex) % svsHeader.numSnapshotClients]; oldnum = oldcs->number; } if ( newnum == oldnum ) { // delta update from old position // because the force parm is qfalse, this will not result // in any bytes being emited if the entity has not changed at all MSG_WriteDeltaClient( &snapInfo, msg, svsHeader.time, oldcs, newcs, qfalse ); oldindex++; newindex++; continue; } if ( newnum < oldnum ) { MSG_WriteDeltaClient( &snapInfo, msg, svsHeader.time, NULL, newcs, qtrue ); newindex++; continue; } if ( newnum > oldnum ) { MSG_WriteDeltaClient( &snapInfo, msg, svsHeader.time, oldcs, NULL, qtrue ); oldindex++; continue; } } MSG_WriteBit0(msg); if(sv_padPackets->integer){ for( i=0 ; i < sv_padPackets->integer ; i++){ MSG_WriteByte( msg, 0); //svc_nop } } }
/* ================== SV_WriteSnapshotToClient ================== */ static void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) { clientSnapshot_t *frame, *oldframe; int lastframe; int snapFlags; // this is the snapshot we are creating frame = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ]; // try to use a previous frame as the source for delta compressing the snapshot if ( client->deltaMessage <= 0 || client->state != CS_ACTIVE ) { // client is asking for a retransmit oldframe = NULL; lastframe = 0; } else if ( client->netchan.outgoingSequence - client->deltaMessage >= (PACKET_BACKUP - 3) ) { // client hasn't gotten a good message through in a long time Com_DPrintf ("%s: Delta request from out of date packet.\n", client->name); oldframe = NULL; lastframe = 0; } else { // we have a valid snapshot to delta from oldframe = &client->frames[ client->deltaMessage & PACKET_MASK ]; lastframe = client->netchan.outgoingSequence - client->deltaMessage; // the snapshot's entities may still have rolled off the buffer, though if ( oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities ) { Com_DPrintf ("%s: Delta request from out of date entities.\n", client->name); oldframe = NULL; lastframe = 0; } } MSG_WriteByte (msg, svc_snapshot); // let the client know which reliable clientCommands we have received MSG_WriteLong( msg, client->lastClientCommand ); // send over the current server time so the client can drift // its view of time to try to match MSG_WriteLong (msg, sv.time); // we must write a message number, because recorded demos won't have // the same network message sequences MSG_WriteLong (msg, client->netchan.outgoingSequence ); MSG_WriteByte (msg, lastframe); // what we are delta'ing from MSG_WriteLong (msg, client->cmdNum); // we have executed up to here snapFlags = client->rateDelayed | ( client->droppedCommands << 1 ); client->droppedCommands = 0; MSG_WriteByte (msg, snapFlags); // send over the areabits MSG_WriteByte (msg, frame->areabytes); MSG_WriteData (msg, frame->areabits, frame->areabytes); // delta encode the playerstate if ( oldframe ) { MSG_WriteDeltaPlayerstate( msg, &oldframe->ps, &frame->ps ); } else { MSG_WriteDeltaPlayerstate( msg, NULL, &frame->ps ); } // delta encode the entities SV_EmitPacketEntities (oldframe, frame, msg); }
/* ================== SV_WriteSnapshotToClient ================== */ static void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) { clientSnapshot_t *frame, *oldframe; int lastframe; int i; int snapFlags; // this is the snapshot we are creating frame = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ]; // try to use a previous frame as the source for delta compressing the snapshot if ( client->deltaMessage <= 0 || client->state != CS_ACTIVE ) { // client is asking for a retransmit oldframe = NULL; lastframe = 0; } else if ( client->netchan.outgoingSequence - client->deltaMessage >= (PACKET_BACKUP - 3) ) { // client hasn't gotten a good message through in a long time Com_DPrintf ("%s: Delta request from out of date packet.\n", client->name); oldframe = NULL; lastframe = 0; } else { // we have a valid snapshot to delta from oldframe = &client->frames[ client->deltaMessage & PACKET_MASK ]; lastframe = client->netchan.outgoingSequence - client->deltaMessage; // the snapshot's entities may still have rolled off the buffer, though if ( oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities ) { Com_DPrintf ("%s: Delta request from out of date entities.\n", client->name); oldframe = NULL; lastframe = 0; } } MSG_WriteByte (msg, svc_snapshot); // NOTE, MRE: now sent at the start of every message from server to client // let the client know which reliable clientCommands we have received //MSG_WriteLong( msg, client->lastClientCommand ); // send over the current server time so the client can drift // its view of time to try to match MSG_WriteLong (msg, svs.time); // what we are delta'ing from MSG_WriteByte (msg, lastframe); snapFlags = svs.snapFlagServerBit; if ( client->rateDelayed ) { snapFlags |= SNAPFLAG_RATE_DELAYED; } if ( client->state != CS_ACTIVE ) { snapFlags |= SNAPFLAG_NOT_ACTIVE; } MSG_WriteByte (msg, snapFlags); // send over the areabits MSG_WriteByte (msg, frame->areabytes); MSG_WriteData (msg, frame->areabits, frame->areabytes); // delta encode the playerstate if ( oldframe ) { #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate( msg, &oldframe->ps, &frame->ps, frame->pDeltaOneBit, frame->pDeltaNumBit ); #else MSG_WriteDeltaPlayerstate( msg, &oldframe->ps, &frame->ps ); #endif if (frame->ps.m_iVehicleNum) { //then write the vehicle's playerstate too if (!oldframe->ps.m_iVehicleNum) { //if last frame didn't have vehicle, then the old vps isn't gonna delta //properly (because our vps on the client could be anything) #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate( msg, NULL, &frame->vps, NULL, NULL, qtrue ); #else MSG_WriteDeltaPlayerstate( msg, NULL, &frame->vps, qtrue ); #endif } else { #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate( msg, &oldframe->vps, &frame->vps, frame->pDeltaOneBitVeh, frame->pDeltaNumBitVeh, qtrue ); #else MSG_WriteDeltaPlayerstate( msg, &oldframe->vps, &frame->vps, qtrue ); #endif } } } else { #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate( msg, NULL, &frame->ps, NULL, NULL ); #else MSG_WriteDeltaPlayerstate( msg, NULL, &frame->ps ); #endif if (frame->ps.m_iVehicleNum) { //then write the vehicle's playerstate too #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate( msg, NULL, &frame->vps, NULL, NULL, qtrue ); #else MSG_WriteDeltaPlayerstate( msg, NULL, &frame->vps, qtrue ); #endif } } // delta encode the entities SV_EmitPacketEntities (oldframe, frame, msg); // padding for rate debugging if ( sv_padPackets->integer ) { for ( i = 0 ; i < sv_padPackets->integer ; i++ ) { MSG_WriteByte (msg, svc_nop); } } }
/* ================== SV_WriteSnapshotToClient ================== */ static void SV_WriteSnapshotToClient( client_t *client, msg_t *msg ) { clientSnapshot_t *frame, *oldframe; int lastframe; int i; int snapFlags; int deltaMessage; // this is the snapshot we are creating frame = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ]; // bots never acknowledge, but it doesn't matter since the only use case is for serverside demos // in which case we can delta against the very last message every time deltaMessage = client->deltaMessage; if ( client->demo.isBot ) { client->deltaMessage = client->netchan.outgoingSequence; } // try to use a previous frame as the source for delta compressing the snapshot if ( deltaMessage <= 0 || client->state != CS_ACTIVE ) { // client is asking for a retransmit oldframe = NULL; lastframe = 0; } else if ( client->netchan.outgoingSequence - deltaMessage >= (PACKET_BACKUP - 3) ) { // client hasn't gotten a good message through in a long time Com_DPrintf ("%s: Delta request from out of date packet.\n", client->name); oldframe = NULL; lastframe = 0; } else if ( client->demo.demorecording && client->demo.demowaiting ) { // demo is waiting for a non-delta-compressed frame for this client, so don't delta compress oldframe = NULL; lastframe = 0; } else if ( client->demo.minDeltaFrame > deltaMessage ) { // we saved a non-delta frame to the demo and sent it to the client, but the client didn't ack it // we can't delta against an old frame that's not in the demo without breaking the demo. so send // non-delta frames until the client acks. oldframe = NULL; lastframe = 0; } else { // we have a valid snapshot to delta from oldframe = &client->frames[ deltaMessage & PACKET_MASK ]; lastframe = client->netchan.outgoingSequence - deltaMessage; // the snapshot's entities may still have rolled off the buffer, though if ( oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities ) { Com_DPrintf ("%s: Delta request from out of date entities.\n", client->name); oldframe = NULL; lastframe = 0; } } if ( oldframe == NULL ) { if ( client->demo.demowaiting ) { // this is a non-delta frame, so we can delta against it in the demo client->demo.minDeltaFrame = client->netchan.outgoingSequence; } client->demo.demowaiting = qfalse; } MSG_WriteByte (msg, svc_snapshot); // NOTE, MRE: now sent at the start of every message from server to client // let the client know which reliable clientCommands we have received //MSG_WriteLong( msg, client->lastClientCommand ); // send over the current server time so the client can drift // its view of time to try to match if( client->oldServerTime && !( client->demo.demorecording && client->demo.isBot ) ) { // The server has not yet got an acknowledgement of the // new gamestate from this client, so continue to send it // a time as if the server has not restarted. Note from // the client's perspective this time is strictly speaking // incorrect, but since it'll be busy loading a map at // the time it doesn't really matter. MSG_WriteLong (msg, sv.time + client->oldServerTime); } else { MSG_WriteLong (msg, sv.time); } // what we are delta'ing from MSG_WriteByte (msg, lastframe); snapFlags = svs.snapFlagServerBit; if ( client->rateDelayed ) { snapFlags |= SNAPFLAG_RATE_DELAYED; } if ( client->state != CS_ACTIVE ) { snapFlags |= SNAPFLAG_NOT_ACTIVE; } MSG_WriteByte (msg, snapFlags); // send over the areabits MSG_WriteByte (msg, frame->areabytes); MSG_WriteData (msg, frame->areabits, frame->areabytes); // delta encode the playerstate if ( oldframe ) { #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate( msg, &oldframe->ps, &frame->ps, frame->pDeltaOneBit, frame->pDeltaNumBit ); #else MSG_WriteDeltaPlayerstate( msg, &oldframe->ps, &frame->ps ); #endif if (frame->ps.m_iVehicleNum) { //then write the vehicle's playerstate too if (!oldframe->ps.m_iVehicleNum) { //if last frame didn't have vehicle, then the old vps isn't gonna delta //properly (because our vps on the client could be anything) #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate( msg, NULL, &frame->vps, NULL, NULL, qtrue ); #else MSG_WriteDeltaPlayerstate( msg, NULL, &frame->vps, qtrue ); #endif } else { #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate( msg, &oldframe->vps, &frame->vps, frame->pDeltaOneBitVeh, frame->pDeltaNumBitVeh, qtrue ); #else MSG_WriteDeltaPlayerstate( msg, &oldframe->vps, &frame->vps, qtrue ); #endif } } } else { #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate( msg, NULL, &frame->ps, NULL, NULL ); #else MSG_WriteDeltaPlayerstate( msg, NULL, &frame->ps ); #endif if (frame->ps.m_iVehicleNum) { //then write the vehicle's playerstate too #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate( msg, NULL, &frame->vps, NULL, NULL, qtrue ); #else MSG_WriteDeltaPlayerstate( msg, NULL, &frame->vps, qtrue ); #endif } } // delta encode the entities SV_EmitPacketEntities (oldframe, frame, msg); // padding for rate debugging if ( sv_padPackets->integer ) { for ( i = 0 ; i < sv_padPackets->integer ; i++ ) { MSG_WriteByte (msg, svc_nop); } } }
/* ================== SV_WriteSnapshotToClient ================== */ static void SV_WriteSnapshotToClient(client_t *client, msg_t *msg) { clientSnapshot_t *frame, *oldframe; int lastframe; int snapFlags; // this is the snapshot we are creating frame = &client->frames[client->netchan.outgoingSequence & PACKET_MASK]; // try to use a previous frame as the source for delta compressing the snapshot if (client->deltaMessage <= 0 || client->state != CS_ACTIVE) { // client is asking for a retransmit oldframe = NULL; lastframe = 0; } else if (client->netchan.outgoingSequence - client->deltaMessage >= (PACKET_BACKUP - 3)) { // client hasn't gotten a good message through in a long time Com_DPrintf("%s: Delta request from out of date packet.\n", client->name); oldframe = NULL; lastframe = 0; } else { // we have a valid snapshot to delta from oldframe = &client->frames[client->deltaMessage & PACKET_MASK]; lastframe = client->netchan.outgoingSequence - client->deltaMessage; // the snapshot's entities may still have rolled off the buffer, though if (oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities) { Com_DPrintf("%s: Delta request from out of date entities.\n", client->name); oldframe = NULL; lastframe = 0; } } MSG_WriteByte(msg, svc_snapshot); // NOTE, MRE: now sent at the start of every message from server to client // let the client know which reliable clientCommands we have received //MSG_WriteLong( msg, client->lastClientCommand ); // send over the current server time so the client can drift // its view of time to try to match MSG_WriteLong(msg, svs.time); // what we are delta'ing from MSG_WriteByte(msg, lastframe); snapFlags = svs.snapFlagServerBit; if (client->rateDelayed) { snapFlags |= SNAPFLAG_RATE_DELAYED; } if (client->state != CS_ACTIVE) { snapFlags |= SNAPFLAG_NOT_ACTIVE; } MSG_WriteByte(msg, snapFlags); // send over the areabits MSG_WriteByte(msg, frame->areabytes); MSG_WriteData(msg, frame->areabits, frame->areabytes); //{ //int sz = msg->cursize; //int usz = msg->uncompsize; // delta encode the playerstate if (oldframe) { MSG_WriteDeltaPlayerstate(msg, &oldframe->ps, &frame->ps); } else { MSG_WriteDeltaPlayerstate(msg, NULL, &frame->ps); } //Com_Printf( "Playerstate delta size: %f\n", ((msg->cursize - sz) * sv_fps->integer) / 8.f ); //} // delta encode the entities SV_EmitPacketEntities(oldframe, frame, msg); // padding for rate debugging if (sv_padPackets->integer) { int i; for (i = 0 ; i < sv_padPackets->integer ; i++) { MSG_WriteByte(msg, svc_nop); } } }
void demoCutWriteDeltaSnapshot(int firstServerCommand, fileHandle_t f, qboolean forceNonDelta, clientConnection_t *clcCut, clientActive_t *clCut) { msg_t msgImpl, *msg = &msgImpl; byte msgData[MAX_MSGLEN]; clSnapshot_t *frame, *oldframe; int lastframe = 0; int snapFlags; MSG_Init(msg, msgData, sizeof(msgData)); MSG_Bitstream(msg); MSG_WriteLong(msg, clcCut->reliableSequence); // copy over any commands for (int serverCommand = firstServerCommand; serverCommand <= clcCut->serverCommandSequence; serverCommand++) { char *command = clcCut->serverCommands[serverCommand & (MAX_RELIABLE_COMMANDS - 1)]; MSG_WriteByte(msg, svc_serverCommand); MSG_WriteLong(msg, serverCommand/* + serverCommandOffset*/); MSG_WriteString(msg, command); } // this is the snapshot we are creating frame = &clCut->snap; if (clCut->snap.messageNum > 0 && !forceNonDelta) { lastframe = 1; oldframe = &clCut->snapshots[(clCut->snap.messageNum - 1) & PACKET_MASK]; // 1 frame previous if (!oldframe->valid) { // not yet set lastframe = 0; oldframe = NULL; } } else { lastframe = 0; oldframe = NULL; } MSG_WriteByte(msg, svc_snapshot); // send over the current server time so the client can drift // its view of time to try to match MSG_WriteLong(msg, frame->serverTime); // what we are delta'ing from MSG_WriteByte(msg, lastframe); snapFlags = frame->snapFlags; MSG_WriteByte(msg, snapFlags); // send over the areabits MSG_WriteByte(msg, sizeof(frame->areamask)); MSG_WriteData(msg, frame->areamask, sizeof(frame->areamask)); // delta encode the playerstate if (oldframe) { #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate(msg, &oldframe->ps, &frame->ps, frame->pDeltaOneBit, frame->pDeltaNumBit); #else MSG_WriteDeltaPlayerstate(msg, &oldframe->ps, &frame->ps); #endif if (frame->ps.m_iVehicleNum) { //then write the vehicle's playerstate too if (!oldframe->ps.m_iVehicleNum) { //if last frame didn't have vehicle, then the old vps isn't gonna delta //properly (because our vps on the client could be anything) #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate(msg, NULL, &frame->vps, NULL, NULL, qtrue); #else MSG_WriteDeltaPlayerstate(msg, NULL, &frame->vps, qtrue); #endif } else { #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate(msg, &oldframe->vps, &frame->vps, frame->pDeltaOneBitVeh, frame->pDeltaNumBitVeh, qtrue); #else MSG_WriteDeltaPlayerstate(msg, &oldframe->vps, &frame->vps, qtrue); #endif } } } else { #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate(msg, NULL, &frame->ps, NULL, NULL); #else MSG_WriteDeltaPlayerstate(msg, NULL, &frame->ps); #endif if (frame->ps.m_iVehicleNum) { //then write the vehicle's playerstate too #ifdef _ONEBIT_COMBO MSG_WriteDeltaPlayerstate(msg, NULL, &frame->vps, NULL, NULL, qtrue); #else MSG_WriteDeltaPlayerstate(msg, NULL, &frame->vps, qtrue); #endif } } // delta encode the entities demoCutEmitPacketEntities(oldframe, frame, msg, clCut); MSG_WriteByte(msg, svc_EOF); demoCutWriteDemoMessage(msg, f, clcCut); }