logo
ko
한국어

SKSE 플러그인의 주소 라이브러리

제작자: meh321
업데이트됨:2020-02-24 19:31:54
2.8MB
mcafee
인증
200,000,000+명의 사용자에게 신뢰받음

이 모드에 대하여

헤더 파일과 데이터베이스를 포함하여 SKSE DLL 플러그인 버전을 쉽게 독립적으로 만듭니다.
중요한!이 버전은 이제 특별판(1.5.x)과 기념일판(1.6.x)의 두 가지 버전으로 나뉩니다. 두 버전 간에는 주소를 가리키는 ID가 일치하지 않습니다(게임 실행 파일이 너무 달라서 일치할 수 없고, 일치하더라도 해당 함수 내의 코드는 어차피 다릅니다).

설명

일반 모드 사용자의 경우:파일 섹션에서 "올인원" 패키지를 다운로드하여 설치하세요. 모드 매니저를 사용하거나 직접 설치할 수 있습니다. .bin 파일은 다음 위치에 저장하세요.
데이터/SKSE/플러그인/
나머지 내용은 읽을 필요가 없습니다.

SKSE DLL 플러그인 작성자를 위한 정보:
이것은 모더 리소스(헤더 파일)입니다. 오프셋을 저장하는 데이터베이스를 로드하면 DLL 플러그인을 다시 컴파일하지 않고도 버전에 독립적으로 사용할 수 있습니다. 헤더 파일은 파일의 선택 섹션에서 다운로드할 수 있습니다. Anniversary Edition의 경우 헤더 파일은 versiondb.h가 아닌 versionlibdb.h입니다! CommonLib을 사용하는 경우 이 모든 기능이 이미 내장되어 있으므로 여기에서는 아무것도 필요하지 않습니다.


사용 방법

가장 빠른 방법:
스포일러:
보여주다


#include "versiondb.h"

void * 내 주소 = NULL;
부호 없는 long long MyOffset = 0;

bool InitializeOffsets()
{
// 스택에 할당하여 이 함수를 종료할 때 언로드되도록 합니다.
// 아무 이유 없이 전체 데이터베이스를 로드하고 메모리를 사용할 필요는 없습니다.
버전Db db;

// 현재 실행 가능한 버전으로 데이터베이스를 로드합니다.
if (!db.Load())
{
_FATALERROR("현재 실행 파일의 버전 데이터베이스를 로드하는 데 실패했습니다!");
거짓을 반환합니다.
}
또 다른
{
// "스카이림SE.exe", "1.5.97.0"
_MESSAGE("%s 버전 %s에 대한 데이터베이스가 로드되었습니다.", db.GetModuleName().c_str(), db.GetLoadedVersionString().c_str());
}

// 이 주소에는 모듈의 기본 주소가 이미 포함되어 있으므로 주소를 직접 사용할 수 있습니다.
내 주소 = db.FindAddressById(123);
내 주소가 NULL인 경우
{
_FATALERROR("주소를 찾을 수 없습니다!");
거짓을 반환합니다.
}

// 이 오프셋에는 기본 주소가 포함되지 않습니다. 실제 주소는 ModuleBase + MyOffset입니다.
if (!db.FindOffsetById(123, MyOffset))
{
_FATALERROR("내 항목에 대한 오프셋을 찾을 수 없습니다!");
거짓을 반환합니다.
}

// 모든 것이 성공적이었습니다.
true를 반환합니다.
}



이제 "123" 값이 무엇인지 궁금하시겠죠. 이 값은 주소의 ID입니다. 버전에 따라 주소 ID는 동일하지만, 다른 값을 가리킬 수 있습니다. 특정 버전의 모든 ID와 값 쌍 목록을 보려면 다음과 같이 하세요.

스포일러:
보여주다


#include "versiondb.h"

