SKSE插件的地址库

创作者: meh321
已更新:2024-02-14 09:19:54
2.3MB

前置 MOD

使用 SKSE插件的地址库 时将自动安装

关于此 MOD

包含头文件和数据库,以便轻松实现 SKSE DLL 插件的版本独立性。
重要的! 这现在分为两个版本:特别版(1.5.x)和周年纪念版(1.6.x)。指向地址的id在这两个版本之间不会匹配(游戏可执行文件差异太大,无法匹配,即使它们匹配了,这些函数中的代码也是不同的)。

描述

对于普通mod用户: 从文件部分下载并安装“一体化”软件包。您可以使用mod manager或手动执行。.bin文件应该放在这里:
数据/SKSE/插件/
你没有必要阅读其余的内容。

对于SKSE DLL插件作者:
这是一个modder资源(头文件)。您可以加载一个存储偏移量的数据库,这样您的DLL插件就可以独立于版本,而不需要重新编译。头文件可以从文件的可选部分下载。对于周年纪念版,头文件名为versionlibdb.h,而不是versiondb.h!如果您使用的是CommonLib,那么所有这些都已经内置了,您不需要这里的任何东西。


如何使用

最快的方法:
剧透:  
表明


#包括“versiondb.h”

void*MyAddress=NULL
无符号long long MyOffset=0;

bool InitializeOffsets()
{
//在堆栈上分配,这样当我们退出这个函数时,它将被卸载。
//不需要加载整个数据库并无缘无故地耗尽内存。
版本数据库数据库;

//使用当前可执行版本加载数据库。
if(!db.Load())
{
_FATALERROR(“无法加载当前可执行文件的版本数据库!”);

}
else
{
//"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(“找不到地址!”);
返回false;
}

//此偏移量不包括基址。实际地址将是ModuleBase+MyOffset。
if(!db.FindOffsetById(123, MyOffset))
{
_FATALERROR(“找不到我的东西的偏移量!”);

}

//一切都很成功。
返回true;
}



现在你想知道那里的“123”值是多少。这是一个地址的ID。不同版本的数据库将具有相同的地址ID,但它可能指向不同的值。要获取特定版本的所有ID和值对的列表,请执行以下操作:

剧透:  
表明


#包括“versiondb.h”

布尔转储SpecificVersion()
{
版本数据库数据库;

//尝试加载1.5.62.0版本的数据库,而不管运行的可执行版本如何。
如果(!db.Load(1, 5, 62, 0))
{
_FATALERROR(“无法加载1.5.62.0的数据库!”);
返回false;
}

//写出一个名为offsets-1.5.62.0.txt的文件,其中每一行都是ID和偏移量。
db.Dump("offsets-1.5.62.0.txt");
_MESSAGE(“1.5.62.0的转储偏移量”);
返回true;
}



不要用1, 5, 62, 0,而是用你正在反转和熟悉的版本。您必须首先在/Data/SKSE/Plugins目录中拥有相应的数据库文件。

调用后,您应该在Skyrim主目录中有一个名为“offsets-1.5.62.0.txt”的新文件,或者您输入的任何文件名。每行的格式如下:
十进制ID<tab>六角偏移<newline>

例如,如果您在1.5.62.0中有一个地址142F4DEF8(玩家角色静态指针),您希望使其与版本无关,您可以这样做:
1.在offsets文件中查找2F4DEF8。因为这是没有基数140000000的偏移量
2.看到ID是517014(十进制!)
3.如果您希望在运行时将此地址包含在DLL中,请执行以下操作:


void*addressof 142 f 4 def8=db.FindAddressById(517014);


现在你有了。

VersionDb结构具有以下功能:
剧透:  
表明


布尔转储(常量std::字符串和路径);//将当前加载的数据库转储到文件
布尔加载(int major、int minor、int revision、int build);//如果Data/SKSE/Plugins目录中存在db-major-minor-revision-build.bin,则加载特定版本
bool Load();//加载当前应用程序的版本
void Clear();//清除当前加载的数据库
void GetLoadedVersion(int&major、int&minor、int&revision、int&build)常量;//获取我们现在加载的数据库文件的版本
bool GetExecutableVersion(int&major,int&minor,int&revision,int&build)常量;//获取当前执行的应用程序的版本
const std::string&GetModuleName()const;//获取当前加载的数据库模块的名称,这应该显示“SkyrimSE.exe”
const std::string&GetLoadedVersionString()const;//以字符串形式获取当前加载的版本,例如“1.5.62.0”
const std::map<unsigned long long, unsigned long long>&GetOffsetMap()常量;//如果需要手动迭代,获取ID到offset的映射
void*FindAddressById(无符号长长id)常量;//按ID查找地址,这将已经包括基址并且是正确的地址。如果找不到,它将返回NULL!
bool FindOffsetById(无符号长长id,无符号长长&结果)常量;//按ID查找偏移量,这将只是不包括基数的偏移量。
bool FindIdByAddress(void*ptr,无符号long long&result)常量;//按地址查找ID,这将尝试反向查找以将地址转换为ID
bool FindIdByOffset(无符号长长偏移量,无符号长长&结果)常量;//按偏移量查找ID,这将尝试反向查找以将偏移量转换为ID



你应该知道和记住的事情:

1.您可以在插件中包含任何(或所有)数据库文件,但这可能会大大增加文件大小(大约2.5 mb)。到目前为止,通常将这个mod标记为依赖项。

