From 497945bbbd18b4ff9cd264dc6a9d6cf8ba6bf08e Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Sat, 6 Jul 2024 12:40:36 +0200 Subject: Fix multiple audio file overrides (#677) This basically prevents audio files from being loaded into memory if matching audio event has already been overriden by a previous mod, preventing a crash from occurring. This means that audio mods now respect the load priority, i.e. mods with higher priority (= lower int value) will have priority over other mods on audio overrides. --- primedev/client/audio.cpp | 31 ++++++++++++++++++++++++++++--- primedev/client/audio.h | 4 ++-- primedev/mods/modmanager.cpp | 2 +- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/primedev/client/audio.cpp b/primedev/client/audio.cpp index 099fdcee..e5989f5c 100644 --- a/primedev/client/audio.cpp +++ b/primedev/client/audio.cpp @@ -7,6 +7,7 @@ #include #include #include +#include AUTOHOOK_INIT() @@ -28,7 +29,7 @@ unsigned char EMPTY_WAVE[45] = {0x52, 0x49, 0x46, 0x46, 0x25, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x44, 0xAC, 0x00, 0x00, 0x88, 0x58, 0x01, 0x00, 0x02, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x74, 0x00, 0x00, 0x00, 0x00}; -EventOverrideData::EventOverrideData(const std::string& data, const fs::path& path) +EventOverrideData::EventOverrideData(const std::string& data, const fs::path& path, const std::vector& registeredEvents) { if (data.length() <= 0) { @@ -191,6 +192,14 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa { std::string pathString = file.path().string(); + // Retrieve event id from path (standard?) + std::string eventId = file.path().parent_path().filename().string(); + if (std::find(registeredEvents.begin(), registeredEvents.end(), eventId) != registeredEvents.end()) + { + spdlog::warn("{} couldn't be loaded because {} event has already been overrided, skipping.", pathString, eventId); + continue; + } + // Open the file. std::ifstream wavStream(pathString, std::ios::binary); @@ -259,7 +268,7 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa LoadedSuccessfully = true; } -bool CustomAudioManager::TryLoadAudioOverride(const fs::path& defPath) +bool CustomAudioManager::TryLoadAudioOverride(const fs::path& defPath, std::string modName) { if (IsDedicatedServer()) return true; // silently fail @@ -279,19 +288,35 @@ bool CustomAudioManager::TryLoadAudioOverride(const fs::path& defPath) jsonStream.close(); - std::shared_ptr data = std::make_shared(jsonStringStream.str(), defPath); + // Pass the list of overriden events to avoid multiple event registrations crash + auto kv = std::views::keys(m_loadedAudioOverrides); + std::vector keys {kv.begin(), kv.end()}; + std::shared_ptr data = std::make_shared(jsonStringStream.str(), defPath, keys); if (!data->LoadedSuccessfully) return false; // no logging, the constructor has probably already logged for (const std::string& eventId : data->EventIds) { + if (m_loadedAudioOverrides.contains(eventId)) + { + spdlog::warn("\"{}\" mod tried to override sound event \"{}\" but it is already overriden, skipping.", modName, eventId); + continue; + } spdlog::info("Registering sound event {}", eventId); m_loadedAudioOverrides.insert({eventId, data}); } for (const auto& eventIdRegexData : data->EventIdsRegex) { + if (m_loadedAudioOverridesRegex.contains(eventIdRegexData.first)) + { + spdlog::warn( + "\"{}\" mod tried to override sound event regex \"{}\" but it is already overriden, skipping.", + modName, + eventIdRegexData.first); + continue; + } spdlog::info("Registering sound event regex {}", eventIdRegexData.first); m_loadedAudioOverridesRegex.insert({eventIdRegexData.first, data}); } diff --git a/primedev/client/audio.h b/primedev/client/audio.h index 15fd1a35..7cd0ddd1 100644 --- a/primedev/client/audio.h +++ b/primedev/client/audio.h @@ -15,7 +15,7 @@ enum class AudioSelectionStrategy class EventOverrideData { public: - EventOverrideData(const std::string&, const fs::path&); + EventOverrideData(const std::string&, const fs::path&, const std::vector& registeredEvents); EventOverrideData(); public: @@ -35,7 +35,7 @@ public: class CustomAudioManager { public: - bool TryLoadAudioOverride(const fs::path&); + bool TryLoadAudioOverride(const fs::path&, std::string modName); void ClearAudioOverrides(); std::shared_mutex m_loadingMutex; diff --git a/primedev/mods/modmanager.cpp b/primedev/mods/modmanager.cpp index edf69c9f..68f9bd0f 100644 --- a/primedev/mods/modmanager.cpp +++ b/primedev/mods/modmanager.cpp @@ -972,7 +972,7 @@ void ModManager::LoadMods() { if (fs::is_regular_file(file) && file.path().extension().string() == ".json") { - if (!g_CustomAudioManager.TryLoadAudioOverride(file.path())) + if (!g_CustomAudioManager.TryLoadAudioOverride(file.path(), mod.Name)) { spdlog::warn("Mod {} has an invalid audio def {}", mod.Name, file.path().filename().string()); continue; -- cgit v1.2.3 From 52b11022997c834efd2b50234e1e664603806503 Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Wed, 10 Jul 2024 01:21:40 +0200 Subject: fix: Do not crash on unknown MAD manifesto format (#749) Verify JSON has attributes before trying to access them --- primedev/mods/autodownload/moddownloader.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/primedev/mods/autodownload/moddownloader.cpp b/primedev/mods/autodownload/moddownloader.cpp index 3a946263..feaa08ea 100644 --- a/primedev/mods/autodownload/moddownloader.cpp +++ b/primedev/mods/autodownload/moddownloader.cpp @@ -92,6 +92,13 @@ void ModDownloader::FetchModsListFromAPI() verifiedModsJson.Parse(readBuffer); for (auto i = verifiedModsJson.MemberBegin(); i != verifiedModsJson.MemberEnd(); ++i) { + // Format testing + if (!i->value.HasMember("DependencyPrefix") || !i->value.HasMember("Versions")) + { + spdlog::warn("Verified mods manifesto format is unrecognized, skipping loading."); + return; + } + std::string name = i->name.GetString(); std::string dependency = i->value["DependencyPrefix"].GetString(); @@ -101,6 +108,13 @@ void ModDownloader::FetchModsListFromAPI() for (auto& attribute : versions.GetArray()) { assert(attribute.IsObject()); + // Format testing + if (!attribute.HasMember("Version") || !attribute.HasMember("Checksum")) + { + spdlog::warn("Verified mods manifesto format is unrecognized, skipping loading."); + return; + } + std::string version = attribute["Version"].GetString(); std::string checksum = attribute["Checksum"].GetString(); modVersions.insert({version, {.checksum = checksum}}); -- cgit v1.2.3 From acdfefdc335d5c7817c52986103d0ef2ce522ec9 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 10 Jul 2024 15:13:31 +0200 Subject: Fix typo in class member function (#750) `pushSQObject` does not exist Co-authored-by: EladNLG --- primedev/squirrel/squirrel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/primedev/squirrel/squirrel.h b/primedev/squirrel/squirrel.h index 1054de7f..1225f909 100644 --- a/primedev/squirrel/squirrel.h +++ b/primedev/squirrel/squirrel.h @@ -447,7 +447,7 @@ inline VoidFunction SQMessageBufferPushArg(Vector3& arg) { // Vectors template inline VoidFunction SQMessageBufferPushArg(SQObject* arg) { - return [arg]{ g_pSquirrel->pushSQObject(g_pSquirrel->m_pSQVM->sqvm, arg); }; + return [arg]{ g_pSquirrel->pushobject(g_pSquirrel->m_pSQVM->sqvm, arg); }; } // Ints template -- cgit v1.2.3 From 2cd78297274e1173d64f8f6e78383bfd6da88c7e Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 10 Jul 2024 15:13:52 +0200 Subject: Define `fs` alias in source file where used (#747) for filesystem namespace instead of relying on implicit include Co-authored-by: Jan --- primedev/client/audio.cpp | 2 ++ primedev/client/audio.h | 2 ++ primedev/client/languagehooks.cpp | 2 ++ primedev/core/hooks.cpp | 2 ++ primedev/mods/autodownload/moddownloader.h | 2 ++ primedev/mods/modmanager.h | 2 ++ primedev/plugins/pluginmanager.cpp | 2 ++ primedev/plugins/pluginmanager.h | 2 ++ primedev/server/buildainfile.cpp | 2 ++ primedev/squirrel/squirrel.h | 2 ++ 10 files changed, 20 insertions(+) diff --git a/primedev/client/audio.cpp b/primedev/client/audio.cpp index e5989f5c..63501414 100644 --- a/primedev/client/audio.cpp +++ b/primedev/client/audio.cpp @@ -9,6 +9,8 @@ #include #include +namespace fs = std::filesystem; + AUTOHOOK_INIT() static const char* pszAudioEventName; diff --git a/primedev/client/audio.h b/primedev/client/audio.h index 7cd0ddd1..22bcf3f0 100644 --- a/primedev/client/audio.h +++ b/primedev/client/audio.h @@ -5,6 +5,8 @@ #include #include +namespace fs = std::filesystem; + enum class AudioSelectionStrategy { INVALID = -1, diff --git a/primedev/client/languagehooks.cpp b/primedev/client/languagehooks.cpp index 0146d1d4..36b5d5ae 100644 --- a/primedev/client/languagehooks.cpp +++ b/primedev/client/languagehooks.cpp @@ -3,6 +3,8 @@ #include #include +namespace fs = std::filesystem; + AUTOHOOK_INIT() typedef LANGID (*Tier0_DetectDefaultLanguageType)(); diff --git a/primedev/core/hooks.cpp b/primedev/core/hooks.cpp index 6e849291..fef8bbcf 100644 --- a/primedev/core/hooks.cpp +++ b/primedev/core/hooks.cpp @@ -12,6 +12,8 @@ #define XINPUT1_3_DLL "XInput1_3.dll" +namespace fs = std::filesystem; + AUTOHOOK_INIT() // called from the ON_DLL_LOAD macros diff --git a/primedev/mods/autodownload/moddownloader.h b/primedev/mods/autodownload/moddownloader.h index 10df39ce..0d851e2f 100644 --- a/primedev/mods/autodownload/moddownloader.h +++ b/primedev/mods/autodownload/moddownloader.h @@ -1,3 +1,5 @@ +namespace fs = std::filesystem; + class ModDownloader { private: diff --git a/primedev/mods/modmanager.h b/primedev/mods/modmanager.h index 233f004d..95a8fe12 100644 --- a/primedev/mods/modmanager.h +++ b/primedev/mods/modmanager.h @@ -9,6 +9,8 @@ #include #include +namespace fs = std::filesystem; + const std::string MOD_FOLDER_SUFFIX = "\\mods"; const std::string THUNDERSTORE_MOD_FOLDER_SUFFIX = "\\packages"; const std::string REMOTE_MOD_FOLDER_SUFFIX = "\\runtime\\remote\\mods"; diff --git a/primedev/plugins/pluginmanager.cpp b/primedev/plugins/pluginmanager.cpp index 718e6956..14d5692b 100644 --- a/primedev/plugins/pluginmanager.cpp +++ b/primedev/plugins/pluginmanager.cpp @@ -5,6 +5,8 @@ #include "config/profile.h" #include "core/convar/concommand.h" +namespace fs = std::filesystem; + PluginManager* g_pPluginManager; const std::vector& PluginManager::GetLoadedPlugins() const diff --git a/primedev/plugins/pluginmanager.h b/primedev/plugins/pluginmanager.h index 8c021851..7993cbb8 100644 --- a/primedev/plugins/pluginmanager.h +++ b/primedev/plugins/pluginmanager.h @@ -3,6 +3,8 @@ #include +namespace fs = std::filesystem; + class Plugin; class PluginManager diff --git a/primedev/server/buildainfile.cpp b/primedev/server/buildainfile.cpp index a7f59961..19a6d0e3 100644 --- a/primedev/server/buildainfile.cpp +++ b/primedev/server/buildainfile.cpp @@ -5,6 +5,8 @@ #include #include +namespace fs = std::filesystem; + AUTOHOOK_INIT() const int AINET_VERSION_NUMBER = 57; diff --git a/primedev/squirrel/squirrel.h b/primedev/squirrel/squirrel.h index 1225f909..d747bce3 100644 --- a/primedev/squirrel/squirrel.h +++ b/primedev/squirrel/squirrel.h @@ -5,6 +5,8 @@ #include "core/math/vector.h" #include "mods/modmanager.h" +namespace fs = std::filesystem; + /* definitions from hell required to function -- cgit v1.2.3 From c4055830dd03ab3df11071bdf1f1f6410c79e055 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sun, 28 Jul 2024 13:14:09 +0100 Subject: Fix logging sometimes not working (#754) Revert #741 and remove log message since it's not a big deal --- primedev/logging/logging.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/primedev/logging/logging.cpp b/primedev/logging/logging.cpp index 4367b384..6d71eea0 100644 --- a/primedev/logging/logging.cpp +++ b/primedev/logging/logging.cpp @@ -124,11 +124,7 @@ void CustomSink::custom_log(const custom_log_msg& msg) void InitialiseConsole() { - if (GetConsoleWindow() == NULL && AllocConsole() == FALSE) - { - std::cout << "[*] Failed to create a console window" << std::endl; - } - else + if (AllocConsole() != FALSE) { freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); -- cgit v1.2.3 From 65516328610c136db00b644d06bdcf98912ddf70 Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Tue, 30 Jul 2024 00:40:59 +0200 Subject: Only fetch MAD manifesto on server join (#751) Previously, the verified mods manifesto was fetched on game start without checking if the verified mod feature is enabled Squirrel-side; with this, the manifesto is only fetched when the user wants to download a mod (meaning they enabled the feature beforehand). --- primedev/mods/autodownload/moddownloader.cpp | 17 ++++++++++++++++- primedev/mods/autodownload/moddownloader.h | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/primedev/mods/autodownload/moddownloader.cpp b/primedev/mods/autodownload/moddownloader.cpp index feaa08ea..8e533dec 100644 --- a/primedev/mods/autodownload/moddownloader.cpp +++ b/primedev/mods/autodownload/moddownloader.cpp @@ -55,6 +55,8 @@ size_t WriteToString(void* ptr, size_t size, size_t count, void* stream) void ModDownloader::FetchModsListFromAPI() { + modState.state = MANIFESTO_FETCHING; + std::thread requestThread( [this]() { @@ -63,6 +65,9 @@ void ModDownloader::FetchModsListFromAPI() rapidjson::Document verifiedModsJson; std::string url = modsListUrl; + // Empty verified mods manifesto + verifiedMods = {}; + curl_global_init(CURL_GLOBAL_ALL); easyhandle = curl_easy_init(); std::string readBuffer; @@ -75,7 +80,12 @@ void ModDownloader::FetchModsListFromAPI() curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &readBuffer); curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, WriteToString); result = curl_easy_perform(easyhandle); - ScopeGuard cleanup([&] { curl_easy_cleanup(easyhandle); }); + ScopeGuard cleanup( + [&] + { + curl_easy_cleanup(easyhandle); + modState.state = DOWNLOADING; + }); if (result == CURLcode::CURLE_OK) { @@ -614,7 +624,12 @@ void ModDownloader::DownloadMod(std::string modName, std::string modVersion) ON_DLL_LOAD_RELIESON("engine.dll", ModDownloader, (ConCommand), (CModule module)) { g_pModDownloader = new ModDownloader(); +} + +ADD_SQFUNC("void", NSFetchVerifiedModsManifesto, "", "", ScriptContext::SERVER | ScriptContext::CLIENT | ScriptContext::UI) +{ g_pModDownloader->FetchModsListFromAPI(); + return SQRESULT_NULL; } ADD_SQFUNC( diff --git a/primedev/mods/autodownload/moddownloader.h b/primedev/mods/autodownload/moddownloader.h index 0d851e2f..98fc27ae 100644 --- a/primedev/mods/autodownload/moddownloader.h +++ b/primedev/mods/autodownload/moddownloader.h @@ -116,6 +116,8 @@ public: enum ModInstallState { + MANIFESTO_FETCHING, + // Normal installation process DOWNLOADING, CHECKSUMING, -- cgit v1.2.3 From 51991cc45f8557dbeedbf6de176285e51a77676f Mon Sep 17 00:00:00 2001 From: EladNLG Date: Tue, 30 Jul 2024 01:52:15 +0300 Subject: Add CreateScriptInstance (#692) Adds a function that converts entities to SQObjects to the SquirrelManagers. --- primedev/squirrel/squirrel.cpp | 2 ++ primedev/squirrel/squirrel.h | 1 + primedev/squirrel/squirrelclasstypes.h | 1 + 3 files changed, 4 insertions(+) diff --git a/primedev/squirrel/squirrel.cpp b/primedev/squirrel/squirrel.cpp index f6df0c5f..29540cce 100644 --- a/primedev/squirrel/squirrel.cpp +++ b/primedev/squirrel/squirrel.cpp @@ -707,6 +707,7 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) g_pSquirrel->__sq_GetEntityConstant_CBaseEntity = module.Offset(0x3E49B0).RCast(); g_pSquirrel->__sq_getentityfrominstance = module.Offset(0x114F0).RCast(); + g_pSquirrel->__sq_createscriptinstance = module.Offset(0xC20E0).RCast(); g_pSquirrel->__sq_GetEntityConstant_CBaseEntity = g_pSquirrel->__sq_GetEntityConstant_CBaseEntity; g_pSquirrel->__sq_getentityfrominstance = g_pSquirrel->__sq_getentityfrominstance; @@ -800,6 +801,7 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerSquirrel, ConCommand, (CModule module)) g_pSquirrel->__sq_GetEntityConstant_CBaseEntity = module.Offset(0x418AF0).RCast(); g_pSquirrel->__sq_getentityfrominstance = module.Offset(0x1E920).RCast(); + g_pSquirrel->__sq_createscriptinstance = module.Offset(0x43F2F0).RCast(); g_pSquirrel->logger = NS::log::SCRIPT_SV; // Message buffer stuff diff --git a/primedev/squirrel/squirrel.h b/primedev/squirrel/squirrel.h index d747bce3..547b1efc 100644 --- a/primedev/squirrel/squirrel.h +++ b/primedev/squirrel/squirrel.h @@ -117,6 +117,7 @@ public: sq_getfunctionType __sq_getfunction; sq_getentityfrominstanceType __sq_getentityfrominstance; + sq_createscriptinstanceType __sq_createscriptinstance; sq_GetEntityConstantType __sq_GetEntityConstant_CBaseEntity; sq_pushnewstructinstanceType __sq_pushnewstructinstance; diff --git a/primedev/squirrel/squirrelclasstypes.h b/primedev/squirrel/squirrelclasstypes.h index 91c3c468..3a39c957 100644 --- a/primedev/squirrel/squirrelclasstypes.h +++ b/primedev/squirrel/squirrelclasstypes.h @@ -227,6 +227,7 @@ typedef SQRESULT (*sq_setuserdatatypeidType)(HSquirrelVM* sqvm, SQInteger iStack // sq misc entity funcs typedef void* (*sq_getentityfrominstanceType)(CSquirrelVM* sqvm, SQObject* pInstance, char** ppEntityConstant); +typedef SQObject* (*sq_createscriptinstanceType)(void* ent); typedef char** (*sq_GetEntityConstantType)(); typedef int (*sq_getfunctionType)(HSquirrelVM* sqvm, const char* name, SQObject* returnObj, const char* signature); -- cgit v1.2.3