• 產品
  • 特點
  • Mod Master
  • 下載
  • 遊戲
  • 博客
  • 定價

SKSE插件的地址庫

作者:meh321最後更新:2024-02-14 09:19:5421.1M2.3MB

The Elder Scrolls V: Skyrim Special Edition SKSE插件的地址庫-1-lagofast 模組大師

模組介紹

包含頭檔和資料庫,以便輕鬆實現 SKSE DLL 插件的版本獨立性。
重要! 這現在分為兩個版本:特別版(1.5.x)和周年紀念版(1.6.x)。 指向地址的id在這兩個版本之間不會匹配(遊戲可執行文件差異太大,無法匹配,即使它們匹配了,這些函數中的代碼也是不同的)。

說明

對於普通mod用戶: 從文件部分下載並安裝“一體化”軟件包。 您可以使用mod manager或手動執行。 .bin文件應該放在這裏:
數據/SKSE/插件/
你沒有必要閱讀其餘的內容。

對於SKSE DLL插件作者:
這是一個modder資源(頭文件)。 您可以加載一個存儲偏移量的數據庫,這樣您的DLL插件就可以獨立於版本,而不需要重新編譯。 頭文件可以從文件的可選部分下載。 對於周年紀念版,頭文件名為versionlibdb.h,而不是versiondb.h! 如果您使用的是CommonLib,那麼所有這些都已經內置了,您不需要這裏的任何東西。


如何使用

最快的方法:
劇透:  
Show


#包括“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和值對的列表,請執行以下操作:

劇透:  
Show


#包括“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結構具有以下功能:
劇透:  
Show


布爾轉儲(常量標準::字符串和路徑); //將當前加載的數據庫轉儲到文件
布爾加載(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的映射
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以確保其存在:
劇透:  
Show


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.有時你需要根據運行的遊戲版本做一些不同的事情。 您可以使用以下代碼片段執行此操作:
劇透:  
Show


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)。


權限

你想做什麼就做什麼。
本工具由三方[bufftool]提供注意圖標

立即下载模组

安裝 LagoFast,啟動 The Elder Scrolls V: Skyrim Special Edition 並暢玩你喜愛的模組。