Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

sv_snapshot.c File Reference

#include "server.h"

Include dependency graph for sv_snapshot.c:

Include dependency graph

Go to the source code of this file.

Data Structures

struct  snapshotEntityNumbers_t

Defines

#define HEADER_RATE_BYTES   48
#define MAX_SNAPSHOT_ENTITIES   1024

Functions

void SV_AddEntitiesVisibleFromPoint (vec3_t origin, clientSnapshot_t *frame, snapshotEntityNumbers_t *eNums, qboolean portal)
void SV_AddEntToSnapshot (svEntity_t *svEnt, sharedEntity_t *gEnt, snapshotEntityNumbers_t *eNums)
void SV_BuildClientSnapshot (client_t *client)
void SV_EmitPacketEntities (clientSnapshot_t *from, clientSnapshot_t *to, msg_t *msg)
int QDECL SV_QsortEntityNumbers (const void *a, const void *b)
int SV_RateMsec (client_t *client, int messageSize)
void SV_SendClientMessages (void)
void SV_SendClientSnapshot (client_t *client)
void SV_SendMessageToClient (msg_t *msg, client_t *client)
void SV_UpdateServerCommandsToClient (client_t *client, msg_t *msg)
void SV_WriteSnapshotToClient (client_t *client, msg_t *msg)


Define Documentation

#define HEADER_RATE_BYTES   48
 

Definition at line 526 of file sv_snapshot.c.

#define MAX_SNAPSHOT_ENTITIES   1024
 

Definition at line 228 of file sv_snapshot.c.


Function Documentation

void SV_AddEntitiesVisibleFromPoint vec3_t  origin,
clientSnapshot_t frame,
snapshotEntityNumbers_t eNums,
qboolean  portal
[static]
 

Definition at line 283 of file sv_snapshot.c.

References clientSnapshot_t::areabits, clientSnapshot_t::areabytes, svEntity_s::areanum, svEntity_s::areanum2, byte, playerState_s::clientNum, svEntity_s::clusternums, CM_AreasConnected(), CM_ClusterPVS(), CM_LeafArea(), CM_LeafCluster(), CM_PointLeafnum(), CM_WriteAreaBits(), Com_DPrintf(), Com_Error(), e, ERR_DROP, entityState_s::generic1, i, l, svEntity_s::lastCluster, entityShared_t::linked, server_t::num_entities, entityState_s::number, svEntity_s::numClusters, entityState_s::origin, entityState_s::origin2, clientSnapshot_t::ps, qtrue, sharedEntity_t::r, sharedEntity_t::s, entityShared_t::singleClient, server_t::snapshotCounter, svEntity_s::snapshotCounter, server_t::state, sv, SV_AddEntToSnapshot(), SV_GentityNum(), SV_SvEntityForGentity(), svEntity_t, entityShared_t::svFlags, vec3_t, VectorLengthSquared(), and VectorSubtract.

Referenced by SV_BuildClientSnapshot().

