Exemplo n.º 1
0
static inline int TV_Module_CM_LeafCluster( relay_t *relay, int leafnum )
{
	if( !relay )
	{
		Com_Printf( "Error: TV_Module_CM_LeafCluster: Relay not set\n" );
		return 0;
	}

	return CM_LeafCluster( relay->cms, leafnum );
}
Exemplo n.º 2
0
/*
=================
SV_inPVSIgnorePortals

Does NOT check portalareas
=================
*/
bool SV_inPVSIgnorePortals(const vec3_t p1, const vec3_t p2) {
	int             leafnum, cluster, area1, area2;
	byte           *mask;

	leafnum = CM_PointLeafnum(p1);
	cluster = CM_LeafCluster(leafnum);
	area1 = CM_LeafArea(leafnum);
	mask = CM_ClusterPVS(cluster);

	leafnum = CM_PointLeafnum(p2);
	cluster = CM_LeafCluster(leafnum);
	area2 = CM_LeafArea(leafnum);

	if(mask && (!(mask[cluster >> 3] & (1 << (cluster & 7))))) {
		return false;
	}

	return true;
}
Exemplo n.º 3
0
/*
=================
SV_inPVS

Also checks portalareas so that doors block sight
=================
*/
bool SV_inPVS(const vec3_t p1, const vec3_t p2) {
	int             leafnum, cluster, area1, area2;
	byte           *mask;

	leafnum = CM_PointLeafnum(p1);
	cluster = CM_LeafCluster(leafnum);
	area1 = CM_LeafArea(leafnum);
	mask = CM_ClusterPVS(cluster);

	leafnum = CM_PointLeafnum(p2);
	cluster = CM_LeafCluster(leafnum);
	area2 = CM_LeafArea(leafnum);
	if(mask && (!(mask[cluster >> 3] & (1 << (cluster & 7))))) {
		return false;
	}
	if(!CM_AreasConnected(area1, area2)) {
		return false; // a door blocks sight
	}
	return true;
}
//-----------------------------------------------------------------------------
// Is the prop in the PVS?
//-----------------------------------------------------------------------------
bool CStaticPropMgr::IsPropInPVS( IHandleEntity *pHandleEntity, const byte *pVis ) const
{
	// Strip off the bits
	int nIndex = HandleEntityToIndex( pHandleEntity );

	// Get the prop
	const CStaticProp &prop = m_StaticProps[nIndex];

	int i;
	int end = prop.FirstLeaf() + prop.LeafCount();
	for( i = prop.FirstLeaf(); i < end; i++ )
	{
		Assert( i >= 0 && i < m_StaticPropLeaves.Count() );
		int clusterID = CM_LeafCluster( m_StaticPropLeaves[i].m_Leaf );
		if( pVis[ clusterID >> 3 ] & ( 1 << ( clusterID & 7 ) ) )
		{
			return true;
		}
	}
	return false;
}
Exemplo n.º 5
0
/*
* CM_MergePVS
* Merge PVS at origin into out
*/
void CM_MergePVS( cmodel_state_t *cms, vec3_t org, qbyte *out )
{
	int leafs[128];
	int i, j, count;
	int longs;
	qbyte *src;
	vec3_t mins, maxs;

	for( i = 0; i < 3; i++ )
	{
		mins[i] = org[i] - 9;
		maxs[i] = org[i] + 9;
	}

	count = CM_BoxLeafnums( cms, mins, maxs, leafs, sizeof( leafs )/sizeof( int ), NULL );
	if( count < 1 )
		Com_Error( ERR_FATAL, "CM_MergePVS: count < 1" );
	longs = CM_ClusterRowLongs( cms );

	// convert leafs to clusters
	for( i = 0; i < count; i++ )
		leafs[i] = CM_LeafCluster( cms, leafs[i] );

	// or in all the other leaf bits
	for( i = 0; i < count; i++ )
	{
		for( j = 0; j < i; j++ )
			if( leafs[i] == leafs[j] )
				break;
		if( j != i )
			continue; // already have the cluster we want
		src = CM_ClusterPVS( cms, leafs[i] );
		for( j = 0; j < longs; j++ )
			( (int *)out )[j] |= ( (int *)src )[j];
	}
}
Exemplo n.º 6
0
/*
===============
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 );
		}

	}
Exemplo n.º 7
0
void SV_LinkEntity( sharedEntity_t *gEnt ) {
	worldSector_t	*node;
	int			leafs[MAX_TOTAL_ENT_LEAFS];
	int			cluster;
	int			num_leafs;
	int			i, j, k;
	int			area;
	int			lastLeaf;
	float		*origin, *angles;
	svEntity_t	*ent;

	ent = SV_SvEntityForGentity( gEnt );

	if ( ent->worldSector ) {
		SV_UnlinkEntity( gEnt );	// unlink from old position
	}

	// encode the size into the entityState_t for client prediction
	if ( gEnt->r.bmodel ) {
		gEnt->s.solid = SOLID_BMODEL;		// a solid_box will never create this value
	} else if ( gEnt->r.contents & ( CONTENTS_SOLID | CONTENTS_BODY ) ) {
		// assume that x/y are equal and symetric
		i = gEnt->r.maxs[0];
		if (i<1)
			i = 1;
		if (i>255)
			i = 255;

		// z is not symetric
		j = (-gEnt->r.mins[2]);
		if (j<1)
			j = 1;
		if (j>255)
			j = 255;

		// and z maxs can be negative...
		k = (gEnt->r.maxs[2]+32);
		if (k<1)
			k = 1;
		if (k>255)
			k = 255;

		gEnt->s.solid = (k<<16) | (j<<8) | i;
	} else {
		gEnt->s.solid = 0;
	}

	// get the position
	origin = gEnt->r.currentOrigin;
	angles = gEnt->r.currentAngles;

	// set the abs box
	if ( gEnt->r.bmodel && (angles[0] || angles[1] || angles[2]) ) {
		// expand for rotation
		float		max;
		int			i;

		max = RadiusFromBounds( gEnt->r.mins, gEnt->r.maxs );
		for (i=0 ; i<3 ; i++) {
			gEnt->r.absmin[i] = origin[i] - max;
			gEnt->r.absmax[i] = origin[i] + max;
		}
	} else {
		// normal
		VectorAdd (origin, gEnt->r.mins, gEnt->r.absmin);	
		VectorAdd (origin, gEnt->r.maxs, gEnt->r.absmax);
	}

	// because movement is clipped an epsilon away from an actual edge,
	// we must fully check even when bounding boxes don't quite touch
	gEnt->r.absmin[0] -= 1;
	gEnt->r.absmin[1] -= 1;
	gEnt->r.absmin[2] -= 1;
	gEnt->r.absmax[0] += 1;
	gEnt->r.absmax[1] += 1;
	gEnt->r.absmax[2] += 1;

	// link to PVS leafs
	ent->numClusters = 0;
	ent->lastCluster = 0;
	ent->areanum = -1;
	ent->areanum2 = -1;

	//get all leafs, including solids
	num_leafs = CM_BoxLeafnums( gEnt->r.absmin, gEnt->r.absmax,
		leafs, MAX_TOTAL_ENT_LEAFS, &lastLeaf );

	// if none of the leafs were inside the map, the
	// entity is outside the world and can be considered unlinked
	if ( !num_leafs ) {
		return;
	}

	// set areas, even from clusters that don't fit in the entity array
	for (i=0 ; i<num_leafs ; i++) {
		area = CM_LeafArea (leafs[i]);
		if (area != -1) {
			// doors may legally straggle two areas,
			// but nothing should evern need more than that
			if (ent->areanum != -1 && ent->areanum != area) {
				if (ent->areanum2 != -1 && ent->areanum2 != area && sv.state == SS_LOADING) {
					Com_DPrintf ("Object %i touching 3 areas at %f %f %f\n",
					gEnt->s.number,
					gEnt->r.absmin[0], gEnt->r.absmin[1], gEnt->r.absmin[2]);
				}
				ent->areanum2 = area;
			} else {
				ent->areanum = area;
			}
		}
	}

	// store as many explicit clusters as we can
	ent->numClusters = 0;
	for (i=0 ; i < num_leafs ; i++) {
		cluster = CM_LeafCluster( leafs[i] );
		if ( cluster != -1 ) {
			ent->clusternums[ent->numClusters++] = cluster;
			if ( ent->numClusters == MAX_ENT_CLUSTERS ) {
				break;
			}
		}
	}

	// store off a last cluster if we need to
	if ( i != num_leafs ) {
		ent->lastCluster = CM_LeafCluster( lastLeaf );
	}

	gEnt->r.linkcount++;

	// find the first world sector node that the ent's box crosses
	node = sv_worldSectors;
	while (1)
	{
		if (node->axis == -1)
			break;
		if ( gEnt->r.absmin[node->axis] > node->dist)
			node = node->children[0];
		else if ( gEnt->r.absmax[node->axis] < node->dist)
			node = node->children[1];
		else
			break;		// crosses the node
	}
	
	// link it in
	ent->worldSector = node;
	ent->nextEntityInWorldSector = node->entities;
	node->entities = ent;

	gEnt->r.linked = qtrue;
}
Exemplo n.º 8
0
/*
===============
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);
        }
    }
Exemplo n.º 9
0
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 );
			}
		}
	}
Exemplo n.º 10
0
/*
===============
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;
	}
Exemplo n.º 11
0
void SV_LinkEdict (edict_t *ent)
{
	areanode_t	*node;
	int			leafs[MAX_TOTAL_ENT_LEAFS];
	int			clusters[MAX_TOTAL_ENT_LEAFS];
	int			num_leafs;
	int			i, j, k;
	int			area;
	int			topnode;

	if (ent->area.prev)
		SV_UnlinkEdict (ent);	// unlink from old position
		
	if (ent == ge->edicts)
		return;		// don't add the world

	if (!ent->inuse)
		return;

	// set the size
	VectorSubtract (ent->maxs, ent->mins, ent->size);
	
	// encode the size into the entity_state for client prediction
	if (ent->solid == SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER))
	{	// assume that x/y are equal and symetric
		i = ent->maxs[0]/8;
		if (i<1)
			i = 1;
		if (i>31)
			i = 31;

		// z is not symetric
		j = (-ent->mins[2])/8;
		if (j<1)
			j = 1;
		if (j>31)
			j = 31;

		// and z maxs can be negative...
		k = (ent->maxs[2]+32)/8;
		if (k<1)
			k = 1;
		if (k>63)
			k = 63;

		ent->s.solid = (k<<10) | (j<<5) | i;
	}
	else if (ent->solid == SOLID_BSP)
	{
		ent->s.solid = 31;		// a solid_bbox will never create this value
	}
	else
		ent->s.solid = 0;

	// set the abs box
	if (ent->solid == SOLID_BSP && 
	(ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) )
	{	// expand for rotation
		float		max, v;
		int			i;

		max = 0;
		for (i=0 ; i<3 ; i++)
		{
			v =fabs( ent->mins[i]);
			if (v > max)
				max = v;
			v =fabs( ent->maxs[i]);
			if (v > max)
				max = v;
		}
		for (i=0 ; i<3 ; i++)
		{
			ent->absmin[i] = ent->s.origin[i] - max;
			ent->absmax[i] = ent->s.origin[i] + max;
		}
	}
	else
	{	// normal
		VectorAdd (ent->s.origin, ent->mins, ent->absmin);	
		VectorAdd (ent->s.origin, ent->maxs, ent->absmax);
	}

	// because movement is clipped an epsilon away from an actual edge,
	// we must fully check even when bounding boxes don't quite touch
	ent->absmin[0] -= 1;
	ent->absmin[1] -= 1;
	ent->absmin[2] -= 1;
	ent->absmax[0] += 1;
	ent->absmax[1] += 1;
	ent->absmax[2] += 1;

// link to PVS leafs
	ent->num_clusters = 0;
	ent->areanum = 0;
	ent->areanum2 = 0;

	//get all leafs, including solids
	num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax,
		leafs, MAX_TOTAL_ENT_LEAFS, &topnode);

	// set areas
	for (i=0 ; i<num_leafs ; i++)
	{
		clusters[i] = CM_LeafCluster (leafs[i]);
		area = CM_LeafArea (leafs[i]);
		if (area)
		{	// doors may legally straggle two areas,
			// but nothing should evern need more than that
			if (ent->areanum && ent->areanum != area)
			{
				if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading)
					Com_DPrintf ("Object touching 3 areas at %f %f %f\n",
					ent->absmin[0], ent->absmin[1], ent->absmin[2]);
				ent->areanum2 = area;
			}
			else
				ent->areanum = area;
		}
	}

	if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
	{	// assume we missed some leafs, and mark by headnode
		ent->num_clusters = -1;
		ent->headnode = topnode;
	}
	else
	{
		ent->num_clusters = 0;
		for (i=0 ; i<num_leafs ; i++)
		{
			if (clusters[i] == -1)
				continue;		// not a visible leaf
			for (j=0 ; j<i ; j++)
				if (clusters[j] == clusters[i])
					break;
			if (j == i)
			{
				if (ent->num_clusters == MAX_ENT_CLUSTERS)
				{	// assume we missed some leafs, and mark by headnode
					ent->num_clusters = -1;
					ent->headnode = topnode;
					break;
				}

				ent->clusternums[ent->num_clusters++] = clusters[i];
			}
		}
	}

	// if first time, make sure old_origin is valid
	if (!ent->linkcount)
	{
		VectorCopy (ent->s.origin, ent->s.old_origin);
	}
	ent->linkcount++;

	if (ent->solid == SOLID_NOT)
		return;

// find the first node that the ent's box crosses
	node = sv_areanodes;
	while (1)
	{
		if (node->axis == -1)
			break;
		if (ent->absmin[node->axis] > node->dist)
			node = node->children[0];
		else if (ent->absmax[node->axis] < node->dist)
			node = node->children[1];
		else
			break;		// crosses the node
	}
	
	// link it in	
	if (ent->solid == SOLID_TRIGGER)
		InsertLinkBefore (&ent->area, &node->trigger_edicts);
	else
		InsertLinkBefore (&ent->area, &node->solid_edicts);

}
Exemplo n.º 12
0
/*
===============
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 );
		}

	}
Exemplo n.º 13
0
//-----------------------------------------------------------------------------
// Purpose: Builds the cluster list for an entity
// Input  : *pEdict - 
//-----------------------------------------------------------------------------
void SV_BuildEntityClusterList( edict_t *pEdict )
{
	int		i, j;
	int		topnode;
	int		leafCount;
	int		leafs[MAX_TOTAL_ENT_LEAFS], clusters[MAX_TOTAL_ENT_LEAFS];
	int		area;

	IServerEntity *serverEntity = pEdict->GetIServerEntity();
	Assert( serverEntity );
	if ( !serverEntity )
		return;

	pEdict->clusterCount = 0;
	topnode = -1;
	pEdict->areanum = 0;
	pEdict->areanum2 = 0;

	//get all leafs, including solids
	leafCount = CM_BoxLeafnums( serverEntity->GetAbsMins(), serverEntity->GetAbsMaxs(), leafs, MAX_TOTAL_ENT_LEAFS, &topnode );

	// set areas
	for ( i = 0; i < leafCount; i++ )
	{
		clusters[i] = CM_LeafCluster( leafs[i] );
		area = CM_LeafArea( leafs[i] );
		if ( area )
		{	// doors may legally straggle two areas,
			// but nothing should evern need more than that
			if ( pEdict->areanum && pEdict->areanum != area )
			{
				if ( pEdict->areanum2 && pEdict->areanum2 != area && sv.state == ss_loading )
				{
					Con_DPrintf ("Object touching 3 areas at %f %f %f\n",
						serverEntity->GetAbsMins()[0], serverEntity->GetAbsMins()[1], serverEntity->GetAbsMins()[2]);
				}
				pEdict->areanum2 = area;
			}
			else
			{
				pEdict->areanum = area;
			}
		}
	}

	pEdict->headnode = topnode;	// save headnode

	if ( leafCount >= MAX_TOTAL_ENT_LEAFS )
	{	// assume we missed some leafs, and mark by headnode
		pEdict->clusterCount = -1;
	}
	else
	{
		for ( i = 0; i < leafCount; i++ )
		{
			if (clusters[i] == -1)
				continue;		// not a visible leaf

			for ( j = 0; j < i; j++ )
			{
				if (clusters[j] == clusters[i])
					break;
			}

			if ( j == i )
			{
				if ( pEdict->clusterCount == MAX_ENT_CLUSTERS )
				{	// assume we missed some leafs, and mark by headnode
					pEdict->clusterCount = -1;
					break;
				}

				pEdict->clusters[pEdict->clusterCount++] = clusters[i];
			}
		}
	}
}
Exemplo n.º 14
0
/*
===============
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 );
        }

    }
Exemplo n.º 15
0
static inline int PF_CM_LeafCluster( int leafnum ) {
	return CM_LeafCluster( svs.cms, leafnum );
}
Exemplo n.º 16
0
/*
===============
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
		}
	}
}
Exemplo n.º 17
0
static void SVT3_AddEntitiesVisibleFromPoint( int clientNum, const vec3_t origin, q3clientSnapshot_t* frame,
	snapshotEntityNumbers_t* eNums, bool portal, bool localClient ) {
	// 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;
	}

	int leafnum = CM_PointLeafnum( origin );
	int clientarea = CM_LeafArea( leafnum );
	int clientcluster = CM_LeafCluster( leafnum );

	// calculate the visible areas
	frame->areabytes = CM_WriteAreaBits( frame->areabits, clientarea );

	byte* clientpvs = CM_ClusterPVS( clientcluster );

	idEntity3* playerEnt = SVT3_EntityNum( clientNum );
	if ( playerEnt->GetSvFlagSelfPortal() ) {
		SVT3_AddEntitiesVisibleFromPoint( clientNum, playerEnt->GetOrigin2(), frame, eNums, portal, localClient );
	}

	int l;
	for ( int e = 0; e < sv.q3_num_entities; e++ ) {
		idEntity3* ent = SVT3_EntityNum( e );

		// never send entities that aren't linked in
		if ( !ent->GetLinked() ) {
			continue;
		}

		if ( ent->GetNumber() != e ) {
			common->DPrintf( "FIXING ENT->S.NUMBER!!!\n" );
			ent->SetNumber( e );
		}

		// entities can be flagged to explicitly not be sent to the client
		if ( ent->GetSvFlags() & Q3SVF_NOCLIENT ) {
			continue;
		}

		// entities can be flagged to be sent to only one client
		if ( ent->GetSvFlagSingleClient() ) {
			if ( ent->GetSingleClient() != clientNum ) {
				continue;
			}
		}
		// entities can be flagged to be sent to everyone but one client
		if ( ent->GetSvFlagNotSingleClient() ) {
			if ( ent->GetSingleClient() == clientNum ) {
				continue;
			}
		}
		// entities can be flagged to be sent to a given mask of clients
		if ( ent->GetSvFlagClientMask() ) {
			if ( clientNum >= 32 ) {
				common->Error( "Q3SVF_CLIENTMASK: cientNum > 32\n" );
			}
			if ( ~ent->GetSingleClient() & ( 1 << clientNum ) ) {
				continue;
			}
		}

		q3svEntity_t* svEnt = &sv.q3_svEntities[ e ];

		// don't double add an entity through portals
		if ( svEnt->snapshotCounter == sv.q3_snapshotCounter ) {
			continue;
		}

		// if this client is viewing from a camera, only add ents visible from portal ents
		if ( playerEnt->GetEFlagViewingCamera() && !portal ) {
			if ( ent->GetSvFlags() & Q3SVF_PORTAL ) {
				SVT3_AddEntToSnapshot( clientNum, svEnt, ent, eNums );
				SVT3_AddEntitiesVisibleFromPoint( clientNum, ent->GetOrigin2(), frame, eNums, true, localClient );
			}
			continue;
		}

		// broadcast entities are always sent
		if ( ent->GetSvFlags() & Q3SVF_BROADCAST ) {
			SVT3_AddEntToSnapshot( clientNum, svEnt, ent, eNums );
			continue;
		}

		byte* bitvector = clientpvs;

		// Gordon: just check origin for being in pvs, ignore bmodel extents
		if ( ent->GetSvFlagIgnoreBModelExtents() ) {
			if ( bitvector[ svEnt->originCluster >> 3 ] & ( 1 << ( svEnt->originCluster & 7 ) ) ) {
				SVT3_AddEntToSnapshot( clientNum, 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
			}
		}

		// check individual leafs
		if ( !svEnt->numClusters ) {
			goto notVisible;
		}
		l = 0;
		int i;
		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->GetSvFlags() & WOLFSVF_VISDUMMY ) {
			//find master;
			idEntity3* ment = SVT3_EntityNum( ent->GetOtherEntityNum() );

			q3svEntity_t* master = &sv.q3_svEntities[ ent->GetOtherEntityNum() ];

			if ( master->snapshotCounter == sv.q3_snapshotCounter || !ment->GetLinked() ) {
				goto notVisible;
			}

			SVT3_AddEntToSnapshot( clientNum, master, ment, eNums );
			// master needs to be added, but not this dummy ent
			goto notVisible;
		} else if ( ent->GetSvFlags() & WOLFSVF_VISDUMMY_MULTIPLE ) {
			{
				for ( int h = 0; h < sv.q3_num_entities; h++ ) {
					idEntity3* ment = SVT3_EntityNum( h );

					if ( ment == ent ) {
						continue;
					}

					q3svEntity_t* master = &sv.q3_svEntities[ h ];

					if ( !ment->GetLinked() ) {
						continue;
					}

					if ( ment->GetNumber() != h ) {
						common->DPrintf( "FIXING vis dummy multiple ment->S.NUMBER!!!\n" );
						ment->SetNumber( h );
					}

					if ( ment->GetSvFlags() & Q3SVF_NOCLIENT ) {
						continue;
					}

					if ( master->snapshotCounter == sv.q3_snapshotCounter ) {
						continue;
					}

					if ( ment->GetOtherEntityNum() == ent->GetNumber() ) {
						SVT3_AddEntToSnapshot( clientNum, master, ment, eNums );
					}
				}
				goto notVisible;
			}
		}

		// add it
		SVT3_AddEntToSnapshot( clientNum, svEnt, ent, eNums );

		// if its a portal entity, add everything visible from its camera position
		if ( ent->GetSvFlags() & Q3SVF_PORTAL ) {
			if ( ent->GetGeneric1() ) {
				vec3_t dir;
				VectorSubtract( ent->GetOrigin(), origin, dir );
				if ( VectorLengthSquared( dir ) > ( float )ent->GetGeneric1() * ent->GetGeneric1() ) {
					continue;
				}
			}
			SVT3_AddEntitiesVisibleFromPoint( clientNum, ent->GetOrigin2(), frame, eNums, true, 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 ( GGameType & ( GAME_WolfSP | GAME_WolfMP ) && svt3_gametype->integer == Q3GT_SINGLE_PLAYER && localClient ) {
			if ( ent->GetEventTime() == svs.q3_time ) {
				ent->SetEFlagNoDraw();		// don't draw, just process event
				SVT3_AddEntToSnapshot( clientNum, svEnt, ent, eNums );
			} else if ( ent->GetEType() == Q3ET_PLAYER ) {
				// keep players around if they are alive and active (so sounds dont get messed up)
				if ( !ent->GetEFlagDead() ) {
					ent->SetEFlagNoDraw();		// don't draw, just process events and sounds
					SVT3_AddEntToSnapshot( clientNum, svEnt, ent, eNums );
				}
			}
		}
	}
Exemplo n.º 18
0
/*
===============
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 );
		}

	}
Exemplo n.º 19
0
/*
===============
SV_LinkEdict

General purpose routine shared between game DLL and MVD code.
Links entity to PVS leafs.
===============
*/
void SV_LinkEdict(cm_t *cm, edict_t *ent)
{
    mleaf_t     *leafs[MAX_TOTAL_ENT_LEAFS];
    int         clusters[MAX_TOTAL_ENT_LEAFS];
    int         num_leafs;
    int         i, j;
    int         area;
    mnode_t     *topnode;

    // set the size
    VectorSubtract(ent->maxs, ent->mins, ent->size);

    // set the abs box
    if (ent->solid == SOLID_BSP &&
        (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2])) {
        // expand for rotation
        float   max, v;
        int     i;

        max = 0;
        for (i = 0; i < 3; i++) {
            v = Q_fabs(ent->mins[i]);
            if (v > max)
                max = v;
            v = Q_fabs(ent->maxs[i]);
            if (v > max)
                max = v;
        }
        for (i = 0; i < 3; i++) {
            ent->absmin[i] = ent->s.origin[i] - max;
            ent->absmax[i] = ent->s.origin[i] + max;
        }
    } else {
        // normal
        VectorAdd(ent->s.origin, ent->mins, ent->absmin);
        VectorAdd(ent->s.origin, ent->maxs, ent->absmax);
    }

    // because movement is clipped an epsilon away from an actual edge,
    // we must fully check even when bounding boxes don't quite touch
    ent->absmin[0] -= 1;
    ent->absmin[1] -= 1;
    ent->absmin[2] -= 1;
    ent->absmax[0] += 1;
    ent->absmax[1] += 1;
    ent->absmax[2] += 1;

