Skip to content

Commit

Permalink
Add KH1 support
Browse files Browse the repository at this point in the history
  • Loading branch information
Sirius902 committed Aug 11, 2021
1 parent 9c6e967 commit bdae7f5
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 21 deletions.
6 changes: 4 additions & 2 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

### Internal LuaBackend Hook [DLL]
- Download ``DINPUT8.zip`` from the Releases tab.
- Extract ``DINPUT8.dll`` from ``DINPUT8.zip`` to Kingdom Hearts II's EXE location.
- Place your scripts in a folder named `scripts` in the `KINGDOM HEARTS HD 1.5+2.5 ReMIX` folder in your Documents folder.
- Extract ``DINPUT8.dll`` from ``DINPUT8.zip`` to the directory Kingdom Hearts 1.5+2.5 is installed which should be `KH_1.5_2.5`.
- Place your scripts in a folder named `scripts/[gameid]` in the `KINGDOM HEARTS HD 1.5+2.5 ReMIX` folder in your Documents folder.
- For Kingdom Hearts Final Mix the folder will be `scripts/kh1`.
- For Kingdom Hearts II Final Mix the folder will be `scripts/kh2`.
- The installation is now finished. LuaBackend will be automatically started with the game and can be easily uninstalled
by simply removing the ``DINPUT8.dll``. To verify it is installed correctly, you can open the LuaBackend console using
the F2 key on the keyboard in game.
16 changes: 16 additions & 0 deletions LuaBackendDLL/game_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <cstddef>
#include <cstdint>
#include <string_view>

struct HookInfo {
std::uintptr_t start;
std::size_t size;
};

struct GameInfo {
HookInfo hookInfo;
std::uintptr_t baseAddress;
std::string_view scriptsPath;
};
57 changes: 39 additions & 18 deletions LuaBackendDLL/main_dll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <condition_variable>
#include <thread>
#include <mutex>
#include <unordered_map>
#include <optional>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
Expand All @@ -17,6 +19,14 @@
#include <mIni/ini.h>

#include "x86_64.h"
#include "game_info.h"

const std::unordered_map<std::string_view, GameInfo> gameInfos{
{ "KINGDOM HEARTS FINAL MIX.exe", { { 0x10814C, 14 }, 0x3A0606, "kh1" } },
{ "KINGDOM HEARTS II FINAL MIX.exe", { { 0x14C845, 15 }, 0x56450E, "kh2" } },
};

namespace fs = std::filesystem;

using DirectInput8CreateProc = HRESULT(WINAPI*)(HINSTANCE hinst, DWORD dwVersion, LPCVOID riidltf, LPVOID* ppvOut, LPVOID punkOuter);

Expand All @@ -29,6 +39,8 @@ bool scriptsFrameDone = false;

std::thread luaThread;

std::optional<GameInfo> gameInfo{};