00284                                                                                       {
00285     int     e, i;
00286     sharedEntity_t *ent;
00287     svEntity_t  *svEnt;
00288     int     l;
00289     int     clientarea, clientcluster;
00290     int     leafnum;
00291     int     c_fullsend;
00292     byte    *clientpvs;
00293     byte    *bitvector;
00294 
00295     // during an error shutdown message we may need to transmit
00296     // the shutdown message after the server has shutdown, so
00297     // specfically check for it
00298     if ( !sv.state ) {
00299         return;
00300     }
00301 
00302     leafnum = CM_PointLeafnum (origin);
00303     clientarea = CM_LeafArea (leafnum);
00304     clientcluster = CM_LeafCluster (leafnum);
00305 
00306     // calculate the visible areas
00307     frame->areabytes = CM_WriteAreaBits( frame->areabits, clientarea );
00308 
00309     clientpvs = CM_ClusterPVS (clientcluster);
00310 
00311     c_fullsend = 0;
00312 
00313     for ( e = 0 ; e < sv.num_entities ; e++ ) {
00314         ent = SV_GentityNum(e);
00315 
00316         // never send entities that aren't linked in
00317         if ( !ent->r.linked ) {
00318             continue;
00319         }
00320 
00321         if (ent->s.number != e) {
00322             Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n");
00323             ent->s.number = e;
00324         }
00325 
00326         // entities can be flagged to explicitly not be sent to the client
00327         if ( ent->r.svFlags & SVF_NOCLIENT ) {
00328             continue;
00329         }
00330 
00331         // entities can be flagged to be sent to only one client
00332         if ( ent->r.svFlags & SVF_SINGLECLIENT ) {
00333             if ( ent->r.singleClient != frame->ps.clientNum ) {
00334                 continue;
00335             }
00336         }
00337         // entities can be flagged to be sent to everyone but one client
00338         if ( ent->r.svFlags & SVF_NOTSINGLECLIENT ) {
00339             if ( ent->r.singleClient == frame->ps.clientNum ) {
00340                 continue;
00341             }
00342         }
00343         // entities can be flagged to be sent to a given mask of clients
00344         if ( ent->r.svFlags & SVF_CLIENTMASK ) {
00345             if (frame->ps.clientNum >= 32)
00346                 Com_Error( ERR_DROP, "SVF_CLIENTMASK: cientNum > 32\n" );
00347             if (~ent->r.singleClient & (1 << frame->ps.clientNum))
00348                 continue;
00349         }
00350 
00351         svEnt = SV_SvEntityForGentity( ent );
00352 
00353         // don't double add an entity through portals
00354         if ( svEnt->snapshotCounter == sv.snapshotCounter ) {
00355             continue;
00356         }
00357 
00358         // broadcast entities are always sent
00359         if ( ent->r.svFlags & SVF_BROADCAST ) {
00360             SV_AddEntToSnapshot( svEnt, ent, eNums );
00361             continue;
00362         }
00363 
00364         // ignore if not touching a PV leaf
00365         // check area
00366         if ( !CM_AreasConnected( clientarea, svEnt->areanum ) ) {
00367             // doors can legally straddle two areas, so
00368             // we may need to check another one
00369             if ( !CM_AreasConnected( clientarea, svEnt->areanum2 ) ) {
00370                 continue;       // blocked by a door
00371             }
00372         }
00373 
00374         bitvector = clientpvs;
00375 
00376         // check individual leafs
00377         if ( !svEnt->numClusters ) {
00378             continue;
00379         }
00380         l = 0;
00381         for ( i=0 ; i < svEnt->numClusters ; i++ ) {
00382             l = svEnt->clusternums[i];
00383             if ( bitvector[l >> 3] & (1 << (l&7) ) ) {
00384                 break;
00385             }
00386         }
00387 
00388         // if we haven't found it to be visible,
00389         // check overflow clusters that coudln't be stored
00390         if ( i == svEnt->numClusters ) {
00391             if ( svEnt->lastCluster ) {
00392                 for ( ; l <= svEnt->lastCluster ; l++ ) {
00393                     if ( bitvector[l >> 3] & (1 << (l&7) ) ) {
00394                         break;
00395                     }
00396                 }
00397                 if ( l == svEnt->lastCluster ) {
00398                     continue;   // not visible
00399                 }
00400             } else {
00401                 continue;
00402             }
00403         }
00404 
00405         // add it
00406         SV_AddEntToSnapshot( svEnt, ent, eNums );
00407 
00408         // if its a portal entity, add everything visible from its camera position
00409         if ( ent->r.svFlags & SVF_PORTAL ) {
00410             if ( ent->s.generic1 ) {
00411                 vec3_t dir;
00412                 VectorSubtract(ent->s.origin, origin, dir);
00413                 if ( VectorLengthSquared(dir) > (float) ent->s.generic1 * ent->s.generic1 ) {
00414                     continue;
00415                 }
00416             }
00417             SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue );
00418         }
00419 
00420     }
00421 }

Here is the call graph for this function:

void SV_AddEntToSnapshot svEntity_t svEnt,
sharedEntity_t gEnt,
snapshotEntityNumbers_t eNums
[static]
 

Definition at line 262 of file sv_snapshot.c.

References entityState_s::number, snapshotEntityNumbers_t::numSnapshotEntities, sharedEntity_t::s, server_t::snapshotCounter, svEntity_s::snapshotCounter, snapshotEntityNumbers_t::snapshotEntities, sv, and svEntity_t.

Referenced by SV_AddEntitiesVisibleFromPoint().