// link to PVS leafs
    ent->num_clusters = 0;
    ent->areanum = 0;
    ent->areanum2 = 0;

    //get all leafs, including solids
    num_leafs = CM_BoxLeafs(cm, ent->absmin, ent->absmax,
                            leafs, MAX_TOTAL_ENT_LEAFS, &topnode);

    // set areas
    for (i = 0; i < num_leafs; i++) {
        clusters[i] = CM_LeafCluster(leafs[i]);
        area = CM_LeafArea(leafs[i]);
        if (area) {
            // doors may legally straggle two areas,
            // but nothing should evern need more than that
            if (ent->areanum && ent->areanum != area) {
                if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading) {
                    Com_DPrintf("Object touching 3 areas at %f %f %f\n",
                                ent->absmin[0], ent->absmin[1], ent->absmin[2]);
                }
                ent->areanum2 = area;
            } else
                ent->areanum = area;
        }
    }

    if (num_leafs >= MAX_TOTAL_ENT_LEAFS) {
        // assume we missed some leafs, and mark by headnode
        ent->num_clusters = -1;
        ent->headnode = CM_NumNode(cm, topnode);
    } else {
        ent->num_clusters = 0;
        for (i = 0; i < num_leafs; i++) {
            if (clusters[i] == -1)
                continue;        // not a visible leaf
            for (j = 0; j < i; j++)
                if (clusters[j] == clusters[i])
                    break;
            if (j == i) {
                if (ent->num_clusters == MAX_ENT_CLUSTERS) {
                    // assume we missed some leafs, and mark by headnode
                    ent->num_clusters = -1;
                    ent->headnode = CM_NumNode(cm, topnode);
                    break;
                }

                ent->clusternums[ent->num_clusters++] = clusters[i];
            }
        }
    }
}
Exemplo n.º 20
0
bool CLT3_InPvs( const vec3_t p1, const vec3_t p2 ) {
	byte* vis = CM_ClusterPVS( CM_LeafCluster( CM_PointLeafnum( p1 ) ) );
	int cluster = CM_LeafCluster( CM_PointLeafnum( p2 ) );
	return !!( vis[ cluster >> 3 ] & ( 1 << ( cluster & 7 ) ) );
}
Exemplo n.º 21
0
/*
===============
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 );
				}
			}
		}

	}
Exemplo n.º 22
0
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;
	}
Exemplo n.º 23
0
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 );
	}
}