3#define REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL(a_nopropQual, a_propQual, ...) \
8 struct member_function_pod_type<R (Cls::*)(Args...) __VA_ARGS__ a_nopropQual a_propQual> \
10 using type = R(__VA_ARGS__ Cls*, Args...) a_propQual; \
17 struct member_function_pod_type<R (Cls::*)(Args..., ...) __VA_ARGS__ a_nopropQual a_propQual> \
19 using type = R(__VA_ARGS__ Cls*, Args..., ...) a_propQual; \
22#define REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(a_qualifer, ...) \
23 REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL(a_qualifer, , ##__VA_ARGS__) \
24 REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL(a_qualifer, noexcept, ##__VA_ARGS__)
26#define REL_MAKE_MEMBER_FUNCTION_POD_TYPE(...) \
27 REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(, __VA_ARGS__) \
28 REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(&, ##__VA_ARGS__) \
29 REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(&&, ##__VA_ARGS__)
31#define REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL(a_nopropQual, a_propQual, ...) \
36 struct member_function_non_pod_type<R (Cls::*)(Args...) __VA_ARGS__ a_nopropQual a_propQual> \
38 using type = R&(__VA_ARGS__ Cls*, void*, Args...)a_propQual; \
45 struct member_function_non_pod_type<R (Cls::*)(Args..., ...) __VA_ARGS__ a_nopropQual a_propQual> \
47 using type = R&(__VA_ARGS__ Cls*, void*, Args..., ...)a_propQual; \
50#define REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(a_qualifer, ...) \
51 REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL(a_qualifer, , ##__VA_ARGS__) \
52 REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL(a_qualifer, noexcept, ##__VA_ARGS__)
54#define REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE(...) \
55 REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(, __VA_ARGS__) \
56 REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(&, ##__VA_ARGS__) \
57 REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(&&, ##__VA_ARGS__)
70 _mapping(a_rhs._mapping),
73 a_rhs._mapping =
nullptr;
74 a_rhs._view =
nullptr;
83 if (
this != std::addressof(a_rhs)) {
84 _mapping = a_rhs._mapping;
85 a_rhs._mapping =
nullptr;
88 a_rhs._view =
nullptr;
93 [[nodiscard]]
void*
data() noexcept {
return _view; }
100 void* _mapping{
nullptr };
101 void* _view{
nullptr };
131 std::bool_constant<sizeof(T) == 1>,
132 std::bool_constant<sizeof(T) == 2>,
133 std::bool_constant<sizeof(T) == 4>,
134 std::bool_constant<sizeof(T) == 8>>
140 std::is_trivially_constructible<T>,
141 std::is_trivially_destructible<T>,
142 std::is_trivially_copy_assignable<T>,
144 std::is_polymorphic<T>>>
149 std::is_standard_layout<T>
152 template <
class T,
class =
void>
161 std::is_union_v<T>>> :
169 std::is_class_v<T>>> :
172 meets_function_req<T>,
184 noexcept(std::is_nothrow_invocable_v<F, First, Rest...>)
186 using result_t = std::invoke_result_t<F, First, Rest...>;
187 std::aligned_storage_t<
sizeof(result_t),
alignof(result_t)> result;
190 auto func = stl::unrestricted_cast<func_t*>(std::forward<F>(a_func));
192 return func(std::forward<First>(a_first), std::addressof(result), std::forward<Rest>(a_rest)...);
196 inline constexpr std::uint8_t
NOP = 0x90;
197 inline constexpr std::uint8_t
RET = 0xC3;
198 inline constexpr std::uint8_t
INT3 = 0xCC;
200 template <
class F,
class... Args>
201 std::invoke_result_t<F, Args...>
invoke(F&& a_func, Args&&... a_args)
202 noexcept(std::is_nothrow_invocable_v<F, Args...>)
203 requires(std::invocable<F, Args...>)
205 if constexpr (std::is_member_function_pointer_v<std::decay_t<F>>) {
208 auto func = stl::unrestricted_cast<func_t*>(std::forward<F>(a_func));
209 return func(std::forward<Args>(a_args)...);
214 return std::forward<F>(a_func)(std::forward<Args>(a_args)...);
218 inline void safe_write(std::uintptr_t a_dst,
const void* a_src, std::size_t a_count)
220 std::uint32_t old{ 0 };
223 reinterpret_cast<void*
>(a_dst),
226 std::addressof(old));
228 std::memcpy(
reinterpret_cast<void*
>(a_dst), a_src, a_count);
231 reinterpret_cast<void*
>(a_dst),
234 std::addressof(old));
237 assert(success != 0);
240 template <std::
integral T>
243 safe_write(a_dst, std::addressof(a_data),
sizeof(T));
249 safe_write(a_dst, a_data.data(), a_data.size_bytes());
252 inline void safe_fill(std::uintptr_t a_dst, std::uint8_t a_value, std::size_t a_count)
254 std::uint32_t old{ 0 };
257 reinterpret_cast<void*
>(a_dst),
260 std::addressof(old));
262 std::fill_n(
reinterpret_cast<std::uint8_t*
>(a_dst), a_count, a_value);
265 reinterpret_cast<void*
>(a_dst),
268 std::addressof(old));
271 assert(success != 0);
288 _impl{ a_v1, a_v2, a_v3, a_v4 }
294 [[nodiscard]]
constexpr decltype(
auto)
begin()
const noexcept {
return _impl.begin(); }
295 [[nodiscard]]
constexpr decltype(
auto)
cbegin()
const noexcept {
return _impl.cbegin(); }
296 [[nodiscard]]
constexpr decltype(
auto)
end()
const noexcept {
return _impl.end(); }
297 [[nodiscard]]
constexpr decltype(
auto)
cend()
const noexcept {
return _impl.cend(); }
299 [[nodiscard]] std::strong_ordering
constexpr compare(
const Version& a_rhs)
const noexcept
301 for (std::size_t i = 0; i < _impl.size(); ++i) {
302 if ((*
this)[i] != a_rhs[i]) {
303 return (*
this)[i] < a_rhs[i] ? std::strong_ordering::less : std::strong_ordering::greater;
306 return std::strong_ordering::equal;
309 [[nodiscard]]
constexpr std::uint32_t
pack() const noexcept
311 return static_cast<std::uint32_t
>(
312 (_impl[0] & 0x0FF) << 24u |
313 (_impl[1] & 0x0FF) << 16u |
314 (_impl[2] & 0xFFF) << 4u |
315 (_impl[3] & 0x00F) << 0u);
321 for (
auto&& ver : _impl) {
332 for (
auto&& ver : _impl) {
333 result += std::to_wstring(ver);
341 std::array<value_type, 4> _impl{ 0, 0, 0, 0 };
345 [[nodiscard]]
constexpr std::strong_ordering
operator<=>(
const Version& a_lhs,
const Version& a_rhs)
noexcept {
return a_lhs.compare(a_rhs); }
359 void* verBuf{
nullptr };
360 std::uint32_t verLen{ 0 };
361 if (!
WinAPI::VerQueryValue(buf.data(), L
"\\StringFileInfo\\040904B0\\ProductVersion", std::addressof(verBuf), std::addressof(verLen))) {
366 std::wistringstream ss(
367 std::wstring(
static_cast<const wchar_t*
>(verBuf), verLen));
369 for (std::size_t i = 0; i < 4 &&
std::getline(ss, token, L
'.'); ++i) {
370 version[i] =
static_cast<std::uint16_t
>(std::stoi(token));
394 Segment(
std::uintptr_t a_proxyBase,
std::uintptr_t a_address,
std::uintptr_t a_size) noexcept :
395 _proxyBase(a_proxyBase),
400 [[nodiscard]] std::uintptr_t
address() const noexcept {
return _address; }
401 [[nodiscard]] std::size_t
offset() const noexcept {
return address() - _proxyBase; }
402 [[nodiscard]] std::size_t
size() const noexcept {
return _size; }
404 [[nodiscard]]
void*
pointer() const noexcept {
return reinterpret_cast<void*
>(
address()); }
409 return static_cast<T*
>(
pointer());
413 std::uintptr_t _proxyBase{ 0 };
414 std::uintptr_t _address{ 0 };
415 std::size_t _size{ 0 };
427 [[nodiscard]] std::uintptr_t
base() const noexcept {
return _base; }
433 [[nodiscard]]
void*
pointer() const noexcept {
return reinterpret_cast<void*
>(
base()); }
438 return static_cast<T*
>(
pointer());
444 const auto getFilename = [&]() {
448 static_cast<std::uint32_t
>(_filename.size()));
451 _filename.resize(getFilename());
452 if (
const auto result = getFilename();
453 result != _filename.size() - 1 ||
455 _filename = L
"SkyrimSE.exe"sv;
461 Module(
const Module&) =
delete;
462 Module(Module&&) =
delete;
464 ~Module() noexcept = default;
466 Module& operator=(const Module&) = delete;
467 Module& operator=(Module&&) = delete;
472 if (handle ==
nullptr) {
475 "Failed to obtain module handle for: \"{0}\".\n"
476 "You have likely renamed the executable to something unexpected. "
477 "Renaming the executable back to \"{0}\" may resolve the issue."sv,
480 _base =
reinterpret_cast<std::uintptr_t
>(handle);
486 void load_segments();
496 "Failed to obtain file version info for: {}\n"
497 "Please contact the author of this script extender plugin for further assistance."sv,
502 static constexpr std::array SEGMENTS{
504 std::make_pair(
".idata"sv,
static_cast<std::uint32_t
>(0)),
505 std::make_pair(
".rdata"sv,
static_cast<std::uint32_t
>(0)),
506 std::make_pair(
".data"sv,
static_cast<std::uint32_t
>(0)),
507 std::make_pair(
".pdata"sv,
static_cast<std::uint32_t
>(0)),
508 std::make_pair(
".tls"sv,
static_cast<std::uint32_t
>(0)),
510 std::make_pair(
".gfids"sv,
static_cast<std::uint32_t
>(0))
513 static constexpr auto ENVIRONMENT = L
"SKSE_RUNTIME"sv;
515 std::wstring _filename;
516 std::array<Segment, Segment::total> _segments;
518 std::uintptr_t _base{ 0 };
527 std::uint64_t offset;
540 template <
class ExecutionPolicy>
542 requires(std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>)
551 [](
auto&& a_lhs,
auto&& a_rhs) {
552 return a_lhs.offset < a_rhs.offset;
560 [[nodiscard]] std::uint64_t
operator()(std::size_t a_offset)
const
562 const mapping_t elem{ 0, a_offset };
563 const auto it = std::lower_bound(
567 [](
auto&& a_lhs,
auto&& a_rhs) {
568 return a_lhs.offset < a_rhs.offset;
570 if (it == _offset2id.end()) {
573 "Failed to find the offset within the database: 0x{:08X}"sv,
604 [[nodiscard]]
inline std::size_t
id2offset(std::uint64_t a_id)
const
606 mapping_t elem{ a_id, 0 };
607 const auto it = std::lower_bound(
611 [](
auto&& a_lhs,
auto&& a_rhs) {
612 return a_lhs.id < a_rhs.id;
614 if (it == _id2offset.end()) {
617 "Failed to find the id within the address library: {}\n"
618 "This means this script extender plugin is incompatible with the address "
619 "library for this version of the game, and thus does not support it."sv,
623 return static_cast<std::size_t
>(it->offset);
632 void read(binary_io::file_istream& a_in)
634 const auto [format] = a_in.read<std::int32_t>();
635#ifdef SKYRIM_SUPPORT_AE
642 "Unsupported address library format: {}\n"
643 "This means this script extender plugin is incompatible with the address "
644 "library available for this version of the game, and thus does not "
649 const auto [major, minor, patch, revision] =
650 a_in.read<std::int32_t, std::int32_t, std::int32_t, std::int32_t>();
651 _version[0] =
static_cast<std::uint16_t
>(major);
652 _version[1] =
static_cast<std::uint16_t
>(minor);
653 _version[2] =
static_cast<std::uint16_t
>(patch);
654 _version[3] =
static_cast<std::uint16_t
>(revision);
656 const auto [nameLen] = a_in.read<std::int32_t>();
657 a_in.seek_relative(nameLen);
659 a_in.read(_pointerSize, _addressCount);
662 [[nodiscard]] std::size_t address_count() const noexcept {
return static_cast<std::size_t
>(_addressCount); }
663 [[nodiscard]] std::uint64_t pointer_size() const noexcept {
return static_cast<std::uint64_t
>(_pointerSize); }
664 [[nodiscard]] Version version() const noexcept {
return _version; }
668 std::int32_t _pointerSize{ 0 };
669 std::int32_t _addressCount{ 0 };
672 IDDatabase() { load(); }
674 IDDatabase(
const IDDatabase&) =
delete;
675 IDDatabase(IDDatabase&&) =
delete;
677 ~IDDatabase() =
default;
679 IDDatabase& operator=(
const IDDatabase&) =
delete;
680 IDDatabase& operator=(IDDatabase&&) =
delete;
685 const auto filename =
688#ifdef SKYRIM_SUPPORT_AE
689 "Data/SKSE/Plugins/versionlib-{}.bin"sv,
691 "Data/SKSE/Plugins/version-{}.bin"sv,
694 .value_or(L
"<unknown filename>"s);
695 load_file(filename, version);
701 binary_io::file_istream in(a_filename);
704 if (header.version() != a_version) {
708 auto mapname = L
"CommonLibSSEOffsets-v2-"s;
709 mapname += a_version.wstring();
710 const auto byteSize =
static_cast<std::size_t
>(header.address_count()) *
sizeof(mapping_t);
711 if (_mmap.open(mapname, byteSize)) {
712 _id2offset = {
static_cast<mapping_t*
>(_mmap.data()), header.address_count() };
713 }
else if (_mmap.create(mapname, byteSize)) {
714 _id2offset = {
static_cast<mapping_t*
>(_mmap.data()), header.address_count() };
715 unpack_file(in, header);
719 [](
auto&& a_lhs,
auto&& a_rhs) {
720 return a_lhs.id < a_rhs.id;
725 }
catch (
const std::system_error&) {
728 "Failed to locate an appropriate address library with the path: {}\n"
729 "This means you are missing the address library for this specific version of "
730 "the game. Please continue to the mod page for address library to download "
731 "an appropriate version. If one is not available, then it is likely that "
732 "address library has not yet added support for this version of the game."sv,
737 void unpack_file(binary_io::file_istream& a_in, header_t a_header)
739 std::uint8_t type = 0;
740 std::uint64_t
id = 0;
741 std::uint64_t offset = 0;
742 std::uint64_t prevID = 0;
743 std::uint64_t prevOffset = 0;
744 for (
auto& mapping : _id2offset) {
746 const auto lo =
static_cast<std::uint8_t
>(type & 0xF);
747 const auto hi =
static_cast<std::uint8_t
>(type >> 4);
757 id = prevID + std::get<0>(a_in.read<std::uint8_t>());
760 id = prevID - std::get<0>(a_in.read<std::uint8_t>());
763 id = prevID + std::get<0>(a_in.read<std::uint16_t>());
766 id = prevID - std::get<0>(a_in.read<std::uint16_t>());
769 std::tie(
id) = a_in.read<std::uint16_t>();
772 std::tie(
id) = a_in.read<std::uint32_t>();
778 const std::uint64_t tmp = (hi & 8) != 0 ? (prevOffset / a_header.pointer_size()) : prevOffset;
788 offset = tmp + std::get<0>(a_in.read<std::uint8_t>());
791 offset = tmp - std::get<0>(a_in.read<std::uint8_t>());
794 offset = tmp + std::get<0>(a_in.read<std::uint16_t>());
797 offset = tmp - std::get<0>(a_in.read<std::uint16_t>());
800 std::tie(offset) = a_in.read<std::uint16_t>();
803 std::tie(offset) = a_in.read<std::uint32_t>();
810 offset *= a_header.pointer_size();
813 mapping = { id, offset };
820 detail::memory_map _mmap;
821 std::span<mapping_t> _id2offset;
829 explicit constexpr
Offset(
std::
size_t a_offset) noexcept :
839 [[nodiscard]] std::uintptr_t
address()
const {
return base() + offset(); }
840 [[nodiscard]]
constexpr std::size_t
offset() const noexcept {
return _offset; }
843 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().base(); }
845 std::size_t _offset{ 0 };
851 constexpr ID() noexcept = default;
853 explicit constexpr
ID(
std::uint64_t a_id) noexcept :
863 [[nodiscard]] std::uintptr_t
address()
const {
return base() + offset(); }
864 [[nodiscard]]
constexpr std::uint64_t
id() const noexcept {
return _id; }
865 [[nodiscard]] std::size_t
offset()
const {
return IDDatabase::get().id2offset(_id); }
868 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().base(); }
870 std::uint64_t _id{ 0 };
879 std::is_member_pointer_v<T> || std::is_function_v<std::remove_pointer_t<T>>,
890 _impl{ a_offset.address() }
894 _impl{ a_id.address() }
898 _impl{ a_id.address() + a_offset }
919 template <
class U = value_type>
920 [[nodiscard]]
decltype(
auto)
operator*()
const noexcept
921 requires(std::is_pointer_v<U>)
926 template <
class U = value_type>
928 requires(
std::is_pointer_v<U>)
933 template <
class... Args>
935 noexcept(std::is_nothrow_invocable_v<
const value_type&, Args...>)
936 requires(std::invocable<const value_type&, Args...>)
938 return REL::invoke(get(), std::forward<Args>(a_args)...);
941 [[nodiscard]]
constexpr std::uintptr_t
address() const noexcept {
return _impl; }
942 [[nodiscard]] std::size_t
offset()
const {
return _impl - base(); }
948 return stl::unrestricted_cast<value_type>(_impl);
951 template <
class U = value_type>
952 std::uintptr_t
write_vfunc(std::size_t a_idx, std::uintptr_t a_newFunc)
953 requires(std::same_as<U, std::uintptr_t>)
955 const auto addr = address() + (
sizeof(
void*) * a_idx);
956 const auto result = *
reinterpret_cast<std::uintptr_t*
>(addr);
963 requires(std::same_as<value_type, std::uintptr_t>)
965 return write_vfunc(a_idx, stl::unrestricted_cast<std::uintptr_t>(a_newFunc));
970 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().base(); }
973 std::uintptr_t _impl{ 0 };
982 return (
'0' <= a_ch && a_ch <=
'9') ||
983 (
'A' <= a_ch && a_ch <=
'F') ||
984 (
'a' <= a_ch && a_ch <=
'f');
987 [[nodiscard]]
constexpr bool space(
char a_ch)
noexcept
992 [[nodiscard]]
constexpr bool wildcard(
char a_ch)
noexcept
1004 constexpr auto lut = []()
noexcept {
1005 std::array<std::uint8_t, std::numeric_limits<unsigned char>::max() + 1> a = {};
1007 const auto iterate = [&](std::uint8_t a_iFirst,
unsigned char a_cFirst,
unsigned char a_cLast)
noexcept {
1008 for (; a_cFirst <= a_cLast; ++a_cFirst, ++a_iFirst) {
1009 a[a_cFirst] = a_iFirst;
1013 iterate(0,
'0',
'9');
1014 iterate(0xA,
'A',
'F');
1015 iterate(0xa,
'a',
'f');
1020 return static_cast<std::byte
>(
1021 lut[
static_cast<unsigned char>(a_hi)] * 0x10u +
1022 lut[
static_cast<unsigned char>(a_lo)]);
1026 template <
char HI,
char LO>
1030 [[nodiscard]]
static constexpr bool match(std::byte a_byte)
noexcept
1032 constexpr auto expected = detail::hexacharacters_to_hexadecimal(HI, LO);
1033 return a_byte == expected;
1037 static_assert(Hexadecimal<'5', '7'>::match(std::byte{ 0x57 }));
1038 static_assert(Hexadecimal<'6', '5'>::match(std::byte{ 0x65 }));
1039 static_assert(Hexadecimal<'B', 'D'>::match(std::byte{ 0xBD }));
1040 static_assert(Hexadecimal<'1', 'C'>::match(std::byte{ 0x1C }));
1041 static_assert(Hexadecimal<'F', '2'>::match(std::byte{ 0xF2 }));
1042 static_assert(Hexadecimal<'9', 'f'>::match(std::byte{ 0x9f }));
1044 static_assert(!Hexadecimal<'D', '4'>::match(std::byte{ 0xF8 }));
1045 static_assert(!Hexadecimal<'6', '7'>::match(std::byte{ 0xAA }));
1046 static_assert(!Hexadecimal<'7', '8'>::match(std::byte{ 0xE3 }));
1047 static_assert(!Hexadecimal<'6', 'E'>::match(std::byte{ 0x61 }));
1052 [[nodiscard]]
static constexpr bool match(std::byte)
noexcept
1058 static_assert(Wildcard::match(std::byte{ 0xB9 }));
1059 static_assert(Wildcard::match(std::byte{ 0x96 }));
1060 static_assert(Wildcard::match(std::byte{ 0x35 }));
1061 static_assert(Wildcard::match(std::byte{ 0xE4 }));
1063 template <
char,
char>
1066 template <
char C1,
char C2>
1068 requires(characters::hexadecimal(C1) && characters::hexadecimal(C2));
1070 template <
char C1,
char C2>
1072 requires(characters::wildcard(C1) && characters::wildcard(C2));
1075 template <class... Rules>
1079 static_assert(
sizeof...(Rules) >= 1,
"must provide at least 1 rule for the pattern matcher");
1081 [[nodiscard]]
constexpr bool match(std::span<
const std::byte,
sizeof...(Rules)> a_bytes)
const noexcept
1084 return (Rules::match(a_bytes[i++]) && ...);
1087 [[nodiscard]]
bool match(std::uintptr_t a_address)
const noexcept
1089 return this->match(*
reinterpret_cast<const std::byte(*)[sizeof...(Rules)]
>(a_address));
1092 void match_or_fail(std::uintptr_t a_address, std::source_location a_loc = std::source_location::current()) const noexcept
1094 if (!this->match(a_address)) {
1095 const auto version = Module::get().version();
1098 "A pattern has failed to match.\n"
1099 "This means the plugin is incompatible with the current version of the game ({}.{}.{}). "
1100 "Head to the mod page of this plugin to see if an update is available."sv,
1111 template <stl::nttp::string S,
class... Rules>
1114 if constexpr (S.length() == 0) {
1116 }
else if constexpr (S.length() == 1) {
1117 constexpr char c = S[0];
1118 if constexpr (characters::hexadecimal(c) || characters::wildcard(c)) {
1119 consteval_error(
"the given pattern has an unpaired rule (rules are required to be written in pairs of 2)");
1121 consteval_error(
"the given pattern has trailing characters at the end (which is not allowed)");
1124 using rule_t =
decltype(rules::rule_for<S[0], S[1]>());
1125 if constexpr (std::same_as<rule_t, void>) {
1128 if constexpr (S.length() <= 3) {
1130 }
else if constexpr (characters::space(S[2])) {
1133 consteval_error(
"a space character is required to split byte patterns");
1139 template <
class... Bytes>
1141 -> std::array<std::byte,
sizeof...(Bytes)>
1143 static_assert((std::integral<Bytes> && ...),
"all bytes must be an integral type");
1144 return {
static_cast<std::byte
>(a_bytes)... };
1148 template <stl::nttp::
string S>
1151 return detail::do_make_pattern<S>();
1154 static_assert(make_pattern<
"40 10 F2 ??">().match(
1155 detail::make_byte_array(0x40, 0x10, 0xF2, 0x41)));
1156 static_assert(make_pattern<
"B8 D0 ?? ?? D4 6E">().match(
1157 detail::make_byte_array(0xB8, 0xD0, 0x35, 0x2A, 0xD4, 0x6E)));
1160#undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE
1161#undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER
1162#undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL
1164#undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE
1165#undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER
1166#undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL
Definition: Relocation.h:532
Offset2ID()
Definition: Relocation.h:556
typename container_type::const_iterator const_iterator
Definition: Relocation.h:537
typename container_type::const_reverse_iterator const_reverse_iterator
Definition: Relocation.h:538
const_reverse_iterator crbegin() const noexcept
Definition: Relocation.h:587
const_iterator begin() const noexcept
Definition: Relocation.h:580
std::vector< value_type > container_type
Definition: Relocation.h:535
size_type size() const noexcept
Definition: Relocation.h:592
Offset2ID(ExecutionPolicy &&a_policy)
Definition: Relocation.h:541
const_reverse_iterator rbegin() const noexcept
Definition: Relocation.h:586
const_reverse_iterator crend() const noexcept
Definition: Relocation.h:590
const_iterator cbegin() const noexcept
Definition: Relocation.h:581
typename container_type::size_type size_type
Definition: Relocation.h:536
const_iterator cend() const noexcept
Definition: Relocation.h:584
std::uint64_t operator()(std::size_t a_offset) const
Definition: Relocation.h:560
mapping_t value_type
Definition: Relocation.h:534
const_reverse_iterator rend() const noexcept
Definition: Relocation.h:589
const_iterator end() const noexcept
Definition: Relocation.h:583
Definition: Relocation.h:522
static IDDatabase & get()
Definition: Relocation.h:598
std::size_t id2offset(std::uint64_t a_id) const
Definition: Relocation.h:604
Definition: Relocation.h:849
std::size_t offset() const
Definition: Relocation.h:865
constexpr ID & operator=(std::uint64_t a_id) noexcept
Definition: Relocation.h:857
constexpr std::uint64_t id() const noexcept
Definition: Relocation.h:864
constexpr ID() noexcept=default
std::uintptr_t address() const
Definition: Relocation.h:863
Definition: Relocation.h:419
Version version() const noexcept
Definition: Relocation.h:429
T * pointer() const noexcept
Definition: Relocation.h:436
std::uintptr_t base() const noexcept
Definition: Relocation.h:427
stl::zwstring filename() const noexcept
Definition: Relocation.h:428
static Module & get()
Definition: Relocation.h:421
void * pointer() const noexcept
Definition: Relocation.h:433
Segment segment(Segment::Name a_segment) const noexcept
Definition: Relocation.h:431
Definition: Relocation.h:825
constexpr Offset() noexcept=default
std::uintptr_t address() const
Definition: Relocation.h:839
constexpr Offset & operator=(std::size_t a_offset) noexcept
Definition: Relocation.h:833
constexpr std::size_t offset() const noexcept
Definition: Relocation.h:840
Definition: Relocation.h:875
std::uintptr_t write_vfunc(std::size_t a_idx, std::uintptr_t a_newFunc)
Definition: Relocation.h:952
constexpr std::uintptr_t address() const noexcept
Definition: Relocation.h:941
std::conditional_t< std::is_member_pointer_v< T >||std::is_function_v< std::remove_pointer_t< T > >, std::decay_t< T >, T > value_type
Definition: Relocation.h:881
Relocation & operator=(ID a_id)
Definition: Relocation.h:913
value_type get() const noexcept(std::is_nothrow_copy_constructible_v< value_type >)
Definition: Relocation.h:944
Relocation(Offset a_offset)
Definition: Relocation.h:889
auto operator->() const noexcept
Definition: Relocation.h:927
Relocation(ID a_id, std::ptrdiff_t a_offset)
Definition: Relocation.h:897
constexpr Relocation & operator=(std::uintptr_t a_address) noexcept
Definition: Relocation.h:901
constexpr Relocation() noexcept=default
Relocation(ID a_id)
Definition: Relocation.h:893
std::invoke_result_t< const value_type &, Args... > operator()(Args &&... a_args) const noexcept(std::is_nothrow_invocable_v< const value_type &, Args... >)
Definition: Relocation.h:934
std::size_t offset() const
Definition: Relocation.h:942
Relocation & operator=(Offset a_offset)
Definition: Relocation.h:907
std::uintptr_t write_vfunc(std::size_t a_idx, F a_newFunc)
Definition: Relocation.h:962
Definition: Relocation.h:377
std::size_t size() const noexcept
Definition: Relocation.h:402
Name
Definition: Relocation.h:380
@ data
Definition: Relocation.h:384
@ tls
Definition: Relocation.h:386
@ textw
Definition: Relocation.h:387
@ gfids
Definition: Relocation.h:388
@ total
Definition: Relocation.h:389
@ idata
Definition: Relocation.h:382
@ textx
Definition: Relocation.h:381
@ pdata
Definition: Relocation.h:385
@ rdata
Definition: Relocation.h:383
void * pointer() const noexcept
Definition: Relocation.h:404
std::uintptr_t address() const noexcept
Definition: Relocation.h:400
Segment() noexcept=default
std::size_t offset() const noexcept
Definition: Relocation.h:401
T * pointer() const noexcept
Definition: Relocation.h:407
Definition: Relocation.h:275
constexpr decltype(auto) end() const noexcept
Definition: Relocation.h:296
constexpr Version(value_type a_v1, value_type a_v2=0, value_type a_v3=0, value_type a_v4=0) noexcept
Definition: Relocation.h:287
constexpr reference operator[](std::size_t a_idx) noexcept
Definition: Relocation.h:291
std::strong_ordering constexpr compare(const Version &a_rhs) const noexcept
Definition: Relocation.h:299
constexpr decltype(auto) cbegin() const noexcept
Definition: Relocation.h:295
std::string string() const
Definition: Relocation.h:318
constexpr std::uint32_t pack() const noexcept
Definition: Relocation.h:309
constexpr const_reference operator[](std::size_t a_idx) const noexcept
Definition: Relocation.h:292
std::uint16_t value_type
Definition: Relocation.h:277
constexpr decltype(auto) cend() const noexcept
Definition: Relocation.h:297
value_type & reference
Definition: Relocation.h:278
const value_type & const_reference
Definition: Relocation.h:279
constexpr Version() noexcept=default
constexpr decltype(auto) begin() const noexcept
Definition: Relocation.h:294
std::wstring wstring() const
Definition: Relocation.h:329
Definition: Relocation.h:1077
constexpr bool match(std::span< const std::byte, sizeof...(Rules)> a_bytes) const noexcept
Definition: Relocation.h:1081
void match_or_fail(std::uintptr_t a_address, std::source_location a_loc=std::source_location::current()) const noexcept
Definition: Relocation.h:1092
bool match(std::uintptr_t a_address) const noexcept
Definition: Relocation.h:1087
Definition: Relocation.h:64
~memory_map()
Definition: Relocation.h:77
memory_map & operator=(memory_map &&a_rhs) noexcept
Definition: Relocation.h:81
memory_map & operator=(const memory_map &)=delete
memory_map() noexcept=default
void * data() noexcept
Definition: Relocation.h:93
bool create(stl::zwstring a_name, std::size_t a_size)
bool open(stl::zwstring a_name, std::size_t a_size)
Definition: Relocation.h:1028
static constexpr bool match(std::byte a_byte) noexcept
Definition: Relocation.h:1030
Definition: Relocation.h:1050
static constexpr bool match(std::byte) noexcept
Definition: Relocation.h:1052
constexpr bool space(char a_ch) noexcept
Definition: Relocation.h:987
constexpr bool hexadecimal(char a_ch) noexcept
Definition: Relocation.h:980
constexpr bool wildcard(char a_ch) noexcept
Definition: Relocation.h:992
consteval std::byte hexacharacters_to_hexadecimal(char a_hi, char a_lo) noexcept
Definition: Relocation.h:1002
typename member_function_non_pod_type< F >::type member_function_non_pod_type_t
Definition: Relocation.h:124
decltype(auto) invoke_member_function_non_pod(F &&a_func, First &&a_first, Rest &&... a_rest) noexcept(std::is_nothrow_invocable_v< F, First, Rest... >)
Definition: Relocation.h:183
consteval auto make_byte_array(Bytes... a_bytes) noexcept -> std::array< std::byte, sizeof...(Bytes)>
Definition: Relocation.h:1140
typename member_function_pod_type< F >::type member_function_pod_type_t
Definition: Relocation.h:113
constexpr bool is_x64_pod_v
Definition: Relocation.h:177
void consteval_error(const char *a_error)
constexpr auto do_make_pattern() noexcept
Definition: Relocation.h:1112
REL_MAKE_MEMBER_FUNCTION_POD_TYPE()
REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE()
Definition: Relocation.h:60
std::invoke_result_t< F, Args... > invoke(F &&a_func, Args &&... a_args) noexcept(std::is_nothrow_invocable_v< F, Args... >)
Definition: Relocation.h:201
std::optional< Version > get_file_version(stl::zwstring a_filename)
Definition: Relocation.h:347
constexpr std::uint8_t NOP
Definition: Relocation.h:196
constexpr std::strong_ordering operator<=>(const Version &a_lhs, const Version &a_rhs) noexcept
Definition: Relocation.h:345
constexpr std::uint8_t INT3
Definition: Relocation.h:198
constexpr bool operator==(const Version &a_lhs, const Version &a_rhs) noexcept
Definition: Relocation.h:344
void safe_fill(std::uintptr_t a_dst, std::uint8_t a_value, std::size_t a_count)
Definition: Relocation.h:252
void safe_write(std::uintptr_t a_dst, const void *a_src, std::size_t a_count)
Definition: Relocation.h:218
constexpr auto make_pattern() noexcept
Definition: Relocation.h:1149
constexpr std::uint8_t RET
Definition: Relocation.h:197
std::uint32_t GetFileVersionInfoSize(const char *a_filename, std::uint32_t *a_handle) noexcept
std::uint32_t GetEnvironmentVariable(const char *a_name, char *a_buffer, std::uint32_t a_size) noexcept
bool VirtualProtect(void *a_address, std::size_t a_size, std::uint32_t a_newProtect, std::uint32_t *a_oldProtect) noexcept
constexpr auto IMAGE_SCN_MEM_WRITE
Definition: WinAPI.h:7
constexpr auto PAGE_EXECUTE_READWRITE
Definition: WinAPI.h:11
void * GetModuleHandle(const char *a_moduleName) noexcept
bool GetFileVersionInfo(const char *a_filename, std::uint32_t a_handle, std::uint32_t a_len, void *a_data) noexcept
constexpr auto IMAGE_SCN_MEM_EXECUTE
Definition: WinAPI.h:6
bool VerQueryValue(const void *a_block, const char *a_subBlock, void **a_buffer, unsigned int *a_len) noexcept
void report_and_fail(std::string_view a_msg, std::source_location a_loc=std::source_location::current())
Definition: PCH.h:587
auto utf16_to_utf8(std::wstring_view a_in) noexcept -> std::optional< std::string >
Definition: PCH.h:559
auto utf8_to_utf16(std::string_view a_in) noexcept -> std::optional< std::wstring >
Definition: PCH.h:533
basic_zstring< wchar_t > zwstring
Definition: PCH.h:79
Definition: EffectArchetypes.h:65
bool getline(RE::NiBinaryStream &a_input, std::basic_string< CharT, Traits, Allocator > &a_str)
Definition: NiBinaryStream.h:96
std::string to_string(RE::EffectArchetype a_archetype)
Definition: EffectArchetypes.h:66
Definition: Relocation.h:155
Definition: Relocation.h:145
Definition: Relocation.h:135
Definition: Relocation.h:150
Definition: Relocation.h:116
Definition: Relocation.h:105