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));
246 template <std::ranges::contiguous_range R>
251 std::ranges::data(a_data),
252 std::ranges::size(a_data) *
sizeof(std::ranges::range_value_t<R>));
258 safe_write(a_dst, a_data.data(), a_data.size_bytes());
261 inline void safe_fill(std::uintptr_t a_dst, std::uint8_t a_value, std::size_t a_count)
263 std::uint32_t old{ 0 };
266 reinterpret_cast<void*
>(a_dst),
269 std::addressof(old));
271 std::fill_n(
reinterpret_cast<std::uint8_t*
>(a_dst), a_count, a_value);
274 reinterpret_cast<void*
>(a_dst),
277 std::addressof(old));
280 assert(success != 0);
297 _impl{ a_v1, a_v2, a_v3, a_v4 }
303 [[nodiscard]] constexpr decltype(
auto)
begin() const noexcept {
return _impl.begin(); }
304 [[nodiscard]] constexpr decltype(
auto)
cbegin() const noexcept {
return _impl.cbegin(); }
305 [[nodiscard]] constexpr decltype(
auto)
end() const noexcept {
return _impl.end(); }
306 [[nodiscard]] constexpr decltype(
auto)
cend() const noexcept {
return _impl.cend(); }
308 [[nodiscard]] std::strong_ordering constexpr
compare(
const Version& a_rhs)
const noexcept
310 for (std::size_t i = 0; i < _impl.size(); ++i) {
311 if ((*
this)[i] != a_rhs[i]) {
312 return (*
this)[i] < a_rhs[i] ? std::strong_ordering::less : std::strong_ordering::greater;
315 return std::strong_ordering::equal;
318 [[nodiscard]] constexpr std::uint32_t
pack() const noexcept
320 return static_cast<std::uint32_t
>(
321 (_impl[0] & 0x0FF) << 24u |
322 (_impl[1] & 0x0FF) << 16u |
323 (_impl[2] & 0xFFF) << 4u |
324 (_impl[3] & 0x00F) << 0u);
330 for (
auto&& ver : _impl) {
331 result += std::to_string(ver);
341 for (
auto&& ver : _impl) {
342 result += std::to_wstring(ver);
350 std::array<value_type, 4> _impl{ 0, 0, 0, 0 };
354 [[nodiscard]] constexpr std::strong_ordering
operator<=>(
const Version& a_lhs,
const Version& a_rhs) noexcept {
return a_lhs.compare(a_rhs); }
368 void* verBuf{
nullptr };
369 std::uint32_t verLen{ 0 };
370 if (!
WinAPI::VerQueryValue(buf.data(), L
"\\StringFileInfo\\040904B0\\ProductVersion", std::addressof(verBuf), std::addressof(verLen))) {
375 std::wistringstream ss(
376 std::wstring(
static_cast<const wchar_t*
>(verBuf), verLen));
378 for (std::size_t i = 0; i < 4 &&
std::getline(ss, token, L
'.'); ++i) {
379 version[i] =
static_cast<std::uint16_t
>(std::stoi(token));
403 Segment(
std::uintptr_t a_proxyBase,
std::uintptr_t a_address,
std::uintptr_t a_size) noexcept :
404 _proxyBase(a_proxyBase),
409 [[nodiscard]] std::uintptr_t
address() const noexcept {
return _address; }
410 [[nodiscard]] std::size_t
offset() const noexcept {
return address() - _proxyBase; }
411 [[nodiscard]] std::size_t
size() const noexcept {
return _size; }
413 [[nodiscard]]
void*
pointer() const noexcept {
return reinterpret_cast<void*
>(
address()); }
418 return static_cast<T*
>(
pointer());
422 std::uintptr_t _proxyBase{ 0 };
423 std::uintptr_t _address{ 0 };
424 std::size_t _size{ 0 };
438 [[nodiscard]] constexpr std::uintptr_t
base() const noexcept {
return _base; }
444 [[nodiscard]]
void*
pointer() const noexcept {
return reinterpret_cast<void*
>(
base()); }
449 return static_cast<T*
>(
pointer());
461 constexpr
Module() = default;
466 if (handle ==
nullptr) {
468 "Failed to obtain module handle for game executable."sv);
470 _base =
reinterpret_cast<std::uintptr_t
>(handle);
475 static_cast<std::uint32_t
>(_filename.size()));
481 void load_segments();
491 "Failed to obtain file version info for: {}\n"
492 "Please contact the author of this script extender plugin for further assistance."sv,
497 static constexpr std::array SEGMENTS{
509 inline static bool _loaded{
false };
510 std::array<wchar_t, SKSE::WinAPI::MAX_PATH> _filename{ L
"" };
511 std::array<Segment, Segment::total> _segments{};
513 std::uintptr_t _base{ 0 };
516 inline constinit Module Module::_singleton;
534 std::uint64_t offset;
536 constexpr
auto operator<=>(
const mapping_t&)
const noexcept =
default;
541 constexpr
bool operator()(
const mapping_t& a_lhs,
const mapping_t& a_rhs)
const noexcept
543 return a_lhs.offset < a_rhs.offset;
550 std::uint64_t backup;
552 constexpr
auto operator<=>(
const backup_t&)
const noexcept =
default;
565 template <
class ExecutionPolicy>
567 requires(std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>)
572 std::sort(a_policy, _offset2id.begin(), _offset2id.end(), comp_offset());
579 [[nodiscard]] std::uint64_t
operator()(std::size_t a_offset)
const
581 const mapping_t elem{ 0, a_offset };
582 const auto it = std::ranges::lower_bound(_offset2id, elem, comp_offset());
583 if (it == _offset2id.end()) {
586 "Failed to find the offset within the database: 0x{:08X}"sv,
621 [[nodiscard]]
inline std::size_t
id2offset(std::uint64_t a_id)
const
623 auto it = std::ranges::lower_bound(_id2offset, mapping_t{ a_id, 0 });
624 if (it == _id2offset.end() || it->id != a_id) {
625 const auto backup = std::ranges::lower_bound(_backups, backup_t{ a_id, 0 });
626 if (backup != _backups.end() && backup->id == a_id) {
627 a_id = backup->backup;
628 it = std::ranges::lower_bound(_id2offset, mapping_t{ a_id, 0 });
632 if (it == _id2offset.end() || it->id != a_id) {
635 "Failed to find the id within the address library: {}\n"
636 "This means this script extender plugin is incompatible with the address "
637 "library for this version of the game, and thus does not support it."sv,
641 return static_cast<std::size_t
>(it->offset);
658 void read(binary_io::file_istream& a_in)
660 const auto [format] = a_in.read<std::int32_t>();
664 "Unsupported address library format: {}\n"
665 "This means this script extender plugin is incompatible with the address "
666 "library available for this version of the game, and thus does not "
671 const auto [major, minor, patch, revision] =
672 a_in.read<std::int32_t, std::int32_t, std::int32_t, std::int32_t>();
673 _version[0] =
static_cast<std::uint16_t
>(major);
674 _version[1] =
static_cast<std::uint16_t
>(minor);
675 _version[2] =
static_cast<std::uint16_t
>(patch);
676 _version[3] =
static_cast<std::uint16_t
>(revision);
678 const auto [nameLen] = a_in.read<std::int32_t>();
679 a_in.seek_relative(nameLen);
681 a_in.read(_pointerSize, _addressCount);
684 [[nodiscard]] std::size_t address_count()
const noexcept {
return static_cast<std::size_t
>(_addressCount); }
685 [[nodiscard]] std::uint64_t pointer_size()
const noexcept {
return static_cast<std::uint64_t
>(_pointerSize); }
686 [[nodiscard]]
Version version()
const noexcept {
return _version; }
690 std::int32_t _pointerSize{ 0 };
691 std::int32_t _addressCount{ 0 };
699 const auto filename =
702 "Data/SKSE/Plugins/versionlib-{}.bin"sv,
704 .value_or(L
"<unknown filename>"s);
705 load_file(filename, version);
711 binary_io::file_istream in(a_filename);
714 if (header.version() != a_version) {
718 auto mapname = L
"CommonLibSSEOffsets-v2-"s;
719 mapname += a_version.wstring();
720 const auto byteSize =
static_cast<std::size_t
>(header.address_count()) *
sizeof(mapping_t);
721 if (_mmap.
open(mapname, byteSize)) {
722 _id2offset = {
static_cast<mapping_t*
>(_mmap.
data()), header.address_count() };
723 }
else if (_mmap.
create(mapname, byteSize)) {
724 _id2offset = {
static_cast<mapping_t*
>(_mmap.
data()), header.address_count() };
725 unpack_file(in, header);
729 [](
auto&& a_lhs,
auto&& a_rhs) {
730 return a_lhs.id < a_rhs.id;
735 }
catch (
const std::system_error&) {
738 "Failed to locate an appropriate address library with the path: {}\n"
739 "This means you are missing the address library for this specific version of "
740 "the game. Please continue to the mod page for address library to download "
741 "an appropriate version. If one is not available, then it is likely that "
742 "address library has not yet added support for this version of the game."sv,
747 void unpack_file(binary_io::file_istream& a_in, header_t a_header)
749 std::uint8_t type = 0;
750 std::uint64_t
id = 0;
751 std::uint64_t offset = 0;
752 std::uint64_t prevID = 0;
753 std::uint64_t prevOffset = 0;
754 for (
auto& mapping : _id2offset) {
756 const auto lo =
static_cast<std::uint8_t
>(type & 0xF);
757 const auto hi =
static_cast<std::uint8_t
>(type >> 4);
767 id = prevID + std::get<0>(a_in.read<std::uint8_t>());
770 id = prevID - std::get<0>(a_in.read<std::uint8_t>());
773 id = prevID + std::get<0>(a_in.read<std::uint16_t>());
776 id = prevID - std::get<0>(a_in.read<std::uint16_t>());
779 std::tie(
id) = a_in.read<std::uint16_t>();
782 std::tie(
id) = a_in.read<std::uint32_t>();
788 const std::uint64_t tmp = (hi & 8) != 0 ? (prevOffset / a_header.pointer_size()) : prevOffset;
798 offset = tmp + std::get<0>(a_in.read<std::uint8_t>());
801 offset = tmp - std::get<0>(a_in.read<std::uint8_t>());
804 offset = tmp + std::get<0>(a_in.read<std::uint16_t>());
807 offset = tmp - std::get<0>(a_in.read<std::uint16_t>());
810 std::tie(offset) = a_in.read<std::uint16_t>();
813 std::tie(offset) = a_in.read<std::uint32_t>();
820 offset *= a_header.pointer_size();
823 mapping = { id, offset };
831 inline static bool _loaded{
false };
832 detail::memory_map _mmap;
833 std::span<mapping_t> _id2offset;
836 inline static constexpr
auto _backups =
837 std::to_array<backup_t>({
843 static_assert(std::ranges::is_sorted(_backups));
846 inline constinit IDDatabase IDDatabase::_singleton;
863 explicit constexpr
Offset(
std::
size_t a_offset) noexcept :
874 [[nodiscard]] constexpr std::size_t
offset() const noexcept {
return _offset; }
877 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().
base(); }
879 std::size_t _offset{ 0 };
885 constexpr
ID() noexcept = default;
887 explicit constexpr
ID(
std::uint64_t a_id) noexcept :
898 [[nodiscard]] constexpr std::uint64_t
id() const noexcept {
return _id; }
902 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().
base(); }
904 std::uint64_t _id{ 0 };
910 using reg_t = std::pair<std::uint64_t, std::uintptr_t*>;
918 for (
const auto& [
id, offsetAddr] : std::span(_buffer.get(), _size)) {
926 if (_size == _capacity) {
929 std::construct_at(&_buffer[_size++], a_ID, a_offsetAddr);
942 const std::size_t capacity = _capacity > 0 ? _capacity * 2 : 1;
943 auto buffer = std::make_unique<reg_t[]>(capacity);
944 std::memcpy(buffer.get(), _buffer.get(), _capacity *
sizeof(
reg_t));
945 _buffer.swap(buffer);
946 _capacity = capacity;
951 std::unique_ptr<reg_t[]> _buffer{
nullptr };
952 std::size_t _size{ 0 };
953 std::size_t _capacity{ 0 };
956 inline constinit AddressManager AddressManager::_singleton;
963 template <std::u
int64_t ID>
977 std::uintptr_t _offset;
980 inline static Cache _cache;
989 std::is_member_pointer_v<T> || std::is_function_v<std::remove_pointer_t<T>>,
1008 _impl{ a_id.
address() + a_offset }
1029 template <
class U = value_type>
1030 [[nodiscard]] decltype(
auto) operator*() const noexcept
1036 template <
class U = value_type>
1043 template <
class... Args>
1045 noexcept(std::is_nothrow_invocable_v<const value_type&, Args...>)
1046 requires(std::invocable<const value_type&, Args...>)
1051 [[nodiscard]] constexpr std::uintptr_t
address() const noexcept {
return _impl; }
1052 [[nodiscard]] std::size_t
offset()
const {
return _impl - base(); }
1058 return stl::unrestricted_cast<value_type>(_impl);
1061 template <
class U = value_type>
1062 std::uintptr_t
write_vfunc(std::size_t a_idx, std::uintptr_t a_newFunc)
1063 requires(std::same_as<U, std::uintptr_t>)
1065 const auto addr =
address() + (
sizeof(
void*) * a_idx);
1066 const auto result = *
reinterpret_cast<std::uintptr_t*
>(addr);
1073 requires(std::same_as<value_type, std::uintptr_t>)
1075 return write_vfunc(a_idx, stl::unrestricted_cast<std::uintptr_t>(a_newFunc));
1080 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().
base(); }
1083 std::uintptr_t _impl{ 0 };
1088 namespace characters
1092 return (
'0' <= a_ch && a_ch <=
'9') ||
1093 (
'A' <= a_ch && a_ch <=
'F') ||
1094 (
'a' <= a_ch && a_ch <=
'f');
1097 [[nodiscard]] constexpr
bool space(
char a_ch) noexcept
1102 [[nodiscard]] constexpr
bool wildcard(
char a_ch) noexcept
1114 constexpr
auto lut = []() noexcept {
1115 std::array<std::uint8_t, std::numeric_limits<unsigned char>::max() + 1> a = {};
1117 const auto iterate = [&](std::uint8_t a_iFirst,
unsigned char a_cFirst,
unsigned char a_cLast) noexcept {
1118 for (; a_cFirst <= a_cLast; ++a_cFirst, ++a_iFirst) {
1119 a[a_cFirst] = a_iFirst;
1123 iterate(0,
'0',
'9');
1124 iterate(0xA,
'A',
'F');
1125 iterate(0xa,
'a',
'f');
1130 return static_cast<std::byte
>(
1131 lut[
static_cast<unsigned char>(a_hi)] * 0x10u +
1132 lut[
static_cast<unsigned char>(a_lo)]);
1136 template <
char HI,
char LO>
1140 [[nodiscard]]
static constexpr
bool match(std::byte a_byte) noexcept
1143 return a_byte == expected;
1162 [[nodiscard]]
static constexpr
bool match(std::byte) noexcept
1173 template <
char,
char>
1176 template <
char C1,
char C2>
1180 template <
char C1,
char C2>
1185 template <class... Rules>
1189 static_assert(
sizeof...(Rules) >= 1,
"must provide at least 1 rule for the pattern matcher");
1191 [[nodiscard]] constexpr
bool match(std::span<
const std::byte,
sizeof...(Rules)> a_bytes)
const noexcept
1194 return (Rules::match(a_bytes[i++]) && ...);
1197 [[nodiscard]]
bool match(std::uintptr_t a_address)
const noexcept
1199 return this->match(*
reinterpret_cast<const std::byte(*)[sizeof...(Rules)]
>(a_address));
1202 void match_or_fail(std::uintptr_t a_address, std::source_location a_loc = std::source_location::current()) const noexcept
1204 if (!this->match(a_address)) {
1208 "A pattern has failed to match.\n"
1209 "This means the plugin is incompatible with the current version of the game ({}.{}.{}). "
1210 "Head to the mod page of this plugin to see if an update is available."sv,
1224 if constexpr (S.length() == 0) {
1226 }
else if constexpr (S.length() == 1) {
1227 constexpr
char c = S[0];
1229 consteval_error(
"the given pattern has an unpaired rule (rules are required to be written in pairs of 2)");
1231 consteval_error(
"the given pattern has trailing characters at the end (which is not allowed)");
1235 if constexpr (std::same_as<rule_t, void>) {
1238 if constexpr (S.length() <= 3) {
1243 consteval_error(
"a space character is required to split byte patterns");
1249 template <
class... Bytes>
1251 -> std::array<std::byte,
sizeof...(Bytes)>
1253 static_assert((std::integral<Bytes> && ...),
"all bytes must be an integral type");
1254 return {
static_cast<std::byte
>(a_bytes)... };
1258 template <stl::nttp::
string S>
1261 return detail::do_make_pattern<S>();
1264 static_assert(make_pattern<"40 10 F2 ??">().match(
1266 static_assert(make_pattern<"B8 D0 ?? ?? D4 6E">().match(
1271 # define STATIC_OFFSET(name) ::REL::StaticID<::RE::Offset::name.id()>()
1273 # define STATIC_OFFSET(name) ::RE::Offset::name
1276 #undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE
1277 #undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER
1278 #undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL
1280 #undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE
1281 #undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER
1282 #undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL
Definition: Relocation.h:908
static AddressManager & get()
Definition: Relocation.h:958
void flush()
Definition: Relocation.h:916
std::pair< std::uint64_t, std::uintptr_t * > reg_t
Definition: Relocation.h:910
void clear()
Definition: Relocation.h:932
void register_address(std::uint64_t a_ID, std::uintptr_t *a_offsetAddr)
Definition: Relocation.h:924
constexpr AddressManager() noexcept=default
Definition: Relocation.h:557
Offset2ID()
Definition: Relocation.h:575
typename container_type::const_iterator const_iterator
Definition: Relocation.h:562
typename container_type::const_reverse_iterator const_reverse_iterator
Definition: Relocation.h:563
const_reverse_iterator crbegin() const noexcept
Definition: Relocation.h:600
Offset2ID(ExecutionPolicy &&a_policy) requires(std
Definition: Relocation.h:566
const_iterator begin() const noexcept
Definition: Relocation.h:593
std::vector< value_type > container_type
Definition: Relocation.h:560
size_type size() const noexcept
Definition: Relocation.h:605
const_reverse_iterator rbegin() const noexcept
Definition: Relocation.h:599
const_reverse_iterator crend() const noexcept
Definition: Relocation.h:603
const_iterator cbegin() const noexcept
Definition: Relocation.h:594
typename container_type::size_type size_type
Definition: Relocation.h:561
const_iterator cend() const noexcept
Definition: Relocation.h:597
std::uint64_t operator()(std::size_t a_offset) const
Definition: Relocation.h:579
mapping_t value_type
Definition: Relocation.h:559
const_reverse_iterator rend() const noexcept
Definition: Relocation.h:602
const_iterator end() const noexcept
Definition: Relocation.h:596
Definition: Relocation.h:529
IDDatabase(IDDatabase &&)=delete
std::size_t id2offset(std::uint64_t a_id) const
Definition: Relocation.h:621
static IDDatabase & get()
Definition: Relocation.h:848
IDDatabase(const IDDatabase &)=delete
IDDatabase & operator=(const IDDatabase &)=delete
static void init()
Definition: Relocation.h:613
IDDatabase & operator=(IDDatabase &&)=delete
Definition: Relocation.h:883
std::size_t offset() const
Definition: Relocation.h:899
constexpr ID & operator=(std::uint64_t a_id) noexcept
Definition: Relocation.h:891
constexpr std::uint64_t id() const noexcept
Definition: Relocation.h:898
constexpr ID() noexcept=default
std::uintptr_t address() const
Definition: Relocation.h:897
Definition: Relocation.h:428
constexpr Version version() const noexcept
Definition: Relocation.h:440
constexpr Segment segment(Segment::Name a_segment) const noexcept
Definition: Relocation.h:442
constexpr stl::zwstring filename() const noexcept
Definition: Relocation.h:439
static void init()
Definition: Relocation.h:432
Module(const Module &)=delete
constexpr ~Module() noexcept=default
T * pointer() const noexcept
Definition: Relocation.h:447
void * pointer() const noexcept
Definition: Relocation.h:444
constexpr std::uintptr_t base() const noexcept
Definition: Relocation.h:438
static Module & get()
Definition: Relocation.h:518
Definition: Relocation.h:859
constexpr Offset() noexcept=default
std::uintptr_t address() const
Definition: Relocation.h:873
constexpr Offset & operator=(std::size_t a_offset) noexcept
Definition: Relocation.h:867
constexpr std::size_t offset() const noexcept
Definition: Relocation.h:874
Definition: Relocation.h:985
constexpr std::uintptr_t address() const noexcept
Definition: Relocation.h:1051
auto operator->() const noexcept requires(std
Definition: Relocation.h:1037
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:991
constexpr Relocation & operator=(std::uintptr_t a_address) noexcept
Definition: Relocation.h:1011
std::invoke_result_t< const value_type &, Args... > operator()(Args &&... a_args) const noexcept(std::is_nothrow_invocable_v< const value_type &, Args... >) requires(std
Definition: Relocation.h:1044
value_type get() const noexcept(std::is_nothrow_copy_constructible_v< value_type >)
Definition: Relocation.h:1054
Relocation(Offset a_offset)
Definition: Relocation.h:999
Relocation(ID a_id, std::ptrdiff_t a_offset)
Definition: Relocation.h:1007
std::uintptr_t write_vfunc(std::size_t a_idx, std::uintptr_t a_newFunc) requires(std
Definition: Relocation.h:1062
std::uintptr_t write_vfunc(std::size_t a_idx, F a_newFunc) requires(std
Definition: Relocation.h:1072
Relocation & operator=(Offset a_offset)
Definition: Relocation.h:1017
constexpr Relocation() noexcept=default
Relocation(ID a_id)
Definition: Relocation.h:1003
Relocation & operator=(ID a_id)
Definition: Relocation.h:1023
std::size_t offset() const
Definition: Relocation.h:1052
Definition: Relocation.h:386
std::size_t size() const noexcept
Definition: Relocation.h:411
void * pointer() const noexcept
Definition: Relocation.h:413
Name
Definition: Relocation.h:389
@ data
Definition: Relocation.h:393
@ tls
Definition: Relocation.h:395
@ textw
Definition: Relocation.h:396
@ gfids
Definition: Relocation.h:397
@ total
Definition: Relocation.h:398
@ idata
Definition: Relocation.h:391
@ textx
Definition: Relocation.h:390
@ pdata
Definition: Relocation.h:394
@ rdata
Definition: Relocation.h:392
T * pointer() const noexcept
Definition: Relocation.h:416
constexpr Segment() noexcept=default
std::uintptr_t address() const noexcept
Definition: Relocation.h:409
std::size_t offset() const noexcept
Definition: Relocation.h:410
Definition: Relocation.h:965
Definition: Relocation.h:284
constexpr decltype(auto) end() const noexcept
Definition: Relocation.h:305
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:296
constexpr reference operator[](std::size_t a_idx) noexcept
Definition: Relocation.h:300
constexpr decltype(auto) cbegin() const noexcept
Definition: Relocation.h:304
std::string string() const
Definition: Relocation.h:327
constexpr std::uint32_t pack() const noexcept
Definition: Relocation.h:318
constexpr const_reference operator[](std::size_t a_idx) const noexcept
Definition: Relocation.h:301
std::uint16_t value_type
Definition: Relocation.h:286
constexpr decltype(auto) cend() const noexcept
Definition: Relocation.h:306
value_type & reference
Definition: Relocation.h:287
const value_type & const_reference
Definition: Relocation.h:288
constexpr Version() noexcept=default
constexpr std::strong_ordering compare(const Version &a_rhs) const noexcept
Definition: Relocation.h:308
constexpr decltype(auto) begin() const noexcept
Definition: Relocation.h:303
std::wstring wstring() const
Definition: Relocation.h:338
Definition: Relocation.h:1187
constexpr bool match(std::span< const std::byte, sizeof...(Rules)> a_bytes) const noexcept
Definition: Relocation.h:1191
void match_or_fail(std::uintptr_t a_address, std::source_location a_loc=std::source_location::current()) const noexcept
Definition: Relocation.h:1202
bool match(std::uintptr_t a_address) const noexcept
Definition: Relocation.h:1197
Definition: Relocation.h:64
~memory_map()
Definition: Relocation.h:77
void * data() noexcept
Definition: Relocation.h:93
constexpr memory_map & operator=(memory_map &&a_rhs) noexcept
Definition: Relocation.h:81
constexpr memory_map() noexcept=default
bool create(stl::zwstring a_name, std::size_t a_size)
memory_map & operator=(const memory_map &)=delete
bool open(stl::zwstring a_name, std::size_t a_size)
Definition: Relocation.h:1138
static constexpr bool match(std::byte a_byte) noexcept
Definition: Relocation.h:1140
Definition: Relocation.h:1160
static constexpr bool match(std::byte) noexcept
Definition: Relocation.h:1162
constexpr bool space(char a_ch) noexcept
Definition: Relocation.h:1097
constexpr bool hexadecimal(char a_ch) noexcept
Definition: Relocation.h:1090
constexpr bool wildcard(char a_ch) noexcept
Definition: Relocation.h:1102
consteval std::byte hexacharacters_to_hexadecimal(char a_hi, char a_lo) noexcept
Definition: Relocation.h:1112
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:1250
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:1222
REL_MAKE_MEMBER_FUNCTION_POD_TYPE()
REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE()
Definition: Relocation.h:60
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:354
constexpr std::uint8_t INT3
Definition: Relocation.h:198
constexpr bool operator==(const Version &a_lhs, const Version &a_rhs) noexcept
Definition: Relocation.h:353
void safe_fill(std::uintptr_t a_dst, std::uint8_t a_value, std::size_t a_count)
Definition: Relocation.h:261
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:1259
std::optional< Version > get_file_version(stl::zwstring a_filename)
Definition: Relocation.h:356
std::invoke_result_t< F, Args... > invoke(F &&a_func, Args &&... a_args) noexcept(std::is_nothrow_invocable_v< F, Args... >) requires(std
Definition: Relocation.h:201
constexpr std::uint8_t RET
Definition: Relocation.h:197
auto make_pair(T1 &&a_first, T2 &&a_second)
Definition: BSTTuple.h:177
std::uint32_t GetFileVersionInfoSize(const char *a_filename, std::uint32_t *a_handle) 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
std::uint32_t GetModuleFileName(void *a_module, char *a_filename, std::uint32_t a_size) noexcept
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
string(const CharT(&)[N]) -> string< CharT, N - 1 >
void report_and_fail(std::string_view a_msg, std::source_location a_loc=std::source_location::current())
Definition: PCH.h:621
auto utf16_to_utf8(std::wstring_view a_in) noexcept -> std::optional< std::string >
Definition: PCH.h:593
auto utf8_to_utf16(std::string_view a_in) noexcept -> std::optional< std::wstring >
Definition: PCH.h:567
requires(std::invocable< std::remove_reference_t< EF >>) class scope_exit
Definition: PCH.h:190
basic_zstring< wchar_t > zwstring
Definition: PCH.h:78
Definition: NiBinaryStream.h:94
bool getline(RE::NiBinaryStream &a_input, std::basic_string< CharT, Traits, Allocator > &a_str)
Definition: NiBinaryStream.h:96
Definition: Relocation.h:155
Definition: Relocation.h:145
Definition: Relocation.h:135
Definition: Relocation.h:150
Definition: Relocation.h:116
Definition: Relocation.h:105