Exemple #1
0
bool GetSoundParams(CSoundParameters *soundParams, const char *soundname, cell_t entindex)
{
	if ( !soundname[0] )
		return false;

#if SOURCE_ENGINE >= SE_PORTAL2
	HSOUNDSCRIPTHASH index = (HSOUNDSCRIPTHASH)soundemitterbase->GetSoundIndex(soundname);
#else
	HSOUNDSCRIPTHANDLE index = (HSOUNDSCRIPTHANDLE)soundemitterbase->GetSoundIndex(soundname);
#endif
	if (!soundemitterbase->IsValidIndex(index))
		return false;

	gender_t gender = GENDER_NONE;

	// I don't know if gender applies to any mutliplayer games, but just in case...
	// Of course, if it's SOUND_FROM_PLAYER, we have no idea which gender it is
	int ent = SoundReferenceToIndex(entindex);
	if (ent > 0)
	{
		edict_t *edict = gamehelpers->EdictOfIndex(ent);
		if (edict != NULL && !edict->IsFree())
		{
			IServerEntity *serverEnt = edict->GetIServerEntity();
			if (serverEnt != NULL)
			{
				const char *actormodel = STRING(serverEnt->GetModelName());
				gender = soundemitterbase->GetActorGender(actormodel);
			}
		}
	}

	return soundemitterbase->GetParametersForSoundEx(soundname, index, *soundParams, gender);
}
	IterationRetval_t EnumElement( IHandleEntity *pHandleEntity )
	{
		// skip static props, the game DLL doesn't care about them
		if ( StaticPropMgr()->IsStaticProp( pHandleEntity ) )
			return ITERATION_CONTINUE;

		IServerNetworkable *pNetworkable = static_cast< IServerNetworkable* >( pHandleEntity );
		Assert( pNetworkable );

		// Convert the user ID to and edict_t*...
		edict_t* pTouch = pNetworkable->GetEdict();

		// Can't ever touch itself because it's in the other list
		if ( pTouch == m_pTriggerEntity )
			return ITERATION_CONTINUE;

		IServerEntity *serverEntity = pTouch->GetIServerEntity();
		if ( !serverEntity )
			return ITERATION_CONTINUE;

		if ( m_headnode >= 0 )
		{
			Vector vecMins, vecMaxs;
			CM_WorldAlignBounds( serverEntity->GetCollideable(), &vecMins, &vecMaxs );
			int contents = CM_TransformedBoxContents( serverEntity->GetAbsOrigin(), 
					vecMins, vecMaxs, m_headnode, m_origin, m_angles );
			if ( !(contents & MASK_SOLID) )
				return ITERATION_CONTINUE;
		}

		m_TouchedEntities.AddToTail( pTouch );

		return ITERATION_CONTINUE;
	}
Exemple #3
0
int CheckBaseHandle(CBaseHandle &hndl)
{
	if (!hndl.IsValid())
	{
		return -1;
	}

	int index = hndl.GetEntryIndex();

	edict_t *pStoredEdict;

	pStoredEdict = engine->PEntityOfEntIndex(index);

	if (pStoredEdict == NULL)
	{
		return -1;
	}

	IServerEntity *pSE = pStoredEdict->GetIServerEntity();

	if (pSE == NULL)
	{
		return -1;
	}

	if (pSE->GetRefEHandle() != hndl)
	{
		return -1;
	}

	return index;
}
Exemple #4
0
//-----------------------------------------------------------------------------
// Purpose: Hack to allow this code to run on a client that's not connected to a server
//  (i.e., demo playback, or multiplayer game )
// Input  : ent_num -
//			origin -
//			mins -
//			maxs -
// Output : static void
//-----------------------------------------------------------------------------
static bool GetEntityOriginClientOrServer( int ent_num, Vector& origin )
{
    // Assume failure
    origin.Init();

    if ( sv.active )
    {
        edict_t *e = EDICT_NUM( ent_num );
        if ( e )
        {
            IServerEntity *serverEntity = e->GetIServerEntity();
            if ( serverEntity )
            {
                CM_WorldSpaceCenter( serverEntity->GetCollideable(), &origin );
            }

            return true;
        }
    }
    else
    {
        IClientEntity *clent = entitylist->GetClientEntity( ent_num );
        if ( clent )
        {
            CM_WorldSpaceCenter( clent->GetClientCollideable(), &origin );
            return true;
        }
    }

    return false;
}
	CTriggerMoved( edict_t *pTriggerEntity ) : m_TouchedEntities( 8, 8 )
	{
		m_headnode = -1;
		m_pTriggerEntity = pTriggerEntity;
		IServerEntity *pServerTrigger = pTriggerEntity->GetIServerEntity();
		if ( !pServerTrigger )
		{
			m_origin.Init();
			m_angles.Init();
		}
		else
		{
			model_t *pModel = sv.GetModel( pServerTrigger->GetModelIndex() );
			if ( pModel && pModel->type == mod_brush )
			{
				m_headnode = SV_HullForEntity( pTriggerEntity );
			}
			m_origin = pServerTrigger->GetAbsOrigin();
			m_angles = pServerTrigger->GetAbsAngles();
		}
	}