extern "C"
{
using namespace std;
Expand Down Expand Up @@ -275,13 +287,13 @@ extern "C" void onFrame() {
void hookGame(uint64_t moduleAddress) {
static_assert(sizeof(uint64_t) == sizeof(uintptr_t));

uint8_t relocated[0xF];
uintptr_t hookStart = moduleAddress + 0x14C845;
uintptr_t hookEnd = hookStart + sizeof(relocated);
std::vector<uint8_t> relocated(gameInfo->hookInfo.size);
uintptr_t hookStart = moduleAddress + gameInfo->hookInfo.start;
uintptr_t hookEnd = hookStart + relocated.size();

DWORD originalProt = 0;
VirtualProtect((void*)hookStart, sizeof(relocated), PAGE_EXECUTE_READWRITE, &originalProt);
std::memcpy((void*)relocated, (void*)hookStart, sizeof(relocated));
VirtualProtect((void*)hookStart, relocated.size(), PAGE_EXECUTE_READWRITE, &originalProt);
std::memcpy(relocated.data(), (void*)hookStart, relocated.size());

uint8_t func[] = {
PUSHF_1, PUSHF_2,
Expand Down Expand Up @@ -309,22 +321,24 @@ void hookGame(uint64_t moduleAddress) {
JUMP_TO(hookEnd),
};

uint64_t funcSize = sizeof(relocated) + sizeof(func);
uint64_t funcSize = relocated.size() + sizeof(func);
void* funcPtr = VirtualAlloc(nullptr, funcSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
uintptr_t funcAddress = (uintptr_t)funcPtr;

uint8_t patch[] = {
std::vector<uint8_t> patch{
JUMP_TO(funcAddress),
NOP,
};

static_assert(sizeof(relocated) == sizeof(patch));
std::memcpy((void*)hookStart, (void*)patch, sizeof(patch));
while (patch.size() < gameInfo->hookInfo.size) {
patch.push_back(NOP);
}

std::memcpy((void*)hookStart, patch.data(), patch.size());

std::memcpy((void*)funcAddress, relocated, sizeof(relocated));
std::memcpy((void*)(funcAddress + sizeof(relocated)), func, sizeof(func));
std::memcpy((void*)funcAddress, relocated.data(), relocated.size());
std::memcpy((void*)(funcAddress + relocated.size()), func, sizeof(func));

VirtualProtect((void*)hookStart, sizeof(relocated), originalProt, &originalProt);
VirtualProtect((void*)hookStart, relocated.size(), originalProt, &originalProt);
}

DWORD WINAPI entry(LPVOID lpParameter) {
Expand All @@ -337,28 +351,35 @@ DWORD WINAPI entry(LPVOID lpParameter) {
moduleName.remove_prefix(pos + 1);
}

if (moduleName != "KINGDOM HEARTS II FINAL MIX.exe") return 0;
auto entry = gameInfos.find(moduleName);
if (entry != gameInfos.end()) {
gameInfo = entry->second;
} else {
return 0;
}

AllocConsole();
std::freopen("CONOUT$", "w", stdout);

uint64_t moduleAddress = (uint64_t)GetModuleHandleA(nullptr);
uint64_t baseAddress = moduleAddress + 0x56450E;
uint64_t baseAddress = moduleAddress + gameInfo->baseAddress;
char scriptsPath[MAX_PATH];
SHGetFolderPathA(0, CSIDL_MYDOCUMENTS, nullptr, 0, scriptsPath);
std::strcat(scriptsPath, "\\KINGDOM HEARTS HD 1.5+2.5 ReMIX\\scripts");

fs::path gameScriptsPath = fs::path{scriptsPath} / gameInfo->scriptsPath;

luaThread = std::thread(LuaThread);
luaThread.detach();

if (std::filesystem::exists(scriptsPath)) {
if (EntryLUA(GetCurrentProcessId(), GetCurrentProcess(), baseAddress, scriptsPath) == 0) {
if (fs::exists(gameScriptsPath)) {
if (EntryLUA(GetCurrentProcessId(), GetCurrentProcess(), baseAddress, gameScriptsPath.u8string().c_str()) == 0) {
hookGame(moduleAddress);
} else {
std::cout << "Failed to initialize internal LuaBackend!" << std::endl;
}
} else {
std::cout << "Scripts directory does not exist! Expected at: " << scriptsPath << std::endl;
std::cout << "Scripts directory does not exist! Expected at: " << gameScriptsPath << std::endl;
}

return 0;
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ loop effectively eliminating these issues. However, scripts that rely on new fea
are not supported and it is recommended to use LuaFrontend concurrently with LuaBackend Hook to achieve this.

## Support
For the time being, only supports the Global version of KINGDOM HEARTS II FINAL MIX on PC.
For the time being, only supports the PC Global versions of:
* Kingdom Hearts Final Mix
* Kingdom Hearts II Final Mix

Installation instructions are in [INSTALL.md](INSTALL.md).

Expand Down

0 comments on commit bdae7f5

Please sign in to comment.