From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/game/shared/particle_parse.cpp | 570 ++++++++++++++++++++++++++++++++++ 1 file changed, 570 insertions(+) create mode 100644 mp/src/game/shared/particle_parse.cpp (limited to 'mp/src/game/shared/particle_parse.cpp') diff --git a/mp/src/game/shared/particle_parse.cpp b/mp/src/game/shared/particle_parse.cpp new file mode 100644 index 00000000..e3fc5b62 --- /dev/null +++ b/mp/src/game/shared/particle_parse.cpp @@ -0,0 +1,570 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "filesystem.h" +#include +#include "particle_parse.h" +#include "particles/particles.h" + +#ifdef GAME_DLL +#include "te_effect_dispatch.h" +#include "networkstringtable_gamedll.h" +#else +#include "c_te_effect_dispatch.h" +#include "networkstringtable_clientdll.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define PARTICLES_MANIFEST_FILE "particles/particles_manifest.txt" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int GetAttachTypeFromString( const char *pszString ) +{ + if ( !pszString || !pszString[0] ) + return -1; + + // If you add new attach types, you need to add them to this list + static const char *pAttachmentNames[MAX_PATTACH_TYPES] = + { + "start_at_origin", // PATTACH_ABSORIGIN = 0, + "follow_origin", // PATTACH_ABSORIGIN_FOLLOW, + "start_at_customorigin",// PATTACH_CUSTOMORIGIN, + "start_at_attachment", // PATTACH_POINT, + "follow_attachment", // PATTACH_POINT_FOLLOW, + "follow_rootbone", // PATTACH_ROOTBONE_FOLLOW + }; + + for ( int i = 0; i < MAX_PATTACH_TYPES; i++ ) + { + if ( FStrEq( pAttachmentNames[i], pszString ) ) + return i; + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : list - +//----------------------------------------------------------------------------- +void GetParticleManifest( CUtlVector& list ) +{ + // Open the manifest file, and read the particles specified inside it + KeyValues *manifest = new KeyValues( PARTICLES_MANIFEST_FILE ); + if ( manifest->LoadFromFile( filesystem, PARTICLES_MANIFEST_FILE, "GAME" ) ) + { + for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() ) + { + if ( !Q_stricmp( sub->GetName(), "file" ) ) + { + list.AddToTail( sub->GetString() ); + continue; + } + + Warning( "CParticleMgr::Init: Manifest '%s' with bogus file type '%s', expecting 'file'\n", PARTICLES_MANIFEST_FILE, sub->GetName() ); + } + } + else + { + Warning( "PARTICLE SYSTEM: Unable to load manifest file '%s'\n", PARTICLES_MANIFEST_FILE ); + } + + manifest->deleteThis(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ParseParticleEffects( bool bLoadSheets, bool bPrecache ) +{ + MEM_ALLOC_CREDIT(); + + g_pParticleSystemMgr->ShouldLoadSheets( bLoadSheets ); + + CUtlVector files; + GetParticleManifest( files ); + + int nCount = files.Count(); + for ( int i = 0; i < nCount; ++i ) + { + g_pParticleSystemMgr->ReadParticleConfigFile( files[i], bPrecache, false ); + } + + g_pParticleSystemMgr->DecommitTempMemory(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ReloadParticleEffectsInList( IFileList *pFilesToReload ) +{ + MEM_ALLOC_CREDIT(); + + CUtlVector files; + GetParticleManifest( files ); + + // CAB 2/17/11 Reload all the particles regardless (Fixes filename change exploits). + bool bReloadAll = true; + + //int nCount = files.Count(); + //for ( int i = 0; i < nCount; ++i ) + //{ + // // Skip the precache marker + // const char *pFile = files[i]; + // if ( pFile[0] == '!' ) + // { + // pFile++; + // } + + // char szDX80Filename[MAX_PATH]; + // V_strncpy( szDX80Filename, pFile, sizeof( szDX80Filename ) ); + // V_StripExtension( pFile, szDX80Filename, sizeof( szDX80Filename ) ); + // V_strncat( szDX80Filename, "_dx80.", sizeof( szDX80Filename ) ); + // V_strncat( szDX80Filename, V_GetFileExtension( pFile ), sizeof( szDX80Filename ) ); + + // if ( pFilesToReload->IsFileInList( pFile ) || pFilesToReload->IsFileInList( szDX80Filename ) ) + // { + // Msg( "Reloading all particle files due to pure settings.\n" ); + // bReloadAll = true; + // break; + // } + //} + + // Then check to see if we need to reload the map's particles + const char *pszMapName = NULL; +#ifdef CLIENT_DLL + pszMapName = engine->GetLevelName(); +#else + pszMapName = STRING( gpGlobals->mapname ); +#endif + if ( pszMapName && pszMapName[0] ) + { + char mapname[MAX_MAP_NAME]; + Q_FileBase( pszMapName, mapname, sizeof( mapname ) ); + Q_strlower( mapname ); + ParseParticleEffectsMap( mapname, true, pFilesToReload ); + } + + if ( bReloadAll ) + { + ParseParticleEffects( true, true ); + } + + g_pParticleSystemMgr->DecommitTempMemory(); +} + +//----------------------------------------------------------------------------- +// Purpose: loads per-map manifest! +//----------------------------------------------------------------------------- +void ParseParticleEffectsMap( const char *pMapName, bool bLoadSheets, IFileList *pFilesToReload ) +{ + MEM_ALLOC_CREDIT(); + + CUtlVector files; + char szMapManifestFilename[MAX_PATH]; + + szMapManifestFilename[0] = NULL; + + if ( pMapName && *pMapName ) + { + V_snprintf( szMapManifestFilename, sizeof( szMapManifestFilename ), "maps/%s_particles.txt", pMapName ); + } + + // Open the manifest file, and read the particles specified inside it + KeyValues *manifest = new KeyValues( szMapManifestFilename ); + if ( manifest->LoadFromFile( filesystem, szMapManifestFilename, "GAME" ) ) + { + DevMsg( "Successfully loaded particle effects manifest '%s' for map '%s'\n", szMapManifestFilename, pMapName ); + for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() ) + { + if ( !Q_stricmp( sub->GetName(), "file" ) ) + { + // Ensure the particles are in the particles directory + char szPath[ 512 ]; + Q_strncpy( szPath, sub->GetString(), sizeof( szPath ) ); + Q_StripFilename( szPath ); + char *pszPath = (szPath[0] == '!') ? &szPath[1] : &szPath[0]; + if ( pszPath && pszPath[0] && !Q_stricmp( pszPath, "particles" ) ) + { + files.AddToTail( sub->GetString() ); + continue; + } + else + { + Warning( "CParticleMgr::LevelInit: Manifest '%s' contains a particle file '%s' that's not under the particles directory. Custom particles must be placed in the particles directory.\n", szMapManifestFilename, sub->GetString() ); + } + } + else + { + Warning( "CParticleMgr::LevelInit: Manifest '%s' with bogus file type '%s', expecting 'file'\n", szMapManifestFilename, sub->GetName() ); + } + } + } + else + { + // Don't print a warning, and don't proceed any further if the file doesn't exist! + return; + } + + int nCount = files.Count(); + if ( !nCount ) + { + return; + } + + g_pParticleSystemMgr->ShouldLoadSheets( bLoadSheets ); + + for ( int i = 0; i < nCount; ++i ) + { + // If we've been given a list of particles to reload, only reload those. + if ( !pFilesToReload || (pFilesToReload && pFilesToReload->IsFileInList( files[i] )) ) + { + g_pParticleSystemMgr->ReadParticleConfigFile( files[i], true, true ); + } + } + + g_pParticleSystemMgr->DecommitTempMemory(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void PrecacheStandardParticleSystems( ) +{ +#ifdef GAME_DLL + // Now add each particle system name to the network string pool, so we can send string_t's + // down to the client instead of full particle system names. + for ( int i = 0; i < g_pParticleSystemMgr->GetParticleSystemCount(); i++ ) + { + const char *pParticleSystemName = g_pParticleSystemMgr->GetParticleSystemNameFromIndex(i); + CParticleSystemDefinition *pParticleSystem = g_pParticleSystemMgr->FindParticleSystem( pParticleSystemName ); + if ( pParticleSystem->ShouldAlwaysPrecache() ) + { + PrecacheParticleSystem( pParticleSystemName ); + } + } +#endif +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DispatchParticleEffect( const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, const char *pszAttachmentName, bool bResetAllParticlesOnEntity ) +{ + int iAttachment = -1; + if ( pEntity && pEntity->GetBaseAnimating() ) + { + // Find the attachment point index + iAttachment = pEntity->GetBaseAnimating()->LookupAttachment( pszAttachmentName ); + if ( iAttachment <= 0 ) + { + Warning("Model '%s' doesn't have attachment '%s' to attach particle system '%s' to.\n", STRING(pEntity->GetBaseAnimating()->GetModelName()), pszAttachmentName, pszParticleName ); + return; + } + } + + DispatchParticleEffect( pszParticleName, iAttachType, pEntity, iAttachment, bResetAllParticlesOnEntity ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DispatchParticleEffect( const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, int iAttachmentPoint, bool bResetAllParticlesOnEntity ) +{ + CEffectData data; + + data.m_nHitBox = GetParticleSystemIndex( pszParticleName ); + if ( pEntity ) + { +#ifdef CLIENT_DLL + data.m_hEntity = pEntity; +#else + data.m_nEntIndex = pEntity->entindex(); +#endif + data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY; + data.m_vOrigin = pEntity->GetAbsOrigin(); + } + data.m_nDamageType = iAttachType; + data.m_nAttachmentIndex = iAttachmentPoint; + + if ( bResetAllParticlesOnEntity ) + { + data.m_fFlags |= PARTICLE_DISPATCH_RESET_PARTICLES; + } + +#ifdef GAME_DLL + if ( ( data.m_fFlags & PARTICLE_DISPATCH_FROM_ENTITY ) != 0 && + ( iAttachType == PATTACH_ABSORIGIN_FOLLOW || iAttachType == PATTACH_POINT_FOLLOW || iAttachType == PATTACH_ROOTBONE_FOLLOW ) ) + { + CReliableBroadcastRecipientFilter filter; + DispatchEffect( "ParticleEffect", data, filter ); + } + else +#endif + { + DispatchEffect( "ParticleEffect", data ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DispatchParticleEffect( const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, const char *pszAttachmentName, Vector vecColor1, Vector vecColor2, bool bUseColors, bool bResetAllParticlesOnEntity ) +{ + int iAttachment = -1; + if ( pEntity && pEntity->GetBaseAnimating() ) + { + // Find the attachment point index + iAttachment = pEntity->GetBaseAnimating()->LookupAttachment( pszAttachmentName ); + if ( iAttachment <= 0 ) + { + Warning("Model '%s' doesn't have attachment '%s' to attach particle system '%s' to.\n", STRING(pEntity->GetBaseAnimating()->GetModelName()), pszAttachmentName, pszParticleName ); + return; + } + } + + CEffectData data; + + data.m_nHitBox = GetParticleSystemIndex( pszParticleName ); + if ( pEntity ) + { +#ifdef CLIENT_DLL + data.m_hEntity = pEntity; +#else + data.m_nEntIndex = pEntity->entindex(); +#endif + data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY; + data.m_vOrigin = pEntity->GetAbsOrigin(); + } + data.m_nDamageType = iAttachType; + data.m_nAttachmentIndex = iAttachment; + + if ( bResetAllParticlesOnEntity ) + { + data.m_fFlags |= PARTICLE_DISPATCH_RESET_PARTICLES; + } + + if ( bUseColors ) + { + data.m_bCustomColors = true; + data.m_CustomColors.m_vecColor1 = vecColor1; + data.m_CustomColors.m_vecColor2 = vecColor2; + } + +#ifdef GAME_DLL + if ( ( data.m_fFlags & PARTICLE_DISPATCH_FROM_ENTITY ) != 0 && + ( iAttachType == PATTACH_ABSORIGIN_FOLLOW || iAttachType == PATTACH_POINT_FOLLOW || iAttachType == PATTACH_ROOTBONE_FOLLOW ) ) + { + CReliableBroadcastRecipientFilter filter; + DispatchEffect( "ParticleEffect", data, filter ); + } + else +#endif + { + DispatchEffect( "ParticleEffect", data ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DispatchParticleEffect( int iEffectIndex, Vector vecOrigin, Vector vecStart, QAngle vecAngles, CBaseEntity *pEntity ) +{ + CEffectData data; + + data.m_nHitBox = iEffectIndex; + data.m_vOrigin = vecOrigin; + data.m_vStart = vecStart; + data.m_vAngles = vecAngles; + + if ( pEntity ) + { +#ifdef CLIENT_DLL + data.m_hEntity = pEntity; +#else + data.m_nEntIndex = pEntity->entindex(); +#endif + data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY; + data.m_nDamageType = PATTACH_CUSTOMORIGIN; + } + else + { +#ifdef CLIENT_DLL + data.m_hEntity = NULL; +#else + data.m_nEntIndex = 0; +#endif + } + + DispatchEffect( "ParticleEffect", data ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DispatchParticleEffect( const char *pszParticleName, Vector vecOrigin, QAngle vecAngles, Vector vecColor1, Vector vecColor2, bool bUseColors, CBaseEntity *pEntity, int iAttachType ) +{ + int iEffectIndex = GetParticleSystemIndex( pszParticleName ); + + CEffectData data; + + data.m_nHitBox = iEffectIndex; + data.m_vOrigin = vecOrigin; + data.m_vAngles = vecAngles; + + if ( pEntity ) + { +#ifdef CLIENT_DLL + data.m_hEntity = pEntity; +#else + data.m_nEntIndex = pEntity->entindex(); +#endif + data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY; + data.m_nDamageType = PATTACH_CUSTOMORIGIN; + } + else + { +#ifdef CLIENT_DLL + data.m_hEntity = NULL; +#else + data.m_nEntIndex = 0; +#endif + } + + if ( bUseColors ) + { + data.m_bCustomColors = true; + data.m_CustomColors.m_vecColor1 = vecColor1; + data.m_CustomColors.m_vecColor2 = vecColor2; + } + + DispatchEffect( "ParticleEffect", data ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DispatchParticleEffect( const char *pszParticleName, Vector vecOrigin, QAngle vecAngles, CBaseEntity *pEntity ) +{ + int iIndex = GetParticleSystemIndex( pszParticleName ); + DispatchParticleEffect( iIndex, vecOrigin, vecOrigin, vecAngles, pEntity ); +} + +//----------------------------------------------------------------------------- +// Purpose: Yet another overload, lets us supply vecStart +//----------------------------------------------------------------------------- +void DispatchParticleEffect( const char *pszParticleName, Vector vecOrigin, Vector vecStart, QAngle vecAngles, CBaseEntity *pEntity ) +{ + int iIndex = GetParticleSystemIndex( pszParticleName ); + DispatchParticleEffect( iIndex, vecOrigin, vecStart, vecAngles, pEntity ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void StopParticleEffects( CBaseEntity *pEntity ) +{ + CEffectData data; + + if ( pEntity ) + { +#ifdef CLIENT_DLL + data.m_hEntity = pEntity; +#else + data.m_nEntIndex = pEntity->entindex(); +#endif + } + +#ifdef GAME_DLL + CReliableBroadcastRecipientFilter filter; + DispatchEffect( "ParticleEffectStop", data, filter ); +#else + DispatchEffect( "ParticleEffectStop", data ); +#endif +} + +#ifndef CLIENT_DLL + + extern CBaseEntity *GetNextCommandEntity( CBasePlayer *pPlayer, const char *name, CBaseEntity *ent ); + + ConVar particle_test_file( "particle_test_file", "", FCVAR_CHEAT, "Name of the particle system to dynamically spawn" ); + ConVar particle_test_attach_mode( "particle_test_attach_mode", "follow_attachment", FCVAR_CHEAT, "Possible Values: 'start_at_attachment', 'follow_attachment', 'start_at_origin', 'follow_origin'" ); + ConVar particle_test_attach_attachment( "particle_test_attach_attachment", "0", FCVAR_CHEAT, "Attachment index for attachment mode" ); + + void Particle_Test_Start( CBasePlayer* pPlayer, const char *name, bool bStart ) + { + if ( !pPlayer ) + return; + + int iAttachType = GetAttachTypeFromString( particle_test_attach_mode.GetString() ); + + if ( iAttachType < 0 ) + { + Warning( "Invalid attach type specified for particle_test in cvar 'particle_test_attach_mode.\n" ); + return; + } + + int iAttachmentIndex = particle_test_attach_attachment.GetInt(); + + const char *pszParticleFile = particle_test_file.GetString(); + + CBaseEntity *pEntity = NULL; + while ( (pEntity = GetNextCommandEntity( pPlayer, name, pEntity )) != NULL ) + { + /* + Fire the test particle system on this entity + */ + + DispatchParticleEffect( + pszParticleFile, + (ParticleAttachment_t)iAttachType, + pEntity, + iAttachmentIndex, + true ); // stops existing particle systems + } + } + + void CC_Particle_Test_Start( const CCommand& args ) + { + Particle_Test_Start( UTIL_GetCommandClient(), args[1], true ); + } + static ConCommand particle_test_start("particle_test_start", CC_Particle_Test_Start, "Dispatches the test particle system with the parameters specified in particle_test_file,\n particle_test_attach_mode and particle_test_attach_param on the entity the player is looking at.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT); + + + void Particle_Test_Stop( CBasePlayer* pPlayer, const char *name, bool bStart ) + { + if ( !pPlayer ) + return; + + CBaseEntity *pEntity = NULL; + while ( (pEntity = GetNextCommandEntity( pPlayer, name, pEntity )) != NULL ) + { + //Stop all particle systems on the selected entity + DispatchParticleEffect( "", PATTACH_ABSORIGIN, pEntity, 0, true ); + } + } + + void CC_Particle_Test_Stop( const CCommand& args ) + { + Particle_Test_Stop( UTIL_GetCommandClient(), args[1], false ); + } + static ConCommand particle_test_stop("particle_test_stop", CC_Particle_Test_Stop, "Stops all particle systems on the selected entities.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT); + +#endif //CLIENT_DLL -- cgit v1.2.3