//-----------------------------------------------------------------------------
// Purpose: returns a headnode that can be used to collide against this entity
// Input  : *ent - 
// Output : int
//-----------------------------------------------------------------------------
int SV_HullForEntity( edict_t *ent )
{
	model_t		*model;
	IServerEntity *serverEntity = ent->GetIServerEntity();
	Assert( serverEntity );
	if ( !serverEntity )
		return -1;

	int modelindex = serverEntity->GetModelIndex();
	model = sv.GetModel( modelindex );

	if (model->type == mod_brush)
	{
		cmodel_t *pCModel = CM_InlineModelNumber( modelindex - 1 );

		return pCModel->headnode;
	}

	ICollideable *pCollideable = serverEntity->GetCollideable();
	Vector vecMins = pCollideable->WorldAlignMins();
	Vector vecMaxs = pCollideable->WorldAlignMaxs();
	return CM_HeadnodeForBoxHull( vecMins, vecMaxs );
}
edict_t *CHalfLife2::GetHandleEntity(CBaseHandle &hndl)
{
	if (!hndl.IsValid())
	{
		return NULL;
	}

	int index = hndl.GetEntryIndex();

	edict_t *pStoredEdict;
	CBaseEntity *pStoredEntity;

	if (!IndexToAThings(index, &pStoredEntity, &pStoredEdict))
	{
		return NULL;
	}

	if (pStoredEdict == NULL || pStoredEntity == NULL)
	{
		return NULL;
	}

	IServerEntity *pSE = pStoredEdict->GetIServerEntity();

	if (pSE == NULL)
	{
		return NULL;
	}

	if (pSE->GetRefEHandle() != hndl)
	{
		return NULL;
	}

	return pStoredEdict;
}
	IterationRetval_t EnumElement( IHandleEntity *pHandleEntity )
	{
		// Static props should never be in the trigger list 
		Assert( !StaticPropMgr()->IsStaticProp( pHandleEntity ) );

		IServerNetworkable *pNetworkable = static_cast<IServerNetworkable*>( pHandleEntity );
		Assert( pNetworkable );

		// Convert the IHandleEntity to an edict_t*...
		// Context is the thing we're testing everything against		
		edict_t* pTouch = pNetworkable->GetEdict();

		// Can't bump against itself
		if ( pTouch == m_pEnt )
			return ITERATION_CONTINUE;

		IServerEntity *serverEntity = pTouch->GetIServerEntity();
		if ( !serverEntity )
			return ITERATION_CONTINUE;

		// Hmmm.. everything in this list should be a trigger....
		ICollideable *pCollideable = serverEntity->GetCollideable();
		Assert(pCollideable->GetSolidFlags() & FSOLID_TRIGGER );
		if ( (pCollideable->GetSolidFlags() & FSOLID_TRIGGER) == 0 )
			return ITERATION_CONTINUE;

		model_t* pModel = sv.GetModel( pCollideable->GetCollisionModelIndex() );
		if ( pModel && pModel->type == mod_brush )
		{
			int headnode = SV_HullForEntity( pTouch );

			int contents;
			if (!m_Ray.m_IsSwept)
			{
				contents = CM_TransformedBoxContents( m_Ray.m_Start, m_mins, m_maxs,
					headnode, serverEntity->GetAbsOrigin(), serverEntity->GetAbsAngles() );
			}
			else
			{
				trace_t trace;
				CM_TransformedBoxTrace( m_Ray, headnode, MASK_ALL, serverEntity->GetAbsOrigin(), 
					serverEntity->GetAbsAngles(), trace );
				contents = trace.contents;
			}

			if ( !(contents & MASK_SOLID) )
				return ITERATION_CONTINUE;
		}

		m_TouchedEntities.AddToTail( pTouch );

		return ITERATION_CONTINUE;
	}
	CTouchLinks( edict_t* pEnt, const Vector* pPrevAbsOrigin ) : m_TouchedEntities( 8, 8 )
	{
		m_pEnt = pEnt;
		IServerEntity *serverEntity = pEnt->GetIServerEntity();
		Assert( serverEntity );
		if (pPrevAbsOrigin)
		{
			Vector mins, maxs;

			VectorSubtract( serverEntity->GetAbsMins(), serverEntity->GetAbsOrigin(), mins );
			VectorSubtract( serverEntity->GetAbsMaxs(), serverEntity->GetAbsOrigin(), maxs );

			m_Ray.Init( *pPrevAbsOrigin, serverEntity->GetAbsOrigin(), mins, maxs );
		}
		else
		{
			m_Ray.m_Start = serverEntity->GetAbsOrigin();
			m_mins = serverEntity->GetAbsMins() - m_Ray.m_Start;
			m_maxs = serverEntity->GetAbsMaxs() - m_Ray.m_Start;
			m_Ray.m_IsSwept = false;
		}
	}
