Merge pull request #65 from powerlord/master

New functions for SDKTools to get information from game_sound files (r=psychonic).
This commit is contained in:
Nicholas Hastings 2014-07-04 17:17:00 -04:00
commit ffa1887c48
4 changed files with 345 additions and 0 deletions

View File

@ -66,6 +66,7 @@ IPlayerInfoManager *playerinfomngr = NULL;
ICvar *icvar = NULL; ICvar *icvar = NULL;
IServer *iserver = NULL; IServer *iserver = NULL;
CGlobalVars *gpGlobals; CGlobalVars *gpGlobals;
ISoundEmitterSystemBase *soundemitterbase = NULL;
#if SOURCE_ENGINE >= SE_ORANGEBOX #if SOURCE_ENGINE >= SE_ORANGEBOX
IServerTools *servertools = NULL; IServerTools *servertools = NULL;
@ -258,6 +259,7 @@ bool SDKTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool
#if SOURCE_ENGINE >= SE_ORANGEBOX #if SOURCE_ENGINE >= SE_ORANGEBOX
GET_V_IFACE_ANY(GetServerFactory, servertools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION); GET_V_IFACE_ANY(GetServerFactory, servertools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION);
#endif #endif
GET_V_IFACE_ANY(GetEngineFactory, soundemitterbase, ISoundEmitterSystemBase, SOUNDEMITTERSYSTEM_INTERFACE_VERSION);
gpGlobals = ismm->GetCGlobals(); gpGlobals = ismm->GetCGlobals();
enginePatch = SH_GET_CALLCLASS(engine); enginePatch = SH_GET_CALLCLASS(engine);

View File

@ -50,6 +50,7 @@
#include <convar.h> #include <convar.h>
#include <iserver.h> #include <iserver.h>
#include <cdll_int.h> #include <cdll_int.h>
#include "SoundEmitterSystem/isoundemittersystembase.h"
#if SOURCE_ENGINE >= SE_ORANGEBOX #if SOURCE_ENGINE >= SE_ORANGEBOX
#include <itoolentity.h> #include <itoolentity.h>
@ -124,6 +125,7 @@ extern CGlobalVars *gpGlobals;
#if SOURCE_ENGINE >= SE_ORANGEBOX #if SOURCE_ENGINE >= SE_ORANGEBOX
extern IServerTools *servertools; extern IServerTools *servertools;
#endif #endif
extern ISoundEmitterSystemBase *soundemitterbase;
/* Interfaces from SourceMod */ /* Interfaces from SourceMod */
extern IBinTools *g_pBinTools; extern IBinTools *g_pBinTools;
extern IGameConfig *g_pGameConf; extern IGameConfig *g_pGameConf;

View File

