diff --git a/CommonLibSF/include/REL/Module.h b/CommonLibSF/include/REL/Module.h index 3c7910fb..156a1048 100644 --- a/CommonLibSF/include/REL/Module.h +++ b/CommonLibSF/include/REL/Module.h @@ -53,8 +53,44 @@ namespace REL { public: constexpr Module() = delete; - explicit Module(std::uintptr_t a_base); - explicit constexpr Module(std::string_view a_filePath); + + explicit Module(const std::uintptr_t a_base) + { + stl_assert(a_base, "failed to initializing module info with null module base"); + + _base = a_base; + + const auto dosHeader = reinterpret_cast(_base); + const auto ntHeader = stl::adjust_pointer(dosHeader, dosHeader->lfanew); + const auto sections = WinAPI::IMAGE_FIRST_SECTION(ntHeader); + const auto size = std::min(ntHeader->fileHeader.sectionCount, _segments.size()); + + for (std::size_t i = 0; i < size; ++i) { + const auto& section = sections[i]; + if (const auto it = std::ranges::find_if(SEGMENTS.begin(), SEGMENTS.end(), [&](auto&& a_elem) { + constexpr auto size_s = std::extent_v; + const auto len = (std::min)(a_elem.first.size(), size_s); + return std::memcmp(a_elem.first.data(), section.name, len) == 0 && (section.characteristics & a_elem.second) == a_elem.second; + }); + it != SEGMENTS.end()) { + const auto idx = static_cast(std::distance(SEGMENTS.begin(), it)); + _segments[idx] = Segment{ _base, _base + section.virtualAddress, section.virtualSize }; + } + } + + _file = stl::utf8_to_utf16(WinAPI::GetProcPath(nullptr)).value(); + _version = get_file_version(_file).value(); + } + + explicit constexpr Module(std::string_view a_filePath) + { + const auto base = AsAddress(WinAPI::GetModuleHandle(a_filePath.data())) & ~3; + stl_assert(base, + "failed to initializing module info with file {}", + a_filePath); + + *this = Module(base); + } [[nodiscard]] constexpr auto base() const noexcept { return _base; } @@ -68,9 +104,23 @@ namespace REL [[nodiscard]] constexpr auto version() const noexcept { return _version; } - [[nodiscard]] static Module& get(std::uintptr_t a_address) noexcept; + [[nodiscard]] static Module& get(const std::uintptr_t a_address) noexcept + { + static std::unordered_map managed; + + const auto base = AsAddress(a_address) & ~3; + if (!managed.contains(base)) { + managed.try_emplace(base, base); + } + + return managed.at(base); + } - [[nodiscard]] static Module& get(std::string_view a_filePath = {}) noexcept; + [[nodiscard]] static Module& get(const std::string_view a_filePath = {}) noexcept + { + const auto base = AsAddress(WinAPI::GetModuleHandle(a_filePath.empty() ? WinAPI::GetProcPath(nullptr).data() : a_filePath.data())); + return get(base); + } private: static constexpr std::array SEGMENTS{ diff --git a/CommonLibSF/include/REL/Version.h b/CommonLibSF/include/REL/Version.h index 48d3c370..78dd6a37 100644 --- a/CommonLibSF/include/REL/Version.h +++ b/CommonLibSF/include/REL/Version.h @@ -12,12 +12,38 @@ namespace REL constexpr Version() noexcept = default; explicit constexpr Version(const std::array a_version) noexcept : - _impl(a_version) {} + _impl(a_version) + {} constexpr Version(const value_type a_v1, const value_type a_v2 = 0, const value_type a_v3 = 0, const value_type a_v4 = 0) noexcept : - _impl{ a_v1, a_v2, a_v3, a_v4 } {} + _impl{ a_v1, a_v2, a_v3, a_v4 } + {} - explicit constexpr Version(std::string_view a_version); + explicit constexpr Version(const std::string_view a_version) + { + std::array powers{ 1, 1, 1, 1 }; + std::size_t position{}; + for (const auto& c : a_version) { + if (c == '.') { + if (++position == powers.size()) { + throw std::invalid_argument("Too many parts in version number."); + } + } else { + powers[position] *= 10; + } + } + position = 0; + for (const auto& c : a_version) { + if (c == '.') { + ++position; + } else if (c < '0' || c > '9') { + throw std::invalid_argument("Invalid character in version number."); + } else { + powers[position] /= 10; + _impl[position] += static_cast((c - '0') * powers[position]); + } + } + } [[nodiscard]] constexpr reference operator[](const std::size_t a_idx) noexcept { return _impl[a_idx]; } @@ -51,8 +77,11 @@ namespace REL } [[nodiscard]] constexpr value_type major() const noexcept { return _impl[0]; } + [[nodiscard]] constexpr value_type minor() const noexcept { return _impl[1]; } + [[nodiscard]] constexpr value_type patch() const noexcept { return _impl[2]; } + [[nodiscard]] constexpr value_type build() const noexcept { return _impl[3]; } [[nodiscard]] constexpr std::string string(const std::string_view a_separator = "."sv) const @@ -145,7 +174,33 @@ namespace REL } } - [[nodiscard]] std::optional get_file_version(stl::zwstring a_filename); + [[nodiscard]] inline std::optional get_file_version(const stl::zwstring a_filename) + { + std::uint32_t dummy{}; + std::vector buf(WinAPI::GetFileVersionInfoSize(a_filename.data(), std::addressof(dummy))); + if (buf.empty()) { + return std::nullopt; + } + + if (!WinAPI::GetFileVersionInfo(a_filename.data(), 0, buf.size(), buf.data())) { + return std::nullopt; + } + + void* verBuf{}; + std::uint32_t verLen{}; + if (!WinAPI::VerQueryValue(buf.data(), L"\\StringFileInfo\\040904B0\\ProductVersion", std::addressof(verBuf), std::addressof(verLen))) { + return std::nullopt; + } + + Version version; + std::wistringstream ss(std::wstring(static_cast(verBuf), verLen)); + std::wstring token; + for (std::size_t i = 0; i < 4 && std::getline(ss, token, L'.'); ++i) { + version[i] = static_cast(std::stoi(token)); + } + + return version; + } } #ifdef __cpp_lib_format diff --git a/CommonLibSF/include/SFSE/API.h b/CommonLibSF/include/SFSE/API.h index b20daf1e..0bd9eb31 100644 --- a/CommonLibSF/include/SFSE/API.h +++ b/CommonLibSF/include/SFSE/API.h @@ -9,14 +9,18 @@ namespace SFSE { void Init(const LoadInterface* a_intfc, bool a_log = true) noexcept; + void RegisterForAPIInitEvent(const std::function& a_fn); PluginHandle GetPluginHandle() noexcept; const TrampolineInterface* GetTrampolineInterface() noexcept; + const MessagingInterface* GetMessagingInterface() noexcept; + const MenuInterface* GetMenuInterface() noexcept; Trampoline& GetTrampoline(); + void AllocTrampoline(std::size_t a_size, bool a_trySFSEReserve = true); } diff --git a/CommonLibSF/include/SFSE/IAT.h b/CommonLibSF/include/SFSE/IAT.h index 99681684..ca4c3f8a 100644 --- a/CommonLibSF/include/SFSE/IAT.h +++ b/CommonLibSF/include/SFSE/IAT.h @@ -3,6 +3,7 @@ namespace SFSE { [[nodiscard]] std::uintptr_t GetIATAddr(std::string_view a_dll, std::string_view a_function); + [[nodiscard]] std::uintptr_t GetIATAddr(void* a_module, std::string_view a_dll, std::string_view a_function); [[nodiscard]] constexpr void* GetIATPtr(std::string_view a_dll, std::string_view a_function); diff --git a/CommonLibSF/include/SFSE/InputMap.h b/CommonLibSF/include/SFSE/InputMap.h index e42eee8c..45451e11 100644 --- a/CommonLibSF/include/SFSE/InputMap.h +++ b/CommonLibSF/include/SFSE/InputMap.h @@ -41,10 +41,14 @@ namespace SFSE::InputMap }; std::uint32_t GamepadMaskToKeycode(std::uint32_t a_keyMask); + std::uint32_t GamepadKeycodeToMask(std::uint32_t a_keyCode); std::string GetKeyName(std::uint32_t a_keyCode); + std::string GetKeyboardKeyName(std::uint32_t a_keyCode); + std::string GetMouseButtonName(std::uint32_t a_keyCode); + std::string GetGamepadButtonName(std::uint32_t a_keyCode); } diff --git a/CommonLibSF/include/SFSE/Interfaces.h b/CommonLibSF/include/SFSE/Interfaces.h index d80261b1..d03e4557 100644 --- a/CommonLibSF/include/SFSE/Interfaces.h +++ b/CommonLibSF/include/SFSE/Interfaces.h @@ -15,6 +15,7 @@ namespace SFSE { public: [[nodiscard]] REL::Version RuntimeVersion() const; + [[nodiscard]] std::uint32_t SFSEVersion() const; protected: @@ -35,7 +36,9 @@ namespace SFSE }; [[nodiscard]] PluginHandle GetPluginHandle() const; + const PluginInfo* GetPluginInfo(const char* a_name) const; + [[nodiscard]] void* QueryInterface(std::uint32_t a_id) const; }; @@ -68,7 +71,9 @@ namespace SFSE [[nodiscard]] std::uint32_t Version() const; bool Dispatch(std::uint32_t a_messageType, void* a_data, std::uint32_t a_dataLen, const char* a_receiver) const; + bool RegisterListener(EventCallback a_callback) const; + bool RegisterListener(const char* a_sender, EventCallback a_callback) const; protected: @@ -86,6 +91,7 @@ namespace SFSE [[nodiscard]] std::uint32_t Version() const; [[nodiscard]] void* AllocateFromBranchPool(std::size_t a_size) const; + [[nodiscard]] void* AllocateFromLocalPool(std::size_t a_size) const; private: diff --git a/CommonLibSF/include/SFSE/Logger.h b/CommonLibSF/include/SFSE/Logger.h index 834eb187..438c0210 100644 --- a/CommonLibSF/include/SFSE/Logger.h +++ b/CommonLibSF/include/SFSE/Logger.h @@ -26,6 +26,7 @@ namespace SFSE::log SFSE_MAKE_SOURCE_LOGGER(critical, critical); [[nodiscard]] std::optional log_directory(); + void init(); } diff --git a/CommonLibSF/include/SFSE/Trampoline.h b/CommonLibSF/include/SFSE/Trampoline.h index d32ed4e0..952383e5 100644 --- a/CommonLibSF/include/SFSE/Trampoline.h +++ b/CommonLibSF/include/SFSE/Trampoline.h @@ -43,7 +43,8 @@ namespace SFSE Trampoline(Trampoline&& a_rhs) noexcept { move_from(std::move(a_rhs)); } explicit Trampoline(const std::string_view a_name) : - _name(a_name) {} + _name(a_name) + {} ~Trampoline() { release(); } diff --git a/CommonLibSF/src/REL/Module.cpp b/CommonLibSF/src/REL/Module.cpp deleted file mode 100644 index eb124487..00000000 --- a/CommonLibSF/src/REL/Module.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "REL/Module.h" - -namespace REL -{ - Module::Module(const std::uintptr_t a_base) - { - stl_assert(a_base, "failed to initializing module info with null module base"); - - _base = a_base; - - const auto dosHeader = reinterpret_cast(_base); - const auto ntHeader = stl::adjust_pointer(dosHeader, dosHeader->lfanew); - const auto sections = WinAPI::IMAGE_FIRST_SECTION(ntHeader); - const auto size = std::min(ntHeader->fileHeader.sectionCount, _segments.size()); - - for (std::size_t i = 0; i < size; ++i) { - const auto& section = sections[i]; - const auto it = std::ranges::find_if(SEGMENTS.begin(), SEGMENTS.end(), [&](auto&& a_elem) { - constexpr auto size_s = std::extent_v; - const auto len = (std::min)(a_elem.first.size(), size_s); - return std::memcmp(a_elem.first.data(), section.name, len) == 0 && (section.characteristics & a_elem.second) == a_elem.second; - }); - if (it != SEGMENTS.end()) { - const auto idx = static_cast(std::distance(SEGMENTS.begin(), it)); - _segments[idx] = Segment{ _base, _base + section.virtualAddress, section.virtualSize }; - } - } - - _file = stl::utf8_to_utf16(WinAPI::GetProcPath(nullptr)).value(); - _version = get_file_version(_file).value(); - } - - constexpr Module::Module(std::string_view a_filePath) - { - const auto base = AsAddress(WinAPI::GetModuleHandle(a_filePath.data())) & ~3; - stl_assert(base, - "failed to initializing module info with file {}", - a_filePath); - - *this = Module(base); - } - - [[nodiscard]] Module& Module::get(const std::uintptr_t a_address) noexcept - { - static std::unordered_map managed; - - const auto base = AsAddress(a_address) & ~3; - if (!managed.contains(base)) { - managed.try_emplace(base, base); - } - - return managed.at(base); - } - - [[nodiscard]] Module& Module::get(const std::string_view a_filePath) noexcept - { - const auto base = AsAddress(WinAPI::GetModuleHandle(a_filePath.empty() ? WinAPI::GetProcPath(nullptr).data() : a_filePath.data())); - return get(base); - } -} diff --git a/CommonLibSF/src/REL/Version.cpp b/CommonLibSF/src/REL/Version.cpp deleted file mode 100644 index 44d32453..00000000 --- a/CommonLibSF/src/REL/Version.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "REL/Version.h" - -namespace REL -{ - constexpr Version::Version(const std::string_view a_version) - { - std::array powers{ 1, 1, 1, 1 }; - std::size_t position{}; - for (const auto& c : a_version) { - if (c == '.') { - if (++position == powers.size()) { - throw std::invalid_argument("Too many parts in version number."); - } - } else { - powers[position] *= 10; - } - } - position = 0; - for (const auto& c : a_version) { - if (c == '.') { - ++position; - } else if (c < '0' || c > '9') { - throw std::invalid_argument("Invalid character in version number."); - } else { - powers[position] /= 10; - _impl[position] += static_cast((c - '0') * powers[position]); - } - } - } - - [[nodiscard]] std::optional get_file_version(const stl::zwstring a_filename) - { - std::uint32_t dummy{}; - std::vector buf(WinAPI::GetFileVersionInfoSize(a_filename.data(), std::addressof(dummy))); - if (buf.empty()) { - return std::nullopt; - } - - if (!WinAPI::GetFileVersionInfo(a_filename.data(), 0, buf.size(), buf.data())) { - return std::nullopt; - } - - void* verBuf{}; - std::uint32_t verLen{}; - if (!WinAPI::VerQueryValue(buf.data(), L"\\StringFileInfo\\040904B0\\ProductVersion", std::addressof(verBuf), std::addressof(verLen))) { - return std::nullopt; - } - - Version version; - std::wistringstream ss(std::wstring(static_cast(verBuf), verLen)); - std::wstring token; - for (std::size_t i = 0; i < 4 && std::getline(ss, token, L'.'); ++i) { - version[i] = static_cast(std::stoi(token)); - } - - return version; - } -} diff --git a/CommonLibSF/src/SFSE/API.cpp b/CommonLibSF/src/SFSE/API.cpp index 48044889..aef29ee7 100644 --- a/CommonLibSF/src/SFSE/API.cpp +++ b/CommonLibSF/src/SFSE/API.cpp @@ -27,12 +27,15 @@ namespace SFSE private: APIStorage() noexcept = default; + ~APIStorage() noexcept = default; constexpr APIStorage(const APIStorage&) = delete; + constexpr APIStorage(APIStorage&&) = delete; constexpr APIStorage& operator=(const APIStorage&) = delete; + constexpr APIStorage& operator=(APIStorage&&) = delete; }; diff --git a/CommonLibSF/src/SFSE/InputMap.cpp b/CommonLibSF/src/SFSE/InputMap.cpp index 08c020b6..a74bc865 100644 --- a/CommonLibSF/src/SFSE/InputMap.cpp +++ b/CommonLibSF/src/SFSE/InputMap.cpp @@ -7,6 +7,7 @@ namespace SFSE std::uint32_t InputMap::GamepadMaskToKeycode(const std::uint32_t a_keyMask) { using XInputButton = RE::XInput::XInputButton; + switch (a_keyMask) { case XInputButton::XINPUT_GAMEPAD_DPAD_UP: return kGamepadButtonOffset_DPAD_UP;