From 8c593f666f259acb7e034351adc654bb3f07ca5c Mon Sep 17 00:00:00 2001
From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com>
Date: Sat, 16 Mar 2024 11:47:59 +0100
Subject: [PATCH] Miles: add global type and prevent non-existent banks from
 loading

This patch adds miles globals and additional code to prevent banks from loading that don't exist. It falls back to "english" if requested language isn't installed.
---
 r5dev/codecs/Miles/miles_impl.cpp | 38 +++++++++++++++++++++++--
 r5dev/codecs/Miles/miles_impl.h   | 47 ++++++++++++++++++++++++++++++-
 r5dev/public/tier1/stringpool.h   |  4 +--
 3 files changed, 84 insertions(+), 5 deletions(-)

diff --git a/r5dev/codecs/Miles/miles_impl.cpp b/r5dev/codecs/Miles/miles_impl.cpp
index e083da56..ed56aa71 100644
--- a/r5dev/codecs/Miles/miles_impl.cpp
+++ b/r5dev/codecs/Miles/miles_impl.cpp
@@ -1,9 +1,11 @@
 #include "core/stdafx.h"
 #include "miles_impl.h"
 #include "tier0/fasttimer.h"
+#include "tier0/commandline.h"
 #include "tier1/cvar.h"
+#include "filesystem/filesystem.h"
 
-ConVar miles_debug("miles_debug", "0", FCVAR_RELEASE, "Enables debug prints for the Miles Sound System", "1 = print; 0 (zero) = no print");
+static ConVar miles_debug("miles_debug", "0", FCVAR_RELEASE, "Enables debug prints for the Miles Sound System", "1 = print; 0 (zero) = no print");
 
 //-----------------------------------------------------------------------------
 // Purpose: logs debug output emitted from the Miles Sound System