00262                                                                                                            {
00263     // if we have already added this entity to this snapshot, don't add again
00264     if ( svEnt->snapshotCounter == sv.snapshotCounter ) {
00265         return;
00266     }
00267     svEnt->snapshotCounter = sv.snapshotCounter;
00268 
00269     // if we are full, silently discard entities
00270     if ( eNums->numSnapshotEntities == MAX_SNAPSHOT_ENTITIES ) {
00271         return;
00272     }
00273 
00274     eNums->snapshotEntities[ eNums->numSnapshotEntities ] = gEnt->s.number;
00275     eNums->numSnapshotEntities++;
00276 }

void SV_BuildClientSnapshot client_t client  )  [static]
 

Definition at line 436 of file sv_snapshot.c.

References clientSnapshot_t::areabits, client_t, playerState_s::clientNum, serverStatic_t::clients, Com_Error(), Com_Memset(), entityState_t, ERR_DROP, ERR_FATAL, clientSnapshot_t::first_entity, client_s::frames, client_s::gentity, i, MAX_MAP_AREA_BYTES, client_s::netchan, serverStatic_t::nextSnapshotEntities, clientSnapshot_t::num_entities, serverStatic_t::numSnapshotEntities, snapshotEntityNumbers_t::numSnapshotEntities, playerState_s::origin, netchan_t::outgoingSequence, playerState_t, clientSnapshot_t::ps, qfalse, qsort(), sharedEntity_t::s, svEntity_s::snapshotCounter, server_t::snapshotCounter, serverStatic_t::snapshotEntities, snapshotEntityNumbers_t::snapshotEntities, state, client_s::state, sv, SV_AddEntitiesVisibleFromPoint(), SV_GameClientNum(), SV_GentityNum(), SV_QsortEntityNumbers(), server_t::svEntities, svEntity_t, svs, vec3_t, VectorCopy, and playerState_s::viewheight.

Referenced by SV_SendClientSnapshot().

00436                                                        {
00437     vec3_t                      org;
00438     clientSnapshot_t            *frame;
00439     snapshotEntityNumbers_t     entityNumbers;
00440     int                         i;
00441     sharedEntity_t              *ent;
00442     entityState_t               *state;
00443     svEntity_t                  *svEnt;
00444     sharedEntity_t              *clent;
00445     int                         clientNum;
00446     playerState_t               *ps;
00447 
00448     // bump the counter used to prevent double adding
00449     sv.snapshotCounter++;
00450 
00451     // this is the frame we are creating
00452     frame = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ];
00453 
00454     // clear everything in this snapshot
00455     entityNumbers.numSnapshotEntities = 0;
00456     Com_Memset( frame->areabits, 0, sizeof( frame->areabits ) );
00457 
00458   // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=62
00459     frame->num_entities = 0;
00460     
00461     clent = client->gentity;
00462     if ( !clent || client->state == CS_ZOMBIE ) {
00463         return;
00464     }
00465 
00466     // grab the current playerState_t
00467     ps = SV_GameClientNum( client - svs.clients );
00468     frame->ps = *ps;
00469 
00470     // never send client's own entity, because it can
00471     // be regenerated from the playerstate
00472     clientNum = frame->ps.clientNum;
00473     if ( clientNum < 0 || clientNum >= MAX_GENTITIES ) {
00474         Com_Error( ERR_DROP, "SV_SvEntityForGentity: bad gEnt" );
00475     }
00476     svEnt = &sv.svEntities[ clientNum ];
00477 
00478     svEnt->snapshotCounter = sv.snapshotCounter;
00479 
00480     // find the client's viewpoint
00481     VectorCopy( ps->origin, org );
00482     org[2] += ps->viewheight;
00483 
00484     // add all the entities directly visible to the eye, which
00485     // may include portal entities that merge other viewpoints
00486     SV_AddEntitiesVisibleFromPoint( org, frame, &entityNumbers, qfalse );
00487 
00488     // if there were portals visible, there may be out of order entities
00489     // in the list which will need to be resorted for the delta compression
00490     // to work correctly.  This also catches the error condition
00491     // of an entity being included twice.
00492     qsort( entityNumbers.snapshotEntities, entityNumbers.numSnapshotEntities, 
00493         sizeof( entityNumbers.snapshotEntities[0] ), SV_QsortEntityNumbers );
00494 
00495     // now that all viewpoint's areabits have been OR'd together, invert
00496     // all of them to make it a mask vector, which is what the renderer wants
00497     for ( i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++ ) {
00498         ((int *)frame->areabits)[i] = ((int *)frame->areabits)[i] ^ -1;
00499     }
00500 
00501     // copy the entity states out
00502     frame->num_entities = 0;
00503     frame->first_entity = svs.nextSnapshotEntities;
00504     for ( i = 0 ; i < entityNumbers.numSnapshotEntities ; i++ ) {
00505         ent = SV_GentityNum(entityNumbers.snapshotEntities[i]);
00506         state = &svs.snapshotEntities[svs.nextSnapshotEntities % svs.numSnapshotEntities];
00507         *state = ent->s;
00508         svs.nextSnapshotEntities++;
00509         // this should never hit, map should always be restarted first in SV_Frame
00510         if ( svs.nextSnapshotEntities >= 0x7FFFFFFE ) {
00511             Com_Error(ERR_FATAL, "svs.nextSnapshotEntities wrapped");
00512         }
00513         frame->num_entities++;
00514     }
00515 }

