Содержит заголовочный файл и базу данных, позволяющие легко сделать плагины SKSE DLL независимыми от версии.
Важно! теперь это разделено на 2 версии: специальное издание (1.5.x) и юбилейное издание (1.6.x). идентификаторы, указывающие на адреса, не совпадают между этими двумя версиями (исполняемый файл игры слишком разный, чтобы соответствовать, и даже если они совпадают с кодом в этих функциях, все равно разный).описаниеДля обычных пользователей мода: загрузите и установите пакет «все в одном» из раздела файлов. вы можете использовать менеджер модов или сделать это вручную. файлы. bin должны идти сюда:
Данные/СКСЕ/Плагины/вам нет необходимости читать остальное всего этого.
для авторов плагинов skse dll:это ресурс моддера (файл заголовка). вы можете загрузить базу данных, в которой хранятся смещения, чтобы ваш плагин DLL мог быть независимым от версии без необходимости перекомпиляции. файл заголовка можно скачать из дополнительного раздела файлов. для юбилейного издания файл заголовка называется versionlibdb.h вместо versiondb.h! если вы используете commonlib, то все это уже встроено, и вам ничего отсюда не нужно.
Как использоватьсамый быстрый способ:
Спойлер:
Показывать
# включить "versiondb.h"
void * MyAddress = NULL;
без знака длинный длинный миофсет = 0;
bool InitializeOffsets ()
{
//выделить в стеке, чтобы он был разгружен, когда мы выходим из этой функции.
//нет необходимости загружать всю базу данных и без причины использовать память.
версияdb db;
//загрузите базу данных с текущей исполняемой версией.
if (! db.Load ())
{
_FATALERROR ("не удалось загрузить базу данных версий текущего исполняемого файла!");
}
В остальном
{
//"SkyrimSE.exe", "1.5.97.0"
_MESSAGE("загруженная база данных для %s версии %s. ", db.GetModuleName (). c_str (), db.GetLoadedVersionString (). c_str ());
}
//этот адрес уже включает в себя базовый адрес модуля, поэтому мы можем использовать этот адрес напрямую.
MyAddress = db.FindAddressById(123);
if (MyAddress ==NULL)
{
_FATALERROR ("не удалось найти адрес!");
вернуть ложное;
}
//это смещение не включает базовый адрес. фактический адрес будет модульной базой MyOffset.
if(!db.FindOffsetById(123, MyOffset))
{
_FATALERROR ("не удалось найти смещение для моей вещи!");
}
//Все прошло успешно.
вернуть правду;
}
теперь вы задаетесь вопросом, какое там значение «123». это идентификатор адреса. базы данных разных версий будут иметь один и тот же идентификатор адреса, но он может указывать на разные значения. чтобы получить список всех идентификаторов и пар значений для определенной версии, сделайте это:
Спойлер:
Показывать
# включить "versiondb.h"
Булевой дамп SpecificVersion ()
{
версия db db;
//попробуйте загрузить базу данных версии 1.5.62.0 независимо от запуска исполняемой версии.
if(!db.Load(1,5,62,0))
{
_FATALERROR ("не удалось загрузить базу данных для 1.5.62.0!");
вернуть ложное;
}
//запишите файл под названием offsets-1.5.62.0.txt, где каждая строка является идентификатором и смещением.
db.Dump ("offsets-1.5.62.0.txt");
_MESSAGE("демпинговые смещения для 1.5.62.0 ");
вернуть правду;
}
вместо 1,5,62,0 поставьте версию, с которой вы обращаетесь обратно и знакомы. сначала у вас должен быть соответствующий файл базы данных в каталоге /Data/SKSE/plugins.
после того, как вы называете это, у вас должен быть новый файл в основном каталоге skyrim под названием «offsets-1.5.62.0.txt» или что бы вы ни поставили в качестве имени файла. оно будет в формате, в котором каждая строка:
десятичный идентификатор
шестигранное смещение
например, если у вас есть адрес 142f4def8 (статический указатель символов игрока) в 1.5.62.0, который вы хотите сделать версию независимой, вы сделаете это:
1. поиск 2f4def8 в файле смещения. потому что это смещение без базы 140000000
2. см. идентификатор 517014 (десятичная!)
3. если вы хотите, чтобы этот адрес был включен в DLL во время выполнения, сделайте это:
void*addressOf142F4DEF8 = db.FindAddressById(517014);
и вот у тебя оно есть.
структура versiondb имеет следующие функции:
Спойлер:
Показывать
bool Dump (const std::string & path); //сбрасывать текущую загруженную базу данных в файл
нагрузка bool (int major, int minor, int revision, int build); //загрузите определенную версию, если в каталоге data/SKSE/plugins существует db-major-minor-revision-build.bin.
Bool нагрузка (); //загрузить версию для текущего приложения
void Clear (); //очистить теперь загруженную базу данных
void GetLoadedVersion (int & major, int & minor, int & revision, int & build) const; //получите версию файла базы данных, которую мы загрузили прямо сейчас
bool GetExecutableVersion (int & major, int & minor, int & revision, int & build) const; //получить версию текущего выполняемого приложения
const std:: string & GetModuleName () const; //получите имя текущего загруженного модуля базы данных, на нем должно быть показано "SkyrimSE.exe".
const std:: string & GetLoadedVersionString () const; //получите в настоящее время загруженную версию в виде строки, например. "1.5.62.0"
const std:: карта& GetOffsetMap () const; //получите карту идентификатора для смещения, если вам нужно повторить ее вручную.
void * FindAddressById (длинный длинный идентификатор без знака) const; //найдите адрес по идентификатору, это уже будет включать базовый и правильный адрес. он вернется нулевым, если не найден!
bool FindOffsetById (идентификатор без подписи, идентификатор без подписи //найдите смещение по идентификатору, это будет просто смещено без включения базы.
Bool findbyaddress (void * ptr, без подписи long long & result) const; //найти идентификатор по адресу, это попробует обратный поиск для преобразования адреса в идентификатор.
Bool findbyoffset (незнаковое длинное смещение, незнаковое длинное смещение & результат) const; //найти идентификатор по смещению, это попробует обратный поиск для преобразования смещения в идентификатор.
вещи, которые вам следует знать и помнить:
1. вы можете включить любой (или все) файлы базы данных с вашим плагином, но это может значительно увеличить размер файла (примерно на 2,5 Мб). до сих пор было обычным явлением отмечать этот мод как зависимость.
2. вам всегда следует загружать базу данных только один раз при запуске, инициализировать/кэшировать нужные вам адреса и позволить ей разгрузить. разгрузка просто означает, что структура versiondb удаляется или теряется (если вы выделены в стеке). это гарантирует, что вы не используете ненужное количество памяти во время выполнения игры. нет необходимости держать базу данных загруженной во время игрового процесса. это спорный момент, если вы используете commonlib, поскольку он загружает его только один раз, а не для каждой dll.
3. база данных содержит адреса функций, глобальных переменных, RTTI, vtables и все остальное, что может иметь ссылку на нее. он не содержит адресов, находящихся в середине функций или в середине глобалов. если вам нужен адрес посередине функции, вам следует найти базовый адрес функции и добавить дополнительное смещение самостоятельно. он также не содержит бесполезных вещей, таких как выравнивание вокруг функций (на которые ссылаются в rdata), раздел pdata отбрасывается, а некоторые сгенерированные компилятором информацию о rdata отбрасываются.
4. вы всегда должны проверять результат, чтобы убедиться, что база данных успешно загружена (bool load возвращает true) и что запрошенные адреса действительно возвращают действительный результат (не нулевый). если он действительно не сможет загрузить, это означает, что в файле отсутствовала наиболее вероятная или неправильная версия (например, попытка использовать заголовок se в ae). если запрос не удастся, это означает, что адрес не удалось найти в этой версии. это может означать, что код игры изменился достаточно, чтобы адрес больше не был действителен для этой версии, или сама база данных не смогла обнаружить правильный адрес. если произойдет какое-либо из этих вещей, вы должны провалить инициализацию плагина, чтобы сообщить skse, что вы загрузили неправильно. или вручную отображать сообщение об ошибке.
5. Было бы лучше, если бы вы проверили наличие адреса во всех версиях игры перед публикацией вашего dll плагина. для того, чтобы загрузить каждую версию файла базы данных и запросить один и тот же идентификатор адреса в каждой из них, чтобы убедиться, что он существует:
Спойлер:
Показывать
bool LoadAll (std:: вектор& Все)
{
статические int версии [] = {3, 16, 23, 39, 50, 53, 62, 73, 80, 97, -1};
Для (int i=0; версия [i] > = 0; i ++)
{
VersionDb * db = новая версия ();
if (! db-> Load(1,5, версии[i], 0))
{
удалить дБ;
вернуть ложное;
}
all.push_back (db);
}
вернуть правду;
}
Bool existensinall (std:: вектор& all, без подписи длинный длинный идентификатор)
{
неподписанный длинный результат = 0;
{
if(!db- > FindOffsetById(id, результат))
}
вернуть правду;
}
void FreeAll (std:: вектор& Все)
{
для (автоматический db: все)
удалить дБ;
all.clear ();
}
Буль ИсОк ()
{
std::векторвсе;
if (! LoadAll(all))
{
_FATALERROR («не удалось загрузить одну или несколько баз данных версий для текущего исполняемого файла!»);
свободно (все);
вернуть ложное;
}
if (! Existensinall(all, 517014))
{
_FATALERROR ("517014 существует не во всех версиях базы данных!");
}
FreeAll (все);
//Хорошо!
вернуть правду;
}
таким образом вы можете быть уверены, что ваш мод DLL будет работать во всех версиях, или если он не работает в некоторых версиях, вы можете написать это на странице мода.
6. иногда вам придется делать что-то другое в зависимости от запуска версии игры. вы можете сделать это с помощью этого фрагмента кода:
Спойлер:
Показывать
int major = 0, minor = 0, revision = 0, build = 0;
if(!db.GetExecutableVersion(major, minor, revision, build))
{
_FATALERROR ("что-то пошло не так!");
вернуть ложное;
}
//бегущая игра 1.5.x и как минимум версия 1.5.39.0
if (major == 1 & & minor == 5 & & revision > = 39)
{
//вещь...?
}
7. пожалуйста, имейте в виду: если вы компилируете skse dll в режиме отладки, время загрузки базы данных может составлять около 14 секунд! в режиме выпуска это составляет около 0,2 секунды. это связано с тем, что стандартные контейнеры библиотеки работают очень медленно в этом режиме (карта std).
разрешения на получение
делай все, что хочешь.