19 _mapping(a_rhs._mapping),
22 a_rhs._mapping =
nullptr;
23 a_rhs._view =
nullptr;
32 if (
this != std::addressof(a_rhs)) {
33 _mapping = a_rhs._mapping;
34 a_rhs._mapping =
nullptr;
37 a_rhs._view =
nullptr;
42 [[nodiscard]]
void*
data() noexcept {
return _view; }
49 void* _mapping{
nullptr };
50 void* _view{
nullptr };
69 using size_type =
typename container_type::size_type;
73 template <
class ExecutionPolicy>
75 requires(std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>)
80 std::sort(a_policy, _offset2id.begin(), _offset2id.end(), [](
auto&& a_lhs,
auto&& a_rhs) {
81 return a_lhs.offset < a_rhs.offset;
89 [[nodiscard]] std::uint64_t
operator()(std::size_t a_offset)
const
91 const mapping_t elem{ 0, a_offset };
92 const auto it = std::lower_bound(
96 [](
auto&& a_lhs,
auto&& a_rhs) {
97 return a_lhs.offset < a_rhs.offset;
99 if (it == _offset2id.end()) {
102 "Failed to find the offset within the database: 0x{:08X}"sv,
133 [[nodiscard]]
inline std::size_t
id2offset(std::uint64_t a_id)
const
135 mapping_t elem{ a_id, 0 };
136 const auto it = std::lower_bound(
140 [](
auto&& a_lhs,
auto&& a_rhs) {
141 return a_lhs.id < a_rhs.id;
143 if (it->id != a_id) {
146 "Failed to find the id within the address library: {}\n"
147 "This means that this script extender plugin needs a newer version of the "
148 "library than you currently have."sv,
152 return static_cast<std::size_t
>(it->offset);
156 bool IsVRAddressLibraryAtLeastVersion(
const char* pluginName,
const char* minimalVRAddressLibVersion,
bool showWindowsMessage =
false)
const
158 const auto minimalVersion =
REL::Version(minimalVRAddressLibVersion);
160 bool validVersion = minimalVersion <= _vrAddressLibraryVersion;
162 if (!validVersion && showWindowsMessage) {
163 REX::W32::MessageBoxA(NULL, std::format(
"You need version: {} of VR Address Library for SKSEVR, you have version: {}", minimalVersion.string(), _vrAddressLibraryVersion.string()).c_str(), pluginName, 0x00000000L | 0x00000030L);
178 void read(binary_io::file_istream& a_in)
180 const auto [format] = a_in.read<std::int32_t>();
181 #ifdef SKYRIM_SUPPORT_AE
188 "Unsupported address library format: {}\n"
189 "This means this script extender plugin is incompatible with the address "
190 "library available for this version of the game, and thus does not "
195 const auto [major, minor, patch, revision] =
196 a_in.read<std::int32_t, std::int32_t, std::int32_t, std::int32_t>();
197 _version[0] =
static_cast<std::uint16_t
>(major);
198 _version[1] =
static_cast<std::uint16_t
>(minor);
199 _version[2] =
static_cast<std::uint16_t
>(patch);
200 _version[3] =
static_cast<std::uint16_t
>(revision);
202 const auto [nameLen] = a_in.read<std::int32_t>();
203 a_in.seek_relative(nameLen);
205 a_in.read(_pointerSize, _addressCount);
208 [[nodiscard]] std::size_t address_count() const noexcept {
return static_cast<std::size_t
>(_addressCount); }
209 [[nodiscard]] std::uint64_t pointer_size() const noexcept {
return static_cast<std::uint64_t
>(_pointerSize); }
210 [[nodiscard]] Version version() const noexcept {
return _version; }
214 std::int32_t _pointerSize{ 0 };
215 std::int32_t _addressCount{ 0 };
218 IDDatabase() { load(); }
220 IDDatabase(
const IDDatabase&) =
delete;
221 IDDatabase(IDDatabase&&) =
delete;
223 ~IDDatabase() =
default;
225 IDDatabase& operator=(
const IDDatabase&) =
delete;
226 IDDatabase& operator=(IDDatabase&&) =
delete;
231 const auto filename =
234 #ifdef SKYRIM_SUPPORT_AE
235 "Data/SKSE/Plugins/versionlib-{}.bin"sv,
237 "Data/SKSE/Plugins/version-{}.csv"sv,
239 "Data/SKSE/Plugins/version-{}.bin"sv,
242 .value_or(L
"<unknown filename>"s);
244 load_csv(filename, version);
246 load_file(filename, version);
254 const wchar_t* orig = a_filename.data();
255 std::size_t origsize = wcslen(orig) + 1;
256 std::size_t convertedChars = 0;
257 const std::size_t newsize = origsize * 2;
258 char* nstring =
new char[newsize];
259 wcstombs_s(&convertedChars, nstring, newsize, orig, _TRUNCATE);
260 if (!std::filesystem::exists(nstring))
261 stl::report_and_fail(std::format(
"Required VR Address Library file {} does not exist"sv, nstring));
264 std::size_t id, address_count;
266 auto mapname = L
"CommonLibSSEOffsets-v2-"s;
267 mapname += a_version.wstring();
268 in.read_row(address_count, version);
269 _vrAddressLibraryVersion = Version(version);
270 const auto byteSize =
static_cast<std::size_t
>(address_count *
sizeof(mapping_t));
271 if (!_mmap.open(mapname, byteSize) &&
272 !_mmap.create(mapname, byteSize)) {
275 _id2offset = {
static_cast<mapping_t*
>(_mmap.data()),
static_cast<std::size_t
>(address_count) };
277 while (in.read_row(
id, offset)) {
278 if (index >= address_count)
279 stl::report_and_fail(std::format(
"VR Address Library {} tried to exceed {} allocated entries."sv, version, address_count));
280 _id2offset[index++] = {
static_cast<std::uint64_t
>(id),
281 static_cast<std::uint64_t
>(std::stoul(offset, 0, 16)) };
283 if (index != address_count)
284 stl::report_and_fail(std::format(
"VR Address Library {} loaded only {} entries but expected {}. Please redownload."sv, version, index, address_count));
288 [](
auto&& a_lhs,
auto&& a_rhs) {
289 return a_lhs.id < a_rhs.id;
299 binary_io::file_istream in(a_filename);
302 if (header.version() != a_version) {
306 auto mapname = L
"CommonLibSSEOffsets-v2-"s;
307 mapname += a_version.wstring();
308 const auto byteSize =
static_cast<std::size_t
>(header.address_count()) *
sizeof(mapping_t);
309 if (_mmap.open(mapname, byteSize)) {
310 _id2offset = {
static_cast<mapping_t*
>(_mmap.data()), header.address_count() };
311 }
else if (_mmap.create(mapname, byteSize)) {
312 _id2offset = {
static_cast<mapping_t*
>(_mmap.data()), header.address_count() };
313 unpack_file(in, header);
317 [](
auto&& a_lhs,
auto&& a_rhs) {
318 return a_lhs.id < a_rhs.id;
323 }
catch (
const std::system_error&) {
326 "Failed to locate an appropriate address library with the path: {}\n"
327 "This means you are missing the address library for this specific version of "
328 "the game. Please continue to the mod page for address library to download "
329 "an appropriate version. If one is not available, then it is likely that "
330 "address library has not yet added support for this version of the game."sv,
335 void unpack_file(binary_io::file_istream& a_in, header_t a_header)
337 std::uint8_t type = 0;
338 std::uint64_t
id = 0;
339 std::uint64_t offset = 0;
340 std::uint64_t prevID = 0;
341 std::uint64_t prevOffset = 0;
342 for (
auto& mapping : _id2offset) {
344 const auto lo =
static_cast<std::uint8_t
>(type & 0xF);
345 const auto hi =
static_cast<std::uint8_t
>(type >> 4);
355 id = prevID + std::get<0>(a_in.read<std::uint8_t>());
358 id = prevID - std::get<0>(a_in.read<std::uint8_t>());
361 id = prevID + std::get<0>(a_in.read<std::uint16_t>());
364 id = prevID - std::get<0>(a_in.read<std::uint16_t>());
367 std::tie(
id) = a_in.read<std::uint16_t>();
370 std::tie(
id) = a_in.read<std::uint32_t>();
376 const std::uint64_t tmp = (hi & 8) != 0 ? (prevOffset / a_header.pointer_size()) : prevOffset;
386 offset = tmp + std::get<0>(a_in.read<std::uint8_t>());
389 offset = tmp - std::get<0>(a_in.read<std::uint8_t>());
392 offset = tmp + std::get<0>(a_in.read<std::uint16_t>());
395 offset = tmp - std::get<0>(a_in.read<std::uint16_t>());
398 std::tie(offset) = a_in.read<std::uint16_t>();
401 std::tie(offset) = a_in.read<std::uint32_t>();
408 offset *= a_header.pointer_size();
411 mapping = { id, offset };
418 detail::memory_map _mmap;
419 std::span<mapping_t> _id2offset;
422 Version _vrAddressLibraryVersion;
429 constexpr
ID() noexcept = default;
431 explicit constexpr
ID(
std::uint64_t a_id) noexcept :
441 [[nodiscard]] std::uintptr_t
address()
const {
return base() + offset(); }
442 [[nodiscard]] constexpr std::uint64_t
id() const noexcept {
return _id; }
446 [[nodiscard]]
static std::uintptr_t base() {
return Module::get().
base(); }
448 std::uint64_t _id{ 0 };
Offset2ID()
Definition: ID.h:85
typename container_type::const_iterator const_iterator
Definition: ID.h:70
typename container_type::const_reverse_iterator const_reverse_iterator
Definition: ID.h:71
const_reverse_iterator crbegin() const noexcept
Definition: ID.h:116
Offset2ID(ExecutionPolicy &&a_policy) requires(std
Definition: ID.h:74
const_iterator begin() const noexcept
Definition: ID.h:109
std::vector< value_type > container_type
Definition: ID.h:68
size_type size() const noexcept
Definition: ID.h:121
const_reverse_iterator rbegin() const noexcept
Definition: ID.h:115
const_reverse_iterator crend() const noexcept
Definition: ID.h:119
const_iterator cbegin() const noexcept
Definition: ID.h:110
typename container_type::size_type size_type
Definition: ID.h:69
const_iterator cend() const noexcept
Definition: ID.h:113
std::uint64_t operator()(std::size_t a_offset) const
Definition: ID.h:89
mapping_t value_type
Definition: ID.h:67
const_reverse_iterator rend() const noexcept
Definition: ID.h:118
const_iterator end() const noexcept
Definition: ID.h:112
std::size_t id2offset(std::uint64_t a_id) const
Definition: ID.h:133
static IDDatabase & get()
Definition: ID.h:127
std::size_t offset() const
Definition: ID.h:443
constexpr ID & operator=(std::uint64_t a_id) noexcept
Definition: ID.h:435
constexpr std::uint64_t id() const noexcept
Definition: ID.h:442
constexpr ID() noexcept=default
std::uintptr_t address() const
Definition: ID.h:441
static Module & get()
Definition: Module.h:54
Version version() const noexcept
Definition: Module.h:62
std::uintptr_t base() const noexcept
Definition: Module.h:60
~memory_map()
Definition: ID.h:26
void * data() noexcept
Definition: ID.h:42
memory_map & operator=(memory_map &&a_rhs) noexcept
Definition: ID.h:30
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)
bool TerminateProcess(HANDLE a_process, std::uint32_t a_exitCode) noexcept
std::int32_t MessageBoxA(HWND a_wnd, const char *a_text, const char *a_caption, std::uint32_t a_type) noexcept
HANDLE GetCurrentProcess() 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:588
auto utf16_to_utf8(std::wstring_view a_in) noexcept -> std::optional< std::string >
Definition: PCH.h:560
auto utf8_to_utf16(std::string_view a_in) noexcept -> std::optional< std::wstring >
Definition: PCH.h:534
requires(std::invocable< std::remove_reference_t< EF >>) class scope_exit
Definition: PCH.h:151
basic_zstring< wchar_t > zwstring
Definition: PCH.h:80
static const ignore_column ignore_missing_column
Definition: csv.h:759
Definition: EffectArchetypes.h:65