Here is the call graph for this function:

void SV_EmitPacketEntities clientSnapshot_t from,
clientSnapshot_t to,
msg_t msg
[static]
 

Definition at line 55 of file sv_snapshot.c.

References svEntity_s::baseline, entityState_t, clientSnapshot_t::first_entity, GENTITYNUM_BITS, MAX_GENTITIES, MSG_WriteBits(), MSG_WriteDeltaEntity(), NULL, clientSnapshot_t::num_entities, entityState_s::number, serverStatic_t::numSnapshotEntities, qfalse, qtrue, serverStatic_t::snapshotEntities, sv, server_t::svEntities, and svs.

Referenced by SV_WriteSnapshotToClient().

00055                                                                                               {
00056     entityState_t   *oldent, *newent;
00057     int     oldindex, newindex;
00058     int     oldnum, newnum;
00059     int     from_num_entities;
00060 
00061     // generate the delta update
00062     if ( !from ) {
00063         from_num_entities = 0;
00064     } else {
00065         from_num_entities = from->num_entities;
00066     }
00067 
00068     newent = NULL;
00069     oldent = NULL;
00070     newindex = 0;
00071     oldindex = 0;
00072     while ( newindex < to->num_entities || oldindex < from_num_entities ) {
00073         if ( newindex >= to->num_entities ) {
00074             newnum = 9999;
00075         } else {
00076             newent = &svs.snapshotEntities[(to->first_entity+newindex) % svs.numSnapshotEntities];
00077             newnum = newent->number;
00078         }
00079 
00080         if ( oldindex >= from_num_entities ) {
00081             oldnum = 9999;
00082         } else {
00083             oldent = &svs.snapshotEntities[(from->first_entity+oldindex) % svs.numSnapshotEntities];
00084             oldnum = oldent->number;
00085         }
00086 
00087         if ( newnum == oldnum ) {
00088             // delta update from old position
00089             // because the force parm is qfalse, this will not result
00090             // in any bytes being emited if the entity has not changed at all
00091             MSG_WriteDeltaEntity (msg, oldent, newent, qfalse );
00092             oldindex++;
00093             newindex++;
00094             continue;
00095         }
00096 
00097         if ( newnum < oldnum ) {
00098             // this is a new entity, send it from the baseline
00099             MSG_WriteDeltaEntity (msg, &sv.svEntities[newnum].baseline, newent, qtrue );
00100             newindex++;
00101             continue;
00102         }
00103 
00104         if ( newnum > oldnum ) {
00105             // the old entity isn't present in the new message
00106             MSG_WriteDeltaEntity (msg, oldent, NULL, qtrue );
00107             oldindex++;
00108             continue;
00109         }
00110     }
00111 
00112     MSG_WriteBits( msg, (MAX_GENTITIES-1), GENTITYNUM_BITS );   // end of packetentities
00113 }

Here is the call graph for this function:

int QDECL SV_QsortEntityNumbers const void *  a,
const void *  b
[static]
 

Definition at line 239 of file sv_snapshot.c.

References Com_Error(), ERR_DROP, and QDECL.

Referenced by SV_BuildClientSnapshot().

