From 76b504949e960799b5633137583e67772357a93d Mon Sep 17 00:00:00 2001 From: F1F7Y <64418963+F1F7Y@users.noreply.github.com> Date: Wed, 9 Aug 2023 12:27:51 +0200 Subject: [PATCH] logging refactor (#3) * Add basic logging functions * Move to new logging functions * Fix compilation * Gracefully terminate when our directory isnt writable * Add `-wconsole` argument * Use new functions in more places * Add helper funcs * Thanks spoon * Print to game console * Stop using NS::log and spdlog:: in squirrel * add log context string to each print * Print to win terminal * Don't automatically add eol * Properly shutdown spdlog * Fixup some messages * Formatting * Use spaces in CMakeLists.txt * Formatting * Use new funcs fol plugin log * Always allocate console when we'rea dedi * Update dedilogtoclient * Remove old logging classes * Fix PLUGIN_LOG * Color logging * Don't log searchpath * Fix masterserver error log * Properly break in switch in spew func * Remove comment * Log to disk * Format * Terminate on fatal error call * Improve doc comments in `dbg.cpp` * Use displayName for plugin logging * Improve more doc comments * add `-nologfiles` argument * Rename `g_bSpdLog_UseAnsiColor` to `g_bConsole_UseAnsiColor` * Add plugin color * Adjust colors * Add missing newlines * Fix specifier * Separate SQ_GetLogContext into native and script versions * Replace spdlog::info i missed * Format * Only close console once gamewindow has been created * Improve log categories * Fix compile error context * Fix missed format in `scriptdatatables.cpp` * Rename `pszAnsiString` to `svAnsiString` * Add lock guard * Don't try to show messagebox when we're a dedicated server on error * Rename `fLogger` to `pLogger` * Use new funcs for system info * Rename `StartupLog` to `Sys_PrintOSVer` * Initilaze `g_svLogDirectory` directly in `InitilazeNorthstar` * Cleanup `InitilaseNorthstar` * Add back ntdll check --- NorthstarDLL/CMakeLists.txt | 2 + NorthstarDLL/client/audio.cpp | 107 +++--- NorthstarDLL/client/clientvideooverrides.cpp | 2 +- NorthstarDLL/client/languagehooks.cpp | 27 +- NorthstarDLL/client/latencyflex.cpp | 4 +- NorthstarDLL/client/localchatwriter.cpp | 2 +- NorthstarDLL/client/modlocalisation.cpp | 6 +- NorthstarDLL/core/convar/concommand.cpp | 4 +- NorthstarDLL/core/convar/convar.cpp | 8 +- NorthstarDLL/core/filesystem/filesystem.cpp | 5 +- .../core/filesystem/rpakfilesystem.cpp | 10 +- NorthstarDLL/core/hooks.cpp | 19 +- NorthstarDLL/core/hooks.h | 6 +- NorthstarDLL/core/math/color.h | 4 +- NorthstarDLL/core/sourceinterface.cpp | 6 +- NorthstarDLL/core/sourceinterface.h | 2 +- NorthstarDLL/dedicated/dedicated.cpp | 17 +- .../dedicated/dedicatedlogtoclient.cpp | 17 +- NorthstarDLL/dedicated/dedicatedlogtoclient.h | 10 +- NorthstarDLL/dllmain.cpp | 32 +- NorthstarDLL/engine/host.cpp | 2 +- NorthstarDLL/engine/hoststate.cpp | 14 +- NorthstarDLL/engine/r2engine.h | 2 + NorthstarDLL/logging/dbg.cpp | 248 ++++++++++++++ NorthstarDLL/logging/dbg.h | 101 ++++++ NorthstarDLL/logging/logging.cpp | 320 ++++++++---------- NorthstarDLL/logging/logging.h | 158 ++------- NorthstarDLL/logging/loghooks.cpp | 37 +- NorthstarDLL/logging/sourceconsole.cpp | 35 -- NorthstarDLL/logging/sourceconsole.h | 19 -- NorthstarDLL/masterserver/masterserver.cpp | 206 ++++++----- NorthstarDLL/mods/compiled/kb_act.cpp | 2 +- NorthstarDLL/mods/compiled/modkeyvalues.cpp | 4 +- NorthstarDLL/mods/compiled/modpdef.cpp | 2 +- NorthstarDLL/mods/compiled/modscriptsrson.cpp | 2 +- NorthstarDLL/mods/modmanager.cpp | 190 +++++++---- NorthstarDLL/mods/modmanager.h | 2 +- NorthstarDLL/pch.h | 3 + NorthstarDLL/plugins/pluginbackend.cpp | 7 +- NorthstarDLL/plugins/plugins.cpp | 92 +++-- NorthstarDLL/plugins/plugins.h | 2 - NorthstarDLL/scripts/scriptdatatables.cpp | 8 +- .../scripts/scripthttprequesthandler.cpp | 64 ++-- NorthstarDLL/scripts/scriptjson.cpp | 6 +- .../scripts/server/miscserverscript.cpp | 8 +- NorthstarDLL/server/auth/bansystem.cpp | 4 +- .../server/auth/serverauthentication.cpp | 8 +- NorthstarDLL/server/buildainfile.cpp | 55 ++- NorthstarDLL/server/servernethooks.cpp | 55 +-- .../shared/exploit_fixes/exploitfixes.cpp | 8 +- .../shared/exploit_fixes/ns_limits.cpp | 12 +- NorthstarDLL/shared/misccommands.cpp | 14 +- NorthstarDLL/shared/playlist.cpp | 2 +- NorthstarDLL/squirrel/squirrel.cpp | 110 +++--- NorthstarDLL/squirrel/squirrel.h | 33 +- NorthstarDLL/squirrel/squirrelautobind.cpp | 2 +- NorthstarDLL/util/printcommands.cpp | 14 +- NorthstarDLL/util/printmaps.cpp | 6 +- NorthstarDLL/util/utils.cpp | 55 +++ NorthstarDLL/util/utils.h | 7 +- thirdparty/spdlog/tweakme.h | 2 +- 61 files changed, 1320 insertions(+), 891 deletions(-) create mode 100644 NorthstarDLL/logging/dbg.cpp create mode 100644 NorthstarDLL/logging/dbg.h diff --git a/NorthstarDLL/CMakeLists.txt b/NorthstarDLL/CMakeLists.txt index 5c275887c..f992f5610 100644 --- a/NorthstarDLL/CMakeLists.txt +++ b/NorthstarDLL/CMakeLists.txt @@ -66,6 +66,8 @@ add_library(NorthstarDLL SHARED "engine/runframe.cpp" "logging/crashhandler.cpp" "logging/crashhandler.h" + "logging/dbg.cpp" + "logging/dbg.h" "logging/logging.cpp" "logging/logging.h" "logging/loghooks.cpp" diff --git a/NorthstarDLL/client/audio.cpp b/NorthstarDLL/client/audio.cpp index 66d344046..033c5374a 100644 --- a/NorthstarDLL/client/audio.cpp +++ b/NorthstarDLL/client/audio.cpp @@ -23,7 +23,7 @@ CustomAudioManager g_CustomAudioManager; EventOverrideData::EventOverrideData() { - spdlog::warn("Initialised struct EventOverrideData without any data!"); + Warning(eLog::AUDIO, "Initialised struct EventOverrideData without any data!\n"); LoadedSuccessfully = false; } @@ -36,7 +36,7 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa { if (data.length() <= 0) { - spdlog::error("Failed reading audio override file {}: file is empty", path.string()); + Error(eLog::AUDIO, NO_ERROR, "Failed reading audio override file %s: file is empty\n", path.string().c_str()); return; } @@ -45,10 +45,12 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa if (!fs::exists(samplesFolder)) { - spdlog::error( - "Failed reading audio override file {}: samples folder doesn't exist; should be named the same as the definition file without " - "JSON extension.", - path.string()); + Error( + eLog::AUDIO, + NO_ERROR, + "Failed reading audio override file %s: samples folder doesn't exist; should be named the same as the definition file without " + "JSON extension.\n", + path.string().c_str()); return; } @@ -58,9 +60,11 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa // fail if parse error if (dataJson.HasParseError()) { - spdlog::error( - "Failed reading audio override file {}: encountered parse error \"{}\" at offset {}", - path.string(), + Error( + eLog::AUDIO, + NO_ERROR, + "Failed reading audio override file %s: encountered parse error \"%s\" at offset %i\n", + path.string().c_str(), GetParseError_En(dataJson.GetParseError()), dataJson.GetErrorOffset()); return; @@ -69,14 +73,18 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa // fail if it's not a json obj (could be an array, string, etc) if (!dataJson.IsObject()) { - spdlog::error("Failed reading audio override file {}: file is not a JSON object", path.string()); + Error(eLog::AUDIO, NO_ERROR, "Failed reading audio override file %s: file is not a JSON object\n", path.string().c_str()); return; } // fail if no event ids given if (!dataJson.HasMember("EventId")) { - spdlog::error("Failed reading audio override file {}: JSON object does not have the EventId property", path.string()); + Error( + eLog::AUDIO, + NO_ERROR, + "Failed reading audio override file %s: JSON object does not have the EventId property\n", + path.string().c_str()); return; } @@ -87,8 +95,11 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa { if (!eventId.IsString()) { - spdlog::error( - "Failed reading audio override file {}: EventId array has a value of invalid type, all must be strings", path.string()); + Error( + eLog::AUDIO, + NO_ERROR, + "Failed reading audio override file %s: EventId array has a value of invalid type, all must be strings\n", + path.string().c_str()); return; } @@ -103,9 +114,11 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa // incorrect type else { - spdlog::error( - "Failed reading audio override file {}: EventId property is of invalid type (must be a string or an array of strings)", - path.string()); + Error( + eLog::AUDIO, + NO_ERROR, + "Failed reading audio override file %s: EventId property is of invalid type (must be a string or an array of strings)\n", + path.string().c_str()); return; } @@ -118,9 +131,11 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa { if (!eventId.IsString()) { - spdlog::error( - "Failed reading audio override file {}: EventIdRegex array has a value of invalid type, all must be strings", - path.string()); + Error( + eLog::AUDIO, + NO_ERROR, + "Failed reading audio override file %s: EventIdRegex array has a value of invalid type, all must be strings\n", + path.string().c_str()); return; } @@ -132,7 +147,8 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa } catch (...) { - spdlog::error("Malformed regex \"{}\" in audio override file {}", regex, path.string()); + Error( + eLog::AUDIO, NO_ERROR, "Malformed regex \"%s\" in audio override file %s\n", regex.c_str(), path.string().c_str()); return; } } @@ -147,16 +163,19 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa } catch (...) { - spdlog::error("Malformed regex \"{}\" in audio override file {}", regex, path.string()); + Error(eLog::AUDIO, NO_ERROR, "Malformed regex \"%s\" in audio override file %s\n", regex.c_str(), path.string().c_str()); return; } } // incorrect type else { - spdlog::error( - "Failed reading audio override file {}: EventIdRegex property is of invalid type (must be a string or an array of strings)", - path.string()); + Error( + eLog::AUDIO, + NO_ERROR, + "Failed reading audio override file %s: EventIdRegex property is of invalid type (must be a string or an array of " + "strings)\n", + path.string().c_str()); return; } } @@ -165,7 +184,11 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa { if (!dataJson["AudioSelectionStrategy"].IsString()) { - spdlog::error("Failed reading audio override file {}: AudioSelectionStrategy property must be a string", path.string()); + Error( + eLog::AUDIO, + NO_ERROR, + "Failed reading audio override file %s: AudioSelectionStrategy property must be a string\n", + path.string().c_str()); return; } @@ -181,9 +204,11 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa } else { - spdlog::error( - "Failed reading audio override file {}: AudioSelectionStrategy string must be either \"sequential\" or \"random\"", - path.string()); + Error( + eLog::AUDIO, + NO_ERROR, + "Failed reading audio override file %s: AudioSelectionStrategy string must be either \"sequential\" or \"random\"\n", + path.string().c_str()); return; } } @@ -200,7 +225,7 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa if (wavStream.fail()) { - spdlog::error("Failed reading audio sample {}", file.path().string()); + Error(eLog::AUDIO, NO_ERROR, "Failed reading audio sample %s\n", file.path().string().c_str()); continue; } @@ -226,7 +251,7 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa // would be weird if this got hit, since it would've worked previously if (wavStream.fail()) { - spdlog::error("Failed async read of audio sample {}", pathString); + Error(eLog::AUDIO, NO_ERROR, "Failed async read of audio sample %s\n", pathString.c_str()); return; } @@ -235,7 +260,7 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa wavStream.read(reinterpret_cast(data), fileSize); wavStream.close(); - spdlog::info("Finished async read of audio sample {}", pathString); + DevMsg(eLog::AUDIO, "Finished async read of audio sample %s\n", pathString.c_str()); }); readThread.detach(); @@ -256,9 +281,9 @@ EventOverrideData::EventOverrideData(const std::string& data, const fs::path& pa */ if (Samples.size() == 0) - spdlog::warn("Audio override {} has no valid samples! Sounds will not play for this event.", path.string()); + Warning(eLog::AUDIO, "Audio override %s has no valid samples! Sounds will not play for this event.\n", path.string().c_str()); - spdlog::info("Loaded audio override file {}", path.string()); + DevMsg(eLog::AUDIO, "Loaded audio override file %s\n", path.string().c_str()); LoadedSuccessfully = true; } @@ -274,7 +299,7 @@ bool CustomAudioManager::TryLoadAudioOverride(const fs::path& defPath) // fail if no audio json if (jsonStream.fail()) { - spdlog::warn("Unable to read audio override from file {}", defPath.string()); + Warning(eLog::AUDIO, "Unable to read audio override from file %s\n", defPath.string().c_str()); return false; } @@ -290,13 +315,13 @@ bool CustomAudioManager::TryLoadAudioOverride(const fs::path& defPath) for (const std::string& eventId : data->EventIds) { - spdlog::info("Registering sound event {}", eventId); + DevMsg(eLog::AUDIO, "Registering sound event %s\n", eventId.c_str()); m_loadedAudioOverrides.insert({eventId, data}); } for (const auto& eventIdRegexData : data->EventIdsRegex) { - spdlog::info("Registering sound event regex {}", eventIdRegexData.first); + DevMsg(eLog::AUDIO, "Registering sound event regex %s\n", eventIdRegexData.first.c_str()); m_loadedAudioOverridesRegex.insert({eventIdRegexData.first, data}); } @@ -394,7 +419,7 @@ bool __declspec(noinline) __fastcall LoadSampleMetadata_Internal( char* eventName = (char*)parentEvent + 0x110; if (Cvar_ns_print_played_sounds->GetInt() > 0) - spdlog::info("[AUDIO] Playing event {}", eventName); + DevMsg(eLog::AUDIO, "Playing event %s\n", eventName); auto iter = g_CustomAudioManager.m_loadedAudioOverrides.find(eventName); std::shared_ptr overrideData; @@ -461,7 +486,7 @@ bool __declspec(noinline) __fastcall LoadSampleMetadata_Internal( } if (!dat) - spdlog::warn("Could not get sample data from override struct for event {}! Shouldn't happen", eventName); + Warning(eLog::AUDIO, "Could not get sample data from override struct for event %s! Shouldn't happen\n", eventName); else { data = dat->second.get(); @@ -471,7 +496,7 @@ bool __declspec(noinline) __fastcall LoadSampleMetadata_Internal( if (!data) { - spdlog::warn("Could not fetch override sample data for event {}! Using original data instead.", eventName); + Warning(eLog::AUDIO, "Could not fetch override sample data for event {}! Using original data instead.\n", eventName); return LoadSampleMetadata(sample, audioBuffer, audioBufferLength, audioType); } @@ -485,7 +510,7 @@ bool __declspec(noinline) __fastcall LoadSampleMetadata_Internal( // 64 - Auto-detect sample type bool res = LoadSampleMetadata(sample, audioBuffer, audioBufferLength, 64); if (!res) - spdlog::error("LoadSampleMetadata failed! The game will crash :("); + Error(eLog::AUDIO, NO_ERROR, "LoadSampleMetadata failed! The game will crash :(\n"); return res; } @@ -498,7 +523,7 @@ void, __fastcall, (int level, const char* string)) if (!Cvar_mileslog_enable->GetBool()) return; - spdlog::info("[MSS] {} - {}", level, string); + DevMsg(eLog::AUDIO, "%i - %s\n", level, string); } ON_DLL_LOAD_RELIESON("engine.dll", MilesLogFuncHooks, ConVar, (CModule module)) diff --git a/NorthstarDLL/client/clientvideooverrides.cpp b/NorthstarDLL/client/clientvideooverrides.cpp index d8aa27541..edeaa0052 100644 --- a/NorthstarDLL/client/clientvideooverrides.cpp +++ b/NorthstarDLL/client/clientvideooverrides.cpp @@ -8,7 +8,7 @@ void*, __fastcall, (const char* path, uint32_t flags)) // clang-format on { std::string filename(fs::path(path).filename().string()); - spdlog::info("BinkOpen {}", filename); + DevMsg(eLog::VIDEO, "BinkOpen %s\n", filename); // figure out which mod is handling the bink Mod* fileOwner = nullptr; diff --git a/NorthstarDLL/client/languagehooks.cpp b/NorthstarDLL/client/languagehooks.cpp index 4251dbbdf..0d4878d61 100644 --- a/NorthstarDLL/client/languagehooks.cpp +++ b/NorthstarDLL/client/languagehooks.cpp @@ -61,14 +61,15 @@ char*, __fastcall, ()) { if (!CheckLangAudioExists((char*)forcedLanguage)) { - spdlog::info( - "User tried to force the language (-language) to \"{}\", but audio for this language doesn't exist and the game is bound " - "to error, falling back to next option...", + Warning( + eLog::AUDIO, + "User tried to force the language (-language) to \"%s\", but audio for this language doesn't exist and the game is bound " + "to error, falling back to next option...\n", forcedLanguage); } else { - spdlog::info("User forcing the language (-language) to: {}", forcedLanguage); + DevMsg(eLog::AUDIO, "User forcing the language (-language) to: %s\n", forcedLanguage); strncpy(ingameLang1, forcedLanguage, 256); return ingameLang1; } @@ -81,12 +82,14 @@ char*, __fastcall, ()) { if (strcmp(lang, "russian") != 0) // don't log for "russian" since it's the default and that means Origin detection just didn't change it most likely - spdlog::info( - "Origin detected language \"{}\", but we do not have audio for it installed, falling back to the next option", lang); + DevMsg( + eLog::AUDIO, + "Origin detected language \"%s\", but we do not have audio for it installed, falling back to the next option\n", + lang); } else { - spdlog::info("Origin detected language: {}", lang); + DevMsg(eLog::AUDIO, "Origin detected language: %s\n", lang); return lang; } } @@ -95,13 +98,15 @@ char*, __fastcall, ()) // defaulting to Russian canOriginDictateLang = false; // Origin has no say anymore, we will fallback to user's system setup language auto lang = GetGameLanguage(); - spdlog::info("Detected system language: {}", lang); + DevMsg(eLog::AUDIO, "Detected system language: %s\n", lang); if (!CheckLangAudioExists(lang)) { - spdlog::warn("Caution, audio for this language does NOT exist. You might want to override your game language with -language " - "command line option."); + Warning( + eLog::AUDIO, + "Caution, audio for this language does NOT exist. You might want to override your game language with -language command line " + "option.\n"); auto lang = GetAnyInstalledAudioLanguage(); - spdlog::warn("Falling back to the first installed audio language: {}", lang.c_str()); + Warning(eLog::AUDIO, "Falling back to the first installed audio language: %s\n", lang.c_str()); strncpy(ingameLang1, lang.c_str(), 256); return ingameLang1; } diff --git a/NorthstarDLL/client/latencyflex.cpp b/NorthstarDLL/client/latencyflex.cpp index 25e38c7a4..75e8ae2e6 100644 --- a/NorthstarDLL/client/latencyflex.cpp +++ b/NorthstarDLL/client/latencyflex.cpp @@ -32,12 +32,12 @@ ON_DLL_LOAD_CLIENT_RELIESON("client.dll", LatencyFlex, ConVar, (CModule module)) reinterpret_cast(reinterpret_cast(GetProcAddress(pLfxModule, "winelfx_WaitAndBeginFrame"))); else { - spdlog::info("Unable to load LatencyFleX library, LatencyFleX disabled."); + Warning(eLog::NS, "Unable to load LatencyFleX library, LatencyFleX disabled.\n"); return; } AUTOHOOK_DISPATCH() - spdlog::info("LatencyFleX initialized."); + DevMsg(eLog::NS, "LatencyFleX initialized.\n"); Cvar_r_latencyflex = new ConVar("r_latencyflex", "1", FCVAR_ARCHIVE, "Whether or not to use LatencyFleX input latency reduction."); } diff --git a/NorthstarDLL/client/localchatwriter.cpp b/NorthstarDLL/client/localchatwriter.cpp index 848d898f6..a9592afa8 100644 --- a/NorthstarDLL/client/localchatwriter.cpp +++ b/NorthstarDLL/client/localchatwriter.cpp @@ -316,7 +316,7 @@ void LocalChatWriter::InsertChar(wchar_t ch) void LocalChatWriter::InsertText(const char* str) { - spdlog::info(str); + DevMsg(eLog::CHAT, "%s\n", str); WCHAR messageUnicode[288]; ConvertANSIToUnicode(str, -1, messageUnicode, 274); diff --git a/NorthstarDLL/client/modlocalisation.cpp b/NorthstarDLL/client/modlocalisation.cpp index 2b73876b3..b6840e768 100644 --- a/NorthstarDLL/client/modlocalisation.cpp +++ b/NorthstarDLL/client/modlocalisation.cpp @@ -14,7 +14,7 @@ bool, __fastcall, (void* pVguiLocalize, const char* path, const char* pathId, bo bool ret = CLocalize__AddFile(pVguiLocalize, path, pathId, bIncludeFallbackSearchPaths); if (ret) - spdlog::info("Loaded localisation file {} successfully", path); + DevMsg(eLog::MODSYS, "Loaded localisation file %s successfully\n", path); return true; } @@ -30,7 +30,7 @@ void, __fastcall, (void* pVguiLocalize)) for (std::string& localisationFile : mod.LocalisationFiles) CLocalize__AddFile(g_pVguiLocalize, localisationFile.c_str(), nullptr, false); - spdlog::info("reloading localization..."); + DevMsg(eLog::MODSYS, "reloading localization...\n"); CLocalize__ReloadLocalizationFiles(pVguiLocalize); } @@ -41,6 +41,8 @@ void, __fastcall, (void* self)) { CEngineVGui__Init(self); // this loads r1_english, valve_english, dev_english + g_bEngineVguiInitilazed = true; + // previously we did this in CLocalize::AddFile, but for some reason it won't properly overwrite localization from // files loaded previously if done there, very weird but this works so whatever for (Mod mod : g_pModManager->m_LoadedMods) diff --git a/NorthstarDLL/core/convar/concommand.cpp b/NorthstarDLL/core/convar/concommand.cpp index 41f54c76a..3e46a2603 100644 --- a/NorthstarDLL/core/convar/concommand.cpp +++ b/NorthstarDLL/core/convar/concommand.cpp @@ -129,7 +129,7 @@ ConCommandConstructorType ConCommandConstructor; void RegisterConCommand(const char* name, FnCommandCallback_t callback, const char* helpString, int flags) { - spdlog::info("Registering ConCommand {}", name); + DevMsg(eLog::ENGINE, "Registering ConCommand %s\n", name); // no need to free this ever really, it should exist as long as game does ConCommand* newCommand = new ConCommand; @@ -139,7 +139,7 @@ void RegisterConCommand(const char* name, FnCommandCallback_t callback, const ch void RegisterConCommand( const char* name, FnCommandCallback_t callback, const char* helpString, int flags, FnCommandCompletionCallback completionCallback) { - spdlog::info("Registering ConCommand {}", name); + DevMsg(eLog::ENGINE, "Registering ConCommand %s\n", name); // no need to free this ever really, it should exist as long as game does ConCommand* newCommand = new ConCommand; diff --git a/NorthstarDLL/core/convar/convar.cpp b/NorthstarDLL/core/convar/convar.cpp index 594989c20..2725570c2 100644 --- a/NorthstarDLL/core/convar/convar.cpp +++ b/NorthstarDLL/core/convar/convar.cpp @@ -53,7 +53,7 @@ ON_DLL_LOAD("engine.dll", ConVar, (CModule module)) //----------------------------------------------------------------------------- ConVar::ConVar(const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString) { - spdlog::info("Registering Convar {}", pszName); + DevMsg(eLog::ENGINE, "Registering Convar %s\n", pszName); this->m_ConCommandBase.m_pConCommandBaseVTable = g_pConVar_Vtable; this->m_ConCommandBase.s_pConCommandBases = (ConCommandBase*)g_pIConVar_Vtable; @@ -76,7 +76,7 @@ ConVar::ConVar( float fMax, FnChangeCallback_t pCallback) { - spdlog::info("Registering Convar {}", pszName); + DevMsg(eLog::ENGINE, "Registering Convar %s\n", pszName); this->m_ConCommandBase.m_pConCommandBaseVTable = g_pConVar_Vtable; this->m_ConCommandBase.s_pConCommandBases = (ConCommandBase*)g_pIConVar_Vtable; @@ -325,7 +325,7 @@ void ConVar::SetValue(const char* pszValue) float flNewValue = (float)atof(pszValue); if (!std::isfinite(flNewValue)) { - spdlog::warn("Warning: ConVar '{}' = '{}' is infinite, clamping value.\n", GetBaseName(), pszValue); + Warning(eLog::NS, "ConVar '%s' = '%s' is infinite, clamping value.\n", GetBaseName(), pszValue); flNewValue = FLT_MAX; } @@ -526,7 +526,7 @@ int ParseConVarFlagsString(std::string modName, std::string sFlags) } if (!ok) { - spdlog::warn("Mod ConCommand {} has unknown flag {}", modName, sFlag); + Warning(eLog::NS, "Mod ConCommand %s has unknown flag %s\n", modName.c_str(), sFlag.c_str()); } } diff --git a/NorthstarDLL/core/filesystem/filesystem.cpp b/NorthstarDLL/core/filesystem/filesystem.cpp index e4da647f2..9a14c2aa8 100644 --- a/NorthstarDLL/core/filesystem/filesystem.cpp +++ b/NorthstarDLL/core/filesystem/filesystem.cpp @@ -73,6 +73,9 @@ void SetNewModSearchPaths(Mod* mod) { if ((fs::absolute(mod->m_ModDirectory) / MOD_OVERRIDE_DIR).string().compare(sCurrentModPath)) { + // NOTE [Fifty]: Possibly put this behind some check + // DevMsg(eLog::FS, "Changing mod search path from %s to %s\n", sCurrentModPath.c_str(), mod->m_ModDirectory.string().c_str()); + AddSearchPath( &*(*g_pFilesystem), (fs::absolute(mod->m_ModDirectory) / MOD_OVERRIDE_DIR).string().c_str(), "GAME", PATH_ADD_TO_HEAD); sCurrentModPath = (fs::absolute(mod->m_ModDirectory) / MOD_OVERRIDE_DIR).string(); @@ -141,7 +144,7 @@ FileHandle_t, __fastcall, (IFileSystem* filesystem, const char* pPath, const cha HOOK(MountVPKHook, MountVPK, VPKData*, , (IFileSystem * fileSystem, const char* pVpkPath)) { - NS::log::fs->info("MountVPK {}", pVpkPath); + DevMsg(eLog::FS, "MountVPK %s\n", pVpkPath); VPKData* ret = MountVPK(fileSystem, pVpkPath); for (Mod mod : g_pModManager->m_LoadedMods) diff --git a/NorthstarDLL/core/filesystem/rpakfilesystem.cpp b/NorthstarDLL/core/filesystem/rpakfilesystem.cpp index 8d50b07a6..193dcf775 100644 --- a/NorthstarDLL/core/filesystem/rpakfilesystem.cpp +++ b/NorthstarDLL/core/filesystem/rpakfilesystem.cpp @@ -215,13 +215,13 @@ int, __fastcall, (char* pPath, void* unknownSingleton, int flags, void* pCallbac if (bNeedToFreePakName) delete[] pPath; - NS::log::rpak->info("Not loading pak {} for dedicated server", originalPath); + DevMsg(eLog::RTECH, "Not loading pak %s for dedicated server\n", originalPath.c_str()); return -1; } } int iPakHandle = LoadPakAsync(pPath, unknownSingleton, flags, pCallback0, pCallback1); - NS::log::rpak->info("LoadPakAsync {} {}", pPath, iPakHandle); + DevMsg(eLog::RTECH, "LoadPakAsync %s %i\n", pPath, iPakHandle); // trak the pak g_pPakLoadManager->TrackLoadedPak(ePakLoadSource::UNTRACKED, iPakHandle, nPathHash); @@ -249,7 +249,7 @@ void*, __fastcall, (int nPakHandle, void* pCallback)) bShouldUnloadPaks = true; } - NS::log::rpak->info("UnloadPak {}", nPakHandle); + DevMsg(eLog::RTECH, "UnloadPak %i\n", nPakHandle); return UnloadPak(nPakHandle, pCallback); } @@ -269,7 +269,7 @@ void*, __fastcall, (const char* pPath, void* pCallback)) if (IsDedicatedServer()) return nullptr; - NS::log::rpak->info("LoadStreamBsp: {}", filename.string()); + DevMsg(eLog::RTECH, "LoadStreamBsp: %s\n", filename.string().c_str()); // resolve modded stbsp path so we can load mod stbsps auto modFile = g_pModManager->m_ModFiles.find(g_pModManager->NormaliseModFilePath(fs::path("maps" / filename))); @@ -326,7 +326,7 @@ void*, __fastcall, (const char* pPath, void* pCallback)) } LOG_STARPAK: - NS::log::rpak->info("LoadStreamPak: {}", filename.string()); + DevMsg(eLog::RTECH, "LoadStreamPak: %s\n", filename.string().c_str()); } return ReadFileAsync(pPath, pCallback); diff --git a/NorthstarDLL/core/hooks.cpp b/NorthstarDLL/core/hooks.cpp index da7f9f3e5..51904f41b 100644 --- a/NorthstarDLL/core/hooks.cpp +++ b/NorthstarDLL/core/hooks.cpp @@ -106,14 +106,14 @@ bool ManualHook::Dispatch(LPVOID addr, LPVOID* orig) { if (MH_EnableHook(addr) == MH_OK) { - spdlog::info("Enabling hook {}", pFuncName); + DevMsg(eLog::NS, "Enabling hook %s\n", pFuncName); return true; } else - spdlog::error("MH_EnableHook failed for function {}", pFuncName); + Error(eLog::NS, NO_ERROR, "MH_EnableHook failed for function %s\n", pFuncName); } else - spdlog::error("MH_CreateHook failed for function {}", pFuncName); + Error(eLog::NS, NO_ERROR, "MH_CreateHook failed for function %s\n", pFuncName); return false; } @@ -211,12 +211,12 @@ void MakeHook(LPVOID pTarget, LPVOID pDetour, void* ppOriginal, const char* pFun if (MH_CreateHook(pTarget, pDetour, (LPVOID*)ppOriginal) == MH_OK) { if (MH_EnableHook(pTarget) == MH_OK) - spdlog::info("Enabling hook {}", pStrippedFuncName); + DevMsg(eLog::NS, "Enabling hook %s\n", pStrippedFuncName); else - spdlog::error("MH_EnableHook failed for function {}", pStrippedFuncName); + Error(eLog::NS, NO_ERROR, "MH_EnableHook failed for function %s\n", pStrippedFuncName); } else - spdlog::error("MH_CreateHook failed for function {}", pStrippedFuncName); + Error(eLog::NS, NO_ERROR, "MH_CreateHook failed for function %s\n", pStrippedFuncName); } AUTOHOOK_ABSOLUTEADDR(_GetCommandLineA, (LPVOID)GetCommandLineA, LPSTR, WINAPI, ()) @@ -271,7 +271,7 @@ AUTOHOOK_ABSOLUTEADDR(_GetCommandLineA, (LPVOID)GetCommandLineA, LPSTR, WINAPI, cmdlineModified = new char[len + 1]; if (!cmdlineModified) { - spdlog::error("malloc failed for command line"); + Error(eLog::NS, NO_ERROR, "malloc failed for command line\n"); return cmdlineOrg; } memcpy(cmdlineModified, args.c_str(), len + 1); @@ -400,8 +400,7 @@ HMODULE, WINAPI, (LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)) if (!moduleAddress) { - MessageBoxA(0, "Could not find XInput9_1_0.dll", "Northstar", MB_ICONERROR); - exit(EXIT_FAILURE); + Error(eLog::NS, EXIT_FAILURE, "Could not find XInput9_1_0.dll\n"); return nullptr; } @@ -463,7 +462,7 @@ HMODULE, WINAPI, (LPCWSTR lpLibFileName)) void InstallInitialHooks() { if (MH_Initialize() != MH_OK) - spdlog::error("MH_Initialize (minhook initialization) failed"); + Error(eLog::NS, NO_ERROR, "MH_Initialize (minhook initialization) failed\n"); AUTOHOOK_DISPATCH() } diff --git a/NorthstarDLL/core/hooks.h b/NorthstarDLL/core/hooks.h index 01244b3d2..db54efde0 100644 --- a/NorthstarDLL/core/hooks.h +++ b/NorthstarDLL/core/hooks.h @@ -205,12 +205,12 @@ class __autohook if (MH_CreateHook(targetAddr, pHookFunc, ppOrigFunc) == MH_OK) { if (MH_EnableHook(targetAddr) == MH_OK) - spdlog::info("Enabling hook {}", pFuncName); + DevMsg(eLog::NS, "Enabling hook %s\n", pFuncName); else - spdlog::error("MH_EnableHook failed for function {}", pFuncName); + Error(eLog::NS, NO_ERROR, "MH_EnableHook failed for function %s\n", pFuncName); } else - spdlog::error("MH_CreateHook failed for function {}", pFuncName); + Error(eLog::NS, NO_ERROR, "MH_CreateHook failed for function %s\n", pFuncName); } }; diff --git a/NorthstarDLL/core/math/color.h b/NorthstarDLL/core/math/color.h index 76cf8a478..6d4c1cd86 100644 --- a/NorthstarDLL/core/math/color.h +++ b/NorthstarDLL/core/math/color.h @@ -159,8 +159,8 @@ class Color std::string out = "\033[38;2;"; out += std::to_string(_color[0]) + ";"; out += std::to_string(_color[1]) + ";"; - out += std::to_string(_color[2]) + ";"; - out += "49m"; + out += std::to_string(_color[2]); + out += "m"; return out; } diff --git a/NorthstarDLL/core/sourceinterface.cpp b/NorthstarDLL/core/sourceinterface.cpp index 5a72beb07..ccdc4108e 100644 --- a/NorthstarDLL/core/sourceinterface.cpp +++ b/NorthstarDLL/core/sourceinterface.cpp @@ -11,7 +11,7 @@ void*, __fastcall, (const char* pName, const int* pReturnCode)) // clang-format on { void* ret = ClientCreateInterface(pName, pReturnCode); - spdlog::info("CreateInterface CLIENT {}", pName); + DevMsg(eLog::CLIENT, "CreateInterface CLIENT %s\n", pName); if (!strcmp(pName, "GameClientExports001")) InitialiseConsoleOnInterfaceCreation(); @@ -25,7 +25,7 @@ void*, __fastcall, (const char* pName, const int* pReturnCode)) // clang-format on { void* ret = ServerCreateInterface(pName, pReturnCode); - spdlog::info("CreateInterface SERVER {}", pName); + DevMsg(eLog::SERVER, "CreateInterface SERVER %s\n", pName); return ret; } @@ -36,7 +36,7 @@ void*, __fastcall, (const char* pName, const int* pReturnCode)) // clang-format on { void* ret = EngineCreateInterface(pName, pReturnCode); - spdlog::info("CreateInterface ENGINE {}", pName); + DevMsg(eLog::ENGINE, "CreateInterface ENGINE %s\n", pName); return ret; } diff --git a/NorthstarDLL/core/sourceinterface.h b/NorthstarDLL/core/sourceinterface.h index 474e961b3..afd17a460 100644 --- a/NorthstarDLL/core/sourceinterface.h +++ b/NorthstarDLL/core/sourceinterface.h @@ -16,7 +16,7 @@ template class SourceInterface CreateInterfaceFn createInterface = (CreateInterfaceFn)GetProcAddress(handle, "CreateInterface"); m_interface = (T*)createInterface(interfaceName.c_str(), NULL); if (m_interface == nullptr) - spdlog::error("Failed to call CreateInterface for %s in %s", interfaceName, moduleName); + Error(eLog::NS, NO_ERROR, "Failed to call CreateInterface for %s in %s\n", interfaceName, moduleName); } T* operator->() const diff --git a/NorthstarDLL/dedicated/dedicated.cpp b/NorthstarDLL/dedicated/dedicated.cpp index 34282f51c..be8182d4a 100644 --- a/NorthstarDLL/dedicated/dedicated.cpp +++ b/NorthstarDLL/dedicated/dedicated.cpp @@ -37,13 +37,13 @@ struct CDedicatedExports void Sys_Printf(CDedicatedExports* dedicated, const char* msg) { - spdlog::info("[DEDICATED SERVER] {}", msg); + DevMsg(eLog::ENGINE, "[DEDICATED SERVER] %s\n", msg); } void RunServer(CDedicatedExports* dedicated) { - spdlog::info("CDedicatedExports::RunServer(): starting"); - spdlog::info(Tier0::CommandLine()->GetCmdLine()); + DevMsg(eLog::ENGINE, "CDedicatedExports::RunServer(): starting\n"); + DevMsg(eLog::ENGINE, "%s\n", Tier0::CommandLine()->GetCmdLine()); // initialise engine g_pEngine->Frame(); @@ -95,7 +95,7 @@ DWORD WINAPI ConsoleInputThread(PVOID pThreadParameter) FILE* fp = nullptr; freopen_s(&fp, "CONIN$", "r", stdin); - spdlog::info("Ready to receive console commands."); + DevMsg(eLog::NS, "Ready to receive console commands.\n"); { // Process console input @@ -121,7 +121,7 @@ bool,, ()) ON_DLL_LOAD_DEDI_RELIESON("engine.dll", DedicatedServer, ServerPresence, (CModule module)) { - spdlog::info("InitialiseDedicated"); + DevMsg(eLog::NS, "InitialiseDedicated\n"); AUTOHOOK_DISPATCH_MODULE(engine.dll) @@ -227,9 +227,6 @@ ON_DLL_LOAD_DEDI_RELIESON("engine.dll", DedicatedServer, ServerPresence, (CModul DedicatedConsoleServerPresence* presenceReporter = new DedicatedConsoleServerPresence; g_pServerPresence->AddPresenceReporter(presenceReporter); - // setup dedicated printing to client - RegisterCustomSink(std::make_shared()); - // Disable Quick Edit mode to reduce chance of user unintentionally hanging their server by selecting something. if (!Tier0::CommandLine()->CheckParm("-bringbackquickedit")) { @@ -250,13 +247,13 @@ ON_DLL_LOAD_DEDI_RELIESON("engine.dll", DedicatedServer, ServerPresence, (CModul } } else - spdlog::info("Quick Edit enabled by user request"); + DevMsg(eLog::NS, "Quick Edit enabled by user request\n"); // create console input thread if (!Tier0::CommandLine()->CheckParm("-noconsoleinput")) consoleInputThreadHandle = CreateThread(0, 0, ConsoleInputThread, 0, 0, NULL); else - spdlog::info("Console input disabled by user request"); + DevMsg(eLog::NS, "Console input disabled by user request\n"); } ON_DLL_LOAD_DEDI("tier0.dll", DedicatedServerOrigin, (CModule module)) diff --git a/NorthstarDLL/dedicated/dedicatedlogtoclient.cpp b/NorthstarDLL/dedicated/dedicatedlogtoclient.cpp index a48b1b39b..962994de9 100644 --- a/NorthstarDLL/dedicated/dedicatedlogtoclient.cpp +++ b/NorthstarDLL/dedicated/dedicatedlogtoclient.cpp @@ -1,10 +1,16 @@ #include "dedicatedlogtoclient.h" + +#include "core/convar/convar.h" #include "engine/r2engine.h" +#include "logging/logging.h" void (*CGameClient__ClientPrintf)(R2::CBaseClient* pClient, const char* fmt, ...); -void DedicatedServerLogToClientSink::custom_sink_it_(const custom_log_msg& msg) +void DediClientMsg(const char* pszMessage) { + if (R2::g_pServerState == NULL || R2::g_pCVar == NULL) + return; + if (*R2::g_pServerState == R2::server_state_t::ss_dead) return; @@ -20,7 +26,7 @@ void DedicatedServerLogToClientSink::custom_sink_it_(const custom_log_msg& msg) if (eSendPrints == eSendPrintsToClient::NONE) return; - std::string sLogMessage = fmt::format("[DEDICATED SERVER] [{}] {}", level_names[msg.level], msg.payload); + std::string sLogMessage = fmt::format("{}", pszMessage); for (int i = 0; i < R2::g_pGlobals->m_nMaxClients; i++) { R2::CBaseClient* pClient = &R2::g_pClientArray[i]; @@ -35,13 +41,6 @@ void DedicatedServerLogToClientSink::custom_sink_it_(const custom_log_msg& msg) } } -void DedicatedServerLogToClientSink::sink_it_(const spdlog::details::log_msg& msg) -{ - throw std::runtime_error("sink_it_ called on DedicatedServerLogToClientSink with pure log_msg. This is an error!"); -} - -void DedicatedServerLogToClientSink::flush_() {} - ON_DLL_LOAD_DEDI("engine.dll", DedicatedServerLogToClient, (CModule module)) { CGameClient__ClientPrintf = module.Offset(0x1016A0).RCast(); diff --git a/NorthstarDLL/dedicated/dedicatedlogtoclient.h b/NorthstarDLL/dedicated/dedicatedlogtoclient.h index 16f1e5844..96a45da72 100644 --- a/NorthstarDLL/dedicated/dedicatedlogtoclient.h +++ b/NorthstarDLL/dedicated/dedicatedlogtoclient.h @@ -1,11 +1,3 @@ #pragma once -#include "logging/logging.h" -#include "core/convar/convar.h" -class DedicatedServerLogToClientSink : public CustomSink -{ - protected: - void custom_sink_it_(const custom_log_msg& msg); - void sink_it_(const spdlog::details::log_msg& msg) override; - void flush_() override; -}; +void DediClientMsg(const char* pszMessage); diff --git a/NorthstarDLL/dllmain.cpp b/NorthstarDLL/dllmain.cpp index d82c9ffbb..ef408d3bc 100644 --- a/NorthstarDLL/dllmain.cpp +++ b/NorthstarDLL/dllmain.cpp @@ -17,15 +17,14 @@ #include #include +#include -BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) { - switch (ul_reason_for_call) + switch (dwReason) { - case DLL_PROCESS_ATTACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: + SpdLog_Shutdown(); break; } @@ -40,21 +39,30 @@ bool InitialiseNorthstar() bInitialised = true; + // Initilaze working profile directory InitialiseNorthstarPrefix(); - // initialise the console if needed (-northstar needs this) - InitialiseConsole(); - // initialise logging before most other things so that they can use spdlog and it have the proper formatting - InitialiseLogging(); - InitialiseVersion(); - CreateLogFiles(); + // Initilaze log directory + g_svLogDirectory = fmt::format("{:s}\\logs\\{:s}", GetNorthstarPrefix(), NS::Utils::CreateTimeStamp()); + + // Checks if we can write into install directory + SpdLog_PreInit(); + + // Make sure we have a console window + Console_Init(); + + // Init logging + SpdLog_Init(); + SpdLog_CreateLoggers(); g_pCrashHandler = new CCrashHandler(); bool bAllFatal = strstr(GetCommandLineA(), "-crash_handle_all") != NULL; g_pCrashHandler->SetAllFatal(bAllFatal); // Write launcher version to log - StartupLog(); + Sys_PrintOSVer(); + + InitialiseVersion(); InstallInitialHooks(); diff --git a/NorthstarDLL/engine/host.cpp b/NorthstarDLL/engine/host.cpp index 49cc36630..dc0429c7d 100644 --- a/NorthstarDLL/engine/host.cpp +++ b/NorthstarDLL/engine/host.cpp @@ -13,7 +13,7 @@ AUTOHOOK(Host_Init, engine.dll + 0x155EA0, void, __fastcall, (bool bDedicated)) // clang-format on { - spdlog::info("Host_Init()"); + DevMsg(eLog::ENGINE, "Host_Init()\n"); Host_Init(bDedicated); FixupCvarFlags(); // need to initialise these after host_init since they do stuff to preexisting concommands/convars without being client/server specific diff --git a/NorthstarDLL/engine/hoststate.cpp b/NorthstarDLL/engine/hoststate.cpp index 1734a1c38..1eff8fa27 100644 --- a/NorthstarDLL/engine/hoststate.cpp +++ b/NorthstarDLL/engine/hoststate.cpp @@ -66,7 +66,7 @@ AUTOHOOK(CHostState__State_NewGame, engine.dll + 0x16E7D0, void, __fastcall, (CHostState* self)) // clang-format on { - spdlog::info("HostState: NewGame"); + DevMsg(eLog::ENGINE, "HostState: NewGame\n"); Cbuf_AddText(Cbuf_GetCurrentPlayer(), "exec autoexec_ns_server", cmd_source_t::kCommandSrcCode); Cbuf_Execute(); @@ -79,7 +79,7 @@ void, __fastcall, (CHostState* self)) double dStartTime = Tier0::Plat_FloatTime(); CHostState__State_NewGame(self); - spdlog::info("loading took {}s", Tier0::Plat_FloatTime() - dStartTime); + DevMsg(eLog::ENGINE, "loading took %f sec\n", Tier0::Plat_FloatTime() - dStartTime); // setup server presence g_pServerPresence->CreatePresence(); @@ -98,7 +98,7 @@ void, __fastcall, (CHostState* self)) // singleplayer server starting // useless in 99% of cases but without it things could potentially break very much - spdlog::info("HostState: LoadGame"); + DevMsg(eLog::ENGINE, "HostState: LoadGame\n"); Cbuf_AddText(Cbuf_GetCurrentPlayer(), "exec autoexec_ns_server", cmd_source_t::kCommandSrcCode); Cbuf_Execute(); @@ -109,7 +109,7 @@ void, __fastcall, (CHostState* self)) double dStartTime = Tier0::Plat_FloatTime(); CHostState__State_LoadGame(self); - spdlog::info("loading took {}s", Tier0::Plat_FloatTime() - dStartTime); + DevMsg(eLog::ENGINE, "loading took %f sec\n", Tier0::Plat_FloatTime() - dStartTime); // no server presence, can't do it because no map name in hoststate // and also not super important for sp saves really @@ -122,13 +122,13 @@ AUTOHOOK(CHostState__State_ChangeLevelMP, engine.dll + 0x16E520, void, __fastcall, (CHostState* self)) // clang-format on { - spdlog::info("HostState: ChangeLevelMP"); + DevMsg(eLog::ENGINE, "HostState: ChangeLevelMP\n"); ServerStartingOrChangingMap(); double dStartTime = Tier0::Plat_FloatTime(); CHostState__State_ChangeLevelMP(self); - spdlog::info("loading took {}s", Tier0::Plat_FloatTime() - dStartTime); + DevMsg(eLog::ENGINE, "loading took %f sec\n", Tier0::Plat_FloatTime() - dStartTime); g_pServerPresence->SetMap(g_pHostState->m_levelName); } @@ -138,7 +138,7 @@ AUTOHOOK(CHostState__State_GameShutdown, engine.dll + 0x16E640, void, __fastcall, (CHostState* self)) // clang-format on { - spdlog::info("HostState: GameShutdown"); + DevMsg(eLog::ENGINE, "HostState: GameShutdown\n"); g_pServerPresence->DestroyPresence(); diff --git a/NorthstarDLL/engine/r2engine.h b/NorthstarDLL/engine/r2engine.h index df0cda74c..c01885d00 100644 --- a/NorthstarDLL/engine/r2engine.h +++ b/NorthstarDLL/engine/r2engine.h @@ -1,4 +1,6 @@ #pragma once + +#include "core/convar/concommand.h" #include "shared/keyvalues.h" // use the R2 namespace for game funcs diff --git a/NorthstarDLL/logging/dbg.cpp b/NorthstarDLL/logging/dbg.cpp new file mode 100644 index 000000000..74f66eb40 --- /dev/null +++ b/NorthstarDLL/logging/dbg.cpp @@ -0,0 +1,248 @@ +#include "dbg.h" + +#include "util/utils.h" +#include "logging/sourceconsole.h" +#include "logging/logging.h" +#include +#include +#include "dedicated/dedicated.h" + +const std::regex AnsiRegex("\\\033\\[.*?m"); +std::mutex g_LogMutex; + +//----------------------------------------------------------------------------- +// Purpose: Get the log context string +// Input : eContext - +// Output : Zero terminated string +//----------------------------------------------------------------------------- +const char* Log_GetContextString(eLog eContext) +{ + return sLogString[static_cast(eContext)]; +} + +//----------------------------------------------------------------------------- +// Purpose: Get the color for a given context and level combination +// Input : eContext - +// eLevel - +// Output : The color +//----------------------------------------------------------------------------- +Color Log_GetColor(eLog eContext, eLogLevel eLevel) +{ + if (eLevel == eLogLevel::LOG_WARN) + return Color(200, 200, 50); + if (eLevel == eLogLevel::LOG_ERROR) + return Color(220, 50, 50); + + switch (eContext) + { + case eLog::NS: + return Color(50, 110, 170); + case eLog::SCRIPT_SERVER: + return Color(120, 110, 50); + case eLog::SCRIPT_CLIENT: + return Color(90, 110, 40); + case eLog::SCRIPT_UI: + return Color(70, 110, 90); + case eLog::SERVER: + return Color(200, 160, 80); + case eLog::CLIENT: + return Color(170, 200, 80); + case eLog::UI: + return Color(110, 200, 150); + case eLog::ENGINE: + return Color(110, 180, 150); + case eLog::RTECH: + return Color(220, 160, 40); + case eLog::FS: + return Color(40, 220, 210); + case eLog::MAT: + return Color(40, 230, 120); + case eLog::AUDIO: + return Color(130, 130, 220); + case eLog::VIDEO: + return Color(200, 130, 200); + case eLog::MS: + return Color(40, 110, 220); + case eLog::MODSYS: + return Color(20, 100, 150); + case eLog::PLUGSYS: + return Color(190, 190, 90); + case eLog::PLUGIN: + return Color(190, 140, 90); + case eLog::CHAT: + return Color(220, 180, 70); + } + return Color(255, 255, 255); +} + +//----------------------------------------------------------------------------- +// Purpose: Get logger based on the log level +// Input : eLevel - +// Output : Smart pointer to the logger +//----------------------------------------------------------------------------- +std::shared_ptr Log_GetLogger(eLogLevel eLevel) +{ + std::string svName; + + switch (eLevel) + { + case eLogLevel::LOG_INFO: + svName = "northstar(info)"; + break; + case eLogLevel::LOG_WARN: + svName = "northstar(warning)"; + break; + case eLogLevel::LOG_ERROR: + svName = "northstar(error)"; + break; + } + + return spdlog::get(svName); +} + +//----------------------------------------------------------------------------- +// Purpose: Prints to all outputs based on parameters, va_list version +// Input : eContext - +// eLevel - +// iCode - +// *pszName - +// *fmt - +// vArgs - +//----------------------------------------------------------------------------- +void CoreMsgV(eLog eContext, eLogLevel eLevel, const int iCode, const char* pszName, const char* fmt, va_list vArgs) +{ + std::string svMessage; + + //----------------------------------- + // Format header + if (g_bConsole_UseAnsiColor) + { + std::string svAnsiString = Log_GetColor(eContext, eLevel).ToANSIColor(); + svMessage += NS::Utils::Format("%s[%s] ", svAnsiString.c_str(), pszName); + } + else + { + svMessage += NS::Utils::Format("[%s] ", pszName); + } + + // Add the message itself + svMessage += NS::Utils::FormatV(fmt, vArgs); + + //----------------------------------- + // Emit to all loggers + //----------------------------------- + std::lock_guard lock(g_LogMutex); + + g_WinLogger->debug("{}", svMessage); + + // Remove ansi escape sequences + svMessage = std::regex_replace(svMessage, AnsiRegex, ""); + + // Log to file + std::shared_ptr pLogger = Log_GetLogger(eLevel); + if (pLogger.get()) // "-nologfiles" or programmer error can cause this to fail + pLogger->info("{:s}", svMessage); + + // Log to clients if enabled + DediClientMsg(svMessage.c_str()); + + // Log to game console + // TODO [Fifty]: Use "VEngineCvar007" interface to print instead of this fuckery + if (g_bEngineVguiInitilazed && (*g_pSourceGameConsole)->m_pConsole) + { + (*g_pSourceGameConsole)->m_pConsole->m_pConsolePanel->ColorPrint(Log_GetColor(eContext, eLevel).ToSourceColor(), svMessage.c_str()); + //(*g_pSourceGameConsole)->m_pConsole->m_pConsolePanel->Print(svMessage.c_str()); + } + + //----------------------------------- + // Terminate process if needed + //----------------------------------- + if (iCode) + { + if (!IsDedicatedServer()) + MessageBoxA(NULL, svMessage.c_str(), "Northstar Error", MB_ICONERROR | MB_OK); + + TerminateProcess(GetCurrentProcess(), iCode); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Prints to all outputs based on parameters +// Input : eContext - +// eLevel - +// iCode - +// *pszName - +// *fmt - +// ... - +//----------------------------------------------------------------------------- +void CoreMsg(eLog eContext, eLogLevel eLevel, const int iCode, const char* pszName, const char* fmt, ...) +{ + va_list vArgs; + va_start(vArgs, fmt); + CoreMsgV(eContext, eLevel, iCode, pszName, fmt, vArgs); + va_end(vArgs); +} + +//----------------------------------------------------------------------------- +// Purpose: Prints a LOG_INFO level message +// Input : eContext - +// *fmt - +// ... - +//----------------------------------------------------------------------------- +void DevMsg(eLog eContext, const char* fmt, ...) +{ + const char* pszContext = Log_GetContextString(eContext); + + va_list vArgs; + va_start(vArgs, fmt); + CoreMsgV(eContext, eLogLevel::LOG_INFO, 0, pszContext, fmt, vArgs); + va_end(vArgs); +} + +//----------------------------------------------------------------------------- +// Purpose: Prints a LOG_WARNING level message +// Input : eContext - +// *fmt - +// ... - +//----------------------------------------------------------------------------- +void Warning(eLog eContext, const char* fmt, ...) +{ + const char* pszContext = Log_GetContextString(eContext); + + va_list vArgs; + va_start(vArgs, fmt); + CoreMsgV(eContext, eLogLevel::LOG_WARN, 0, pszContext, fmt, vArgs); + va_end(vArgs); +} + +//----------------------------------------------------------------------------- +// Purpose: Prints a LOG_ERROR level message +// Input : eContext - +// nCode - The code to terminate with, 0 means we don't teminate +// *fmt - +// ... - +//----------------------------------------------------------------------------- +void Error(eLog eContext, int nCode, const char* fmt, ...) +{ + const char* pszContext = Log_GetContextString(eContext); + + va_list vArgs; + va_start(vArgs, fmt); + CoreMsgV(eContext, eLogLevel::LOG_ERROR, nCode, pszContext, fmt, vArgs); + va_end(vArgs); +} + +//----------------------------------------------------------------------------- +// Purpose: Prints a message with a custom header, ONLY USE FOR PLUGINS OR RENAME +// Input : eLevel - +// *pszName - +// *fmt - +// ... - +//----------------------------------------------------------------------------- +void PluginMsg(eLogLevel eLevel, const char* pszName, const char* fmt, ...) +{ + va_list vArgs; + va_start(vArgs, fmt); + CoreMsgV(eLog::PLUGIN, eLevel, 0, pszName, fmt, vArgs); + va_end(vArgs); +} diff --git a/NorthstarDLL/logging/dbg.h b/NorthstarDLL/logging/dbg.h new file mode 100644 index 000000000..036ec22a7 --- /dev/null +++ b/NorthstarDLL/logging/dbg.h @@ -0,0 +1,101 @@ +#pragma once + +extern std::mutex g_LogMutex; + +// We can only print to gameconsole when CEngineVgui is initilazed +inline bool g_bEngineVguiInitilazed = false; + +//----------------------------------------------------------------------------- +// Log context +enum class eLogLevel : int +{ + LOG_INFO = 0, + LOG_WARN = 1, + LOG_ERROR = 2 +}; + +//----------------------------------------------------------------------------- +// Log context +enum class eLog : int +{ + //----------------------------------------------------------------------------- + // Common + //----------------------------------------------------------------------------- + NONE = 0, + NS = 1, + + //----------------------------------------------------------------------------- + // Script + //----------------------------------------------------------------------------- + SCRIPT_SERVER = 2, + SCRIPT_CLIENT = 3, + SCRIPT_UI = 4, + + //----------------------------------------------------------------------------- + // Native + //----------------------------------------------------------------------------- + SERVER = 5, + CLIENT = 6, + UI = 7, + ENGINE = 8, + RTECH = 9, + FS = 10, + MAT = 11, + AUDIO = 12, + VIDEO = 13, + + //----------------------------------------------------------------------------- + // Custom systems + //----------------------------------------------------------------------------- + MS = 14, // Masterserver + MODSYS = 15, // Mod system + PLUGSYS = 16, // Plugin system + PLUGIN = 17, + + //----------------------------------------------------------------------------- + // Misc + //----------------------------------------------------------------------------- + CHAT = 18 // Chat +}; + +// clang-format off +constexpr const char* sLogString[19] = +{ + "", + "NORTHSTAR", + "SCRIPT SV", + "SCRIPT CL", + "SCRIPT UI", + "NATIVE SV", + "NATIVE CL", + "NATIVE UI", + "NATIVE EN", + "RTECH SYS", + "FILESYSTM", + "MATERIAL ", + "AUDIO SYS", + "VIDEO SYS", + "MASTERSVR", + "MODSYSTEM", + "PLUGSYSTM", + "PLUGIN", // This is replaced in PLUGIN_LOG + "CHATSYSTM" +}; + +// clang-format on + +void DevMsg(eLog eContext, const char* fmt, ...); +void Warning(eLog eContext, const char* fmt, ...); +void Error(eLog eContext, int nCode, const char* fmt, ...); + +void PluginMsg(eLogLevel eLevel, const char* pszName, const char* fmt, ...); + +// Stubs so i can compile +namespace NS +{ + namespace log + + { + inline void FlushLoggers() {}; + } +} // namespace NS diff --git a/NorthstarDLL/logging/logging.cpp b/NorthstarDLL/logging/logging.cpp index 3416bb8cb..27917f539 100644 --- a/NorthstarDLL/logging/logging.cpp +++ b/NorthstarDLL/logging/logging.cpp @@ -5,225 +5,161 @@ #include "core/tier0.h" #include "util/version.h" #include "spdlog/sinks/basic_file_sink.h" +#include "spdlog/sinks/stdout_sinks.h" +#include "spdlog/sinks/rotating_file_sink.h" #include #include #include #include +#include +#include +#include AUTOHOOK_INIT() -std::vector> loggers {}; - -namespace NS::log +//----------------------------------------------------------------------------- +// Purpose: Checks if install folder is writable, exits if it is not +//----------------------------------------------------------------------------- +void SpdLog_PreInit(void) { - std::shared_ptr SCRIPT_UI; - std::shared_ptr SCRIPT_CL; - std::shared_ptr SCRIPT_SV; - - std::shared_ptr NATIVE_UI; - std::shared_ptr NATIVE_CL; - std::shared_ptr NATIVE_SV; - std::shared_ptr NATIVE_EN; - - std::shared_ptr fs; - std::shared_ptr rpak; - std::shared_ptr echo; - - std::shared_ptr NORTHSTAR; - std::shared_ptr PLUGINSYS; -}; // namespace NS::log + // This is called before SpdLog_Init so we can't use any logging helpers -// This needs to be called after hooks are loaded so we can access the command line args -void CreateLogFiles() -{ - if (strstr(GetCommandLineA(), "-disablelogs")) + // NOTE [Fifty]: Instead of checking every reason as to why we might not be able to write to a directory + // it is easier to just try to create a file + FILE* pFile = fopen(".nstemp", "w"); + if (pFile) { - spdlog::default_logger()->set_level(spdlog::level::off); + fclose(pFile); + remove(".nstemp"); + return; } - else + + // Show message box + int iAction = MessageBoxA( + NULL, + "The current directory isn't writable!\n" + "Please move the game into a writable directory to be able to continue\n\n" + "Click \"OK\" to open the wiki in your browser", + "Northstar Error", + MB_ICONERROR | MB_OKCANCEL); + + // User chose to open the troubleshooting wiki page + if (iAction == IDOK) { - try - { - // todo: might be good to delete logs that are too old - time_t time = std::time(nullptr); - tm currentTime = *std::localtime(&time); - std::stringstream stream; - - stream << std::put_time(¤tTime, (GetNorthstarPrefix() + "/logs/nslog%Y-%m-%d %H-%M-%S.txt").c_str()); - auto sink = std::make_shared(stream.str(), false); - sink->set_pattern("[%Y-%m-%d] [%H:%M:%S] [%n] [%l] %v"); - for (auto& logger : loggers) - { - logger->sinks().push_back(sink); - } - spdlog::flush_on(spdlog::level::info); - } - catch (...) - { - spdlog::error("Failed creating log file!"); - MessageBoxA( - 0, "Failed creating log file! Make sure the profile directory is writable.", "Northstar Warning", MB_ICONWARNING | MB_OK); - } + ShellExecuteA( + NULL, + NULL, + "https://r2northstar.gitbook.io/r2northstar-wiki/installing-northstar/" + "troubleshooting#cannot-write-log-file-when-using-northstar-on-ea-app", + NULL, + NULL, + SW_NORMAL); } -} -void ExternalConsoleSink::sink_it_(const spdlog::details::log_msg& msg) -{ - throw std::runtime_error("sink_it_ called on SourceConsoleSink with pure log_msg. This is an error!"); + // Gracefully close + TerminateProcess(GetCurrentProcess(), -1); } -void ExternalConsoleSink::custom_sink_it_(const custom_log_msg& msg) +//----------------------------------------------------------------------------- +// Purpose: Initilases spdlog + windows console logger +//----------------------------------------------------------------------------- +void SpdLog_Init(void) { - spdlog::memory_buf_t formatted; - spdlog::sinks::base_sink::formatter_->format(msg, formatted); + g_WinLogger = spdlog::stdout_logger_mt("win_console"); + spdlog::set_default_logger(g_WinLogger); + spdlog::set_level(spdlog::level::trace); - std::string out = ""; - // if ansi colour is turned off, just use WriteConsoleA and return - if (!g_bSpdLog_UseAnsiColor) - { - out += fmt::to_string(formatted); - } + // NOTE [Fifty]: This may be bad as it writes to disk for every message? + // Seems to fix logs not flushing properly, still needs testing + spdlog::flush_on(spdlog::level::trace); - // print to the console with colours + if (g_bConsole_UseAnsiColor) + g_WinLogger->set_pattern("%v\u001b[0m"); else - { - // get message string - std::string str = fmt::to_string(formatted); - - std::string levelColor = m_LogColours[msg.level]; - std::string name {msg.logger_name.begin(), msg.logger_name.end()}; + g_WinLogger->set_pattern("%v"); +} - std::string name_str = "[NAME]"; - int name_pos = str.find(name_str); - str.replace(name_pos, name_str.length(), msg.origin->ANSIColor + "[" + name + "]" + default_color); +//----------------------------------------------------------------------------- +// Purpose: Creates all loggers we use +//----------------------------------------------------------------------------- +void SpdLog_CreateLoggers(void) +{ + g_bSpdLog_CreateLogFiles = strstr(GetCommandLineA(), "-nologfiles") == NULL; - std::string level_str = "[LVL]"; - int level_pos = str.find(level_str); - str.replace(level_pos, level_str.length(), levelColor + "[" + std::string(level_names[msg.level]) + "]" + default_color); + if (!g_bSpdLog_CreateLogFiles) + return; - out += str; - } - // print the string to the console - this is definitely bad i think - HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); - auto ignored = WriteConsoleA(handle, out.c_str(), std::strlen(out.c_str()), nullptr, nullptr); - (void)ignored; + spdlog::rotating_logger_mt( + "northstar(info)", fmt::format("{:s}\\{:s}", g_svLogDirectory, "message.txt"), SPDLOG_MAX_LOG_SIZE, SPDLOG_MAX_FILES) + ->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %v"); + spdlog::rotating_logger_mt( + "northstar(warning)", fmt::format("{:s}\\{:s}", g_svLogDirectory, "warning.txt"), SPDLOG_MAX_LOG_SIZE, SPDLOG_MAX_FILES) + ->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %v"); + spdlog::rotating_logger_mt( + "northstar(error)", fmt::format("{:s}\\{:s}", g_svLogDirectory, "error.txt"), SPDLOG_MAX_LOG_SIZE, SPDLOG_MAX_FILES) + ->set_pattern("[%Y-%m-%d %H:%M:%S.%e] %v"); } -void ExternalConsoleSink::flush_() +//----------------------------------------------------------------------------- +// Purpose: Shutdowns spdlog +//----------------------------------------------------------------------------- +void SpdLog_Shutdown(void) { - std::cout << std::flush; + spdlog::shutdown(); } - -void CustomSink::custom_log(const custom_log_msg& msg) +//----------------------------------------------------------------------------- +// Purpose: Initilazes the windows console +//----------------------------------------------------------------------------- +void Console_Init(void) { - std::lock_guard lock(mutex_); - custom_sink_it_(msg); -} + g_bConsole_UseAnsiColor = strstr(GetCommandLineA(), "-noansicolor") == NULL; -void InitialiseConsole() -{ - if (AllocConsole() == FALSE) - { - std::cout << "[*] Failed to create a console window, maybe a console already exists?" << std::endl; - } - else - { - freopen("CONOUT$", "w", stdout); - freopen("CONOUT$", "w", stderr); - } + // Always show the console when starting-up. + (void)AllocConsole(); - // this if statement is adapted from r5sdk - if (!strstr(GetCommandLineA(), "-noansiclr")) + FILE* pDummy; + freopen_s(&pDummy, "CONIN$", "r", stdin); + freopen_s(&pDummy, "CONOUT$", "w", stdout); + freopen_s(&pDummy, "CONOUT$", "w", stderr); + + if (g_bConsole_UseAnsiColor) { - g_bSpdLog_UseAnsiColor = true; DWORD dwMode = 0; HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleMode(hOutput, &dwMode); dwMode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING; - if (!SetConsoleMode(hOutput, dwMode)) // Some editions of Windows have 'VirtualTerminalLevel' disabled by default. + if (!SetConsoleMode(hOutput, dwMode)) { - // If 'VirtualTerminalLevel' can't be set, just disable ANSI color, since it wouldnt work anyway. - spdlog::warn("could not set VirtualTerminalLevel. Disabling color output"); - g_bSpdLog_UseAnsiColor = false; + g_bConsole_UseAnsiColor = false; } } } -void RegisterLogger(std::shared_ptr logger) -{ - loggers.push_back(logger); -} - -void RegisterCustomSink(std::shared_ptr sink) -{ - for (auto& logger : loggers) - { - logger->custom_sinks_.push_back(sink); - } -}; - -void InitialiseLogging() +//----------------------------------------------------------------------------- +// Purpose: Closes the console window if wanted +//----------------------------------------------------------------------------- +void Console_PostInit(void) { - // create a logger, and set it to default - NS::log::NORTHSTAR = std::make_shared("NORTHSTAR", NS::Colors::NORTHSTAR, true); - NS::log::NORTHSTAR->sinks().clear(); - loggers.push_back(NS::log::NORTHSTAR); - spdlog::set_default_logger(NS::log::NORTHSTAR); - - // create our console sink - auto sink = std::make_shared(); - // set the pattern - if (g_bSpdLog_UseAnsiColor) - // dont put the log level in the pattern if we are using colours, as the colour will show the log level - sink->set_pattern("[%H:%M:%S] [NAME] [LVL] %v"); - else - sink->set_pattern("[%H:%M:%S] [%n] [%l] %v"); - - // add our sink to the logger - NS::log::NORTHSTAR->custom_sinks_.push_back(sink); - - NS::log::SCRIPT_UI = std::make_shared("SCRIPT UI", NS::Colors::SCRIPT_UI); - NS::log::SCRIPT_CL = std::make_shared("SCRIPT CL", NS::Colors::SCRIPT_CL); - NS::log::SCRIPT_SV = std::make_shared("SCRIPT SV", NS::Colors::SCRIPT_SV); - - NS::log::NATIVE_UI = std::make_shared("NATIVE UI", NS::Colors::NATIVE_UI); - NS::log::NATIVE_CL = std::make_shared("NATIVE CL", NS::Colors::NATIVE_CL); - NS::log::NATIVE_SV = std::make_shared("NATIVE SV", NS::Colors::NATIVE_SV); - NS::log::NATIVE_EN = std::make_shared("NATIVE EN", NS::Colors::NATIVE_ENGINE); + // Hide the console if user wants to + bool bHide = strstr(GetCommandLineA(), "-wconsole") == NULL && !IsDedicatedServer(); - NS::log::fs = std::make_shared("FILESYSTM", NS::Colors::FILESYSTEM); - NS::log::rpak = std::make_shared("RPAK_FSYS", NS::Colors::RPAK); - NS::log::echo = std::make_shared("ECHO", NS::Colors::ECHO); - - NS::log::PLUGINSYS = std::make_shared("PLUGINSYS", NS::Colors::PLUGINSYS); - - loggers.push_back(NS::log::SCRIPT_UI); - loggers.push_back(NS::log::SCRIPT_CL); - loggers.push_back(NS::log::SCRIPT_SV); - - loggers.push_back(NS::log::NATIVE_UI); - loggers.push_back(NS::log::NATIVE_CL); - loggers.push_back(NS::log::NATIVE_SV); - loggers.push_back(NS::log::NATIVE_EN); - - loggers.push_back(NS::log::PLUGINSYS); + if (!bHide) + return; - loggers.push_back(NS::log::fs); - loggers.push_back(NS::log::rpak); - loggers.push_back(NS::log::echo); + HWND hConsole = GetConsoleWindow(); + (void)FreeConsole(); + (void)PostMessageA(hConsole, WM_CLOSE, 0, 0); } -void NS::log::FlushLoggers() -{ - for (auto& logger : loggers) - logger->flush(); - - spdlog::default_logger()->flush(); -} +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void Console_Shutdown(void) {} +//----------------------------------------------------------------------------- // Wine specific functions typedef const char*(CDECL* wine_get_host_version_type)(const char**, const char**); wine_get_host_version_type wine_get_host_version; @@ -231,21 +167,25 @@ wine_get_host_version_type wine_get_host_version; typedef const char*(CDECL* wine_get_build_id_type)(void); wine_get_build_id_type wine_get_build_id; +//----------------------------------------------------------------------------- // Not exported Winapi methods typedef NTSTATUS(WINAPI* RtlGetVersion_type)(PRTL_OSVERSIONINFOW); RtlGetVersion_type RtlGetVersion; -void StartupLog() +//----------------------------------------------------------------------------- +// Purpose: Print Operating System information +//----------------------------------------------------------------------------- +void Sys_PrintOSVer() { - spdlog::info("NorthstarLauncher version: {}", version); - spdlog::info("Command line: {}", GetCommandLineA()); - spdlog::info("Using profile: {}", GetNorthstarPrefix()); + DevMsg(eLog::NS, "NorthstarLauncher version: %s\n", version); + DevMsg(eLog::NS, "Command line: %s\n", GetCommandLineA()); + DevMsg(eLog::NS, "Using profile: %s\n", GetNorthstarPrefix().c_str()); + // ntdll is always loaded HMODULE ntdll = GetModuleHandleA("ntdll.dll"); if (!ntdll) { - // How did we get here - spdlog::info("Operating System: Unknown"); + DevMsg(eLog::NS, "Operating System: Unknown\n"); return; } @@ -258,8 +198,8 @@ void StartupLog() const char* sysname; wine_get_host_version(&sysname, NULL); - spdlog::info("Operating System: {} (Wine)", sysname); - spdlog::info("Wine build: {}", wine_get_build_id()); + DevMsg(eLog::NS, "Operating System: %s (Wine)\n", sysname); + DevMsg(eLog::NS, "Wine build: %s\n", wine_get_build_id()); // STEAM_COMPAT_TOOL_PATHS is a colon separated lists of all compat tool paths used // The first one tends to be the Proton path itself @@ -276,7 +216,7 @@ void StartupLog() if (protonBasenameStart == std::string_view::npos) protonBasenameStart = 0; - spdlog::info("Proton build: {}", compatToolPath.substr(protonBasenameStart, protonBasenameEnd - protonBasenameStart)); + DevMsg(eLog::NS, "Proton build: %s\n", compatToolPath.substr(protonBasenameStart, protonBasenameEnd - protonBasenameStart)); } } else @@ -292,11 +232,29 @@ void StartupLog() { // Version reference table // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoa#remarks - spdlog::info("Operating System: Windows (NT{}.{})", osvi.dwMajorVersion, osvi.dwMinorVersion); + DevMsg(eLog::NS, "Operating System: Windows (NT%i.%i)\n", osvi.dwMajorVersion, osvi.dwMinorVersion); } else { - spdlog::info("Operating System: Windows"); + DevMsg(eLog::NS, "Operating System: Windows\n"); } } } + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +// clang-format off +AUTOHOOK(Respawn_CreateWindow, engine.dll + 0x1CD0E0, bool, __fastcall, + (void* a1)) +// clang-format on +{ + Console_PostInit(); + return Respawn_CreateWindow(a1); +} + +//----------------------------------------------------------------------------- +ON_DLL_LOAD_CLIENT("engine.dll", CreateWindowLog, (CModule module)) +{ + AUTOHOOK_DISPATCH() +} diff --git a/NorthstarDLL/logging/logging.h b/NorthstarDLL/logging/logging.h index af4b506c1..4436c2f0f 100644 --- a/NorthstarDLL/logging/logging.h +++ b/NorthstarDLL/logging/logging.h @@ -4,133 +4,31 @@ #include "squirrel/squirrel.h" #include "core/math/color.h" -void CreateLogFiles(); -void InitialiseLogging(); -void InitialiseConsole(); -void StartupLog(); - -class ColoredLogger; - -struct custom_log_msg : spdlog::details::log_msg -{ - public: - custom_log_msg(ColoredLogger* origin, spdlog::details::log_msg msg) : origin(origin), spdlog::details::log_msg(msg) {} - - ColoredLogger* origin; -}; - -class CustomSink : public spdlog::sinks::base_sink -{ - public: - void custom_log(const custom_log_msg& msg); - virtual void custom_sink_it_(const custom_log_msg& msg) - { - throw std::runtime_error("Pure virtual call to CustomSink::custom_sink_it_"); - } -}; - -class ColoredLogger : public spdlog::logger -{ - public: - std::string ANSIColor; - SourceColor SRCColor; - - std::vector> custom_sinks_; - - ColoredLogger(std::string name, Color color, bool first = false) : spdlog::logger(*spdlog::default_logger()) - { - name_ = std::move(name); - if (!first) - { - custom_sinks_ = dynamic_pointer_cast(spdlog::default_logger())->custom_sinks_; - } - - ANSIColor = color.ToANSIColor(); - SRCColor = color.ToSourceColor(); - } - - void sink_it_(const spdlog::details::log_msg& msg) - { - custom_log_msg custom_msg {this, msg}; - - // Ugh - for (auto& sink : sinks_) - { - SPDLOG_TRY - { - sink->log(custom_msg); - } - SPDLOG_LOGGER_CATCH() - } - - for (auto& sink : custom_sinks_) - { - SPDLOG_TRY - { - sink->custom_log(custom_msg); - } - SPDLOG_LOGGER_CATCH() - } - - if (should_flush_(custom_msg)) - { - flush_(); - } - } -}; - -namespace NS::log -{ - // Squirrel - extern std::shared_ptr SCRIPT_UI; - extern std::shared_ptr SCRIPT_CL; - extern std::shared_ptr SCRIPT_SV; - - // Native code - extern std::shared_ptr NATIVE_UI; - extern std::shared_ptr NATIVE_CL; - extern std::shared_ptr NATIVE_SV; - extern std::shared_ptr NATIVE_EN; - - // File system - extern std::shared_ptr fs; - // RPak - extern std::shared_ptr rpak; - // Echo - extern std::shared_ptr echo; - - extern std::shared_ptr NORTHSTAR; - - extern std::shared_ptr PLUGINSYS; - - void FlushLoggers(); -}; // namespace NS::log - -void RegisterCustomSink(std::shared_ptr sink); -void RegisterLogger(std::shared_ptr logger); - -inline bool g_bSpdLog_UseAnsiColor = true; - -// Could maybe use some different names here, idk -static const char* level_names[] {"trac", "dbug", "info", "warn", "errr", "crit", "off"}; - -// spdlog logger, for cool colour things -class ExternalConsoleSink : public CustomSink -{ - private: - std::map m_LogColours = { - {spdlog::level::trace, NS::Colors::TRACE.ToANSIColor()}, - {spdlog::level::debug, NS::Colors::DEBUG.ToANSIColor()}, - {spdlog::level::info, NS::Colors::INFO.ToANSIColor()}, - {spdlog::level::warn, NS::Colors::WARN.ToANSIColor()}, - {spdlog::level::err, NS::Colors::ERR.ToANSIColor()}, - {spdlog::level::critical, NS::Colors::CRIT.ToANSIColor()}, - {spdlog::level::off, NS::Colors::OFF.ToANSIColor()}}; - - std::string default_color = "\033[39;49m"; - - protected: - void sink_it_(const spdlog::details::log_msg& msg) override; - void custom_sink_it_(const custom_log_msg& msg); - void flush_() override; -}; +// Directory we put log files in ( %profile%\\logs\\%timestamp%\\ ) +inline std::string g_svLogDirectory; + +// Windows terminal logger +inline std::shared_ptr g_WinLogger; + +// Settings +inline bool g_bConsole_UseAnsiColor = false; +inline bool g_bSpdLog_CreateLogFiles = true; + +// Log file settings +constexpr int SPDLOG_MAX_LOG_SIZE = 10 * 1024 * 1024; // 10 MB max +constexpr int SPDLOG_MAX_FILES = 512; + +//----------------------------------------------------------------------------- +void SpdLog_PreInit(void); +void SpdLog_Init(void); +void SpdLog_CreateLoggers(void); +void SpdLog_Shutdown(void); + +// TODO [Fifty]: Possibly move into it's own file +void Console_Init(void); +void Console_PostInit(void); +void Console_Shutdown(void); + +// +void Sys_PrintOSVer(); +// TODO [Fifty]: Print hardware info too diff --git a/NorthstarDLL/logging/loghooks.cpp b/NorthstarDLL/logging/loghooks.cpp index 41e1bce23..faaee849b 100644 --- a/NorthstarDLL/logging/loghooks.cpp +++ b/NorthstarDLL/logging/loghooks.cpp @@ -53,14 +53,6 @@ const std::unordered_map PrintSpewTypes = { {SpewType_t::SPEW_ERROR, "SPEW_ERROR"}, {SpewType_t::SPEW_LOG, "SPEW_LOG"}}; -// these are used to define the base text colour for these things -const std::unordered_map PrintSpewLevels = { - {SpewType_t::SPEW_MESSAGE, spdlog::level::level_enum::info}, - {SpewType_t::SPEW_WARNING, spdlog::level::level_enum::warn}, - {SpewType_t::SPEW_ASSERT, spdlog::level::level_enum::err}, - {SpewType_t::SPEW_ERROR, spdlog::level::level_enum::err}, - {SpewType_t::SPEW_LOG, spdlog::level::level_enum::info}}; - const std::unordered_map PrintSpewTypes_Short = { {SpewType_t::SPEW_MESSAGE, 'M'}, {SpewType_t::SPEW_WARNING, 'W'}, @@ -90,7 +82,7 @@ void,, (BFRead* msg)) break; default: - spdlog::warn("Unimplemented TextMsg type {}! printing to console", msg_dest); + Warning(eLog::CLIENT, "Unimplemented TextMsg type %i! printing to console\n", msg_dest); [[fallthrough]]; case TextMsgPrintType_t::HUD_PRINTCONSOLE: @@ -98,7 +90,7 @@ void,, (BFRead* msg)) if (text[endpos - 1] == '\n') text[endpos - 1] = '\0'; // cut off repeated newline - spdlog::info(text); + DevMsg(eLog::CLIENT, "%s\n", text); break; } } @@ -118,7 +110,7 @@ int,, (void* const stream, const char* const format, ...)) { if (buf[charsWritten - 1] == '\n') buf[charsWritten - 1] = '\0'; - NS::log::NATIVE_EN->info("{}", buf); + DevMsg(eLog::ENGINE, "%s\n", buf); } va_end(va); @@ -131,7 +123,7 @@ void,, (const CCommand& arg)) // clang-format on { if (arg.ArgC() >= 2) - NS::log::echo->info("{}", arg.ArgS()); + DevMsg(eLog::ENGINE, "%s\n", arg.ArgS()); } // clang-format off @@ -201,13 +193,26 @@ void, __fastcall, (void* pEngineServer, SpewType_t type, const char* format, va_ if (bShouldFormat) vsnprintf(formatted, sizeof(formatted), format, args); else - spdlog::warn("Failed to format {} \"{}\"", typeStr, format); + Warning(eLog::NS, "Failed to format %s \"%s\"\n", typeStr, format); auto endpos = strlen(formatted); if (formatted[endpos - 1] == '\n') formatted[endpos - 1] = '\0'; // cut off repeated newline - NS::log::NATIVE_SV->log(PrintSpewLevels.at(type), "{}", formatted); + switch (type) + { + case SpewType_t::SPEW_MESSAGE: + case SpewType_t::SPEW_LOG: + DevMsg(eLog::ENGINE, "%s\n", formatted); + break; + case SpewType_t::SPEW_WARNING: + Warning(eLog::ENGINE, "%s\n", formatted); + break; + case SpewType_t::SPEW_ASSERT: + case SpewType_t::SPEW_ERROR: + Error(eLog::ENGINE, NO_ERROR, "%s\n", formatted); + break; + } } // used for printing the output of status @@ -227,7 +232,7 @@ void,, (const char* text, ...)) if (formatted[endpos - 1] == '\n') formatted[endpos - 1] = '\0'; // cut off repeated newline - spdlog::info(formatted); + DevMsg(eLog::ENGINE, "%s\n", formatted); } // clang-format off @@ -241,7 +246,7 @@ bool,, (void* thisptr, uintptr_t msg)) if (text[endpos - 1] == '\n') text[endpos - 1] = '\0'; // cut off repeated newline - spdlog::info(text); + DevMsg(eLog::ENGINE, "%s\n", text); return true; } diff --git a/NorthstarDLL/logging/sourceconsole.cpp b/NorthstarDLL/logging/sourceconsole.cpp index e436d1d42..172955df8 100644 --- a/NorthstarDLL/logging/sourceconsole.cpp +++ b/NorthstarDLL/logging/sourceconsole.cpp @@ -24,34 +24,6 @@ void ConCommand_hideconsole(const CCommand& arg) (*g_pSourceGameConsole)->Hide(); } -void SourceConsoleSink::custom_sink_it_(const custom_log_msg& msg) -{ - if (!(*g_pSourceGameConsole)->m_bInitialized) - return; - - spdlog::memory_buf_t formatted; - spdlog::sinks::base_sink::formatter_->format(msg, formatted); - - // get message string - std::string str = fmt::to_string(formatted); - - SourceColor levelColor = m_LogColours[msg.level]; - std::string name {msg.logger_name.begin(), msg.logger_name.end()}; - - (*g_pSourceGameConsole)->m_pConsole->m_pConsolePanel->ColorPrint(msg.origin->SRCColor, ("[" + name + "]").c_str()); - (*g_pSourceGameConsole)->m_pConsole->m_pConsolePanel->Print(" "); - (*g_pSourceGameConsole)->m_pConsole->m_pConsolePanel->ColorPrint(levelColor, ("[" + std::string(level_names[msg.level]) + "]").c_str()); - (*g_pSourceGameConsole)->m_pConsole->m_pConsolePanel->Print(" "); - (*g_pSourceGameConsole)->m_pConsole->m_pConsolePanel->Print(fmt::to_string(formatted).c_str()); -} - -void SourceConsoleSink::sink_it_(const spdlog::details::log_msg& msg) -{ - throw std::runtime_error("sink_it_ called on SourceConsoleSink with pure log_msg. This is an error!"); -} - -void SourceConsoleSink::flush_() {} - // clang-format off HOOK(OnCommandSubmittedHook, OnCommandSubmitted, void, __fastcall, (CConsoleDialog* consoleDialog, const char* pCommand)) @@ -72,13 +44,6 @@ void InitialiseConsoleOnInterfaceCreation() (*g_pSourceGameConsole)->Initialize(); // hook OnCommandSubmitted so we print inputted commands OnCommandSubmittedHook.Dispatch((LPVOID)(*g_pSourceGameConsole)->m_pConsole->m_vtable->OnCommandSubmitted); - - auto consoleSink = std::make_shared(); - if (g_bSpdLog_UseAnsiColor) - consoleSink->set_pattern("%v"); // no need to include the level in the game console, the text colour signifies it anyway - else - consoleSink->set_pattern("[%n] [%l] %v"); // no colour, so we should show the level for colourblind people - RegisterCustomSink(consoleSink); } ON_DLL_LOAD_CLIENT_RELIESON("client.dll", SourceConsole, ConCommand, (CModule module)) diff --git a/NorthstarDLL/logging/sourceconsole.h b/NorthstarDLL/logging/sourceconsole.h index 3abcc4705..7528719ea 100644 --- a/NorthstarDLL/logging/sourceconsole.h +++ b/NorthstarDLL/logging/sourceconsole.h @@ -63,23 +63,4 @@ class CGameConsole extern SourceInterface* g_pSourceGameConsole; -// spdlog logger -class SourceConsoleSink : public CustomSink -{ - private: - std::map m_LogColours = { - {spdlog::level::trace, NS::Colors::TRACE.ToSourceColor()}, - {spdlog::level::debug, NS::Colors::DEBUG.ToSourceColor()}, - {spdlog::level::info, NS::Colors::INFO.ToSourceColor()}, - {spdlog::level::warn, NS::Colors::WARN.ToSourceColor()}, - {spdlog::level::err, NS::Colors::ERR.ToSourceColor()}, - {spdlog::level::critical, NS::Colors::CRIT.ToSourceColor()}, - {spdlog::level::off, NS::Colors::OFF.ToSourceColor()}}; - - protected: - void custom_sink_it_(const custom_log_msg& msg); - void sink_it_(const spdlog::details::log_msg& msg) override; - void flush_() override; -}; - void InitialiseConsoleOnInterfaceCreation(); diff --git a/NorthstarDLL/masterserver/masterserver.cpp b/NorthstarDLL/masterserver/masterserver.cpp index 64f172c98..df83739ac 100644 --- a/NorthstarDLL/masterserver/masterserver.cpp +++ b/NorthstarDLL/masterserver/masterserver.cpp @@ -102,7 +102,7 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(const char* uid, co std::thread requestThread( [this, uidStr, tokenStr]() { - spdlog::info("Trying to authenticate with northstar masterserver for user {}", uidStr); + DevMsg(eLog::MS, "Trying to authenticate with northstar masterserver for user %s\n", uidStr.c_str()); CURL* curl = curl_easy_init(); SetCommonHttpClientOptions(curl); @@ -126,15 +126,18 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(const char* uid, co if (originAuthInfo.HasParseError()) { - spdlog::error( - "Failed reading origin auth info response: encountered parse error \"{}\"", + Error( + eLog::MS, + NO_ERROR, + "Failed reading origin auth info response: encountered parse error \"%s\"\n", rapidjson::GetParseError_En(originAuthInfo.GetParseError())); goto REQUEST_END_CLEANUP; } if (!originAuthInfo.IsObject() || !originAuthInfo.HasMember("success")) { - spdlog::error("Failed reading origin auth info response: malformed response object {}", readBuffer); + Error( + eLog::MS, NO_ERROR, "Failed reading origin auth info response: malformed response object %s\n", readBuffer.c_str()); goto REQUEST_END_CLEANUP; } @@ -145,12 +148,12 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(const char* uid, co sizeof(m_sOwnClientAuthToken), originAuthInfo["token"].GetString(), sizeof(m_sOwnClientAuthToken) - 1); - spdlog::info("Northstar origin authentication completed successfully!"); + DevMsg(eLog::MS, "Northstar origin authentication completed successfully!\n"); m_bOriginAuthWithMasterServerSuccessful = true; } else { - spdlog::error("Northstar origin authentication failed"); + Error(eLog::MS, NO_ERROR, "Northstar origin authentication failed\n"); if (originAuthInfo.HasMember("error") && originAuthInfo["error"].IsObject()) { @@ -169,7 +172,7 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(const char* uid, co } else { - spdlog::error("Failed performing northstar origin auth: error {}", curl_easy_strerror(result)); + Error(eLog::MS, NO_ERROR, "Failed performing northstar origin auth: error %s\n", curl_easy_strerror(result)); m_bSuccessfullyConnected = false; } @@ -199,7 +202,7 @@ void MasterServerManager::RequestServerList() m_bRequestingServerList = true; m_bScriptRequestingServerList = true; - spdlog::info("Requesting server list from {}", Cvar_ns_masterserver_hostname->GetString()); + DevMsg(eLog::MS, "Requesting server list from %s\n", Cvar_ns_masterserver_hostname->GetString()); CURL* curl = curl_easy_init(); SetCommonHttpClientOptions(curl); @@ -221,34 +224,36 @@ void MasterServerManager::RequestServerList() if (serverInfoJson.HasParseError()) { - spdlog::error( - "Failed reading masterserver response: encountered parse error \"{}\"", + Error( + eLog::MS, + NO_ERROR, + "Failed reading masterserver response: encountered parse error \"%s\"\n", rapidjson::GetParseError_En(serverInfoJson.GetParseError())); goto REQUEST_END_CLEANUP; } if (serverInfoJson.IsObject() && serverInfoJson.HasMember("error")) { - spdlog::error("Failed reading masterserver response: got fastify error response"); - spdlog::error(readBuffer); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver response: got fastify error response\n"); + Error(eLog::MS, NO_ERROR, "%s\n", readBuffer.c_str()); goto REQUEST_END_CLEANUP; } if (!serverInfoJson.IsArray()) { - spdlog::error("Failed reading masterserver response: root object is not an array"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver response: root object is not an array\n"); goto REQUEST_END_CLEANUP; } rapidjson::GenericArray serverArray = serverInfoJson.GetArray(); - spdlog::info("Got {} servers", serverArray.Size()); + DevMsg(eLog::MS, "Got %li servers\n", serverArray.Size()); for (auto& serverObj : serverArray) { if (!serverObj.IsObject()) { - spdlog::error("Failed reading masterserver response: member of server array is not an object"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver response: member of server array is not an object\n"); goto REQUEST_END_CLEANUP; } @@ -261,7 +266,7 @@ void MasterServerManager::RequestServerList() !serverObj["hasPassword"].IsBool() || !serverObj.HasMember("modInfo") || !serverObj["modInfo"].HasMember("Mods") || !serverObj["modInfo"]["Mods"].IsArray()) { - spdlog::error("Failed reading masterserver response: malformed server object"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver response: malformed server object\n"); continue; }; @@ -337,7 +342,7 @@ void MasterServerManager::RequestServerList() } else { - spdlog::error("Failed requesting servers: error {}", curl_easy_strerror(result)); + Error(eLog::MS, NO_ERROR, "Failed requesting servers: error %s\n", curl_easy_strerror(result)); m_bSuccessfullyConnected = false; } @@ -382,22 +387,24 @@ void MasterServerManager::RequestMainMenuPromos() if (mainMenuPromoJson.HasParseError()) { - spdlog::error( - "Failed reading masterserver main menu promos response: encountered parse error \"{}\"", + Error( + eLog::MS, + NO_ERROR, + "Failed reading masterserver main menu promos response: encountered parse error \"%s\"\n", rapidjson::GetParseError_En(mainMenuPromoJson.GetParseError())); goto REQUEST_END_CLEANUP; } if (!mainMenuPromoJson.IsObject()) { - spdlog::error("Failed reading masterserver main menu promos response: root object is not an object"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver main menu promos response: root object is not an object\n"); goto REQUEST_END_CLEANUP; } if (mainMenuPromoJson.HasMember("error")) { - spdlog::error("Failed reading masterserver response: got fastify error response"); - spdlog::error(readBuffer); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver response: got fastify error response\n"); + Error(eLog::MS, NO_ERROR, "%s\n", readBuffer.c_str()); goto REQUEST_END_CLEANUP; } @@ -425,7 +432,7 @@ void MasterServerManager::RequestMainMenuPromos() !mainMenuPromoJson["smallButton2"].HasMember("ImageIndex") || !mainMenuPromoJson["smallButton2"]["ImageIndex"].IsNumber()) { - spdlog::error("Failed reading masterserver main menu promos response: malformed json object"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver main menu promos response: malformed json object\n"); goto REQUEST_END_CLEANUP; } @@ -450,7 +457,7 @@ void MasterServerManager::RequestMainMenuPromos() } else { - spdlog::error("Failed requesting main menu promos: error {}", curl_easy_strerror(result)); + Error(eLog::MS, NO_ERROR, "Failed requesting main menu promos: error %s\n", curl_easy_strerror(result)); m_bSuccessfullyConnected = false; } @@ -503,22 +510,24 @@ void MasterServerManager::AuthenticateWithOwnServer(const char* uid, const char* if (authInfoJson.HasParseError()) { - spdlog::error( - "Failed reading masterserver authentication response: encountered parse error \"{}\"", + Error( + eLog::MS, + NO_ERROR, + "Failed reading masterserver authentication response: encountered parse error \"%s\"\n", rapidjson::GetParseError_En(authInfoJson.GetParseError())); goto REQUEST_END_CLEANUP; } if (!authInfoJson.IsObject()) { - spdlog::error("Failed reading masterserver authentication response: root object is not an object"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver authentication response: root object is not an object\n"); goto REQUEST_END_CLEANUP; } if (authInfoJson.HasMember("error")) { - spdlog::error("Failed reading masterserver response: got fastify error response"); - spdlog::error(readBuffer); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver response: got fastify error response\n"); + Error(eLog::MS, NO_ERROR, "%s\n", readBuffer.c_str()); if (authInfoJson["error"].HasMember("msg")) m_sAuthFailureReason = authInfoJson["error"]["msg"].GetString(); @@ -532,7 +541,7 @@ void MasterServerManager::AuthenticateWithOwnServer(const char* uid, const char* if (!authInfoJson["success"].IsTrue()) { - spdlog::error("Authentication with masterserver failed: \"success\" is not true"); + Error(eLog::MS, NO_ERROR, "Authentication with masterserver failed: \"success\" is not true\n"); goto REQUEST_END_CLEANUP; } @@ -540,7 +549,7 @@ void MasterServerManager::AuthenticateWithOwnServer(const char* uid, const char* !authInfoJson.HasMember("authToken") || !authInfoJson["authToken"].IsString() || !authInfoJson.HasMember("persistentData") || !authInfoJson["persistentData"].IsArray()) { - spdlog::error("Failed reading masterserver authentication response: malformed json object"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver authentication response: malformed json object\n"); goto REQUEST_END_CLEANUP; } @@ -558,7 +567,7 @@ void MasterServerManager::AuthenticateWithOwnServer(const char* uid, const char* { if (!byte.IsUint() || byte.GetUint() > 255) { - spdlog::error("Failed reading masterserver authentication response: malformed json object"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver authentication response: malformed json object\n"); goto REQUEST_END_CLEANUP; } @@ -574,7 +583,7 @@ void MasterServerManager::AuthenticateWithOwnServer(const char* uid, const char* } else { - spdlog::error("Failed authenticating with own server: error {}", curl_easy_strerror(result)); + Error(eLog::MS, NO_ERROR, "Failed authenticating with own server: error %s\n", curl_easy_strerror(result)); m_bSuccessfullyConnected = false; m_bSuccessfullyAuthenticatedWithGameServer = false; m_bScriptAuthenticatingWithGameServer = false; @@ -620,7 +629,7 @@ void MasterServerManager::AuthenticateWithServer(const char* uid, const char* pl while (m_bSavingPersistentData) Sleep(100); - spdlog::info("Attempting authentication with server of id \"{}\"", serverIdStr); + DevMsg(eLog::MS, "Attempting authentication with server of id \"%s\"\n", serverIdStr.c_str()); CURL* curl = curl_easy_init(); SetCommonHttpClientOptions(curl); @@ -659,22 +668,24 @@ void MasterServerManager::AuthenticateWithServer(const char* uid, const char* pl if (connectionInfoJson.HasParseError()) { - spdlog::error( - "Failed reading masterserver authentication response: encountered parse error \"{}\"", + Error( + eLog::MS, + NO_ERROR, + "Failed reading masterserver authentication response: encountered parse error \"%s\"\n", rapidjson::GetParseError_En(connectionInfoJson.GetParseError())); goto REQUEST_END_CLEANUP; } if (!connectionInfoJson.IsObject()) { - spdlog::error("Failed reading masterserver authentication response: root object is not an object"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver authentication response: root object is not an object\n"); goto REQUEST_END_CLEANUP; } if (connectionInfoJson.HasMember("error")) { - spdlog::error("Failed reading masterserver response: got fastify error response"); - spdlog::error(readBuffer); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver response: got fastify error response\n"); + Error(eLog::MS, NO_ERROR, "%s\n", readBuffer.c_str()); if (connectionInfoJson["error"].HasMember("msg")) m_sAuthFailureReason = connectionInfoJson["error"]["msg"].GetString(); @@ -688,7 +699,7 @@ void MasterServerManager::AuthenticateWithServer(const char* uid, const char* pl if (!connectionInfoJson["success"].IsTrue()) { - spdlog::error("Authentication with masterserver failed: \"success\" is not true"); + Error(eLog::MS, NO_ERROR, "Authentication with masterserver failed: \"success\" is not true\n"); goto REQUEST_END_CLEANUP; } @@ -697,7 +708,7 @@ void MasterServerManager::AuthenticateWithServer(const char* uid, const char* pl !connectionInfoJson["port"].IsNumber() || !connectionInfoJson.HasMember("authToken") || !connectionInfoJson["authToken"].IsString()) { - spdlog::error("Failed reading masterserver authentication response: malformed json object"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver authentication response: malformed json object\n"); goto REQUEST_END_CLEANUP; } @@ -718,7 +729,7 @@ void MasterServerManager::AuthenticateWithServer(const char* uid, const char* pl } else { - spdlog::error("Failed authenticating with server: error {}", curl_easy_strerror(result)); + Error(eLog::MS, NO_ERROR, "Failed authenticating with server: error %s\n", curl_easy_strerror(result)); m_bSuccessfullyConnected = false; m_bSuccessfullyAuthenticatedWithGameServer = false; m_bScriptAuthenticatingWithGameServer = false; @@ -739,7 +750,7 @@ void MasterServerManager::WritePlayerPersistentData(const char* playerId, const m_bSavingPersistentData = true; if (!pdataSize) { - spdlog::warn("attempted to write pdata of size 0!"); + Warning(eLog::MS, "attempted to write pdata of size 0!"); return; } @@ -799,13 +810,18 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data) if (obj.HasParseError()) { // note: it's okay to print the data as-is since we've already checked that it actually came from Atlas - spdlog::error("invalid Atlas connectionless packet request ({}): {}", data, GetParseError_En(obj.GetParseError())); + Error( + eLog::MS, + NO_ERROR, + "invalid Atlas connectionless packet request (%s): %i\n", + data.c_str(), + GetParseError_En(obj.GetParseError())); return; } if (!obj.HasMember("type") || !obj["type"].IsString()) { - spdlog::error("invalid Atlas connectionless packet request ({}): missing type", data); + Error(eLog::MS, NO_ERROR, "invalid Atlas connectionless packet request (%s): missing type\n", data); return; } @@ -815,7 +831,7 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data) { if (!obj.HasMember("token") || !obj["token"].IsString()) { - spdlog::error("failed to handle Atlas connect request: missing or invalid connection token field"); + Error(eLog::MS, NO_ERROR, "failed to handle Atlas connect request: missing or invalid connection token field\n"); return; } std::string token = obj["token"].GetString(); @@ -825,11 +841,11 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data) else return; // already handled - spdlog::info("handling Atlas connect request {}", data); + DevMsg(eLog::MS, "handling Atlas connect request %s\n", data.c_str()); if (!obj.HasMember("uid") || !obj["uid"].IsUint64()) { - spdlog::error("failed to handle Atlas connect request {}: missing or invalid uid field", token); + Error(eLog::MS, NO_ERROR, "failed to handle Atlas connect request %s: missing or invalid uid field\n", token.c_str()); return; } uint64_t uid = obj["uid"].GetUint64(); @@ -845,7 +861,7 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data) std::string pdata; if (reject == "") { - spdlog::info("getting pdata for connection {} (uid={} username={})", token, uid, username); + DevMsg(eLog::MS, "getting pdata for connection %s (uid=%i username=%s)\n", token.c_str(), uid, username.c_str()); CURL* curl = curl_easy_init(); SetCommonHttpClientOptions(curl); @@ -862,7 +878,7 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data) CURLcode result = curl_easy_perform(curl); if (result != CURLcode::CURLE_OK) { - spdlog::error("failed to make Atlas connect pdata request {}: {}", token, curl_easy_strerror(result)); + Error(eLog::MS, NO_ERROR, "failed to make Atlas connect pdata request %s: %s\n", token.c_str(), curl_easy_strerror(result)); curl_easy_cleanup(curl); return; } @@ -878,28 +894,37 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data) obj.Parse(pdata.c_str()); if (!obj.HasParseError() && obj.HasMember("error") && obj["error"].IsObject()) - spdlog::error( - "failed to make Atlas connect pdata request {}: response status {}, error: {} ({})", - token, + Error( + eLog::MS, + NO_ERROR, + "failed to make Atlas connect pdata request %s: response status %li, error: %s (%s)\n", + token.c_str(), respStatus, ((obj["error"].HasMember("enum") && obj["error"]["enum"].IsString()) ? obj["error"]["enum"].GetString() : ""), ((obj["error"].HasMember("msg") && obj["error"]["msg"].IsString()) ? obj["error"]["msg"].GetString() : "")); else - spdlog::error("failed to make Atlas connect pdata request {}: response status {}", token, respStatus); + Error( + eLog::MS, + NO_ERROR, + "failed to make Atlas connect pdata request %s: response status %li\n", + token.c_str(), + respStatus); return; } if (!pdata.length()) { - spdlog::error("failed to make Atlas connect pdata request {}: pdata response is empty", token); + Error(eLog::MS, NO_ERROR, "failed to make Atlas connect pdata request %s: pdata response is empty\n", token.c_str()); return; } if (pdata.length() > R2::PERSISTENCE_MAX_SIZE) { - spdlog::error( - "failed to make Atlas connect pdata request {}: pdata is too large (max={} len={})", - token, + Error( + eLog::MS, + NO_ERROR, + "failed to make Atlas connect pdata request %s: pdata is too large (max=%i len=%i)\n", + token.c_str(), R2::PERSISTENCE_MAX_SIZE, pdata.length()); return; @@ -907,9 +932,21 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data) } if (reject == "") - spdlog::info("accepting connection {} (uid={} username={}) with {} bytes of pdata", token, uid, username, pdata.length()); + DevMsg( + eLog::MS, + "accepting connection %s (uid=%li username=%s) with %li bytes of pdata\n", + token.c_str(), + uid, + username.c_str(), + pdata.length()); else - spdlog::info("rejecting connection {} (uid={} username={}) with reason \"{}\"", token, uid, username, reject); + DevMsg( + eLog::MS, + "rejecting connection %s (uid=%li username=%s) with reason \"%s\"\n", + token.c_str(), + uid, + username.c_str(), + reject.c_str()); if (reject == "") g_pServerAuthentication->AddRemotePlayer(token, uid, username, pdata); @@ -921,7 +958,7 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data) char* rejectEnc = curl_easy_escape(curl, reject.c_str(), reject.length()); if (!rejectEnc) { - spdlog::error("failed to handle Atlas connect request {}: failed to escape reject", token); + Error(eLog::MS, NO_ERROR, "failed to handle Atlas connect request %s: failed to escape reject\n", token.c_str()); return; } curl_easy_setopt( @@ -946,7 +983,7 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data) CURLcode result = curl_easy_perform(curl); if (result != CURLcode::CURLE_OK) { - spdlog::error("failed to respond to Atlas connect request {}: {}", token, curl_easy_strerror(result)); + Error(eLog::MS, NO_ERROR, "failed to respond to Atlas connect request %s: %s\n", token.c_str(), curl_easy_strerror(result)); curl_easy_cleanup(curl); return; } @@ -962,14 +999,21 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data) obj.Parse(buf.c_str()); if (!obj.HasParseError() && obj.HasMember("error") && obj["error"].IsObject()) - spdlog::error( - "failed to respond to Atlas connect request {}: response status {}, error: {} ({})", - token, + Error( + eLog::MS, + NO_ERROR, + "failed to respond to Atlas connect request %s: response status %li, error: %s (%s)\n", + token.c_str(), respStatus, ((obj["error"].HasMember("enum") && obj["error"]["enum"].IsString()) ? obj["error"]["enum"].GetString() : ""), ((obj["error"].HasMember("msg") && obj["error"]["msg"].IsString()) ? obj["error"]["msg"].GetString() : "")); else - spdlog::error("failed to respond to Atlas connect request {}: response status {}", token, respStatus); + Error( + eLog::MS, + NO_ERROR, + "failed to respond to Atlas connect request %s: response status %li\n", + token.c_str(), + respStatus); return; } } @@ -977,7 +1021,7 @@ void MasterServerManager::ProcessConnectionlessPacketSigreq1(std::string data) return; } - spdlog::error("invalid Atlas connectionless packet request: unknown type {}", type); + Error(eLog::MS, NO_ERROR, "invalid Atlas connectionless packet request: unknown type %s\n", type.c_str()); } void ConCommand_ns_fetchservers(const CCommand& args) @@ -1128,7 +1172,7 @@ void MasterServerPresenceReporter::RunFrame(double flCurrentTime, const ServerPr if (m_nNumRegistrationAttempts >= MAX_REGISTRATION_ATTEMPTS) { - spdlog::error("Reached max ms server registration attempts."); + Error(eLog::MS, NO_ERROR, "Reached max ms server registration attempts.\n"); } } else if (updateServerFuture.valid()) @@ -1177,7 +1221,7 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ std::string modInfo = g_pMasterServerManager->m_sOwnModInfoJson; std::string hostname = Cvar_ns_masterserver_hostname->GetString(); - spdlog::info("Attempting to register the local server to the master server."); + DevMsg(eLog::MS, "Attempting to register the local server to the master server.\n"); addServerFuture = std::async( std::launch::async, @@ -1258,22 +1302,24 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ // No retry. if (serverAddedJson.HasParseError()) { - spdlog::error( - "Failed reading masterserver authentication response: encountered parse error \"{}\"", + Error( + eLog::MS, + NO_ERROR, + "Failed reading masterserver authentication response: encountered parse error \"%s\"\n", rapidjson::GetParseError_En(serverAddedJson.GetParseError())); return ReturnCleanup(MasterServerReportPresenceResult::FailedNoRetry); } if (!serverAddedJson.IsObject()) { - spdlog::error("Failed reading masterserver authentication response: root object is not an object"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver authentication response: root object is not an object\n"); return ReturnCleanup(MasterServerReportPresenceResult::FailedNoRetry); } if (serverAddedJson.HasMember("error")) { - spdlog::error("Failed reading masterserver response: got fastify error response"); - spdlog::error(readBuffer); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver response: got fastify error response\n"); + Error(eLog::MS, NO_ERROR, "%s\n", readBuffer.c_str()); // If this is DUPLICATE_SERVER, we'll retry adding the server every 20 seconds. // The master server will only update its internal server list and clean up dead servers on certain events. @@ -1282,7 +1328,7 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ if (serverAddedJson["error"].HasMember("enum") && strcmp(serverAddedJson["error"]["enum"].GetString(), "DUPLICATE_SERVER") == 0) { - spdlog::error("Cooling down while the master server cleans the dead server entry, if any."); + Error(eLog::MS, NO_ERROR, "Cooling down while the master server cleans the dead server entry, if any.\n"); return ReturnCleanup(MasterServerReportPresenceResult::FailedDuplicateServer); } @@ -1292,18 +1338,18 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ if (!serverAddedJson["success"].IsTrue()) { - spdlog::error("Adding server to masterserver failed: \"success\" is not true"); + Error(eLog::MS, NO_ERROR, "Adding server to masterserver failed: \"success\" is not true\n"); return ReturnCleanup(MasterServerReportPresenceResult::FailedNoRetry); } if (!serverAddedJson.HasMember("id") || !serverAddedJson["id"].IsString() || !serverAddedJson.HasMember("serverAuthToken") || !serverAddedJson["serverAuthToken"].IsString()) { - spdlog::error("Failed reading masterserver response: malformed json object"); + Error(eLog::MS, NO_ERROR, "Failed reading masterserver response: malformed json object\n"); return ReturnCleanup(MasterServerReportPresenceResult::FailedNoRetry); } - spdlog::info("Successfully registered the local server to the master server."); + DevMsg(eLog::MS, "Successfully registered the local server to the master server.\n"); return ReturnCleanup( MasterServerReportPresenceResult::Success, serverAddedJson["id"].GetString(), @@ -1311,7 +1357,7 @@ void MasterServerPresenceReporter::InternalAddServer(const ServerPresence* pServ } else { - spdlog::error("Failed adding self to server list: error {}", curl_easy_strerror(result)); + Error(eLog::MS, NO_ERROR, "Failed adding self to server list: error %s\n", curl_easy_strerror(result)); return ReturnCleanup(MasterServerReportPresenceResult::FailedNoConnect); } }); @@ -1434,7 +1480,7 @@ void MasterServerPresenceReporter::InternalUpdateServer(const ServerPresence* pS } else { - spdlog::warn("Heartbeat failed with error {}", curl_easy_strerror(result)); + Warning(eLog::MS, "Heartbeat failed with error %s\n", curl_easy_strerror(result)); return ReturnCleanup(MasterServerReportPresenceResult::Failed); } }); diff --git a/NorthstarDLL/mods/compiled/kb_act.cpp b/NorthstarDLL/mods/compiled/kb_act.cpp index 3fc7ee309..fe57ed4ef 100644 --- a/NorthstarDLL/mods/compiled/kb_act.cpp +++ b/NorthstarDLL/mods/compiled/kb_act.cpp @@ -8,7 +8,7 @@ const char* KB_ACT_PATH = "scripts\\kb_act.lst"; // compiles the file kb_act.lst, that defines entries for keybindings in the options menu void ModManager::BuildKBActionsList() { - spdlog::info("Building kb_act.lst"); + DevMsg(eLog::MODSYS, "Building kb_act.lst\n"); fs::create_directories(GetCompiledAssetsPath() / "scripts"); std::ofstream soCompiledKeys(GetCompiledAssetsPath() / KB_ACT_PATH, std::ios::binary); diff --git a/NorthstarDLL/mods/compiled/modkeyvalues.cpp b/NorthstarDLL/mods/compiled/modkeyvalues.cpp index fe262a607..f3c104576 100644 --- a/NorthstarDLL/mods/compiled/modkeyvalues.cpp +++ b/NorthstarDLL/mods/compiled/modkeyvalues.cpp @@ -7,7 +7,7 @@ AUTOHOOK_INIT() void ModManager::TryBuildKeyValues(const char* filename) { - spdlog::info("Building KeyValues for file {}", filename); + DevMsg(eLog::MODSYS, "Building KeyValues for file %s\n", filename); std::string normalisedPath = g_pModManager->NormaliseModFilePath(fs::path(filename)); fs::path compiledPath = GetCompiledAssetsPath() / filename; @@ -60,7 +60,7 @@ void ModManager::TryBuildKeyValues(const char* filename) if (!originalFile.length()) { - spdlog::warn("Tried to patch kv {} but no base kv was found!", ogFilePath); + Warning(eLog::MODSYS, "Tried to patch kv %s but no base kv was found!\n", ogFilePath.c_str()); return; } diff --git a/NorthstarDLL/mods/compiled/modpdef.cpp b/NorthstarDLL/mods/compiled/modpdef.cpp index 4b1b12b76..9d880de8d 100644 --- a/NorthstarDLL/mods/compiled/modpdef.cpp +++ b/NorthstarDLL/mods/compiled/modpdef.cpp @@ -10,7 +10,7 @@ const char* VPK_PDEF_PATH = "cfg/server/persistent_player_data_version_231.pdef" void ModManager::BuildPdef() { - spdlog::info("Building persistent_player_data_version_231.pdef..."); + DevMsg(eLog::MODSYS, "Building persistent_player_data_version_231.pdef...\n"); fs::path MOD_PDEF_PATH = fs::path(GetCompiledAssetsPath() / MOD_PDEF_SUFFIX); diff --git a/NorthstarDLL/mods/compiled/modscriptsrson.cpp b/NorthstarDLL/mods/compiled/modscriptsrson.cpp index cbe266514..2b2b0f092 100644 --- a/NorthstarDLL/mods/compiled/modscriptsrson.cpp +++ b/NorthstarDLL/mods/compiled/modscriptsrson.cpp @@ -9,7 +9,7 @@ const char* VPK_SCRIPTS_RSON_PATH = "scripts\\vscripts\\scripts.rson"; void ModManager::BuildScriptsRson() { - spdlog::info("Building custom scripts.rson"); + DevMsg(eLog::MODSYS, "Building custom scripts.rson\n"); fs::path MOD_SCRIPTS_RSON_PATH = fs::path(GetCompiledAssetsPath() / MOD_SCRIPTS_RSON_SUFFIX); fs::remove(MOD_SCRIPTS_RSON_PATH); diff --git a/NorthstarDLL/mods/modmanager.cpp b/NorthstarDLL/mods/modmanager.cpp index 8ad832c1d..282e2440d 100644 --- a/NorthstarDLL/mods/modmanager.cpp +++ b/NorthstarDLL/mods/modmanager.cpp @@ -6,6 +6,7 @@ #include "core/filesystem/filesystem.h" #include "core/filesystem/rpakfilesystem.h" #include "config/profile.h" +#include "squirrel/squirrel.h" #include "rapidjson/error/en.h" #include "rapidjson/document.h" @@ -29,14 +30,16 @@ Mod::Mod(fs::path modDir, char* jsonBuf) rapidjson_document modJson; modJson.Parse(jsonBuf); - spdlog::info("Loading mod file at path '{}'", modDir.string()); + DevMsg(eLog::MODSYS, "Loading mod file at path '%s'\n", modDir.string().c_str()); // fail if parse error if (modJson.HasParseError()) { - spdlog::error( - "Failed reading mod file {}: encountered parse error \"{}\" at offset {}", - (modDir / "mod.json").string(), + Error( + eLog::MODSYS, + NO_ERROR, + "Failed reading mod file %s: encountered parse error \"%s\" at offset %li\n", + (modDir / "mod.json").string().c_str(), GetParseError_En(modJson.GetParseError()), modJson.GetErrorOffset()); return; @@ -45,7 +48,7 @@ Mod::Mod(fs::path modDir, char* jsonBuf) // fail if it's not a json obj (could be an array, string, etc) if (!modJson.IsObject()) { - spdlog::error("Failed reading mod file {}: file is not a JSON object", (modDir / "mod.json").string()); + Error(eLog::MODSYS, NO_ERROR, "Failed reading mod file %s: file is not a JSON object\n", (modDir / "mod.json").string().c_str()); return; } @@ -53,17 +56,21 @@ Mod::Mod(fs::path modDir, char* jsonBuf) // name is required if (!modJson.HasMember("Name")) { - spdlog::error("Failed reading mod file {}: missing required member \"Name\"", (modDir / "mod.json").string()); + Error( + eLog::MODSYS, + NO_ERROR, + "Failed reading mod file %s: missing required member \"Name\"\n", + (modDir / "mod.json").string().c_str()); return; } Name = modJson["Name"].GetString(); - spdlog::info("Loading mod '{}'", Name); + Warning(eLog::MODSYS, "Loading mod '%s'\n", Name.c_str()); // Don't load blacklisted mods if (!strstr(GetCommandLineA(), "-nomodblacklist") && MODS_BLACKLIST.find(Name) != std::end(MODS_BLACKLIST)) { - spdlog::warn("Skipping blacklisted mod \"{}\"!", Name); + Warning(eLog::MODSYS, "Skipping blacklisted mod \"%s\"!\n", Name.c_str()); return; } @@ -77,7 +84,7 @@ Mod::Mod(fs::path modDir, char* jsonBuf) else { Version = "0.0.0"; - spdlog::warn("Mod file {} is missing a version, consider adding a version", (modDir / "mod.json").string()); + Warning(eLog::MS, "Mod file %s is missing a version, consider adding a version\n", (modDir / "mod.json").string().c_str()); } if (modJson.HasMember("DownloadLink")) @@ -94,7 +101,7 @@ Mod::Mod(fs::path modDir, char* jsonBuf) LoadPriority = modJson["LoadPriority"].GetInt(); else { - spdlog::info("Mod file {} is missing a LoadPriority, consider adding one", (modDir / "mod.json").string()); + Warning(eLog::MS, "Mod file %s is missing a LoadPriority, consider adding one\n", (modDir / "mod.json").string().c_str()); LoadPriority = 0; } @@ -119,7 +126,7 @@ void Mod::ParseConVars(rapidjson_document& json) if (!json["ConVars"].IsArray()) { - spdlog::warn("'ConVars' field is not an array, skipping..."); + Warning(eLog::MODSYS, "'ConVars' field is not an array, skipping...\n"); return; } @@ -127,18 +134,18 @@ void Mod::ParseConVars(rapidjson_document& json) { if (!convarObj.IsObject()) { - spdlog::warn("ConVar is not an object, skipping..."); + Warning(eLog::MODSYS, "ConVar is not an object, skipping...\n"); continue; } if (!convarObj.HasMember("Name")) { - spdlog::warn("ConVar does not have a Name, skipping..."); + Warning(eLog::MODSYS, "ConVar does not have a Name, skipping...\n"); continue; } // from here on, the ConVar can be referenced by name in logs if (!convarObj.HasMember("DefaultValue")) { - spdlog::warn("ConVar '{}' does not have a DefaultValue, skipping...", convarObj["Name"].GetString()); + Warning(eLog::MODSYS, "ConVar '%s' does not have a DefaultValue, skipping...\n", convarObj["Name"].GetString()); continue; } @@ -170,7 +177,7 @@ void Mod::ParseConVars(rapidjson_document& json) ConVars.push_back(convar); - spdlog::info("'{}' contains ConVar '{}'", Name, convar->Name); + DevMsg(eLog::MODSYS, "'%s' contains ConVar '%s'\n", Name.c_str(), convar->Name.c_str()); } } @@ -181,7 +188,7 @@ void Mod::ParseConCommands(rapidjson_document& json) if (!json["ConCommands"].IsArray()) { - spdlog::warn("'ConCommands' field is not an array, skipping..."); + Warning(eLog::MODSYS, "'ConCommands' field is not an array, skipping...\n"); return; } @@ -189,23 +196,23 @@ void Mod::ParseConCommands(rapidjson_document& json) { if (!concommandObj.IsObject()) { - spdlog::warn("ConCommand is not an object, skipping..."); + Warning(eLog::MODSYS, "ConCommand is not an object, skipping...\n"); continue; } if (!concommandObj.HasMember("Name")) { - spdlog::warn("ConCommand does not have a Name, skipping..."); + Warning(eLog::MODSYS, "ConCommand does not have a Name, skipping...\n"); continue; } // from here on, the ConCommand can be referenced by name in logs if (!concommandObj.HasMember("Function")) { - spdlog::warn("ConCommand '{}' does not have a Function, skipping...", concommandObj["Name"].GetString()); + Warning(eLog::MODSYS, "ConCommand '{}' does not have a Function, skipping...\n", concommandObj["Name"].GetString()); continue; } if (!concommandObj.HasMember("Context")) { - spdlog::warn("ConCommand '{}' does not have a Context, skipping...", concommandObj["Name"].GetString()); + Warning(eLog::MODSYS, "ConCommand '{}' does not have a Context, skipping...\n", concommandObj["Name"].GetString()); continue; } @@ -217,7 +224,8 @@ void Mod::ParseConCommands(rapidjson_document& json) concommand->Context = ScriptContextFromString(concommandObj["Context"].GetString()); if (concommand->Context == ScriptContext::INVALID) { - spdlog::warn("ConCommand '{}' has invalid context '{}', skipping...", concommand->Name, concommandObj["Context"].GetString()); + Warning( + eLog::MODSYS, "Mod ConCommand %s has invalid context %s\n", concommand->Name.c_str(), concommandObj["Context"].GetString()); continue; } @@ -245,7 +253,7 @@ void Mod::ParseConCommands(rapidjson_document& json) ConCommands.push_back(concommand); - spdlog::info("'{}' contains ConCommand '{}'", Name, concommand->Name); + DevMsg(eLog::MODSYS, "'%s' contains ConCommand '%s'\n", Name.c_str(), concommand->Name.c_str()); } } @@ -256,7 +264,7 @@ void Mod::ParseScripts(rapidjson_document& json) if (!json["Scripts"].IsArray()) { - spdlog::warn("'Scripts' field is not an array, skipping..."); + Warning(eLog::MODSYS, "'Scripts' field is not an array, skipping...\n"); return; } @@ -264,12 +272,12 @@ void Mod::ParseScripts(rapidjson_document& json) { if (!scriptObj.IsObject()) { - spdlog::warn("Script is not an object, skipping..."); + Warning(eLog::MODSYS, "Script is not an object, skipping...\n"); continue; } if (!scriptObj.HasMember("Path")) { - spdlog::warn("Script does not have a Path, skipping..."); + Warning(eLog::MODSYS, "Script does not have a Path, skipping...\n"); continue; } // from here on, the Path for a script is used as it's name in logs @@ -277,7 +285,7 @@ void Mod::ParseScripts(rapidjson_document& json) { // "a RunOn" sounds dumb but anything else doesn't match the format of the warnings... // this is the best i could think of within 20 seconds - spdlog::warn("Script '{}' does not have a RunOn field, skipping...", scriptObj["Path"].GetString()); + Warning(eLog::MODSYS, "Script '%s' does not have a RunOn field, skipping...\n", scriptObj["Path"].GetString()); continue; } @@ -298,7 +306,10 @@ void Mod::ParseScripts(rapidjson_document& json) if (scriptObj["ServerCallback"]["Before"].IsString()) callback.BeforeCallback = scriptObj["ServerCallback"]["Before"].GetString(); else - spdlog::warn("'Before' ServerCallback for script '{}' is not a string, skipping...", scriptObj["Path"].GetString()); + Warning( + eLog::MODSYS, + "'Before' ServerCallback for script '%s' is not a string, skipping...\n", + scriptObj["Path"].GetString()); } if (scriptObj["ServerCallback"].HasMember("After")) @@ -306,7 +317,10 @@ void Mod::ParseScripts(rapidjson_document& json) if (scriptObj["ServerCallback"]["After"].IsString()) callback.AfterCallback = scriptObj["ServerCallback"]["After"].GetString(); else - spdlog::warn("'After' ServerCallback for script '{}' is not a string, skipping...", scriptObj["Path"].GetString()); + Warning( + eLog::MODSYS, + "'After' ServerCallback for script '%s' is not a string, skipping...\n", + scriptObj["Path"].GetString()); } if (scriptObj["ServerCallback"].HasMember("Destroy")) @@ -314,15 +328,17 @@ void Mod::ParseScripts(rapidjson_document& json) if (scriptObj["ServerCallback"]["Destroy"].IsString()) callback.DestroyCallback = scriptObj["ServerCallback"]["Destroy"].GetString(); else - spdlog::warn( - "'Destroy' ServerCallback for script '{}' is not a string, skipping...", scriptObj["Path"].GetString()); + Warning( + eLog::MODSYS, + "'Destroy' ServerCallback for script '%s' is not a string, skipping...\n", + scriptObj["Path"].GetString()); } script.Callbacks.push_back(callback); } else { - spdlog::warn("ServerCallback for script '{}' is not an object, skipping...", scriptObj["Path"].GetString()); + Warning(eLog::MODSYS, "ServerCallback for script '%s' is not an object, skipping...\n", scriptObj["Path"].GetString()); } } @@ -338,7 +354,10 @@ void Mod::ParseScripts(rapidjson_document& json) if (scriptObj["ClientCallback"]["Before"].IsString()) callback.BeforeCallback = scriptObj["ClientCallback"]["Before"].GetString(); else - spdlog::warn("'Before' ClientCallback for script '{}' is not a string, skipping...", scriptObj["Path"].GetString()); + Warning( + eLog::MODSYS, + "'Before' ClientCallback for script '%s' is not a string, skipping...\n", + scriptObj["Path"].GetString()); } if (scriptObj["ClientCallback"].HasMember("After")) @@ -346,7 +365,10 @@ void Mod::ParseScripts(rapidjson_document& json) if (scriptObj["ClientCallback"]["After"].IsString()) callback.AfterCallback = scriptObj["ClientCallback"]["After"].GetString(); else - spdlog::warn("'After' ClientCallback for script '{}' is not a string, skipping...", scriptObj["Path"].GetString()); + Warning( + eLog::MODSYS, + "'After' ClientCallback for script '%s' is not a string, skipping...\n", + scriptObj["Path"].GetString()); } if (scriptObj["ClientCallback"].HasMember("Destroy")) @@ -354,15 +376,17 @@ void Mod::ParseScripts(rapidjson_document& json) if (scriptObj["ClientCallback"]["Destroy"].IsString()) callback.DestroyCallback = scriptObj["ClientCallback"]["Destroy"].GetString(); else - spdlog::warn( - "'Destroy' ClientCallback for script '{}' is not a string, skipping...", scriptObj["Path"].GetString()); + Warning( + eLog::MODSYS, + "'Destroy' ClientCallback for script '%s' is not a string, skipping...\n", + scriptObj["Path"].GetString()); } script.Callbacks.push_back(callback); } else { - spdlog::warn("ClientCallback for script '{}' is not an object, skipping...", scriptObj["Path"].GetString()); + Warning(eLog::MODSYS, "ClientCallback for script '%s' is not an object, skipping...\n", scriptObj["Path"].GetString()); } } @@ -378,7 +402,10 @@ void Mod::ParseScripts(rapidjson_document& json) if (scriptObj["UICallback"]["Before"].IsString()) callback.BeforeCallback = scriptObj["UICallback"]["Before"].GetString(); else - spdlog::warn("'Before' UICallback for script '{}' is not a string, skipping...", scriptObj["Path"].GetString()); + Warning( + eLog::MODSYS, + "'Before' UICallback for script '%s' is not a string, skipping...\n", + scriptObj["Path"].GetString()); } if (scriptObj["UICallback"].HasMember("After")) @@ -386,7 +413,10 @@ void Mod::ParseScripts(rapidjson_document& json) if (scriptObj["UICallback"]["After"].IsString()) callback.AfterCallback = scriptObj["UICallback"]["After"].GetString(); else - spdlog::warn("'After' UICallback for script '{}' is not a string, skipping...", scriptObj["Path"].GetString()); + Warning( + eLog::MODSYS, + "'After' UICallback for script '%s' is not a string, skipping...\n", + scriptObj["Path"].GetString()); } if (scriptObj["UICallback"].HasMember("Destroy")) @@ -394,20 +424,23 @@ void Mod::ParseScripts(rapidjson_document& json) if (scriptObj["UICallback"]["Destroy"].IsString()) callback.DestroyCallback = scriptObj["UICallback"]["Destroy"].GetString(); else - spdlog::warn("'Destroy' UICallback for script '{}' is not a string, skipping...", scriptObj["Path"].GetString()); + Warning( + eLog::MODSYS, + "'Destroy' UICallback for script '%s' is not a string, skipping...\n", + scriptObj["Path"].GetString()); } script.Callbacks.push_back(callback); } else { - spdlog::warn("UICallback for script '{}' is not an object, skipping...", scriptObj["Path"].GetString()); + Warning(eLog::MODSYS, "UICallback for script '%s' is not an object, skipping...\n", scriptObj["Path"].GetString()); } } Scripts.push_back(script); - spdlog::info("'{}' contains Script '{}'", Name, script.Path); + DevMsg(eLog::MODSYS, "'%s' contains Script '%s'\n", Name.c_str(), script.Path.c_str()); } } @@ -418,7 +451,7 @@ void Mod::ParseLocalization(rapidjson_document& json) if (!json["Localisation"].IsArray()) { - spdlog::warn("'Localisation' field is not an array, skipping..."); + Warning(eLog::MODSYS, "'Localisation' field is not an array, skipping...\n"); return; } @@ -427,13 +460,13 @@ void Mod::ParseLocalization(rapidjson_document& json) if (!localisationStr.IsString()) { // not a string but we still GetString() to log it :trol: - spdlog::warn("Localisation '{}' is not a string, skipping...", localisationStr.GetString()); + Warning(eLog::MODSYS, "Localisation '%s' is not a string, skipping...\n", localisationStr.GetString()); continue; } LocalisationFiles.push_back(localisationStr.GetString()); - spdlog::info("'{}' registered Localisation '{}'", Name, localisationStr.GetString()); + DevMsg(eLog::MODSYS, "'%s' registered Localisation '%s'\n", Name.c_str(), localisationStr.GetString()); } } @@ -444,7 +477,7 @@ void Mod::ParseDependencies(rapidjson_document& json) if (!json["Dependencies"].IsObject()) { - spdlog::warn("'Dependencies' field is not an object, skipping..."); + Warning(eLog::MODSYS, "'Dependencies' field is not an object, skipping...\n"); return; } @@ -452,12 +485,12 @@ void Mod::ParseDependencies(rapidjson_document& json) { if (!v->name.IsString()) { - spdlog::warn("Dependency constant '{}' is not a string, skipping...", v->name.GetString()); + Warning(eLog::MODSYS, "Dependency constant '%s' is not a string, skipping...\n", v->name.GetString()); continue; } if (!v->value.IsString()) { - spdlog::warn("Dependency constant '{}' is not a string, skipping...", v->value.GetString()); + Warning(eLog::MODSYS, "Dependency constant '%s' is not a string, skipping...\n", v->value.GetString()); continue; } @@ -466,20 +499,27 @@ void Mod::ParseDependencies(rapidjson_document& json) { // this is fatal because otherwise the mod will probably try to use functions that dont exist, // which will cause errors further down the line that are harder to debug - spdlog::error( - "'{}' attempted to register a dependency constant '{}' for '{}' that already exists for '{}'. " - "Change the constant name.", - Name, + Error( + eLog::MODSYS, + NO_ERROR, + "'%s' attempted to register a dependency constant '%s' for '%s' that already exists for '%s'. " + "Change the constant name.\n", + Name.c_str(), v->name.GetString(), v->value.GetString(), - DependencyConstants[v->name.GetString()]); + DependencyConstants[v->name.GetString()].c_str()); return; } if (DependencyConstants.find(v->name.GetString()) == DependencyConstants.end()) DependencyConstants.emplace(v->name.GetString(), v->value.GetString()); - spdlog::info("'{}' registered dependency constant '{}' for mod '{}'", Name, v->name.GetString(), v->value.GetString()); + DevMsg( + eLog::MODSYS, + "'%s' registered dependency constant '%s' for mod '%s'\n", + Name.c_str(), + v->name.GetString(), + v->value.GetString()); } } @@ -490,7 +530,7 @@ void Mod::ParseInitScript(rapidjson_document& json) if (!json["InitScript"].IsString()) { - spdlog::warn("'InitScript' field is not a string, skipping..."); + Warning(eLog::MODSYS, "'InitScript' field is not a string, skipping...\n"); return; } @@ -535,7 +575,11 @@ template auto ModConCommandCallback_Internal(std::string } else { - spdlog::warn("ConCommand `{}` was called while the associated Squirrel VM `{}` was unloaded", name, GetContextName(context)); + Warning( + eLog::MODSYS, + "ConCommand `%s` was called while the associated Squirrel VM `%s` was unloaded\n", + name.c_str(), + GetContextName(context)); } } @@ -658,8 +702,10 @@ void ModManager::LoadMods() // fail if no mod json if (jsonStream.fail()) { - spdlog::warn( - "Mod file at '{}' does not exist or could not be read, is it installed correctly?", (modDir / "mod.json").string()); + Warning( + eLog::MODSYS, + "Mod file at '%s' does not exist or could not be read, is it installed correctly?\n", + (modDir / "mod.json").string().c_str()); continue; } @@ -674,13 +720,15 @@ void ModManager::LoadMods() { if (m_DependencyConstants.find(pair.first) != m_DependencyConstants.end() && m_DependencyConstants[pair.first] != pair.second) { - spdlog::error( - "'{}' attempted to register a dependency constant '{}' for '{}' that already exists for '{}'. " - "Change the constant name.", - mod.Name, - pair.first, - pair.second, - m_DependencyConstants[pair.first]); + Error( + eLog::MODSYS, + NO_ERROR, + "'%s' attempted to register a dependency constant '%s' for '%s' that already exists for '%s'. " + "Change the constant name.\n", + mod.Name.c_str(), + pair.first.c_str(), + pair.second.c_str(), + m_DependencyConstants[pair.first].c_str()); mod.m_bWasReadSuccessfully = false; break; } @@ -696,14 +744,14 @@ void ModManager::LoadMods() if (mod.m_bWasReadSuccessfully) { if (mod.m_bEnabled) - spdlog::info("'{}' loaded successfully", mod.Name); + DevMsg(eLog::MODSYS, "'%s' loaded successfully\n", mod.Name.c_str()); else - spdlog::info("'{}' loaded successfully (DISABLED)", mod.Name); + DevMsg(eLog::MODSYS, "'%s' loaded successfully (DISABLED)\n", mod.Name.c_str()); m_LoadedMods.push_back(mod); } else - spdlog::warn("Mod file at '{}' failed to load", (modDir / "mod.json").string()); + Warning(eLog::MODSYS, "Mod file at '%s' failed to load\n", (modDir / "mod.json").string().c_str()); } // sort by load prio, lowest-highest @@ -884,7 +932,7 @@ void ModManager::LoadMods() if (!str.empty()) { mod.StarpakPaths.push_back(STR_HASH(str)); - spdlog::info("Mod {} registered starpak '{}'", mod.Name, str); + DevMsg(eLog::MODSYS, "Mod %s registered starpak '%s'\n", mod.Name.c_str(), str.c_str()); str = ""; } } @@ -945,7 +993,11 @@ void ModManager::LoadMods() { if (!g_CustomAudioManager.TryLoadAudioOverride(file.path())) { - spdlog::warn("Mod {} has an invalid audio def {}", mod.Name, file.path().filename().string()); + Warning( + eLog::MODSYS, + "Mod %s has an invalid audio def %s\n", + mod.Name.c_str(), + file.path().filename().string().c_str()); continue; } } diff --git a/NorthstarDLL/mods/modmanager.h b/NorthstarDLL/mods/modmanager.h index 813edec79..44642f577 100644 --- a/NorthstarDLL/mods/modmanager.h +++ b/NorthstarDLL/mods/modmanager.h @@ -1,7 +1,7 @@ #pragma once #include "core/convar/convar.h" #include "core/memalloc.h" -#include "squirrel/squirrel.h" +#include "squirrel/squirrelclasstypes.h" #include "rapidjson/document.h" #include diff --git a/NorthstarDLL/pch.h b/NorthstarDLL/pch.h index b9ba0e082..1b249ec3a 100644 --- a/NorthstarDLL/pch.h +++ b/NorthstarDLL/pch.h @@ -34,10 +34,13 @@ typedef void (*callable_v)(void* v); #include "core/structs.h" #include "core/math/color.h" +#include "logging/dbg.h" + #include "spdlog/spdlog.h" #include "logging/logging.h" #include "MinHook.h" #include "curl/curl.h" + #include "core/hooks.h" #include "core/memory.h" diff --git a/NorthstarDLL/plugins/pluginbackend.cpp b/NorthstarDLL/plugins/pluginbackend.cpp index 850394acf..1458229f8 100644 --- a/NorthstarDLL/plugins/pluginbackend.cpp +++ b/NorthstarDLL/plugins/pluginbackend.cpp @@ -26,7 +26,12 @@ void PluginCommunicationHandler::RunFrame() switch (storedRequest.type) { default: - spdlog::error("{} was called with invalid request type '{}'", __FUNCTION__, static_cast(storedRequest.type)); + Error( + eLog::PLUGSYS, + NO_ERROR, + "'%s' was called with invalid request type %i\n", + __FUNCTION__, + static_cast(storedRequest.type)); } requestQueue.pop(); } diff --git a/NorthstarDLL/plugins/plugins.cpp b/NorthstarDLL/plugins/plugins.cpp index 121512e56..84f33eced 100644 --- a/NorthstarDLL/plugins/plugins.cpp +++ b/NorthstarDLL/plugins/plugins.cpp @@ -21,18 +21,41 @@ void freeLibrary(HMODULE hLib) { if (!FreeLibrary(hLib)) { - spdlog::error("There was an error while trying to free library"); + Error(eLog::PLUGSYS, NO_ERROR, "There was an error while trying to free library\n"); } } EXPORT void PLUGIN_LOG(LogMsg* msg) { - spdlog::source_loc src {}; - src.filename = msg->source.file; - src.funcname = msg->source.func; - src.line = msg->source.line; - auto&& logger = g_pPluginManager->m_vLoadedPlugins[msg->pluginHandle].logger; - logger->log(src, (spdlog::level::level_enum)msg->level, msg->msg); + eLogLevel eLevel = eLogLevel::LOG_INFO; + + switch (msg->level) + { + case spdlog::level::level_enum::debug: + case spdlog::level::level_enum::info: + eLevel = eLogLevel::LOG_INFO; + break; + case spdlog::level::level_enum::off: + case spdlog::level::level_enum::trace: + case spdlog::level::level_enum::warn: + eLevel = eLogLevel::LOG_WARN; + break; + case spdlog::level::level_enum::critical: + case spdlog::level::level_enum::err: + eLevel = eLogLevel::LOG_ERROR; + break; + } + + int hPlugin = msg->pluginHandle; + if (hPlugin < g_pPluginManager->m_vLoadedPlugins.size() && hPlugin >= 0) + { + const char* pszName = g_pPluginManager->m_vLoadedPlugins[hPlugin].displayName.c_str(); + PluginMsg(eLevel, pszName, "%s\n", msg->msg); + } + else + { + DevMsg(eLog::PLUGSYS, "Invalid plugin handle: %i\n", hPlugin); + } } EXPORT void* CreateObject(ObjectType type) @@ -60,21 +83,26 @@ std::optional PluginManager::LoadPlugin(fs::path path, PluginInitFuncs* HMODULE datafile = LoadLibraryExW(wpptr, 0, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); // Load the DLL as a data file if (datafile == NULL) { - NS::log::PLUGINSYS->info("Failed to load library '{}': ", std::system_category().message(GetLastError())); + Error( + eLog::PLUGSYS, + NO_ERROR, + "Failed to load library '%s': %s\n", + pathstring.c_str(), + std::system_category().message(GetLastError()).c_str()); return std::nullopt; } HRSRC manifestResource = FindResourceW(datafile, MAKEINTRESOURCEW(IDR_RCDATA1), RT_RCDATA); if (manifestResource == NULL) { - NS::log::PLUGINSYS->info("Could not find manifest for library '{}'", pathstring); + Error(eLog::PLUGSYS, NO_ERROR, "Could not find manifest for library '%s'\n", pathstring.c_str()); freeLibrary(datafile); return std::nullopt; } HGLOBAL myResourceData = LoadResource(datafile, manifestResource); if (myResourceData == NULL) { - NS::log::PLUGINSYS->error("Failed to load manifest from library '{}'", pathstring); + Error(eLog::PLUGSYS, NO_ERROR, "Failed to load manifest from library '%s'\n", pathstring.c_str()); freeLibrary(datafile); return std::nullopt; } @@ -87,49 +115,54 @@ std::optional PluginManager::LoadPlugin(fs::path path, PluginInitFuncs* if (manifestJSON.HasParseError()) { - NS::log::PLUGINSYS->error("Manifest for '{}' was invalid", pathstring); + Error(eLog::PLUGSYS, NO_ERROR, "Manifest for '%s' was invalid\n", pathstring.c_str()); return std::nullopt; } if (!manifestJSON.HasMember("name")) { - NS::log::PLUGINSYS->error("'{}' is missing a name in its manifest", pathstring); + Error(eLog::PLUGSYS, NO_ERROR, "'%s' is missing a name in its manifest\n", pathstring.c_str()); return std::nullopt; } if (!manifestJSON.HasMember("displayname")) { - NS::log::PLUGINSYS->error("'{}' is missing a displayname in its manifest", pathstring); + Error(eLog::PLUGSYS, NO_ERROR, "'%s' is missing a displayname in its manifest\n", pathstring.c_str()); return std::nullopt; } if (!manifestJSON.HasMember("description")) { - NS::log::PLUGINSYS->error("'{}' is missing a description in its manifest", pathstring); + Error(eLog::PLUGSYS, NO_ERROR, "'%s' is missing a description in its manifest\n", pathstring.c_str()); return std::nullopt; } if (!manifestJSON.HasMember("api_version")) { - NS::log::PLUGINSYS->error("'{}' is missing a api_version in its manifest", pathstring); + Error(eLog::PLUGSYS, NO_ERROR, "'%s' is missing a api_version in its manifest\n", pathstring.c_str()); return std::nullopt; } if (!manifestJSON.HasMember("version")) { - NS::log::PLUGINSYS->error("'{}' is missing a version in its manifest", pathstring); + Error(eLog::PLUGSYS, NO_ERROR, "'%s' is missing a version in its manifest\n", pathstring.c_str()); return std::nullopt; } if (!manifestJSON.HasMember("run_on_server")) { - NS::log::PLUGINSYS->error("'{}' is missing 'run_on_server' in its manifest", pathstring); + Error(eLog::PLUGSYS, NO_ERROR, "'%s' is missing 'run_on_server' in its manifest\n", pathstring.c_str()); return std::nullopt; } if (!manifestJSON.HasMember("run_on_client")) { - NS::log::PLUGINSYS->error("'{}' is missing 'run_on_client' in its manifest", pathstring); + Error(eLog::PLUGSYS, NO_ERROR, "'%s' is missing 'run_on_client' in its manifest\n", pathstring.c_str()); return std::nullopt; } auto test = manifestJSON["api_version"].GetString(); if (strcmp(manifestJSON["api_version"].GetString(), std::to_string(ABI_VERSION).c_str())) { - NS::log::PLUGINSYS->error( - "'{}' has an incompatible API version number in its manifest. Current ABI version is '{}'", pathstring, ABI_VERSION); + Error( + eLog::PLUGSYS, + NO_ERROR, + "'%s' has an incompatible API version number '%s' in its manifest. Current ABI version is '%i'\n", + pathstring.c_str(), + manifestJSON["api_version"].GetString(), + ABI_VERSION); return std::nullopt; } // Passed all checks, going to actually load it now @@ -137,16 +170,21 @@ std::optional PluginManager::LoadPlugin(fs::path path, PluginInitFuncs* HMODULE pluginLib = LoadLibraryW(wpptr); // Load the DLL as a data file if (pluginLib == NULL) { - NS::log::PLUGINSYS->info("Failed to load library '{}': ", std::system_category().message(GetLastError())); + Error( + eLog::PLUGSYS, + NO_ERROR, + "Failed to load library '%s': %s\n", + pathstring.c_str(), + std::system_category().message(GetLastError()).c_str()); return std::nullopt; } plugin.init = (PLUGIN_INIT_TYPE)GetProcAddress(pluginLib, "PLUGIN_INIT"); if (plugin.init == NULL) { - NS::log::PLUGINSYS->info("Library '{}' has no function 'PLUGIN_INIT'", pathstring); + Error(eLog::PLUGSYS, NO_ERROR, "Library '%s' has no function 'PLUGIN_INIT'\n", pathstring.c_str()); return std::nullopt; } - NS::log::PLUGINSYS->info("Succesfully loaded {}", pathstring); + DevMsg(eLog::PLUGSYS, "Succesfully loaded %s\n", pathstring.c_str()); plugin.name = manifestJSON["name"].GetString(); plugin.displayName = manifestJSON["displayname"].GetString(); @@ -179,9 +217,7 @@ std::optional PluginManager::LoadPlugin(fs::path path, PluginInitFuncs* plugin.run_frame = (PLUGIN_RUNFRAME)GetProcAddress(pluginLib, "PLUGIN_RUNFRAME"); plugin.handle = m_vLoadedPlugins.size(); - plugin.logger = std::make_shared(plugin.displayName.c_str(), NS::Colors::PLUGIN); - RegisterLogger(plugin.logger); - NS::log::PLUGINSYS->info("Loading plugin {} version {}", plugin.displayName, plugin.version); + DevMsg(eLog::PLUGSYS, "Loading plugin %s version %s\n", plugin.displayName.c_str(), plugin.version.c_str()); m_vLoadedPlugins.push_back(plugin); plugin.init(funcs, data); @@ -208,7 +244,7 @@ bool PluginManager::LoadPlugins() { if (strstr(GetCommandLineA(), "-noplugins") != NULL) { - NS::log::PLUGINSYS->warn("-noplugins detected; skipping loading plugins"); + Warning(eLog::PLUGSYS, "-noplugins detected; skipping loading plugins\n"); return false; } @@ -249,7 +285,7 @@ bool PluginManager::LoadPlugins() if (paths.empty()) { - NS::log::PLUGINSYS->warn("Could not find any plugins. Skipped loading plugins"); + Warning(eLog::PLUGSYS, "Could not find any plugins. Skipped loading plugins\n"); return false; } diff --git a/NorthstarDLL/plugins/plugins.h b/NorthstarDLL/plugins/plugins.h index d91b28113..01c750da7 100644 --- a/NorthstarDLL/plugins/plugins.h +++ b/NorthstarDLL/plugins/plugins.h @@ -18,8 +18,6 @@ class Plugin // Maybe a bit shit but it works int handle; - std::shared_ptr logger; - bool run_on_client = false; bool run_on_server = false; diff --git a/NorthstarDLL/scripts/scriptdatatables.cpp b/NorthstarDLL/scripts/scriptdatatables.cpp index 532624f39..b55d599a9 100644 --- a/NorthstarDLL/scripts/scriptdatatables.cpp +++ b/NorthstarDLL/scripts/scriptdatatables.cpp @@ -623,7 +623,7 @@ REPLACE_SQFUNC(GetDataTableRowGreaterThanOrEqualToIntValue, (ScriptContext::UI | { if (nIntVal >= std::stoi(csv->dataPointers[i][nCol])) { - spdlog::info("datatable not loaded"); + Warning(eLog::NS, "datatable not loaded\n"); g_pSquirrel->pushinteger(sqvm, 1); return SQRESULT_NOTNULL; } @@ -789,7 +789,7 @@ void DumpDatatable(const char* pDatatablePath) Datatable* pDatatable = (Datatable*)g_pPakLoadManager->LoadFile(pDatatablePath); if (!pDatatable) { - spdlog::error("couldn't load datatable {} (rpak containing it may not be loaded?)", pDatatablePath); + Error(eLog::NS, NO_ERROR, "couldn't load datatable {} (rpak containing it may not be loaded?)\n", pDatatablePath); return; } @@ -801,14 +801,14 @@ void DumpDatatable(const char* pDatatablePath) outputStream.write(sDatatableContents.c_str(), sDatatableContents.size()); outputStream.close(); - spdlog::info("dumped datatable {} {} to {}", pDatatablePath, (void*)pDatatable, sOutputPath); + DevMsg(eLog::NS, "dumped datatable %s %p to %s\n", pDatatablePath, (void*)pDatatable, sOutputPath.c_str()); } void ConCommand_dump_datatable(const CCommand& args) { if (args.ArgC() < 2) { - spdlog::info("usage: dump_datatable datatable/tablename.rpak"); + DevMsg(eLog::NS, "usage: dump_datatable datatable/tablename.rpak\n"); return; } diff --git a/NorthstarDLL/scripts/scripthttprequesthandler.cpp b/NorthstarDLL/scripts/scripthttprequesthandler.cpp index 813bd50e8..da2f97eee 100644 --- a/NorthstarDLL/scripts/scripthttprequesthandler.cpp +++ b/NorthstarDLL/scripts/scripthttprequesthandler.cpp @@ -35,24 +35,24 @@ void HttpRequestHandler::StartHttpRequestHandler() { if (IsRunning()) { - spdlog::warn("%s was called while IsRunning() is true!", __FUNCTION__); + Warning(eLog::NS, "%s was called while IsRunning() is true!\n", __FUNCTION__); return; } m_bIsHttpRequestHandlerRunning = true; - spdlog::info("HttpRequestHandler started."); + DevMsg(eLog::NS, "HttpRequestHandler started.\n"); } void HttpRequestHandler::StopHttpRequestHandler() { if (!IsRunning()) { - spdlog::warn("%s was called while IsRunning() is false", __FUNCTION__); + Warning(eLog::NS, "%s was called while IsRunning() is false\n", __FUNCTION__); return; } m_bIsHttpRequestHandlerRunning = false; - spdlog::info("HttpRequestHandler stopped."); + DevMsg(eLog::NS, "HttpRequestHandler stopped.\n"); } bool IsHttpDestinationHostAllowed(const std::string& host, std::string& outHostname, std::string& outAddress, std::string& outPort) @@ -60,13 +60,13 @@ bool IsHttpDestinationHostAllowed(const std::string& host, std::string& outHostn CURLU* url = curl_url(); if (!url) { - spdlog::error("Failed to call curl_url() for http request."); + Error(eLog::NS, NO_ERROR, "Failed to call curl_url() for http request.\n"); return false; } if (curl_url_set(url, CURLUPART_URL, host.c_str(), CURLU_DEFAULT_SCHEME) != CURLUE_OK) { - spdlog::error("Failed to parse destination URL for http request."); + Error(eLog::NS, NO_ERROR, "Failed to parse destination URL for http request.\n"); curl_url_cleanup(url); return false; @@ -75,7 +75,7 @@ bool IsHttpDestinationHostAllowed(const std::string& host, std::string& outHostn char* urlHostname = nullptr; if (curl_url_get(url, CURLUPART_HOST, &urlHostname, 0) != CURLUE_OK) { - spdlog::error("Failed to parse hostname from destination URL for http request."); + Error(eLog::NS, NO_ERROR, "Failed to parse hostname from destination URL for http request.\n"); curl_url_cleanup(url); return false; @@ -84,7 +84,7 @@ bool IsHttpDestinationHostAllowed(const std::string& host, std::string& outHostn char* urlScheme = nullptr; if (curl_url_get(url, CURLUPART_SCHEME, &urlScheme, CURLU_DEFAULT_SCHEME) != CURLUE_OK) { - spdlog::error("Failed to parse scheme from destination URL for http request."); + Error(eLog::NS, NO_ERROR, "Failed to parse scheme from destination URL for http request.\n"); curl_url_cleanup(url); curl_free(urlHostname); @@ -94,7 +94,7 @@ bool IsHttpDestinationHostAllowed(const std::string& host, std::string& outHostn char* urlPort = nullptr; if (curl_url_get(url, CURLUPART_PORT, &urlPort, CURLU_DEFAULT_PORT) != CURLUE_OK) { - spdlog::error("Failed to parse port from destination URL for http request."); + Error(eLog::NS, NO_ERROR, "Failed to parse port from destination URL for http request.\n"); curl_url_cleanup(url); curl_free(urlHostname); @@ -110,7 +110,7 @@ bool IsHttpDestinationHostAllowed(const std::string& host, std::string& outHostn if (getaddrinfo(urlHostname, urlScheme, &hints, &result) != 0) { - spdlog::error("Failed to resolve http request destination {} using getaddrinfo().", urlHostname); + Error(eLog::NS, NO_ERROR, "Failed to resolve http request destination %s using getaddrinfo().\n", urlHostname); curl_url_cleanup(url); curl_free(urlHostname); @@ -136,11 +136,14 @@ bool IsHttpDestinationHostAllowed(const std::string& host, std::string& outHostn { if (bFoundIPv6) { - spdlog::error("Only IPv4 destinations are supported for HTTP requests. To allow IPv6, launch the game using -allowlocalhttp."); + Error( + eLog::NS, + NO_ERROR, + "Only IPv4 destinations are supported for HTTP requests. To allow IPv6, launch the game using -allowlocalhttp.\n"); } else { - spdlog::error("Failed to resolve http request destination {} into a valid IPv4 address.", urlHostname); + Error(eLog::NS, NO_ERROR, "Failed to resolve http request destination %s into a valid IPv4 address.\n", urlHostname); } curl_free(urlHostname); @@ -213,14 +216,16 @@ template int HttpRequestHandler::MakeHttpRequest(const H { if (!IsRunning()) { - spdlog::warn("%s was called while IsRunning() is false!", __FUNCTION__); + Warning(eLog::NS, "%s was called while IsRunning() is false!\n", __FUNCTION__); return -1; } if (IsHttpDisabled()) { - spdlog::warn("NS_InternalMakeHttpRequest called while the game is running with -disablehttprequests." - " Please check if requests are allowed using NSIsHttpEnabled() first."); + Warning( + eLog::NS, + "NS_InternalMakeHttpRequest called while the game is running with -disablehttprequests." + " Please check if requests are allowed using NSIsHttpEnabled() first.\n"); return -1; } @@ -238,9 +243,10 @@ template int HttpRequestHandler::MakeHttpRequest(const H { if (!IsHttpDestinationHostAllowed(requestParameters.baseUrl, hostname, resolvedAddress, resolvedPort)) { - spdlog::warn( + Warning( + eLog::NS, "HttpRequestHandler::MakeHttpRequest attempted to make a request to a private network. This is only allowed when " - "running the game with -allowlocalhttp."); + "running the game with -allowlocalhttp.\n"); g_pSquirrel->AsyncCall( "NSHandleFailedHttpRequest", handle, @@ -254,7 +260,7 @@ template int HttpRequestHandler::MakeHttpRequest(const H CURL* curl = curl_easy_init(); if (!curl) { - spdlog::error("HttpRequestHandler::MakeHttpRequest failed to init libcurl for request."); + Error(eLog::NS, NO_ERROR, "HttpRequestHandler::MakeHttpRequest failed to init libcurl for request.\n"); g_pSquirrel->AsyncCall( "NSHandleFailedHttpRequest", handle, static_cast(CURLE_FAILED_INIT), curl_easy_strerror(CURLE_FAILED_INIT)); return; @@ -423,15 +429,21 @@ template int HttpRequestHandler::MakeHttpRequest(const H else { // Pass CURL result code & error. - spdlog::error( - "curl_easy_perform() failed with code {}, error: {}", static_cast(result), curl_easy_strerror(result)); + Error( + eLog::NS, + NO_ERROR, + "curl_easy_perform() failed with code %i, error: %s\n", + static_cast(result), + curl_easy_strerror(result)); // If it's an SSL issue, tell the user they may disable SSL checks using -disablehttpssl. if (result == CURLE_PEER_FAILED_VERIFICATION || result == CURLE_SSL_CERTPROBLEM || result == CURLE_SSL_INVALIDCERTSTATUS) { - spdlog::error("You can try disabling SSL verifications for this issue using the -disablehttpssl launch argument. " - "Keep in mind this is potentially dangerous!"); + Warning( + eLog::NS, + "You can try disabling SSL verifications for this issue using the -disablehttpssl launch argument. " + "Keep in mind this is potentially dangerous!\n"); } g_pSquirrel->AsyncCall( @@ -454,15 +466,17 @@ template SQRESULT SQ_InternalMakeHttpRequest(HSquirrelVM { if (!g_httpRequestHandler || !g_httpRequestHandler->IsRunning()) { - spdlog::warn("NS_InternalMakeHttpRequest called while the http request handler isn't running."); + Warning(eLog::NS, "NS_InternalMakeHttpRequest called while the http request handler isn't running.\n"); g_pSquirrel->pushinteger(sqvm, -1); return SQRESULT_NOTNULL; } if (IsHttpDisabled()) { - spdlog::warn("NS_InternalMakeHttpRequest called while the game is running with -disablehttprequests." - " Please check if requests are allowed using NSIsHttpEnabled() first."); + Warning( + eLog::NS, + "NS_InternalMakeHttpRequest called while the game is running with -disablehttprequests." + " Please check if requests are allowed using NSIsHttpEnabled() first.\n"); g_pSquirrel->pushinteger(sqvm, -1); return SQRESULT_NOTNULL; } diff --git a/NorthstarDLL/scripts/scriptjson.cpp b/NorthstarDLL/scripts/scriptjson.cpp index 06bda6f42..a2f0090cb 100644 --- a/NorthstarDLL/scripts/scriptjson.cpp +++ b/NorthstarDLL/scripts/scriptjson.cpp @@ -140,7 +140,7 @@ template void EncodeJSONTable( obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), newArray, allocator); break; default: - spdlog::warn("SQ_EncodeJSON: squirrel type {} not supported", SQTypeNameFromID(node->val._Type)); + Warning(eLog::NS, "SQ_EncodeJSON: squirrel type %s not supported\n", SQTypeNameFromID(node->val._Type)); break; } } @@ -185,7 +185,7 @@ template void EncodeJSONArray( obj->PushBack(newArray, allocator); break; default: - spdlog::info("SQ encode Json type {} not supported", SQTypeNameFromID(node->_Type)); + Warning(eLog::NS, "SQ encode Json type %s not supported\n", SQTypeNameFromID(node->_Type)); } } } @@ -217,7 +217,7 @@ ADD_SQFUNC( return SQRESULT_ERROR; } - spdlog::warn(sErrorString); + Warning(eLog::NS, "%s\n", sErrorString.c_str()); return SQRESULT_NOTNULL; } diff --git a/NorthstarDLL/scripts/server/miscserverscript.cpp b/NorthstarDLL/scripts/server/miscserverscript.cpp index 3ea44cebb..8ab481085 100644 --- a/NorthstarDLL/scripts/server/miscserverscript.cpp +++ b/NorthstarDLL/scripts/server/miscserverscript.cpp @@ -12,7 +12,7 @@ ADD_SQFUNC("void", NSEarlyWritePlayerPersistenceForLeave, "entity player", "", S const R2::CBasePlayer* pPlayer = g_pSquirrel->template getentity(sqvm, 1); if (!pPlayer) { - spdlog::warn("NSEarlyWritePlayerPersistenceForLeave got null player"); + Warning(eLog::NS, "NSEarlyWritePlayerPersistenceForLeave got null player\n"); g_pSquirrel->pushbool(sqvm, false); return SQRESULT_NOTNULL; @@ -41,7 +41,7 @@ ADD_SQFUNC("bool", NSIsPlayerLocalPlayer, "entity player", "", ScriptContext::SE const R2::CBasePlayer* pPlayer = g_pSquirrel->template getentity(sqvm, 1); if (!pPlayer) { - spdlog::warn("NSIsPlayerLocalPlayer got null player"); + Warning(eLog::NS, "NSIsPlayerLocalPlayer got null player\n"); g_pSquirrel->pushbool(sqvm, false); return SQRESULT_NOTNULL; @@ -70,7 +70,7 @@ ADD_SQFUNC( if (!pPlayer) { - spdlog::warn("Attempted to call NSDisconnectPlayer() with null player."); + Warning(eLog::NS, "Attempted to call NSDisconnectPlayer() with null player.\n"); g_pSquirrel->pushbool(sqvm, false); return SQRESULT_NOTNULL; @@ -80,7 +80,7 @@ ADD_SQFUNC( R2::CBaseClient* pClient = &R2::g_pClientArray[pPlayer->m_nPlayerIndex - 1]; if (!pClient) { - spdlog::warn("NSDisconnectPlayer(): player entity has null CBaseClient!"); + Warning(eLog::NS, "NSDisconnectPlayer(): player entity has null CBaseClient!\n"); g_pSquirrel->pushbool(sqvm, false); return SQRESULT_NOTNULL; diff --git a/NorthstarDLL/server/auth/bansystem.cpp b/NorthstarDLL/server/auth/bansystem.cpp index 9b9d24c43..7e3ac83bc 100644 --- a/NorthstarDLL/server/auth/bansystem.cpp +++ b/NorthstarDLL/server/auth/bansystem.cpp @@ -88,7 +88,7 @@ void ServerBanSystem::BanUID(uint64_t uid) m_vBannedUids.push_back(uid); m_sBanlistStream << std::to_string(uid) << std::endl; m_sBanlistStream.close(); - spdlog::info("{} was banned", uid); + DevMsg(eLog::NS, "%li was banned\n", uid); } void ServerBanSystem::UnbanUID(uint64_t uid) @@ -168,7 +168,7 @@ void ServerBanSystem::UnbanUID(uint64_t uid) m_sBanlistStream << updatedLine << std::endl; m_sBanlistStream.close(); - spdlog::info("{} was unbanned", uid); + DevMsg(eLog::NS, "%li was unbanned\n", uid); } bool ServerBanSystem::IsUIDAllowed(uint64_t uid) diff --git a/NorthstarDLL/server/auth/serverauthentication.cpp b/NorthstarDLL/server/auth/serverauthentication.cpp index d5653dccf..2600599c4 100644 --- a/NorthstarDLL/server/auth/serverauthentication.cpp +++ b/NorthstarDLL/server/auth/serverauthentication.cpp @@ -260,7 +260,7 @@ bool,, (R2::CBaseClient* self, char* pName, void* pNetChannel, char bFakePlayer, if (pAuthenticationFailure) { - spdlog::info("{}'s (uid {}) connection was rejected: \"{}\"", pName, iNextPlayerUid, pAuthenticationFailure); + Warning(eLog::NS, "%s's (uid %li) connection was rejected: \"%s\"\n", pName, iNextPlayerUid, pAuthenticationFailure); strncpy_s(pDisconnectReason, 256, pAuthenticationFailure, 255); return false; @@ -313,7 +313,7 @@ void,, (R2::CBaseClient* self, uint32_t unknownButAlways1, const char* pReason, // this reason is used while connecting to a local server, hacky, but just ignore it if (strcmp(pReason, "Connection closing")) { - spdlog::info("Player {} disconnected: \"{}\"", self->m_Name, buf); + DevMsg(eLog::NS, "Player %s disconnected: \"%s\"\n", self->m_Name, buf); // dcing, write persistent data if (g_pServerAuthentication->m_PlayerAuthenticationData[self].needPersistenceWriteOnLeave) @@ -335,11 +335,11 @@ void ConCommand_ns_resetpersistence(const CCommand& args) { if (*R2::g_pServerState == R2::server_state_t::ss_active) { - spdlog::error("ns_resetpersistence must be entered from the main menu"); + Error(eLog::NS, NO_ERROR, "ns_resetpersistence must be entered from the main menu\n"); return; } - spdlog::info("resetting persistence on next lobby load..."); + Warning(eLog::NS, "resetting persistence on next lobby load...\n"); g_pServerAuthentication->m_bForceResetLocalPlayerPersistence = true; } diff --git a/NorthstarDLL/server/buildainfile.cpp b/NorthstarDLL/server/buildainfile.cpp index d0143295b..cb655e886 100644 --- a/NorthstarDLL/server/buildainfile.cpp +++ b/NorthstarDLL/server/buildainfile.cpp @@ -182,27 +182,22 @@ void DumpAINInfo(CAI_Network* aiNetwork) writePath += ".ain"; // dump from memory - spdlog::info("writing ain file {}", writePath.string()); - spdlog::info(""); - spdlog::info(""); - spdlog::info(""); - spdlog::info(""); - spdlog::info(""); + DevMsg(eLog::NS, "writing ain file %s\n", writePath.string().c_str()); std::ofstream writeStream(writePath, std::ofstream::binary); - spdlog::info("writing ainet version: {}", AINET_VERSION_NUMBER); + DevMsg(eLog::NS, "writing ainet version: %i\n", AINET_VERSION_NUMBER); writeStream.write((char*)&AINET_VERSION_NUMBER, sizeof(int)); int mapVersion = R2::g_pGlobals->m_nMapVersion; - spdlog::info("writing map version: {}", mapVersion); + DevMsg(eLog::NS, "writing map version: %i\n", mapVersion); writeStream.write((char*)&mapVersion, sizeof(int)); - spdlog::info("writing placeholder crc: {}", PLACEHOLDER_CRC); + DevMsg(eLog::NS, "writing placeholder crc: %i\n", PLACEHOLDER_CRC); writeStream.write((char*)&PLACEHOLDER_CRC, sizeof(int)); int calculatedLinkcount = 0; // path nodes - spdlog::info("writing nodecount: {}", aiNetwork->nodecount); + DevMsg(eLog::NS, "writing nodecount: %i\n", aiNetwork->nodecount); writeStream.write((char*)&aiNetwork->nodecount, sizeof(int)); for (int i = 0; i < aiNetwork->nodecount; i++) @@ -220,7 +215,7 @@ void DumpAINInfo(CAI_Network* aiNetwork) for (int j = 0; j < MAX_HULLS; j++) { diskNode.unk2[j] = (short)aiNetwork->nodes[i]->unk2[j]; - spdlog::info((short)aiNetwork->nodes[i]->unk2[j]); + DevMsg(eLog::NS, "%i\n", (short)aiNetwork->nodes[i]->unk2[j]); } memcpy(diskNode.unk3, aiNetwork->nodes[i]->unk3, sizeof(diskNode.unk3)); @@ -229,26 +224,26 @@ void DumpAINInfo(CAI_Network* aiNetwork) -1; // aiNetwork->nodes[i]->unk8; // this field is wrong, however, it's always -1 in vanilla navmeshes anyway, so no biggie memcpy(diskNode.unk6, aiNetwork->nodes[i]->unk10, sizeof(diskNode.unk6)); - spdlog::info("writing node {} from {} to {:x}", aiNetwork->nodes[i]->index, (void*)aiNetwork->nodes[i], writeStream.tellp()); + DevMsg(eLog::NS, "writing node %i from %li to 0x%p\n", aiNetwork->nodes[i]->index, (void*)aiNetwork->nodes[i], writeStream.tellp()); writeStream.write((char*)&diskNode, sizeof(CAI_NodeDisk)); calculatedLinkcount += aiNetwork->nodes[i]->linkcount; } // links - spdlog::info("linkcount: {}", aiNetwork->linkcount); - spdlog::info("calculated total linkcount: {}", calculatedLinkcount); + DevMsg(eLog::NS, "linkcount: %i\n", aiNetwork->linkcount); + DevMsg(eLog::NS, "calculated total linkcount: %i\n", calculatedLinkcount); calculatedLinkcount /= 2; if (Cvar_ns_ai_dumpAINfileFromLoad->GetBool()) { if (aiNetwork->linkcount == calculatedLinkcount) - spdlog::info("caculated linkcount is normal!"); + DevMsg(eLog::NS, "caculated linkcount is normal!\n"); else - spdlog::warn("calculated linkcount has weird value! this is expected on build!"); + Warning(eLog::NS, "calculated linkcount has weird value! this is expected on build!\n"); } - spdlog::info("writing linkcount: {}", calculatedLinkcount); + DevMsg(eLog::NS, "writing linkcount: %i\n", calculatedLinkcount); writeStream.write((char*)&calculatedLinkcount, sizeof(int)); for (int i = 0; i < aiNetwork->nodecount; i++) @@ -265,13 +260,13 @@ void DumpAINInfo(CAI_Network* aiNetwork) diskLink.unk0 = aiNetwork->nodes[i]->links[j]->unk1; memcpy(diskLink.hulls, aiNetwork->nodes[i]->links[j]->hulls, sizeof(diskLink.hulls)); - spdlog::info("writing link {} => {} to {:x}", diskLink.srcId, diskLink.destId, writeStream.tellp()); + DevMsg(eLog::NS, "writing link %i => %i to 0x%p\n", diskLink.srcId, diskLink.destId, writeStream.tellp()); writeStream.write((char*)&diskLink, sizeof(CAI_NodeLinkDisk)); } } // don't know what this is, it's likely a block from tf1 that got deprecated? should just be 1 int per node - spdlog::info("writing {:x} bytes for unknown block at {:x}", aiNetwork->nodecount * sizeof(uint32_t), writeStream.tellp()); + DevMsg(eLog::NS, "writing %x bytes for unknown block at 0x%p\n", aiNetwork->nodecount * sizeof(uint32_t), writeStream.tellp()); uint32_t* unkNodeBlock = new uint32_t[aiNetwork->nodecount]; memset(unkNodeBlock, 0, aiNetwork->nodecount * sizeof(uint32_t)); writeStream.write((char*)unkNodeBlock, aiNetwork->nodecount * sizeof(uint32_t)); @@ -279,24 +274,24 @@ void DumpAINInfo(CAI_Network* aiNetwork) // TODO: this is traverse nodes i think? these aren't used in tf2 ains so we can get away with just writing count=0 and skipping // but ideally should actually dump these - spdlog::info("writing {} traversal nodes at {:x}...", 0, writeStream.tellp()); + DevMsg(eLog::NS, "writing 0x%p traversal nodes at {:x}...\n", 0, writeStream.tellp()); short traverseNodeCount = 0; writeStream.write((char*)&traverseNodeCount, sizeof(short)); // only write count since count=0 means we don't have to actually do anything here // TODO: ideally these should be actually dumped, but they're always 0 in tf2 from what i can tell - spdlog::info("writing {} bytes for unknown hull block at {:x}", MAX_HULLS * 8, writeStream.tellp()); + DevMsg(eLog::NS, "writing %i bytes for unknown hull block at 0x%p\n", MAX_HULLS * 8, writeStream.tellp()); char* unkHullBlock = new char[MAX_HULLS * 8]; memset(unkHullBlock, 0, MAX_HULLS * 8); writeStream.write(unkHullBlock, MAX_HULLS * 8); delete[] unkHullBlock; // unknown struct that's seemingly node-related - spdlog::info("writing {} unknown node structs at {:x}", *pUnkStruct0Count, writeStream.tellp()); + DevMsg(eLog::NS, "writing %i unknown node structs at 0x%p\n", *pUnkStruct0Count, writeStream.tellp()); writeStream.write((char*)pUnkStruct0Count, sizeof(*pUnkStruct0Count)); for (int i = 0; i < *pUnkStruct0Count; i++) { - spdlog::info("writing unknown node struct {} at {:x}", i, writeStream.tellp()); + DevMsg(eLog::NS, "writing unknown node struct %i at 0x%p\n", i, writeStream.tellp()); UnkNodeStruct0* nodeStruct = (*pppUnkNodeStruct0s)[i]; writeStream.write((char*)&nodeStruct->index, sizeof(nodeStruct->index)); @@ -324,12 +319,12 @@ void DumpAINInfo(CAI_Network* aiNetwork) } // unknown struct that's seemingly link-related - spdlog::info("writing {} unknown link structs at {:x}", *pUnkLinkStruct1Count, writeStream.tellp()); + DevMsg(eLog::NS, "writing %i unknown link structs at 0x%p\n", *pUnkLinkStruct1Count, writeStream.tellp()); writeStream.write((char*)pUnkLinkStruct1Count, sizeof(*pUnkLinkStruct1Count)); for (int i = 0; i < *pUnkLinkStruct1Count; i++) { // disk and memory structs are literally identical here so just directly write - spdlog::info("writing unknown link struct {} at {:x}", i, writeStream.tellp()); + DevMsg(eLog::NS, "writing unknown link struct %i at 0x%p\n", i, writeStream.tellp()); writeStream.write((char*)(*pppUnkStruct1s)[i], sizeof(*(*pppUnkStruct1s)[i])); } @@ -337,20 +332,20 @@ void DumpAINInfo(CAI_Network* aiNetwork) writeStream.write((char*)&aiNetwork->unk5, sizeof(aiNetwork->unk5)); // tf2-exclusive stuff past this point, i.e. ain v57 only - spdlog::info("writing {} script nodes at {:x}", aiNetwork->scriptnodecount, writeStream.tellp()); + DevMsg(eLog::NS, "writing %i script nodes at 0x%p\n", aiNetwork->scriptnodecount, writeStream.tellp()); writeStream.write((char*)&aiNetwork->scriptnodecount, sizeof(aiNetwork->scriptnodecount)); for (int i = 0; i < aiNetwork->scriptnodecount; i++) { // disk and memory structs are literally identical here so just directly write - spdlog::info("writing script node {} at {:x}", i, writeStream.tellp()); + DevMsg(eLog::NS, "writing script node %i at 0x%p\n", i, writeStream.tellp()); writeStream.write((char*)&aiNetwork->scriptnodes[i], sizeof(aiNetwork->scriptnodes[i])); } - spdlog::info("writing {} hints at {:x}", aiNetwork->hintcount, writeStream.tellp()); + DevMsg(eLog::NS, "writing %i hints at 0x%p\n", aiNetwork->hintcount, writeStream.tellp()); writeStream.write((char*)&aiNetwork->hintcount, sizeof(aiNetwork->hintcount)); for (int i = 0; i < aiNetwork->hintcount; i++) { - spdlog::info("writing hint data {} at {:x}", i, writeStream.tellp()); + DevMsg(eLog::NS, "writing hint data %i at 0x%p\n", i, writeStream.tellp()); writeStream.write((char*)&aiNetwork->hints[i], sizeof(aiNetwork->hints[i])); } @@ -376,7 +371,7 @@ void, __fastcall, (void* aimanager, void* buf, const char* filename)) if (Cvar_ns_ai_dumpAINfileFromLoad->GetBool()) { - spdlog::info("running DumpAINInfo for loaded file {}", filename); + DevMsg(eLog::NS, "running DumpAINInfo for loaded file %s\n", filename); DumpAINInfo(*(CAI_Network**)((char*)aimanager + 2536)); } } diff --git a/NorthstarDLL/server/servernethooks.cpp b/NorthstarDLL/server/servernethooks.cpp index f74f2d386..fb55cf48a 100644 --- a/NorthstarDLL/server/servernethooks.cpp +++ b/NorthstarDLL/server/servernethooks.cpp @@ -23,19 +23,23 @@ static bool InitHMACSHA256() if ((status = BCryptOpenAlgorithmProvider(&HMACSHA256, BCRYPT_SHA256_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG))) { - spdlog::error("failed to initialize HMAC-SHA256: BCryptOpenAlgorithmProvider: error 0x{:08X}", (ULONG)status); + Error(eLog::NS, NO_ERROR, "failed to initialize HMAC-SHA256: BCryptOpenAlgorithmProvider: error 0x%x\n", (ULONG)status); return false; } if ((status = BCryptGetProperty(HMACSHA256, BCRYPT_HASH_LENGTH, (PUCHAR)&hashLength, sizeof(hashLength), &hashLengthSz, 0))) { - spdlog::error("failed to initialize HMAC-SHA256: BCryptGetProperty(BCRYPT_HASH_LENGTH): error 0x{:08X}", (ULONG)status); + Error(eLog::NS, NO_ERROR, "failed to initialize HMAC-SHA256: BCryptGetProperty(BCRYPT_HASH_LENGTH): error 0x%x\n", (ULONG)status); return false; } if (hashLength != HMACSHA256_LEN) { - spdlog::error("failed to initialize HMAC-SHA256: BCryptGetProperty(BCRYPT_HASH_LENGTH): unexpected value {}", hashLength); + Error( + eLog::NS, + NO_ERROR, + "failed to initialize HMAC-SHA256: BCryptGetProperty(BCRYPT_HASH_LENGTH): unexpected value %i\n", + hashLength); return false; } @@ -53,19 +57,19 @@ static bool VerifyHMACSHA256(std::string key, std::string sig, std::string data) if ((status = BCryptCreateHash(HMACSHA256, &h, NULL, 0, (PUCHAR)key.c_str(), (ULONG)key.length(), 0))) { - spdlog::error("failed to verify HMAC-SHA256: BCryptCreateHash: error 0x{:08X}", (ULONG)status); + Error(eLog::NS, NO_ERROR, "failed to verify HMAC-SHA256: BCryptCreateHash: error 0x%x\n", (ULONG)status); goto cleanup; } if ((status = BCryptHashData(h, (PUCHAR)data.c_str(), (ULONG)data.length(), 0))) { - spdlog::error("failed to verify HMAC-SHA256: BCryptHashData: error 0x{:08X}", (ULONG)status); + Error(eLog::NS, NO_ERROR, "failed to verify HMAC-SHA256: BCryptHashData: error 0x%x\n", (ULONG)status); goto cleanup; } if ((status = BCryptFinishHash(h, (PUCHAR)&hash, (ULONG)sizeof(hash), 0))) { - spdlog::error("failed to verify HMAC-SHA256: BCryptFinishHash: error 0x{:08X}", (ULONG)status); + Error(eLog::NS, NO_ERROR, "failed to verify HMAC-SHA256: BCryptFinishHash: error 0x%x\n", (ULONG)status); goto cleanup; } @@ -89,7 +93,11 @@ static void ProcessAtlasConnectionlessPacketSigreq1(R2::netpacket_t* packet, boo if (pData.length() < HMACSHA256_LEN) { if (dbg) - spdlog::warn("ignoring Atlas connectionless packet (size={} type={}): invalid: too short for signature", packet->size, pType); + Warning( + eLog::MS, + "ignoring Atlas connectionless packet (size=%i type=%s): invalid: too short for signature\n", + packet->size, + pType.c_str()); return; } @@ -100,11 +108,12 @@ static void ProcessAtlasConnectionlessPacketSigreq1(R2::netpacket_t* packet, boo if (!g_pMasterServerManager || !g_pMasterServerManager->m_sOwnServerAuthToken[0]) { if (dbg) - spdlog::warn( - "ignoring Atlas connectionless packet (size={} type={}): invalid (data={}): no masterserver token yet", + Warning( + eLog::MS, + "ignoring Atlas connectionless packet (size=%i type=%s): invalid (data=%s): no masterserver token yet\n", packet->size, - pType, - pData); + pType.c_str(), + pData.c_str()); return; } @@ -113,21 +122,23 @@ static void ProcessAtlasConnectionlessPacketSigreq1(R2::netpacket_t* packet, boo if (!Cvar_net_debug_atlas_packet_insecure->GetBool()) { if (dbg) - spdlog::warn( - "ignoring Atlas connectionless packet (size={} type={}): invalid: invalid signature (key={})", + Warning( + eLog::MS, + "ignoring Atlas connectionless packet (size=%i type=%s): invalid: invalid signature (key=%s)\n", packet->size, - pType, - std::string(g_pMasterServerManager->m_sOwnServerAuthToken)); + pType.c_str(), + g_pMasterServerManager->m_sOwnServerAuthToken); return; } - spdlog::warn( - "processing Atlas connectionless packet (size={} type={}) with invalid signature due to net_debug_atlas_packet_insecure", + Warning( + eLog::MS, + "processing Atlas connectionless packet (size=%i type=%s) with invalid signature due to net_debug_atlas_packet_insecure\n", packet->size, - pType); + pType.c_str()); } if (dbg) - spdlog::info("got Atlas connectionless packet (size={} type={} data={})", packet->size, pType, pData); + DevMsg(eLog::MS, "got Atlas connectionless packet (size=%i type=%s data=%s)\n", packet->size, pType.c_str(), pData.c_str()); std::thread t(&MasterServerManager::ProcessConnectionlessPacketSigreq1, g_pMasterServerManager, pData); t.detach(); @@ -164,7 +175,7 @@ static void ProcessAtlasConnectionlessPacket(R2::netpacket_t* packet) } if (dbg) - spdlog::warn("ignoring Atlas connectionless packet (size={} type={}): unknown type", packet->size, pType); + Warning(eLog::MS, "ignoring Atlas connectionless packet (size=%i type=%s): unknown type\n", packet->size, pType.c_str()); return; } @@ -194,14 +205,14 @@ ON_DLL_LOAD_RELIESON("engine.dll", ServerNetHooks, ConVar, (CModule module)) AUTOHOOK_DISPATCH_MODULE(engine.dll) if (!InitHMACSHA256()) - throw std::runtime_error("failed to initialize bcrypt"); + Error(eLog::NS, EXIT_FAILURE, "Failed to initialize bcrypt\n"); if (!VerifyHMACSHA256( "test", "\x88\xcd\x21\x08\xb5\x34\x7d\x97\x3c\xf3\x9c\xdf\x90\x53\xd7\xdd\x42\x70\x48\x76\xd8\xc9\xa9\xbd\x8e\x2d\x16\x82\x59\xd3\xdd" "\xf7", "test")) - throw std::runtime_error("bcrypt HMAC-SHA256 is broken"); + Error(eLog::NS, EXIT_FAILURE, "bcrypt HMAC-SHA256 is broken\n"); Cvar_net_debug_atlas_packet = new ConVar( "net_debug_atlas_packet", diff --git a/NorthstarDLL/shared/exploit_fixes/exploitfixes.cpp b/NorthstarDLL/shared/exploit_fixes/exploitfixes.cpp index 2a0a9c2ca..9f6430cd9 100644 --- a/NorthstarDLL/shared/exploit_fixes/exploitfixes.cpp +++ b/NorthstarDLL/shared/exploit_fixes/exploitfixes.cpp @@ -21,7 +21,7 @@ ConVar* Cvar_sv_cheats; { \ std::stringstream stream; \ stream << "ExploitFixes.cpp: " << BLOCK_PREFIX << s; \ - spdlog::error(stream.str()); \ + Error(eLog::NS, NO_ERROR, "%s\n", stream.str().c_str()); \ } \ return false; \ }()) @@ -271,7 +271,7 @@ bool, __fastcall, (R2::CBaseClient* self, uint32_t unknown, const char* pCommand // clang-format on { if (Cvar_ns_should_log_all_clientcommands->GetBool()) - spdlog::info("player {} (UID: {}) sent command: \"{}\"", self->m_Name, self->m_UID, pCommandString); + DevMsg(eLog::NS, "player %s (UID: %s) sent command: \"%s\"\n", self->m_Name, self->m_UID, pCommandString); if (!g_pServerLimits->CheckStringCommandLimits(self)) { @@ -362,7 +362,7 @@ void*, __fastcall, (int i)) if (i >= MAX_ENT_IDX) { - spdlog::warn("GetEntByIndex {} is out of bounds (max {})", i, MAX_ENT_IDX); + Warning(eLog::NS, "GetEntByIndex %i is out of bounds (max %i)\n", i, MAX_ENT_IDX); return nullptr; } @@ -440,7 +440,7 @@ ON_DLL_LOAD_RELIESON("server.dll", ServerExploitFixes, ConVar, (CModule module)) { // Just return, none of them have any args or are userpurge exportAddr.Patch("C3"); - spdlog::info("Patched AntiTamper function export \"{}\"", exportName); + DevMsg(eLog::NS, "Patched AntiTamper function export \"%s\"\n", exportName); } } diff --git a/NorthstarDLL/shared/exploit_fixes/ns_limits.cpp b/NorthstarDLL/shared/exploit_fixes/ns_limits.cpp index c9085cb07..96d9fe4ea 100644 --- a/NorthstarDLL/shared/exploit_fixes/ns_limits.cpp +++ b/NorthstarDLL/shared/exploit_fixes/ns_limits.cpp @@ -126,8 +126,9 @@ char, __fastcall, (void* self, void* buf)) if (g_pServerLimits->m_PlayerLimitData[sender].netChanProcessingLimitTime >= g_pServerLimits->Cvar_net_chan_limit_msec_per_sec->GetInt()) { - spdlog::warn( - "Client {} hit netchan processing limit with {}ms of processing time this second (max is {})", + Warning( + eLog::NS, + "Client %s hit netchan processing limit with %f ms of processing time this second (max is %i)\n", (char*)sender + 0x16, g_pServerLimits->m_PlayerLimitData[sender].netChanProcessingLimitTime, g_pServerLimits->Cvar_net_chan_limit_msec_per_sec->GetInt()); @@ -182,8 +183,9 @@ bool ServerLimitsManager::CheckConnectionlessPacketLimits(R2::netpacket_t* packe if (sendData->packetCount >= g_pServerLimits->Cvar_sv_querylimit_per_sec->GetInt()) { - spdlog::warn( - "Client went over connectionless ratelimit of {} per sec with packet of type {}", + Warning( + eLog::NS, + "Client went over connectionless ratelimit of %i per sec with packet of type %c\n", g_pServerLimits->Cvar_sv_querylimit_per_sec->GetInt(), packet->data[4]); @@ -247,7 +249,7 @@ void, __fastcall, (void* self, R2::CBasePlayer* player, SV_CUserCmd* pUserCmd, u if (pLimitData->flFrameUserCmdBudget <= 0.0) { - spdlog::warn("player {} went over usercmd budget ({})", pClient->m_Name, pLimitData->flFrameUserCmdBudget); + Warning(eLog::NS, "player %s went over usercmd budget (%f)\n", pClient->m_Name, pLimitData->flFrameUserCmdBudget); return; } } diff --git a/NorthstarDLL/shared/misccommands.cpp b/NorthstarDLL/shared/misccommands.cpp index 5d9ced996..f8a90e98f 100644 --- a/NorthstarDLL/shared/misccommands.cpp +++ b/NorthstarDLL/shared/misccommands.cpp @@ -48,14 +48,14 @@ void ConCommand_cvar_setdefaultvalue(const CCommand& arg) { if (arg.ArgC() < 3) { - spdlog::info("usage: cvar_setdefaultvalue mp_gamemode tdm"); + DevMsg(eLog::NS, "usage: cvar_setdefaultvalue mp_gamemode tdm\n"); return; } ConVar* pCvar = R2::g_pCVar->FindVar(arg.Arg(1)); if (!pCvar) { - spdlog::info("usage: cvar_setdefaultvalue mp_gamemode tdm"); + DevMsg(eLog::NS, "usage: cvar_setdefaultvalue mp_gamemode tdm\n"); return; } @@ -71,14 +71,14 @@ void ConCommand_cvar_setvalueanddefaultvalue(const CCommand& arg) { if (arg.ArgC() < 3) { - spdlog::info("usage: cvar_setvalueanddefaultvalue mp_gamemode tdm"); + DevMsg(eLog::NS, "usage: cvar_setvalueanddefaultvalue mp_gamemode tdm\n"); return; } ConVar* pCvar = R2::g_pCVar->FindVar(arg.Arg(1)); if (!pCvar) { - spdlog::info("usage: cvar_setvalueanddefaultvalue mp_gamemode tdm"); + DevMsg(eLog::NS, "usage: cvar_setvalueanddefaultvalue mp_gamemode tdm\n"); return; } @@ -95,14 +95,14 @@ void ConCommand_cvar_reset(const CCommand& arg) { if (arg.ArgC() < 2) { - spdlog::info("usage: cvar_reset mp_gamemode"); + DevMsg(eLog::NS, "usage: cvar_reset mp_gamemode\n"); return; } ConVar* pCvar = R2::g_pCVar->FindVar(arg.Arg(1)); if (!pCvar) { - spdlog::info("usage: cvar_reset mp_gamemode"); + DevMsg(eLog::NS, "usage: cvar_reset mp_gamemode\n"); return; } @@ -166,7 +166,7 @@ void FixupCvarFlags() pair.second->m_nFlags = flags; } - spdlog::info("Removed {} hidden/devonly cvar flags", iNumCvarsAltered); + DevMsg(eLog::NS, "Removed %i hidden/devonly cvar flags\n", iNumCvarsAltered); } // make all engine client commands FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS diff --git a/NorthstarDLL/shared/playlist.cpp b/NorthstarDLL/shared/playlist.cpp index ab7aab222..f162f5acd 100644 --- a/NorthstarDLL/shared/playlist.cpp +++ b/NorthstarDLL/shared/playlist.cpp @@ -41,7 +41,7 @@ bool, __fastcall, (const char* pPlaylistName)) if (bSuccess) { - spdlog::info("Set playlist to {}", R2::GetCurrentPlaylistName()); + DevMsg(eLog::NS, "Set playlist to %s\n", R2::GetCurrentPlaylistName()); g_pServerPresence->SetPlaylist(R2::GetCurrentPlaylistName()); } diff --git a/NorthstarDLL/squirrel/squirrel.cpp b/NorthstarDLL/squirrel/squirrel.cpp index e43686d71..cc0519305 100644 --- a/NorthstarDLL/squirrel/squirrel.cpp +++ b/NorthstarDLL/squirrel/squirrel.cpp @@ -14,34 +14,41 @@ AUTOHOOK_INIT() -std::shared_ptr getSquirrelLoggerByContext(ScriptContext context) +//----------------------------------------------------------------------------- +// Purpose: Returns script log context based on Script context +//----------------------------------------------------------------------------- +eLog SQ_GetLogContextScript(ScriptContext nSqContext) { - switch (context) + switch (nSqContext) { - case ScriptContext::UI: - return NS::log::SCRIPT_UI; - case ScriptContext::CLIENT: - return NS::log::SCRIPT_CL; case ScriptContext::SERVER: - return NS::log::SCRIPT_SV; - default: - throw std::runtime_error("getSquirrelLoggerByContext called with invalid context"); - return nullptr; + return eLog::SCRIPT_SERVER; + case ScriptContext::CLIENT: + return eLog::SCRIPT_CLIENT; + case ScriptContext::UI: + return eLog::SCRIPT_UI; } + + return eLog::NONE; } -namespace NS::log +//----------------------------------------------------------------------------- +// Purpose:Returns native log context based on Script context +//----------------------------------------------------------------------------- +eLog SQ_GetLogContextNative(ScriptContext nSqContext) { - template std::shared_ptr squirrel_logger() + switch (nSqContext) { - // Switch statements can't be constexpr afaik - // clang-format off - if constexpr (context == ScriptContext::UI) { return SCRIPT_UI; } - if constexpr (context == ScriptContext::CLIENT) { return SCRIPT_CL; } - if constexpr (context == ScriptContext::SERVER) { return SCRIPT_SV; } - // clang-format on + case ScriptContext::SERVER: + return eLog::SERVER; + case ScriptContext::CLIENT: + return eLog::CLIENT; + case ScriptContext::UI: + return eLog::UI; } -}; // namespace NS::log + + return eLog::NONE; +} const char* GetContextName(ScriptContext context) { @@ -240,7 +247,7 @@ template void SquirrelManager::VMCreated(CSquir for (SQFuncRegistration* funcReg : m_funcRegistrations) { - spdlog::info("Registering {} function {}", GetContextName(context), funcReg->squirrelFuncName); + DevMsg(SQ_GetLogContextNative(context), "Registering %s function %s\n", GetContextName(context), funcReg->squirrelFuncName); RegisterSquirrelFunc(m_pSQVM, funcReg, 1); } @@ -281,7 +288,7 @@ template void SquirrelManager::VMDestroyed() // Call all registered mod Destroy callbacks. if (g_pModManager) { - NS::log::squirrel_logger()->info("Calling Destroy callbacks for all loaded mods."); + DevMsg(SQ_GetLogContextNative(context), "Calling Destroy callbacks for all loaded mods.\n"); for (const Mod& loadedMod : g_pModManager->m_LoadedMods) { @@ -295,7 +302,7 @@ template void SquirrelManager::VMDestroyed() } Call(callback.DestroyCallback.c_str()); - NS::log::squirrel_logger()->info("Executed Destroy callback {}.", callback.DestroyCallback); + DevMsg(SQ_GetLogContextNative(context), "Executed Destroy callback %s.\n", callback.DestroyCallback.c_str()); } } } @@ -314,23 +321,24 @@ template void SquirrelManager::ExecuteCode(cons { if (!m_pSQVM || !m_pSQVM->sqvm) { - spdlog::error("Cannot execute code, {} squirrel vm is not initialised", GetContextName(context)); + Error( + SQ_GetLogContextNative(context), NO_ERROR, "Cannot execute code, %s squirrel vm is not initialised\n", GetContextName(context)); return; } - spdlog::info("Executing {} script code {} ", GetContextName(context), pCode); + DevMsg(SQ_GetLogContextNative(context), "Executing %s script code %s\n", GetContextName(context), pCode); std::string strCode(pCode); CompileBufferState bufferState = CompileBufferState(strCode); SQRESULT compileResult = compilebuffer(&bufferState, "console"); - spdlog::info("sq_compilebuffer returned {}", PrintSQRESULT.at(compileResult)); + DevMsg(SQ_GetLogContextNative(context), "sq_compilebuffer returned %s\n", PrintSQRESULT.at(compileResult)); if (compileResult != SQRESULT_ERROR) { pushroottable(m_pSQVM->sqvm); SQRESULT callResult = _call(m_pSQVM->sqvm, 0); - spdlog::info("sq_call returned {}", PrintSQRESULT.at(callResult)); + DevMsg(SQ_GetLogContextNative(context), "sq_call returned %s\n", PrintSQRESULT.at(callResult)); } } @@ -406,7 +414,7 @@ template SQInteger SQPrintHook(HSquirrelVM* sqvm, const { if (buf[charsWritten - 1] == '\n') buf[charsWritten - 1] = '\0'; - g_pSquirrel->logger->info("{}", buf); + DevMsg(SQ_GetLogContextScript(context), "%s\n", buf); } va_end(va); @@ -422,7 +430,7 @@ template CSquirrelVM* __fastcall CreateNewVMHook(void* a else g_pSquirrel->VMCreated(sqvm); - spdlog::info("CreateNewVM {} {}", GetContextName(realContext), (void*)sqvm); + DevMsg(SQ_GetLogContextNative(context), "CreateNewVM %s %p\n", GetContextName(realContext), (void*)sqvm); return sqvm; } @@ -459,7 +467,7 @@ template void __fastcall DestroyVMHook(void* a1, CSquirr DestroyVM(a1, sqvm); } - spdlog::info("DestroyVM {} {}", GetContextName(realContext), (void*)sqvm); + DevMsg(SQ_GetLogContextNative(context), "DestroyVM %s %p\n", GetContextName(realContext), (void*)sqvm); } template void (*SQCompileError)(HSquirrelVM* sqvm, const char* error, const char* file, int line, int column); @@ -474,10 +482,10 @@ void __fastcall ScriptCompileErrorHook(HSquirrelVM* sqvm, const char* error, con bIsFatalError = g_pSquirrel->m_bFatalCompilationErrors; } - auto logger = getSquirrelLoggerByContext(realContext); + eLog eContext = SQ_GetLogContextNative(realContext); - logger->error("COMPILE ERROR {}", error); - logger->error("{} line [{}] column [{}]", file, line, column); + Error(eContext, NO_ERROR, "COMPILE ERROR %s\n", error); + Error(eContext, NO_ERROR, "%s line [%i] column [%i]\n", file, line, column); // use disconnect to display an error message for the compile error, but only if the compilation error was fatal // todo, we could get this from sqvm itself probably, rather than hooking sq_compiler_create @@ -486,10 +494,7 @@ void __fastcall ScriptCompileErrorHook(HSquirrelVM* sqvm, const char* error, con // kill dedicated server if we hit this if (IsDedicatedServer()) { - logger->error("Exiting dedicated server, compile error is fatal"); - // flush the logger before we exit so debug things get saved to log file - logger->flush(); - exit(EXIT_FAILURE); + Error(eContext, EXIT_FAILURE, "Exiting dedicated server, compile error is fatal\n"); } else { @@ -520,7 +525,7 @@ int64_t __fastcall RegisterSquirrelFunctionHook(CSquirrelVM* sqvm, SQFuncRegistr { g_pSquirrel->m_funcOriginals[funcReg->squirrelFuncName] = funcReg->funcPtr; funcReg->funcPtr = g_pSquirrel->m_funcOverrides[funcReg->squirrelFuncName]; - spdlog::info("Replacing {} in UI", std::string(funcReg->squirrelFuncName)); + DevMsg(SQ_GetLogContextNative(context), "Replacing %s in UI\n", funcReg->squirrelFuncName); } return g_pSquirrel->RegisterSquirrelFunc(sqvm, funcReg, unknown); @@ -530,7 +535,7 @@ int64_t __fastcall RegisterSquirrelFunctionHook(CSquirrelVM* sqvm, SQFuncRegistr { g_pSquirrel->m_funcOriginals[funcReg->squirrelFuncName] = funcReg->funcPtr; funcReg->funcPtr = g_pSquirrel->m_funcOverrides[funcReg->squirrelFuncName]; - spdlog::info("Replacing {} in Client", std::string(funcReg->squirrelFuncName)); + DevMsg(SQ_GetLogContextNative(context), "Replacing %s in Client\n", funcReg->squirrelFuncName); } return g_pSquirrel->RegisterSquirrelFunc(sqvm, funcReg, unknown); @@ -565,7 +570,11 @@ template bool __fastcall CallScriptInitCallbackHook(void { if (modCallback.Context == realContext && modCallback.BeforeCallback.length()) { - spdlog::info("Running custom {} script callback \"{}\"", GetContextName(realContext), modCallback.BeforeCallback); + DevMsg( + SQ_GetLogContextNative(context), + "Running custom %s script callback \"%s\"\n", + GetContextName(realContext), + modCallback.BeforeCallback.c_str()); CallScriptInitCallback(sqvm, modCallback.BeforeCallback.c_str()); } } @@ -573,9 +582,9 @@ template bool __fastcall CallScriptInitCallbackHook(void } } - spdlog::info("{} CodeCallback {} called", GetContextName(realContext), callback); + DevMsg(SQ_GetLogContextNative(context), "%s CodeCallback %s called\n", GetContextName(realContext), callback); if (!bShouldCallCustomCallbacks) - spdlog::info("Not executing custom callbacks for CodeCallback {}", callback); + DevMsg(SQ_GetLogContextNative(context), "Not executing custom callbacks for CodeCallback %s\n", callback); bool ret = CallScriptInitCallback(sqvm, callback); // run after callbacks @@ -592,7 +601,11 @@ template bool __fastcall CallScriptInitCallbackHook(void { if (modCallback.Context == realContext && modCallback.AfterCallback.length()) { - spdlog::info("Running custom {} script callback \"{}\"", GetContextName(realContext), modCallback.AfterCallback); + DevMsg( + SQ_GetLogContextNative(context), + "Running custom %s script callback \"%s\"\n", + GetContextName(realContext), + modCallback.AfterCallback.c_str()); CallScriptInitCallback(sqvm, modCallback.AfterCallback.c_str()); } } @@ -621,7 +634,7 @@ template struct TemplateStringLiteral template SQRESULT SQ_StubbedFunc(HSquirrelVM* sqvm) { - spdlog::info("Blocking call to stubbed function {} in {}", funcName.value, GetContextName(context)); + DevMsg(SQ_GetLogContextNative(context), "Blocking call to stubbed function %s in %s\n", funcName.value, GetContextName(context)); return SQRESULT_NULL; } @@ -648,8 +661,11 @@ template void SquirrelManager::ProcessMessageBu int result = sq_getfunction(m_pSQVM->sqvm, message.functionName.c_str(), &functionobj, 0); if (result != 0) // This func returns 0 on success for some reason { - NS::log::squirrel_logger()->error( - "ProcessMessageBuffer was unable to find function with name '{}'. Is it global?", message.functionName); + Error( + SQ_GetLogContextNative(context), + NO_ERROR, + "ProcessMessageBuffer was unable to find function with name '%s'. Is it global?\n", + message.functionName.c_str()); continue; } @@ -809,9 +825,6 @@ ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrel, ConCommand, (CModule module)) &g_pSquirrel->RegisterSquirrelFunc); g_pSquirrel->RegisterSquirrelFunc = g_pSquirrel->RegisterSquirrelFunc; - g_pSquirrel->logger = NS::log::SCRIPT_CL; - g_pSquirrel->logger = NS::log::SCRIPT_UI; - // uiscript_reset concommand: don't loop forever if compilation fails module.Offset(0x3C6E4C).NOP(6); @@ -887,7 +900,6 @@ 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->logger = NS::log::SCRIPT_SV; // Message buffer stuff g_pSquirrel->__sq_getfunction = module.Offset(0x6C85).RCast(); g_pSquirrel->__sq_stackinfos = module.Offset(0x35920).RCast(); diff --git a/NorthstarDLL/squirrel/squirrel.h b/NorthstarDLL/squirrel/squirrel.h index 50dd31d05..7c06800a8 100644 --- a/NorthstarDLL/squirrel/squirrel.h +++ b/NorthstarDLL/squirrel/squirrel.h @@ -6,6 +6,9 @@ #include "plugins/plugin_abi.h" #include "mods/modmanager.h" +eLog SQ_GetLogContextScript(ScriptContext nSqContext); +eLog SQ_GetLogContextNative(ScriptContext nSqContext); + /* definitions from hell required to function @@ -55,11 +58,6 @@ void AsyncCall_External(ScriptContext context, const char* func_name, SquirrelMe ScriptContext ScriptContextFromString(std::string string); -namespace NS::log -{ - template std::shared_ptr squirrel_logger(); -}; // namespace NS::log - // This base class means that only the templated functions have to be rebuilt for each template instance // Cuts down on compile time by ~5 seconds class SquirrelManagerBase @@ -74,8 +72,6 @@ class SquirrelManagerBase bool m_bFatalCompilationErrors = false; - std::shared_ptr logger; - #pragma region SQVM funcs RegisterSquirrelFuncType RegisterSquirrelFunc; sq_defconstType __sq_defconst; @@ -256,7 +252,6 @@ class SquirrelManagerBase { return __sq_stackinfos(sqvm, level, &out, sqvm->_callstacksize); } - inline Mod* getcallingmod(HSquirrelVM* sqvm, int depth = 0) { SQStackInfos stackInfo {}; @@ -353,15 +348,20 @@ template class SquirrelManager : public virtual Squirrel if (!m_pSQVM || !m_pSQVM->sqvm) { - spdlog::error( - "{} was called on context {} while VM was not initialized. This will crash", __FUNCTION__, GetContextName(context)); + // TODO [Fifty]: Potentially make this fatal? + Error( + SQ_GetLogContextNative(context), + NO_ERROR, + "%s was called on context %s while VM was not initialized. This will crash\n", + __FUNCTION__, + GetContextName(context)); } SQObject functionobj {}; int result = sq_getfunction(m_pSQVM->sqvm, funcname, &functionobj, 0); if (result != 0) // This func returns 0 on success for some reason { - NS::log::squirrel_logger()->error("Call was unable to find function with name '{}'. Is it global?", funcname); + Error(SQ_GetLogContextNative(context), NO_ERROR, "Call was unable to find function with name '%s'. Is it global?\n", funcname); return SQRESULT_ERROR; } pushobject(m_pSQVM->sqvm, &functionobj); // Push the function object @@ -377,14 +377,19 @@ template class SquirrelManager : public virtual Squirrel // If you want to call into squirrel asynchronously, use `schedule_call` instead if (!m_pSQVM || !m_pSQVM->sqvm) { - spdlog::error( - "{} was called on context {} while VM was not initialized. This will crash", __FUNCTION__, GetContextName(context)); + // TODO [Fifty]: Potentially make this fatal? + Error( + SQ_GetLogContextNative(context), + NO_ERROR, + "%s was called on context %s while VM was not initialized. This will crash\n", + __FUNCTION__, + GetContextName(context)); } SQObject functionobj {}; int result = sq_getfunction(m_pSQVM->sqvm, funcname, &functionobj, 0); if (result != 0) // This func returns 0 on success for some reason { - NS::log::squirrel_logger()->error("Call was unable to find function with name '{}'. Is it global?", funcname); + Error(SQ_GetLogContextNative(context), NO_ERROR, "Call was unable to find function with name '%s'. Is it global?\n", funcname); return SQRESULT_ERROR; } pushobject(m_pSQVM->sqvm, &functionobj); // Push the function object diff --git a/NorthstarDLL/squirrel/squirrelautobind.cpp b/NorthstarDLL/squirrel/squirrelautobind.cpp index c15240f53..895a79bfc 100644 --- a/NorthstarDLL/squirrel/squirrelautobind.cpp +++ b/NorthstarDLL/squirrel/squirrelautobind.cpp @@ -4,7 +4,7 @@ SquirrelAutoBindContainer* g_pSqAutoBindContainer; ON_DLL_LOAD_RELIESON("client.dll", ClientSquirrelAutoBind, ClientSquirrel, (CModule module)) { - spdlog::info("ClientSquirrelAutoBInd AutoBindFuncsVectorsize {}", g_pSqAutoBindContainer->clientSqAutoBindFuncs.size()); + DevMsg(eLog::CLIENT, "ClientSquirrelAutoBInd AutoBindFuncsVectorsize %i\n", g_pSqAutoBindContainer->clientSqAutoBindFuncs.size()); for (auto& autoBindFunc : g_pSqAutoBindContainer->clientSqAutoBindFuncs) { autoBindFunc(); diff --git a/NorthstarDLL/util/printcommands.cpp b/NorthstarDLL/util/printcommands.cpp index 7c915318a..989ae77a3 100644 --- a/NorthstarDLL/util/printcommands.cpp +++ b/NorthstarDLL/util/printcommands.cpp @@ -7,7 +7,7 @@ void PrintCommandHelpDialogue(const ConCommandBase* command, const char* name) { if (!command) { - spdlog::info("unknown command {}", name); + DevMsg(eLog::NS, "unknown command %s\n", name); return; } @@ -44,9 +44,9 @@ void PrintCommandHelpDialogue(const ConCommandBase* command, const char* name) } if (cvar) - spdlog::info("\"{}\" = \"{}\" {}- {}", cvar->GetBaseName(), cvar->GetString(), flagString, cvar->GetHelpText()); + DevMsg(eLog::NS, "\"%s\" = \"%s\" %s- %s\n", cvar->GetBaseName(), cvar->GetString(), flagString.c_str(), cvar->GetHelpText()); else - spdlog::info("\"{}\" {} - {}", command->m_pszName, flagString, command->GetHelpText()); + DevMsg(eLog::NS, "\"%s\" %s - %s\n", command->m_pszName, flagString.c_str(), command->GetHelpText()); } void TryPrintCvarHelpForCommand(const char* pCommand) @@ -77,7 +77,7 @@ void ConCommand_help(const CCommand& arg) { if (arg.ArgC() < 2) { - spdlog::info("Usage: help "); + DevMsg(eLog::NS, "Usage: help \n"); return; } @@ -88,7 +88,7 @@ void ConCommand_find(const CCommand& arg) { if (arg.ArgC() < 2) { - spdlog::info("Usage: find [...]"); + DevMsg(eLog::NS, "Usage: find [...]\n"); return; } @@ -139,9 +139,9 @@ void ConCommand_findflags(const CCommand& arg) { if (arg.ArgC() < 2) { - spdlog::info("Usage: findflags "); + DevMsg(eLog::NS, "Usage: findflags \n"); for (auto& flagPair : g_PrintCommandFlags) - spdlog::info(" - {}", flagPair.second); + DevMsg(eLog::NS, " - %i\n", flagPair.second); return; } diff --git a/NorthstarDLL/util/printmaps.cpp b/NorthstarDLL/util/printmaps.cpp index 5b406c4c8..c3a7b42ac 100644 --- a/NorthstarDLL/util/printmaps.cpp +++ b/NorthstarDLL/util/printmaps.cpp @@ -176,8 +176,8 @@ void ConCommand_maps(const CCommand& args) { if (args.ArgC() < 2) { - spdlog::info("Usage: maps "); - spdlog::info("maps * for full listing"); + DevMsg(eLog::NS, "Usage: maps \n"); + DevMsg(eLog::NS, "maps * for full listing\n"); return; } @@ -185,7 +185,7 @@ void ConCommand_maps(const CCommand& args) for (MapVPKInfo& map : vMapList) // need to figure out a nice way to include parent path without making the formatting awful if ((*args.Arg(1) == '*' && !args.Arg(1)[1]) || strstr(map.name.c_str(), args.Arg(1))) - spdlog::info("({}) {}", PrintMapSource.at(map.source), map.name); + DevMsg(eLog::NS, "(%s) %s\n", PrintMapSource.at(map.source), map.name.c_str()); } void InitialiseMapsPrint() diff --git a/NorthstarDLL/util/utils.cpp b/NorthstarDLL/util/utils.cpp index 2c9dc85a0..23906b032 100644 --- a/NorthstarDLL/util/utils.cpp +++ b/NorthstarDLL/util/utils.cpp @@ -80,3 +80,58 @@ void NS::Utils::RemoveAsciiControlSequences(char* str, bool allow_color_codes) *pc = ' '; } } + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +std::string NS::Utils::FormatV(const char* fmt, va_list vArgs) +{ + va_list vArgsCopy; + va_copy(vArgsCopy, vArgs); + int iLen = std::vsnprintf(NULL, 0, fmt, vArgsCopy); + va_end(vArgsCopy); + + std::string svResult; + + if (iLen > 0) + { + svResult.resize(iLen); + std::vsnprintf(svResult.data(), iLen + 1, fmt, vArgs); + } + + return svResult; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +std::string NS::Utils::Format(const char* fmt, ...) +{ + std::string svResult; + + va_list vArgs; + va_start(vArgs, fmt); + svResult = FormatV(fmt, vArgs); + va_end(vArgs); + + return svResult; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +std::string NS::Utils::CreateTimeStamp() +{ + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + + std::chrono::milliseconds ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; + + time_t timer = std::chrono::system_clock::to_time_t(now); + std::tm localtime = *std::localtime(&timer); + + std::ostringstream oss; + oss << std::put_time(&localtime, "%Y-%m-%d_%H-%M-%S"); + oss << '.' << std::setfill('0') << std::setw(3) << ms.count(); + + return oss.str(); +} diff --git a/NorthstarDLL/util/utils.h b/NorthstarDLL/util/utils.h index 97b92f181..8a8ac7246 100644 --- a/NorthstarDLL/util/utils.h +++ b/NorthstarDLL/util/utils.h @@ -3,4 +3,9 @@ namespace NS::Utils { void RemoveAsciiControlSequences(char* str, bool allow_color_codes); -} + + std::string FormatV(const char* fmt, va_list vArgs); + std::string Format(const char* fmt, ...); + + std::string CreateTimeStamp(); +} // namespace NS::Utils diff --git a/thirdparty/spdlog/tweakme.h b/thirdparty/spdlog/tweakme.h index 31e417ab2..5c04715d7 100644 --- a/thirdparty/spdlog/tweakme.h +++ b/thirdparty/spdlog/tweakme.h @@ -55,7 +55,7 @@ /////////////////////////////////////////////////////////////////////////////// // Uncomment to override default eol ("\n" or "\r\n" under Linux/Windows) // -// #define SPDLOG_EOL ";-)\n" +#define SPDLOG_EOL "" /////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////