diff --git a/primedev/client/audio.cpp b/primedev/client/audio.cpp index 099fdcee5..635014141 100644 --- a/primedev/client/audio.cpp +++ b/primedev/client/audio.cpp @@ -7,6 +7,9 @@ #include #include #include +#include + +namespace fs = std::filesystem; AUTOHOOK_INIT() @@ -28,7 +31,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 +194,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 +270,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 +290,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 15fd1a351..22bcf3f08 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, @@ -15,7 +17,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 +37,7 @@ class EventOverrideData 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/client/languagehooks.cpp b/primedev/client/languagehooks.cpp index 0146d1d4c..36b5d5aed 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 6e8492914..fef8bbcf1 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/logging/logging.cpp b/primedev/logging/logging.cpp index 4367b384b..6d71eea0a 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); diff --git a/primedev/mods/autodownload/moddownloader.cpp b/primedev/mods/autodownload/moddownloader.cpp index 3a9462630..8e533decb 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) { @@ -92,6 +102,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 +118,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}}); @@ -600,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 10df39ceb..98fc27ae3 100644 --- a/primedev/mods/autodownload/moddownloader.h +++ b/primedev/mods/autodownload/moddownloader.h @@ -1,3 +1,5 @@ +namespace fs = std::filesystem; + class ModDownloader { private: @@ -114,6 +116,8 @@ class ModDownloader enum ModInstallState { + MANIFESTO_FETCHING, + // Normal installation process DOWNLOADING, CHECKSUMING, diff --git a/primedev/mods/modmanager.cpp b/primedev/mods/modmanager.cpp index b99c87610..b3c8ab7ad 100644 --- a/primedev/mods/modmanager.cpp +++ b/primedev/mods/modmanager.cpp @@ -989,7 +989,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; diff --git a/primedev/mods/modmanager.h b/primedev/mods/modmanager.h index 5f6d07e75..3df7fe53e 100644 --- a/primedev/mods/modmanager.h +++ b/primedev/mods/modmanager.h @@ -9,6 +9,8 @@ #include #include +namespace fs = std::filesystem; + const std::string CORE_MOD_FOLDER_SUFFIX = "\\mods\\core"; const std::string MANUAL_MOD_FOLDER_SUFFIX = "\\mods\\manual"; const std::string THUNDERSTORE_LEGACY_MOD_FOLDER_SUFFIX = "\\mods\\thunderstore-legacy"; diff --git a/primedev/plugins/pluginmanager.cpp b/primedev/plugins/pluginmanager.cpp index 1abd0def2..0b89f76e6 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 8c0218510..7993cbb86 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 a7f599618..19a6d0e36 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.cpp b/primedev/squirrel/squirrel.cpp index f6df0c5f3..29540ccea 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 1054de7f9..547b1efcd 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 @@ -115,6 +117,7 @@ class SquirrelManagerBase sq_getfunctionType __sq_getfunction; sq_getentityfrominstanceType __sq_getentityfrominstance; + sq_createscriptinstanceType __sq_createscriptinstance; sq_GetEntityConstantType __sq_GetEntityConstant_CBaseEntity; sq_pushnewstructinstanceType __sq_pushnewstructinstance; @@ -447,7 +450,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 diff --git a/primedev/squirrel/squirrelclasstypes.h b/primedev/squirrel/squirrelclasstypes.h index 91c3c4683..3a39c957e 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);