00239                                                                        {
00240     int *ea, *eb;
00241 
00242     ea = (int *)a;
00243     eb = (int *)b;
00244 
00245     if ( *ea == *eb ) {
00246         Com_Error( ERR_DROP, "SV_QsortEntityStates: duplicated entity" );
00247     }
00248 
00249     if ( *ea < *eb ) {
00250         return -1;
00251     }
00252 
00253     return 1;
00254 }

Here is the call graph for this function:

int SV_RateMsec client_t client,
int  messageSize
[static]
 

Definition at line 527 of file sv_snapshot.c.

References client_t, Cvar_Set(), cvar_s::integer, client_s::rate, and sv_maxRate.

Referenced by SV_SendClientMessages(), and SV_SendMessageToClient().

00527                                                             {
00528     int     rate;
00529     int     rateMsec;
00530 
00531     // individual messages will never be larger than fragment size
00532     if ( messageSize > 1500 ) {
00533         messageSize = 1500;
00534     }
00535     rate = client->rate;
00536     if ( sv_maxRate->integer ) {
00537         if ( sv_maxRate->integer < 1000 ) {
00538             Cvar_Set( "sv_MaxRate", "1000" );
00539         }
00540         if ( sv_maxRate->integer < rate ) {
00541             rate = sv_maxRate->integer;
00542         }
00543     }
00544     rateMsec = ( messageSize + HEADER_RATE_BYTES ) * 1000 / rate;
00545 
00546     return rateMsec;
00547 }

Here is the call graph for this function:

void SV_SendClientMessages void   ) 
 

Definition at line 655 of file sv_snapshot.c.

References c, client_t, serverStatic_t::clients, i, cvar_s::integer, client_s::netchan, client_s::nextSnapshotTime, client_s::state, sv_maxclients, SV_Netchan_TransmitNextFragment(), SV_RateMsec(), SV_SendClientSnapshot(), svs, serverStatic_t::time, netchan_t::unsentFragments, netchan_t::unsentFragmentStart, and netchan_t::unsentLength.

Referenced by SV_Frame().

00655                                    {
00656     int         i;
00657     client_t    *c;
00658 
00659     // send a message to each connected client
00660     for (i=0, c = svs.clients ; i < sv_maxclients->integer ; i++, c++) {
00661         if (!c->state) {
00662             continue;       // not connected
00663         }
00664 
00665         if ( svs.time < c->nextSnapshotTime ) {
00666             continue;       // not time yet
00667         }
00668 
00669         // send additional message fragments if the last message
00670         // was too large to send at once
00671         if ( c->netchan.unsentFragments ) {
00672             c->nextSnapshotTime = svs.time + 
00673                 SV_RateMsec( c, c->netchan.unsentLength - c->netchan.unsentFragmentStart );
00674             SV_Netchan_TransmitNextFragment( c );
00675             continue;
00676         }
00677 
00678         // generate and send a new message
00679         SV_SendClientSnapshot( c );
00680     }
00681 }

Here is the call graph for this function:

void SV_SendClientSnapshot client_t client  ) 
 

Definition at line 610 of file sv_snapshot.c.

References msg_t::allowoverflow, byte, client_t, Com_Printf(), client_s::gentity, client_s::lastClientCommand, MSG_Clear(), MSG_Init(), MSG_WriteLong(), client_s::name, msg_t::overflowed, sharedEntity_t::r, SV_BuildClientSnapshot(), SV_SendMessageToClient(), SV_UpdateServerCommandsToClient(), SV_WriteDownloadToClient(), SV_WriteSnapshotToClient(), and entityShared_t::svFlags.

Referenced by SV_FinalMessage(), SV_SendClientMessages(), and SV_VerifyPaks_f().

00610                                                {
00611     byte        msg_buf[MAX_MSGLEN];
00612     msg_t       msg;
00613 
00614     // build the snapshot
00615     SV_BuildClientSnapshot( client );
00616 
00617     // bots need to have their snapshots build, but
00618     // the query them directly without needing to be sent
00619     if ( client->gentity && client->gentity->r.svFlags & SVF_BOT ) {
00620         return;
00621     }
00622 
00623     MSG_Init (&msg, msg_buf, sizeof(msg_buf));
00624     msg.allowoverflow = qtrue;
00625 
00626     // NOTE, MRE: all server->client messages now acknowledge
00627     // let the client know which reliable clientCommands we have received
00628     MSG_WriteLong( &msg, client->lastClientCommand );
00629 
00630     // (re)send any reliable server commands
00631     SV_UpdateServerCommandsToClient( client, &msg );
00632 
00633     // send over all the relevant entityState_t
00634     // and the playerState_t
00635     SV_WriteSnapshotToClient( client, &msg );
00636 
00637     // Add any download data if the client is downloading
00638     SV_WriteDownloadToClient( client, &msg );
00639 
00640     // check for overflow
00641     if ( msg.overflowed ) {
00642         Com_Printf ("WARNING: msg overflowed for %s\n", client->name);
00643         MSG_Clear (&msg);
00644     }
00645 
00646     SV_SendMessageToClient( &msg, client );
00647 }

