/* =============== SV_AddEntitiesVisibleFromPoint =============== */ static void SV_AddEntitiesVisibleFromPoint(vec3_t origin, clientSnapshot_t *frame, snapshotEntityNumbers_t *eNums) { int e, i; sharedEntity_t *ent; svEntity_t *svEnt; int l; int clientarea, clientcluster; int leafnum; byte *clientpvs; byte *bitvector; // 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); for (e = 0; e < sv.num_entities; e++) { ent = SV_GentityNum(e); // never send entities that aren't linked in if (!ent->r.linked) { continue; } if (ent->s.number != e) { Com_DPrintf("FIXING ENT->S.NUMBER!!!\n"); ent->s.number = e; } // entities can be flagged to explicitly not be sent to the client if (ent->r.svFlags & SVF_NOCLIENT) { continue; } // entities can be flagged to be sent to only one client if (ent->r.svFlags & SVF_SINGLECLIENT) { if (ent->r.singleClient != frame->ps.clientNum) { continue; } } // entities can be flagged to be sent to everyone but one client if (ent->r.svFlags & SVF_NOTSINGLECLIENT) { if (ent->r.singleClient == frame->ps.clientNum) { continue; } } // entities can be flagged to be sent to a given mask of clients if (ent->r.svFlags & SVF_CLIENTMASK) { if (frame->ps.clientNum >= 32) { if (~ent->r.hack.generic1 & (1 << (frame->ps.clientNum - 32))) continue; } else { if (~ent->r.singleClient & (1 << frame->ps.clientNum)) continue; } } svEnt = SV_SvEntityForGentity(ent); // don't double add an entity through portals if (svEnt->snapshotCounter == sv.snapshotCounter) { continue; } // broadcast entities are always sent if (ent->r.svFlags & SVF_BROADCAST) { 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; for (i = 0; i < svEnt->numClusters; i++) { l = svEnt->clusternums[i]; if (bitvector[l >> 3] & (1 << (l & 7))) { break; } } // if we haven't found it to be visible, // check overflow clusters that coudln't be stored if (i == svEnt->numClusters) { 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 it's a portal entity, add everything visible from its camera position if (ent->r.svFlags & SVF_PORTAL) { if (ent->s.generic1) { vec3_t dir; VectorSubtract(ent->r.currentOrigin, origin, dir); if (VectorLengthSquared(dir) > (float)ent->s.generic1 * ent->s.generic1) { continue; } } SV_AddEntitiesVisibleFromPoint(ent->s.origin2, frame, eNums); } }
static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame, snapshotEntityNumbers_t *eNums, qboolean portal ) { int e, i; sharedEntity_t *ent; svEntity_t *svEnt; int l; int clientarea, clientcluster; int leafnum; byte *clientpvs; byte *bitvector; vec3_t difference; float length, radius; // 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); for ( e = 0 ; e < sv.num_entities ; e++ ) { ent = SV_GentityNum(e); // never send entities that aren't linked in if ( !ent->r.linked ) { 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; } // entities can be flagged to explicitly not be sent to the client if ( ent->r.svFlags & SVF_NOCLIENT ) { continue; } // entities can be flagged to be sent to only one client if ( ent->r.svFlags & SVF_SINGLECLIENT ) { if ( ent->r.singleClient != frame->ps.clientNum ) { continue; } } // entities can be flagged to be sent to everyone but one client if ( ent->r.svFlags & SVF_NOTSINGLECLIENT ) { if ( ent->r.singleClient == frame->ps.clientNum ) { 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->r.svFlags & SVF_BROADCAST || (e == frame->ps.clientNum) || (ent->r.broadcastClients[frame->ps.clientNum/32] & (1<<(frame->ps.clientNum%32)))) { 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 (com_RMG && com_RMG->integer) { VectorAdd(ent->r.absmax, ent->r.absmin, difference); VectorScale(difference, 0.5f, difference); VectorSubtract(origin, difference, difference); length = VectorLength(difference); // calculate the diameter VectorSubtract(ent->r.absmax, ent->r.absmin, difference); radius = VectorLength(difference); if (length-radius < /*sv_RMGDistanceCull->integer*/5000.0f) { // more of a diameter check SV_AddEntToSnapshot( svEnt, ent, eNums ); } } else { // 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; for ( i=0 ; i < svEnt->numClusters ; i++ ) { l = svEnt->clusternums[i]; if ( bitvector[l >> 3] & (1 << (l&7) ) ) { break; } } // if we haven't found it to be visible, // check overflow clusters that coudln't be stored if ( i == svEnt->numClusters ) { 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; } } if (g_svCullDist != -1.0f) { //do a distance cull check VectorAdd(ent->r.absmax, ent->r.absmin, difference); VectorScale(difference, 0.5f, difference); VectorSubtract(origin, difference, difference); length = VectorLength(difference); // calculate the diameter VectorSubtract(ent->r.absmax, ent->r.absmin, difference); radius = VectorLength(difference); if (length-radius >= g_svCullDist) { //then don't add it continue; } } // add it SV_AddEntToSnapshot( svEnt, ent, eNums ); // if its a portal entity, add everything visible from its camera position if ( ent->r.svFlags & SVF_PORTAL ) { if ( ent->s.generic1 ) { vec3_t dir; VectorSubtract(ent->s.origin, origin, dir); if ( VectorLengthSquared(dir) > (float) ent->s.generic1 * ent->s.generic1 ) { continue; } } SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue ); } } }
/* =============== SV_AddEntitiesVisibleFromPoint =============== */ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame, // snapshotEntityNumbers_t *eNums, qboolean portal, clientSnapshot_t *oldframe, qboolean localClient ) { // snapshotEntityNumbers_t *eNums, qboolean portal ) { snapshotEntityNumbers_t *eNums /*, qboolean portal, qboolean localClient */ ) { int e, i; sharedEntity_t *ent, *playerEnt; svEntity_t *svEnt; int l; int clientarea, clientcluster; int leafnum; // int c_fullsend; byte *clientpvs; byte *bitvector; // 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; playerEnt = SV_GentityNum( frame->ps.clientNum ); if ( playerEnt->r.svFlags & SVF_SELF_PORTAL ) { SV_AddEntitiesVisibleFromPoint( playerEnt->s.origin2, frame, eNums ); } for ( e = 0; e < sv.num_entities; e++ ) { ent = SV_GentityNum( e ); // never send entities that aren't linked in if ( !ent->r.linked ) { continue; } if ( ent->s.number != e ) { Com_DPrintf( "FIXING ENT->S.NUMBER!!!\n" ); ent->s.number = e; } // entities can be flagged to explicitly not be sent to the client if ( ent->r.svFlags & SVF_NOCLIENT ) { continue; } // entities can be flagged to be sent to only one client if ( ent->r.svFlags & SVF_SINGLECLIENT ) { if ( ent->r.singleClient != frame->ps.clientNum ) { continue; } } // entities can be flagged to be sent to everyone but one client if ( ent->r.svFlags & SVF_NOTSINGLECLIENT ) { if ( ent->r.singleClient == frame->ps.clientNum ) { continue; } } // entities can be flagged to be sent to only a given mask of clients if ( ent->r.svFlags & SVF_CLIENTMASK ) { if ( frame->ps.clientNum >= 32 ) { if ( ~ent->r.hiMask & ( 1 << ( frame->ps.clientNum - 32 ) ) ) { continue; } } else { if ( ~ent->r.loMask & ( 1 << frame->ps.clientNum ) ) { continue; } } } svEnt = SV_SvEntityForGentity( ent ); // don't double add an entity through portals if ( svEnt->snapshotCounter == sv.snapshotCounter ) { continue; } // broadcast entities are always sent if ( ent->r.svFlags & SVF_BROADCAST ) { SV_AddEntToSnapshot( playerEnt, svEnt, ent, eNums ); continue; } // send entity if the client is in range if ( (ent->r.svFlags & SVF_CLIENTS_IN_RANGE) && Distance( ent->s.origin, playerEnt->s.origin ) <= ent->r.clientRadius ) { SV_AddEntToSnapshot( playerEnt, svEnt, ent, eNums ); continue; } bitvector = clientpvs; // Gordon: just check origin for being in pvs, ignore bmodel extents if ( ent->r.svFlags & SVF_IGNOREBMODELEXTENTS ) { if ( bitvector[ ent->r.originCluster >> 3 ] & ( 1 << ( ent->r.originCluster & 7 ) ) ) { SV_AddEntToSnapshot( playerEnt, svEnt, ent, eNums ); } continue; } // ignore if not touching a PV leaf // check area if ( !CM_AreasConnected( clientarea, ent->r.areanum ) ) { // doors can legally straddle two areas, so // we may need to check another one if ( !CM_AreasConnected( clientarea, ent->r.areanum2 ) ) { continue; } } // check individual leafs if ( !ent->r.numClusters ) { continue; } l = 0; for ( i = 0; i < ent->r.numClusters; i++ ) { l = ent->r.clusternums[ i ]; if ( bitvector[ l >> 3 ] & ( 1 << ( l & 7 ) ) ) { break; } } // if we haven't found it to be visible, // check the overflow clusters that couldn't be stored if ( i == ent->r.numClusters ) { if ( ent->r.lastCluster ) { for ( ; l <= ent->r.lastCluster; l++ ) { if ( bitvector[ l >> 3 ] & ( 1 << ( l & 7 ) ) ) { break; } } if ( l == ent->r.lastCluster ) { continue; } } else { continue; } } //----(SA) added "visibility dummies" if ( ent->r.svFlags & SVF_VISDUMMY ) { sharedEntity_t *ment = 0; //find master; ment = SV_GentityNum( ent->s.otherEntityNum ); if ( ment ) { svEntity_t *master = 0; master = SV_SvEntityForGentity( ment ); if ( master->snapshotCounter == sv.snapshotCounter || !ment->r.linked ) { continue; } SV_AddEntToSnapshot( playerEnt, master, ment, eNums ); } continue; // master needs to be added, but not this dummy ent } //----(SA) end else if ( ent->r.svFlags & SVF_VISDUMMY_MULTIPLE ) { { int h; sharedEntity_t *ment = 0; svEntity_t *master = 0; for ( h = 0; h < sv.num_entities; h++ ) { ment = SV_GentityNum( h ); if ( ment == ent ) { continue; } if ( ment ) { master = SV_SvEntityForGentity( ment ); } else { continue; } if ( !( ment->r.linked ) ) { continue; } if ( ment->s.number != h ) { Com_DPrintf( "FIXING vis dummy multiple ment->S.NUMBER!!!\n" ); ment->s.number = h; } if ( ment->r.svFlags & SVF_NOCLIENT ) { continue; } if ( master->snapshotCounter == sv.snapshotCounter ) { continue; } if ( ment->s.otherEntityNum == ent->s.number ) { SV_AddEntToSnapshot( playerEnt, master, ment, eNums ); } } continue; } } // add it SV_AddEntToSnapshot( playerEnt, svEnt, ent, eNums ); // if it's a portal entity, add everything visible from its camera position if ( ent->r.svFlags & SVF_PORTAL ) { if ( ent->s.generic1 ) { vec3_t dir; VectorSubtract( ent->s.origin, origin, dir ); if ( VectorLengthSquared( dir ) > ( float ) ent->s.generic1 * ent->s.generic1 ) { continue; } } // SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue, oldframe, localClient ); SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums /*, qtrue, localClient */ ); } continue; }
static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t* frame, snapshotEntityNumbers_t* eNums, bool portal, bitSet_c& areaBits ) { int e;//, i; edict_s* ent; svEntity_t* svEnt; //int l; // 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; } bspPointDesc_s eyeDesc; // for .bsp PVS pvsHandle_t procVisHandle; // for .proc vis if ( sv_bsp ) { sv_bsp->filterPoint( origin, eyeDesc ); sv_bsp->appendCurrentAreaBits( eyeDesc.area, areaBits ); } else if ( sv_procVis ) { procVisHandle = sv_procVis->SetupCurrentPVS( origin ); } for ( e = 0 ; e < sv.num_entities ; e++ ) { ent = SV_GentityNum( e ); // never send entities that aren't active if ( ent->s == 0 ) { continue; } if ( ent->s->number != e ) { Com_DPrintf( "FIXING ENT->S.NUMBER!!!\n" ); ent->s->number = e; } // never send entities that aren't visible if ( ent->s->isHidden() ) { continue; } // never send ai waypoints (pathnodes) if ( ent->s->eType == ET_PATHNODE ) { continue; } edict_s* visEnt = ent; while ( visEnt->s->parentNum != ENTITYNUM_NONE ) { visEnt = SV_GentityNum( visEnt->s->parentNum ); } if ( visEnt->bspBoxDesc == 0 ) { continue; // not linked } svEnt = SV_SvEntityForGentity( ent ); // don't double add an entity through portals if ( svEnt->snapshotCounter == sv.snapshotCounter ) { continue; } if ( sv_cullEntities.getInt() ) { if ( sv_bsp && sv_bsp->checkVisibility( eyeDesc, *visEnt->bspBoxDesc ) == false ) { continue; // culled by .bsp PVS } if ( sv_procVis && sv_procVis->InCurrentPVS( procVisHandle, visEnt->bspBoxDesc->areas.getArray(), visEnt->bspBoxDesc->areas.size() ) == false ) { continue; // culled by Doom3 .proc vis } } SV_AddEntToSnapshot( svEnt, ent, eNums ); } if ( sv_procVis ) { sv_procVis->FreeCurrentPVS( procVisHandle ); } }
/* =============== 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; byte *clientpvs; byte *bitvector; // 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; for ( e = 0 ; e < ge->num_entities ; e++ ) { ent = SV_GentityNum(e); if (!ent->inuse) { 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; } // 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; for ( i=0 ; i < svEnt->numClusters ; i++ ) { l = svEnt->clusternums[i]; if ( bitvector[l >> 3] & (1 << (l&7) ) ) { break; } } // if we haven't found it to be visible, // check overflow clusters that coudln't be stored if ( i == svEnt->numClusters ) { 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 ); } }
static void SV_AddEntitiesVisibleFromPoint(vec3_t origin, clientSnapshot_t *frame, snapshotEntityNumbers_t *eNums) #endif { int e, i; sharedEntity_t *ent, *playerEnt, *ment; #ifdef FEATURE_ANTICHEAT sharedEntity_t *client; #endif svEntity_t *svEnt; int l; int clientarea, clientcluster; int leafnum; byte *clientpvs; byte *bitvector; // 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); playerEnt = SV_GentityNum(frame->ps.clientNum); if (playerEnt->r.svFlags & SVF_SELF_PORTAL) { #ifdef FEATURE_ANTICHEAT SV_AddEntitiesVisibleFromPoint(playerEnt->s.origin2, frame, eNums, qtrue); // portal qtrue?! #else SV_AddEntitiesVisibleFromPoint(playerEnt->s.origin2, frame, eNums); #endif } for (e = 0 ; e < sv.num_entities ; e++) { ent = SV_GentityNum(e); // never send entities that aren't linked in if (!ent->r.linked) { continue; } if (ent->s.number != e) { Com_DPrintf("FIXING ENT->S.NUMBER!!!\n"); ent->s.number = e; } // entities can be flagged to explicitly not be sent to the client if (ent->r.svFlags & SVF_NOCLIENT) { continue; } // entities can be flagged to be sent to only one client if (ent->r.svFlags & SVF_SINGLECLIENT) { if (ent->r.singleClient != frame->ps.clientNum) { continue; } } // entities can be flagged to be sent to everyone but one client if (ent->r.svFlags & SVF_NOTSINGLECLIENT) { if (ent->r.singleClient == frame->ps.clientNum) { continue; } } svEnt = SV_SvEntityForGentity(ent); // don't double add an entity through portals if (svEnt->snapshotCounter == sv.snapshotCounter) { continue; } // broadcast entities are always sent if (ent->r.svFlags & SVF_BROADCAST) { SV_AddEntToSnapshot(playerEnt, svEnt, ent, eNums); continue; } bitvector = clientpvs; // just check origin for being in pvs, ignore bmodel extents if (ent->r.svFlags & SVF_IGNOREBMODELEXTENTS) { if (bitvector[svEnt->originCluster >> 3] & (1 << (svEnt->originCluster & 7))) { SV_AddEntToSnapshot(playerEnt, 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; } } // check individual leafs if (!svEnt->numClusters) { continue; } l = 0; for (i = 0 ; i < svEnt->numClusters ; i++) { l = svEnt->clusternums[i]; if (bitvector[l >> 3] & (1 << (l & 7))) { break; } } // if we haven't found it to be visible, // check overflow clusters that coudln't be stored if (i == svEnt->numClusters) { 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; } } // added "visibility dummies" if (ent->r.svFlags & SVF_VISDUMMY) { // find master; ment = SV_GentityNum(ent->s.otherEntityNum); if (ment) { svEntity_t *master = 0; master = SV_SvEntityForGentity(ment); if (master->snapshotCounter == sv.snapshotCounter || !ment->r.linked) { continue; } SV_AddEntToSnapshot(playerEnt, master, ment, eNums); } continue; // master needs to be added, but not this dummy ent } else if (ent->r.svFlags & SVF_VISDUMMY_MULTIPLE) { int h; sharedEntity_t *ment = 0; svEntity_t *master = 0; for (h = 0; h < sv.num_entities; h++) { ment = SV_GentityNum(h); if (ment == ent) { continue; } if (ment) { master = SV_SvEntityForGentity(ment); } else { continue; } if (!(ment->r.linked)) { continue; } if (ment->s.number != h) { Com_DPrintf("FIXING vis dummy multiple ment->S.NUMBER!!!\n"); ment->s.number = h; } if (ment->r.svFlags & SVF_NOCLIENT) { continue; } if (master->snapshotCounter == sv.snapshotCounter) { continue; } if (ment->s.otherEntityNum == ent->s.number) { SV_AddEntToSnapshot(playerEnt, master, ment, eNums); } } continue; } #ifdef FEATURE_ANTICHEAT if (sv_wh_active->integer > 0 && e < sv_maxclients->integer) // client { // note: !r.linked is already exclused - see above if (e == frame->ps.clientNum) { continue; } client = SV_GentityNum(frame->ps.clientNum); // exclude bots and free flying specs if (!portal && !(client->r.svFlags & SVF_BOT) && (frame->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR) && !(frame->ps.pm_flags & PMF_FOLLOW)) { if (!SV_CanSee(frame->ps.clientNum, e)) { SV_RandomizePos(frame->ps.clientNum, e); SV_AddEntToSnapshot(client, svEnt, ent, eNums); continue; } } } #endif // add it SV_AddEntToSnapshot(playerEnt, svEnt, ent, eNums); // if its a portal entity, add everything visible from its camera position if (ent->r.svFlags & SVF_PORTAL) { #ifdef FEATURE_ANTICHEAT SV_AddEntitiesVisibleFromPoint(ent->s.origin2, frame, eNums, qtrue /*localClient*/); #else SV_AddEntitiesVisibleFromPoint(ent->s.origin2, frame, eNums /*, qtrue, localClient*/); #endif } continue; }
/* =============== SV_AddEntitiesVisibleFromPoint =============== */ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame, snapshotEntityNumbers_t *eNums, qboolean portal ) { int e, i; sharedEntity_t *ent; svEntity_t *svEnt; int l; int clientarea, clientcluster; int leafnum; byte *clientpvs; byte *bitvector; client_t *cl; vec3_t diff; // 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); for ( e = 0 ; e < sv.num_entities ; e++ ) { ent = SV_GentityNum(e); // never send entities that aren't linked in if ( !ent->r.linked ) { continue; } if (ent->s.number != e) { Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n"); ent->s.number = e; } // entities can be flagged to explicitly not be sent to the client if ( ent->r.svFlags & SVF_NOCLIENT ) { continue; } // entities can be flagged to be sent to only one client if ( ent->r.svFlags & SVF_SINGLECLIENT ) { if ( ent->r.singleClient != frame->ps.clientNum ) { continue; } } // entities can be flagged to be sent to everyone but one client if ( ent->r.svFlags & SVF_NOTSINGLECLIENT ) { if ( ent->r.singleClient == frame->ps.clientNum ) { continue; } } // entities can be flagged to be sent to a given mask of clients if ( ent->r.svFlags & SVF_CLIENTMASK ) { if (frame->ps.clientNum >= 32) Com_Error( ERR_DROP, "SVF_CLIENTMASK: clientNum >= 32" ); if (~ent->r.singleClient & (1 << frame->ps.clientNum)) continue; } svEnt = SV_SvEntityForGentity( ent ); // don't double add an entity through portals if ( svEnt->snapshotCounter == sv.snapshotCounter ) { continue; } // broadcast entities are always sent cl = svs.clients+frame->ps.clientNum; // if ( ent->r.svFlags & SVF_BROADCAST ) { if ( ent->r.svFlags & SVF_BROADCAST && (ent->s.eType != ET_PLAYER || sv_antiwallhack->integer == 0 || recentlySeen(cl,ent->s.clientNum))) {// broadcast only non-players. Warning: in case sv_antiwallhack equals 1, bots will be disappearing on dm_train when touching doors, unless you compensate with "recentlySeen". SV_AddEntToSnapshot( svEnt, ent, eNums ); continue; } //if (!(ent->r.svFlags & SVF_BOT)) {// if this entity is not a bot ... (compensation for the broadcast restriction to non-players) // 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; for ( i=0 ; i < svEnt->numClusters ; i++ ) { l = svEnt->clusternums[i]; if ( bitvector[l >> 3] & (1 << (l&7) ) ) { break; } } // if we haven't found it to be visible, // check overflow clusters that coudln't be stored if ( i == svEnt->numClusters ) { 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; } } if (sv_antiwallhack->integer == 1 && (cl->netchan.remoteAddress.type != NA_BOT) && ent->s.eType == ET_PLAYER) { if (!SV_IsPlayerVisibleFromPoint(origin,frame,ent,diff)) { continue; } } // add it SV_AddEntToSnapshot( svEnt, ent, eNums ); // reset ps.pm_type? // if it's a portal entity, add everything visible from its camera position if ( ent->r.svFlags & SVF_PORTAL ) { if ( ent->s.generic1 ) { vec3_t dir; VectorSubtract(ent->s.origin, origin, dir); if ( VectorLengthSquared(dir) > (float) ent->s.generic1 * ent->s.generic1 ) { continue; } } SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue ); } }
/* =============== SV_AddEntitiesVisibleFromPoint =============== */ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame, snapshotEntityNumbers_t *eNums, qboolean portal ) { int e, i; sharedEntity_t *ent; svEntity_t *svEnt; int l; int clientarea, clientcluster; int leafnum; int c_fullsend; byte *clientpvs; byte *bitvector; // 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; for ( e = 0 ; e < sv.num_entities ; e++ ) { ent = SV_GentityNum(e); // never send entities that aren't linked in if ( !ent->r.linked ) { continue; } if (ent->s.number != e) { Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n"); ent->s.number = e; } svEnt = SV_SvEntityForGentity( ent ); if ( sv.gentitiesMV != NULL && sv.gentitySizeMV > 0 ) { mvsharedEntity_t *mvEnt = MV_EntityNum(e); if ( VM_MVAPILevel( gvm ) >= 2 ) { // MV entities can be flagged to be sent only to // spectators or non-spectators if ( frame->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR || (frame->ps.pm_flags & PMF_FOLLOW) ) { if ( mvEnt->mvFlags & MVF_NOSPEC ) continue; } else { if ( mvEnt->mvFlags & MVF_SPECONLY ) continue; } } // MV entities can be flagged to be sent only to specific // clients (can't filter following spectators this way) if ( mvEnt->snapshotIgnore[frame->ps.clientNum] ) continue; else if ( mvEnt->snapshotEnforce[frame->ps.clientNum] ) { SV_AddEntToSnapshot( svEnt, ent, eNums ); continue; } } // entities can be flagged to explicitly not be sent to the client if ( ent->r.svFlags & SVF_NOCLIENT ) { continue; } // entities can be flagged to be sent to only one client if ( ent->r.svFlags & SVF_SINGLECLIENT ) { if ( ent->r.singleClient != frame->ps.clientNum ) { continue; } } // entities can be flagged to be sent to everyone but one client if ( ent->r.svFlags & SVF_NOTSINGLECLIENT ) { if ( ent->r.singleClient == frame->ps.clientNum ) { continue; } } // 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->r.svFlags & SVF_BROADCAST || (e == frame->ps.clientNum) || (ent->r.broadcastClients[frame->ps.clientNum/32] & (1<<(frame->ps.clientNum%32)))) { 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; for ( i=0 ; i < svEnt->numClusters ; i++ ) { l = svEnt->clusternums[i]; if ( bitvector[l >> 3] & (1 << (l&7) ) ) { break; } } // if we haven't found it to be visible, // check overflow clusters that coudln't be stored if ( i == svEnt->numClusters ) { 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->r.svFlags & SVF_PORTAL ) { if ( ent->s.generic1 ) { vec3_t dir; VectorSubtract(ent->s.origin, origin, dir); if ( VectorLengthSquared(dir) > (float) ent->s.generic1 * ent->s.generic1 ) { continue; } } SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue ); } }
/* =============== SV_AddEntitiesVisibleFromPoint =============== */ static void SV_AddEntitiesVisibleFromPoint( int psIndex, int clientNum, vec3_t origin, clientSnapshot_t *frame, snapshotEntityNumbers_t *eNums, qboolean portal ) { int e, i; sharedEntity_t *ent; svEntity_t *svEnt; int l; int clientarea, clientcluster; int leafnum; byte *clientpvs; byte *bitvector; // 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[psIndex] = CM_WriteAreaBits( frame->areabits[psIndex], clientarea ); clientpvs = CM_ClusterPVS (clientcluster); for ( e = 0 ; e < sv.num_entities ; e++ ) { ent = SV_GentityNum(e); // never send entities that aren't linked in if ( !ent->r.linked ) { continue; } if (ent->s.number != e) { Com_DPrintf ("FIXING ENT->S.NUMBER!!!\n"); ent->s.number = e; } // entities can be flagged to explicitly not be sent to the client if ( ent->r.svFlags & SVF_NOCLIENT ) { continue; } // entities can be flagged to be sent to a given mask of clients if ( ent->r.svFlags & SVF_CLIENTMASK ) { if ( !Com_ClientListContains( &ent->r.sendClients, clientNum ) ) continue; } svEnt = SV_SvEntityForGentity( ent ); // don't double add an entity through portals if ( svEnt->snapshotCounter == sv.snapshotCounter ) { continue; } // limit based on distance if ( ent->r.cullDistance ) { vec3_t dir; VectorSubtract(ent->s.origin, origin, dir); if ( VectorLengthSquared(dir) > (float) ent->r.cullDistance * ent->r.cullDistance ) { continue; } } // broadcast entities are always sent if ( ent->r.svFlags & SVF_BROADCAST ) { SV_AddEntToSnapshot( frame, 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; for ( i=0 ; i < svEnt->numClusters ; i++ ) { l = svEnt->clusternums[i]; if ( bitvector[l >> 3] & (1 << (l&7) ) ) { break; } } // if we haven't found it to be visible, // check overflow clusters that coudln't be stored if ( i == svEnt->numClusters ) { 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; } } // visibility dummies if ( ent->r.svFlags & SVF_VISDUMMY ) { sharedEntity_t *ment = NULL; // find master ment = SV_GentityNum( ent->r.visDummyNum ); if ( ment ) { svEntity_t *master = NULL; master = SV_SvEntityForGentity( ment ); if ( master->snapshotCounter == sv.snapshotCounter || !ment->r.linked ) { continue; } SV_AddEntToSnapshot( frame, master, ment, eNums ); } // master needs to be added, but not this dummy ent continue; } else if ( ent->r.svFlags & SVF_VISDUMMY_MULTIPLE ) { int h; sharedEntity_t *ment = NULL; svEntity_t *master = NULL; for ( h = 0; h < sv.num_entities; h++ ) { ment = SV_GentityNum( h ); if ( ment == ent ) { continue; } if ( ment ) { master = SV_SvEntityForGentity( ment ); } else { continue; } if ( !ment->r.linked ) { continue; } if ( ment->s.number != h ) { Com_DPrintf( "FIXING vis dummy multiple ment->S.NUMBER!!!\n" ); ment->s.number = h; } if ( ment->r.svFlags & SVF_NOCLIENT ) { continue; } if ( master->snapshotCounter == sv.snapshotCounter ) { continue; } if ( ment->r.visDummyNum == ent->s.number ) { SV_AddEntToSnapshot( frame, master, ment, eNums ); } } // masters need to be added, but not this dummy ent continue; } // add it SV_AddEntToSnapshot( frame, svEnt, ent, eNums ); // if it's a portal entity, add everything visible from its camera position if ( ent->r.svFlags & SVF_PORTAL ) { if ( ent->r.portalCullDistance ) { vec3_t dir; VectorSubtract(ent->s.origin, origin, dir); if ( VectorLengthSquared(dir) > (float) ent->r.portalCullDistance * ent->r.portalCullDistance ) { continue; } } SV_AddEntitiesVisibleFromPoint( psIndex, clientNum, ent->s.origin2, frame, eNums, qtrue ); } }
/* =============== SV_AddEntitiesVisibleFromPoint =============== */ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame, // snapshotEntityNumbers_t *eNums, qboolean portal, clientSnapshot_t *oldframe, qboolean localClient ) { // snapshotEntityNumbers_t *eNums, qboolean portal ) { snapshotEntityNumbers_t *eNums, qboolean portal, qboolean localClient ) { int e, i; sharedEntity_t *ent, *playerEnt; svEntity_t *svEnt; int l; int clientarea, clientcluster; int leafnum; int c_fullsend; byte *clientpvs; byte *bitvector; // 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; playerEnt = SV_GentityNum( frame->ps.clientNum ); for ( e = 0 ; e < sv.num_entities ; e++ ) { ent = SV_GentityNum( e ); // never send entities that aren't linked in if ( !ent->r.linked ) { continue; } if ( ent->s.number != e ) { Com_DPrintf( "FIXING ENT->S.NUMBER!!!\n" ); ent->s.number = e; } // entities can be flagged to explicitly not be sent to the client if ( ent->r.svFlags & SVF_NOCLIENT ) { continue; } // entities can be flagged to be sent to only one client if ( ent->r.svFlags & SVF_SINGLECLIENT ) { if ( ent->r.singleClient != frame->ps.clientNum ) { continue; } } // entities can be flagged to be sent to everyone but one client if ( ent->r.svFlags & SVF_NOTSINGLECLIENT ) { if ( ent->r.singleClient == frame->ps.clientNum ) { continue; } } svEnt = SV_SvEntityForGentity( ent ); // don't double add an entity through portals if ( svEnt->snapshotCounter == sv.snapshotCounter ) { continue; } // if this client is viewing from a camera, only add ents visible from portal ents if ( ( playerEnt->s.eFlags & EF_VIEWING_CAMERA ) && !portal ) { if ( ent->r.svFlags & SVF_PORTAL ) { SV_AddEntToSnapshot( svEnt, ent, eNums ); // SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue, oldframe, localClient ); SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue, localClient ); } continue; } // broadcast entities are always sent if ( ent->r.svFlags & SVF_BROADCAST ) { 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 ) ) { goto notVisible; // blocked by a door } } bitvector = clientpvs; // check individual leafs if ( !svEnt->numClusters ) { goto notVisible; } l = 0; for ( i = 0 ; i < svEnt->numClusters ; i++ ) { l = svEnt->clusternums[i]; if ( bitvector[l >> 3] & ( 1 << ( l & 7 ) ) ) { break; } } // if we haven't found it to be visible, // check overflow clusters that coudln't be stored if ( i == svEnt->numClusters ) { if ( svEnt->lastCluster ) { for ( ; l <= svEnt->lastCluster ; l++ ) { if ( bitvector[l >> 3] & ( 1 << ( l & 7 ) ) ) { break; } } if ( l == svEnt->lastCluster ) { goto notVisible; // not visible } } else { goto notVisible; } } //----(SA) added "visibility dummies" if ( ent->r.svFlags & SVF_VISDUMMY ) { sharedEntity_t *ment = 0; //find master; ment = SV_GentityNum( ent->s.otherEntityNum ); if ( ment ) { svEntity_t *master = 0; master = SV_SvEntityForGentity( ment ); if ( master->snapshotCounter == sv.snapshotCounter || !ment->r.linked ) { goto notVisible; //continue; } SV_AddEntToSnapshot( master, ment, eNums ); } goto notVisible; //continue; // master needs to be added, but not this dummy ent } //----(SA) end else if ( ent->r.svFlags & SVF_VISDUMMY_MULTIPLE ) { { int h; sharedEntity_t *ment = 0; svEntity_t *master = 0; for ( h = 0; h < sv.num_entities; h++ ) { ment = SV_GentityNum( h ); if ( ment == ent ) { continue; } if ( ment ) { master = SV_SvEntityForGentity( ment ); } else { continue; } if ( !( ment->r.linked ) ) { continue; } if ( ment->s.number != h ) { Com_DPrintf( "FIXING vis dummy multiple ment->S.NUMBER!!!\n" ); ment->s.number = h; } if ( ment->r.svFlags & SVF_NOCLIENT ) { continue; } if ( master->snapshotCounter == sv.snapshotCounter ) { continue; } if ( ment->s.otherEntityNum == ent->s.number ) { SV_AddEntToSnapshot( master, ment, eNums ); } } goto notVisible; } } // add it SV_AddEntToSnapshot( svEnt, ent, eNums ); // if its a portal entity, add everything visible from its camera position if ( ent->r.svFlags & SVF_PORTAL ) { // SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue, oldframe, localClient ); SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, qtrue, localClient ); } continue; notVisible: // Ridah, if this entity has changed events, then send it regardless of whether we can see it or not // DHM - Nerve :: not in multiplayer please if ( sv_gametype->integer == GT_SINGLE_PLAYER && localClient ) { if ( ent->r.eventTime == svs.time ) { ent->s.eFlags |= EF_NODRAW; // don't draw, just process event SV_AddEntToSnapshot( svEnt, ent, eNums ); } else if ( ent->s.eType == ET_PLAYER ) { // keep players around if they are alive and active (so sounds dont get messed up) if ( !( ent->s.eFlags & EF_DEAD ) ) { ent->s.eFlags |= EF_NODRAW; // don't draw, just process events and sounds SV_AddEntToSnapshot( svEnt, ent, eNums ); } } } }
/* =============== 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 } } }
static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_frame_t *frame, sv_ents_t *ents, bool portal ) { edict_t *ent; vec3_t origin; byte *pset; sv_client_t *cl; int leafnum, fullvis = false; int e, clientcluster, clientarea; bool force = false; // 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; if( pClient && !portal ) { // portals can't change hostflags sv.hostflags &= ~SVF_SKIPLOCALHOST; cl = SV_ClientFromEdict( pClient, true ); Com_Assert( cl == NULL ); // setup hostflags if( com.atoi( Info_ValueForKey( cl->userinfo, "cl_lw" )) == 1 ) sv.hostflags |= SVF_SKIPLOCALHOST; } e = svgame.dllFuncs.pfnSetupVisibility( pViewEnt, pClient, portal, origin ); if( e == 0 ) return; // invalid viewent ? if( e == -1 ) fullvis = true; clientpvs = CM_FatPVS( origin, portal ); leafnum = CM_PointLeafnum( origin ); clientarea = CM_LeafArea( leafnum ); clientcluster = CM_LeafCluster( leafnum ); clientphs = CM_FatPHS( clientcluster, portal ); // calculate the visible areas if( fullvis ) { if( !portal ) Mem_Set( frame->areabits, 0xFF, sizeof( frame->areabits )); frame->areabits_size = sizeof( frame->areabits ); } else frame->areabits_size = CM_WriteAreaBits( frame->areabits, clientarea, portal ); for( e = 1; e < svgame.globals->numEntities; e++ ) { ent = EDICT_NUM( e ); if( ent->free ) continue; if( ent->serialnumber != e ) { // this should never happens MsgDev( D_NOTE, "fixing ent->serialnumber from %i to %i\n", ent->serialnumber, e ); ent->serialnumber = e; } // don't double add an entity through portals (already added) if( ent->pvServerData->framenum == sv.net_framenum ) continue; if( fullvis ) force = true; else force = false; // clear forceflag // NOTE: always add himslef to list if( !portal && ( ent == pClient )) force = true; if( ent->v.flags & FL_PHS_FILTER ) pset = clientphs; else pset = clientpvs; if( !force ) { // run custom user filter if( !svgame.dllFuncs.pfnAddToFullPack( pViewEnt, pClient, ent, sv.hostflags, clientarea, pset )) continue; } SV_AddEntToSnapshot( ent->pvServerData, ent, ents ); // add it if( fullvis ) continue; // portal ents will be added anywhere, ignore recursion // if its a portal entity, add everything visible from its camera position if( !portal && (ent->pvServerData->s.ed_type == ED_PORTAL || ent->pvServerData->s.ed_type == ED_SKYPORTAL)) SV_AddEntitiesToPacket( ent, pClient, frame, ents, true ); } }