gkms-localify-dmm/src/main.cpp

167 lines
4.1 KiB
C++

#include <stdinclude.hpp>
#include <minizip/unzip.h>
#include <TlHelp32.h>
#include <unordered_set>
#include <charconv>
#include <cassert>
#include <format>
#include <cpprest/uri.h>
#include <cpprest/http_listener.h>
#include <ranges>
#include <windows.h>
#include "windowsPlatform.hpp"
extern void start_console();
const auto CONSOLE_TITLE = L"Gakumas Localify";
std::filesystem::path gakumasLocalPath = "./gakumas-local";
std::filesystem::path ProgramConfigJson = gakumasLocalPath / "config.json";
std::filesystem::path ConfigJson = gakumasLocalPath / "localizationConfig.json";
bool g_has_config_file = false;
bool g_enable_console = true;
bool g_useRemoteAssets = false;
bool g_useAPIAssets = false;
std::string g_remoteResourceUrl = "";
std::string g_useAPIAssetsURL = "";
namespace
{
void create_debug_console()
{
AllocConsole();
// open stdout stream
auto _ = freopen("CONOUT$", "w+t", stdout);
_ = freopen("CONOUT$", "w", stderr);
_ = freopen("CONIN$", "r", stdin);
SetConsoleTitleW(CONSOLE_TITLE);
// set this to avoid turn japanese texts into question mark
SetConsoleOutputCP(65001);
std::locale::global(std::locale(""));
wprintf(L"%ls Loaded! - By chinosk\n", CONSOLE_TITLE);
}
}
void readProgramConfig() {
std::vector<std::string> dicts{};
std::ifstream config_stream{ ProgramConfigJson };
if (!config_stream.is_open())
return;
rapidjson::IStreamWrapper wrapper{ config_stream };
rapidjson::Document document;
document.ParseStream(wrapper);
if (!document.HasParseError())
{
g_has_config_file = true;
if (document.HasMember("enableConsole")) {
g_enable_console = document["enableConsole"].GetBool();
}
if (document.HasMember("useRemoteAssets")) {
g_useRemoteAssets = document["useRemoteAssets"].GetBool();
}
if (document.HasMember("transRemoteZipUrl")) {
g_remoteResourceUrl = document["transRemoteZipUrl"].GetString();
}
if (document.HasMember("useAPIAssets")) {
g_useAPIAssets = document["useAPIAssets"].GetBool();
}
if (document.HasMember("useAPIAssetsURL")) {
g_useAPIAssetsURL = document["useAPIAssetsURL"].GetString();
}
}
config_stream.close();
}
LONG WINAPI AddressExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) {
// Check if the exception is an access violation
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
// Check if the violation address is above 0x7FFFFFFFFFFF
if (ExceptionInfo->ExceptionRecord->ExceptionAddress > (PVOID)0x7FFFFFFFFFFF) {
// Return EXCEPTION_CONTINUE_EXECUTION to ignore the exception and continue
return EXCEPTION_CONTINUE_EXECUTION;
}
}
// For other exceptions or addresses, use the default exception handler
return EXCEPTION_CONTINUE_SEARCH;
}
int __stdcall DllMain(HINSTANCE dllModule, DWORD reason, LPVOID)
{
if (reason == DLL_PROCESS_ATTACH)
{
AddVectoredExceptionHandler(1, AddressExceptionHandler);
// the DMM Launcher set start path to system32 wtf????
std::string module_name;
module_name.resize(MAX_PATH);
module_name.resize(GetModuleFileName(nullptr, module_name.data(), MAX_PATH));
std::filesystem::path module_path(module_name);
// check name
if (module_path.filename() != "gakumas.exe")
return 1;
std::filesystem::current_path(
module_path.parent_path()
);
readProgramConfig();
if (g_enable_console)
create_debug_console();
std::thread init_thread([] {
if (g_enable_console)
{
start_console();
printf("Command: %s\n", GetCommandLineA());
}
loadConfig(ConfigJson);
initHook();
std::mutex mutex;
std::condition_variable cond;
std::atomic<bool> hookIsReady(false);
// 依赖检查游戏版本的指针加载,因此在 hook 完成后再加载翻译数据
std::unique_lock lock(mutex);
cond.wait(lock, [&] {
return hookIsReady.load(std::memory_order_acquire);
});
if (g_enable_console)
{
auto _ = freopen("CONOUT$", "w+t", stdout);
_ = freopen("CONOUT$", "w", stderr);
_ = freopen("CONIN$", "r", stdin);
}
});
init_thread.detach();
}
else if (reason == DLL_PROCESS_DETACH)
{
RemoveVectoredExceptionHandler(AddressExceptionHandler);
unInitHook();
}
return 1;
}