@ -512,6 +512,74 @@ RETURN_META_NEWPARAMS(
#endif #endif
} }
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);
}
bool InternalPrecacheScriptSound(const char *soundname)
{
int soundIndex = soundemitterbase->GetSoundIndex(soundname);
if (!soundemitterbase->IsValidIndex(soundIndex))
{
return false;
}
CSoundParametersInternal *internal = soundemitterbase->InternalGetParametersForSound(soundIndex);
if (!internal)
return false;
int waveCount = internal->NumSoundNames();
if (!waveCount)
{
return false;
}
for (int wave = 0; wave < waveCount; wave++)
{
const char* waveName = soundemitterbase->GetWaveName(internal->GetSoundNames()[wave].symbol);
// return true even if we precache no new wavs
if (!engsound->IsSoundPrecached(waveName))
{
engsound->PrecacheSound(waveName);
}
}
return true;
}
/************************ /************************
* * * *
* Sound Related Natives * * Sound Related Natives *
@ -1135,6 +1203,51 @@ static cell_t smn_GetDistGainFromSoundLevel(IPluginContext *pContext, const cell
return sp_ftoc(engsound->GetDistGainFromSoundLevel((soundlevel_t)decibel, distance)); return sp_ftoc(engsound->GetDistGainFromSoundLevel((soundlevel_t)decibel, distance));
} }
// native bool:GetGameSoundParams(const String:gameSound[], &channel, &soundLevel, &Float:volume, &pitch, String:sample[], maxlength, entity=SOUND_FROM_WORLD)
static cell_t smn_GetGameSoundParams(IPluginContext *pContext, const cell_t *params)
{
char *soundname;
pContext->LocalToString(params[1], &soundname);
CSoundParameters soundParams;
if (!GetSoundParams(&soundParams, soundname, params[8]))
return false;
cell_t *channel;
cell_t *fakeVolume;
cell_t *pitch;
cell_t *soundLevel;
pContext->LocalToPhysAddr(params[2], &channel);
pContext->LocalToPhysAddr(params[3], &soundLevel);
pContext->LocalToPhysAddr(params[4], &fakeVolume);
pContext->LocalToPhysAddr(params[5], &pitch);
*channel = soundParams.channel;
*pitch = soundParams.pitch;
*soundLevel = (cell_t)soundParams.soundlevel;
*fakeVolume = sp_ftoc(soundParams.volume);
pContext->StringToLocal(params[6], params[7], soundParams.soundname);
// Precache the sound we're returning
if (!engsound->IsSoundPrecached(soundParams.soundname))
{
InternalPrecacheScriptSound(soundname);
}
return true;
}
// native bool:PrecacheScriptSound(const String:soundname[])
static cell_t smn_PrecacheScriptSound(IPluginContext *pContext, const cell_t *params)
{
char *soundname;
pContext->LocalToString(params[1], &soundname);
return InternalPrecacheScriptSound(soundname);
}
sp_nativeinfo_t g_SoundNatives[] = sp_nativeinfo_t g_SoundNatives[] =
{ {
{"EmitAmbientSound", EmitAmbientSound}, {"EmitAmbientSound", EmitAmbientSound},
@ -1149,5 +1262,7 @@ sp_nativeinfo_t g_SoundNatives[] =
{"RemoveAmbientSoundHook", smn_RemoveAmbientSoundHook}, {"RemoveAmbientSoundHook", smn_RemoveAmbientSoundHook},
{"RemoveNormalSoundHook", smn_RemoveNormalSoundHook}, {"RemoveNormalSoundHook", smn_RemoveNormalSoundHook},
{"GetDistGainFromSoundLevel", smn_GetDistGainFromSoundLevel}, {"GetDistGainFromSoundLevel", smn_GetDistGainFromSoundLevel},
{"GetGameSoundParams", smn_GetGameSoundParams},
{"PrecacheScriptSound", smn_PrecacheScriptSound},
{NULL, NULL}, {NULL, NULL},
}; };

View File

@ -448,3 +448,229 @@ stock ATTN_TO_SNDLEVEL(Float:attn)
} }
return 0; return 0;
} }
/**
* Retrieves the parameters for a game sound.
*
* Game sounds are found in a game's scripts/game_sound.txt or other files
* referenced from it
*
* Note that if a game sound has a rndwave section, one of them will be returned
* at random.
*
* @param gameSound Name of game sound.
* @param channel Channel to emit with.
* @param level Sound level.
* @param volume Sound volume.
* @param pitch Sound pitch.
* @param sample Sound file name relative to the "sounds" folder.
* @param maxlength Maximum length of sample string buffer.
* @param entity Entity the sound is being emitted from.
* @return True if the sound was successfully retrieved, false if it
* was not found
*/
native bool:GetGameSoundParams(const String:gameSound[],
&channel,
&soundLevel,
&Float:volume,
&pitch,
String:sample[],
maxlength,
entity=SOUND_FROM_PLAYER);
/**
* Emits a game sound to a list of clients.
*
* Game sounds are found in a game's scripts/game_sound.txt or other files
* referenced from it
*
* Note that if a game sound has a rndwave section, one of them will be returned
* at random.
*
* @param clients Array of client indexes.
* @param numClients Number of clients in the array.
* @param gameSound Name of game sound.
* @param entity Entity to emit from.
* @param flags Sound flags.
* @param speakerentity Unknown.
* @param origin Sound origin.
* @param dir Sound direction.
* @param updatePos Unknown (updates positions?)
* @param soundtime Alternate time to play sound for.
* @return True if the sound was played successfully, false if it failed
* @error Invalid client index.
*/
stock bool:EmitGameSound(const clients[],
numClients,
const String:gameSound[],
entity = SOUND_FROM_PLAYER,
flags = SND_NOFLAGS,
speakerentity = -1,
const Float:origin[3] = NULL_VECTOR,
const Float:dir[3] = NULL_VECTOR,
bool:updatePos = true,
Float:soundtime = 0.0)
{
new channel;
new level;
new Float:volume;
new pitch;
new String:sample[PLATFORM_MAX_PATH];
if (GetGameSoundParams(gameSound, channel, level, volume, pitch, sample, sizeof(sample), entity))
{
EmitSound(clients, numClients, sample, entity, channel, level, flags, volume, pitch, speakerentity, origin, dir, updatePos, soundtime);
return true;
}
else
{
return false;
}
}
/**
* Emits an ambient game sound.
*
* Game sounds are found in a game's scripts/game_sound.txt or other files
* referenced from it
*
* Note that if a game sound has a rndwave section, one of them will be returned
* at random.
*
* @param gameSound Name of game sound.
* @param pos Origin of sound.
* @param entity Entity index to associate sound with.
* @param flags Sound flags.
* @param delay Play delay.
* @noreturn
*/
stock bool:EmitAmbientGameSound(const String:gameSound[],
const Float:pos[3],
entity = SOUND_FROM_WORLD,
flags = SND_NOFLAGS,
Float:delay = 0.0)
{
new channel; // This is never actually used for Ambients, but it's a mandatory field to GetGameSoundParams
new level;
new Float:volume;
new pitch;
new String:sample[PLATFORM_MAX_PATH];
if (GetGameSoundParams(gameSound, channel, level, volume, pitch, sample, sizeof(sample), entity))
{
EmitAmbientSound(sample, pos, entity, level, flags, volume, pitch, delay);
return true;
}
else
{
return false;
}
}
/**
* Wrapper to emit a game sound to one client.
*
* Game sounds are found in a game's scripts/game_sound.txt or other files
* referenced from it
*
* Note that if a game sound has a rndwave section, one of them will be returned
* at random.
*
* @param client Client index.
* @param gameSound Name of game sound.
* @param entity Entity to emit from.
* @param flags Sound flags.
* @param speakerentity Unknown.
* @param origin Sound origin.
* @param dir Sound direction.
* @param updatePos Unknown (updates positions?)
* @param soundtime Alternate time to play sound for.
* @noreturn
* @error Invalid client index.
*/
stock bool:EmitGameSoundToClient(client,
const String:gameSound[],
entity = SOUND_FROM_PLAYER,
flags = SND_NOFLAGS,
speakerentity = -1,
const Float:origin[3] = NULL_VECTOR,
const Float:dir[3] = NULL_VECTOR,
bool:updatePos = true,
Float:soundtime = 0.0)
{
new clients[1];
clients[0] = client;
/* Save some work for SDKTools and remove SOUND_FROM_PLAYER references */
entity = (entity == SOUND_FROM_PLAYER) ? client : entity;
return EmitGameSound(clients, 1, gameSound, entity, flags,
speakerentity, origin, dir, updatePos, soundtime);
}
/**
* Wrapper to emit game sound to all clients.
*
* Game sounds are found in a game's scripts/game_sound.txt or other files
* referenced from it
*
* Note that if a game sound has a rndwave section, one of them will be returned
* at random.
*
* @param gameSound Name of game sound.
* @param entity Entity to emit from.
* @param flags Sound flags.
* @param speakerentity Unknown.
* @param origin Sound origin.
* @param dir Sound direction.
* @param updatePos Unknown (updates positions?)
* @param soundtime Alternate time to play sound for.
* @noreturn
* @error Invalid client index.
*/
stock bool:EmitGameSoundToAll(const String:gameSound[],
entity = SOUND_FROM_PLAYER,
flags = SND_NOFLAGS,
speakerentity = -1,
const Float:origin[3] = NULL_VECTOR,
const Float:dir[3] = NULL_VECTOR,
bool:updatePos = true,
Float:soundtime = 0.0)
{
new clients[MaxClients];
new total = 0;
for (new i=1; i<=MaxClients; i++)
{
if (IsClientInGame(i))
{
clients[total++] = i;
}
}
if (!total)
{
return false;
}
return EmitGameSound(clients, total, gameSound, entity, flags,
speakerentity, origin, dir, updatePos, soundtime);
}
/**
* Precache a game sound.
*
* Most games will precache all game sounds on map start, but this is not guaranteed...
* Team Fortress 2 is known to not pre-cache MvM game mode sounds on non-MvM maps.
*
* Due to the above, this native should be called before any calls to GetGameSoundParams,
* EmitGameSound*, or EmitAmbientGameSound.
*
* It should be safe to pass already precached game sounds to this function.
*
* Note: It precaches all files for a game sound.
*
* @param soundname Game sound to precache
*
* @return True if the game sound was found, false if sound did not exist
* or had no files
*/
native bool:PrecacheScriptSound(const String:soundname[]);