Here is the call graph for this function:

void SV_SendMessageToClient msg_t msg,
client_t client
 

Definition at line 556 of file sv_snapshot.c.

References client_t, msg_t::cursize, client_s::downloadName, client_s::frames, cvar_s::integer, clientSnapshot_t::messageAcked, clientSnapshot_t::messageSent, clientSnapshot_t::messageSize, NA_LOOPBACK, client_s::netchan, client_s::nextSnapshotTime, netchan_t::outgoingSequence, client_s::rateDelayed, netchan_t::remoteAddress, client_s::snapshotMsec, client_s::state, sv_lanForceRate, SV_Netchan_Transmit(), SV_RateMsec(), svs, Sys_IsLANAddress(), serverStatic_t::time, and netadr_t::type.

Referenced by SV_SendClientGameState(), and SV_SendClientSnapshot().

00556                                                             {
00557     int         rateMsec;
00558 
00559     // record information about the message
00560     client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = msg->cursize;
00561     client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = svs.time;
00562     client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageAcked = -1;
00563 
00564     // send the datagram
00565     SV_Netchan_Transmit( client, msg ); //msg->cursize, msg->data );
00566 
00567     // set nextSnapshotTime based on rate and requested number of updates
00568 
00569     // local clients get snapshots every frame
00570     // TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491
00571     // added sv_lanForceRate check
00572     if ( client->netchan.remoteAddress.type == NA_LOOPBACK || (sv_lanForceRate->integer && Sys_IsLANAddress (client->netchan.remoteAddress)) ) {
00573         client->nextSnapshotTime = svs.time - 1;
00574         return;
00575     }
00576     
00577     // normal rate / snapshotMsec calculation
00578     rateMsec = SV_RateMsec( client, msg->cursize );
00579 
00580     if ( rateMsec < client->snapshotMsec ) {
00581         // never send more packets than this, no matter what the rate is at
00582         rateMsec = client->snapshotMsec;
00583         client->rateDelayed = qfalse;
00584     } else {
00585         client->rateDelayed = qtrue;
00586     }
00587 
00588     client->nextSnapshotTime = svs.time + rateMsec;
00589 
00590     // don't pile up empty snapshots while connecting
00591     if ( client->state != CS_ACTIVE ) {
00592         // a gigantic connection message may have already put the nextSnapshotTime
00593         // more than a second away, so don't shorten it
00594         // do shorten if client is downloading
00595         if ( !*client->downloadName && client->nextSnapshotTime < svs.time + 1000 ) {
00596             client->nextSnapshotTime = svs.time + 1000;
00597         }
00598     }
00599 }

Here is the call graph for this function:

void SV_UpdateServerCommandsToClient client_t client,
msg_t msg
 

Definition at line 208 of file sv_snapshot.c.

References client_t, i, MAX_RELIABLE_COMMANDS, MSG_WriteByte(), MSG_WriteLong(), MSG_WriteString(), client_s::reliableAcknowledge, client_s::reliableCommands, client_s::reliableSent, client_s::reliableSequence, and svc_serverCommand.

Referenced by SV_SendClientGameState(), and SV_SendClientSnapshot().

