Chứa tệp tiêu đề và cơ sở dữ liệu để dễ dàng tạo phiên bản plugin SKSE DLL độc lập.
Quan trọng! Này hiện được chia thành 2 phiên bản: phiên bản đặc biệt (1.5.x) và phiên bản kỷ niệm (1.6.x). Các id trỏ đến địa chỉ sẽ không khớp giữa 2 phiên bản đó (tệp thực thi trò chơi quá khác nhau để khớp và ngay cả khi chúng khớp với mã trong các hàm đó thì cũng khác nhau).Mô tảDành cho người dùng mod thông thường: Tải xuống và cài đặt gói "tất cả trong một" từ phần tệp. Bạn có thể sử dụng trình quản lý mod hoặc thực hiện theo cách thủ công. Các tập tin. bin nên đến đây:
Dữ liệu/SKSE/Plugin/Bạn không cần phải đọc phần còn lại của điều này.
Cho tác giả plugin skse dll:đây là tài nguyên modder (tệp tiêu đề). Bạn có thể tải cơ sở dữ liệu lưu trữ độ bù để plugin dll của bạn có thể độc lập với phiên bản mà không cần phải biên dịch lại. Tệp tiêu đề có thể được tải xuống từ phần tùy chọn của tệp. đối với phiên bản kỷ niệm, tệp tiêu đề được gọi là versionlibdb.h thay vì versiondb.h! Nếu bạn đang sử dụng commonlib thì tất cả những điều này đã được tích hợp sẵn và bạn không cần bất cứ thứ gì từ đây.
Cách sử dụngCách nhanh nhất:
Spoiler:
Hiển thị
# bao gồm "versiondb.h"
void*MyAddress=NULL;
Myoffset dài không có dấu = 0;
bool InitializeOffsets ()
{
//phân bổ trên ngăn xếp để nó sẽ được dỡ tải khi chúng ta thoát khỏi hàm này.
//không cần phải tải toàn bộ cơ sở dữ liệu và sử dụng hết bộ nhớ mà không có lý do gì.
Phiên bản db db;
//tải cơ sở dữ liệu với phiên bản thực thi hiện tại.
if (! db.Load ())
{
_FATALERROR ("không tải cơ sở dữ liệu phiên bản cho tệp thực thi hiện tại!");
}
Nếu không
{
//"SkyrimSE.exe", "1.5.97.0"
_MESSAGE("cơ sở dữ liệu đã tải cho %s phiên bản %s. ", db.GetModuleName (). c_str (), db.GetLoadedVersionString (). c_str ());
}
//địa chỉ này đã bao gồm địa chỉ cơ bản của mô-đun để chúng ta có thể sử dụng địa chỉ đó trực tiếp.
địa chỉ my=db.FindAddressById(123);
if (địa chỉ my==NULL)
{
_FATALERROR ("không tìm được địa chỉ!");
Trả lại sai;
}
//độ bù này không bao gồm địa chỉ cơ bản. địa chỉ thực tế sẽ là modulebase MyOffset.
if (! db.FindOffsetById(123, MyOffset))
{
_FATALERROR ("không tìm được bù đắp cho thứ của tôi!");
}
//mọi thứ đều thành công.
Trả lại đúng;
}
Bây giờ bạn đang tự hỏi giá trị "123" ở đó là gì. đây là id của một địa chỉ. Cơ sở dữ liệu phiên bản khác nhau sẽ có cùng ID cho một địa chỉ nhưng nó có thể trỏ đến các giá trị khác nhau. để có được danh sách tất cả các cặp id và giá trị cho một phiên bản cụ thể, hãy làm điều này:
Spoiler:
Hiển thị
# bao gồm "versiondb.h"
Boolean dump SpecificVersion ()
{
Phiên bản db db;
//cố gắng tải cơ sở dữ liệu của phiên bản 1.5.62.0 bất kể đang chạy phiên bản thực thi.
if (! db.Load(1,5,62,0))
{
_FATALERROR ("không tải cơ sở dữ liệu cho 1.5.62.0!");
Trả lại sai;
}
//viết ra một tệp có tên offsets-1.5.62.0.txt trong đó mỗi dòng là id và offset.
db.Dump ("offsets-1.5.62.0.txt");
_MESSAGE("bù đắp được bán cho 1.5.62.0 ");
Trả lại đúng;
}
Thay vì 1,5,62,0 đặt phiên bản bạn đang đảo ngược và quen thuộc. Trước tiên bạn phải có tệp cơ sở dữ liệu tương ứng trong thư mục /Data/SKSE/plugins.
Sau khi gọi điều này, bạn nên có một tệp mới trong thư mục skyrim chính có tên "offsets-1.5.62.0.txt" hoặc bất cứ thứ gì bạn đặt làm tên tệp. Nó sẽ ở định dạng mà mỗi dòng là:
ID thập phân<tab>độ lệch lục giác<newline>
Ví dụ: nếu bạn có địa chỉ 142f4def8 (con trỏ tĩnh ký tự người chơi) trong 1.5.62.0 mà bạn muốn làm cho phiên bản độc lập, bạn sẽ làm điều này:
1. tra cứu 2f4def8 trong tệp bù trừ. Bởi vì đây là độ bù mà không có cơ sở 140000000
2. xem id là 517014 (thập phân!)
3. nếu bạn muốn địa chỉ này trong dll của bạn tại thời gian chạy, hãy làm điều này:
void*addressOf142F4DEF8 = db.FindAddressById(517014);
Và bạn có nó đó.
Cấu trúc versiondb có các chức năng sau:
Spoiler:
Hiển thị
bool Dump (const std::string //đổ cơ sở dữ liệu hiện đang tải vào tệp
Tải bool (int major, int minor, int revision, int build); //tải một phiên bản cụ thể nếu db-major-minor-revision-build.bin tồn tại trong thư mục data/SKSE/plugins
Tải bool (); //tải phiên bản cho ứng dụng hiện tại
Void rõ ràng (); //xóa cơ sở dữ liệu hiện đang tải
void GetLoadedVersion (int & major, int & minor, int & revision, int & build) const; //lấy phiên bản tệp cơ sở dữ liệu mà chúng tôi đã tải ngay bây giờ
bool GetExecutableVersion (int & major, int & minor, int & revision, int & build) const; //lấy phiên bản ứng dụng hiện đang thực thi
const std::string & GetModuleName () const; //lấy tên của mô-đun cơ sở dữ liệu hiện đang tải, điều này sẽ hiển thị "SkyrimSE.exe"
const std::string & GetLoadedVersionString () const; //lấy phiên bản hiện đang tải dưới dạng chuỗi, ví dụ: "1.5.62.0"
const std:: bản đồ<unsigned long long, unsigned long long>& GetOffsetMap () const; //lấy bản đồ id để bù đắp nếu bạn cần lặp lại nó theo cách thủ công
void * FindAddressById (id dài không có dấu) const; //tìm địa chỉ theo id, điều này sẽ bao gồm địa chỉ cơ sở và chính xác. Nó sẽ trả về null nếu không tìm thấy!
bool FindOffsetById (id dài không có dấu, không có dấu dài //tìm bù trừ theo id, điều này sẽ chỉ được bù trừ mà không bao gồm cơ sở.
Bool findbyaddress(void*ptr, longlong không ký hiệu //tìm id theo địa chỉ, điều này sẽ cố gắng tìm kiếm ngược để chuyển đổi địa chỉ thành id
Bool findbyoffset (bù trừ dài không ký hiệu, bù trừ dài không ký hiệu //tìm id theo bù trừ, điều này sẽ cố gắng tìm kiếm ngược để chuyển đổi bù trừ thành id
Những điều bạn nên biết và ghi nhớ:
1. bạn có thể bao gồm bất kỳ (hoặc tất cả) các tập tin cơ sở dữ liệu với plugin của bạn nhưng nó có thể tăng kích thước tập tin đáng kể (khoảng 2,5 mb). Cho đến nay, thay vào đó, việc đánh dấu mod này là một phụ thuộc đã trở nên phổ biến.
2. bạn nên luôn luôn chỉ tải cơ sở dữ liệu một lần khi khởi động, khởi tạo/cache các địa chỉ bạn cần và để nó dỡ tải. Dỡ tải chỉ có nghĩa là cấu trúc versiondb sẽ bị xóa hoặc mất (nếu bạn được phân bổ trên ngăn xếp). điều này sẽ đảm bảo bạn không sử dụng lượng bộ nhớ không cần thiết trong thời gian chạy trò chơi. Không cần phải nạp cơ sở dữ liệu trong quá trình chơi. đây là một điểm tranh luận nếu bạn sử dụng commonlib vì nó chỉ tải nó một lần thay vì cho mỗi dll.
3. cơ sở dữ liệu chứa địa chỉ của các hàm, biến toàn cục, RTTI, vtables và bất cứ thứ gì khác có thể tham chiếu đến nó. Nó không chứa các địa chỉ ở giữa các hàm hoặc giữa các chữ toàn cục. Nếu bạn cần một địa chỉ ở giữa hàm, bạn nên tra cứu địa chỉ cơ sở hàm và tự thêm bù trừ thêm. Nó cũng không chứa những thứ vô dụng như căn chỉnh xung quanh các hàm (được tham chiếu trong rdata), phần pdata bị loại bỏ và một số thông tin seh do trình biên dịch tạo từ rdata bị loại bỏ.
4. bạn nên luôn kiểm tra kết quả để đảm bảo cơ sở dữ liệu được tải thành công (tải bool trả về đúng) và rằng các địa chỉ được truy vấn thực sự trả về kết quả hợp lệ (không phải null). Nếu nó không tải được, điều đó có nghĩa là tệp rất có thể bị thiếu hoặc phiên bản sai (ví dụ: cố gắng sử dụng tiêu đề se trong ae). Nếu truy vấn không thành công, điều đó có nghĩa là không thể tìm thấy địa chỉ trong phiên bản đó. điều này có thể có nghĩa là mã trò chơi đã thay đổi đủ để địa chỉ không còn hợp lệ đối với phiên bản đó hoặc bản thân cơ sở dữ liệu không phát hiện được địa chỉ chính xác. Nếu một trong những điều đó xảy ra, bạn sẽ không khởi tạo plugin để cho skse biết bạn đã tải không chính xác. Hoặc hiển thị thông báo lỗi theo cách thủ công.
5. nó cũng sẽ là tốt nhất nếu bạn kiểm tra để đảm bảo địa chỉ tồn tại trong tất cả các phiên bản của trò chơi trước khi xuất bản plugin dll của bạn. để thực hiện điều đó tải từng phiên bản của tệp cơ sở dữ liệu và truy vấn cùng một id địa chỉ trong mỗi phiên bản để đảm bảo nó tồn tại:
Spoiler:
Hiển thị
bool LoadAll (std:: vector<VersionDb*>& Tất cả)
{
Phiên bản int tĩnh [] = {3, 16, 23, 39, 50, 53, 62, 73, 80, 97, -1};
Đối với (int i=0; version[i] > = 0; i ++)
{
Phiên bản * db = phiên bản mới ();
if (! db-> Load(1,5, phiên bản [i], 0))
{
Xóa db;
Trả lại sai;
}
Tất cả.push_back(db);
}
Trả lại đúng;
}
bool ExistsInAll (std:: vector<VersionDb*>& tất cả, id dài không ký)
{
Kết quả dài không ký = 0;
{
if (! db-> FindOffsetById(id, kết quả))
}
Trả lại đúng;
}
void FreeAll (std::vector<VersionDb*>& Tất cả)
{
Cho (db tự động: tất cả)
Xóa db;
all.clear ();
}
Boolean IsOk ()
{
std::vectơ<VersionDb*>Tất cả;
if (! LoadAll (tất cả))
{
_FATALERROR ("không tải được một hoặc nhiều cơ sở dữ liệu phiên bản cho tệp thực thi hiện tại!");
Miễn phí tất cả (tất cả);
Trả lại sai;
}
if (! ExistsInAll(all, 517014))
{
_FATALERROR("517014 không tồn tại trong tất cả các phiên bản của cơ sở dữ liệu! ");
}
Miễn phí tất cả (tất cả);
//Được rồi!
Trả lại đúng;
}
Bằng cách này, bạn có thể chắc chắn rằng mod dll của mình sẽ hoạt động trong tất cả các phiên bản hoặc nếu nó không hoạt động trong một số phiên bản, bạn có thể viết điều đó trên trang mod của mình.
6. đôi khi bạn sẽ cần phải làm điều gì đó khác nhau dựa trên phiên bản trò chơi đang chạy. Bạn có thể làm điều đó với đoạn mã này:
Spoiler:
Hiển thị
int major = 0, minor = 0, sửa đổi = 0, xây dựng = 0;
if (! db.GetExecutableVersion(chính, nhỏ, sửa đổi, xây dựng))
{
_FATALERROR ("có điều gì đó không ổn!");
Trả lại sai;
}
//đang chạy trò chơi là 1.5.x và ít nhất là phiên bản 1.5.39.0
if (chính == 1 & & nhỏ == 5 & & sửa đổi > = 39)
{
//thứ...?
}
7. xin hãy nhớ: nếu bạn biên dịch skse dll của bạn ở chế độ gỡ lỗi, thời gian tải của cơ sở dữ liệu có thể là khoảng 14 giây! ở chế độ phát hành thì khoảng 0,2 giây. điều này là do các vùng chứa thư viện tiêu chuẩn rất chậm ở chế độ đó (bản đồ std).
Quyền quyềnLàm bất cứ điều gì bạn muốn.