Skip to content

Commit d190da7

Browse files
committed
soundscape: extent it
1 parent 0770b6b commit d190da7

File tree

4 files changed

+358
-0
lines changed

4 files changed

+358
-0
lines changed

source/modules/soundscape.cpp

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
#include "LuaInterface.h"
55
#include "lua.h"
66
#include "player.h"
7+
#define private public
8+
#include "soundscape_system.h"
9+
#include "soundscape.h"
10+
#undef private
711

812
// memdbgon must be the last include file in a .cpp file!!!
913
#include "tier0/memdbgon.h"
@@ -24,6 +28,8 @@ class CSoundscapeModule : public IModule
2428
static CSoundscapeModule g_pSoundscapeModule;
2529
IModule* pSoundscapeModule = &g_pSoundscapeModule;
2630

31+
static ConVar soundscape_updateplayerhook("holylib_soundscape_updateplayerhook", "0", FCVAR_ARCHIVE, "If enabled, the soundscape hooks are called.");
32+
2733
static DTVarByOffset m_Local_Offset("DT_LocalPlayerExclusive", "m_Local");
2834
static DTVarByOffset m_Audio_Offset("DT_Local", "m_audio.localSound[0]");
2935
static inline audioparams_t* GetAudioParams(void* pPlayer)
@@ -85,6 +91,163 @@ LUA_FUNCTION_STATIC(soundscape_GetActivePositions)
8591
return 1;
8692
}
8793