00208                                                                      {
00209     int     i;
00210 
00211     // write any unacknowledged serverCommands
00212     for ( i = client->reliableAcknowledge + 1 ; i <= client->reliableSequence ; i++ ) {
00213         MSG_WriteByte( msg, svc_serverCommand );
00214         MSG_WriteLong( msg, i );
00215         MSG_WriteString( msg, client->reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
00216     }
00217     client->reliableSent = client->reliableSequence;
00218 }

Here is the call graph for this function:

void SV_WriteSnapshotToClient client_t client,
msg_t msg
[static]
 

Definition at line 122 of file sv_snapshot.c.

References clientSnapshot_t::areabits, clientSnapshot_t::areabytes, client_t, Com_DPrintf(), client_s::deltaMessage, clientSnapshot_t::first_entity, client_s::frames, i, cvar_s::integer, MSG_WriteByte(), MSG_WriteData(), MSG_WriteDeltaPlayerstate(), MSG_WriteLong(), client_s::name, client_s::netchan, serverStatic_t::nextSnapshotEntities, NULL, serverStatic_t::numSnapshotEntities, netchan_t::outgoingSequence, PACKET_BACKUP, clientSnapshot_t::ps, client_s::rateDelayed, serverStatic_t::snapFlagServerBit, client_s::state, SV_EmitPacketEntities(), sv_padPackets, svc_nop, svc_snapshot, svs, and serverStatic_t::time.

Referenced by SV_SendClientSnapshot().

00122                                                                      {
00123     clientSnapshot_t    *frame, *oldframe;
00124     int                 lastframe;
00125     int                 i;
00126     int                 snapFlags;
00127 
00128     // this is the snapshot we are creating
00129     frame = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ];
00130 
00131     // try to use a previous frame as the source for delta compressing the snapshot
00132     if ( client->deltaMessage <= 0 || client->state != CS_ACTIVE ) {
00133         // client is asking for a retransmit
00134         oldframe = NULL;
00135         lastframe = 0;
00136     } else if ( client->netchan.outgoingSequence - client->deltaMessage 
00137         >= (PACKET_BACKUP - 3) ) {
00138         // client hasn't gotten a good message through in a long time
00139         Com_DPrintf ("%s: Delta request from out of date packet.\n", client->name);
00140         oldframe = NULL;
00141         lastframe = 0;
00142     } else {
00143         // we have a valid snapshot to delta from
00144         oldframe = &client->frames[ client->deltaMessage & PACKET_MASK ];
00145         lastframe = client->netchan.outgoingSequence - client->deltaMessage;
00146 
00147         // the snapshot's entities may still have rolled off the buffer, though
00148         if ( oldframe->first_entity <= svs.nextSnapshotEntities - svs.numSnapshotEntities ) {
00149             Com_DPrintf ("%s: Delta request from out of date entities.\n", client->name);
00150             oldframe = NULL;
00151             lastframe = 0;
00152         }
00153     }
00154 
00155     MSG_WriteByte (msg, svc_snapshot);
00156 
00157     // NOTE, MRE: now sent at the start of every message from server to client
00158     // let the client know which reliable clientCommands we have received
00159     //MSG_WriteLong( msg, client->lastClientCommand );
00160 
00161     // send over the current server time so the client can drift
00162     // its view of time to try to match
00163     MSG_WriteLong (msg, svs.time);
00164 
00165     // what we are delta'ing from
00166     MSG_WriteByte (msg, lastframe);
00167 
00168     snapFlags = svs.snapFlagServerBit;
00169     if ( client->rateDelayed ) {
00170         snapFlags |= SNAPFLAG_RATE_DELAYED;
00171     }
00172     if ( client->state != CS_ACTIVE ) {
00173         snapFlags |= SNAPFLAG_NOT_ACTIVE;
00174     }
00175 
00176     MSG_WriteByte (msg, snapFlags);
00177 
00178     // send over the areabits
00179     MSG_WriteByte (msg, frame->areabytes);
00180     MSG_WriteData (msg, frame->areabits, frame->areabytes);
00181 
00182     // delta encode the playerstate
00183     if ( oldframe ) {
00184         MSG_WriteDeltaPlayerstate( msg, &oldframe->ps, &frame->ps );
00185     } else {
00186         MSG_WriteDeltaPlayerstate( msg, NULL, &frame->ps );
00187     }
00188 
00189     // delta encode the entities
00190     SV_EmitPacketEntities (oldframe, frame, msg);
00191 
00192     // padding for rate debugging
00193     if ( sv_padPackets->integer ) {
00194         for ( i = 0 ; i < sv_padPackets->integer ; i++ ) {
00195             MSG_WriteByte (msg, svc_nop);
00196         }
00197     }
00198 }

Here is the call graph for this function:


Generated on Thu Aug 25 15:33:37 2005 for Quake III Arena by  doxygen 1.3.9.1