2.您应该始终只在启动时加载数据库一次,初始化/缓存您需要的地址并让它卸载。卸载只是意味着VersionDb结构被删除或丢失(如果您在堆栈上分配)。这将确保您在游戏运行时不会使用不必要的内存。在游戏过程中没有必要保持数据库的加载。如果您使用CommonLib,这是一个有争议的问题,因为它只加载一次,而不是为每个DLL加载。

3.数据库包含函数、全局变量、RTTI、vtables以及其他任何可能对其有引用的内容的地址。它不包含位于函数中间或全局中间的地址。如果您需要函数中间的地址,您应该查找函数基址并自己添加额外的偏移量。它也不包含无用的东西,如函数周围的对齐(在rdata中引用),pdata部分被丢弃,一些编译器从rdata生成的SEH信息被丢弃。

4.您应该始终检查结果,以确保数据库加载成功(bool Load返回true),并且查询的地址实际上返回了有效的结果(而不是NULL)。如果它无法加载,这意味着文件很可能丢失或版本错误(例如,试图在AE中使用SE头)。如果查询失败,则意味着在该版本中找不到地址。这可能意味着游戏代码发生了足够大的变化,以至于地址对该版本不再有效,或者数据库本身未能检测到正确的地址。如果这两种情况中的任何一种发生,你应该让插件初始化失败,让SKSE知道你没有正确加载。或手动显示错误消息。

5.如果您在发布DLL插件之前检查以确保该地址存在于游戏的所有版本中,那也是最好的。为此,请加载数据库文件的每个版本,并在每个版本中查询相同的地址ID以确保其存在:
剧透:  
表明


bool LoadAll(std::vector<VersionDb*>(&all)
{
静态int版本[]={3,16,23,39,50,53,62,73,80,97,-1};
对于(int i=0;版本[i]>=0;i++)
{
version db*db=new version db();
if(!db->Load(1, 5,版本[i], 0))
{
删除数据库;
返回false;
}
all.push_back(db);
}
返回true;
}

bool ExistsInAll(std::vector<VersionDb*>(&all,无符号长id)
{
无符号长长结果=0;

{
if(!db->FindOffsetById(id,result))

}
返回true;
}

void FreeAll(std::vector<VersionDb*>(&all)
{
对于(自动数据库:全部)
删除数据库;
全部。clear();
}

布尔IsOk()
{
std::vector<VersionDb*>全部;
if(!LoadAll(all))
{
_FATALERROR(“无法加载当前可执行文件的一个或多个版本数据库!”);
FreeAll(全部);
返回false;
}

if(!ExistsInAll(all, 517014))
{
_FATALERROR("517014不存在于所有版本的数据库中!");


}

FreeAll(全部);
//好的!
返回true;
}



这样你可以确保你的DLL mod在所有版本中都能工作,或者如果它在某些版本中不能工作,你可以在你的mod页面上写出来。

6.有时你需要根据运行的游戏版本做一些不同的事情。您可以使用以下代码片段执行此操作:
剧透:  
表明


int major=0,minor=0,revision=0,build=0;
if(!db.GetExecutableVersion(major、minor、revision、build))
{
_FATALERROR(“出了问题!”);
返回false;
}

//正在运行的游戏是1.5.x并且至少是1.5.39.0版本
如果(主要==1&&次要==5&&修订>=39)
{
//东西...?
}



7.请记住:如果你在调试模式下编译你的SKSE DLL,数据库的加载时间可以在14秒左右!在释放模式下,这大约是0.2秒。这是因为标准库容器在该模式下非常慢(std map)。


权限

你想做什么就做什么。

上古卷轴5:天际 特别版 的热门 MOD

探索适用于 上古卷轴5:天际 特别版 的最佳MOD,带来新功能、升级画面,以及令人兴奋的方式来改变您的游戏体验。

2025-12-16 11:53:50

前置必备Mod

Mod组织者2

ModOrganizerTeam2024-08-04 16:31:44

Mod Organizer(MO)是一个用于管理任意大小的Mod集合的工具。它是专门为那些喜欢尝试mods的人设计的,因此需要一种简单可靠的方法来安装和卸载它们。

天空用户界面

schlangster2017-10-04 05:03:26

界面优雅,对电脑友好,并具有许多高级功能。

非官方《上古卷轴5:天际》特别版补丁 - USSEP

Arthmoor2025-09-01 07:56:09

一款针对《上古卷轴V:天际特别版》的综合性错误修复模组。非官方天际特别版补丁(简称USSEP)的目标是最终修复《天际特别版》中所有尚未被官方修复的错误。

静态网格改进模组 - SMIM

Brumbek2018-07-05 02:28:26

这是一个旨在大幅提升《上古卷轴5:天际》中无数静态3D模型外观的大型项目。简而言之,我希望通过这个项目让天际的建筑、杂物、家具和景观更加美观。

SKSE插件的地址库

meh3212024-02-14 09:19:54

包含头文件和数据库,以便轻松实现 SKSE DLL 插件的版本独立性。

比赛菜单

expired69782024-01-27 03:38:17

角色创建菜单全面改版,新增多种自定义功能,例如多种RGBA战纹、身体彩绘、手部彩绘和脚部彩绘。(需要SKSE)

Fores Skyrim SE-FNIS SE中的新闲置

NexusModsCaretaker2020-02-19 01:47:03

Skyrim没有可能的自定义动画?错误的。FNIS行为允许添加不同类型的动画到游戏:闲置/姿势,顺序,家具,配对,杀戮,生物,等等。

使用 Xmod 解锁 上古卷轴5:天际 特别版 的全部潜力 — 今天就探索这些顶级 MOD!