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; 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, 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; } } 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; // Gordon: 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; } } 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 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; }
/* =============== 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_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; } // 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; } // 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 ); } }