From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/server/soundscape_system.cpp | 916 +++++++++++++++---------------- 1 file changed, 458 insertions(+), 458 deletions(-) (limited to 'mp/src/game/server/soundscape_system.cpp') diff --git a/mp/src/game/server/soundscape_system.cpp b/mp/src/game/server/soundscape_system.cpp index 571c49db..29b29402 100644 --- a/mp/src/game/server/soundscape_system.cpp +++ b/mp/src/game/server/soundscape_system.cpp @@ -1,458 +1,458 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - - -#include "cbase.h" -#include "soundscape_system.h" -#include "soundscape.h" -#include "KeyValues.h" -#include "filesystem.h" -#include "game.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - -#define SOUNDSCAPE_MANIFEST_FILE "scripts/soundscapes_manifest.txt" - -CON_COMMAND(soundscape_flush, "Flushes the server & client side soundscapes") -{ - CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() ); - if ( engine->IsDedicatedServer() ) - { - // If it's a dedicated server, only the server console can run this. - if ( pPlayer ) - return; - } - else - { - // If it's a listen server, only the listen server host can run this. - if ( !pPlayer || pPlayer != UTIL_GetListenServerHost() ) - return; - } - - g_SoundscapeSystem.FlushSoundscapes(); // don't bother forgetting about the entities - g_SoundscapeSystem.Init(); - - - if ( engine->IsDedicatedServer() ) - { - // If the ds console typed it, send it to everyone. - for ( int i = 1; i <= gpGlobals->maxClients; i++ ) - { - CBasePlayer *pSendToPlayer = UTIL_PlayerByIndex( i ); - if ( pSendToPlayer ) - engine->ClientCommand( pSendToPlayer->edict(), "cl_soundscape_flush\n" ); - } - } - else - { - engine->ClientCommand( pPlayer->edict(), "cl_soundscape_flush\n" ); - } -} - -CSoundscapeSystem g_SoundscapeSystem( "CSoundscapeSystem" ); - -extern ConVar soundscape_debug; - -void CSoundscapeSystem::AddSoundscapeFile( const char *filename ) -{ - MEM_ALLOC_CREDIT(); - // Open the soundscape data file, and abort if we can't - KeyValues *pKeyValuesData = new KeyValues( filename ); - if ( filesystem->LoadKeyValues( *pKeyValuesData, IFileSystem::TYPE_SOUNDSCAPE, filename, "GAME" ) ) - { - // parse out all of the top level sections and save their names - KeyValues *pKeys = pKeyValuesData; - while ( pKeys ) - { - if ( pKeys->GetFirstSubKey() ) - { - if ( g_pDeveloper->GetBool() ) - { - if ( strstr( pKeys->GetName(), "{" ) ) - { - Msg("Error parsing soundscape file %s after %s\n", filename, m_soundscapeCount>0 ?m_soundscapes.GetStringText( m_soundscapeCount-1 ) : "FIRST" ); - } - } - m_soundscapes.AddString( pKeys->GetName(), m_soundscapeCount ); - - if ( IsX360() ) - { - AddSoundscapeSounds( pKeys, m_soundscapeCount ); - } - m_soundscapeCount++; - } - pKeys = pKeys->GetNextKey(); - } - } - pKeyValuesData->deleteThis(); -} - -CON_COMMAND_F( sv_soundscape_printdebuginfo, "print soundscapes", FCVAR_DEVELOPMENTONLY ) -{ - if ( !UTIL_IsCommandIssuedByServerAdmin() ) - return; - - g_SoundscapeSystem.PrintDebugInfo(); -} - - -void CSoundscapeSystem::PrintDebugInfo() -{ - Msg( "\n------- SERVER SOUNDSCAPES -------\n" ); - for ( int key=m_soundscapes.First(); key != m_soundscapes.InvalidIndex(); key = m_soundscapes.Next( key ) ) - { - int id = m_soundscapes.GetIDForKey( key ); - const char *pName = m_soundscapes.GetStringForKey( key ); - - Msg( "- %d: %s\n", id, pName ); - } - Msg( "-------- SOUNDSCAPE ENTITIES -----\n" ); - for( int entityIndex = 0; entityIndex < m_soundscapeEntities.Size(); ++entityIndex ) - { - CEnvSoundscape *currentSoundscape = m_soundscapeEntities[entityIndex]; - Msg("- %d: %s x:%.4f y:%.4f z:%.4f\n", - entityIndex, - STRING(currentSoundscape->GetSoundscapeName()), - currentSoundscape->GetAbsOrigin().x, - currentSoundscape->GetAbsOrigin().y, - currentSoundscape->GetAbsOrigin().z - ); - } - Msg( "----------------------------------\n\n" ); -} - -bool CSoundscapeSystem::Init() -{ - m_soundscapeCount = 0; - - const char *mapname = STRING( gpGlobals->mapname ); - const char *mapSoundscapeFilename = NULL; - if ( mapname && *mapname ) - { - mapSoundscapeFilename = UTIL_VarArgs( "scripts/soundscapes_%s.txt", mapname ); - } - - KeyValues *manifest = new KeyValues( SOUNDSCAPE_MANIFEST_FILE ); - if ( filesystem->LoadKeyValues( *manifest, IFileSystem::TYPE_SOUNDSCAPE, SOUNDSCAPE_MANIFEST_FILE, "GAME" ) ) - { - for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() ) - { - if ( !Q_stricmp( sub->GetName(), "file" ) ) - { - // Add - AddSoundscapeFile( sub->GetString() ); - if ( mapSoundscapeFilename && FStrEq( sub->GetString(), mapSoundscapeFilename ) ) - { - mapSoundscapeFilename = NULL; // we've already loaded the map's soundscape - } - continue; - } - - Warning( "CSoundscapeSystem::Init: Manifest '%s' with bogus file type '%s', expecting 'file'\n", - SOUNDSCAPE_MANIFEST_FILE, sub->GetName() ); - } - - if ( mapSoundscapeFilename && filesystem->FileExists( mapSoundscapeFilename ) ) - { - AddSoundscapeFile( mapSoundscapeFilename ); - } - } - else - { - Error( "Unable to load manifest file '%s'\n", SOUNDSCAPE_MANIFEST_FILE ); - } - manifest->deleteThis(); - m_activeIndex = 0; - - return true; -} - -void CSoundscapeSystem::FlushSoundscapes( void ) -{ - m_soundscapeCount = 0; - m_soundscapes.ClearStrings(); -} - -void CSoundscapeSystem::Shutdown() -{ - FlushSoundscapes(); - m_soundscapeEntities.RemoveAll(); - m_activeIndex = 0; - - if ( IsX360() ) - { - m_soundscapeSounds.Purge(); - } -} - -void CSoundscapeSystem::LevelInitPreEntity() -{ - g_SoundscapeSystem.Shutdown(); - g_SoundscapeSystem.Init(); -} - -void CSoundscapeSystem::LevelInitPostEntity() -{ - if ( IsX360() ) - { - m_soundscapeSounds.Purge(); - } - CUtlVector clusterbounds; - int clusterCount = engine->GetClusterCount(); - clusterbounds.SetCount( clusterCount ); - engine->GetAllClusterBounds( clusterbounds.Base(), clusterCount ); - m_soundscapesInCluster.SetCount(clusterCount); - for ( int i = 0; i < clusterCount; i++ ) - { - m_soundscapesInCluster[i].soundscapeCount = 0; - m_soundscapesInCluster[i].firstSoundscape = 0; - } - unsigned char myPVS[16 * 1024]; - CUtlVector clusterIndexList; - CUtlVector soundscapeIndexList; - - // find the clusters visible from each soundscape - // add this soundscape to the list of soundscapes for that cluster, clip cluster bounds to radius - for ( int i = 0; i < m_soundscapeEntities.Count(); i++ ) - { - Vector position = m_soundscapeEntities[i]->GetAbsOrigin(); - float radius = m_soundscapeEntities[i]->m_flRadius; - float radiusSq = radius * radius; - engine->GetPVSForCluster( engine->GetClusterForOrigin( position ), sizeof( myPVS ), myPVS ); - for ( int j = 0; j < clusterCount; j++ ) - { - if ( myPVS[ j >> 3 ] & (1<<(j&7)) ) - { - float distSq = CalcSqrDistanceToAABB( clusterbounds[j].mins, clusterbounds[j].maxs, position ); - if ( distSq < radiusSq || radius < 0 ) - { - m_soundscapesInCluster[j].soundscapeCount++; - clusterIndexList.AddToTail(j); - // UNDONE: Technically you just need a soundscape index and a count for this list. - soundscapeIndexList.AddToTail(i); - } - } - } - } - - // basically this part is like a radix sort - // this is how many entries we need in the soundscape index list - m_soundscapeIndexList.SetCount(soundscapeIndexList.Count()); - - // now compute the starting index of each cluster - int firstSoundscape = 0; - for ( int i = 0; i < clusterCount; i++ ) - { - m_soundscapesInCluster[i].firstSoundscape = firstSoundscape; - firstSoundscape += m_soundscapesInCluster[i].soundscapeCount; - m_soundscapesInCluster[i].soundscapeCount = 0; - } - // now add each soundscape index to the appropriate cluster's list - // The resulting list is precomputing all soundscapes that need to be checked for a player - // in each cluster. This is used to accelerate the per-frame operations - for ( int i = 0; i < soundscapeIndexList.Count(); i++ ) - { - int cluster = clusterIndexList[i]; - int outIndex = m_soundscapesInCluster[cluster].soundscapeCount + m_soundscapesInCluster[cluster].firstSoundscape; - m_soundscapesInCluster[cluster].soundscapeCount++; - m_soundscapeIndexList[outIndex] = soundscapeIndexList[i]; - } -} - -int CSoundscapeSystem::GetSoundscapeIndex( const char *pName ) -{ - return m_soundscapes.GetStringID( pName ); -} - -bool CSoundscapeSystem::IsValidIndex( int index ) -{ - if ( index >= 0 && index < m_soundscapeCount ) - return true; - return false; -} - -void CSoundscapeSystem::AddSoundscapeEntity( CEnvSoundscape *pSoundscape ) -{ - if ( m_soundscapeEntities.Find( pSoundscape ) == -1 ) - { - int index = m_soundscapeEntities.AddToTail( pSoundscape ); - pSoundscape->m_soundscapeEntityId = index + 1; - } -} - -void CSoundscapeSystem::RemoveSoundscapeEntity( CEnvSoundscape *pSoundscape ) -{ - m_soundscapeEntities.FindAndRemove( pSoundscape ); - pSoundscape->m_soundscapeEntityId = -1; -} - -void CSoundscapeSystem::FrameUpdatePostEntityThink() -{ - int total = m_soundscapeEntities.Count(); - if ( total > 0 ) - { - int traceCount = 0; - int playerCount = 0; - // budget tuned for TF. Do a max of 20 traces. That's going to happen anyway because a bunch of the maps - // use radius -1 for all soundscapes. So to trace one player you'll often need that many and this code must - // always trace one player's soundscapes. - // If the map has been optimized, then allow more players to update per frame. - int maxPlayers = gpGlobals->maxClients / 2; - // maxPlayers has to be at least 1 - maxPlayers = MAX( 1, maxPlayers ); - int maxTraces = 20; - if ( soundscape_debug.GetBool() ) - { - maxTraces = 9999; - maxPlayers = MAX_PLAYERS; - } - - // load balance across server ticks a bit by limiting the numbers of players (get cluster for origin) - // and traces processed in a single tick. In single player this will update the player every tick - // because it always does at least one player's full load of work - for ( int i = 0; i < gpGlobals->maxClients && traceCount <= maxTraces && playerCount <= maxPlayers; i++ ) - { - m_activeIndex = (m_activeIndex+1) % gpGlobals->maxClients; - CBasePlayer *pPlayer = UTIL_PlayerByIndex( m_activeIndex + 1 ); - if ( pPlayer && pPlayer->IsNetClient() ) - { - // check to see if this is the sound entity that is - // currently affecting this player - audioparams_t &audio = pPlayer->GetAudioParams(); - - // if we got this far, we're looking at an entity that is contending - // for current player sound. the closest entity to player wins. - CEnvSoundscape *pCurrent = (CEnvSoundscape *)( audio.ent.Get() ); - if ( pCurrent ) - { - int nEntIndex = pCurrent->m_soundscapeEntityId - 1; - NOTE_UNUSED( nEntIndex ); - Assert( m_soundscapeEntities[nEntIndex] == pCurrent ); - } - ss_update_t update; - update.pPlayer = pPlayer; - update.pCurrentSoundscape = pCurrent; - update.playerPosition = pPlayer->EarPosition(); - update.bInRange = false; - update.currentDistance = 0; - update.traceCount = 0; - if ( pCurrent ) - { - pCurrent->UpdateForPlayer(update); - } - - int clusterIndex = engine->GetClusterForOrigin( update.playerPosition ); - - if ( clusterIndex >= 0 && clusterIndex < m_soundscapesInCluster.Count() ) - { - // find all soundscapes that could possibly attach to this player and update them - for ( int j = 0; j < m_soundscapesInCluster[clusterIndex].soundscapeCount; j++ ) - { - int ssIndex = m_soundscapeIndexList[m_soundscapesInCluster[clusterIndex].firstSoundscape + j]; - if ( m_soundscapeEntities[ssIndex] == update.pCurrentSoundscape ) - continue; - m_soundscapeEntities[ssIndex]->UpdateForPlayer( update ); - } - } - playerCount++; - traceCount += update.traceCount; - } - } - } -} - -void CSoundscapeSystem::AddSoundscapeSounds( KeyValues *pSoundscape, int soundscapeIndex ) -{ - if ( !IsX360() ) - { - return; - } - - int i = m_soundscapeSounds.AddToTail(); - Assert( i == soundscapeIndex ); - - KeyValues *pKey = pSoundscape->GetFirstSubKey(); - while ( pKey ) - { - if ( !Q_strcasecmp( pKey->GetName(), "playlooping" ) ) - { - KeyValues *pAmbientKey = pKey->GetFirstSubKey(); - while ( pAmbientKey ) - { - if ( !Q_strcasecmp( pAmbientKey->GetName(), "wave" ) ) - { - char const *pSoundName = pAmbientKey->GetString(); - m_soundscapeSounds[i].AddToTail( pSoundName ); - } - pAmbientKey = pAmbientKey->GetNextKey(); - } - } - else if ( !Q_strcasecmp( pKey->GetName(), "playrandom" ) ) - { - KeyValues *pRandomKey = pKey->GetFirstSubKey(); - while ( pRandomKey ) - { - if ( !Q_strcasecmp( pRandomKey->GetName(), "rndwave" ) ) - { - KeyValues *pRndWaveKey = pRandomKey->GetFirstSubKey(); - while ( pRndWaveKey ) - { - if ( !Q_strcasecmp( pRndWaveKey->GetName(), "wave" ) ) - { - char const *pSoundName = pRndWaveKey->GetString(); - m_soundscapeSounds[i].AddToTail( pSoundName ); - } - pRndWaveKey = pRndWaveKey->GetNextKey(); - } - } - pRandomKey = pRandomKey->GetNextKey(); - } - } - else if ( !Q_strcasecmp( pKey->GetName(), "playsoundscape" ) ) - { - KeyValues *pPlayKey = pKey->GetFirstSubKey(); - while ( pPlayKey ) - { - if ( !Q_strcasecmp( pPlayKey->GetName(), "name" ) ) - { - char const *pSoundName = pPlayKey->GetString(); - m_soundscapeSounds[i].AddToTail( pSoundName ); - } - pPlayKey = pPlayKey->GetNextKey(); - } - } - pKey = pKey->GetNextKey(); - } -} - -void CSoundscapeSystem::PrecacheSounds( int soundscapeIndex ) -{ - if ( !IsX360() ) - { - return; - } - - if ( !IsValidIndex( soundscapeIndex ) ) - { - return; - } - - int count = m_soundscapeSounds[soundscapeIndex].Count(); - for ( int i=0; iIsDedicatedServer() ) + { + // If it's a dedicated server, only the server console can run this. + if ( pPlayer ) + return; + } + else + { + // If it's a listen server, only the listen server host can run this. + if ( !pPlayer || pPlayer != UTIL_GetListenServerHost() ) + return; + } + + g_SoundscapeSystem.FlushSoundscapes(); // don't bother forgetting about the entities + g_SoundscapeSystem.Init(); + + + if ( engine->IsDedicatedServer() ) + { + // If the ds console typed it, send it to everyone. + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *pSendToPlayer = UTIL_PlayerByIndex( i ); + if ( pSendToPlayer ) + engine->ClientCommand( pSendToPlayer->edict(), "cl_soundscape_flush\n" ); + } + } + else + { + engine->ClientCommand( pPlayer->edict(), "cl_soundscape_flush\n" ); + } +} + +CSoundscapeSystem g_SoundscapeSystem( "CSoundscapeSystem" ); + +extern ConVar soundscape_debug; + +void CSoundscapeSystem::AddSoundscapeFile( const char *filename ) +{ + MEM_ALLOC_CREDIT(); + // Open the soundscape data file, and abort if we can't + KeyValues *pKeyValuesData = new KeyValues( filename ); + if ( filesystem->LoadKeyValues( *pKeyValuesData, IFileSystem::TYPE_SOUNDSCAPE, filename, "GAME" ) ) + { + // parse out all of the top level sections and save their names + KeyValues *pKeys = pKeyValuesData; + while ( pKeys ) + { + if ( pKeys->GetFirstSubKey() ) + { + if ( g_pDeveloper->GetBool() ) + { + if ( strstr( pKeys->GetName(), "{" ) ) + { + Msg("Error parsing soundscape file %s after %s\n", filename, m_soundscapeCount>0 ?m_soundscapes.GetStringText( m_soundscapeCount-1 ) : "FIRST" ); + } + } + m_soundscapes.AddString( pKeys->GetName(), m_soundscapeCount ); + + if ( IsX360() ) + { + AddSoundscapeSounds( pKeys, m_soundscapeCount ); + } + m_soundscapeCount++; + } + pKeys = pKeys->GetNextKey(); + } + } + pKeyValuesData->deleteThis(); +} + +CON_COMMAND_F( sv_soundscape_printdebuginfo, "print soundscapes", FCVAR_DEVELOPMENTONLY ) +{ + if ( !UTIL_IsCommandIssuedByServerAdmin() ) + return; + + g_SoundscapeSystem.PrintDebugInfo(); +} + + +void CSoundscapeSystem::PrintDebugInfo() +{ + Msg( "\n------- SERVER SOUNDSCAPES -------\n" ); + for ( int key=m_soundscapes.First(); key != m_soundscapes.InvalidIndex(); key = m_soundscapes.Next( key ) ) + { + int id = m_soundscapes.GetIDForKey( key ); + const char *pName = m_soundscapes.GetStringForKey( key ); + + Msg( "- %d: %s\n", id, pName ); + } + Msg( "-------- SOUNDSCAPE ENTITIES -----\n" ); + for( int entityIndex = 0; entityIndex < m_soundscapeEntities.Size(); ++entityIndex ) + { + CEnvSoundscape *currentSoundscape = m_soundscapeEntities[entityIndex]; + Msg("- %d: %s x:%.4f y:%.4f z:%.4f\n", + entityIndex, + STRING(currentSoundscape->GetSoundscapeName()), + currentSoundscape->GetAbsOrigin().x, + currentSoundscape->GetAbsOrigin().y, + currentSoundscape->GetAbsOrigin().z + ); + } + Msg( "----------------------------------\n\n" ); +} + +bool CSoundscapeSystem::Init() +{ + m_soundscapeCount = 0; + + const char *mapname = STRING( gpGlobals->mapname ); + const char *mapSoundscapeFilename = NULL; + if ( mapname && *mapname ) + { + mapSoundscapeFilename = UTIL_VarArgs( "scripts/soundscapes_%s.txt", mapname ); + } + + KeyValues *manifest = new KeyValues( SOUNDSCAPE_MANIFEST_FILE ); + if ( filesystem->LoadKeyValues( *manifest, IFileSystem::TYPE_SOUNDSCAPE, SOUNDSCAPE_MANIFEST_FILE, "GAME" ) ) + { + for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() ) + { + if ( !Q_stricmp( sub->GetName(), "file" ) ) + { + // Add + AddSoundscapeFile( sub->GetString() ); + if ( mapSoundscapeFilename && FStrEq( sub->GetString(), mapSoundscapeFilename ) ) + { + mapSoundscapeFilename = NULL; // we've already loaded the map's soundscape + } + continue; + } + + Warning( "CSoundscapeSystem::Init: Manifest '%s' with bogus file type '%s', expecting 'file'\n", + SOUNDSCAPE_MANIFEST_FILE, sub->GetName() ); + } + + if ( mapSoundscapeFilename && filesystem->FileExists( mapSoundscapeFilename ) ) + { + AddSoundscapeFile( mapSoundscapeFilename ); + } + } + else + { + Error( "Unable to load manifest file '%s'\n", SOUNDSCAPE_MANIFEST_FILE ); + } + manifest->deleteThis(); + m_activeIndex = 0; + + return true; +} + +void CSoundscapeSystem::FlushSoundscapes( void ) +{ + m_soundscapeCount = 0; + m_soundscapes.ClearStrings(); +} + +void CSoundscapeSystem::Shutdown() +{ + FlushSoundscapes(); + m_soundscapeEntities.RemoveAll(); + m_activeIndex = 0; + + if ( IsX360() ) + { + m_soundscapeSounds.Purge(); + } +} + +void CSoundscapeSystem::LevelInitPreEntity() +{ + g_SoundscapeSystem.Shutdown(); + g_SoundscapeSystem.Init(); +} + +void CSoundscapeSystem::LevelInitPostEntity() +{ + if ( IsX360() ) + { + m_soundscapeSounds.Purge(); + } + CUtlVector clusterbounds; + int clusterCount = engine->GetClusterCount(); + clusterbounds.SetCount( clusterCount ); + engine->GetAllClusterBounds( clusterbounds.Base(), clusterCount ); + m_soundscapesInCluster.SetCount(clusterCount); + for ( int i = 0; i < clusterCount; i++ ) + { + m_soundscapesInCluster[i].soundscapeCount = 0; + m_soundscapesInCluster[i].firstSoundscape = 0; + } + unsigned char myPVS[16 * 1024]; + CUtlVector clusterIndexList; + CUtlVector soundscapeIndexList; + + // find the clusters visible from each soundscape + // add this soundscape to the list of soundscapes for that cluster, clip cluster bounds to radius + for ( int i = 0; i < m_soundscapeEntities.Count(); i++ ) + { + Vector position = m_soundscapeEntities[i]->GetAbsOrigin(); + float radius = m_soundscapeEntities[i]->m_flRadius; + float radiusSq = radius * radius; + engine->GetPVSForCluster( engine->GetClusterForOrigin( position ), sizeof( myPVS ), myPVS ); + for ( int j = 0; j < clusterCount; j++ ) + { + if ( myPVS[ j >> 3 ] & (1<<(j&7)) ) + { + float distSq = CalcSqrDistanceToAABB( clusterbounds[j].mins, clusterbounds[j].maxs, position ); + if ( distSq < radiusSq || radius < 0 ) + { + m_soundscapesInCluster[j].soundscapeCount++; + clusterIndexList.AddToTail(j); + // UNDONE: Technically you just need a soundscape index and a count for this list. + soundscapeIndexList.AddToTail(i); + } + } + } + } + + // basically this part is like a radix sort + // this is how many entries we need in the soundscape index list + m_soundscapeIndexList.SetCount(soundscapeIndexList.Count()); + + // now compute the starting index of each cluster + int firstSoundscape = 0; + for ( int i = 0; i < clusterCount; i++ ) + { + m_soundscapesInCluster[i].firstSoundscape = firstSoundscape; + firstSoundscape += m_soundscapesInCluster[i].soundscapeCount; + m_soundscapesInCluster[i].soundscapeCount = 0; + } + // now add each soundscape index to the appropriate cluster's list + // The resulting list is precomputing all soundscapes that need to be checked for a player + // in each cluster. This is used to accelerate the per-frame operations + for ( int i = 0; i < soundscapeIndexList.Count(); i++ ) + { + int cluster = clusterIndexList[i]; + int outIndex = m_soundscapesInCluster[cluster].soundscapeCount + m_soundscapesInCluster[cluster].firstSoundscape; + m_soundscapesInCluster[cluster].soundscapeCount++; + m_soundscapeIndexList[outIndex] = soundscapeIndexList[i]; + } +} + +int CSoundscapeSystem::GetSoundscapeIndex( const char *pName ) +{ + return m_soundscapes.GetStringID( pName ); +} + +bool CSoundscapeSystem::IsValidIndex( int index ) +{ + if ( index >= 0 && index < m_soundscapeCount ) + return true; + return false; +} + +void CSoundscapeSystem::AddSoundscapeEntity( CEnvSoundscape *pSoundscape ) +{ + if ( m_soundscapeEntities.Find( pSoundscape ) == -1 ) + { + int index = m_soundscapeEntities.AddToTail( pSoundscape ); + pSoundscape->m_soundscapeEntityId = index + 1; + } +} + +void CSoundscapeSystem::RemoveSoundscapeEntity( CEnvSoundscape *pSoundscape ) +{ + m_soundscapeEntities.FindAndRemove( pSoundscape ); + pSoundscape->m_soundscapeEntityId = -1; +} + +void CSoundscapeSystem::FrameUpdatePostEntityThink() +{ + int total = m_soundscapeEntities.Count(); + if ( total > 0 ) + { + int traceCount = 0; + int playerCount = 0; + // budget tuned for TF. Do a max of 20 traces. That's going to happen anyway because a bunch of the maps + // use radius -1 for all soundscapes. So to trace one player you'll often need that many and this code must + // always trace one player's soundscapes. + // If the map has been optimized, then allow more players to update per frame. + int maxPlayers = gpGlobals->maxClients / 2; + // maxPlayers has to be at least 1 + maxPlayers = MAX( 1, maxPlayers ); + int maxTraces = 20; + if ( soundscape_debug.GetBool() ) + { + maxTraces = 9999; + maxPlayers = MAX_PLAYERS; + } + + // load balance across server ticks a bit by limiting the numbers of players (get cluster for origin) + // and traces processed in a single tick. In single player this will update the player every tick + // because it always does at least one player's full load of work + for ( int i = 0; i < gpGlobals->maxClients && traceCount <= maxTraces && playerCount <= maxPlayers; i++ ) + { + m_activeIndex = (m_activeIndex+1) % gpGlobals->maxClients; + CBasePlayer *pPlayer = UTIL_PlayerByIndex( m_activeIndex + 1 ); + if ( pPlayer && pPlayer->IsNetClient() ) + { + // check to see if this is the sound entity that is + // currently affecting this player + audioparams_t &audio = pPlayer->GetAudioParams(); + + // if we got this far, we're looking at an entity that is contending + // for current player sound. the closest entity to player wins. + CEnvSoundscape *pCurrent = (CEnvSoundscape *)( audio.ent.Get() ); + if ( pCurrent ) + { + int nEntIndex = pCurrent->m_soundscapeEntityId - 1; + NOTE_UNUSED( nEntIndex ); + Assert( m_soundscapeEntities[nEntIndex] == pCurrent ); + } + ss_update_t update; + update.pPlayer = pPlayer; + update.pCurrentSoundscape = pCurrent; + update.playerPosition = pPlayer->EarPosition(); + update.bInRange = false; + update.currentDistance = 0; + update.traceCount = 0; + if ( pCurrent ) + { + pCurrent->UpdateForPlayer(update); + } + + int clusterIndex = engine->GetClusterForOrigin( update.playerPosition ); + + if ( clusterIndex >= 0 && clusterIndex < m_soundscapesInCluster.Count() ) + { + // find all soundscapes that could possibly attach to this player and update them + for ( int j = 0; j < m_soundscapesInCluster[clusterIndex].soundscapeCount; j++ ) + { + int ssIndex = m_soundscapeIndexList[m_soundscapesInCluster[clusterIndex].firstSoundscape + j]; + if ( m_soundscapeEntities[ssIndex] == update.pCurrentSoundscape ) + continue; + m_soundscapeEntities[ssIndex]->UpdateForPlayer( update ); + } + } + playerCount++; + traceCount += update.traceCount; + } + } + } +} + +void CSoundscapeSystem::AddSoundscapeSounds( KeyValues *pSoundscape, int soundscapeIndex ) +{ + if ( !IsX360() ) + { + return; + } + + int i = m_soundscapeSounds.AddToTail(); + Assert( i == soundscapeIndex ); + + KeyValues *pKey = pSoundscape->GetFirstSubKey(); + while ( pKey ) + { + if ( !Q_strcasecmp( pKey->GetName(), "playlooping" ) ) + { + KeyValues *pAmbientKey = pKey->GetFirstSubKey(); + while ( pAmbientKey ) + { + if ( !Q_strcasecmp( pAmbientKey->GetName(), "wave" ) ) + { + char const *pSoundName = pAmbientKey->GetString(); + m_soundscapeSounds[i].AddToTail( pSoundName ); + } + pAmbientKey = pAmbientKey->GetNextKey(); + } + } + else if ( !Q_strcasecmp( pKey->GetName(), "playrandom" ) ) + { + KeyValues *pRandomKey = pKey->GetFirstSubKey(); + while ( pRandomKey ) + { + if ( !Q_strcasecmp( pRandomKey->GetName(), "rndwave" ) ) + { + KeyValues *pRndWaveKey = pRandomKey->GetFirstSubKey(); + while ( pRndWaveKey ) + { + if ( !Q_strcasecmp( pRndWaveKey->GetName(), "wave" ) ) + { + char const *pSoundName = pRndWaveKey->GetString(); + m_soundscapeSounds[i].AddToTail( pSoundName ); + } + pRndWaveKey = pRndWaveKey->GetNextKey(); + } + } + pRandomKey = pRandomKey->GetNextKey(); + } + } + else if ( !Q_strcasecmp( pKey->GetName(), "playsoundscape" ) ) + { + KeyValues *pPlayKey = pKey->GetFirstSubKey(); + while ( pPlayKey ) + { + if ( !Q_strcasecmp( pPlayKey->GetName(), "name" ) ) + { + char const *pSoundName = pPlayKey->GetString(); + m_soundscapeSounds[i].AddToTail( pSoundName ); + } + pPlayKey = pPlayKey->GetNextKey(); + } + } + pKey = pKey->GetNextKey(); + } +} + +void CSoundscapeSystem::PrecacheSounds( int soundscapeIndex ) +{ + if ( !IsX360() ) + { + return; + } + + if ( !IsValidIndex( soundscapeIndex ) ) + { + return; + } + + int count = m_soundscapeSounds[soundscapeIndex].Count(); + for ( int i=0; i