@@ -24,8 +26,24 @@ bool Miles_Initialize()
 {
 	const char* pszLanguage = miles_language->GetString();
 	if (!pszLanguage[0])
-	{
 		pszLanguage = MILES_DEFAULT_LANGUAGE;
+
+	const bool isEnglishLanguage = _stricmp(pszLanguage, "english") == 0;
+
+	if (!isEnglishLanguage)
+	{
+		const bool useShipSound = !CommandLine()->FindParm("-devsound") || CommandLine()->FindParm("-shipsound");
+
+		const std::string baseStreamFilePath = Format("%s/general_%s.mstr", useShipSound ? "audio/ship" : "audio/dev", pszLanguage);
+
+		// if the requested language for miles does not have a MSTR file present, throw a non-fatal error and force english as a fallback
+		// if we are loading english and the file is still not found, we can let it hit the regular engine error, since that is not recoverable
+		if (!FileSystem()->FileExists(baseStreamFilePath.c_str()))
+		{
+			Error(eDLL_T::AUDIO, NO_ERROR, "%s: attempted to load language '%s' but the required stream bank (%s) was not found. falling back to english...\n", pszLanguage, baseStreamFilePath.c_str());
+
+			pszLanguage = MILES_DEFAULT_LANGUAGE;
+		}
 	}
 
 	Msg(eDLL_T::AUDIO, "%s: initializing MSS with language: '%s'\n", __FUNCTION__, pszLanguage);
@@ -53,6 +71,21 @@ void MilesBankPatch(Miles::Bank* bank, char* streamPatch, char* localizedStreamP
 	v_MilesBankPatch(bank, streamPatch, localizedStreamPatch);
 }
 
+void CSOM_AddEventToQueue(const char* eventName)
+{
+	if (miles_debug.GetBool())
+		Msg(eDLL_T::AUDIO, "%s: queuing audio event '%s'\n", __FUNCTION__, eventName);
+
+	v_CSOM_AddEventToQueue(eventName);
+
+	if (g_milesGlobals->queuedEventHash == 1)
+		Warning(eDLL_T::AUDIO, "%s: failed to add event to queue; invalid event name '%s'\n", __FUNCTION__, eventName);
+
+	if (g_milesGlobals->queuedEventHash == 2)
+		Warning(eDLL_T::AUDIO, "%s: failed to add event to queue; event '%s' not found.\n", __FUNCTION__, eventName);
+};
+
+
 ///////////////////////////////////////////////////////////////////////////////
 void MilesCore::Detour(const bool bAttach) const
 {
@@ -60,4 +93,5 @@ void MilesCore::Detour(const bool bAttach) const
 	DetourSetup(&v_Miles_Initialize, &Miles_Initialize, bAttach);
 	DetourSetup(&v_MilesQueueEventRun, &MilesQueueEventRun, bAttach);
 	DetourSetup(&v_MilesBankPatch, &MilesBankPatch, bAttach);
+	DetourSetup(&v_CSOM_AddEventToQueue, &CSOM_AddEventToQueue, bAttach);
 }
diff --git a/r5dev/codecs/Miles/miles_impl.h b/r5dev/codecs/Miles/miles_impl.h
index 322be48b..74c4483c 100644
--- a/r5dev/codecs/Miles/miles_impl.h
+++ b/r5dev/codecs/Miles/miles_impl.h
@@ -6,6 +6,44 @@ inline void(*v_AIL_LogFunc)(int64_t nLogLevel, const char* pszMessage);
 inline bool(*v_Miles_Initialize)();
 inline void(*v_MilesQueueEventRun)(Miles::Queue*, const char*);
 inline void(*v_MilesBankPatch)(Miles::Bank*, char*, char*);
+inline void(*v_CSOM_AddEventToQueue)(const char* eventName);
+
+struct MilesBankList_t
+{
+	char banks[64][16];
+	int bankCount;
+};
+
+struct MilesGlobalState_t
+{
+	char gap0[24];
+	bool mismatchedBuildTag;
+	char gap19[63];
+	uintptr_t queuedEventHash;
+	char gap60[4];
+	Vector3D queuedSoundPosition;
+	char gap70[24];
+	float soundMasterVolume;
+	char gap8c[28];
+	void* samplesXlogType;
+	char gapB0[8];
+	void* dumpXlogType;
+	char gapC0[48];
+	void* driver;
+	void* queue;
+	char gap100[40];
+	MilesBankList_t bankList;
+	char gap52c[4];
+	void* loadedBanks[16];
+	char gap5b0[290448];
+	HANDLE milesInitializedEvent;
+	HANDLE milesThread;
+	char gap47450[272];
+	char milesOutputBuffer[1024];
+	char unk[96];
+};
+
+inline MilesGlobalState_t* g_milesGlobals;
 
 ///////////////////////////////////////////////////////////////////////////////
 class MilesCore : public IDetour
@@ -16,11 +54,18 @@ class MilesCore : public IDetour
 		LogFunAdr("Miles_Initialize", v_Miles_Initialize);
 		LogFunAdr("MilesQueueEventRun", v_MilesQueueEventRun);
 		LogFunAdr("MilesBankPatch", v_MilesBankPatch);
+		LogFunAdr("CSOM_AddEventToQueue", v_CSOM_AddEventToQueue);
+		LogVarAdr("g_milesGlobals", g_milesGlobals);
 	}
 	virtual void GetFun(void) const
 	{
 		g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 48 8B DA 48 8D 15 ?? ?? ?? ??").GetPtr(v_AIL_LogFunc);
-		g_GameDll.FindPatternSIMD("40 53 56 57 41 54 41 55 41 56 41 57 48 81 EC ?? ?? ?? ?? 80 3D ?? ?? ?? ?? ??").GetPtr(v_Miles_Initialize);
+		g_GameDll.FindPatternSIMD("0F B6 11 4C 8B C1").GetPtr(v_CSOM_AddEventToQueue);
+		
+		CMemory milesInitializeFunc = g_GameDll.FindPatternSIMD("40 53 56 57 41 54 41 55 41 56 41 57 48 81 EC ?? ?? ?? ?? 80 3D ?? ?? ?? ?? ??");
+		milesInitializeFunc.GetPtr(v_Miles_Initialize);
+
+		g_milesGlobals = milesInitializeFunc.FindPatternSelf("48 8D", CMemory::Direction::DOWN, 0x50).ResolveRelativeAddressSelf(0x3, 0x7).RCast<MilesGlobalState_t*>();
 
 		g_RadAudioSystemDll.GetExportedSymbol("MilesQueueEventRun").GetPtr(v_MilesQueueEventRun);
 		g_RadAudioSystemDll.GetExportedSymbol("MilesBankPatch").GetPtr(v_MilesBankPatch);
diff --git a/r5dev/public/tier1/stringpool.h b/r5dev/public/tier1/stringpool.h
index 3ff006cf..7f753e1a 100644
--- a/r5dev/public/tier1/stringpool.h
+++ b/r5dev/public/tier1/stringpool.h
@@ -345,10 +345,10 @@ inline void CCountedStringPoolBase<T>::SpewStrings()
 		char* pString = m_Elements[i].pString;
 		NOTE_UNUSED(pString);
 
-		DevMsg("String %d: ref:%hhu %s\n", i, m_Elements[i].nReferenceCount, pString == NULL? "EMPTY - ok for slot zero only!" : pString);
+		DevMsg(eDLL_T::COMMON, "String %d: ref:%hhu %s\n", i, m_Elements[i].nReferenceCount, pString == NULL? "EMPTY - ok for slot zero only!" : pString);
 	}
 
-	DevMsg("\n%d total counted strings.", m_Elements.Count());
+	DevMsg(eDLL_T::COMMON, "\n%d total counted strings.", m_Elements.Count());
 }
 
 #define STRING_POOL_VERSION		MAKEID( 'C', 'S', 'P', '1' )