94+
static CSoundscapeSystem* g_pSoundscapeSystem = nullptr;
95+
LUA_FUNCTION_STATIC(soundscape_GetAll)
96+
{
97+
if (!g_pSoundscapeSystem)
98+
LUA->ThrowError("Failed to load g_pSoundscapeSystem!");
99+
100+
LUA->CreateTable();
101+
102+
for (auto nIndex=g_pSoundscapeSystem->m_soundscapes.First(); nIndex != g_pSoundscapeSystem->m_soundscapes.InvalidIndex(); nIndex = g_pSoundscapeSystem->m_soundscapes.Next(nIndex))
103+
{
104+
LUA->PushString(g_pSoundscapeSystem->m_soundscapes.GetStringForKey(nIndex));
105+
LUA->PushNumber(g_pSoundscapeSystem->m_soundscapes.GetIDForKey(nIndex));
106+
107+
LUA->RawSet(-3);
108+
}
109+
110+
return 1;
111+
}
112+
113+
static bool IsValidStringIndex(int nIndex)
114+
{
115+
if (!g_pSoundscapeSystem)
116+
return false;
117+
118+
return nIndex >= 0 && nIndex < g_pSoundscapeSystem->m_soundscapeCount;
119+
}
120+
121+
LUA_FUNCTION_STATIC(soundscape_GetNameByIndex)
122+
{
123+
if (!g_pSoundscapeSystem)
124+
LUA->ThrowError("Failed to load g_pSoundscapeSystem!");
125+
126+
int nIndex = LUA->CheckNumber(1);
127+
if (!IsValidStringIndex(nIndex))
128+
{
129+
LUA->PushNil();
130+
return 1;
131+
}
132+
133+
const char* pName = g_pSoundscapeSystem->m_soundscapes.GetStringText(nIndex);
134+
if (!pName)
135+
{
136+
LUA->PushNil();
137+
return 1;
138+
}
139+
140+
LUA->PushString(pName);
141+
return 1;
142+
}
143+
144+
LUA_FUNCTION_STATIC(soundscape_GetIndexByName)
145+
{
146+
if (!g_pSoundscapeSystem)
147+
LUA->ThrowError("Failed to load g_pSoundscapeSystem!");
148+
149+
const char* pName = LUA->CheckString(1);
150+
151+
int nIndex = g_pSoundscapeSystem->m_soundscapes.GetStringID(pName);
152+
if (IsValidStringIndex(nIndex))
153+
LUA->PushNumber(nIndex);
154+
else
155+
LUA->PushNil();
156+
157+
return 1;
158+
}
159+
160+
LUA_FUNCTION_STATIC(soundscape_GetAllEntities)
161+
{
162+
if (!g_pSoundscapeSystem)
163+
LUA->ThrowError("Failed to load g_pSoundscapeSystem!");
164+
165+
int nCount = g_pSoundscapeSystem->m_soundscapeEntities.Count();
166+
LUA->PreCreateTable(nCount, 0);
167+
168+
int nLuaIndex = 0;
169+
for(int entityIndex = 0; entityIndex < nCount; ++entityIndex)
170+
{
171+
Util::Push_Entity(LUA, g_pSoundscapeSystem->m_soundscapeEntities[entityIndex]);
172+
Util::RawSetI(LUA, -2, ++nLuaIndex);
173+
}
174+
175+
return 1;
176+
}
177+
178+
static int nLastUpdateTick = -1;
179+
static std::unordered_set<CBasePlayer*> pHandledPlayers;
180+
static ss_update_t* pCurrentUpdate = nullptr;
181+
static Detouring::Hook detour_CEnvSoundscape_UpdateForPlayer;
182+
static Symbols::CEnvSoundscape_WriteAudioParamsTo func_CEnvSoundscape_WriteAudioParamsTo = nullptr;
183+
static void hook_CEnvSoundscape_UpdateForPlayer(CBaseEntity* pSoundScape, ss_update_t& update)
184+
{
185+
int nTick = gpGlobals->tickcount;
186+
if (nTick != nLastUpdateTick)
187+
pHandledPlayers.clear();
188+
189+
// Player got handled by Lua already, so we can skip
190+
if (update.pPlayer && pHandledPlayers.find(update.pPlayer) != pHandledPlayers.end())
191+
return;
192+
193+
// Can update.pPlayer even be NULL? Probably no
194+
if (soundscape_updateplayerhook.GetBool() && update.pPlayer && Lua::PushHook("HolyLib:OnSoundScapeUpdateForPlayer"))
195+
{
196+
pCurrentUpdate = &update;
197+
if (g_Lua->CallFunctionProtected(1, 1, true))
198+
{
199+
bool bCancel = g_Lua->GetBool(-1);
200+
g_Lua->Pop(1);
201+
202+
if (bCancel)
203+
{
204+
audioparams_t* pParams = GetAudioParams(update.pPlayer);
205+
if (pParams && func_CEnvSoundscape_WriteAudioParamsTo)
206+
func_CEnvSoundscape_WriteAudioParamsTo(update.pCurrentSoundscape, *pParams);
207+
208+
// We canceled, so we now, we don't want anything to mess with the player further, so we'll block further actions for this tick.
209+
pHandledPlayers.insert(update.pPlayer);
210+
pCurrentUpdate = nullptr;
211+
return;
212+
}
213+
}
214+
pCurrentUpdate = nullptr;
215+
}
216+
217+
detour_CEnvSoundscape_UpdateForPlayer.GetTrampoline<Symbols::CEnvSoundscape_UpdateForPlayer>()(pSoundScape, update);
218+
}
219+
220+
LUA_FUNCTION_STATIC(soundscape_SetCurrentDistance)
221+
{
222+
if (!pCurrentUpdate)
223+
LUA->ThrowError("Tried to use this function outside of a Soundscape hook call!");
224+
225+
// If one lets the Hook continue/doesn't cancel from Lua, then this can influence which other soundscape might get picked
226+
pCurrentUpdate->currentDistance = LUA->CheckNumber(1);
227+
pCurrentUpdate->bInRange = LUA->GetBool(2);
228+
return 0;
229+
}
230+
231+
// This basically is the only one realisticly useful
232+
// SetCurrentDistance & SetCurrentPlayerPosition are just to influence the soundscape selection
233+
LUA_FUNCTION_STATIC(soundscape_SetCurrentSoundscape)
234+
{
235+
if (!pCurrentUpdate)
236+
LUA->ThrowError("Tried to use this function outside of a Soundscape hook call!");
237+
238+
pCurrentUpdate->pCurrentSoundscape = (CEnvSoundscape*)Util::Get_Entity(LUA, 1, true);
239+
return 0;
240+
}
241+
242+
LUA_FUNCTION_STATIC(soundscape_SetCurrentPlayerPosition)
243+
{
244+
if (!pCurrentUpdate)
245+
LUA->ThrowError("Tried to use this function outside of a Soundscape hook call!");
246+
247+
pCurrentUpdate->playerPosition = *Get_Vector(LUA, 1, true);
248+
return 0;
249+
}
250+
88251
void CSoundscapeModule::Init(CreateInterfaceFn* appfn, CreateInterfaceFn* gamefn)
89252
{
90253
}
@@ -94,6 +257,18 @@ void CSoundscapeModule::InitDetour(bool bPreServer)
94257
if (bPreServer)
95258
return;
96259