bool DumpSpecificVersion()
{
버전Db db;

// 실행 파일 버전에 관계 없이 버전 1.5.62.0의 데이터베이스를 로드하려고 시도합니다.
if (!db.Load(1, 5, 62, 0))
{
_FATALERROR("1.5.62.0에 대한 데이터베이스를 로드하는 데 실패했습니다!");
거짓을 반환합니다.
}

// 각 줄에 ID와 오프셋을 포함하는 offsets-1.5.62.0.txt라는 파일을 작성합니다.
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" 또는 파일 이름을 입력하신 대로 새 파일이 생성됩니다. 각 줄의 형식은 다음과 같습니다.
10진수 ID육각형 오프셋

예를 들어 1.5.62.0에 플레이어 캐릭터 정적 포인터인 주소 142F4DEF8이 있고 이를 버전과 독립적으로 만들고 싶다면 다음과 같이 하면 됩니다.
1. 오프셋 파일에서 2F4DEF8을 찾으세요. 이는 밑변 140000000을 제외한 오프셋입니다.
2. ID가 517014(10진수!)인지 확인하세요.
3. 런타임에 DLL에 이 주소가 필요하면 다음을 수행하세요.


void* addressOf142F4DEF8 = db.FindAddressById(517014);


그리고 그것이 바로 그것입니다.

VersionDb 구조체에는 다음과 같은 기능이 있습니다.
스포일러:
보여주다


bool Dump(const std::string& path); // 현재 로드된 데이터베이스를 파일에 덤프합니다.
bool Load(int major, int minor, int revision, int build); // db-major-minor-revision-build.bin이 Data/SKSE/Plugins 디렉토리에 있는 경우 특정 버전을 로드합니다.
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")
상수 std::map& GetOffsetMap() const; // 수동으로 반복해야 하는 경우 ID의 맵을 오프셋으로 가져옵니다.
void* FindAddressById(unsigned long long id) const; // 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.5MB). 지금까지는 이 모드를 종속성으로 표시하는 것이 일반적이었습니다.

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 = 새 버전 데이터베이스();
if (!db->Load(1, 5, version[i], 0))
{
db 삭제;
거짓을 반환합니다.
}
모든.푸시백(db);
}
true를 반환합니다.
}

bool ExistsInAll(std::vector& 모두, unsigned long long id)
{
unsigned long long 결과 = 0;
(자동 DB : 모두)
{
if (!db->FindOffsetById(id, result))
거짓을 반환합니다.
}
true를 반환합니다.
}

void FreeAll(std::vector& 모두)
{
(자동 DB : 모두)
db 삭제;
모두 지우기();
}

bool IsOk()
{
std::벡터모두;
if (!LoadAll(all))
{
_FATALERROR("현재 실행 파일에 대한 하나 이상의 버전 데이터베이스를 로드하는 데 실패했습니다!");
FreeAll(모두);
거짓을 반환합니다.
}

if (!ExistsInAll(모두, 517014))
{
_FATALERROR("517014는 모든 버전의 데이터베이스에 존재하지 않습니다!");
FreeAll(모두);
거짓을 반환합니다.
}

FreeAll(모두);
// 좋아요!
true를 반환합니다.
}



이렇게 하면 DLL 모드가 모든 버전에서 작동할지 확인할 수 있고, 일부 버전에서 작동하지 않는 경우 모드 페이지에 해당 내용을 적어둘 수 있습니다.

6. 실행 중인 게임 버전에 따라 다른 작업을 해야 할 때가 있습니다. 다음 코드 조각을 사용하면 됩니다.
스포일러:
보여주다


int major = 0, minor = 0, revision = 0, build = 0;
if (!db.GetExecutableVersion(major, minor, revision, build))
{
_FATALERROR("뭔가 잘못되었습니다!");
거짓을 반환합니다.
}

// 실행 중인 게임은 1.5.x이고 최소 버전은 1.5.39.0입니다.
if (major == 1 && minor == 5 && revision >= 39)
{
// 물건 ... ?
}



7. SKSE DLL을 디버그 모드에서 컴파일하면 데이터베이스 로드 시간이 약 14초가 될 수 있습니다! 릴리스 모드에서는 약 0.2초입니다. 이는 해당 모드에서 표준 라이브러리 컨테이너(std map)가 매우 느리기 때문입니다.


권한

당신이 원하는 것을 하세요.

Multiverse Loot Hunter용 인기 모드

Multiverse Loot Hunter의 최고의 모드를 탐색하세요. 새로운 기능, 향상된 그래픽, 그리고 흥미로운 방식으로 게임 플레이 경험을 변화시킬 수 있습니다.

Xmod로 Multiverse Loot Hunter의 모든 잠재력을 발휘하세요 — 오늘 이 최고 모드를 탐험해보세요!

mcafee
인증
200,000,000+명의 사용자에게 신뢰받음

다운로드 또는 설치에 문제가 있나요? 지원을 위해 우리 Discord 커뮤니티에 참여하세요!

logo
언어

게임 솔루션

리소스

파트너

우리를 팔로우하세요

discordfacebooktwitteryoutube
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