Merge pull request #247 from AnthonyIacono/normalshook-upgrade
Improvements for NormalSHook functionality (r=psychonic).
This commit is contained in:
commit
589482736f
@ -283,6 +283,57 @@ void SoundHooks::OnEmitAmbientSound(int entindex, const Vector &pos, const char
|
||||
}
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
// This should probably be moved to the gamedata
|
||||
#define SOUND_ENTRY_HASH_SEED 0x444F5441
|
||||
|
||||
uint32 GenerateSoundEntryHash(char const *pSoundEntry)
|
||||
{
|
||||
// First we need to convert the sound entry to lowercase before we calculate the hash
|
||||
int nSoundEntryLength = strlen(pSoundEntry);
|
||||
char *pSoundEntryLowerCase = (char *)stackalloc(nSoundEntryLength + 1);
|
||||
|
||||
for (int nIndex = 0; nIndex < nSoundEntryLength; nIndex++)
|
||||
pSoundEntryLowerCase[nIndex] = tolower(pSoundEntry[nIndex]);
|
||||
|
||||
// Second we need to calculate the hash using the algorithm reconstructed from CS:GO
|
||||
const uint32 nMagicNumber = 0x5bd1e995;
|
||||
|
||||
uint32 nSoundHash = SOUND_ENTRY_HASH_SEED ^ nSoundEntryLength;
|
||||
|
||||
unsigned char *pData = (unsigned char *)pSoundEntryLowerCase;
|
||||
|
||||
while (nSoundEntryLength >= 4)
|
||||
{
|
||||
uint32 nLittleDWord = LittleDWord(*(uint32 *)pData);
|
||||
|
||||
nLittleDWord *= nMagicNumber;
|
||||
nLittleDWord ^= nLittleDWord >> 24;
|
||||
nLittleDWord *= nMagicNumber;
|
||||
|
||||
nSoundHash *= nMagicNumber;
|
||||
nSoundHash ^= nLittleDWord;
|
||||
|
||||
pData += 4;
|
||||
nSoundEntryLength -= 4;
|
||||
}
|
||||
|
||||
switch (nSoundEntryLength)
|
||||
{
|
||||
case 3: nSoundHash ^= pData[2] << 16;
|
||||
case 2: nSoundHash ^= pData[1] << 8;
|
||||
case 1: nSoundHash ^= pData[0];
|
||||
nSoundHash *= nMagicNumber;
|
||||
};
|
||||
|
||||
nSoundHash ^= nSoundHash >> 13;
|
||||
nSoundHash *= nMagicNumber;
|
||||
nSoundHash ^= nSoundHash >> 15;
|
||||
|
||||
return nSoundHash;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
int SoundHooks::OnEmitSound(IRecipientFilter &filter, int iEntIndex, int iChannel, const char *pSoundEntry, unsigned int nSoundEntryHash, const char *pSample,
|
||||
float flVolume, soundlevel_t iSoundlevel, int nSeed, int iFlags, int iPitch, const Vector *pOrigin,
|
||||
@ -306,6 +357,15 @@ void SoundHooks::OnEmitSound(IRecipientFilter &filter, int iEntIndex, int iChann
|
||||
char buffer[PLATFORM_MAX_PATH];
|
||||
strcpy(buffer, pSample);
|
||||
|
||||
char soundEntry[PLATFORM_MAX_PATH] = "";
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
Q_strncpy(soundEntry, pSoundEntry, sizeof(soundEntry));
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE < SE_PORTAL2
|
||||
int nSeed = 0;
|
||||
#endif
|
||||
|
||||
for (iter=m_NormalFuncs.begin(); iter!=m_NormalFuncs.end(); iter++)
|
||||
{
|
||||
int players[SM_MAXPLAYERS], size;
|
||||
@ -321,6 +381,8 @@ void SoundHooks::OnEmitSound(IRecipientFilter &filter, int iEntIndex, int iChann
|
||||
pFunc->PushCellByRef(reinterpret_cast<cell_t *>(&iSoundlevel));
|
||||
pFunc->PushCellByRef(&iPitch);
|
||||
pFunc->PushCellByRef(&iFlags);
|
||||
pFunc->PushStringEx(soundEntry, sizeof(soundEntry), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
|
||||
pFunc->PushCellByRef(&nSeed);
|
||||
g_InSoundHook = true;
|
||||
pFunc->Execute(&res);
|
||||
g_InSoundHook = false;
|
||||
@ -360,6 +422,16 @@ void SoundHooks::OnEmitSound(IRecipientFilter &filter, int iEntIndex, int iChann
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
if (strcmp(pSoundEntry, soundEntry) != 0 || strcmp(pSample, buffer) != 0)
|
||||
{
|
||||
if (strcmp(soundEntry, buffer) == 0)
|
||||
nSoundEntryHash = -1;
|
||||
else if (strcmp(soundEntry, "") != 0)
|
||||
nSoundEntryHash = GenerateSoundEntryHash(soundEntry);
|
||||
}
|
||||
#endif
|
||||
|
||||
CellRecipientFilter crf;
|
||||
crf.Initialize(players, size);
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
@ -368,7 +440,7 @@ void SoundHooks::OnEmitSound(IRecipientFilter &filter, int iEntIndex, int iChann
|
||||
-1,
|
||||
static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char*, unsigned int, const char*, float, soundlevel_t,
|
||||
int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound),
|
||||
(crf, iEntIndex, iChannel, buffer, -1, buffer, flVolume, iSoundlevel, nSeed, iFlags, iPitch, pOrigin,
|
||||
(crf, iEntIndex, iChannel, soundEntry, nSoundEntryHash, buffer, flVolume, iSoundlevel, nSeed, iFlags, iPitch, pOrigin,
|
||||
pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
|
||||
);
|
||||
#elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
|
||||
@ -421,6 +493,15 @@ void SoundHooks::OnEmitSound2(IRecipientFilter &filter, int iEntIndex, int iChan
|
||||
char buffer[PLATFORM_MAX_PATH];
|
||||
strcpy(buffer, pSample);
|
||||
|
||||
char soundEntry[PLATFORM_MAX_PATH] = "";
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
Q_strncpy(soundEntry, pSoundEntry, sizeof(soundEntry));
|
||||
#endif
|
||||
|
||||
#if SOURCE_ENGINE < SE_PORTAL2
|
||||
int nSeed = 0;
|
||||
#endif
|
||||
|
||||
for (iter=m_NormalFuncs.begin(); iter!=m_NormalFuncs.end(); iter++)
|
||||
{
|
||||
int players[SM_MAXPLAYERS], size;
|
||||
@ -436,6 +517,8 @@ void SoundHooks::OnEmitSound2(IRecipientFilter &filter, int iEntIndex, int iChan
|
||||
pFunc->PushCellByRef(&sndlevel);
|
||||
pFunc->PushCellByRef(&iPitch);
|
||||
pFunc->PushCellByRef(&iFlags);
|
||||
pFunc->PushStringEx(soundEntry, sizeof(soundEntry), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
|
||||
pFunc->PushCellByRef(&nSeed);
|
||||
g_InSoundHook = true;
|
||||
pFunc->Execute(&res);
|
||||
g_InSoundHook = false;
|
||||
@ -475,6 +558,16 @@ void SoundHooks::OnEmitSound2(IRecipientFilter &filter, int iEntIndex, int iChan
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
if (strcmp(pSoundEntry, soundEntry) != 0 || strcmp(pSample, buffer) != 0)
|
||||
{
|
||||
if (strcmp(soundEntry, buffer) == 0)
|
||||
nSoundEntryHash = -1;
|
||||
else if (strcmp(soundEntry, "") != 0)
|
||||
nSoundEntryHash = GenerateSoundEntryHash(soundEntry);
|
||||
}
|
||||
#endif
|
||||
|
||||
CellRecipientFilter crf;
|
||||
crf.Initialize(players, size);
|
||||
#if SOURCE_ENGINE >= SE_PORTAL2
|
||||
@ -483,7 +576,7 @@ void SoundHooks::OnEmitSound2(IRecipientFilter &filter, int iEntIndex, int iChan
|
||||
-1,
|
||||
static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char *, unsigned int, const char *, float, float,
|
||||
int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>(&IEngineSound::EmitSound),
|
||||
(crf, iEntIndex, iChannel, buffer, -1, buffer, flVolume, SNDLVL_TO_ATTN(static_cast<soundlevel_t>(sndlevel)),
|
||||
(crf, iEntIndex, iChannel, soundEntry, nSoundEntryHash, buffer, flVolume, SNDLVL_TO_ATTN(static_cast<soundlevel_t>(sndlevel)),
|
||||
nSeed, iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity)
|
||||
);
|
||||
#elif SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2
|
||||
@ -1037,6 +1130,147 @@ static cell_t EmitSound(IPluginContext *pContext, const cell_t *params)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t EmitSoundEntry(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
#if SOURCE_ENGINE < SE_PORTAL2
|
||||
return pContext->ThrowNativeError("EmitSoundEntry is not available in this game.");
|
||||
#else
|
||||
cell_t *addr, *cl_array;
|
||||
CellRecipientFilter crf;
|
||||
unsigned int numClients;
|
||||
int client;
|
||||
IGamePlayer *pPlayer = NULL;
|
||||
|
||||
pContext->LocalToPhysAddr(params[1], &cl_array);
|
||||
numClients = params[2];
|
||||
|
||||
/* Client validation */
|
||||
for (unsigned int i = 0; i < numClients; i++)
|
||||
{
|
||||
client = cl_array[i];
|
||||
pPlayer = playerhelpers->GetGamePlayer(client);
|
||||
|
||||
if (!pPlayer)
|
||||
{
|
||||
return pContext->ThrowNativeError("Client index %d is invalid", client);
|
||||
}
|
||||
else if (!pPlayer->IsInGame()) {
|
||||
return pContext->ThrowNativeError("Client %d is not connected", client);
|
||||
}
|
||||
}
|
||||
|
||||
crf.Initialize(cl_array, numClients);
|
||||
|
||||
char *soundEntry;
|
||||
pContext->LocalToString(params[3], &soundEntry);
|
||||
|
||||
char *sample;
|
||||
pContext->LocalToString(params[4], &sample);
|
||||
|
||||
// By default, we want the hash to equal maxint
|
||||
unsigned int soundEntryHash = -1;
|
||||
|
||||
// We only generate a hash if the sample is not the same as the sound entry and the sound entry is not empty.
|
||||
if (strcmp(soundEntry, sample) != 0 && strcmp(soundEntry, "") != 0)
|
||||
soundEntryHash = GenerateSoundEntryHash(soundEntry);
|
||||
|
||||
int entity = SoundReferenceToIndex(params[5]);
|
||||
int channel = params[6];
|
||||
int level = params[7];
|
||||
int seed = params[8];
|
||||
int flags = params[9];
|
||||
float vol = sp_ctof(params[10]);
|
||||
int pitch = params[11];
|
||||
int speakerentity = params[12];
|
||||
|
||||
Vector *pOrigin = NULL, origin;
|
||||
Vector *pDir = NULL, dir;
|
||||
|
||||
pContext->LocalToPhysAddr(params[13], &addr);
|
||||
if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
|
||||
{
|
||||
pOrigin = &origin;
|
||||
origin.x = sp_ctof(addr[0]);
|
||||
origin.y = sp_ctof(addr[1]);
|
||||
origin.z = sp_ctof(addr[2]);
|
||||
}
|
||||
|
||||
pContext->LocalToPhysAddr(params[14], &addr);
|
||||
if (addr != pContext->GetNullRef(SP_NULL_VECTOR))
|
||||
{
|
||||
pDir = &dir;
|
||||
dir.x = sp_ctof(addr[0]);
|
||||
dir.y = sp_ctof(addr[1]);
|
||||
dir.z = sp_ctof(addr[2]);
|
||||
}
|
||||
|
||||
bool updatePos = params[15] ? true : false;
|
||||
float soundtime = sp_ctof(params[16]);
|
||||
|
||||
CUtlVector<Vector> *pOrigVec = NULL;
|
||||
CUtlVector<Vector> origvec;
|
||||
if (params[0] > 16)
|
||||
{
|
||||
pOrigVec = &origvec;
|
||||
for (cell_t i = 17; i <= params[0]; i++)
|
||||
{
|
||||
Vector vec;
|
||||
pContext->LocalToPhysAddr(params[i], &addr);
|
||||
vec.x = sp_ctof(addr[0]);
|
||||
vec.y = sp_ctof(addr[1]);
|
||||
vec.z = sp_ctof(addr[2]);
|
||||
origvec.AddToTail(vec);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're going to a "local player" and this is a dedicated server,
|
||||
* intelligently redirect each sound.
|
||||
*/
|
||||
|
||||
if (entity == -2 && engine->IsDedicatedServer())
|
||||
{
|
||||
for (unsigned int i = 0; i < numClients; i++)
|
||||
{
|
||||
cell_t player[1];
|
||||
player[0] = cl_array[i];
|
||||
crf.Reset();
|
||||
crf.Initialize(player, 1);
|
||||
|
||||
if (g_InSoundHook)
|
||||
{
|
||||
SH_CALL(enginesoundPatch,
|
||||
static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char*, unsigned int, const char*, float,
|
||||
soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
|
||||
(&IEngineSound::EmitSound))(crf, player[0], channel, soundEntry, soundEntryHash, sample, vol, (soundlevel_t)level, seed,
|
||||
flags, pitch, pOrigin, pDir, pOrigVec, updatePos, soundtime, speakerentity);
|
||||
}
|
||||
else
|
||||
{
|
||||
engsound->EmitSound(crf, player[0], channel, soundEntry, soundEntryHash, sample, vol, (soundlevel_t)level, seed,
|
||||
flags, pitch, pOrigin, pDir, pOrigVec, updatePos, soundtime, speakerentity);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (g_InSoundHook)
|
||||
{
|
||||
SH_CALL(enginesoundPatch,
|
||||
static_cast<int (IEngineSound::*)(IRecipientFilter &, int, int, const char*, unsigned int, const char*, float,
|
||||
soundlevel_t, int, int, int, const Vector *, const Vector *, CUtlVector<Vector> *, bool, float, int)>
|
||||
(&IEngineSound::EmitSound))(crf, entity, channel, soundEntry, soundEntryHash, sample, vol, (soundlevel_t)level,
|
||||
seed, flags, pitch, pOrigin, pDir, pOrigVec, updatePos, soundtime, speakerentity);
|
||||
}
|
||||
else
|
||||
{
|
||||
engsound->EmitSound(crf, entity, channel, soundEntry, soundEntryHash, sample, vol, (soundlevel_t)level, seed,
|
||||
flags, pitch, pOrigin, pDir, pOrigVec, updatePos, soundtime, speakerentity);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static cell_t EmitSentence(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
cell_t *addr;
|
||||
@ -1253,6 +1487,7 @@ sp_nativeinfo_t g_SoundNatives[] =
|
||||
{"EmitAmbientSound", EmitAmbientSound},
|
||||
{"EmitSentence", EmitSentence},
|
||||
{"EmitSound", EmitSound},
|
||||
{"EmitSoundEntry", EmitSoundEntry},
|
||||
{"FadeClientVolume", FadeClientVolume},
|
||||
{"GetSoundDuration", GetSoundDuration},
|
||||
{"PrefetchSound", PrefetchSound},
|
||||
|
@ -221,6 +221,48 @@ native EmitSound(const clients[],
|
||||
Float:soundtime = 0.0,
|
||||
any:...);
|
||||
|
||||
/**
|
||||
* Emits a sound or game sound to a list of clients using the latest version of the engine sound interface.
|
||||
* This native is only available in engines that are greater than or equal to Portal 2.
|
||||
*
|
||||
* @param clients Array of client indexes.
|
||||
* @param numClients Number of clients in the array.
|
||||
* @param soundEntry Sound entry name.
|
||||
* @param sample Sound file name relative to the "sounds" folder.
|
||||
* @param entity Entity to emit from.
|
||||
* @param channel Channel to emit with.
|
||||
* @param level Sound level.
|
||||
* @param seed Sound seed.
|
||||
* @param flags Sound flags.
|
||||
* @param volume Sound volume.
|
||||
* @param pitch Sound pitch.
|
||||
* @param speakerentity Unknown.
|
||||
* @param origin Sound origin.
|
||||
* @param dir Sound direction.
|
||||
* @param updatePos Unknown (updates positions?)
|
||||
* @param soundtime Alternate time to play sound for.
|
||||
* @param ... Optional list of Float[3] arrays to specify additional origins.
|
||||
* @noreturn
|
||||
* @error Invalid client index.
|
||||
*/
|
||||
native EmitSoundEntry(const clients[],
|
||||
numClients,
|
||||
const String:soundEntry[],
|
||||
const String:sample[],
|
||||
entity = SOUND_FROM_PLAYER,
|
||||
channel = SNDCHAN_AUTO,
|
||||
level = SNDLEVEL_NORMAL,
|
||||
seed = 0,
|
||||
flags = SND_NOFLAGS,
|
||||
Float:volume = SNDVOL_NORMAL,
|
||||
pitch = SNDPITCH_NORMAL,
|
||||
speakerentity = -1,
|
||||
const Float:origin[3] = NULL_VECTOR,
|
||||
const Float:dir[3] = NULL_VECTOR,
|
||||
bool:updatePos = true,
|
||||
Float:soundtime = 0.0,
|
||||
any:...);
|
||||
|
||||
/**
|
||||
* Emits a sentence to a list of clients.
|
||||
*
|
||||
@ -307,6 +349,8 @@ typedef AmbientSHook = function Action (
|
||||
* @param level Sound level.
|
||||
* @param pitch Sound pitch.
|
||||
* @param flags Sound flags.
|
||||
* @param soundEntry Game sound entry name. (Used in engines newer than Portal 2)
|
||||
* @param seed Sound seed. (Used in engines newer than Portal 2)
|
||||
* @return Plugin_Continue to allow the sound to be played, Plugin_Stop to block it,
|
||||
* Plugin_Changed when any parameter has been modified.
|
||||
*/
|
||||
@ -319,7 +363,9 @@ typedef NormalSHook = function Action (
|
||||
float &volume,
|
||||
int &level,
|
||||
int &pitch,
|
||||
int &flags
|
||||
int &flags,
|
||||
char soundEntry[PLATFORM_MAX_PATH],
|
||||
int &seed
|
||||
);
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user