forked from chinosk/gkms-localify-dmm
348 lines
11 KiB
C++
348 lines
11 KiB
C++
#include "windowsPlatform.hpp"
|
||
#include "GakumasLocalify/Plugin.h"
|
||
#include "GakumasLocalify/Log.h"
|
||
#include "GakumasLocalify/Local.h"
|
||
#include "GakumasLocalify/MasterLocal.h"
|
||
#include "GakumasLocalify/camera/camera.hpp"
|
||
#include "GakumasLocalify/config/Config.hpp"
|
||
#include "GakumasLocalify/Il2cppUtils.hpp"
|
||
#include "gkmsGUI/gkmsGUIMain.hpp"
|
||
#include "gkmsGUI/GUII18n.hpp"
|
||
#include "resourceUpdate/resourceUpdate.hpp"
|
||
|
||
#include <stdinclude.hpp>
|
||
#include "deps/UnityResolve/UnityResolve.hpp"
|
||
#include <cpprest/details/basic_types.h>
|
||
#include <cpprest/details/http_helpers.h>
|
||
|
||
bool mh_inited;
|
||
extern std::filesystem::path gakumasLocalPath;
|
||
extern std::filesystem::path ConfigJson;
|
||
extern std::filesystem::path ProgramConfigJson;
|
||
int hotk = 'u';
|
||
|
||
void reload_all_data();
|
||
|
||
std::function<void()> g_on_close;
|
||
std::function<void()> on_hotKey_0;
|
||
std::function<void()> g_reload_all_data = reload_all_data;
|
||
|
||
void patchGameAssenbly();
|
||
void readProgramConfig();
|
||
|
||
namespace
|
||
{
|
||
class AndroidHookInstaller : public GakumasLocal::HookInstaller
|
||
{
|
||
public:
|
||
explicit AndroidHookInstaller(const std::string& il2cppLibraryPath, const std::string& localizationFilesDir)
|
||
{
|
||
this->m_Il2CppLibrary = GetModuleHandle("GameAssembly.dll");
|
||
this->m_il2cppLibraryPath = il2cppLibraryPath;
|
||
this->localizationFilesDir = localizationFilesDir;
|
||
}
|
||
|
||
~AndroidHookInstaller() override {
|
||
if (!mh_inited) return;
|
||
MH_DisableHook(MH_ALL_HOOKS);
|
||
MH_Uninitialize();
|
||
}
|
||
|
||
void* InstallHook(void* addr, void* hook, void** orig) override
|
||
{
|
||
auto createStat = MH_CreateHook(addr, hook, orig);
|
||
MH_EnableHook(addr);
|
||
return reinterpret_cast<void*>(createStat);
|
||
}
|
||
|
||
GakumasLocal::OpaqueFunctionPointer LookupSymbol(const char* name) override
|
||
{
|
||
return reinterpret_cast<GakumasLocal::OpaqueFunctionPointer>(GetProcAddress(reinterpret_cast<HMODULE>(m_Il2CppLibrary), name));
|
||
}
|
||
|
||
private:
|
||
void* m_Il2CppLibrary;
|
||
};
|
||
}
|
||
|
||
void* load_library_w_orig;
|
||
HMODULE __stdcall load_library_w_hook(const wchar_t* path)
|
||
{
|
||
// GakumasLocal::Log::DebugFmt("LoadLibrary %s", utility::conversions::to_utf8string(path).c_str());
|
||
|
||
using namespace std;
|
||
if (path == L"VuplexWebViewWindows.dll"sv) {
|
||
// if (path == L"cri_ware_unity.dll"sv) {
|
||
// if (path == L"NVUnityPlugin"sv) {
|
||
patchGameAssenbly();
|
||
}
|
||
return reinterpret_cast<decltype(LoadLibraryW)*>(load_library_w_orig)(path);
|
||
}
|
||
|
||
void patchGameAssenbly() {
|
||
static bool patched = false;
|
||
if (patched) return;
|
||
patched = true;
|
||
|
||
auto& plugin = GakumasLocal::Plugin::GetInstance();
|
||
plugin.InstallHook(std::make_unique<AndroidHookInstaller>("GameAssembly.dll", gakumasLocalPath.string()));
|
||
}
|
||
|
||
void unInitHook() {
|
||
if (!mh_inited) return;
|
||
MH_DisableHook(MH_ALL_HOOKS);
|
||
MH_Uninitialize();
|
||
}
|
||
|
||
void initHook() {
|
||
mh_inited = true;
|
||
|
||
if (MH_Initialize() != MH_OK)
|
||
return;
|
||
|
||
auto stat1 = MH_CreateHook(LoadLibraryW, load_library_w_hook, &load_library_w_orig);
|
||
auto stat2 = MH_EnableHook(LoadLibraryW);
|
||
|
||
g_on_close = []() {
|
||
unInitHook();
|
||
TerminateProcess(GetCurrentProcess(), 0);
|
||
};
|
||
|
||
static bool guiStarting = false;
|
||
on_hotKey_0 = []() {
|
||
if (guiStarting) return;
|
||
guiStarting = true;
|
||
std::thread([]() {
|
||
printf("GUI START\n");
|
||
guimain();
|
||
guiStarting = false;
|
||
printf("GUI END\n");
|
||
}).detach();
|
||
};
|
||
|
||
GakumasLocal::Log::InfoFmt("initHook stat: %s - %s\n", MH_StatusToString(stat1), MH_StatusToString(stat2));
|
||
}
|
||
|
||
void checkAndInitConfig(const std::filesystem::path& LocalConfigFile) {
|
||
if (!std::filesystem::exists(ProgramConfigJson)) {
|
||
g_useAPIAssetsURL = GkmsGUII18n::ts("default_assets_check_api");
|
||
GkmsResourceUpdate::saveProgramConfig();
|
||
}
|
||
if (!std::filesystem::exists(LocalConfigFile)) {
|
||
GakumasLocal::Config::SaveConfig(LocalConfigFile.string());
|
||
}
|
||
}
|
||
|
||
|
||
void loadConfig(const std::string& configJson) {
|
||
GakumasLocal::Config::LoadConfig(configJson);
|
||
}
|
||
|
||
void loadConfig(const std::filesystem::path& filePath) {
|
||
checkAndInitConfig(filePath);
|
||
|
||
std::ifstream file(filePath);
|
||
if (!file.is_open()) {
|
||
GakumasLocal::Log::ErrorFmt("Load config %s failed.\n", filePath.string().c_str());
|
||
loadConfig(std::string("{}"));
|
||
return;
|
||
}
|
||
std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||
file.close();
|
||
|
||
loadConfig(fileContent);
|
||
}
|
||
|
||
void reload_all_data() {
|
||
readProgramConfig();
|
||
loadConfig(ConfigJson);
|
||
GkmsResourceUpdate::GetCurrentResourceVersion(false);
|
||
GakumasLocal::Local::LoadData();
|
||
GakumasLocal::MasterLocal::LoadData();
|
||
}
|
||
|
||
bool getCurrentLodingProgress(int* stepTotal, int* stepCurrent, int* currTotal, int* currCurrent) {
|
||
*stepTotal = UnityResolveProgress::assembliesProgress.total;
|
||
*stepCurrent = UnityResolveProgress::assembliesProgress.current;
|
||
*currTotal = UnityResolveProgress::classProgress.total;
|
||
*currCurrent = UnityResolveProgress::classProgress.current;
|
||
|
||
return UnityResolveProgress::startInit;
|
||
}
|
||
|
||
void checkDBGKey(int action, int key_code) {
|
||
if (action != WM_KEYDOWN) return;
|
||
static const std::vector<int> targetDbgKeyList = { 38, 38, 40, 40, 37, 39, 37, 39, 66, 65};
|
||
static int currentIndex = 0;
|
||
if (targetDbgKeyList[currentIndex] == key_code) {
|
||
if (currentIndex == targetDbgKeyList.size() - 1) {
|
||
currentIndex = 0;
|
||
GakumasLocal::Config::dbgMode = !GakumasLocal::Config::dbgMode;
|
||
GakumasLocal::Config::SaveConfig(ConfigJson.string());
|
||
GakumasLocal::Log::InfoFmt("Debug Mode: %d", GakumasLocal::Config::dbgMode);
|
||
}
|
||
else {
|
||
currentIndex++;
|
||
}
|
||
}
|
||
else {
|
||
currentIndex = 0;
|
||
}
|
||
}
|
||
|
||
void keyboardEvents(int action, int key_code) {
|
||
// GakumasLocal::Log::DebugFmt("keyboardEvents: %d - %d", action, key_code);
|
||
checkDBGKey(action, key_code);
|
||
GKCamera::on_cam_rawinput_keyboard(action, key_code);
|
||
const auto msg = GakumasLocal::Local::OnKeyDown(action, key_code);
|
||
if (!msg.empty()) {
|
||
GakumasLocal::Log::Info(msg.c_str());
|
||
}
|
||
}
|
||
|
||
namespace GakumasLocal::WinHooks {
|
||
using Il2cppString = UnityResolve::UnityType::String;
|
||
|
||
void* LoadAssetBundle(const std::string& path) {
|
||
Il2cppString* bundlePath = Il2cppString::New(path);
|
||
|
||
static auto LoadFromFileAsync = Il2cppUtils::GetMethod("UnityEngine.AssetBundleModule.dll", "UnityEngine", "AssetBundle", "LoadFromFileAsync");
|
||
static auto get_assetBundle = Il2cppUtils::GetMethod("UnityEngine.AssetBundleModule.dll", "UnityEngine", "AssetBundleCreateRequest", "get_assetBundle");
|
||
|
||
auto bundleTask = LoadFromFileAsync->Invoke<void*>(bundlePath);
|
||
|
||
if (!bundleTask) {
|
||
return nullptr;
|
||
}
|
||
return get_assetBundle->Invoke<void*>(bundleTask);
|
||
}
|
||
|
||
namespace Keyboard {
|
||
std::function<void(int, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD)> mKeyBoardCallBack = nullptr;
|
||
|
||
WNDPROC g_pfnOldWndProc = NULL;
|
||
LRESULT CALLBACK WndProcCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||
DWORD SHIFT_key = 0;
|
||
DWORD CTRL_key = 0;
|
||
DWORD ALT_key = 0;
|
||
DWORD SPACE_key = 0;
|
||
DWORD UP_key = 0;
|
||
DWORD DOWN_key = 0;
|
||
DWORD LEFT_key = 0;
|
||
DWORD RIGHT_key = 0;
|
||
|
||
switch (uMsg) {
|
||
case WM_INPUT: {
|
||
RAWINPUT rawInput;
|
||
UINT size = sizeof(RAWINPUT);
|
||
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &rawInput, &size, sizeof(RAWINPUTHEADER)) == size) {
|
||
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if (rawInput.header.dwType == RIM_TYPEMOUSE)
|
||
{
|
||
switch (rawInput.data.mouse.ulButtons) {
|
||
case 0: { // move
|
||
SCCamera::mouseMove(rawInput.data.mouse.lLastX, rawInput.data.mouse.lLastY, 3);
|
||
}; break;
|
||
case 4: { // press
|
||
SCCamera::mouseMove(0, 0, 1);
|
||
}; break;
|
||
case 8: { // release
|
||
SCCamera::mouseMove(0, 0, 2);
|
||
}; break;
|
||
default: break;
|
||
}
|
||
|
||
if (rawInput.data.mouse.usButtonFlags == RI_MOUSE_WHEEL) {
|
||
if (rawInput.data.mouse.usButtonData == 120) {
|
||
SCCamera::mouseMove(0, 1, 4);
|
||
}
|
||
else {
|
||
SCCamera::mouseMove(0, -1, 4);
|
||
}
|
||
}
|
||
|
||
}*/
|
||
}
|
||
}; break;
|
||
|
||
case WM_SYSKEYUP:
|
||
case WM_KEYUP: {
|
||
int key = wParam;
|
||
keyboardEvents(uMsg, key);
|
||
}; break;
|
||
|
||
case WM_SYSKEYDOWN:
|
||
case WM_KEYDOWN: {
|
||
int key = wParam;
|
||
|
||
keyboardEvents(uMsg, key);
|
||
SHIFT_key = GetAsyncKeyState(VK_SHIFT);
|
||
CTRL_key = GetAsyncKeyState(VK_CONTROL);
|
||
ALT_key = GetAsyncKeyState(VK_MENU);
|
||
SPACE_key = GetAsyncKeyState(VK_SPACE);
|
||
|
||
UP_key = GetAsyncKeyState(VK_UP);
|
||
DOWN_key = GetAsyncKeyState(VK_DOWN);
|
||
LEFT_key = GetAsyncKeyState(VK_LEFT);
|
||
RIGHT_key = GetAsyncKeyState(VK_RIGHT);
|
||
|
||
if (mKeyBoardCallBack != nullptr) {
|
||
mKeyBoardCallBack(key, SHIFT_key, CTRL_key, ALT_key, SPACE_key, UP_key, DOWN_key, LEFT_key, RIGHT_key);
|
||
}
|
||
|
||
if (key >= 'A' && key <= 'Z')
|
||
{
|
||
|
||
if (GetAsyncKeyState(VK_SHIFT) >= 0) key += 32;
|
||
|
||
if (CTRL_key != 0 && key == hotk)
|
||
{
|
||
// fopenExternalPlugin(tlgport);
|
||
printf("hotKey pressed.\n");
|
||
if (on_hotKey_0) on_hotKey_0();
|
||
}
|
||
|
||
SHIFT_key = 0;
|
||
CTRL_key = 0;
|
||
ALT_key = 0;
|
||
SPACE_key = 0;
|
||
DWORD UP_key = 0;
|
||
DWORD DOWN_key = 0;
|
||
DWORD LEFT_key = 0;
|
||
DWORD RIGHT_key = 0;
|
||
}
|
||
}; break;
|
||
case WM_NCACTIVATE: {
|
||
if (!wParam) {
|
||
// SCCamera::onKillFocus();
|
||
return FALSE;
|
||
}
|
||
}; break;
|
||
case WM_KILLFOCUS: {
|
||
// SCCamera::onKillFocus();
|
||
return FALSE;
|
||
}; break;
|
||
case WM_CLOSE: {
|
||
if (g_on_close) g_on_close();
|
||
}; break;
|
||
default: break;
|
||
}
|
||
|
||
return CallWindowProc(g_pfnOldWndProc, hWnd, uMsg, wParam, lParam);
|
||
}
|
||
|
||
void InstallWndProcHook() {
|
||
g_pfnOldWndProc = (WNDPROC)GetWindowLongPtr(FindWindowW(L"UnityWndClass", L"gakumas"), GWLP_WNDPROC);
|
||
SetWindowLongPtr(FindWindowW(L"UnityWndClass", L"gakumas"), GWLP_WNDPROC, (LONG_PTR)WndProcCallback);
|
||
}
|
||
|
||
void UninstallWndProcHook(HWND hWnd)
|
||
{
|
||
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)g_pfnOldWndProc);
|
||
}
|
||
|
||
}
|
||
|
||
}
|