SKSE插件地址库

创作者: meh321
已更新:2020-02-24 19:31:54
2.8MB

关于此 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=空;
无符号长长MyOffset=0;

bool初始化偏移()
{
//在堆栈上进行分配,以便在我们退出此函数时卸载它。
//不需要加载整个数据库,也不需要无缘无故地耗尽内存。
VersionDb数据库;

//加载具有当前可执行版本的数据库。
if(!db.Load())
{
_FATALERROR(“无法加载当前可执行文件的版本数据库!”);
返回false;
}
否则
{
//“skyrimse.Exe”,“1.5.97.0”
_MESSAGE(“%s版本%s的已加载数据库”,db.GetModuleName().c_str(),db。GetLoadedVersionString().c_str());
}

//此地址已经包含模块的基址,因此我们可以直接使用该地址。
MyAddress=db。FindAddressById(123);
如果(MyAddress==NULL)
{
_FATALERROR(“找不到地址!”);
返回false;
}

//此偏移量不包括基址。实际地址为ModuleBase+MyOffset。
if(!db.FindOffsetById(123,MyOffset))
{
_Fataleror(“我的东西找不到补偿!”);
返回false;
}

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



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

剧透:
展示


#包括“versiondb.h”

bool转储特定版本()
{
VersionDb数据库;

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

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



用你正在反转并熟悉的版本代替1、5、62、0。您必须首先在/Data/SKSE/Plugins目录中拥有相应的数据库文件。

调用此命令后,您应该在Skyrim主目录中有一个名为“offsets-1.5.62.0.txt”的新文件,或者您指定的文件名。它的格式如下:
十进制ID<制表符>十六进制偏移<换行符>

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


void*地址为142F4DEF8=db。FindAddressById(517014);


在那里你有它。

VersionDb结构具有以下功能:
剧透:
展示


bool转储(const std::string&path);//将当前加载的数据库转储到文件
bool Load(int main,int minor,int revision,int build);//如果Data/SKSE/Plugins目录中存在db-major-minor-revision-builded.bin,则加载特定版本
bool Load();//加载当前应用程序的版本
void Clear();//清除当前加载的数据库
void GetLoadedVersion(int&main,int&minor,int&revision,int&build)const;//获取我们现在加载的数据库文件的版本
bool GetExecutableVersion(int&main,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::map<无符号long long,无符号long long>&GetOffsetMap()const;//如果需要手动迭代,则获取要偏移的ID映射
void*FindAddressById(无符号长长id)const;//按ID查找地址,这将已经包含基址,并且是正确的地址。如果找不到,它将返回NULL!
bool FindOffsetById(无符号长长长id,无符号长long&result)const;//按ID查找偏移量,这将只是不包括基数的偏移量。
bool FindIdByAddress(void*ptr,unsigned long long&result)常量;//按地址查找ID,这将尝试反向查找以将地址转换为ID
bool FindIdByOffset(无符号长长偏移,无符号长偏移和结果)const;//按偏移量查找ID,这将尝试反向查找以将偏移量转换为ID



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

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

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

3.数据库包含函数的地址、全局变量、RTTI、vtable以及任何其他可能引用它的地址。它不包含位于函数中间或全局中间的地址。如果你需要在函数中间有一个地址,你应该查找函数基地址,然后自己添加额外的偏移量。它也不包含无用的东西,例如围绕函数的对齐(在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};
for(int i=0;版本[i]>=0;i++)
{
VersionDb*db=新的VersionDb();
if(!db->Load(1,5,版本[i],0))
{
删除数据库;
返回false;
}
all.push_back(db);
}
返回true;
}

bool ExistsInAll(std::vector<VersionDb*>&all,无符号长长id)
{
无符号长长长结果=0;
for(自动数据库:全部)
{
if(!db->FindOffsetById(id,result))
返回false;
}
返回true;
}

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

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

如果(!全部存在,517014)
{
_FATALERROR(“517014并非存在于所有版本的数据库中!”);
FreeAll(全部);
返回false;
}

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



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

6.有时你需要根据运行的游戏版本做一些不同的事情。您可以通过以下代码片段来实现:
剧透:
展示


int major=0,minor=0,修订=0,构建=0;
if(!dbGetExecutableVersion(主版本、次版本、修订版、内部版本))
{
_Fataleror(“出了点问题!”);
返回false;
}

//跑步游戏是1.5.x版本,至少是1.5.39.0版本
如果(主要==1&&次要==5&&修订>=39)
{
//东西。.. ?
}



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


权限

做任何你想做的事。

漫威蜘蛛侠 重制版 的热门 MOD

探索适用于 漫威蜘蛛侠 重制版 的最佳MOD,带来新功能、升级画面,以及令人兴奋的方式来改变您的游戏体验。

SkyUI

schlangster2017-10-04 05:03:26

优雅、PC友好的界面模块,具有许多高级功能。

非官方Skyrim特别版补丁-USSEP

Arthmoor2025-09-01 07:56:09

《上古卷轴5:天际》特别版的全面错误修复模组。非官方Skyrim特别版补丁(又名USSEP)的目标是最终修复Skyrim特殊版中尚未正式解决的每个错误

模组管理器2

ModOrganizerTeam2024-08-04 16:31:44

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

静态网格改进模块-SMIM

Brumbek2018-07-05 02:28:26

一个巨大的项目,大大改善了Skyrim中无数静态3D模型的外观。基本上,这是我试图让天际线的建筑、杂乱、家具和景观变得更好。

SKSE插件地址库

meh3212020-02-24 19:31:54

包含头文件和数据库,使SKSE DLL插件易于版本独立。

赛车菜单

expired69782024-01-27 03:38:17

彻底检修角色创建菜单,包括新的自定义功能,如多个RGBA扭曲绘制、身体绘制、手绘和脚部绘制。(需要SKSE)

法术特长物品分发器 (SPID)

powerofthree2024-04-17 23:37:04

SKSE 插件,可以使用配置文件为游戏中的每个 NPC 添加法术/技能/物品/呐喊/礼包/服装/关键词/阵营。

表情丰富的面部动画 - 女性版 -

Niroku2019-12-07 19:22:37

此模组替换了玩家和NPC使用的人类和精灵的面部表情变形文件。此模组修改了所有动画,包括嘴唇、眉毛和眼睛的运动和表情。

使用 Xmod 解锁 漫威蜘蛛侠 重制版 的全部潜力 — 今天就探索这些顶级 MOD!