mirror of
				https://github.com/JezuzLizard/T4SP-Server-Plugin.git
				synced 2025-11-04 03:27:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			142 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include <stdinc.hpp>
 | 
						|
#include "loader/component_loader.hpp"
 | 
						|
 | 
						|
#include <utils/hook.hpp>
 | 
						|
#include <utils/io.hpp>
 | 
						|
#include <utils/string.hpp>
 | 
						|
#include <utils/thread.hpp>
 | 
						|
#include <utils/compression.hpp>
 | 
						|
 | 
						|
#include <exception/minidump.hpp>
 | 
						|
 | 
						|
namespace exception
 | 
						|
{
 | 
						|
	namespace
 | 
						|
	{
 | 
						|
		thread_local struct
 | 
						|
		{
 | 
						|
			DWORD code = 0;
 | 
						|
			PVOID address = nullptr;
 | 
						|
		} exception_data;
 | 
						|
 | 
						|
		void show_mouse_cursor()
 | 
						|
		{
 | 
						|
			while (ShowCursor(TRUE) < 0);
 | 
						|
		}
 | 
						|
 | 
						|
		void display_error_dialog()
 | 
						|
		{
 | 
						|
			std::string error_str = utils::string::va("Fatal error (0x%08X) at 0x%p.\n"
 | 
						|
													  "A minidump has been written.\n\n",
 | 
						|
													  exception_data.code, exception_data.address);
 | 
						|
 | 
						|
			error_str += "Make sure to update your graphics card drivers and install operating system updates!";
 | 
						|
 | 
						|
			utils::thread::suspend_other_threads();
 | 
						|
			show_mouse_cursor();
 | 
						|
			MessageBoxA(nullptr, error_str.data(), "Plutonium T4 ERROR", MB_ICONERROR);
 | 
						|
			TerminateProcess(GetCurrentProcess(), exception_data.code);
 | 
						|
		}
 | 
						|
 | 
						|
		void reset_state()
 | 
						|
		{
 | 
						|
			display_error_dialog();
 | 
						|
		}
 | 
						|
 | 
						|
		size_t get_reset_state_stub()
 | 
						|
		{
 | 
						|
			static auto* stub = utils::hook::assemble([](utils::hook::assembler& a)
 | 
						|
			{
 | 
						|
				a.sub(esp, 0x10);
 | 
						|
				a.or_(esp, 0x8);
 | 
						|
				a.jmp(reset_state);
 | 
						|
			});
 | 
						|
 | 
						|
			return reinterpret_cast<size_t>(stub);
 | 
						|
		}
 | 
						|
 | 
						|
		std::string generate_crash_info(const LPEXCEPTION_POINTERS exceptioninfo)
 | 
						|
		{
 | 
						|
			std::string info{};
 | 
						|
			const auto line = [&info](const std::string& text)
 | 
						|
			{
 | 
						|
				info.append(text);
 | 
						|
				info.append("\r\n");
 | 
						|
			};
 | 
						|
 | 
						|
			line("Plutonium T4 Crash Dump");
 | 
						|
			line("");
 | 
						|
			line("Timestamp: "s + utils::string::get_timestamp());
 | 
						|
			line(utils::string::va("Exception: 0x%08X", exceptioninfo->ExceptionRecord->ExceptionCode));
 | 
						|
			line(utils::string::va("Address: 0x%lX", exceptioninfo->ExceptionRecord->ExceptionAddress));
 | 
						|
 | 
						|
			line("");
 | 
						|
			line(build_gsc_dump(game::SCRIPTINSTANCE_SERVER));
 | 
						|
			line("");
 | 
						|
 | 
						|
#pragma warning(push)
 | 
						|
#pragma warning(disable: 4996)
 | 
						|
			OSVERSIONINFOEXA version_info;
 | 
						|
			ZeroMemory(&version_info, sizeof(version_info));
 | 
						|
			version_info.dwOSVersionInfoSize = sizeof(version_info);
 | 
						|
			GetVersionExA(reinterpret_cast<LPOSVERSIONINFOA>(&version_info));
 | 
						|
#pragma warning(pop)
 | 
						|
 | 
						|
			line(utils::string::va("OS Version: %u.%u", version_info.dwMajorVersion, version_info.dwMinorVersion));
 | 
						|
 | 
						|
			return info;
 | 
						|
		}
 | 
						|
 | 
						|
		void write_minidump(const LPEXCEPTION_POINTERS exceptioninfo)
 | 
						|
		{
 | 
						|
			const std::string crash_name = utils::string::va("t4sp-server-plugin/minidumps/plutonium-t4-crash-%s.zip",
 | 
						|
															 utils::string::get_timestamp().data());
 | 
						|
 | 
						|
			utils::compression::zip::archive zip_file{};
 | 
						|
			zip_file.add("crash.dmp", create_minidump(exceptioninfo));
 | 
						|
			zip_file.add("info.txt", generate_crash_info(exceptioninfo));
 | 
						|
			zip_file.write(crash_name, "Plutonium T4 Crash Dump");
 | 
						|
		}
 | 
						|
 | 
						|
		bool is_harmless_error(const LPEXCEPTION_POINTERS exceptioninfo)
 | 
						|
		{
 | 
						|
			const auto code = exceptioninfo->ExceptionRecord->ExceptionCode;
 | 
						|
			return code == STATUS_INTEGER_OVERFLOW || code == STATUS_FLOAT_OVERFLOW || code == STATUS_SINGLE_STEP;
 | 
						|
		}
 | 
						|
 | 
						|
		LONG WINAPI exception_filter(const LPEXCEPTION_POINTERS exceptioninfo)
 | 
						|
		{
 | 
						|
			if (is_harmless_error(exceptioninfo))
 | 
						|
			{
 | 
						|
				return EXCEPTION_CONTINUE_EXECUTION;
 | 
						|
			}
 | 
						|
 | 
						|
			write_minidump(exceptioninfo);
 | 
						|
 | 
						|
			exception_data.code = exceptioninfo->ExceptionRecord->ExceptionCode;
 | 
						|
			exception_data.address = exceptioninfo->ExceptionRecord->ExceptionAddress;
 | 
						|
			exceptioninfo->ContextRecord->Eip = get_reset_state_stub();
 | 
						|
 | 
						|
			return EXCEPTION_CONTINUE_EXECUTION;
 | 
						|
		}
 | 
						|
 | 
						|
		LPTOP_LEVEL_EXCEPTION_FILTER WINAPI set_unhandled_exception_filter_stub(LPTOP_LEVEL_EXCEPTION_FILTER)
 | 
						|
		{
 | 
						|
			// Don't register anything here...
 | 
						|
			return &exception_filter;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	class component final : public component_interface
 | 
						|
	{
 | 
						|
	public:
 | 
						|
		void post_unpack() override
 | 
						|
		{
 | 
						|
		   SetUnhandledExceptionFilter(exception_filter);
 | 
						|
		   utils::hook::jump(reinterpret_cast<uintptr_t>(&SetUnhandledExceptionFilter), set_unhandled_exception_filter_stub);
 | 
						|
		}
 | 
						|
	};
 | 
						|
}
 | 
						|
 | 
						|
REGISTER_COMPONENT(exception::component)
 |