diff options
Diffstat (limited to 'NorthstarDLL/logging')
-rw-r--r-- | NorthstarDLL/logging/crashhandler.cpp | 590 | ||||
-rw-r--r-- | NorthstarDLL/logging/crashhandler.h | 97 | ||||
-rw-r--r-- | NorthstarDLL/logging/logging.cpp | 302 | ||||
-rw-r--r-- | NorthstarDLL/logging/logging.h | 136 | ||||
-rw-r--r-- | NorthstarDLL/logging/loghooks.cpp | 261 | ||||
-rw-r--r-- | NorthstarDLL/logging/loghooks.h | 1 | ||||
-rw-r--r-- | NorthstarDLL/logging/sourceconsole.cpp | 91 | ||||
-rw-r--r-- | NorthstarDLL/logging/sourceconsole.h | 85 |
8 files changed, 0 insertions, 1563 deletions
diff --git a/NorthstarDLL/logging/crashhandler.cpp b/NorthstarDLL/logging/crashhandler.cpp deleted file mode 100644 index a01de5a1..00000000 --- a/NorthstarDLL/logging/crashhandler.cpp +++ /dev/null @@ -1,590 +0,0 @@ -#include "crashhandler.h" -#include "config/profile.h" -#include "dedicated/dedicated.h" -#include "util/version.h" -#include "mods/modmanager.h" -#include "plugins/plugins.h" - -#include <minidumpapiset.h> - -#define CRASHHANDLER_MAX_FRAMES 32 -#define CRASHHANDLER_GETMODULEHANDLE_FAIL "GetModuleHandleExA failed!" - -//----------------------------------------------------------------------------- -// Purpose: Vectored exception callback -//----------------------------------------------------------------------------- -LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS* pExceptionInfo) -{ - g_pCrashHandler->Lock(); - - g_pCrashHandler->SetExceptionInfos(pExceptionInfo); - - // Check if we should handle this - // NOTE [Fifty]: This gets called before even a try{} catch() {} can handle an exception - // we don't handle these unless "-crash_handle_all" is passed as a launch arg - if (!g_pCrashHandler->IsExceptionFatal() && !g_pCrashHandler->GetAllFatal()) - { - g_pCrashHandler->Unlock(); - return EXCEPTION_CONTINUE_SEARCH; - } - - // Don't run if a debbuger is attached - if (IsDebuggerPresent()) - { - g_pCrashHandler->Unlock(); - return EXCEPTION_CONTINUE_SEARCH; - } - - // Prevent recursive calls - if (g_pCrashHandler->GetState()) - { - g_pCrashHandler->Unlock(); - ExitProcess(1); - } - - g_pCrashHandler->SetState(true); - - // Needs to be called first as we use the members this sets later on - g_pCrashHandler->SetCrashedModule(); - - // Format - g_pCrashHandler->FormatException(); - g_pCrashHandler->FormatCallstack(); - g_pCrashHandler->FormatRegisters(); - g_pCrashHandler->FormatLoadedMods(); - g_pCrashHandler->FormatLoadedPlugins(); - g_pCrashHandler->FormatModules(); - - // Flush - NS::log::FlushLoggers(); - - // Write minidump - g_pCrashHandler->WriteMinidump(); - - // Show message box - g_pCrashHandler->ShowPopUpMessage(); - - g_pCrashHandler->Unlock(); - - // We showed the "Northstar has crashed" message box - // make sure we terminate - if (!g_pCrashHandler->IsExceptionFatal()) - ExitProcess(1); - - return EXCEPTION_EXECUTE_HANDLER; -} - -//----------------------------------------------------------------------------- -// Purpose: console control signal handler -//----------------------------------------------------------------------------- -BOOL WINAPI ConsoleCtrlRoutine(DWORD dwCtrlType) -{ - // NOTE [Fifty]: When closing the process by closing the console we don't want - // to trigger the crash handler so we remove it - switch (dwCtrlType) - { - case CTRL_CLOSE_EVENT: - spdlog::info("Exiting due to console close..."); - delete g_pCrashHandler; - g_pCrashHandler = nullptr; - std::exit(EXIT_SUCCESS); - return TRUE; - } - - return FALSE; -} - -//----------------------------------------------------------------------------- -// Purpose: Constructor -//----------------------------------------------------------------------------- -CCrashHandler::CCrashHandler() - : m_hExceptionFilter(nullptr) - , m_pExceptionInfos(nullptr) - , m_bHasSetConsolehandler(false) - , m_bAllExceptionsFatal(false) - , m_bHasShownCrashMsg(false) - , m_bState(false) -{ - Init(); -} - -//----------------------------------------------------------------------------- -// Purpose: Destructor -//----------------------------------------------------------------------------- -CCrashHandler::~CCrashHandler() -{ - Shutdown(); -} - -//----------------------------------------------------------------------------- -// Purpose: Initilazes crash handler -//----------------------------------------------------------------------------- -void CCrashHandler::Init() -{ - m_hExceptionFilter = AddVectoredExceptionHandler(TRUE, ExceptionFilter); - m_bHasSetConsolehandler = SetConsoleCtrlHandler(ConsoleCtrlRoutine, TRUE); -} - -//----------------------------------------------------------------------------- -// Purpose: Shutdowns crash handler -//----------------------------------------------------------------------------- -void CCrashHandler::Shutdown() -{ - if (m_hExceptionFilter) - { - RemoveVectoredExceptionHandler(m_hExceptionFilter); - m_hExceptionFilter = nullptr; - } - - if (m_bHasSetConsolehandler) - { - SetConsoleCtrlHandler(ConsoleCtrlRoutine, FALSE); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Sets the exception info -//----------------------------------------------------------------------------- -void CCrashHandler::SetExceptionInfos(EXCEPTION_POINTERS* pExceptionPointers) -{ - m_pExceptionInfos = pExceptionPointers; -} -//----------------------------------------------------------------------------- -// Purpose: Sets the exception stirngs for message box -//----------------------------------------------------------------------------- -void CCrashHandler::SetCrashedModule() -{ - LPCSTR pCrashAddress = static_cast<LPCSTR>(m_pExceptionInfos->ExceptionRecord->ExceptionAddress); - HMODULE hCrashedModule; - if (!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, pCrashAddress, &hCrashedModule)) - { - m_svCrashedModule = CRASHHANDLER_GETMODULEHANDLE_FAIL; - m_svCrashedOffset = ""; - - DWORD dwErrorID = GetLastError(); - if (dwErrorID != 0) - { - LPSTR pszBuffer; - DWORD dwSize = FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - dwErrorID, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&pszBuffer, - 0, - NULL); - - if (dwSize > 0) - { - m_svError = pszBuffer; - LocalFree(pszBuffer); - } - } - - return; - } - - // Get module filename - CHAR szCrashedModulePath[MAX_PATH]; - GetModuleFileNameExA(GetCurrentProcess(), hCrashedModule, szCrashedModulePath, sizeof(szCrashedModulePath)); - - const CHAR* pszCrashedModuleFileName = strrchr(szCrashedModulePath, '\\') + 1; - - // Get relative address - LPCSTR pModuleBase = reinterpret_cast<LPCSTR>(pCrashAddress - reinterpret_cast<LPCSTR>(hCrashedModule)); - - m_svCrashedModule = pszCrashedModuleFileName; - m_svCrashedOffset = fmt::format("{:#x}", reinterpret_cast<DWORD64>(pModuleBase)); -} - -//----------------------------------------------------------------------------- -// Purpose: Gets the exception null terminated stirng -//----------------------------------------------------------------------------- - -const CHAR* CCrashHandler::GetExceptionString() const -{ - return GetExceptionString(m_pExceptionInfos->ExceptionRecord->ExceptionCode); -} - -//----------------------------------------------------------------------------- -// Purpose: Gets the exception null terminated stirng -//----------------------------------------------------------------------------- -const CHAR* CCrashHandler::GetExceptionString(DWORD dwExceptionCode) const -{ - // clang-format off - switch (dwExceptionCode) - { - case EXCEPTION_ACCESS_VIOLATION: return "EXCEPTION_ACCESS_VIOLATION"; - case EXCEPTION_DATATYPE_MISALIGNMENT: return "EXCEPTION_DATATYPE_MISALIGNMENT"; - case EXCEPTION_BREAKPOINT: return "EXCEPTION_BREAKPOINT"; - case EXCEPTION_SINGLE_STEP: return "EXCEPTION_SINGLE_STEP"; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; - case EXCEPTION_FLT_DENORMAL_OPERAND: return "EXCEPTION_FLT_DENORMAL_OPERAND"; - case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; - case EXCEPTION_FLT_INEXACT_RESULT: return "EXCEPTION_FLT_INEXACT_RESULT"; - case EXCEPTION_FLT_INVALID_OPERATION: return "EXCEPTION_FLT_INVALID_OPERATION"; - case EXCEPTION_FLT_OVERFLOW: return "EXCEPTION_FLT_OVERFLOW"; - case EXCEPTION_FLT_STACK_CHECK: return "EXCEPTION_FLT_STACK_CHECK"; - case EXCEPTION_FLT_UNDERFLOW: return "EXCEPTION_FLT_UNDERFLOW"; - case EXCEPTION_INT_DIVIDE_BY_ZERO: return "EXCEPTION_INT_DIVIDE_BY_ZERO"; - case EXCEPTION_INT_OVERFLOW: return "EXCEPTION_INT_OVERFLOW"; - case EXCEPTION_PRIV_INSTRUCTION: return "EXCEPTION_PRIV_INSTRUCTION"; - case EXCEPTION_IN_PAGE_ERROR: return "EXCEPTION_IN_PAGE_ERROR"; - case EXCEPTION_ILLEGAL_INSTRUCTION: return "EXCEPTION_ILLEGAL_INSTRUCTION"; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; - case EXCEPTION_STACK_OVERFLOW: return "EXCEPTION_STACK_OVERFLOW"; - case EXCEPTION_INVALID_DISPOSITION: return "EXCEPTION_INVALID_DISPOSITION"; - case EXCEPTION_GUARD_PAGE: return "EXCEPTION_GUARD_PAGE"; - case EXCEPTION_INVALID_HANDLE: return "EXCEPTION_INVALID_HANDLE"; - case 3765269347: return "RUNTIME_EXCEPTION"; - } - // clang-format on - return "UNKNOWN_EXCEPTION"; -} - -//----------------------------------------------------------------------------- -// Purpose: Returns true if exception is known -//----------------------------------------------------------------------------- -bool CCrashHandler::IsExceptionFatal() const -{ - return IsExceptionFatal(m_pExceptionInfos->ExceptionRecord->ExceptionCode); -} - -//----------------------------------------------------------------------------- -// Purpose: Returns true if exception is known -//----------------------------------------------------------------------------- -bool CCrashHandler::IsExceptionFatal(DWORD dwExceptionCode) const -{ - // clang-format off - switch (dwExceptionCode) - { - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_DATATYPE_MISALIGNMENT: - case EXCEPTION_BREAKPOINT: - case EXCEPTION_SINGLE_STEP: - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - case EXCEPTION_FLT_DENORMAL_OPERAND: - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - case EXCEPTION_FLT_INEXACT_RESULT: - case EXCEPTION_FLT_INVALID_OPERATION: - case EXCEPTION_FLT_OVERFLOW: - case EXCEPTION_FLT_STACK_CHECK: - case EXCEPTION_FLT_UNDERFLOW: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - case EXCEPTION_INT_OVERFLOW: - case EXCEPTION_PRIV_INSTRUCTION: - case EXCEPTION_IN_PAGE_ERROR: - case EXCEPTION_ILLEGAL_INSTRUCTION: - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - case EXCEPTION_STACK_OVERFLOW: - case EXCEPTION_INVALID_DISPOSITION: - case EXCEPTION_GUARD_PAGE: - case EXCEPTION_INVALID_HANDLE: - return true; - } - // clang-format on - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Shows a message box -//----------------------------------------------------------------------------- -void CCrashHandler::ShowPopUpMessage() -{ - if (m_bHasShownCrashMsg) - return; - - m_bHasShownCrashMsg = true; - - if (!IsDedicatedServer()) - { - std::string svMessage = fmt::format( - "Northstar has crashed! Crash info can be found at {}/logs!\n\n{}\n{} + {}", - GetNorthstarPrefix(), - GetExceptionString(), - m_svCrashedModule, - m_svCrashedOffset); - - MessageBoxA(GetForegroundWindow(), svMessage.c_str(), "Northstar has crashed!", MB_ICONERROR | MB_OK); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CCrashHandler::FormatException() -{ - spdlog::error("-------------------------------------------"); - spdlog::error("Northstar has crashed!"); - spdlog::error("\tVersion: {}", version); - if (!m_svError.empty()) - { - spdlog::info("\tEncountered an error when gathering crash information!"); - spdlog::info("\tWinApi Error: {}", m_svError.c_str()); - } - spdlog::error("\t{}", GetExceptionString()); - - DWORD dwExceptionCode = m_pExceptionInfos->ExceptionRecord->ExceptionCode; - if (dwExceptionCode == EXCEPTION_ACCESS_VIOLATION || dwExceptionCode == EXCEPTION_IN_PAGE_ERROR) - { - ULONG_PTR uExceptionInfo0 = m_pExceptionInfos->ExceptionRecord->ExceptionInformation[0]; - ULONG_PTR uExceptionInfo1 = m_pExceptionInfos->ExceptionRecord->ExceptionInformation[1]; - - if (!uExceptionInfo0) - spdlog::error("\tAttempted to read from: {:#x}", uExceptionInfo1); - else if (uExceptionInfo0 == 1) - spdlog::error("\tAttempted to write to: {:#x}", uExceptionInfo1); - else if (uExceptionInfo0 == 8) - spdlog::error("\tData Execution Prevention (DEP) at: {:#x}", uExceptionInfo1); - else - spdlog::error("\tUnknown access violation at: {:#x}", uExceptionInfo1); - } - - spdlog::error("\tAt: {} + {}", m_svCrashedModule, m_svCrashedOffset); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CCrashHandler::FormatCallstack() -{ - spdlog::error("Callstack:"); - - PVOID pFrames[CRASHHANDLER_MAX_FRAMES]; - - int iFrames = RtlCaptureStackBackTrace(0, CRASHHANDLER_MAX_FRAMES, pFrames, NULL); - - // Above call gives us frames after the crash occured, we only want to print the ones starting from where - // the exception was called - bool bSkipExceptionHandlingFrames = true; - - // We ran into an error when getting the offset, just print all frames - if (m_svCrashedOffset.empty()) - bSkipExceptionHandlingFrames = false; - - for (int i = 0; i < iFrames; i++) - { - const CHAR* pszModuleFileName; - - LPCSTR pAddress = static_cast<LPCSTR>(pFrames[i]); - HMODULE hModule; - if (!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, pAddress, &hModule)) - { - pszModuleFileName = CRASHHANDLER_GETMODULEHANDLE_FAIL; - // If we fail here it's too late to do any damage control - } - else - { - CHAR szModulePath[MAX_PATH]; - GetModuleFileNameExA(GetCurrentProcess(), hModule, szModulePath, sizeof(szModulePath)); - pszModuleFileName = strrchr(szModulePath, '\\') + 1; - } - - // Get relative address - LPCSTR pCrashOffset = reinterpret_cast<LPCSTR>(pAddress - reinterpret_cast<LPCSTR>(hModule)); - std::string svCrashOffset = fmt::format("{:#x}", reinterpret_cast<DWORD64>(pCrashOffset)); - - // Should we log this frame - if (bSkipExceptionHandlingFrames) - { - if (m_svCrashedModule == pszModuleFileName && m_svCrashedOffset == svCrashOffset) - { - bSkipExceptionHandlingFrames = false; - } - else - { - continue; - } - } - - // Log module + offset - spdlog::error("\t{} + {:#x}", pszModuleFileName, reinterpret_cast<DWORD64>(pCrashOffset)); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CCrashHandler::FormatFlags(const CHAR* pszRegister, DWORD nValue) -{ - spdlog::error("\t{}: {:#b}", pszRegister, nValue); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CCrashHandler::FormatIntReg(const CHAR* pszRegister, DWORD64 nValue) -{ - spdlog::error("\t{}: {:#x}", pszRegister, nValue); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CCrashHandler::FormatFloatReg(const CHAR* pszRegister, M128A nValue) -{ - DWORD nVec[4] = { - static_cast<DWORD>(nValue.Low & UINT_MAX), - static_cast<DWORD>(nValue.Low >> 32), - static_cast<DWORD>(nValue.High & UINT_MAX), - static_cast<DWORD>(nValue.High >> 32)}; - - spdlog::error( - "\t{}: [ {:G}, {:G}, {:G}, {:G} ]; [ {:#x}, {:#x}, {:#x}, {:#x} ]", - pszRegister, - static_cast<float>(nVec[0]), - static_cast<float>(nVec[1]), - static_cast<float>(nVec[2]), - static_cast<float>(nVec[3]), - nVec[0], - nVec[1], - nVec[2], - nVec[3]); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CCrashHandler::FormatRegisters() -{ - spdlog::error("Registers:"); - - PCONTEXT pContext = m_pExceptionInfos->ContextRecord; - - FormatFlags("Flags:", pContext->ContextFlags); - - FormatIntReg("Rax", pContext->Rax); - FormatIntReg("Rcx", pContext->Rcx); - FormatIntReg("Rdx", pContext->Rdx); - FormatIntReg("Rbx", pContext->Rbx); - FormatIntReg("Rsp", pContext->Rsp); - FormatIntReg("Rbp", pContext->Rbp); - FormatIntReg("Rsi", pContext->Rsi); - FormatIntReg("Rdi", pContext->Rdi); - FormatIntReg("R8 ", pContext->R8); - FormatIntReg("R9 ", pContext->R9); - FormatIntReg("R10", pContext->R10); - FormatIntReg("R11", pContext->R11); - FormatIntReg("R12", pContext->R12); - FormatIntReg("R13", pContext->R13); - FormatIntReg("R14", pContext->R14); - FormatIntReg("R15", pContext->R15); - FormatIntReg("Rip", pContext->Rip); - - FormatFloatReg("Xmm0 ", pContext->Xmm0); - FormatFloatReg("Xmm1 ", pContext->Xmm1); - FormatFloatReg("Xmm2 ", pContext->Xmm2); - FormatFloatReg("Xmm3 ", pContext->Xmm3); - FormatFloatReg("Xmm4 ", pContext->Xmm4); - FormatFloatReg("Xmm5 ", pContext->Xmm5); - FormatFloatReg("Xmm6 ", pContext->Xmm6); - FormatFloatReg("Xmm7 ", pContext->Xmm7); - FormatFloatReg("Xmm8 ", pContext->Xmm8); - FormatFloatReg("Xmm9 ", pContext->Xmm9); - FormatFloatReg("Xmm10", pContext->Xmm10); - FormatFloatReg("Xmm11", pContext->Xmm11); - FormatFloatReg("Xmm12", pContext->Xmm12); - FormatFloatReg("Xmm13", pContext->Xmm13); - FormatFloatReg("Xmm14", pContext->Xmm14); - FormatFloatReg("Xmm15", pContext->Xmm15); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CCrashHandler::FormatLoadedMods() -{ - if (g_pModManager) - { - spdlog::error("Enabled mods:"); - for (const Mod& mod : g_pModManager->m_LoadedMods) - { - if (!mod.m_bEnabled) - continue; - - spdlog::error("\t{}", mod.Name); - } - - spdlog::error("Disabled mods:"); - for (const Mod& mod : g_pModManager->m_LoadedMods) - { - if (mod.m_bEnabled) - continue; - - spdlog::error("\t{}", mod.Name); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CCrashHandler::FormatLoadedPlugins() -{ - if (g_pPluginManager) - { - spdlog::error("Loaded Plugins:"); - for (const Plugin& plugin : g_pPluginManager->m_vLoadedPlugins) - { - spdlog::error("\t{}", plugin.name); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CCrashHandler::FormatModules() -{ - spdlog::error("Loaded modules:"); - HMODULE hModules[1024]; - DWORD cbNeeded; - - if (EnumProcessModules(GetCurrentProcess(), hModules, sizeof(hModules), &cbNeeded)) - { - for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) - { - CHAR szModulePath[MAX_PATH]; - if (GetModuleFileNameExA(GetCurrentProcess(), hModules[i], szModulePath, sizeof(szModulePath))) - { - const CHAR* pszModuleFileName = strrchr(szModulePath, '\\') + 1; - spdlog::error("\t{}", pszModuleFileName); - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Writes minidump to disk -//----------------------------------------------------------------------------- -void CCrashHandler::WriteMinidump() -{ - time_t time = std::time(nullptr); - tm currentTime = *std::localtime(&time); - std::stringstream stream; - stream << std::put_time(¤tTime, (GetNorthstarPrefix() + "/logs/nsdump%Y-%m-%d %H-%M-%S.dmp").c_str()); - - HANDLE hMinidumpFile = CreateFileA(stream.str().c_str(), GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if (hMinidumpFile) - { - MINIDUMP_EXCEPTION_INFORMATION dumpExceptionInfo; - dumpExceptionInfo.ThreadId = GetCurrentThreadId(); - dumpExceptionInfo.ExceptionPointers = m_pExceptionInfos; - dumpExceptionInfo.ClientPointers = false; - - MiniDumpWriteDump( - GetCurrentProcess(), - GetCurrentProcessId(), - hMinidumpFile, - MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory), - &dumpExceptionInfo, - nullptr, - nullptr); - CloseHandle(hMinidumpFile); - } - else - spdlog::error("Failed to write minidump file {}!", stream.str()); -} - -//----------------------------------------------------------------------------- -CCrashHandler* g_pCrashHandler = nullptr; diff --git a/NorthstarDLL/logging/crashhandler.h b/NorthstarDLL/logging/crashhandler.h deleted file mode 100644 index c059a8ca..00000000 --- a/NorthstarDLL/logging/crashhandler.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include <mutex> - -//----------------------------------------------------------------------------- -// Purpose: Exception handling -//----------------------------------------------------------------------------- -class CCrashHandler -{ -public: - CCrashHandler(); - ~CCrashHandler(); - - void Init(); - void Shutdown(); - - void Lock() - { - m_Mutex.lock(); - } - - void Unlock() - { - m_Mutex.unlock(); - } - - void SetState(bool bState) - { - m_bState = bState; - } - - bool GetState() const - { - return m_bState; - } - - void SetAllFatal(bool bState) - { - m_bAllExceptionsFatal = bState; - } - - bool GetAllFatal() const - { - return m_bAllExceptionsFatal; - } - - //----------------------------------------------------------------------------- - // Exception helpers - //----------------------------------------------------------------------------- - void SetExceptionInfos(EXCEPTION_POINTERS* pExceptionPointers); - - void SetCrashedModule(); - - const CHAR* GetExceptionString() const; - const CHAR* GetExceptionString(DWORD dwExceptionCode) const; - - bool IsExceptionFatal() const; - bool IsExceptionFatal(DWORD dwExceptionCode) const; - - //----------------------------------------------------------------------------- - // Formatting - //----------------------------------------------------------------------------- - void ShowPopUpMessage(); - - void FormatException(); - void FormatCallstack(); - void FormatFlags(const CHAR* pszRegister, DWORD nValue); - void FormatIntReg(const CHAR* pszRegister, DWORD64 nValue); - void FormatFloatReg(const CHAR* pszRegister, M128A nValue); - void FormatRegisters(); - void FormatLoadedMods(); - void FormatLoadedPlugins(); - void FormatModules(); - - //----------------------------------------------------------------------------- - // Minidump - //----------------------------------------------------------------------------- - void WriteMinidump(); - -private: - PVOID m_hExceptionFilter; - EXCEPTION_POINTERS* m_pExceptionInfos; - - bool m_bHasSetConsolehandler; - bool m_bAllExceptionsFatal; - bool m_bHasShownCrashMsg; - bool m_bState; - - std::string m_svCrashedModule; - std::string m_svCrashedOffset; - - std::string m_svError; - - std::mutex m_Mutex; -}; - -extern CCrashHandler* g_pCrashHandler; diff --git a/NorthstarDLL/logging/logging.cpp b/NorthstarDLL/logging/logging.cpp deleted file mode 100644 index 3416bb8c..00000000 --- a/NorthstarDLL/logging/logging.cpp +++ /dev/null @@ -1,302 +0,0 @@ -#include "logging.h" -#include "core/convar/convar.h" -#include "core/convar/concommand.h" -#include "config/profile.h" -#include "core/tier0.h" -#include "util/version.h" -#include "spdlog/sinks/basic_file_sink.h" - -#include <winternl.h> -#include <cstdlib> -#include <iomanip> -#include <sstream> - -AUTOHOOK_INIT() - -std::vector<std::shared_ptr<ColoredLogger>> loggers {}; - -namespace NS::log -{ - std::shared_ptr<ColoredLogger> SCRIPT_UI; - std::shared_ptr<ColoredLogger> SCRIPT_CL; - std::shared_ptr<ColoredLogger> SCRIPT_SV; - - std::shared_ptr<ColoredLogger> NATIVE_UI; - std::shared_ptr<ColoredLogger> NATIVE_CL; - std::shared_ptr<ColoredLogger> NATIVE_SV; - std::shared_ptr<ColoredLogger> NATIVE_EN; - - std::shared_ptr<ColoredLogger> fs; - std::shared_ptr<ColoredLogger> rpak; - std::shared_ptr<ColoredLogger> echo; - - std::shared_ptr<ColoredLogger> NORTHSTAR; - std::shared_ptr<ColoredLogger> PLUGINSYS; -}; // namespace NS::log - -// This needs to be called after hooks are loaded so we can access the command line args -void CreateLogFiles() -{ - if (strstr(GetCommandLineA(), "-disablelogs")) - { - spdlog::default_logger()->set_level(spdlog::level::off); - } - else - { - 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<spdlog::sinks::basic_file_sink_mt>(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); - } - } -} - -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!"); -} - -void ExternalConsoleSink::custom_sink_it_(const custom_log_msg& msg) -{ - spdlog::memory_buf_t formatted; - spdlog::sinks::base_sink<std::mutex>::formatter_->format(msg, formatted); - - std::string out = ""; - // if ansi colour is turned off, just use WriteConsoleA and return - if (!g_bSpdLog_UseAnsiColor) - { - out += fmt::to_string(formatted); - } - - // print to the console with colours - 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()}; - - 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); - - 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); - - 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; -} - -void ExternalConsoleSink::flush_() -{ - std::cout << std::flush; -} - -void CustomSink::custom_log(const custom_log_msg& msg) -{ - std::lock_guard<std::mutex> lock(mutex_); - custom_sink_it_(msg); -} - -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); - } - - // this if statement is adapted from r5sdk - if (!strstr(GetCommandLineA(), "-noansiclr")) - { - 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 '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; - } - } -} - -void RegisterLogger(std::shared_ptr<ColoredLogger> logger) -{ - loggers.push_back(logger); -} - -void RegisterCustomSink(std::shared_ptr<CustomSink> sink) -{ - for (auto& logger : loggers) - { - logger->custom_sinks_.push_back(sink); - } -}; - -void InitialiseLogging() -{ - // create a logger, and set it to default - NS::log::NORTHSTAR = std::make_shared<ColoredLogger>("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<ExternalConsoleSink>(); - // 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<ColoredLogger>("SCRIPT UI", NS::Colors::SCRIPT_UI); - NS::log::SCRIPT_CL = std::make_shared<ColoredLogger>("SCRIPT CL", NS::Colors::SCRIPT_CL); - NS::log::SCRIPT_SV = std::make_shared<ColoredLogger>("SCRIPT SV", NS::Colors::SCRIPT_SV); - - NS::log::NATIVE_UI = std::make_shared<ColoredLogger>("NATIVE UI", NS::Colors::NATIVE_UI); - NS::log::NATIVE_CL = std::make_shared<ColoredLogger>("NATIVE CL", NS::Colors::NATIVE_CL); - NS::log::NATIVE_SV = std::make_shared<ColoredLogger>("NATIVE SV", NS::Colors::NATIVE_SV); - NS::log::NATIVE_EN = std::make_shared<ColoredLogger>("NATIVE EN", NS::Colors::NATIVE_ENGINE); - - NS::log::fs = std::make_shared<ColoredLogger>("FILESYSTM", NS::Colors::FILESYSTEM); - NS::log::rpak = std::make_shared<ColoredLogger>("RPAK_FSYS", NS::Colors::RPAK); - NS::log::echo = std::make_shared<ColoredLogger>("ECHO", NS::Colors::ECHO); - - NS::log::PLUGINSYS = std::make_shared<ColoredLogger>("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); - - loggers.push_back(NS::log::fs); - loggers.push_back(NS::log::rpak); - loggers.push_back(NS::log::echo); -} - -void NS::log::FlushLoggers() -{ - for (auto& logger : loggers) - logger->flush(); - - spdlog::default_logger()->flush(); -} - -// 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; - -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() -{ - spdlog::info("NorthstarLauncher version: {}", version); - spdlog::info("Command line: {}", GetCommandLineA()); - spdlog::info("Using profile: {}", GetNorthstarPrefix()); - - HMODULE ntdll = GetModuleHandleA("ntdll.dll"); - if (!ntdll) - { - // How did we get here - spdlog::info("Operating System: Unknown"); - return; - } - - wine_get_host_version = (wine_get_host_version_type)GetProcAddress(ntdll, "wine_get_host_version"); - if (wine_get_host_version) - { - // Load the rest of the functions we need - wine_get_build_id = (wine_get_build_id_type)GetProcAddress(ntdll, "wine_get_build_id"); - - const char* sysname; - wine_get_host_version(&sysname, NULL); - - spdlog::info("Operating System: {} (Wine)", sysname); - spdlog::info("Wine build: {}", 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 - // We extract the basename out of it to get the name used - char* compatToolPtr = std::getenv("STEAM_COMPAT_TOOL_PATHS"); - if (compatToolPtr) - { - std::string_view compatToolPath(compatToolPtr); - - auto protonBasenameEnd = compatToolPath.find(":"); - if (protonBasenameEnd == std::string_view::npos) - protonBasenameEnd = 0; - auto protonBasenameStart = compatToolPath.rfind("/", protonBasenameEnd) + 1; - if (protonBasenameStart == std::string_view::npos) - protonBasenameStart = 0; - - spdlog::info("Proton build: {}", compatToolPath.substr(protonBasenameStart, protonBasenameEnd - protonBasenameStart)); - } - } - else - { - // We are real Windows (hopefully) - const char* win_ver = "Unknown"; - - RTL_OSVERSIONINFOW osvi; - osvi.dwOSVersionInfoSize = sizeof(osvi); - - RtlGetVersion = (RtlGetVersion_type)GetProcAddress(ntdll, "RtlGetVersion"); - if (RtlGetVersion && !RtlGetVersion(&osvi)) - { - // 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); - } - else - { - spdlog::info("Operating System: Windows"); - } - } -} diff --git a/NorthstarDLL/logging/logging.h b/NorthstarDLL/logging/logging.h deleted file mode 100644 index 5056af27..00000000 --- a/NorthstarDLL/logging/logging.h +++ /dev/null @@ -1,136 +0,0 @@ -#pragma once -#include "spdlog/sinks/base_sink.h" -#include "spdlog/logger.h" -#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<std::mutex> -{ -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<std::shared_ptr<CustomSink>> 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<ColoredLogger>(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<ColoredLogger> SCRIPT_UI; - extern std::shared_ptr<ColoredLogger> SCRIPT_CL; - extern std::shared_ptr<ColoredLogger> SCRIPT_SV; - - // Native code - extern std::shared_ptr<ColoredLogger> NATIVE_UI; - extern std::shared_ptr<ColoredLogger> NATIVE_CL; - extern std::shared_ptr<ColoredLogger> NATIVE_SV; - extern std::shared_ptr<ColoredLogger> NATIVE_EN; - - // File system - extern std::shared_ptr<ColoredLogger> fs; - // RPak - extern std::shared_ptr<ColoredLogger> rpak; - // Echo - extern std::shared_ptr<ColoredLogger> echo; - - extern std::shared_ptr<ColoredLogger> NORTHSTAR; - - extern std::shared_ptr<ColoredLogger> PLUGINSYS; - - void FlushLoggers(); -}; // namespace NS::log - -void RegisterCustomSink(std::shared_ptr<CustomSink> sink); -void RegisterLogger(std::shared_ptr<ColoredLogger> 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<spdlog::level::level_enum, std::string> 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; -}; diff --git a/NorthstarDLL/logging/loghooks.cpp b/NorthstarDLL/logging/loghooks.cpp deleted file mode 100644 index 7efb5b99..00000000 --- a/NorthstarDLL/logging/loghooks.cpp +++ /dev/null @@ -1,261 +0,0 @@ -#include "logging.h" -#include "loghooks.h" -#include "core/convar/convar.h" -#include "core/convar/concommand.h" -#include "core/math/bitbuf.h" -#include "config/profile.h" -#include "core/tier0.h" -#include "squirrel/squirrel.h" -#include <iomanip> -#include <sstream> - -AUTOHOOK_INIT() - -ConVar* Cvar_spewlog_enable; -ConVar* Cvar_cl_showtextmsg; - -enum class TextMsgPrintType_t -{ - HUD_PRINTNOTIFY = 1, - HUD_PRINTCONSOLE, - HUD_PRINTTALK, - HUD_PRINTCENTER -}; - -class ICenterPrint -{ -public: - virtual void ctor() = 0; - virtual void Clear(void) = 0; - virtual void ColorPrint(int r, int g, int b, int a, wchar_t* text) = 0; - virtual void ColorPrint(int r, int g, int b, int a, char* text) = 0; - virtual void Print(wchar_t* text) = 0; - virtual void Print(char* text) = 0; - virtual void SetTextColor(int r, int g, int b, int a) = 0; -}; - -enum class SpewType_t -{ - SPEW_MESSAGE = 0, - - SPEW_WARNING, - SPEW_ASSERT, - SPEW_ERROR, - SPEW_LOG, - - SPEW_TYPE_COUNT -}; - -const std::unordered_map<SpewType_t, const char*> PrintSpewTypes = { - {SpewType_t::SPEW_MESSAGE, "SPEW_MESSAGE"}, - {SpewType_t::SPEW_WARNING, "SPEW_WARNING"}, - {SpewType_t::SPEW_ASSERT, "SPEW_ASSERT"}, - {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<SpewType_t, spdlog::level::level_enum> 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<SpewType_t, const char> PrintSpewTypes_Short = { - {SpewType_t::SPEW_MESSAGE, 'M'}, - {SpewType_t::SPEW_WARNING, 'W'}, - {SpewType_t::SPEW_ASSERT, 'A'}, - {SpewType_t::SPEW_ERROR, 'E'}, - {SpewType_t::SPEW_LOG, 'L'}}; - -ICenterPrint* pInternalCenterPrint = NULL; - -// clang-format off -AUTOHOOK(TextMsg, client.dll + 0x198710, -void,, (BFRead* msg)) -// clang-format on -{ - TextMsgPrintType_t msg_dest = (TextMsgPrintType_t)msg->ReadByte(); - - char text[256]; - msg->ReadString(text, sizeof(text)); - - if (!Cvar_cl_showtextmsg->GetBool()) - return; - - switch (msg_dest) - { - case TextMsgPrintType_t::HUD_PRINTCENTER: - pInternalCenterPrint->Print(text); - break; - - default: - spdlog::warn("Unimplemented TextMsg type {}! printing to console", msg_dest); - [[fallthrough]]; - - case TextMsgPrintType_t::HUD_PRINTCONSOLE: - auto endpos = strlen(text); - if (text[endpos - 1] == '\n') - text[endpos - 1] = '\0'; // cut off repeated newline - - spdlog::info(text); - break; - } -} - -// clang-format off -AUTOHOOK(Hook_fprintf, engine.dll + 0x51B1F0, -int,, (void* const stream, const char* const format, ...)) -// clang-format on -{ - va_list va; - va_start(va, format); - - SQChar buf[1024]; - int charsWritten = vsnprintf_s(buf, _TRUNCATE, format, va); - - if (charsWritten > 0) - { - if (buf[charsWritten - 1] == '\n') - buf[charsWritten - 1] = '\0'; - NS::log::NATIVE_EN->info("{}", buf); - } - - va_end(va); - return 0; -} - -// clang-format off -AUTOHOOK(ConCommand_echo, engine.dll + 0x123680, -void,, (const CCommand& arg)) -// clang-format on -{ - if (arg.ArgC() >= 2) - NS::log::echo->info("{}", arg.ArgS()); -} - -// clang-format off -AUTOHOOK(EngineSpewFunc, engine.dll + 0x11CA80, -void, __fastcall, (void* pEngineServer, SpewType_t type, const char* format, va_list args)) -// clang-format on -{ - if (!Cvar_spewlog_enable->GetBool()) - return; - - const char* typeStr = PrintSpewTypes.at(type); - char formatted[2048] = {0}; - bool bShouldFormat = true; - - // because titanfall 2 is quite possibly the worst thing to yet exist, it sometimes gives invalid specifiers which will crash - // ttf2sdk had a way to prevent them from crashing but it doesnt work in debug builds - // so we use this instead - for (int i = 0; format[i]; i++) - { - if (format[i] == '%') - { - switch (format[i + 1]) - { - // this is fucking awful lol - case 'd': - case 'i': - case 'u': - case 'x': - case 'X': - case 'f': - case 'F': - case 'g': - case 'G': - case 'a': - case 'A': - case 'c': - case 's': - case 'p': - case 'n': - case '%': - case '-': - case '+': - case ' ': - case '#': - case '*': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - break; - - default: - { - bShouldFormat = false; - break; - } - } - } - } - - if (bShouldFormat) - vsnprintf(formatted, sizeof(formatted), format, args); - else - spdlog::warn("Failed to format {} \"{}\"", 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); -} - -// used for printing the output of status -// clang-format off -AUTOHOOK(Status_ConMsg, engine.dll + 0x15ABD0, -void,, (const char* text, ...)) -// clang-format on -{ - char formatted[2048]; - va_list list; - - va_start(list, text); - vsprintf_s(formatted, text, list); - va_end(list); - - auto endpos = strlen(formatted); - if (formatted[endpos - 1] == '\n') - formatted[endpos - 1] = '\0'; // cut off repeated newline - - spdlog::info(formatted); -} - -// clang-format off -AUTOHOOK(CClientState_ProcessPrint, engine.dll + 0x1A1530, -bool,, (void* thisptr, uintptr_t msg)) -// clang-format on -{ - char* text = *(char**)(msg + 0x20); - - auto endpos = strlen(text); - if (text[endpos - 1] == '\n') - text[endpos - 1] = '\0'; // cut off repeated newline - - spdlog::info(text); - return true; -} - -ON_DLL_LOAD_RELIESON("engine.dll", EngineSpewFuncHooks, ConVar, (CModule module)) -{ - AUTOHOOK_DISPATCH_MODULE(engine.dll) - - Cvar_spewlog_enable = new ConVar("spewlog_enable", "0", FCVAR_NONE, "Enables/disables whether the engine spewfunc should be logged"); -} - -ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ClientPrintHooks, ConVar, (CModule module)) -{ - AUTOHOOK_DISPATCH_MODULE(client.dll) - - Cvar_cl_showtextmsg = new ConVar("cl_showtextmsg", "1", FCVAR_NONE, "Enable/disable text messages printing on the screen."); - pInternalCenterPrint = module.Offset(0x216E940).RCast<ICenterPrint*>(); -} diff --git a/NorthstarDLL/logging/loghooks.h b/NorthstarDLL/logging/loghooks.h deleted file mode 100644 index 6f70f09b..00000000 --- a/NorthstarDLL/logging/loghooks.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/NorthstarDLL/logging/sourceconsole.cpp b/NorthstarDLL/logging/sourceconsole.cpp deleted file mode 100644 index e436d1d4..00000000 --- a/NorthstarDLL/logging/sourceconsole.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "core/convar/convar.h" -#include "sourceconsole.h" -#include "core/sourceinterface.h" -#include "core/convar/concommand.h" -#include "util/printcommands.h" - -SourceInterface<CGameConsole>* g_pSourceGameConsole; - -void ConCommand_toggleconsole(const CCommand& arg) -{ - if ((*g_pSourceGameConsole)->IsConsoleVisible()) - (*g_pSourceGameConsole)->Hide(); - else - (*g_pSourceGameConsole)->Activate(); -} - -void ConCommand_showconsole(const CCommand& arg) -{ - (*g_pSourceGameConsole)->Activate(); -} - -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<std::mutex>::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)) -// clang-format on -{ - consoleDialog->m_pConsolePanel->Print("] "); - consoleDialog->m_pConsolePanel->Print(pCommand); - consoleDialog->m_pConsolePanel->Print("\n"); - - TryPrintCvarHelpForCommand(pCommand); - - OnCommandSubmitted(consoleDialog, pCommand); -} - -// called from sourceinterface.cpp in client createinterface hooks, on GameClientExports001 -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<SourceConsoleSink>(); - 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)) -{ - g_pSourceGameConsole = new SourceInterface<CGameConsole>("client.dll", "GameConsole004"); - - RegisterConCommand("toggleconsole", ConCommand_toggleconsole, "Show/hide the console.", FCVAR_DONTRECORD); - RegisterConCommand("showconsole", ConCommand_showconsole, "Show the console.", FCVAR_DONTRECORD); - RegisterConCommand("hideconsole", ConCommand_hideconsole, "Hide the console.", FCVAR_DONTRECORD); -} diff --git a/NorthstarDLL/logging/sourceconsole.h b/NorthstarDLL/logging/sourceconsole.h deleted file mode 100644 index 44d73843..00000000 --- a/NorthstarDLL/logging/sourceconsole.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once -#include "core/sourceinterface.h" -#include "spdlog/sinks/base_sink.h" -#include <map> - -class EditablePanel -{ -public: - virtual ~EditablePanel() = 0; - unsigned char unknown[0x2B0]; -}; - -class IConsoleDisplayFunc -{ -public: - virtual void ColorPrint(const SourceColor& clr, const char* pMessage) = 0; - virtual void Print(const char* pMessage) = 0; - virtual void DPrint(const char* pMessage) = 0; -}; - -class CConsolePanel : public EditablePanel, public IConsoleDisplayFunc -{ -}; - -class CConsoleDialog -{ -public: - struct VTable - { - void* unknown[298]; - void (*OnCommandSubmitted)(CConsoleDialog* consoleDialog, const char* pCommand); - }; - - VTable* m_vtable; - unsigned char unknown[0x398]; - CConsolePanel* m_pConsolePanel; -}; - -class CGameConsole -{ -public: - virtual ~CGameConsole() = 0; - - // activates the console, makes it visible and brings it to the foreground - virtual void Activate() = 0; - - virtual void Initialize() = 0; - - // hides the console - virtual void Hide() = 0; - - // clears the console - virtual void Clear() = 0; - - // return true if the console has focus - virtual bool IsConsoleVisible() = 0; - - virtual void SetParent(int parent) = 0; - - bool m_bInitialized; - CConsoleDialog* m_pConsole; -}; - -extern SourceInterface<CGameConsole>* g_pSourceGameConsole; - -// spdlog logger -class SourceConsoleSink : public CustomSink -{ -private: - std::map<spdlog::level::level_enum, SourceColor> 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(); |