/*
===============
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( );
			}
		}
	}
}
//-----------------------------------------------------------------------------
// 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];
			}
		}
	}
}
//-----------------------------------------------------------------------------
// Writes the compressed packet of entities to all clients
//-----------------------------------------------------------------------------
void SV_ComputeClientPacks( 
	int clientCount, 
	client_t** clients,
	CFrameSnapshot *snapshot, 
	client_frame_t **pPack
	)
{
	VPROF( "SV_ComputeClientPacks" );

	
	ClientPackInfo_t info[MAX_CLIENTS];

	// Do some setup for each client
	int	iClient;
	for (iClient = 0; iClient < clientCount; ++iClient)
	{
		ClientPackInfo_t *pInfo = &info[iClient];


		// This helps handle it if they turn cl_LocalNetworkBackdoor on and off (which is useful to do for profiling).
		SV_HandleLocalNetworkBackdoorChange( clients[iClient] );

		// This will force network string table updates for local client to go through the backdoor if it's active
		SV_CheckDirectUpdate( clients[iClient] );

		SV_ComputeClientPackInfo( clients[iClient], pInfo );

		// This is the frame we are creating, i.e., the next
		// frame after the last one that the client acknowledged
		client_frame_t& frame = clients[iClient]->frames[clients[iClient]->netchan.outgoing_sequence & SV_UPDATE_MASK];
		pPack[iClient] = &frame;

		SV_SetupPack( pPack[iClient], snapshot );

		// Clear the 'transmit edict' bits for this ent for this client.
		memset( pInfo->m_EdictBits, 0, PAD_NUMBER( sv.num_edicts, 8 ) / 8 );
		pInfo->m_pPVS = pInfo->m_PVS;
		pInfo->m_pEdictBits = pInfo->m_EdictBits;

		// Since area to area visibility is determined by each player's PVS, copy
		//  the area network lookups into the ClientPackInfo_t
		pInfo->m_AreasNetworked.RemoveAll();
		int areaCount = g_AreasNetworked.Count();
		for ( int i = 0; i < areaCount; i++ )
		{
			pInfo->m_AreasNetworked.AddToTail( g_AreasNetworked[ i ] );
		}
	}


	// Figure out which entities should be sent.
	int validEdicts[MAX_EDICTS];
	int nValidEdicts = 0;
	for ( int iEdict=0; iEdict < sv.num_edicts; iEdict++ )
	{
		edict_t* ent = SV_GetEdictToTransmit( iEdict, snapshot );
		if ( !ent || !ent->m_pEnt )
			continue;

		// Get the edict send table
		SendTable* pSendTable = GetEntSendTable( ent );
		assert( pSendTable );
		if ( !pSendTable )
			continue;

		validEdicts[nValidEdicts++] = iEdict;

		for ( int iClient=0; iClient < clientCount; iClient++ )
		{		
			ClientPackInfo_t *pInfo = &info[iClient];
			Assert( pInfo );

			int areaCount = pInfo->m_AreasNetworked.Count();

			for ( int iArea=0; iArea < areaCount; iArea++ )
			{
				// If the edict is already marked to send to this client, we don't need to call CheckTransmit on it.
				if ( pInfo->WillTransmit( iEdict ) )
					break;

				pInfo->m_iArea = pInfo->m_AreasNetworked[ iArea ];
				CServerDTITimer timer( pSendTable, SERVERDTI_SHOULDTRANSMIT );
				ent->m_pEnt->CheckTransmit( pInfo );
			}
		}
	}
		

#ifndef SWDS
	int saveTicks = cl.tickcount;
#endif

	if ( g_pLocalNetworkBackdoor )
	{
		g_pLocalNetworkBackdoor->StartEntityStateUpdate();

#ifndef SWDS
		cl.tickcount = sv.tickcount;
		g_ClientGlobalVariables.tickcount = cl.tickcount;
		g_ClientGlobalVariables.curtime = cl.gettime();
#endif
	}
	

	// Send client all active entities in the pvs
	for ( int iValidEdict=0; iValidEdict < nValidEdicts; iValidEdict++ )
	{
		int e = validEdicts[iValidEdict];
		edict_t* ent = SV_GetEdictToTransmit(e, snapshot);
		SendTable* pSendTable = GetEntSendTable( ent );

		// Check to see if the entity changed this frame...
		EntityChange_t changeType = ent->m_pEnt->DetectNetworkStateChanges();
		
		ServerDTI_RegisterNetworkStateChange( pSendTable, changeType );

		// Have we packed this entity this frame?
		bool packedThisEntity = false;
		IServerEntity *serverEntity = ent->GetIServerEntity();
		if ( serverEntity )
		{
			serverEntity->SetSentLastFrame( false );
		}

		// Compute the entity bit + byte for the entity_in_pvs bitfield
		int entityByte = e >> 3;
		byte entityBit = ( 1 << ( e & 7 ) );

		for (int i = 0; i < clientCount; ++i )
		{
			ClientPackInfo_t *pInfo = &info[i];

			if ( g_pLocalNetworkBackdoor )
			{
				// this is a bit of a hack to ensure that we get a "preview" of the
				//  packet timstamp that the server will send so that things that
				//  are encoded relative to packet time will be correct


				int serialNum = ent->m_pEnt->GetRefEHandle().GetSerialNumber() & (1 << NUM_NETWORKED_EHANDLE_SERIAL_NUMBER_BITS) - 1;

				if( pInfo->WillTransmit( e ) )
				{
					CServerDTITimer timer( pSendTable, SERVERDTI_ENCODE );
					
					// If we're using the fast path for a single-player game, just pass the entity
					// directly over to the client.
					ServerClass *pClass = ent->m_pEnt->GetServerClass();
					g_pLocalNetworkBackdoor->EntState( e, serialNum, pClass->m_ClassID, pSendTable, ent->m_pEnt, changeType != ENTITY_CHANGE_NONE );

					// Indicate we've actually put the changes into the pack
					ent->m_pEnt->ResetNetworkStateChanges();
				}
				else
				{
					// Notify the client that the ent is still alive, but its ShouldTransmit returned false.
					g_pLocalNetworkBackdoor->EntityDormant( e, serialNum );
				}
			}
			else
			{
				if( !pInfo->WillTransmit( e ) )
					continue;

				// Mark that this player will have seen this entity created
				// (i.e., sent, at least once)
				ent->entity_created |= info[i].m_ClientBit;
				pPack[i]->entity_in_pvs[ entityByte ] |= entityBit;

				// Check to see if it's already been packed this frame...
				// If it hasn't, then pack it in, baby!
				if ( !packedThisEntity )
				{
					packedThisEntity = true;
					SV_PackEntity( e, ent, pSendTable, changeType, snapshot );
					ent->m_pEnt->ResetNetworkStateChanges();
				}
			}

			// We've got one more entity in this pack.
			++pPack[i]->entities.num_entities;

			// Now this is our biggest ent index in the pack
			pPack[i]->entities.max_entities = e;
		}
	}

	if ( g_pLocalNetworkBackdoor )
	{
		g_pLocalNetworkBackdoor->EndEntityStateUpdate();

#ifndef SWDS
		cl.tickcount = saveTicks;
		g_ClientGlobalVariables.tickcount = cl.tickcount;
		g_ClientGlobalVariables.curtime = cl.gettime();
#endif
	}
}