logo
zh-tw
繁中

SKSE挿件地址庫

創作者: meh321
已更新:2020-02-24 19:31:54
2.8MB
mcafee
驗證
獲得 200,000,000+ 位用戶信任

關於此模組

包含標頭檔和資料庫,使SKSE DLL挿件易於版本獨立。
重要的!現在分為兩個版本:特別版(1.5.x)和週年紀念版(1.6.x)。這兩個版本之間指向地址的ID不一致(遊戲可執行檔差異太大,無法匹配,即使匹配,這些函數中的程式碼也不同)。

描述

對於常規 mod 用戶:從檔案部分下載並安裝「一體化」軟體包。您可以使用模組管理器或手動操作。 .bin 文件應位於此處:
數據/SKSE/插件/
您無需閱讀其餘部分。

對於 SKSE DLL 外掛程式作者:
這是一個模組製作資源(頭檔)。您可以載入一個儲存偏移量的資料庫,這樣您的 DLL 插件就可以獨立於版本,無需重新編譯。頭文件可以從文件的可選部分下載。週年紀念版的頭檔名為 versionlibdb.h,而不是 versiondb.h!如果您使用的是 CommonLib,那麼所有這些都已內置,您無需從這裡下載任何文件。


如何使用

最快的方法:
劇透:
展示


#include "versiondb.h"

void * 我的地址 = NULL;
無符號長整型 MyOffset = 0;

bool 初始化偏移量()
{
// 在堆疊上分配,以便我們退出此函數時它將被卸載。
// 不需要無緣無故地載入整個資料庫並佔用記憶體。
版本資料庫;

// 使用目前可執行版本載入資料庫。
如果(!db.Load())
{
_FATALERROR("無法載入目前可執行檔的版本資料庫!");
返回 false;
}
別的
{
//“SkyrimSE.exe”,“1.5.97.0”
_MESSAGE("已載入 %s 版本 %s 的資料庫。", db.GetModuleName().c_str(), db.GetLoadedVersionString().c_str());
}

// 該位址已經包含模組的基底位址,因此我們可以直接使用該位址。
我的地址 = db.FindAddressById(123);
如果(我的地址 == NULL)
{
_FATALERROR("找不到位址!");
返回 false;
}

// 此偏移量不包含基底址。實際位址為 ModuleBase + MyOffset。
如果(!db.FindOffsetById(123,MyOffset))
{
_FATALERROR("無法找到我的東西的偏移!");
返回 false;
}

// 一切順利。
傳回 true;
}



現在你肯定想知道那個「123」值是什麼。這是一個地址的ID。不同版本的資料庫會為同一個位址分配相同的ID,但它可能指向不同的值。若要取得特定版本的所有ID和值對的列表,請執行下列操作:

劇透:
展示


#include "versiondb.h"

bool DumpSpecificVersion()
{
版本資料庫;

// 無論執行的可執行檔版本為何,都嘗試載入版本 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("偏移量-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六角偏移

例如,如果您在 1.5.62.0 中有一個位址 142F4DEF8(玩家角色靜態指標),並且您想要使它與版本無關,您可以這樣做:
1. 在偏移檔案中尋找 2F4DEF8。因為這是沒有基數 140000000 的偏移量
2.看到ID是517014(十進位!)
3. 如果您希望在執行時間將此位址包含在您的 DLL 中,請執行以下操作:


無效* addressOf142F4DEF8 = db.FindAddressById(517014);


就是這樣了。

VersionDb 結構具有以下功能:
劇透:
展示


bool Dump(const std::string& path); // 將目前載入的資料庫轉儲到文件
bool Load(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) 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::map& GetOffsetMap() const; // 若需要手動迭代,取得ID到偏移量的映射
void* FindAddressById(unsigned long long id) const; // 透過 ID 尋找位址,該 ID 已包含基底地址且為正確位址。如果未找到,則傳回 NULL!
bool FindOffsetById(unsigned long long id, unsigned long long& result) const; // 透過 ID 找出偏移量,這只是不包含基數的偏移量。
bool FindIdByAddress(void* ptr, unsigned long long& result) const; // 透過位址尋找 ID,這將嘗試反向查找以將位址轉換為 ID
bool FindIdByOffset(unsigned long long offset, unsigned long long& result) const; // 透過偏移量尋找 ID,這將嘗試反向查找以將偏移量轉換為 ID



您應該了解並牢記的事情:

1. 您可以在插件中包含任意(或全部)資料庫文件,但這可能會顯著增加文件大小(約 2.5 MB)。目前,通常將此模組標記為依賴項。

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& 全部)
{
靜態 int 版本[] = { 3, 16, 23, 39, 50, 53, 62, 73, 80, 97, -1 };
對於(int i = 0;版本[i]> = 0; i ++)
{
版本資料庫 * db = 新的版本資料庫();
如果(!db->Load(1,5,版本[i],0))
{
刪除資料庫;
返回 false;
}
全部.push_back(db);
}
傳回 true;
}

bool ExistsInAll(std::vector&全部,無符號長整型 id)
{
無符號長整型結果 = 0;
對於(自動資料庫:全部)
{
如果(!db->FindOffsetById(id,結果))
返回 false;
}
傳回 true;
}

無效的FreeAll(std ::向量& 全部)
{
對於(自動資料庫:全部)
刪除資料庫;
全部.清除();
}

bool IsOk()
{
std::vector全部;
如果(!LoadAll(全部))
{
_FATALERROR("無法為目前執行檔載入一個或多個版本資料庫!");
免費全部(全部);
返回 false;
}

如果(!ExistsInAll(全部,517014))
{
_FATALERROR("517014 在所有版本的資料庫中都不存在!");
免費全部(全部);
返回 false;
}

免費全部(全部);
// 好的!
傳回 true;
}



這樣,您可以確保您的 DLL mod 在所有版本中都能工作,或者如果它在某些版本中不起作用,您可以在 mod 頁面上寫明。

6. 有時您需要根據正在執行的遊戲版本執行不同的操作。您可以使用以下程式碼片段來實現:
劇透:
展示


int major = 0,minor = 0,revision = 0,build = 0;
如果(!db.GetExecutableVersion(主要,次要,修訂,建置))
{
_FATALERROR("出現錯誤!");
返回 false;
}

// 正在運行的遊戲是 1.5.x 並且至少是版本 1.5.39.0
if (主 == 1 && 次要 == 5 && 修訂 >= 39)
{
// 東西 ... ?
}



7. 請注意:如果您在偵錯模式下編譯 SKSE DLL,資料庫載入時間可能約為 14 秒!在發布模式下,載入時間約為 0.2 秒。這是因為標準庫容器在該模式下(std map)運作速度非常慢。


權限

做任何你想做的事。

Multiverse Loot Hunter 的熱門模組

探索適用於 Multiverse Loot Hunter 的最佳模組,帶來新功能、升級畫面,以及令人興奮的方式來改變您的遊戲體驗。

使用 XMODhub 解鎖 Multiverse Loot Hunter 的全部潛力 — 今天就探索這些頂級模組!

mcafee
驗證
獲得 200,000,000+ 位用戶信任

需要下載或安裝幫助嗎?加入我們的Discord 社群尋求支援。

logo
語言

遊戲解決方案

資源

合作夥伴

關注我們

discordfacebooktwitteryoutube
聯絡客服:
support@xmodhub.com
Xmod_Lily
商務洽詢:
dc@xmodhub.com or cathy@business.xmodhub.com
catherine_79237

Larvas Limited

Room 1201, 12/F Tai Sang Bank Building 130-132 Des Voeux Road Central HK