260+
SourceSDK::FactoryLoader server_loader("server");
261+
Detour::Create(
262+
&detour_CEnvSoundscape_UpdateForPlayer, "CEnvSoundscape::UpdateForPlayer",
263+
server_loader.GetModule(), Symbols::CEnvSoundscape_UpdateForPlayerSym,
264+
(void*)hook_CEnvSoundscape_UpdateForPlayer, m_pID
265+
);
266+
267+
g_pSoundscapeSystem = Detour::ResolveSymbol<CSoundscapeSystem>(server_loader, Symbols::g_SoundscapeSystemSym);
268+
Detour::CheckValue("get class", "g_SoundscapeSystem", g_pSoundscapeSystem != nullptr);
269+
270+
func_CEnvSoundscape_WriteAudioParamsTo = (Symbols::CEnvSoundscape_WriteAudioParamsTo)Detour::GetFunction(server_loader.GetModule(), Symbols::CEnvSoundscape_WriteAudioParamsToSym);
271+
Detour::CheckFunction((void*)func_CEnvSoundscape_WriteAudioParamsTo, "CEnvSoundscape::WriteAudioParamsTo");
97272
}
98273

99274
void CSoundscapeModule::LuaInit(GarrysMod::Lua::ILuaInterface* pLua, bool bServerInit)
@@ -102,6 +277,15 @@ void CSoundscapeModule::LuaInit(GarrysMod::Lua::ILuaInterface* pLua, bool bServe
102277
Util::AddFunc(pLua, soundscape_GetActiveSoundScape, "GetActiveSoundScape");
103278
Util::AddFunc(pLua, soundscape_GetActiveSoundScapeIndex, "GetActiveSoundScapeIndex");
104279
Util::AddFunc(pLua, soundscape_GetActivePositions, "GetActivePositions");
280+
281+
Util::AddFunc(pLua, soundscape_GetAll, "GetAll");
282+
Util::AddFunc(pLua, soundscape_GetNameByIndex, "GetNameByIndex");
283+
Util::AddFunc(pLua, soundscape_GetIndexByName, "GetIndexByName");
284+
Util::AddFunc(pLua, soundscape_GetAllEntities, "GetAllEntities");
285+
286+
Util::AddFunc(pLua, soundscape_SetCurrentDistance, "SetCurrentDistance");
287+
Util::AddFunc(pLua, soundscape_SetCurrentSoundscape, "SetCurrentSoundscape");
288+
Util::AddFunc(pLua, soundscape_SetCurrentPlayerPosition, "SetCurrentPlayerPosition");
105289
Util::FinishTable(pLua, "soundscape");
106290
}
107291

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
//HOLYLIB_REQUIRES_MODULE=soundscape
2+
//========= Copyright Valve Corporation, All rights reserved. ============//
3+
//
4+
// Purpose: A registry of strings and associated ints
5+
//
6+
// $Workfile: $
7+
// $Date: $
8+
//
9+
//-----------------------------------------------------------------------------
10+
// $Log: $
11+
//
12+
// $NoKeywords: $
13+
//=============================================================================//
14+
15+
16+
#include <stdio.h>
17+
#include <string.h>
18+
#include "stringregistry.h"
19+
#include "utldict.h"
20+
21+
// memdbgon must be the last include file in a .cpp file!!!
22+
#include "tier0/memdbgon.h"
23+
24+
#if !defined(_STATIC_LINKED) || defined(CLIENT_DLL)
25+
26+
//-----------------------------------------------------------------------------
27+
// Purpose: This class wraps the containers that do the actual work
28+
//-----------------------------------------------------------------------------
29+
struct StringTable_t : public CUtlDict<int, unsigned short>
30+
{
31+
};
32+
33+
34+
35+
//-----------------------------------------------------------------------------
36+
// Purpose: Add null terminated string to the string registry
37+
// Input :
38+
// Output :
39+
//-----------------------------------------------------------------------------
40+
unsigned short CStringRegistry::AddString(const char *stringText, int stringID)
41+
{
42+
return m_pStringList->Insert( stringText, stringID );
43+
}
44+
45+
//-----------------------------------------------------------------------------
46+
// Purpose: Given string text get the string ID
47+
// Input : Text of string to find
48+
// Output : Return string id or -1 if no such string exists
49+
//-----------------------------------------------------------------------------
50+
int CStringRegistry::GetStringID( const char *stringText )
51+
{
52+
unsigned short index = m_pStringList->Find( stringText );
53+
if ( m_pStringList->IsValidIndex( index ) )
54+
{
55+
return (*m_pStringList)[index];
56+
}
57+
58+
return -1;
59+
}
60+
61+
//-----------------------------------------------------------------------------
62+
// Purpose: Given a string ID return the string text
63+
// Input : ID of string to find
64+
// Output : Return string text of NULL of no such ID exists
65+
//-----------------------------------------------------------------------------
66+
char const *CStringRegistry::GetStringText( int stringID )
67+
{
68+
for( unsigned short index = m_pStringList->First() ; index != m_pStringList->InvalidIndex(); index = m_pStringList->Next( index ) )
69+
{
70+
if ( (*m_pStringList)[index] == stringID )
71+
{
72+
return m_pStringList->GetElementName( index );
73+
}
74+
}
75+
76+
return NULL;
77+
}
78+
79+
80+
//-----------------------------------------------------------------------------
81+
// Purpose: Given a key return the string text
82+
//-----------------------------------------------------------------------------
83+
char const *CStringRegistry::GetStringForKey( unsigned short key )
84+
{
85+
if ( !m_pStringList->IsValidIndex( key ) )
86+
return NULL;
87+
88+
return m_pStringList->GetElementName( key );
89+
}
90+
91+
//-----------------------------------------------------------------------------
92+
// Purpose: Given a key return the string text
93+
//-----------------------------------------------------------------------------
94+
int CStringRegistry::GetIDForKey( unsigned short key )
95+
{
96+
if ( !m_pStringList->IsValidIndex( key ) )
97+
return 0;
98+
99+
return (*m_pStringList)[key];
100+
}
101+
102+
//-----------------------------------------------------------------------------
103+
// Purpose: Clear all strings from the string registry
104+
//-----------------------------------------------------------------------------
105+
void CStringRegistry::ClearStrings(void)
106+
{
107+
m_pStringList->RemoveAll();
108+
}
109+
110+
//-----------------------------------------------------------------------------
111+
// Purpose: Destructor - delete the list of strings and maps
112+
// Input :
113+
// Output :
114+
//-----------------------------------------------------------------------------
115+
CStringRegistry::~CStringRegistry(void)
116+
{
117+
delete m_pStringList;
118+
}
119+
120+
//-----------------------------------------------------------------------------
121+
// Purpose: Constructor
122+
// Input :
123+
// Output :
124+
//-----------------------------------------------------------------------------
125+
CStringRegistry::CStringRegistry(void)
126+
{
127+
m_pStringList = new StringTable_t;
128+
}
129+
130+
131+
unsigned short CStringRegistry::First() const
132+
{
133+
return m_pStringList->First();
134+
}
135+
136+
unsigned short CStringRegistry::Next( unsigned short key ) const
137+
{
138+
return m_pStringList->Next( key );
139+
}
140+
141+
unsigned short CStringRegistry::InvalidIndex() const
142+
{
143+
return m_pStringList->InvalidIndex();
144+
}
145+
146+
#endif // _STATIC_LINKED && CLIENT_DLL

source/symbols.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,4 +943,19 @@ namespace Symbols
943943
const std::vector<Symbol> Bootil_File_ChangeMonitor_HasChangedSym = {
944944
Symbol::FromName("_ZN6Bootil4File13ChangeMonitor10HasChangesEv"),
945945
};
946+
947+
//---------------------------------------------------------------------------------
948+
// Purpose: AutoRefresh Symbols
949+
//---------------------------------------------------------------------------------
950+
const std::vector<Symbol> CEnvSoundscape_UpdateForPlayerSym = {
951+
Symbol::FromName("_ZN14CEnvSoundscape15UpdateForPlayerER11ss_update_t"),
952+
};
953+
954+
const std::vector<Symbol> CEnvSoundscape_WriteAudioParamsToSym = {
955+
Symbol::FromName("_ZN14CEnvSoundscape18WriteAudioParamsToER13audioparams_t"),
956+
};
957+
958+
const std::vector<Symbol> g_SoundscapeSystemSym = {
959+
Symbol::FromName("g_SoundscapeSystem"),
960+
};
946961
}

0 commit comments

Comments
 (0)