diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..909fe7c --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Linker files +*.ilk + +# Debugger Files +*.pdb + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a + +# Executables +*.exe +*.out +*.app + +# debug information files +*.dwo diff --git a/Core/Diagnostics/CrashHandler.cpp b/Core/Diagnostics/CrashHandler.cpp new file mode 100644 index 0000000..d4574ae --- /dev/null +++ b/Core/Diagnostics/CrashHandler.cpp @@ -0,0 +1,491 @@ +/** + * UniversalSlashingSimulator - Crash Handler Implementation + */ + +#include "CrashHandler.h" +#include "../Logging/Log.h" + +#include +#include +#include + +#pragma comment(lib, "DbgHelp.lib") + +namespace USS +{ + // Static member initialization + bool FCrashHandler::s_bInitialized = false; + bool FCrashHandler::s_bShowMessageBox = true; + bool FCrashHandler::s_bWriteMinidump = true; + LPTOP_LEVEL_EXCEPTION_FILTER FCrashHandler::s_pPreviousFilter = nullptr; + std::terminate_handler FCrashHandler::s_pPreviousTerminate = nullptr; + + // Maximum frames to capture in callstack + constexpr int MAX_CALLSTACK_FRAMES = 64; + + // ======================================================================== + // Exception Type Conversion + // ======================================================================== + + const char* ExceptionTypeToString(EExceptionType Type) + { + switch (Type) + { + case EExceptionType::CPlusPlusException: return "C++ Exception"; + case EExceptionType::AccessViolation: return "Access Violation"; + case EExceptionType::StackOverflow: return "Stack Overflow"; + case EExceptionType::DivideByZero: return "Divide By Zero"; + case EExceptionType::IllegalInstruction: return "Illegal Instruction"; + case EExceptionType::PrivilegedInstruction: return "Privileged Instruction"; + case EExceptionType::InvalidHandle: return "Invalid Handle"; + case EExceptionType::HeapCorruption: return "Heap Corruption"; + case EExceptionType::PureVirtualCall: return "Pure Virtual Call"; + case EExceptionType::InvalidParameter: return "Invalid Parameter"; + case EExceptionType::Other: return "Other Exception"; + default: return "Unknown Exception"; + } + } + + EExceptionType FCrashHandler::GetExceptionType(DWORD ExceptionCode) + { + switch (ExceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: return EExceptionType::AccessViolation; + case EXCEPTION_STACK_OVERFLOW: return EExceptionType::StackOverflow; + case EXCEPTION_INT_DIVIDE_BY_ZERO: return EExceptionType::DivideByZero; + case EXCEPTION_ILLEGAL_INSTRUCTION: return EExceptionType::IllegalInstruction; + case EXCEPTION_PRIV_INSTRUCTION: return EExceptionType::PrivilegedInstruction; + case EXCEPTION_INVALID_HANDLE: return EExceptionType::InvalidHandle; + case STATUS_HEAP_CORRUPTION: return EExceptionType::HeapCorruption; + case 0xE06D7363: return EExceptionType::CPlusPlusException; // MSVC C++ exception + default: return EExceptionType::Other; + } + } + + // ======================================================================== + // Initialization / Shutdown + // ======================================================================== + + EResult FCrashHandler::Initialize() + { + if (s_bInitialized) + return EResult::AlreadyInitialized; + + SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); + if (!SymInitialize(GetCurrentProcess(), nullptr, TRUE)) + { + // Non-fatal - callstacks just won't have symbol names + OutputDebugStringA("[USS] Warning: SymInitialize failed, callstacks will not have symbol names\n"); + } + + s_pPreviousFilter = SetUnhandledExceptionFilter(UnhandledExceptionHandler); + + s_pPreviousTerminate = std::set_terminate(TerminateHandler); + + _set_purecall_handler(PureCallHandler); + + _set_invalid_parameter_handler(InvalidParameterHandler); + + s_bInitialized = true; + + USS_LOG("Crash handler initialized"); + return EResult::Success; + } + + void FCrashHandler::Shutdown() + { + if (!s_bInitialized) + return; + + if (s_pPreviousFilter) + SetUnhandledExceptionFilter(s_pPreviousFilter); + + if (s_pPreviousTerminate) + std::set_terminate(s_pPreviousTerminate); + + SymCleanup(GetCurrentProcess()); + + s_bInitialized = false; + } + + // ======================================================================== + // Callstack Capture + // ======================================================================== + + void FCrashHandler::CaptureAndLogCallstack(CONTEXT* pContext) + { + void* Stack[MAX_CALLSTACK_FRAMES]; + WORD FrameCount = 0; + + if (pContext) + { + // Use StackWalk64 for more accurate results when we have a context + STACKFRAME64 StackFrame = {}; + DWORD MachineType; + +#ifdef _M_X64 + MachineType = IMAGE_FILE_MACHINE_AMD64; + StackFrame.AddrPC.Offset = pContext->Rip; + StackFrame.AddrPC.Mode = AddrModeFlat; + StackFrame.AddrFrame.Offset = pContext->Rbp; + StackFrame.AddrFrame.Mode = AddrModeFlat; + StackFrame.AddrStack.Offset = pContext->Rsp; + StackFrame.AddrStack.Mode = AddrModeFlat; +#else + MachineType = IMAGE_FILE_MACHINE_I386; + StackFrame.AddrPC.Offset = pContext->Eip; + StackFrame.AddrPC.Mode = AddrModeFlat; + StackFrame.AddrFrame.Offset = pContext->Ebp; + StackFrame.AddrFrame.Mode = AddrModeFlat; + StackFrame.AddrStack.Offset = pContext->Esp; + StackFrame.AddrStack.Mode = AddrModeFlat; +#endif + + HANDLE hProcess = GetCurrentProcess(); + HANDLE hThread = GetCurrentThread(); + + // Make a copy of context since StackWalk64 can modify it + CONTEXT ContextCopy = *pContext; + + for (WORD i = 0; i < MAX_CALLSTACK_FRAMES; ++i) + { + if (!StackWalk64(MachineType, hProcess, hThread, &StackFrame, &ContextCopy, + nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr)) + { + break; + } + + if (StackFrame.AddrPC.Offset == 0) + break; + + Stack[FrameCount++] = reinterpret_cast(StackFrame.AddrPC.Offset); + } + } + else + { + // No context provided, capture current callstack + FrameCount = CaptureStackBackTrace(0, MAX_CALLSTACK_FRAMES, Stack, nullptr); + } + + // Log callstack header + Log::Write(ELogLevel::Fatal, "========== CALLSTACK =========="); + + if (FrameCount == 0) + { + Log::Write(ELogLevel::Fatal, " (No frames captured)"); + return; + } + + // Prepare symbol info buffer + constexpr size_t MaxNameLen = 256; + char SymbolBuffer[sizeof(SYMBOL_INFO) + MaxNameLen]; + SYMBOL_INFO* pSymbol = reinterpret_cast(SymbolBuffer); + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MaxNameLen; + + IMAGEHLP_LINE64 LineInfo = {}; + LineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + HANDLE hProcess = GetCurrentProcess(); + + for (WORD i = 0; i < FrameCount; ++i) + { + DWORD64 Address = reinterpret_cast(Stack[i]); + + // Get module name + HMODULE hModule = nullptr; + char ModuleName[MAX_PATH] = ""; + if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(Address), &hModule)) + { + GetModuleFileNameA(hModule, ModuleName, MAX_PATH); + char* LastSlash = strrchr(ModuleName, '\\'); + if (LastSlash) + memmove(ModuleName, LastSlash + 1, strlen(LastSlash)); + } + + DWORD64 Displacement64 = 0; + const char* SymbolName = ""; + if (SymFromAddr(hProcess, Address, &Displacement64, pSymbol)) + { + SymbolName = pSymbol->Name; + } + + DWORD Displacement32 = 0; + char LocationBuffer[512]; + if (SymGetLineFromAddr64(hProcess, Address, &Displacement32, &LineInfo)) + { + snprintf(LocationBuffer, sizeof(LocationBuffer), + " [%02d] 0x%llX %s!%s + 0x%llX (%s:%lu)", + i, Address, ModuleName, SymbolName, Displacement64, + LineInfo.FileName, LineInfo.LineNumber); + } + else + { + snprintf(LocationBuffer, sizeof(LocationBuffer), + " [%02d] 0x%llX %s!%s + 0x%llX", + i, Address, ModuleName, SymbolName, Displacement64); + } + + Log::Write(ELogLevel::Fatal, "%s", LocationBuffer); + } + + Log::Write(ELogLevel::Fatal, "================================"); + } + + // ======================================================================== + // Exception Info Logging + // ======================================================================== + + void FCrashHandler::LogExceptionInfo(EXCEPTION_POINTERS* pExceptionInfo) + { + if (!pExceptionInfo || !pExceptionInfo->ExceptionRecord) + return; + + EXCEPTION_RECORD* pRecord = pExceptionInfo->ExceptionRecord; + EExceptionType Type = GetExceptionType(pRecord->ExceptionCode); + + Log::Write(ELogLevel::Fatal, ""); + Log::Write(ELogLevel::Fatal, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + Log::Write(ELogLevel::Fatal, "!! UNHANDLED EXCEPTION !!"); + Log::Write(ELogLevel::Fatal, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + Log::Write(ELogLevel::Fatal, ""); + Log::Write(ELogLevel::Fatal, "Exception Type: %s", ExceptionTypeToString(Type)); + Log::Write(ELogLevel::Fatal, "Exception Code: 0x%08X", pRecord->ExceptionCode); + Log::Write(ELogLevel::Fatal, "Exception Address: 0x%llX", reinterpret_cast(pRecord->ExceptionAddress)); + + if (pRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && pRecord->NumberParameters >= 2) + { + const char* AccessType = (pRecord->ExceptionInformation[0] == 0) ? "reading" : + (pRecord->ExceptionInformation[0] == 1) ? "writing" : "executing"; + Log::Write(ELogLevel::Fatal, "Access Type: %s address 0x%llX", AccessType, pRecord->ExceptionInformation[1]); + } + + if (pExceptionInfo->ContextRecord) + { + CONTEXT* pCtx = pExceptionInfo->ContextRecord; + Log::Write(ELogLevel::Fatal, ""); + Log::Write(ELogLevel::Fatal, "========== REGISTERS =========="); +#ifdef _M_X64 + Log::Write(ELogLevel::Fatal, "RAX: 0x%016llX RBX: 0x%016llX", pCtx->Rax, pCtx->Rbx); + Log::Write(ELogLevel::Fatal, "RCX: 0x%016llX RDX: 0x%016llX", pCtx->Rcx, pCtx->Rdx); + Log::Write(ELogLevel::Fatal, "RSI: 0x%016llX RDI: 0x%016llX", pCtx->Rsi, pCtx->Rdi); + Log::Write(ELogLevel::Fatal, "RBP: 0x%016llX RSP: 0x%016llX", pCtx->Rbp, pCtx->Rsp); + Log::Write(ELogLevel::Fatal, "R8: 0x%016llX R9: 0x%016llX", pCtx->R8, pCtx->R9); + Log::Write(ELogLevel::Fatal, "R10: 0x%016llX R11: 0x%016llX", pCtx->R10, pCtx->R11); + Log::Write(ELogLevel::Fatal, "R12: 0x%016llX R13: 0x%016llX", pCtx->R12, pCtx->R13); + Log::Write(ELogLevel::Fatal, "R14: 0x%016llX R15: 0x%016llX", pCtx->R14, pCtx->R15); + Log::Write(ELogLevel::Fatal, "RIP: 0x%016llX", pCtx->Rip); +#else + Log::Write(ELogLevel::Fatal, "EAX: 0x%08X EBX: 0x%08X", pCtx->Eax, pCtx->Ebx); + Log::Write(ELogLevel::Fatal, "ECX: 0x%08X EDX: 0x%08X", pCtx->Ecx, pCtx->Edx); + Log::Write(ELogLevel::Fatal, "ESI: 0x%08X EDI: 0x%08X", pCtx->Esi, pCtx->Edi); + Log::Write(ELogLevel::Fatal, "EBP: 0x%08X ESP: 0x%08X", pCtx->Ebp, pCtx->Esp); + Log::Write(ELogLevel::Fatal, "EIP: 0x%08X", pCtx->Eip); +#endif + Log::Write(ELogLevel::Fatal, "================================"); + } + + Log::Write(ELogLevel::Fatal, ""); + + CaptureAndLogCallstack(pExceptionInfo->ContextRecord); + } + + // ======================================================================== + // Minidump Writing + // ======================================================================== + + void FCrashHandler::WriteMinidumpFile(EXCEPTION_POINTERS* pExceptionInfo) + { + if (!s_bWriteMinidump) + return; + + char DumpPath[MAX_PATH]; + time_t Now = time(nullptr); + struct tm TimeInfo; + localtime_s(&TimeInfo, &Now); + + char Timestamp[64]; + strftime(Timestamp, sizeof(Timestamp), "%Y%m%d_%H%M%S", &TimeInfo); + snprintf(DumpPath, sizeof(DumpPath), "USS_Crash_%s.dmp", Timestamp); + + HANDLE hFile = CreateFileA(DumpPath, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile == INVALID_HANDLE_VALUE) + { + Log::Write(ELogLevel::Fatal, "Failed to create minidump file: %s", DumpPath); + return; + } + + MINIDUMP_EXCEPTION_INFORMATION ExInfo = {}; + ExInfo.ThreadId = GetCurrentThreadId(); + ExInfo.ExceptionPointers = pExceptionInfo; + ExInfo.ClientPointers = FALSE; + + BOOL bSuccess = MiniDumpWriteDump( + GetCurrentProcess(), + GetCurrentProcessId(), + hFile, + static_cast(MiniDumpWithDataSegs | MiniDumpWithHandleData | MiniDumpWithThreadInfo), + pExceptionInfo ? &ExInfo : nullptr, + nullptr, + nullptr); + + CloseHandle(hFile); + + if (bSuccess) + { + Log::Write(ELogLevel::Fatal, "Minidump written to: %s", DumpPath); + } + else + { + Log::Write(ELogLevel::Fatal, "Failed to write minidump (error: %lu)", GetLastError()); + } + } + + // ======================================================================== + // Exception Handlers + // ======================================================================== + + LONG WINAPI FCrashHandler::UnhandledExceptionHandler(EXCEPTION_POINTERS* pExceptionInfo) + { + LogExceptionInfo(pExceptionInfo); + + WriteMinidumpFile(pExceptionInfo); + + if (s_bShowMessageBox) + { + char Message[512]; + EExceptionType Type = GetExceptionType(pExceptionInfo->ExceptionRecord->ExceptionCode); + snprintf(Message, sizeof(Message), + "UniversalSlashingSimulator has crashed!\n\n" + "Exception: %s (0x%08X)\n\n" + "A crash dump has been written.\n" + "Check the log file for detailed callstack information.", + ExceptionTypeToString(Type), + pExceptionInfo->ExceptionRecord->ExceptionCode); + + MessageBoxA(nullptr, Message, "USS Crash", MB_OK | MB_ICONERROR); + } + + if (s_pPreviousFilter) + return s_pPreviousFilter(pExceptionInfo); + + return EXCEPTION_EXECUTE_HANDLER; + } + + void FCrashHandler::TerminateHandler() + { + Log::Write(ELogLevel::Fatal, ""); + Log::Write(ELogLevel::Fatal, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + Log::Write(ELogLevel::Fatal, "!! std::terminate() CALLED !!"); + Log::Write(ELogLevel::Fatal, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + Log::Write(ELogLevel::Fatal, ""); + + std::exception_ptr pException = std::current_exception(); + if (pException) + { + try + { + std::rethrow_exception(pException); + } + catch (const std::exception& e) + { + Log::Write(ELogLevel::Fatal, "C++ Exception: %s", e.what()); + } + catch (...) + { + Log::Write(ELogLevel::Fatal, "Unknown C++ exception"); + } + } + + CaptureAndLogCallstack(nullptr); + + if (s_bShowMessageBox) + { + MessageBoxA(nullptr, + "UniversalSlashingSimulator has terminated unexpectedly!\n\n" + "An unhandled C++ exception occurred.\n\n" + "Check the log file for detailed callstack information.", + "USS Crash", MB_OK | MB_ICONERROR); + } + + if (s_pPreviousTerminate) + s_pPreviousTerminate(); + else + std::abort(); + } + + void FCrashHandler::PureCallHandler() + { + Log::Write(ELogLevel::Fatal, ""); + Log::Write(ELogLevel::Fatal, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + Log::Write(ELogLevel::Fatal, "!! PURE VIRTUAL FUNCTION CALL !!"); + Log::Write(ELogLevel::Fatal, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + Log::Write(ELogLevel::Fatal, ""); + + CaptureAndLogCallstack(nullptr); + + if (s_bShowMessageBox) + { + MessageBoxA(nullptr, + "UniversalSlashingSimulator has crashed!\n\n" + "A pure virtual function was called.\n\n" + "Check the log file for detailed callstack information.", + "USS Crash", MB_OK | MB_ICONERROR); + } + + std::abort(); + } + + void FCrashHandler::InvalidParameterHandler( + const wchar_t* Expression, + const wchar_t* Function, + const wchar_t* File, + unsigned int Line, + uintptr_t Reserved) + { + (void)Reserved; + + Log::Write(ELogLevel::Fatal, ""); + Log::Write(ELogLevel::Fatal, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + Log::Write(ELogLevel::Fatal, "!! INVALID CRT PARAMETER !!"); + Log::Write(ELogLevel::Fatal, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + Log::Write(ELogLevel::Fatal, ""); + + if (Expression) + Log::Write(ELogLevel::Fatal, "Expression: %ls", Expression); + if (Function) + Log::Write(ELogLevel::Fatal, "Function: %ls", Function); + if (File) + Log::Write(ELogLevel::Fatal, "File: %ls:%u", File, Line); + + CaptureAndLogCallstack(nullptr); + + if (s_bShowMessageBox) + { + MessageBoxA(nullptr, + "UniversalSlashingSimulator has crashed!\n\n" + "An invalid parameter was passed to a CRT function.\n\n" + "Check the log file for detailed callstack information.", + "USS Crash", MB_OK | MB_ICONERROR); + } + + std::abort(); + } + + // ======================================================================== + // Manual Dump + // ======================================================================== + + void FCrashHandler::DumpCallstack(const char* Reason) + { + Log::Write(ELogLevel::Warning, ""); + Log::Write(ELogLevel::Warning, "========== MANUAL CALLSTACK DUMP =========="); + if (Reason) + Log::Write(ELogLevel::Warning, "Reason: %s", Reason); + Log::Write(ELogLevel::Warning, ""); + + CaptureAndLogCallstack(nullptr); + } + +} \ No newline at end of file diff --git a/Core/Diagnostics/CrashHandler.h b/Core/Diagnostics/CrashHandler.h new file mode 100644 index 0000000..3d329e7 --- /dev/null +++ b/Core/Diagnostics/CrashHandler.h @@ -0,0 +1,108 @@ +/** + * UniversalSlashingSimulator - Crash Handler + * + * Catches all unhandled exceptions (C++ and SEH) and logs callstack + * information before terminating. Essential for debugging DLL injection issues. + */ + +#pragma once + +#include "../Common.h" + +namespace USS +{ + /** + * Exception types that can be caught + */ + enum class EExceptionType : uint8 + { + Unknown = 0, + CPlusPlusException, // std::exception and derivatives + AccessViolation, // SEH - read/write to invalid memory + StackOverflow, // SEH - stack exhaustion + DivideByZero, // SEH - integer divide by zero + IllegalInstruction, // SEH - invalid CPU instruction + PrivilegedInstruction, // SEH - ring 0 instruction in ring 3 + InvalidHandle, // SEH - invalid handle operation + HeapCorruption, // SEH - heap memory corruption + PureVirtualCall, // C++ - pure virtual function called + InvalidParameter, // CRT - invalid parameter to CRT function + Other // Other SEH exception + }; + + /** + * Convert exception type to string + */ + const char* ExceptionTypeToString(EExceptionType Type); + + /** + * Crash Handler - Global exception handling system + */ + class FCrashHandler + { + public: + /** + * Initialize the crash handler + * Sets up SEH filter, terminate handler, and other exception hooks + * @return Success if initialized + */ + static EResult Initialize(); + + /** + * Shutdown the crash handler + * Restores original exception handlers + */ + static void Shutdown(); + + /** + * Check if crash handler is initialized + */ + static bool IsInitialized() { return s_bInitialized; } + + /** + * Manually trigger a crash dump with current callstack + * Useful for debugging - call this when you detect an error condition + */ + static void DumpCallstack(const char* Reason = nullptr); + + /** + * Set whether to show a message box on crash + * Default is true + */ + static void SetShowMessageBox(bool bShow) { s_bShowMessageBox = bShow; } + + /** + * Set whether to write a minidump file on crash + * Default is true + */ + static void SetWriteMinidump(bool bWrite) { s_bWriteMinidump = bWrite; } + + private: + // Internal handlers + static LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* pExceptionInfo); + static void TerminateHandler(); + static void PureCallHandler(); + static void InvalidParameterHandler( + const wchar_t* Expression, + const wchar_t* Function, + const wchar_t* File, + unsigned int Line, + uintptr_t Reserved); + + // Callstack capture and logging + static void CaptureAndLogCallstack(CONTEXT* pContext = nullptr); + static void LogExceptionInfo(EXCEPTION_POINTERS* pExceptionInfo); + static EExceptionType GetExceptionType(DWORD ExceptionCode); + + // Minidump writing + static void WriteMinidumpFile(EXCEPTION_POINTERS* pExceptionInfo); + + // State + static bool s_bInitialized; + static bool s_bShowMessageBox; + static bool s_bWriteMinidump; + static LPTOP_LEVEL_EXCEPTION_FILTER s_pPreviousFilter; + static std::terminate_handler s_pPreviousTerminate; + }; + +} \ No newline at end of file diff --git a/Entry/DllMain.cpp b/Entry/DllMain.cpp index db55091..ec28a03 100644 --- a/Entry/DllMain.cpp +++ b/Entry/DllMain.cpp @@ -25,6 +25,7 @@ #include "../Core/Common.h" #include "../Core/Logging/Log.h" +#include "../Core/Diagnostics/CrashHandler.h" #include "../Engine/EngineCore.h" #include "../STW/GameMode/STWGameMode.h" #include "../STW/Missions/MissionManager.h" @@ -208,6 +209,7 @@ namespace USS DWORD WINAPI InitializationThread(LPVOID lpParam) { + // Initialize logging first EResult Result = Log::Initialize(true, "USS_Log.txt"); if (Result != EResult::Success) { @@ -215,6 +217,12 @@ namespace USS return 1; } + Result = FCrashHandler::Initialize(); + if (Result != EResult::Success) + { + USS_WARN("Failed to initialize crash handler - crashes may not be logged"); + } + USS_LOG("========================================"); USS_LOG(" UniversalSlashingSimulator v0.1.0"); USS_LOG(" STW Gameserver Framework"); @@ -305,6 +313,8 @@ namespace USS GetEngineCore().Shutdown(); + FCrashHandler::Shutdown(); + Log::Shutdown(); g_bInitialized = false; diff --git a/UniversalSlashingSimulator.vcxproj b/UniversalSlashingSimulator.vcxproj index 3f92ffe..75861ea 100644 --- a/UniversalSlashingSimulator.vcxproj +++ b/UniversalSlashingSimulator.vcxproj @@ -74,7 +74,7 @@ Windows true - psapi.lib;%(AdditionalDependencies) + psapi.lib;dbghelp.lib;%(AdditionalDependencies) $(ProjectDir)external\minhook\lib;%(AdditionalLibraryDirectories) @@ -100,7 +100,7 @@ true true true - psapi.lib;%(AdditionalDependencies) + psapi.lib;dbghelp.lib;%(AdditionalDependencies) $(ProjectDir)external\minhook\lib;%(AdditionalLibraryDirectories) UseLinkTimeCodeGeneration @@ -111,6 +111,7 @@ + @@ -141,6 +142,7 @@ + diff --git a/UniversalSlashingSimulator.vcxproj.filters b/UniversalSlashingSimulator.vcxproj.filters index cc95aba..f543162 100644 --- a/UniversalSlashingSimulator.vcxproj.filters +++ b/UniversalSlashingSimulator.vcxproj.filters @@ -56,8 +56,10 @@ {I7Q6P5R4-3N2M-8Q1L-P0O9-R8Q7P6O5N4M3} + + {0959a4cf-e16b-41c6-8c08-dcc99defca03} + - @@ -70,7 +72,6 @@ Core\Versioning - Engine\CoreTypes @@ -96,7 +97,6 @@ Engine - STW\GameMode @@ -119,13 +119,14 @@ STW\Building - Entry + + Core\Diagnostics + - @@ -150,7 +151,6 @@ Core\Hooks - Engine\CoreTypes @@ -176,7 +176,6 @@ Engine - STW\GameMode @@ -208,5 +207,8 @@ STW\Building + + Core\Diagnostics + - + \ No newline at end of file