123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750 |
- // leave this as first line for PCH reasons...
- //
- #include "../server/exe_headers.h"
- #include "..\client\vmachine.h"
- #include "server.h"
- /*
- =============================================================================
- Delta encode a client frame onto the network channel
- A normal server packet will look like:
- 4 sequence number (high bit set if an oversize fragment)
- <optional reliable commands>
- 1 svc_snapshot
- 4 last client reliable command
- 4 serverTime
- 1 lastframe for delta compression
- 1 snapFlags
- 1 areaBytes
- <areabytes>
- <playerstate>
- <packetentities>
- =============================================================================
- */
- /*
- =============
- SV_EmitPacketEntities
- Writes a delta update of an entityState_t list to the message.
- =============
- */
- static void SV_EmitPacketEntities( clientSnapshot_t *from, clientSnapshot_t *to, msg_t *msg ) {
- entityState_t *oldent, *newent;
- int oldindex, newindex;
- int oldnum, newnum;
- int from_num_entities;
- // generate the delta update
- if ( !from ) {
- from_num_entities = 0;
- } else {
- from_num_entities = from->num_entities;
- }
- newent = NULL;
- oldent = NULL;
- newindex = 0;
- oldindex = 0;
- const int num2Send = to->num_entities >= svs.numSnapshotEntities ? svs.numSnapshotEntities : to->num_entities;
- while ( newindex < num2Send || oldindex < from_num_entities ) {
- if ( newindex >= num2Send ) {
- newnum = 9999;
- } else {
- newent = &svs.snapshotEntities[(to->first_entity+newindex) % svs.numSnapshotEntities];
- newnum = newent->number;
- }
- if ( oldindex >= from_num_entities ) {
- oldnum = 9999;
- } else {
- oldent = &svs.snapshotEntities[(from->first_entity+oldindex) % svs.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
- MSG_WriteEntity(msg, newent, 0);
- oldindex++;
- newindex++;
- continue;
- }
- if ( newnum < oldnum ) {
- // this is a new entity, send it from the baseline
- MSG_WriteEntity (msg, newent, 0);
- newindex++;
- continue;
- }
- if ( newnum > oldnum ) {
- // the old entity isn't present in the new message
- if(oldent) {
- MSG_WriteEntity (msg, NULL, oldent->number);
- }
- oldindex++;
- continue;
- }
- }
- MSG_WriteBits( msg, (MAX_GENTITIES-1), GENTITYNUM_BITS ); // end of packetentities
- }
- /*
- ==================
- 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_UpdateServerCommandsToClient
- (re)send all server commands the client hasn't acknowledged yet
- ==================
- */
- static void SV_UpdateServerCommandsToClient( client_t *client, msg_t *msg ) {
- int i;
- // write any unacknowledged serverCommands
- for ( i = client->reliableAcknowledge + 1 ; i <= client->reliableSequence ; i++ ) {
- MSG_WriteByte( msg, svc_serverCommand );
- MSG_WriteLong( msg, i );
- MSG_WriteString( msg, client->reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
- }
- }
- /*
- =============================================================================
- Build a client snapshot structure
- =============================================================================
- */
- #define MAX_SNAPSHOT_ENTITIES 1024
- typedef struct {
- int numSnapshotEntities;
- int snapshotEntities[MAX_SNAPSHOT_ENTITIES];
- } snapshotEntityNumbers_t;
- /*
- =======================
- SV_QsortEntityNumbers
- =======================
- */
- static int SV_QsortEntityNumbers( const void *a, const void *b ) {
- int *ea, *eb;
- ea = (int *)a;
- eb = (int *)b;
- if ( *ea == *eb ) {
- Com_Error( ERR_DROP, "SV_QsortEntityStates: duplicated entity" );
- }
- if ( *ea < *eb ) {
- return -1;
- }
- return 1;
- }
- /*
- ===============
- SV_AddEntToSnapshot
- ===============
- */
- static void SV_AddEntToSnapshot( svEntity_t *svEnt, gentity_t *gEnt, snapshotEntityNumbers_t *eNums ) {
- // if we have already added this entity to this snapshot, don't add again
- if ( svEnt->snapshotCounter == sv.snapshotCounter ) {
- return;
- }
- svEnt->snapshotCounter = sv.snapshotCounter;
- // if we are full, silently discard entities
- if ( eNums->numSnapshotEntities == MAX_SNAPSHOT_ENTITIES ) {
- return;
- }
- if (sv.snapshotCounter &1 && eNums->numSnapshotEntities == svs.numSnapshotEntities-1)
- { //we're full, and about to wrap around and stomp ents, so half the time send the first set without stomping.
- return;
- }
- eNums->snapshotEntities[ eNums->numSnapshotEntities ] = gEnt->s.number;
- eNums->numSnapshotEntities++;
- }
- //rww - bg_public.h won't cooperate in here
- #define EF_PERMANENT 0x00080000
- float sv_sightRangeForLevel[6] =
- {
- 0,//FORCE_LEVEL_0
- 1024.f, //FORCE_LEVEL_1
- 2048.0f,//FORCE_LEVEL_2
- 4096.0f,//FORCE_LEVEL_3
- 4096.0f,//FORCE_LEVEL_4
- 4096.0f//FORCE_LEVEL_5
- };
- qboolean SV_PlayerCanSeeEnt( gentity_t *ent, int sightLevel )
- {//return true if this ent is in view
- //NOTE: this is similar to the func CG_PlayerCanSeeCent in cg_players
- vec3_t viewOrg, viewAngles, viewFwd, dir2Ent;
- if ( !ent )
- {
- return qfalse;
- }
- if ( VM_Call( CG_CAMERA_POS, viewOrg))
- {
- if ( VM_Call( CG_CAMERA_ANG, viewAngles))
- {
- float dot = 0.25f;//1.0f;
- float range = sv_sightRangeForLevel[sightLevel];
- VectorSubtract( ent->currentOrigin, viewOrg, dir2Ent );
- float entDist = VectorNormalize( dir2Ent );
- if ( (ent->s.eFlags&EF_FORCE_VISIBLE) )
- {//no dist check on them?
- }
- else
- {
- if ( entDist < 128.0f )
- {//can always see them if they're really close
- return qtrue;
- }
- if ( entDist > range )
- {//too far away to see them
- return qfalse;
- }
- }
- dot += (0.99f-dot)*entDist/range;//the farther away they are, the more in front they have to be
- AngleVectors( viewAngles, viewFwd, NULL, NULL );
- if ( DotProduct( viewFwd, dir2Ent ) < dot )
- {
- return qfalse;
- }
- return qtrue;
- }
- }
- return qfalse;
- }
- /*
- ===============
- SV_AddEntitiesVisibleFromPoint
- ===============
- */
- static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame,
- snapshotEntityNumbers_t *eNums, qboolean portal ) {
- int e, i;
- gentity_t *ent;
- svEntity_t *svEnt;
- int l;
- int clientarea, clientcluster;
- int leafnum;
- int c_fullsend;
- const byte *clientpvs;
- const byte *bitvector;
- qboolean sightOn = qfalse;
- // during an error shutdown message we may need to transmit
- // the shutdown message after the server has shutdown, so
- // specfically check for it
- if ( !sv.state ) {
- return;
- }
- leafnum = CM_PointLeafnum (origin);
- clientarea = CM_LeafArea (leafnum);
- clientcluster = CM_LeafCluster (leafnum);
- // calculate the visible areas
- frame->areabytes = CM_WriteAreaBits( frame->areabits, clientarea );
- clientpvs = CM_ClusterPVS (clientcluster);
- c_fullsend = 0;
- if ( !portal )
- {//not if this if through a portal...??? James said to do this...
- if ( (frame->ps.forcePowersActive&(1<<FP_SEE)) )
- {
- sightOn = qtrue;
- }
- }
- for ( e = 0 ; e < ge->num_entities ; e++ ) {
- ent = SV_GentityNum(e);
- if (!ent->inuse) {
- continue;
- }
- if (ent->s.eFlags & EF_PERMANENT)
- { // he's permanent, so don't send him down!
- continue;
- }
- if (ent->s.number != e) {
- Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n");
- ent->s.number = e;
- }
- // never send entities that aren't linked in
- if ( !ent->linked ) {
- continue;
- }
- // entities can be flagged to explicitly not be sent to the client
- if ( ent->svFlags & SVF_NOCLIENT ) {
- continue;
- }
- svEnt = SV_SvEntityForGentity( ent );
- // don't double add an entity through portals
- if ( svEnt->snapshotCounter == sv.snapshotCounter ) {
- continue;
- }
- // broadcast entities are always sent, and so is the main player so we don't see noclip weirdness
- if ( ent->svFlags & SVF_BROADCAST || !e) {
- SV_AddEntToSnapshot( svEnt, ent, eNums );
- continue;
- }
- if (ent->s.isPortalEnt)
- { //rww - portal entities are always sent as well
- SV_AddEntToSnapshot( svEnt, ent, eNums );
- continue;
- }
- if ( sightOn )
- {//force sight is on, sees through portals, so draw them always if in radius
- if ( SV_PlayerCanSeeEnt( ent, frame->ps.forcePowerLevel[FP_SEE] ) )
- {//entity is visible
- SV_AddEntToSnapshot( svEnt, ent, eNums );
- continue;
- }
- }
- // ignore if not touching a PV leaf
- // check area
- if ( !CM_AreasConnected( clientarea, svEnt->areanum ) ) {
- // doors can legally straddle two areas, so
- // we may need to check another one
- if ( !CM_AreasConnected( clientarea, svEnt->areanum2 ) ) {
- continue; // blocked by a door
- }
- }
- bitvector = clientpvs;
- // check individual leafs
- if ( !svEnt->numClusters ) {
- continue;
- }
- l = 0;
- #ifdef _XBOX
- if(bitvector) {
- #endif
- for ( i=0 ; i < svEnt->numClusters ; i++ ) {
- l = svEnt->clusternums[i];
- if ( bitvector[l >> 3] & (1 << (l&7) ) ) {
- break;
- }
- }
- #ifdef _XBOX
- }
- #endif
- // if we haven't found it to be visible,
- // check overflow clusters that coudln't be stored
- #ifdef _XBOX
- if ( bitvector && i == svEnt->numClusters ) {
- #else
- if ( i == svEnt->numClusters ) {
- #endif
- if ( svEnt->lastCluster ) {
- for ( ; l <= svEnt->lastCluster ; l++ ) {
- if ( bitvector[l >> 3] & (1 << (l&7) ) ) {
- break;
- }
- }
- if ( l == svEnt->lastCluster ) {
- continue; // not visible
- }
- } else {
- continue;
- }
- }
- // add it
- SV_AddEntToSnapshot( svEnt, ent, eNums );
- // if its a portal entity, add everything visible from its camera position
- if ( ent->svFlags & SVF_PORTAL ) {
- SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue );
- #ifdef _XBOX
- //Must get clientpvs again since above call destroyed it.
- clientpvs = CM_ClusterPVS (clientcluster);
- #endif
- }
- }
- }
- /*
- =============
- SV_BuildClientSnapshot
- Decides which entities are going to be visible to the client, and
- copies off the playerstate and areabits.
- This properly handles multiple recursive portals, but the render
- currently doesn't.
- For viewing through other player's eyes, clent can be something other than client->gentity
- =============
- */
- static clientSnapshot_t *SV_BuildClientSnapshot( client_t *client ) {
- vec3_t org;
- clientSnapshot_t *frame;
- snapshotEntityNumbers_t entityNumbers;
- int i;
- gentity_t *ent;
- entityState_t *state;
- gentity_t *clent;
- // bump the counter used to prevent double adding
- sv.snapshotCounter++;
- // this is the frame we are creating
- frame = &client->frames[ client->netchan.outgoingSequence & PACKET_MASK ];
- // clear everything in this snapshot
- entityNumbers.numSnapshotEntities = 0;
- memset( frame->areabits, 0, sizeof( frame->areabits ) );
- clent = client->gentity;
- if ( !clent ) {
- return frame;
- }
- // grab the current playerState_t
- frame->ps = *clent->client;
- // this stops the main client entity playerstate from being sent across, which has the effect of breaking
- // looping sounds for the main client. So I took it out.
- /* {
- int clientNum;
- svEntity_t *svEnt;
- clientNum = frame->ps.clientNum;
- if ( clientNum < 0 || clientNum >= MAX_GENTITIES ) {
- Com_Error( ERR_DROP, "SV_SvEntityForGentity: bad gEnt" );
- }
- svEnt = &sv.svEntities[ clientNum ];
- // never send client's own entity, because it can
- // be regenerated from the playerstate
- svEnt->snapshotCounter = sv.snapshotCounter;
- }
- */
- // find the client's viewpoint
- //if in camera mode use camera position instead
- if ( VM_Call( CG_CAMERA_POS, org))
- {
- //org[2] += clent->client->viewheight;
- }
- else
- {
- VectorCopy( clent->client->origin, org );
- org[2] += clent->client->viewheight;
- //============
- // need to account for lean, or areaportal doors don't draw properly... -slc
- if (frame->ps.leanofs != 0)
- {
- vec3_t right;
- //add leaning offset
- vec3_t v3ViewAngles;
- VectorCopy(clent->client->viewangles, v3ViewAngles);
- v3ViewAngles[2] += (float)frame->ps.leanofs/2;
- AngleVectors(v3ViewAngles, NULL, right, NULL);
- VectorMA(org, (float)frame->ps.leanofs, right, org);
- }
- //============
- }
- VectorCopy( org, frame->ps.serverViewOrg );
- VectorCopy( org, clent->client->serverViewOrg );
- // add all the entities directly visible to the eye, which
- // may include portal entities that merge other viewpoints
- SV_AddEntitiesVisibleFromPoint( org, frame, &entityNumbers, qfalse );
- /*
- //was in here for debugging- print list of all entities in snapshot when you go over the limit
- if ( entityNumbers.numSnapshotEntities >= 256 )
- {
- for ( int xxx = 0; xxx < entityNumbers.numSnapshotEntities; xxx++ )
- {
- Com_Printf("%d - ", xxx );
- ge->PrintEntClassname( entityNumbers.snapshotEntities[xxx] );
- }
- }
- else if ( entityNumbers.numSnapshotEntities >= 200 )
- {
- Com_Printf(S_COLOR_RED"%d snapshot entities!", entityNumbers.numSnapshotEntities );
- }
- else if ( entityNumbers.numSnapshotEntities >= 128 )
- {
- Com_Printf(S_COLOR_YELLOW"%d snapshot entities", entityNumbers.numSnapshotEntities );
- }
- */
- // if there were portals visible, there may be out of order entities
- // in the list which will need to be resorted for the delta compression
- // to work correctly. This also catches the error condition
- // of an entity being included twice.
- qsort( entityNumbers.snapshotEntities, entityNumbers.numSnapshotEntities,
- sizeof( entityNumbers.snapshotEntities[0] ), SV_QsortEntityNumbers );
- // now that all viewpoint's areabits have been OR'd together, invert
- // all of them to make it a mask vector, which is what the renderer wants
- for ( i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++ ) {
- ((int *)frame->areabits)[i] = ((int *)frame->areabits)[i] ^ -1;
- }
- // copy the entity states out
- frame->num_entities = 0;
- frame->first_entity = svs.nextSnapshotEntities;
- for ( i = 0 ; i < entityNumbers.numSnapshotEntities ; i++ ) {
- ent = SV_GentityNum(entityNumbers.snapshotEntities[i]);
- state = &svs.snapshotEntities[svs.nextSnapshotEntities % svs.numSnapshotEntities];
- *state = ent->s;
- svs.nextSnapshotEntities++;
- frame->num_entities++;
- }
- return frame;
- }
- /*
- =======================
- SV_SendMessageToClient
- Called by SV_SendClientSnapshot and SV_SendClientGameState
- =======================
- */
- #define HEADER_RATE_BYTES 48 // include our header, IP header, and some overhead
- void SV_SendMessageToClient( msg_t *msg, client_t *client ) {
- int rateMsec;
- // record information about the message
- client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = msg->cursize;
- client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = sv.time;
- // send the datagram
- Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
- // set nextSnapshotTime based on rate and requested number of updates
- // local clients get snapshots every frame (FIXME: also treat LAN clients)
- if ( client->netchan.remoteAddress.type == NA_LOOPBACK ) {
- client->nextSnapshotTime = sv.time - 1;
- return;
- }
- // normal rate / snapshotMsec calculation
- rateMsec = ( msg->cursize + HEADER_RATE_BYTES ) * 1000 / client->rate;
- if ( rateMsec < client->snapshotMsec ) {
- rateMsec = client->snapshotMsec;
- client->rateDelayed = qfalse;
- } else {
- client->rateDelayed = qtrue;
- }
- client->nextSnapshotTime = sv.time + rateMsec;
- // if we haven't gotten a message from the client in over a second, we will
- // drop to only sending one snapshot a second until they timeout
- if ( sv.time - client->lastPacketTime > 1000 || client->state != CS_ACTIVE ) {
- if ( client->nextSnapshotTime < sv.time + 1000 ) {
- client->nextSnapshotTime = sv.time + 1000;
- }
- return;
- }
- }
- /*
- =======================
- SV_SendClientEmptyMessage
- This is just an empty message so that we can tell if
- the client dropped the gamestate that went out before
- =======================
- */
- void SV_SendClientEmptyMessage( client_t *client ) {
- msg_t msg;
- byte buffer[10];
- MSG_Init( &msg, buffer, sizeof( buffer ) );
- SV_SendMessageToClient( &msg, client );
- }
- /*
- =======================
- SV_SendClientSnapshot
- =======================
- */
- void SV_SendClientSnapshot( client_t *client ) {
- byte msg_buf[MAX_MSGLEN];
- msg_t msg;
- // 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->svFlags & SVF_BOT ) {
- return;
- }
- MSG_Init (&msg, msg_buf, sizeof(msg_buf));
- msg.allowoverflow = qtrue;
- // (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 );
- // check for overflow
- if ( msg.overflowed ) {
- Com_Printf ("WARNING: msg overflowed for %s\n", client->name);
- MSG_Clear (&msg);
- }
- SV_SendMessageToClient( &msg, client );
- }
- /*
- =======================
- SV_SendClientMessages
- =======================
- */
- void SV_SendClientMessages( void ) {
- int i;
- client_t *c;
- // send a message to each connected client
- for (i=0, c = svs.clients ; i < 1 ; i++, c++) {
- if (!c->state) {
- continue; // not connected
- }
- if ( sv.time < c->nextSnapshotTime ) {
- continue; // not time yet
- }
- if ( c->state != CS_ACTIVE ) {
- if ( c->state != CS_ZOMBIE ) {
- SV_SendClientEmptyMessage( c );
- }
- continue;
- }
- SV_SendClientSnapshot( c );
- }
- }
|