5#define REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL(a_nopropQual, a_propQual, ...) \
10 struct member_function_pod_type<R (Cls::*)(Args...) __VA_ARGS__ a_nopropQual a_propQual> \
12 using type = R(__VA_ARGS__ Cls*, Args...) a_propQual; \
19 struct member_function_pod_type<R (Cls::*)(Args..., ...) __VA_ARGS__ a_nopropQual a_propQual> \
21 using type = R(__VA_ARGS__ Cls*, Args..., ...) a_propQual; \
24#define REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(a_qualifer, ...) \
25 REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL(a_qualifer, , ##__VA_ARGS__) \
26 REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL(a_qualifer, noexcept, ##__VA_ARGS__)
28#define REL_MAKE_MEMBER_FUNCTION_POD_TYPE(...) \
29 REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(, __VA_ARGS__) \
30 REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(&, ##__VA_ARGS__) \
31 REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER(&&, ##__VA_ARGS__)
33#define REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL(a_nopropQual, a_propQual, ...) \
38 struct member_function_non_pod_type<R (Cls::*)(Args...) __VA_ARGS__ a_nopropQual a_propQual> \
40 using type = R&(__VA_ARGS__ Cls*, void*, Args...)a_propQual; \
47 struct member_function_non_pod_type<R (Cls::*)(Args..., ...) __VA_ARGS__ a_nopropQual a_propQual> \
49 using type = R&(__VA_ARGS__ Cls*, void*, Args..., ...)a_propQual; \
52#define REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(a_qualifer, ...) \
53 REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL(a_qualifer, , ##__VA_ARGS__) \
54 REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL(a_qualifer, noexcept, ##__VA_ARGS__)
56#define REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE(...) \
57 REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(, __VA_ARGS__) \
58 REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(&, ##__VA_ARGS__) \
59 REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER(&&, ##__VA_ARGS__)
61#if defined(ENABLE_SKYRIM_VR) && (defined(ENABLE_SKYRIM_AE) || defined(ENABLE_SKYRIM_SE))
65# define SKYRIM_CROSS_VR
68#if !defined(ENABLE_SKYRIM_AE) || (!defined(ENABLE_SKYRIM_SE) && !defined(ENABLE_SKYRIM_VR))
76# define SKYRIM_ADDR constexpr
85# define SKYRIM_ADDR inline
88#if (!defined(ENABLE_SKYRIM_AE) && !defined(ENABLE_SKYRIM_VR)) || (!defined(ENABLE_SKYRIM_SE) && !defined(ENABLE_SKYRIM_VR)) || (!defined(ENABLE_SKYRIM_AE) && !defined(ENABLE_SKYRIM_SE))
96# define SKYRIM_REL constexpr
105# define SKYRIM_REL_CONSTEXPR constexpr
114# define SKYRIM_REL inline
123# define SKYRIM_REL_CONSTEXPR
126#ifndef SKYRIM_CROSS_VR
134# define SKYRIM_REL_VR constexpr
143# define SKYRIM_REL_VR_CONSTEXPR constexpr
152# define SKYRIM_REL_VR_VIRTUAL virtual
161# define SKYRIM_REL_VR inline
170# define SKYRIM_REL_VR_CONSTEXPR
179# define SKYRIM_REL_VR_VIRTUAL
191 _mapping(a_rhs._mapping),
193 a_rhs._mapping =
nullptr;
194 a_rhs._view =
nullptr;
202 if (
this != std::addressof(a_rhs)) {
203 _mapping = a_rhs._mapping;
204 a_rhs._mapping =
nullptr;
207 a_rhs._view =
nullptr;
212 [[nodiscard]]
void *
data() noexcept {
return _view; }
221 void *_mapping{
nullptr};
222 void *_view{
nullptr};
252 std::bool_constant<sizeof(T) == 1>,
253 std::bool_constant<sizeof(T) == 2>,
254 std::bool_constant<sizeof(T) == 4>,
255 std::bool_constant<sizeof(T) == 8>> {
261 std::is_trivially_constructible<T>,
262 std::is_trivially_destructible<T>,
263 std::is_trivially_copy_assignable<T>,
265 std::is_polymorphic<T>>> {
270 std::is_standard_layout<T> {
273 template<
class T,
class =
void>
282 std::is_union_v<T>>> :
290 std::is_class_v<T>>> :
293 meets_function_req<T>,
294 meets_member_req<T>> {
305 noexcept(std::is_nothrow_invocable_v<F, First, Rest...>) {
306 using result_t = std::invoke_result_t<F, First, Rest...>;
307 std::aligned_storage_t<
sizeof(result_t),
alignof(result_t)> result;
310 auto func = stl::unrestricted_cast<func_t *>(std::forward<F>(a_func));
312 return func(std::forward<First>(a_first), std::addressof(result), std::forward<Rest>(a_rest)...);
316 inline constexpr std::uint8_t
NOP = 0x90;
317 inline constexpr std::uint8_t
NOP2[] = { 0x66, 0x90 };
318 inline constexpr std::uint8_t
NOP3[] = { 0x0F, 0x1F, 0x00 };
319 inline constexpr std::uint8_t
NOP4[] = { 0x0F, 0x1F, 0x40, 0x00 };
320 inline constexpr std::uint8_t
NOP5[] = { 0x0F, 0x1F, 0x44, 0x00, 0x00 };
321 inline constexpr std::uint8_t
NOP6[] = { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 };
322 inline constexpr std::uint8_t
NOP7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 };
323 inline constexpr std::uint8_t
NOP8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
324 inline constexpr std::uint8_t
NOP9[] = { 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
326 inline constexpr std::uint8_t
JMP8 = 0xEB;
327 inline constexpr std::uint8_t
JMP32 = 0xE9;
328 inline constexpr std::uint8_t
RET = 0xC3;
329 inline constexpr std::uint8_t
INT3 = 0xCC;
331 template<
class F,
class... Args>
332 std::invoke_result_t<F, Args...>
invoke(F &&a_func, Args &&... a_args)
333 noexcept(std::is_nothrow_invocable_v<F, Args...>)
334 requires(std::invocable<F, Args...>)
336 if constexpr (std::is_member_function_pointer_v<std::decay_t<F>>) {
339 auto func = stl::unrestricted_cast<func_t *>(std::forward<F>(a_func));
340 return func(std::forward<Args>(a_args)...);
345 return std::forward<F>(a_func)(std::forward<Args>(a_args)...);
349 inline void safe_write(std::uintptr_t a_dst,
const void *a_src, std::size_t a_count) {
350 std::uint32_t old{0};
353 reinterpret_cast<void *
>(a_dst),
356 std::addressof(old));
358 std::memcpy(
reinterpret_cast<void *
>(a_dst), a_src, a_count);
361 reinterpret_cast<void *
>(a_dst),
364 std::addressof(old));
367 assert(success != 0);
370 template<std::
integral T>
372 safe_write(a_dst, std::addressof(a_data),
sizeof(T));
377 safe_write(a_dst, a_data.data(), a_data.size_bytes());
380 inline void safe_fill(std::uintptr_t a_dst, std::uint8_t a_value, std::size_t a_count) {
381 std::uint32_t old{0};
384 reinterpret_cast<void *
>(a_dst),
387 std::addressof(old));
389 std::fill_n(
reinterpret_cast<std::uint8_t *
>(a_dst), a_count, a_value);
392 reinterpret_cast<void *
>(a_dst),
395 std::addressof(old));
398 assert(success != 0);
413 _impl{a_v1, a_v2, a_v3, a_v4} {}
415 explicit constexpr Version(std::string_view a_version) {
416 std::array<value_type, 4> powers{1, 1, 1, 1};
417 std::size_t position = 0;
418 for (std::size_t i = 0; i < a_version.size(); ++i) {
419 if (a_version[i] ==
'.') {
420 if (++position == powers.size()) {
421 throw std::invalid_argument(
"Too many parts in version number.");
424 powers[position] *= 10;
428 for (std::size_t i = 0; i < a_version.size(); ++i) {
429 if (a_version[i] ==
'.') {
431 }
else if (a_version[i] <
'0' || a_version[i] >
'9') {
432 throw std::invalid_argument(
"Invalid character in version number.");
434 powers[position] /= 10;
435 _impl[position] +=
static_cast<value_type>((a_version[i] -
'0') * powers[position]);
444 [[nodiscard]]
constexpr decltype(
auto)
begin()
const noexcept {
return _impl.begin(); }
446 [[nodiscard]]
constexpr decltype(
auto)
cbegin()
const noexcept {
return _impl.cbegin(); }
448 [[nodiscard]]
constexpr decltype(
auto)
end()
const noexcept {
return _impl.end(); }
450 [[nodiscard]]
constexpr decltype(
auto)
cend()
const noexcept {
return _impl.cend(); }
452 [[nodiscard]] std::strong_ordering
constexpr compare(
const Version &a_rhs)
const noexcept {
453 for (std::size_t i = 0; i < _impl.size(); ++i) {
454 if ((*
this)[i] != a_rhs[i]) {
455 return (*
this)[i] < a_rhs[i] ? std::strong_ordering::less : std::strong_ordering::greater;
458 return std::strong_ordering::equal;
461 [[nodiscard]]
constexpr std::uint32_t
pack() const noexcept {
462 return static_cast<std::uint32_t
>(
463 (_impl[0] & 0x0FF) << 24u |
464 (_impl[1] & 0x0FF) << 16u |
465 (_impl[2] & 0xFFF) << 4u |
466 (_impl[3] & 0x00F) << 0u);
485 [[nodiscard]] std::string
string(std::string_view a_separator =
"-"sv)
const {
487 for (
auto &&ver: _impl) {
489 result.append(a_separator.data(), a_separator.size());
491 result.erase(result.size() - a_separator.size(), a_separator.size());
495 [[nodiscard]] std::wstring
wstring(std::wstring_view a_separator = L
"-"sv)
const {
497 for (
auto &&ver: _impl) {
498 result += std::to_wstring(ver);
499 result.append(a_separator.data(), a_separator.size());
501 result.erase(result.size() - a_separator.size(), a_separator.size());
505 [[nodiscard]]
static constexpr Version unpack(std::uint32_t a_packedVersion)
noexcept {
507 static_cast<value_type>((a_packedVersion >> 24) & 0x0FF),
508 static_cast<value_type>((a_packedVersion >> 16) & 0x0FF),
509 static_cast<value_type>((a_packedVersion >> 4) & 0xFFF),
510 static_cast<value_type>(a_packedVersion & 0x0F)
515 std::array<value_type, 4> _impl{0, 0, 0, 0};
519 return a_lhs.compare(a_rhs) == std::strong_ordering::equal;
522 [[nodiscard]]
constexpr std::strong_ordering
527 template<std::
size_t Index,
char C>
528 constexpr uint8_t
read_version(std::array<typename REL::Version::value_type, 4> &result) {
529 static_assert(C >=
'0' && C <=
'9',
"Invalid character in semantic version literal.");
530 static_assert(Index < 4,
"Too many components in semantic version literal.");
531 result[Index] += (C -
'0');
535 template<std::size_t Index,
char C,
char... Rest>
536 requires (
sizeof...(Rest) > 0)
537 constexpr uint8_t
read_version(std::array<typename REL::Version::value_type, 4> &result) {
538 static_assert(C ==
'.' || (C >=
'0' && C <=
'9'),
"Invalid character in semantic version literal.");
539 static_assert(Index < 4,
"Too many components in semantic version literal.");
540 if constexpr (C ==
'.') {
545 result[Index] += (C -
'0') * position;
546 return position * 10;
553 std::array<typename REL::Version::value_type, 4> result{0, 0, 0, 0};
558 [[nodiscard]]
constexpr REL::Version operator ""_v(
const char *str, std::size_t len) {
559 return Version(std::string_view(str, len));
570 if (!
GetFileVersionInfo(a_filename.data(), 0,
static_cast<std::uint32_t
>(buf.size()), buf.data())) {
574 void *verBuf{
nullptr};
575 std::uint32_t verLen{0};
576 if (!
VerQueryValue(buf.data(), L
"\\StringFileInfo\\040904B0\\ProductVersion", std::addressof(verBuf),
577 std::addressof(verLen))) {
582 std::wistringstream ss(
583 std::wstring(
static_cast<const wchar_t *
>(verBuf), verLen));
585 for (std::size_t i = 0; i < 4 &&
std::getline(ss, token, L
'.'); ++i) {
586 version[i] =
static_cast<std::uint16_t
>(std::stoi(token));
608 Segment(
std::uintptr_t a_proxyBase,
std::uintptr_t a_address,
std::uintptr_t a_size) noexcept:
609 _proxyBase(a_proxyBase),
613 [[nodiscard]] std::uintptr_t
address() const noexcept {
return _address; }
615 [[nodiscard]] std::size_t
offset() const noexcept {
return address() - _proxyBase; }
617 [[nodiscard]] std::size_t
size() const noexcept {
return _size; }
619 [[nodiscard]]
void *
pointer() const noexcept {
return reinterpret_cast<void *
>(
address()); }
623 return static_cast<T *
>(
pointer());
629 std::uintptr_t _proxyBase{0};
630 std::uintptr_t _address{0};
631 std::size_t _size{0};
659 if (_initialized.load(std::memory_order_relaxed)) {
662 [[maybe_unused]] std::unique_lock lock(_initLock);
668#ifdef ENABLE_COMMONLIBSSE_TESTING
680 static bool inject(std::wstring_view a_filePath) {
683 return _instance.init(a_filePath);
708 constexpr std::size_t bufferSize = 4096;
709 const wchar_t *subKey =
711 LR
"(SOFTWARE\Bethesda Softworks\Skyrim VR)" :
712 LR"(SOFTWARE\Bethesda Softworks\Skyrim Special Edition)";
713 unsigned long length = bufferSize *
sizeof(wchar_t);
714 std::uint8_t value[bufferSize];
719 std::filesystem::path installPath(
reinterpret_cast<wchar_t *
>(value));
720 installPath /= a_runtime ==
Runtime::VR ? L
"SkyrimVR.exe" : L
"SkyrimSE.exe";
721 return inject(installPath.c_str());
725 std::wstring_view a_filename = L
"SkyrimSE.exe"sv, std::uintptr_t a_base = 0,
726 std::array<std::uintptr_t, Segment::total> a_segmentSizes =
727 {0x1603000, 0, 0x8ee000, 0x1887000, 0x15c000, 0x3000, 0x2000, 0x1000}) {
731 if (a_filename.empty() || !a_segmentSizes[0]) {
735 _instance._filename = _instance._filePath = a_filename.data();
736 _instance._version = a_version;
738 switch (a_version[1]) {
749 _instance._runtime = a_runtime;
751 _instance._base = a_base;
753 auto currentAddress = a_base + 0x1000;
754 for (std::size_t i = 0; i < a_segmentSizes.size(); ++i) {
755 auto &
segment = _instance._segments[i];
756 segment._size = a_segmentSizes[i];
766 static void reset() {
767 _initialized =
false;
772 [[nodiscard]] std::uintptr_t
base() const noexcept {
return _base; }
782 [[nodiscard]]
void *
pointer() const noexcept {
return reinterpret_cast<void *
>(
base()); }
786 return static_cast<T *
>(
pointer());
793#if (!defined(ENABLE_SKYRIM_AE) && !defined(ENABLE_SKYRIM_VR))
795#elif (!defined(ENABLE_SKYRIM_SE) && !defined(ENABLE_SKYRIM_VR))
797#elif (!defined(ENABLE_SKYRIM_AE) && !defined(ENABLE_SKYRIM_SE))
800 return get()._runtime;
822#ifndef ENABLE_SKYRIM_VR
824#elif !defined(ENABLE_SKYRIM_AE) && !defined(ENABLE_SKYRIM_SE)
845 const auto getFilename = [&]() {
849 static_cast<std::uint32_t
>(_filename.size()));
852 void *moduleHandle =
nullptr;
853 _filename.resize(getFilename());
854 if (
const auto result = getFilename();
855 result != _filename.size() - 1 ||
857 for (
auto runtime: RUNTIMES) {
865 _filePath = _filename;
869 "Failed to obtain module handle for: \"{0}\".\n"
870 "You have likely renamed the executable to something unexpected. "
871 "Renaming the executable back to \"{0}\" may resolve the issue."sv,
874 return load(moduleHandle,
true);
877 bool init(std::wstring_view a_filePath) {
878 std::filesystem::path exePath(a_filePath);
879 _filename = exePath.filename().wstring();
880 _filePath = exePath.wstring();
882 if (_injectedModule) {
883 return load(_injectedModule,
false);
888 [[nodiscard]]
bool load(
void *a_handle,
bool a_failOnError) {
889 _base =
reinterpret_cast<std::uintptr_t
>(a_handle);
890 if (!load_version(a_failOnError)) {
897 void load_segments();
899 bool load_version(
bool a_failOnError) {
903 switch (_version[1]) {
917 "Failed to obtain file version info for: {}\n"
918 "Please contact the author of this script extender plugin for further assistance."sv,
919 stl::utf16_to_utf8(_filename).value_or(
"<unicode conversion error>"s)), a_failOnError);
924 static constexpr std::array SEGMENTS{
926 std::make_pair(
".idata"sv,
static_cast<std::uint32_t
>(0)),
927 std::make_pair(
".rdata"sv,
static_cast<std::uint32_t
>(0)),
928 std::make_pair(
".data"sv,
static_cast<std::uint32_t
>(0)),
929 std::make_pair(
".pdata"sv,
static_cast<std::uint32_t
>(0)),
930 std::make_pair(
".tls"sv,
static_cast<std::uint32_t
>(0)),
932 std::make_pair(
".gfids"sv,
static_cast<std::uint32_t
>(0))
935 static constexpr auto ENVIRONMENT = L
"SKSE_RUNTIME"sv;
936 static constexpr std::array<std::wstring_view, 2> RUNTIMES{{L
"SkyrimVR.exe",
939 static Module _instance;
940 static inline std::atomic_bool _initialized{
false};
941 static inline std::mutex _initLock;
943 std::wstring _filename;
944 std::wstring _filePath;
945 std::array<Segment, Segment::total> _segments;
947 std::uintptr_t _base{0};
955 std::uint64_t offset;
973 template<
class ExecutionPolicy>
975 requires(std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>)
984 [](
auto &&a_lhs,
auto &&a_rhs) {
985 return a_lhs.offset < a_rhs.offset;
992 [[nodiscard]] std::uint64_t
operator()(std::size_t a_offset)
const {
993 const mapping_t elem{0, a_offset};
994 const auto it = std::lower_bound(
998 [](
auto &&a_lhs,
auto &&a_rhs) {
999 return a_lhs.offset < a_rhs.offset;
1001 if (it == _offset2id.end()) {
1004 "Failed to find the offset within the database: 0x{:08X}"sv,
1034 if (_initialized.load(std::memory_order_relaxed)) {
1037 [[maybe_unused]] std::unique_lock lock(_initLock);
1039 _initialized.store(
true, std::memory_order_relaxed);
1043#ifdef ENABLE_COMMONLIBSSE_TESTING
1044 [[nodiscard]]
static bool inject(std::wstring_view a_filePath,
Format a_format) {
1045 return inject(a_filePath, a_format,
Module::get().version());
1048 [[nodiscard]]
static bool inject(std::wstring_view a_filePath,
Format a_format, Version a_version) {
1049 _initialized =
true;
1053 return _instance.load_file(a_filePath.data(), a_version, 1,
false);
1055 return _instance.load_file(a_filePath.data(), a_version, 2,
false);
1057 return _instance.load_csv(a_filePath.data(), a_version,
false);
1063 static void reset() {
1065 _initialized =
false;
1069 [[nodiscard]]
inline std::size_t
id2offset(std::uint64_t a_id)
const {
1070 mapping_t elem{a_id, 0};
1071 const auto it = std::lower_bound(
1075 [](
auto &&a_lhs,
auto &&a_rhs) {
1076 return a_lhs.id < a_rhs.id;
1079 bool failed =
false;
1080 if (it == _id2offset.end()) {
1083 if (it->id != a_id) {
1090 "Failed to find the id within the address library: {}\n"
1091 "This means this script extender plugin is incompatible with the address "
1092 "library for this version of the game, and thus does not support it."sv,
1096 return static_cast<std::size_t
>(it->offset);
1106 using stream_type = std::ifstream;
1107 using pointer = stream_type *;
1108 using const_pointer =
const stream_type *;
1109 using reference = stream_type &;
1110 using const_reference =
const stream_type &;
1112 inline istream_t(
stl::zwstring a_filename, std::ios_base::openmode a_mode) :
1113 _stream(a_filename.data(), a_mode) {
1114 if (!_stream.is_open()) {
1118 _stream.exceptions(std::ios::badbit | std::ios::failbit | std::ios::eofbit);
1121 inline void ignore(std::streamsize a_count) { _stream.ignore(a_count); }
1124 inline void readin(T &a_val) {
1125 _stream.read(
reinterpret_cast<char *
>(std::addressof(a_val)),
sizeof(T));
1131 std::is_arithmetic_v<T>,
1133 inline T readout() {
1140 stream_type _stream;
1145 void read(istream_t &a_in, std::uint8_t a_formatVersion) {
1146 std::int32_t format{};
1147 a_in.readin(format);
1148 if (format != a_formatVersion) {
1151 "Unsupported address library format: {}\n"
1152 "This means this script extender plugin is incompatible with the address "
1153 "library available for this version of the game, and thus does not "
1158 std::int32_t version[4]{};
1159 std::int32_t nameLen{};
1160 a_in.readin(version);
1161 a_in.readin(nameLen);
1162 a_in.ignore(nameLen);
1164 a_in.readin(_pointerSize);
1165 a_in.readin(_addressCount);
1167 for (std::size_t i = 0; i < std::extent_v<
decltype(version)>; ++i) {
1168 _version[i] =
static_cast<std::uint16_t
>(version[i]);
1172 [[nodiscard]] std::size_t address_count() const noexcept {
return static_cast<std::size_t
>(_addressCount); }
1174 [[nodiscard]] std::uint64_t
1175 pointer_size() const noexcept {
return static_cast<std::uint64_t
>(_pointerSize); }
1177 [[nodiscard]] Version version() const noexcept {
return _version; }
1181 std::int32_t _pointerSize{0};
1182 std::int32_t _addressCount{0};
1185 IDDatabase() =
default;
1187 IDDatabase(
const IDDatabase &) =
delete;
1189 IDDatabase(IDDatabase &&) =
delete;
1191 ~IDDatabase() =
default;
1193 IDDatabase &operator=(
const IDDatabase &) =
delete;
1195 IDDatabase &operator=(IDDatabase &&) =
delete;
1200 const auto filename =
1203 "Data/SKSE/Plugins/version-{}.csv"sv,
1205 .value_or(L
"<unknown filename>"s);
1206 load_csv(filename, version,
true);
1208 const auto filename =
1211 fmt::format(
"Data/SKSE/Plugins/versionlib-{}.bin"sv,
1213 fmt::format(
"Data/SKSE/Plugins/version-{}.bin"sv,
1215 .value_or(L
"<unknown filename>"s);
1216 load_file(filename, version,
Module::IsAE() ? 2 : 1, true);
1220 bool load_file(
stl::zwstring a_filename, Version a_version, std::uint8_t a_formatVersion,
bool a_failOnError) {
1222 istream_t in(a_filename.data(), std::ios::in | std::ios::binary);
1224 header.read(in, a_formatVersion);
1225 if (header.version() != a_version) {
1229 auto mapname = L
"CommonLibSSEOffsets-v2-"s;
1230 mapname += a_version.wstring();
1231 const auto byteSize =
static_cast<std::size_t
>(header.address_count()) *
sizeof(mapping_t);
1232 if (_mmap.
open(mapname, byteSize)) {
1233 _id2offset = {
static_cast<mapping_t*
>(_mmap.
data()), header.address_count() };
1234 }
else if (_mmap.
create(mapname, byteSize)) {
1235 _id2offset = {
static_cast<mapping_t*
>(_mmap.
data()), header.address_count() };
1236 unpack_file(in, header, a_failOnError);
1240 [](
auto&& a_lhs,
auto&& a_rhs) {
1241 return a_lhs.id < a_rhs.id;
1246 }
catch (
const std::system_error &) {
1249 "Failed to locate an appropriate address library with the path: {}\n"
1250 "This means you are missing the address library for this specific version of "
1251 "the game. Please continue to the mod page for address library to download "
1252 "an appropriate version. If one is not available, then it is likely that "
1253 "address library has not yet added support for this version of the game."sv,
1260 bool load_csv(
stl::zwstring a_filename, Version a_version,
bool a_failOnError) {
1262 if (!std::filesystem::exists(nstring)) {
1264 fmt::format(
"Required VR Address Library file {} does not exist"sv, nstring),
1267 rapidcsv::Document in(nstring);
1268 std::size_t id, address_count;
1269 std::string version, offset;
1270 auto mapname = L
"CommonLibSSEOffsets-v2-"s;
1271 mapname += a_version.wstring();
1272 address_count = in.GetCell<std::size_t>(0, 0);
1273 version = in.GetCell<std::string>(1, 0);
1274 const auto byteSize =
static_cast<std::size_t
>(address_count *
sizeof(mapping_t));
1275 if (!_mmap.
open(mapname, byteSize) &&
1276 !_mmap.
create(mapname, byteSize)) {
1279 _id2offset = {
static_cast<mapping_t *
>(_mmap.
data()),
static_cast<std::size_t
>(address_count)};
1280 if (in.GetRowCount() > address_count + 1) {
1282 fmt::format(
"VR Address Library {} tried to exceed {} allocated entries."sv,
1283 version, address_count), a_failOnError);
1284 }
else if (in.GetRowCount() < address_count + 1) {
1287 "VR Address Library {} loaded only {} entries but expected {}. Please redownload."sv,
1288 version, in.GetRowCount() - 1, address_count), a_failOnError);
1290 std::size_t index = 1;
1291 for (; index < in.GetRowCount(); ++index) {
1292 id = in.GetCell<std::size_t>(0, index);
1293 offset = in.GetCell<std::string>(1, index);
1294 _id2offset[index - 1] = {
static_cast<std::uint64_t
>(id),
1295 static_cast<std::uint64_t
>(std::stoul(offset,
nullptr, 16))};
1300 [](
auto &&a_lhs,
auto &&a_rhs) {
1301 return a_lhs.id < a_rhs.id;
1306 bool unpack_file(istream_t &a_in, header_t a_header,
bool a_failOnError) {
1307 std::uint8_t type = 0;
1308 std::uint64_t
id = 0;
1309 std::uint64_t offset = 0;
1310 std::uint64_t prevID = 0;
1311 std::uint64_t prevOffset = 0;
1312 for (
auto &mapping: _id2offset) {
1314 const auto lo =
static_cast<std::uint8_t
>(type & 0xF);
1315 const auto hi =
static_cast<std::uint8_t
>(type >> 4);
1325 id = prevID + a_in.readout<std::uint8_t>();
1328 id = prevID - a_in.readout<std::uint8_t>();
1331 id = prevID + a_in.readout<std::uint16_t>();
1334 id = prevID - a_in.readout<std::uint16_t>();
1337 id = a_in.readout<std::uint16_t>();
1340 id = a_in.readout<std::uint32_t>();
1346 const std::uint64_t tmp = (hi & 8) != 0 ? (prevOffset / a_header.pointer_size()) : prevOffset;
1350 a_in.readin(offset);
1356 offset = tmp + a_in.readout<std::uint8_t>();
1359 offset = tmp - a_in.readout<std::uint8_t>();
1362 offset = tmp + a_in.readout<std::uint16_t>();
1365 offset = tmp - a_in.readout<std::uint16_t>();
1368 offset = a_in.readout<std::uint16_t>();
1371 offset = a_in.readout<std::uint32_t>();
1377 if ((hi & 8) != 0) {
1378 offset *= a_header.pointer_size();
1381 mapping = {id, offset};
1383 prevOffset = offset;
1394 static IDDatabase _instance;
1395 static inline std::atomic_bool _initialized{
false};
1396 static inline std::mutex _initLock;
1397 detail::memory_map _mmap;
1398 std::span<mapping_t> _id2offset;
1406 _offset(a_offset) {}
1415 [[nodiscard]]
constexpr std::size_t
offset() const noexcept {
return _offset; }
1418 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().
base(); }
1420 std::size_t _offset{0};
1428 [[maybe_unused]]
std::
size_t a_aeOffset,
1429 [[maybe_unused]]
std::
size_t a_vrOffset) noexcept {
1430#ifdef ENABLE_SKYRIM_SE
1431 _seOffset = a_seOffset;
1433#ifdef ENABLE_SKYRIM_AE
1434 _aeOffset = a_aeOffset;
1436#ifdef ENABLE_SKYRIM_VR
1437 _vrOffset = a_vrOffset;
1442 auto thisOffset =
offset();
1443 return thisOffset ? base() + thisOffset : 0;
1448#ifdef ENABLE_SKYRIM_AE
1452#ifdef ENABLE_SKYRIM_SE
1456#ifdef ENABLE_SKYRIM_VR
1468 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().
base(); }
1470#ifdef ENABLE_SKYRIM_SE
1471 std::size_t _seOffset{0};
1473#ifdef ENABLE_SKYRIM_AE
1474 std::size_t _aeOffset{0};
1476#ifdef ENABLE_SKYRIM_VR
1477 std::size_t _vrOffset{0};
1483 constexpr ID() noexcept = default;
1485 explicit constexpr
ID(
std::uint64_t a_id) noexcept:
1495 [[nodiscard]]
constexpr std::uint64_t
id() const noexcept {
return _id; }
1500 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().
base(); }
1502 std::uint64_t _id{0};
1510 [[maybe_unused]]
std::uint64_t a_aeID) noexcept {
1511#ifdef ENABLE_SKYRIM_SE
1514#ifdef ENABLE_SKYRIM_AE
1517#ifdef ENABLE_SKYRIM_VR
1522 explicit constexpr RelocationID([[maybe_unused]] std::uint64_t a_seID, [[maybe_unused]] std::uint64_t a_aeID,
1523 [[maybe_unused]] std::uint64_t a_vrID)
noexcept {
1524#ifdef ENABLE_SKYRIM_SE
1527#ifdef ENABLE_SKYRIM_AE
1530#ifdef ENABLE_SKYRIM_VR
1536 auto thisOffset =
offset();
1537 return thisOffset ? base() +
offset() : 0;
1547#ifdef ENABLE_SKYRIM_AE
1551#ifdef ENABLE_SKYRIM_SE
1555#ifdef ENABLE_SKYRIM_VR
1569 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().
base(); }
1571#ifdef ENABLE_SKYRIM_SE
1572 std::uint64_t _seID{0};
1574#ifdef ENABLE_SKYRIM_AE
1575 std::uint64_t _aeID{0};
1577#ifdef ENABLE_SKYRIM_VR
1578 std::uint64_t _vrID{0};
1586 explicit constexpr
VariantID([[maybe_unused]]
std::uint64_t a_seID, [[maybe_unused]]
std::uint64_t a_aeID,
1587 [[maybe_unused]]
std::uint64_t a_vrOffset) noexcept {
1588#ifdef ENABLE_SKYRIM_SE
1591#ifdef ENABLE_SKYRIM_AE
1594#ifdef ENABLE_SKYRIM_VR
1595 _vrOffset = a_vrOffset;
1600 auto thisOffset =
offset();
1601 return thisOffset ? base() +
offset() : 0;
1606#ifdef ENABLE_SKYRIM_AE
1610#ifdef ENABLE_SKYRIM_SE
1614#ifdef ENABLE_SKYRIM_VR
1624 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().
base(); }
1626#ifdef ENABLE_SKYRIM_SE
1627 std::uint64_t _seID{0};
1629#ifdef ENABLE_SKYRIM_AE
1630 std::uint64_t _aeID{0};
1632#ifdef ENABLE_SKYRIM_VR
1633 std::uint64_t _vrOffset{0};
1642 std::is_member_pointer_v<T> || std::is_function_v<std::remove_pointer_t<T>>,
1661 _impl{a_id.
address() + a_offset} {}
1673 _impl{a_id.
address() + a_offset} {}
1685 _impl{a_id.
address() + a_offset} {}
1723 template<
class U = value_type>
1724 [[nodiscard]]
decltype(
auto)
operator*()
const noexcept
1725 requires(std::is_pointer_v<U>)
1730 template<
class U = value_type>
1732 requires(
std::is_pointer_v<U>)
1737 template<
class... Args>
1739 noexcept(std::is_nothrow_invocable_v<
const value_type &, Args...>)
1740 requires(std::invocable<const value_type &, Args...>)
1747 constexpr std::uintptr_t
address() const noexcept {
return _impl; }
1749 [[nodiscard]] std::size_t
offset()
const {
return _impl - base(); }
1752 noexcept(
std::is_nothrow_copy_constructible_v<
value_type>) {
1754 return stl::unrestricted_cast<value_type>(_impl);
1757 template<
class U = value_type>
1758 std::uintptr_t
write_vfunc(std::size_t a_idx, std::uintptr_t a_newFunc)
1759 requires(std::same_as<U, std::uintptr_t>)
1761 const auto addr =
address() + (
sizeof(
void *) * a_idx);
1762 const auto result = *
reinterpret_cast<std::uintptr_t *
>(addr);
1769 requires(std::same_as<value_type, std::uintptr_t>)
1771 return write_vfunc(a_idx, stl::unrestricted_cast<std::uintptr_t>(a_newFunc));
1776 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().
base(); }
1779 std::uintptr_t _impl{0};
1783 namespace characters {
1785 return (
'0' <= a_ch && a_ch <=
'9') ||
1786 (
'A' <= a_ch && a_ch <=
'F') ||
1787 (
'a' <= a_ch && a_ch <=
'f');
1790 [[nodiscard]]
constexpr bool space(
char a_ch)
noexcept {
1794 [[nodiscard]]
constexpr bool wildcard(
char a_ch)
noexcept {
1802 constexpr auto lut = []()
noexcept {
1803 std::array<std::uint8_t, (std::numeric_limits<unsigned char>::max)() + 1> a = {};
1805 const auto iterate = [&](std::uint8_t a_iFirst,
unsigned char a_cFirst,
1806 unsigned char a_cLast)
noexcept {
1807 for (; a_cFirst <= a_cLast; ++a_cFirst, ++a_iFirst) {
1808 a[a_cFirst] = a_iFirst;
1812 iterate(0,
'0',
'9');
1813 iterate(0xA,
'A',
'F');
1814 iterate(0xa,
'a',
'f');
1819 return static_cast<std::byte
>(
1820 lut[
static_cast<unsigned char>(a_hi)] * 0x10u +
1821 lut[
static_cast<unsigned char>(a_lo)]);
1825 template<
char HI,
char LO>
1828 [[nodiscard]]
static constexpr bool match(std::byte a_byte)
noexcept {
1830 return a_byte == expected;
1848 [[nodiscard]]
static constexpr bool match(std::byte)
noexcept {
1858 template<
char,
char>
1861 template<
char C1,
char C2>
1863 rule_for() noexcept requires (characters::hexadecimal(C1) && characters::hexadecimal(C2));
1865 template<
char C1,
char C2>
1869 template<class... Rules>
1872 static_assert(
sizeof...(Rules) >= 1,
"must provide at least 1 rule for the pattern matcher");
1874 [[nodiscard]]
constexpr bool match(std::span<
const std::byte,
sizeof...(Rules)> a_bytes)
const noexcept {
1876 return (Rules::match(a_bytes[i++]) && ...);
1879 [[nodiscard]]
bool match(std::uintptr_t a_address)
const noexcept {
1880 return this->match(*
reinterpret_cast<const std::byte(*)[sizeof...(Rules)]
>(a_address));
1885 if (!this->match(a_address)) {
1889 "A pattern has failed to match.\n"
1890 "This means the plugin is incompatible with the current version of the game ({}.{}.{}). "
1891 "Head to the mod page of this plugin to see if an update is available."sv,
1902 template<stl::nttp::string S,
class... Rules>
1904 if constexpr (S.length() == 0) {
1906 }
else if constexpr (S.length() == 1) {
1907 constexpr char c = S[0];
1910 "the given pattern has an unpaired rule (rules are required to be written in pairs of 2)");
1912 consteval_error(
"the given pattern has trailing characters at the end (which is not allowed)");
1915 using rule_t =
decltype(rules::rule_for<S[0], S[1]>());
1916 if constexpr (std::same_as<rule_t, void>) {
1919 if constexpr (S.length() <= 3) {
1924 consteval_error(
"a space character is required to split byte patterns");
1930 template<
class... Bytes>
1932 -> std::array<std::byte,
sizeof...(Bytes)> {
1933 static_assert((std::integral<Bytes> && ...),
"all bytes must be an integral type");
1934 return {
static_cast<std::byte
>(a_bytes)...};
1938 template<stl::nttp::
string S>
1940 return detail::do_make_pattern<S>();
1945 static_assert(
make_pattern<
"B8 D0 ?? ?? D4 6E">().match(
1965#ifndef ENABLE_SKYRIM_AE
1967#elif !defined(ENABLE_SKYRIM_SE) && !defined(ENABLE_SKYRIM_VR)
1993 [[maybe_unused]] T a_vr)
noexcept {
1994#if !defined(ENABLE_SKYRIM_AE) && !defined(ENABLE_SKYRIM_VR)
1996#elif !defined(ENABLE_SKYRIM_SE) && !defined(ENABLE_SKYRIM_VR)
1998#elif !defined(ENABLE_SKYRIM_AE) && !defined(ENABLE_SKYRIM_SE)
2017 template<
class Ret,
class This>
2024 template<
class Ret,
class This,
class... Args>
2031 template<
class Ret,
class This>
2038 template<
class Ret,
class This,
class... Args>
2045 template<
class Ret,
class This>
2052 template<
class Ret,
class This,
class... Args>
2080 template<
class Fn,
class... Args>
2082 [[maybe_unused]] std::ptrdiff_t a_seAndAEVtableOffset, [[maybe_unused]] std::ptrdiff_t a_vrVtableOffset,
2083 [[maybe_unused]] std::ptrdiff_t a_seAndAEVtableIndex, [[maybe_unused]] std::ptrdiff_t a_vrVtableIndex,
2086 *
reinterpret_cast<const uintptr_t *
>(
reinterpret_cast<uintptr_t
>(a_self) +
2087 #ifndef ENABLE_SKYRIM_VR
2088 a_seAndAEVtableOffset) +
2089 a_seAndAEVtableIndex
2090 #elif !defined(ENABLE_SKYRIM_AE) && !defined(ENABLE_SKYRIM_SE)
2094 (
Module::IsVR() ? a_vrVtableOffset : a_seAndAEVtableOffset)) +
2095 (
Module::IsVR() ? a_vrVtableIndex : a_seAndAEVtableIndex)
2097 *
sizeof(uintptr_t)))(a_self, std::forward<Args>(a_args)...);
2123 template<
class Fn,
class... Args>
2125 std::ptrdiff_t a_seAndAEVtableIndex, std::ptrdiff_t a_vrVtableIndex,
2127 return RelocateVirtual<Fn, Args...>(0, 0, a_seAndAEVtableIndex, a_vrVtableIndex, a_self,
2128 std::forward<Args>(a_args)...);
2148 template<
class T,
class This>
2149 [[nodiscard]]
inline T &
RelocateMember(This *a_self, std::ptrdiff_t a_seAndAE, std::ptrdiff_t a_vr) {
2150 return *
reinterpret_cast<T *
>(
reinterpret_cast<uintptr_t
>(a_self) +
Relocate(a_seAndAE, a_seAndAE, a_vr));
2153 template<
class T,
class This>
2155 return *
reinterpret_cast<T *
>(
reinterpret_cast<uintptr_t
>(a_self) + offset);
2158 template<
class T,
class This>
2159 [[nodiscard]]
inline T &
RelocateMemberIf(
bool condition, This *a_self, std::ptrdiff_t a, std::ptrdiff_t b) {
2160 return *
reinterpret_cast<T *
>(
reinterpret_cast<uintptr_t
>(a_self) + (condition ? a : b));
2163 template<
class T,
class This>
2165 return *
reinterpret_cast<T *
>(
reinterpret_cast<uintptr_t
>(a_self) +
2172 return a_version.
string(
"."sv);
2175#ifdef __cpp_lib_format
2177 template<
class CharT>
2178 struct formatter<
REL::Version, CharT> : formatter<std::string, CharT> {
2179 template<
class FormatContext>
2180 auto format(
const REL::Version &a_version, FormatContext &a_ctx) {
2181 return formatter<std::string, CharT>::format(to_string(a_version), a_ctx);
2189 template<
class CharT>
2190 struct formatter<
REL::Version, CharT> : formatter<std::string, CharT> {
2191 template<
class FormatContext>
2193 return formatter<std::string, CharT>::format(
std::to_string(a_version), a_ctx);
2198#undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE
2199#undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER
2200#undef REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE_HELPER_IMPL
2202#undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE
2203#undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER
2204#undef REL_MAKE_MEMBER_FUNCTION_POD_TYPE_HELPER_IMPL
#define SKYRIM_REL_VR
Definition Relocation.h:134
#define SKYRIM_REL_VR_CONSTEXPR
Definition Relocation.h:143
#define SKYRIM_REL_CONSTEXPR
Definition Relocation.h:105
#define SKYRIM_ADDR
Definition Relocation.h:76
#define SKYRIM_REL
Definition Relocation.h:96
#define GetEnvironmentVariable
Definition WinAPI.h:580
#define IMAGE_SCN_MEM_WRITE
Definition WinAPI.h:572
#define VerQueryValue
Definition WinAPI.h:583
#define LoadLibrary
Definition WinAPI.h:586
#define GetFileVersionInfo
Definition WinAPI.h:584
#define IMAGE_SCN_MEM_EXECUTE
Definition WinAPI.h:571
#define GetModuleHandle
Definition WinAPI.h:585
#define GetFileVersionInfoSize
Definition WinAPI.h:581
#define PAGE_EXECUTE_READWRITE
Definition WinAPI.h:578
Definition Relocation.h:965
Offset2ID()
Definition Relocation.h:989
typename container_type::const_iterator const_iterator
Definition Relocation.h:970
typename container_type::const_reverse_iterator const_reverse_iterator
Definition Relocation.h:971
const_reverse_iterator crbegin() const noexcept
Definition Relocation.h:1021
const_iterator begin() const noexcept
Definition Relocation.h:1011
std::vector< value_type > container_type
Definition Relocation.h:968
size_type size() const noexcept
Definition Relocation.h:1027
Offset2ID(ExecutionPolicy &&a_policy)
Definition Relocation.h:974
const_reverse_iterator rbegin() const noexcept
Definition Relocation.h:1019
const_reverse_iterator crend() const noexcept
Definition Relocation.h:1025
const_iterator cbegin() const noexcept
Definition Relocation.h:1013
typename container_type::size_type size_type
Definition Relocation.h:969
const_iterator cend() const noexcept
Definition Relocation.h:1017
std::uint64_t operator()(std::size_t a_offset) const
Definition Relocation.h:992
mapping_t value_type
Definition Relocation.h:967
const_reverse_iterator rend() const noexcept
Definition Relocation.h:1023
const_iterator end() const noexcept
Definition Relocation.h:1015
Definition Relocation.h:951
static IDDatabase & get()
Definition Relocation.h:1033
std::size_t id2offset(std::uint64_t a_id) const
Definition Relocation.h:1069
Format
Definition Relocation.h:959
Definition Relocation.h:1481
std::size_t offset() const
Definition Relocation.h:1497
constexpr ID & operator=(std::uint64_t a_id) noexcept
Definition Relocation.h:1488
constexpr std::uint64_t id() const noexcept
Definition Relocation.h:1495
constexpr ID() noexcept=default
std::uintptr_t address() const
Definition Relocation.h:1493
Definition Relocation.h:634
static SKYRIM_REL_VR bool IsVR() noexcept
Definition Relocation.h:821
static SKYRIM_REL bool IsSE() noexcept
Definition Relocation.h:814
Runtime
Definition Relocation.h:639
Version version() const noexcept
Definition Relocation.h:778
T * pointer() const noexcept
Definition Relocation.h:785
std::uintptr_t base() const noexcept
Definition Relocation.h:772
stl::zwstring filename() const noexcept
Definition Relocation.h:774
static Module & get()
Definition Relocation.h:658
void * pointer() const noexcept
Definition Relocation.h:782
stl::zwstring filePath() const noexcept
Definition Relocation.h:776
Segment segment(Segment::Name a_segment) const noexcept
Definition Relocation.h:780
static SKYRIM_REL Runtime GetRuntime() noexcept
Definition Relocation.h:792
static SKYRIM_REL bool IsAE() noexcept
Definition Relocation.h:807
Definition Relocation.h:1401
constexpr Offset() noexcept=default
std::uintptr_t address() const
Definition Relocation.h:1413
constexpr Offset & operator=(std::size_t a_offset) noexcept
Definition Relocation.h:1408
constexpr std::size_t offset() const noexcept
Definition Relocation.h:1415
Definition Relocation.h:1638
std::uintptr_t write_vfunc(std::size_t a_idx, std::uintptr_t a_newFunc)
Definition Relocation.h:1758
constexpr std::uintptr_t address() const noexcept
Definition Relocation.h:1747
Relocation & operator=(VariantOffset a_offset)
Definition Relocation.h:1703
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:1644
Relocation & operator=(ID a_id)
Definition Relocation.h:1708
Relocation(ID a_id, Offset a_offset)
Definition Relocation.h:1663
Relocation & operator=(VariantID a_id)
Definition Relocation.h:1718
Relocation(VariantID a_id, VariantOffset a_offset)
Definition Relocation.h:1690
value_type get() const noexcept(std::is_nothrow_copy_constructible_v< value_type >)
Definition Relocation.h:1751
Relocation(Offset a_offset)
Definition Relocation.h:1651
auto operator->() const noexcept
Definition Relocation.h:1731
Relocation(RelocationID a_id, Offset a_offset)
Definition Relocation.h:1675
Relocation(ID a_id, std::ptrdiff_t a_offset)
Definition Relocation.h:1660
Relocation(VariantID a_id, Offset a_offset)
Definition Relocation.h:1687
constexpr Relocation & operator=(std::uintptr_t a_address) noexcept
Definition Relocation.h:1693
Relocation(VariantID a_id)
Definition Relocation.h:1681
Relocation(RelocationID a_id, std::ptrdiff_t a_offset)
Definition Relocation.h:1672
Relocation(VariantID a_id, std::ptrdiff_t a_offset)
Definition Relocation.h:1684
constexpr Relocation() noexcept=default
Relocation(ID a_id, VariantOffset a_offset)
Definition Relocation.h:1666
Relocation(VariantOffset a_offset)
Definition Relocation.h:1654
Relocation(ID a_id)
Definition Relocation.h:1657
Relocation(RelocationID a_id)
Definition Relocation.h:1669
Relocation(RelocationID a_id, VariantOffset a_offset)
Definition Relocation.h:1678
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:1738
std::size_t offset() const
Definition Relocation.h:1749
Relocation & operator=(RelocationID a_id)
Definition Relocation.h:1713
Relocation & operator=(Offset a_offset)
Definition Relocation.h:1698
std::uintptr_t write_vfunc(std::size_t a_idx, F a_newFunc)
Definition Relocation.h:1768
Definition Relocation.h:1505
constexpr RelocationID(std::uint64_t a_seID, std::uint64_t a_aeID, std::uint64_t a_vrID) noexcept
Definition Relocation.h:1522
std::size_t offset() const
Definition Relocation.h:1540
SKYRIM_REL std::uint64_t id() const noexcept
Definition Relocation.h:1545
std::uintptr_t address() const
Definition Relocation.h:1535
constexpr RelocationID() noexcept=default
Definition Relocation.h:592
std::size_t size() const noexcept
Definition Relocation.h:617
Name
Definition Relocation.h:594
@ data
Definition Relocation.h:598
@ tls
Definition Relocation.h:600
@ textw
Definition Relocation.h:601
@ gfids
Definition Relocation.h:602
@ total
Definition Relocation.h:603
@ idata
Definition Relocation.h:596
@ textx
Definition Relocation.h:595
@ pdata
Definition Relocation.h:599
@ rdata
Definition Relocation.h:597
void * pointer() const noexcept
Definition Relocation.h:619
std::uintptr_t address() const noexcept
Definition Relocation.h:613
Segment() noexcept=default
std::size_t offset() const noexcept
Definition Relocation.h:615
T * pointer() const noexcept
Definition Relocation.h:622
Definition Relocation.h:1582
std::uintptr_t address() const
Definition Relocation.h:1599
constexpr VariantID() noexcept=default
std::size_t offset() const
Definition Relocation.h:1604
Definition Relocation.h:1423
std::uintptr_t address() const
Definition Relocation.h:1441
SKYRIM_REL std::size_t offset() const noexcept
Definition Relocation.h:1446
constexpr VariantOffset() noexcept=default
Definition Relocation.h:401
const value_type & const_reference
Definition Relocation.h:405
constexpr value_type build() const noexcept
Definition Relocation.h:481
constexpr decltype(auto) end() const noexcept
Definition Relocation.h:448
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:412
constexpr value_type patch() const noexcept
Definition Relocation.h:477
constexpr reference operator[](std::size_t a_idx) noexcept
Definition Relocation.h:440
std::strong_ordering constexpr compare(const Version &a_rhs) const noexcept
Definition Relocation.h:452
constexpr decltype(auto) cbegin() const noexcept
Definition Relocation.h:446
std::string string(std::string_view a_separator="-"sv) const
Definition Relocation.h:485
std::wstring wstring(std::wstring_view a_separator=L"-"sv) const
Definition Relocation.h:495
constexpr value_type minor() const noexcept
Definition Relocation.h:473
constexpr std::uint32_t pack() const noexcept
Definition Relocation.h:461
constexpr Version(std::string_view a_version)
Definition Relocation.h:415
constexpr const_reference operator[](std::size_t a_idx) const noexcept
Definition Relocation.h:442
static constexpr Version unpack(std::uint32_t a_packedVersion) noexcept
Definition Relocation.h:505
std::uint16_t value_type
Definition Relocation.h:403
constexpr decltype(auto) cend() const noexcept
Definition Relocation.h:450
value_type & reference
Definition Relocation.h:404
constexpr Version() noexcept=default
constexpr decltype(auto) begin() const noexcept
Definition Relocation.h:444
constexpr value_type major() const noexcept
Definition Relocation.h:469
Definition Relocation.h:1870
constexpr bool match(std::span< const std::byte, sizeof...(Rules)> a_bytes) const noexcept
Definition Relocation.h:1874
bool match(std::uintptr_t a_address) const noexcept
Definition Relocation.h:1879
void match_or_fail(std::uintptr_t a_address, SKSE::stl::source_location a_loc=SKSE::stl::source_location::current()) const noexcept
Definition Relocation.h:1883
Definition Relocation.h:184
~memory_map()
Definition Relocation.h:197
memory_map & operator=(memory_map &&a_rhs) noexcept
Definition Relocation.h:201
memory_map & operator=(const memory_map &)=delete
memory_map() noexcept=default
void * data() noexcept
Definition Relocation.h:212
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:1826
static constexpr bool match(std::byte a_byte) noexcept
Definition Relocation.h:1828
Definition Relocation.h:1846
static constexpr bool match(std::byte) noexcept
Definition Relocation.h:1848
constexpr bool space(char a_ch) noexcept
Definition Relocation.h:1790
constexpr bool hexadecimal(char a_ch) noexcept
Definition Relocation.h:1784
constexpr bool wildcard(char a_ch) noexcept
Definition Relocation.h:1794
constexpr std::byte hexacharacters_to_hexadecimal(char a_hi, char a_lo) noexcept
Definition Relocation.h:1801
typename member_function_non_pod_type< F >::type member_function_non_pod_type_t
Definition Relocation.h:245
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:304
consteval auto make_byte_array(Bytes... a_bytes) noexcept -> std::array< std::byte, sizeof...(Bytes)>
Definition Relocation.h:1931
typename member_function_pod_type< F >::type member_function_pod_type_t
Definition Relocation.h:234
constexpr bool is_x64_pod_v
Definition Relocation.h:298
void consteval_error(const char *a_error)
constexpr auto do_make_pattern() noexcept
Definition Relocation.h:1903
REL_MAKE_MEMBER_FUNCTION_POD_TYPE()
REL_MAKE_MEMBER_FUNCTION_NON_POD_TYPE()
constexpr uint8_t read_version(std::array< typename REL::Version::value_type, 4 > &result)
Definition Relocation.h:528
Definition Relocation.h:182
std::invoke_result_t< F, Args... > invoke(F &&a_func, Args &&... a_args) noexcept(std::is_nothrow_invocable_v< F, Args... >)
Definition Relocation.h:332
constexpr std::uint8_t NOP6[]
Definition Relocation.h:321
constexpr std::uint8_t JMP8
Definition Relocation.h:326
std::optional< Version > get_file_version(stl::zwstring a_filename)
Definition Relocation.h:563
constexpr std::uint8_t NOP
Definition Relocation.h:316
detail::RelocateVirtualHelper< Fn >::return_type RelocateVirtual(std::ptrdiff_t a_seAndAEVtableOffset, std::ptrdiff_t a_vrVtableOffset, std::ptrdiff_t a_seAndAEVtableIndex, std::ptrdiff_t a_vrVtableIndex, typename detail::RelocateVirtualHelper< Fn >::this_type *a_self, Args &&... a_args)
Definition Relocation.h:2081
constexpr std::uint8_t NOP4[]
Definition Relocation.h:319
constexpr std::strong_ordering operator<=>(const Version &a_lhs, const Version &a_rhs) noexcept
Definition Relocation.h:523
constexpr std::uint8_t INT3
Definition Relocation.h:329
constexpr std::uint8_t NOP8[]
Definition Relocation.h:323
T & RelocateMember(This *a_self, std::ptrdiff_t a_seAndAE, std::ptrdiff_t a_vr)
Definition Relocation.h:2149
constexpr bool operator==(const Version &a_lhs, const Version &a_rhs) noexcept
Definition Relocation.h:518
constexpr std::uint8_t NOP2[]
Definition Relocation.h:317
T & RelocateMemberIf(bool condition, This *a_self, std::ptrdiff_t a, std::ptrdiff_t b)
Definition Relocation.h:2159
void safe_fill(std::uintptr_t a_dst, std::uint8_t a_value, std::size_t a_count)
Definition Relocation.h:380
void safe_write(std::uintptr_t a_dst, const void *a_src, std::size_t a_count)
Definition Relocation.h:349
constexpr std::uint8_t NOP5[]
Definition Relocation.h:320
constexpr std::uint8_t NOP3[]
Definition Relocation.h:318
constexpr auto make_pattern() noexcept
Definition Relocation.h:1939
constexpr std::uint8_t NOP9[]
Definition Relocation.h:324
SKYRIM_ADDR T Relocate(T &&a_seAndVR, T &&a_ae) noexcept
Definition Relocation.h:1964
T & RelocateMemberIfNewer(Version v, This *a_self, std::ptrdiff_t older, std::ptrdiff_t newer)
Definition Relocation.h:2164
constexpr std::uint8_t RET
Definition Relocation.h:328
constexpr std::uint8_t JMP32
Definition Relocation.h:327
constexpr std::uint8_t NOP7[]
Definition Relocation.h:322
bool VirtualProtect(void *a_address, std::size_t a_size, std::uint32_t a_newProtect, std::uint32_t *a_oldProtect) noexcept
auto HKEY_LOCAL_MACHINE
Definition WinAPI.h:84
HINSTANCE HMODULE
Definition WinAPI.h:79
long RegGetValueW(HKEY hkey, const char *subKey, const char *value, unsigned long flags, unsigned long *type, void *data, unsigned long *length)
string(const CharT(&)[N]) -> string< CharT, N - 1 >
bool report_and_error(std::string_view a_msg, bool a_fail=true, SKSE::stl::source_location a_loc=SKSE::stl::source_location::current())
Definition PCH.h:658
std::source_location source_location
Definition PCH.h:600
auto utf16_to_utf8(std::wstring_view a_in) noexcept -> std::optional< std::string >
Definition PCH.h:571
auto utf8_to_utf16(std::string_view a_in) noexcept -> std::optional< std::wstring >
Definition PCH.h:545
basic_zstring< wchar_t > zwstring
Definition PCH.h:79
void report_and_fail(std::string_view a_msg, SKSE::stl::source_location a_loc=SKSE::stl::source_location::current())
Definition PCH.h:721
Definition ActorValueList.h:50
Definition ActorValueList.h:28
std::string to_string(RE::ActorValue a_actorValue)
Definition ActorValueList.h:29
bool getline(RE::NiBinaryStream &a_input, std::basic_string< CharT, Traits, Allocator > &a_str)
Definition NiBinaryStream.h:96
This this_type
Definition Relocation.h:2026
Ret(This *, Args...) function_type
Definition Relocation.h:2028
Ret return_type
Definition Relocation.h:2027
Ret(This *) function_type
Definition Relocation.h:2021
Ret return_type
Definition Relocation.h:2020
This this_type
Definition Relocation.h:2019
const This this_type
Definition Relocation.h:2047
Ret(const This *) function_type
Definition Relocation.h:2049
Ret return_type
Definition Relocation.h:2048
Ret return_type
Definition Relocation.h:2034
Ret(This *) function_type
Definition Relocation.h:2035
This this_type
Definition Relocation.h:2033
Ret(const This *, Args...) function_type
Definition Relocation.h:2056
Ret return_type
Definition Relocation.h:2055
const This this_type
Definition Relocation.h:2054
Ret return_type
Definition Relocation.h:2041
Ret(This *, Args...) function_type
Definition Relocation.h:2042
This this_type
Definition Relocation.h:2040
Definition Relocation.h:2014
Definition Relocation.h:275
Definition Relocation.h:265
Definition Relocation.h:255
Definition Relocation.h:270
Definition Relocation.h:237
Definition Relocation.h:226