diff --git a/include/RE/C/ConsoleLog.h b/include/RE/C/ConsoleLog.h index c19c1c58..b535b653 100644 --- a/include/RE/C/ConsoleLog.h +++ b/include/RE/C/ConsoleLog.h @@ -1,40 +1,66 @@ #pragma once +#include "RE/B/BSTEvent.h" +#include "RE/B/BSTSingleton.h" +#include "RE/B/BSStringT.h" + namespace RE { - class ConsoleLog + struct ConsoleLogAddEvent; + + class __declspec(novtable) ConsoleLog : + public BSTSingletonSDM, + public BSTEventSource { public: SF_RTTI_VTABLE(ConsoleLog); - // BSTSDM + virtual ~ConsoleLog(); // 00 + [[nodiscard]] static ConsoleLog* GetSingleton() { - static REL::Relocation singleton{ ID::ConsoleLog::singleton }; + static REL::Relocation singleton{ ID::ConsoleLog::Singleton }; return *singleton; } - void VPrint(const char* a_fmt, std::va_list a_args) + void AddString(const char* a_str) + { + using func_t = decltype(&ConsoleLog::AddString); + static REL::Relocation func{ ID::ConsoleLog::AddString }; + func(this, a_str); + } + + void Print(const char* a_fmt, std::va_list a_args) { - using func_t = decltype(&ConsoleLog::VPrint); - static REL::Relocation func{ ID::ConsoleLog::VPrint }; + using func_t = decltype(&ConsoleLog::Print); + static REL::Relocation func{ ID::ConsoleLog::Print }; func(this, a_fmt, a_args); } - // printf format rules, no compile time checking - void Print(const char* a_fmt, ...) + // std::printf rules, no compile time checking + void PrintLine(const char* a_fmt, ...) { std::va_list args; va_start(args, a_fmt); - VPrint(a_fmt, args); + Print(a_fmt, args); va_end(args); } - // std::format rules, compile time checking + // std::format rules, has compile time checking template void Log(const std::format_string a_fmt, Args&&... a_args) { - Print(std::vformat(a_fmt.get(), std::make_format_args(a_args...)).c_str()); + AddString(std::vformat(a_fmt.get(), std::make_format_args(a_args...)).c_str()); } + + void SetUseConsoleOverlay(bool a_value) + { + useConsoleOverlay = a_value; + } + + // members + BSStringT buffer; // 38 + bool useConsoleOverlay; // 48 }; + static_assert(sizeof(ConsoleLog) == 0x48); } diff --git a/include/RE/IDs.h b/include/RE/IDs.h index 773ea27b..19b90a5b 100644 --- a/include/RE/IDs.h +++ b/include/RE/IDs.h @@ -191,8 +191,9 @@ namespace RE::ID namespace ConsoleLog { - inline constexpr REL::ID singleton{ 879277 }; - inline constexpr REL::ID VPrint{ 166358 }; + inline constexpr REL::ID Singleton{ 879277 }; + inline constexpr REL::ID AddString{ 166357 }; + inline constexpr REL::ID Print{ 166358 }; } namespace ExtraDataList diff --git a/include/REL/Relocation.h b/include/REL/Relocation.h index 75353221..dc2ab8c7 100644 --- a/include/REL/Relocation.h +++ b/include/REL/Relocation.h @@ -134,6 +134,21 @@ namespace REL inline constexpr std::uint8_t RET = 0xC3; inline constexpr std::uint8_t INT3 = 0xCC; + template + [[nodiscard]] auto AdjustPointer(U* a_ptr, const std::ptrdiff_t a_adjust) noexcept + { + auto addr = a_ptr ? reinterpret_cast(a_ptr) + a_adjust : 0; + if constexpr (std::is_const_v && std::is_volatile_v) { + return reinterpret_cast*>(addr); + } else if constexpr (std::is_const_v) { + return reinterpret_cast*>(addr); + } else if constexpr (std::is_volatile_v) { + return reinterpret_cast*>(addr); + } else { + return reinterpret_cast(addr); + } + } + template constexpr std::invoke_result_t invoke(F&& a_func, Args&&... a_args) // noexcept(std::is_nothrow_invocable_v) diff --git a/include/REX/W32.h b/include/REX/W32.h index eecc379b..86c56277 100644 --- a/include/REX/W32.h +++ b/include/REX/W32.h @@ -15,6 +15,7 @@ #include "REX/W32/DXGI_5.h" #include "REX/W32/DXGI_6.h" #include "REX/W32/KERNEL32.h" +#include "REX/W32/NT.h" #include "REX/W32/OLE32.h" #include "REX/W32/USER32.h" #include "REX/W32/VERSION.h" diff --git a/include/REX/W32/BASE.h b/include/REX/W32/BASE.h index 13cce382..1196560a 100644 --- a/include/REX/W32/BASE.h +++ b/include/REX/W32/BASE.h @@ -162,6 +162,7 @@ namespace REX::W32 }; std::int64_t value; }; + static_assert(sizeof(LARGE_INTEGER) == 0x8); union ULARGE_INTEGER { @@ -172,6 +173,15 @@ namespace REX::W32 }; std::uint64_t value; }; + static_assert(sizeof(ULARGE_INTEGER) == 0x8); + + struct UNICODE_STRING + { + std::uint16_t length; + std::uint16_t maxLength; + wchar_t* buffer; + }; + static_assert(sizeof(UNICODE_STRING) == 0x10); } namespace REX::W32 diff --git a/include/REX/W32/NT.h b/include/REX/W32/NT.h new file mode 100644 index 00000000..019e1788 --- /dev/null +++ b/include/REX/W32/NT.h @@ -0,0 +1,92 @@ +#pragma once + +#include "REX/W32/BASE.h" + +namespace REX::W32 +{ + struct EXCEPTION_REGISTRATION_RECORD; + struct PEB_LDR_DATA; + struct RTL_USER_PROCESS_PARAMETERS; + struct UNICODE_STRING; + + using PS_POST_PROCESS_INIT_ROUTINE = void(*)(); + + struct LIST_ENTRY + { + struct LIST_ENTRY* fLink; + struct LIST_ENTRY* bLink; + }; + + struct NT_TIB + { + EXCEPTION_REGISTRATION_RECORD* exceptionList; + void* stackBase; + void* stackLimit; + void* subSystemTib; + union + { + void* fiberData; + std::uint32_t version; + }; + void* arbitraryUserPointer; + struct NT_TIB* self; + }; + + struct PEB + { + std::byte reserved1[2]; + std::byte beingDebugged; + std::byte reserved2[1]; + void* reserved3[2]; + PEB_LDR_DATA* ldr; + RTL_USER_PROCESS_PARAMETERS* processParameters; + void* reserved4[3]; + void* atlThunkSListPtr; + void* reserved5; + std::uint32_t reserved6; + void* reserved7; + std::uint32_t reserved8; + std::uint32_t atlThunkSListPtr32; + void* reserved9[45]; + std::byte reserved10[96]; + PS_POST_PROCESS_INIT_ROUTINE postProcessInitRoutine; + std::byte reserved11[128]; + void* reserved12[1]; + std::uint32_t sessionID; + }; + + struct PEB_LDR_DATA + { + std::byte reserved1[8]; + void* reserved2[3]; + LIST_ENTRY inMemoryOrderModuleList; + }; + + struct RTL_USER_PROCESS_PARAMETERS + { + std::byte reserved1[16]; + void* reserved2[10]; + UNICODE_STRING imagePathName; + UNICODE_STRING commandLine; + }; + + struct TEB + { + void* reserved1[11]; + void* threadLocalStoragePointer; + PEB* processEnvironmentBlock; + void* reserved2[399]; + std::byte reserved3[1952]; + void* tlsSlots[64]; + std::byte reserved4[8]; + void* reserved5[26]; + void* reservedForOle; + void* reserved6[4]; + void* tlsExpansionSlots; + }; +} + +namespace REX::W32 +{ + TEB* NtCurrentTeb() noexcept; +} diff --git a/src/REX/W32.cpp b/src/REX/W32.cpp index 469fe4bf..e36dcc66 100644 --- a/src/REX/W32.cpp +++ b/src/REX/W32.cpp @@ -3,10 +3,12 @@ #include "REX/W32/DBGHELP.h" #include "REX/W32/DXGI.h" #include "REX/W32/KERNEL32.h" +#include "REX/W32/NT.h" #include "REX/W32/OLE32.h" #include "REX/W32/SHELL32.h" #include "REX/W32/USER32.h" #include "REX/W32/VERSION.h" +#include "REX/W32/WS2_32.h" // ADVAPI32 @@ -644,6 +646,15 @@ namespace REX::W32 } } +// NT +namespace REX::W32 +{ + TEB* NtCurrentTeb() noexcept + { + return reinterpret_cast(__readgsqword(offsetof(NT_TIB, self))); + } +} + // OLE32 REX_W32_IMPORT(void, CoTaskMemFree, void*);