Exemplo n.º 1
0
//-----------------------------------------------------------------------------
// Lets clients know about all entities in a box
//-----------------------------------------------------------------------------
void CEngineTrace::EnumerateEntities( const Vector &vecAbsMins, const Vector &vecAbsMaxs, IEntityEnumerator *pEnumerator )
{
	// FIXME: If we store CBaseHandles directly in the spatial partition, this method
	// basically becomes obsolete. The spatial partition can be queried directly.
	CEnumerationFilter enumerator( this, pEnumerator );
	SpatialPartition()->EnumerateElementsInBox( SpatialPartitionMask(),
		vecAbsMins, vecAbsMaxs, false, &enumerator );
}
void CStaticProp::RemovePropFromKDTree()
{
	// Release the spatial partition handle
	if ( m_Partition != PARTITION_INVALID_HANDLE )
	{
		SpatialPartition()->DestroyHandle( m_Partition );
		m_Partition = PARTITION_INVALID_HANDLE;
	}
}
Exemplo n.º 3
0
//-----------------------------------------------------------------------------
// Enumerates over all entities along a ray
// If triggers == true, it enumerates all triggers along a ray
//-----------------------------------------------------------------------------
void CEngineTrace::EnumerateEntities( const Ray_t &ray, bool bTriggers, IEntityEnumerator *pEnumerator )
{
	// FIXME: If we store CBaseHandles directly in the spatial partition, this method
	// basically becomes obsolete. The spatial partition can be queried directly.
	CEnumerationFilter enumerator( this, pEnumerator );

	int fMask = !bTriggers ? SpatialPartitionMask() : SpatialPartitionTriggerMask();

	// NOTE: Triggers currently don't exist on the client
	if (fMask)
	{
		SpatialPartition()->EnumerateElementsAlongRay( fMask, ray, false, &enumerator );
	}
}
Exemplo n.º 4
0
/*
===============
SV_ClearWorld

===============
*/
void SV_ClearWorld (void)
{
	// Clean up static props from the previous level
	StaticPropMgr()->LevelShutdown();

	for ( int i = 0; i < 3; i++ )
	{
		if ( host_state.worldmodel->mins[i] < MIN_COORD_INTEGER || host_state.worldmodel->maxs[i] > MAX_COORD_INTEGER )
		{
			Host_EndGame("Map coordinate extents are too large!!\nCheck for errors!\n" );
		}
	}
	SpatialPartition()->Init( host_state.worldmodel->mins, host_state.worldmodel->maxs );

	// Load all static props into the spatial partition
	StaticPropMgr()->LevelInit();
}
Exemplo n.º 5
0
//-----------------------------------------------------------------------------
// Returns the contents mask at a particular world-space position
//-----------------------------------------------------------------------------
int	CEngineTrace::GetPointContents( const Vector &vecAbsPosition, IHandleEntity** ppEntity )
{
	// First check the collision model
	int nContents = CM_PointContents( vecAbsPosition, 0 );
	if ( nContents & MASK_CURRENT )
	{
		nContents = CONTENTS_WATER;
	}
	
	if ( nContents != CONTENTS_SOLID )
	{
		CPointContentsEnum contentsEnum(this, vecAbsPosition);
		SpatialPartition()->EnumerateElementsAtPoint( SpatialPartitionMask(),
			vecAbsPosition, false, &contentsEnum );

		int nEntityContents = contentsEnum.m_Contents;
		if ( nEntityContents & MASK_CURRENT )
			nContents = CONTENTS_WATER;
		if ( nEntityContents != CONTENTS_EMPTY )
		{
			if (ppEntity)
			{
				*ppEntity = contentsEnum.m_pCollide->GetEntityHandle();
			}

			return nEntityContents;
		}
	}

	if (ppEntity)
	{
		*ppEntity = GetWorldCollideable()->GetEntityHandle();
	}

	return nContents;
}
Exemplo n.º 6
0
/*
===============
SV_LinkEdict

===============
*/
void SV_LinkEdict( edict_t *ent, qboolean touch_triggers, const Vector* pPrevAbsOrigin )
{
	IServerEntity *pServerEntity = ent->GetIServerEntity();
	if ( !pServerEntity )
		return;		
	
	// Remove it from whatever lists it may be in at the moment
	// We'll re-add it below if we need to.
	if (ent->partition != PARTITION_INVALID_HANDLE)
	{
		SpatialPartition()->Remove( ent->partition );
	}

	if (ent->free)
		return;

	if (ent == sv.edicts)
		return;		// don't add the world

	pServerEntity->CalcAbsolutePosition();

	// set the abs box
	pServerEntity->SetObjectCollisionBox();
	
	// link to PVS leafs
	SV_BuildEntityClusterList( ent );

	// Update KD tree information
	ICollideable *pCollide = pServerEntity->GetCollideable();
	if (ent->partition == PARTITION_INVALID_HANDLE)
	{
		// Here, we haven't added the entity to the partition before
		// So we have to make a new partition handle.
		ent->partition = SpatialPartition()->CreateHandle( pCollide->GetEntityHandle() );
	}

	// Here, we indicate the entity has moved. Note that this call does
	// some fast early-outing to prevent unnecessary work
	SpatialPartition()->ElementMoved( ent->partition, pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs() );

	// Make sure it's in the list of all entities
	SpatialPartition()->Insert( PARTITION_ENGINE_NON_STATIC_EDICTS, ent->partition );

	SolidType_t iSolid = pCollide->GetSolid();
	int nSolidFlags = pCollide->GetSolidFlags();
	bool bIsSolid = IsSolid( iSolid, nSolidFlags ) || ((nSolidFlags & FSOLID_TRIGGER) != 0);
	if ( !bIsSolid )
	{
		// If this ent's touch list isn't empty, it's transitioning to not solid
		if ( pServerEntity->IsCurrentlyTouching() )
		{
			// mark ent so that at the end of frame it will check to see if it's no longer touch ents
			pServerEntity->SetCheckUntouch( true );
		}
		return;
	}

	// Insert it into the appropriate lists.
	// We have to continually reinsert it because its solid type may have changed
	SpatialPartitionListMask_t mask = 0;
	if (( nSolidFlags & FSOLID_NOT_SOLID ) == 0)
	{
		mask |=	PARTITION_ENGINE_SOLID_EDICTS;
	}
	if (( nSolidFlags & FSOLID_TRIGGER ) != 0 )
	{
		mask |=	PARTITION_ENGINE_TRIGGER_EDICTS;
	}
	Assert( mask != 0 );
	SpatialPartition()->Insert( mask, ent->partition );

	if ( iSolid == SOLID_BSP ) 
	{
		model_t	*model = sv.GetModel( pServerEntity->GetModelIndex() );
		if ( !model && strlen( STRING( pServerEntity->GetModelName() ) ) == 0 ) 
		{
			Con_DPrintf( "Inserted %s with no model\n", STRING( ent->classname ) );
			return;
		}
	}

	// if touch_triggers, touch all entities at this node and descend for more
	if (touch_triggers)
	{
		// mark ent so that at the end of frame it will check to see if it's no longer touch ents
		pServerEntity->SetCheckUntouch( true );

		// If this is a trigger that's moved, then query the solid list instead
		if ( mask == PARTITION_ENGINE_TRIGGER_EDICTS )
		{
			CTriggerMoved triggerEnum( ent );

			SpatialPartition()->EnumerateElementsInBox( PARTITION_ENGINE_SOLID_EDICTS,
				pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs(), false, &triggerEnum );

			triggerEnum.HandleTouchedEntities( );
		}
		else
		{
			if (!pPrevAbsOrigin)
			{
				CTouchLinks touchEnumerator(ent, NULL);

				SpatialPartition()->EnumerateElementsInBox( PARTITION_ENGINE_TRIGGER_EDICTS,
					pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs(), false, &touchEnumerator );

				touchEnumerator.HandleTouchedEntities( );
			}
			else
			{
				CTouchLinks touchEnumerator(ent, pPrevAbsOrigin);

				// A version that checks against an extruded ray indicating the motion
				SpatialPartition()->EnumerateElementsAlongRay( PARTITION_ENGINE_TRIGGER_EDICTS,
					touchEnumerator.m_Ray, false, &touchEnumerator );

				touchEnumerator.HandleTouchedEntities( );
			}
		}
	}
}
Exemplo n.º 7
0
void SV_FastRelink( edict_t *ent, int tempHandle )
{
	SpatialPartition()->FastInsert( ent->partition, tempHandle );
}
Exemplo n.º 8
0
//-----------------------------------------------------------------------------
// Purpose: Temporarily unlink from the collision tree to perform some collision
//			operations and then put the object back in
// Input  : *ent - entity to fast unlink
//-----------------------------------------------------------------------------
int SV_FastUnlink( edict_t *ent )
{
	// Returns a temporary handle
	return SpatialPartition()->FastRemove( ent->partition );
}
Exemplo n.º 9
0
//-----------------------------------------------------------------------------
// A version that simply accepts a ray (can work as a traceline or tracehull)
//-----------------------------------------------------------------------------
void CEngineTrace::TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace )
{
	CTraceFilterHitAll traceFilter;
	if ( !pTraceFilter )
	{
		pTraceFilter = &traceFilter;
	}

	// Gather statistics.
	g_EngineStats.IncrementCountedStat( ENGINE_STATS_NUM_TRACE_LINES, 1 );
	MEASURE_TIMED_STAT( ENGINE_STATS_TRACE_LINE_TIME );
	
	CM_ClearTrace( pTrace );

	// Collide with the world.
	if ( pTraceFilter->GetTraceType() != TRACE_ENTITIES_ONLY )
	{
		ICollideable *pCollide = GetWorldCollideable();

		// Make sure the world entity is unrotated
		// FIXME: BAH! The !pCollide test here is because of
		// CStaticProp::PrecacheLighting.. it's occurring too early
		// need to fix that later
		Assert(!pCollide || pCollide->GetCollisionOrigin() == vec3_origin );
		Assert(!pCollide || pCollide->GetCollisionAngles() == vec3_angle );

		CM_BoxTrace( ray, 0, fMask, true, *pTrace );
		SetTraceEntity( pCollide, pTrace );

		// Blocked by the world.
		if ( pTrace->fraction == 0 )
			return;

		// Early out if we only trace against the world
		if ( pTraceFilter->GetTraceType() == TRACE_WORLD_ONLY )
			return;
	}

	// Save the world collision fraction.
	float flWorldFraction = pTrace->fraction;

	// Create a ray that extends only until we hit the world
	// and adjust the trace accordingly
	Ray_t entityRay = ray;
	entityRay.m_Delta *= pTrace->fraction;

	// We know this is safe because if pTrace->fraction == 0
	// we would have exited above
	pTrace->fractionleftsolid /= pTrace->fraction;
 	pTrace->fraction = 1.0;

	// Collide with entities along the ray
	// FIXME: Hitbox code causes this to be re-entrant for the IK stuff.
	// If we could eliminate that, this could be static and therefore
	// not have to reallocate memory all the time
	CEntitiesAlongRay enumerator;
	enumerator.Reset();
	SpatialPartition()->EnumerateElementsAlongRay( SpatialPartitionMask(), entityRay, false, &enumerator );

	bool bNoStaticProps = pTraceFilter->GetTraceType() == TRACE_ENTITIES_ONLY;
	bool bFilterStaticProps = pTraceFilter->GetTraceType() == TRACE_EVERYTHING_FILTER_PROPS;

	trace_t tr;
	ICollideable *pCollideable;
	const char *pDebugName;
	int nCount = enumerator.m_EntityHandles.Count();
	for ( int i = 0; i < nCount; ++i )
	{
		// Generate a collideable
		IHandleEntity *pHandleEntity = enumerator.m_EntityHandles[i];
		HandleEntityToCollideable( pHandleEntity, &pCollideable, &pDebugName );

		// Check for error condition
		if ( !IsSolid( pCollideable->GetSolid(), pCollideable->GetSolidFlags() ) )
		{
			char temp[1024];
			Q_snprintf(temp, sizeof( temp ), "%s in solid list (not solid)\n", pDebugName );
			Sys_Error (temp);
		}

		if ( !StaticPropMgr()->IsStaticProp( pHandleEntity ) )
		{
			if ( !pTraceFilter->ShouldHitEntity( pHandleEntity, fMask ) )
				continue;
		}
		else
		{
			// FIXME: Could remove this check here by
			// using a different spatial partition mask. Look into it
			// if we want more speedups here.
			if ( bNoStaticProps )
				continue;

			if ( bFilterStaticProps )
			{
				if ( !pTraceFilter->ShouldHitEntity( pHandleEntity, fMask ) )
					continue;
			}
		}

		ClipRayToCollideable( entityRay, fMask, pCollideable, &tr );

		// Make sure the ray is always shorter than it currently is
		ClipTraceToTrace( tr, pTrace );

		// Stop if we're in allsolid
		if (pTrace->allsolid)
			break;
	}

	// Fix up the fractions so they are appropriate given the original
	// unclipped-to-world ray
	pTrace->fraction *= flWorldFraction;
	pTrace->fractionleftsolid *= flWorldFraction;

#ifdef _DEBUG
	Vector vecOffset, vecEndTest;
	VectorAdd( ray.m_Start, ray.m_StartOffset, vecOffset );
	VectorMA( vecOffset, pTrace->fractionleftsolid, ray.m_Delta, vecEndTest );
	Assert( VectorsAreEqual( vecEndTest, pTrace->startpos, 0.1f ) );
	VectorMA( vecOffset, pTrace->fraction, ray.m_Delta, vecEndTest );
	Assert( VectorsAreEqual( vecEndTest, pTrace->endpos, 0.1f ) );
//	Assert( !ray.m_IsRay || pTrace->allsolid || pTrace->fraction >= pTrace->fractionleftsolid );
#endif

	if ( !ray.m_IsRay )
	{
		// Make sure no fractionleftsolid can be used with box sweeps
		VectorAdd( ray.m_Start, ray.m_StartOffset, pTrace->startpos );
		pTrace->fractionleftsolid = 0;

#ifdef _DEBUG
		pTrace->fractionleftsolid = VEC_T_NAN;
#endif
	}
}
Exemplo n.º 10
0
void CEngineTool::ElementMoved( SpatialPartitionHandle_t handle, const Vector& mins, const Vector& maxs )
{
	SpatialPartition()->ElementMoved( handle, mins, maxs );
}
Exemplo n.º 11
0
void CEngineTool::RemovePartitionQueryCallback( IPartitionQueryCallback *pQuery )
{
	SpatialPartition()->RemoveQueryCallback( pQuery );
}
Exemplo n.º 12
0
void CEngineTool::InstallPartitionQueryCallback( IPartitionQueryCallback *pQuery )
{
	SpatialPartition()->InstallQueryCallback( pQuery );
}
Exemplo n.º 13
0
void CEngineTool::DestroyPartitionHandle( SpatialPartitionHandle_t hPartition )
{
	SpatialPartition()->DestroyHandle( hPartition );
}
Exemplo n.º 14
0
SpatialPartitionHandle_t CEngineTool::CreatePartitionHandle( IHandleEntity *pEntity,
	SpatialPartitionListMask_t listMask, const Vector& mins, const Vector& maxs )
{
	return SpatialPartition()->CreateHandle( pEntity, listMask, mins, maxs );
}