Example #1
0
/*
===============
SV_UnlinkEntity

===============
*/
void SV_UnlinkEntity( sharedEntity_t *gEnt ) {
	svEntity_t		*ent;
	svEntity_t		*scan;
	worldSector_t	*ws;
	sharedPlayerState_t	*ps;

	ent = SV_SvEntityForGentity( gEnt );

	gEnt->r.linked = qfalse;
	if (gEnt->s.number < MAX_CLIENTS) {
		ps = SV_GameClientNum(gEnt->s.number);
		ps->linked = qfalse;
	}

	ws = ent->worldSector;
	if ( !ws ) {
		return;		// not linked in anywhere
	}
	ent->worldSector = NULL;

	if ( ws->entities == ent ) {
		ws->entities = ent->nextEntityInWorldSector;
		return;
	}

	for ( scan = ws->entities ; scan ; scan = scan->nextEntityInWorldSector ) {
		if ( scan->nextEntityInWorldSector == ent ) {
			scan->nextEntityInWorldSector = ent->nextEntityInWorldSector;
			return;
		}
	}

	Com_Printf( "WARNING: SV_UnlinkEntity: not found in worldSector\n" );
}
Example #2
0
void SV_UnlinkEntity( sharedEntity_t *gEnt ) {
	svEntity_t		*ent;
	svEntity_t		*scan;
	worldSector_t	*ws;

	ent = SV_SvEntityForGentity( gEnt );

	gEnt->r.linked = qfalse;

	ws = ent->worldSector;
	if ( !ws ) {
		return;		// not linked in anywhere
	}
	ent->worldSector = NULL;

	if ( ws->entities == ent ) {
		ws->entities = ent->nextEntityInWorldSector;
		return;
	}

	for ( scan = ws->entities ; scan ; scan = scan->nextEntityInWorldSector ) {
		if ( scan->nextEntityInWorldSector == ent ) {
			scan->nextEntityInWorldSector = ent->nextEntityInWorldSector;
			return;
		}
	}

	Com_Printf( "WARNING: SV_UnlinkEntity: not found in worldSector\n" );
}
Example #3
0
/*
 * SV_UnlinkEntity
 *
 */
void
SV_UnlinkEntity(Sharedent *gEnt)
{
	Svent				*ent;
	Svent				*scan;
	worldSector_t *ws;

	ent = SV_SvEntityForGentity(gEnt);

	gEnt->r.linked = qfalse;

	ws = ent->worldSector;
	if(!ws)
		return;		/* not linked in anywhere */
	ent->worldSector = NULL;

	if(ws->entities == ent){
		ws->entities = ent->nextEntityInWorldSector;
		return;
	}

	for(scan = ws->entities; scan; scan = scan->nextEntityInWorldSector)
		if(scan->nextEntityInWorldSector == ent){
			scan->nextEntityInWorldSector =
				ent->nextEntityInWorldSector;
			return;
		}

	comprintf("WARNING: SV_UnlinkEntity: not found in worldSector\n");
}
Example #4
0
/*
========================
SV_AdjustAreaPortalState
========================
*/
void SV_AdjustAreaPortalState(sharedEntity_t * ent, bool open) {
	svEntity_t *svEnt;

	svEnt = SV_SvEntityForGentity(ent);
	if(svEnt->areanum2 == -1) {
		return;
	}
	CM_AdjustAreaPortalState(svEnt->areanum, svEnt->areanum2, open);
}
Example #5
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);
        }
    }
Example #6
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;
}
Example #7
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;
	}
Example #8
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 );
			}
		}
	}
Example #9
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 );
		}

	}
Example #10
0
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 );
	}
}
Example #11
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 );
        }

    }
Example #12
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;
	}
Example #13
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 );
		}

	}
Example #14
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 );
		}

	}
Example #15
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 );
				}
			}
		}

	}
Example #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
		}
	}
}