From 163835bec9dab153c38fb434bfa125ed97bdc6bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=81=8D=E5=85=AE=E6=83=9A=E5=85=AE?= <101191390+HIllya51@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:53:59 +0800 Subject: [PATCH] some --- CMakeLists.txt | 2 +- LunaHook/CMakeLists.txt | 2 +- LunaHook/engine64/5pb.cpp | 49 +- LunaHook/engine64/5pb.h | 18 +- LunaHook/engine64/AGES7.cpp | 141 +- LunaHook/engine64/AGES7.h | 15 +- LunaHook/engine64/Artemis.cpp | 4 +- LunaHook/engine64/Artemis.h | 16 +- LunaHook/engine64/CMVS.cpp | 111 +- LunaHook/engine64/CMVS.h | 29 +- LunaHook/engine64/Godot.cpp | 64 +- LunaHook/engine64/Godot.h | 18 +- LunaHook/engine64/Kincaid.cpp | 68 +- LunaHook/engine64/Kincaid.h | 18 +- LunaHook/engine64/KiriKiri.cpp | 124 +- LunaHook/engine64/KiriKiri.h | 24 +- LunaHook/engine64/LightVN.h | 21 +- LunaHook/engine64/PPSSPP.cpp | 4 +- LunaHook/engine64/PPSSPP.h | 20 +- LunaHook/engine64/Ryujinx.cpp | 2 + LunaHook/engine64/Suika2.cpp | 35 +- LunaHook/engine64/Suika2.h | 16 +- LunaHook/engine64/TYPEMOON.cpp | 50 +- LunaHook/engine64/TYPEMOON.h | 21 +- LunaHook/engine64/V8.cpp | 16 +- LunaHook/engine64/V8.h | 18 +- LunaHook/engine64/YOX.cpp | 17 +- LunaHook/engine64/YOX.h | 21 +- LunaHook/engine64/livecaptions.cpp | 81 +- LunaHook/engine64/livecaptions.h | 2 +- LunaHook/engine64/lucasystem.h | 21 +- LunaHook/engine64/mono.cpp | 126 +- LunaHook/engine64/mono.h | 14 +- LunaHook/engine64/pchooks.cpp | 20 +- LunaHook/engine64/pchooks.h | 18 +- LunaHook/engine64/rpcs3.cpp | 251 +- LunaHook/engine64/rpcs3.h | 21 +- LunaHook/engine64/vita3k.cpp | 849 ++++--- LunaHook/engine64/vita3k.h | 21 +- LunaHook/engine64/yuzu.cpp | 2904 ++++++++++++++++++++++ LunaHook/engine64/yuzu.h | 17 + LunaHook/engine64/yuzusuyu.cpp | 2236 ----------------- LunaHook/engine64/yuzusuyu.h | 16 - LunaHook/enginecollection64.cpp | 4 +- LunaHook/engines/ppsspp/specialgames.hpp | 650 ++--- LunaHook/hookfinder.cc | 3 +- LunaHook/main.cc | 9 + LunaHook/main.h | 3 +- LunaHook/texthook.cc | 8 +- LunaHost/GUI/LunaHost.cpp | 12 +- LunaHost/GUI/LunaHost.h | 1 + LunaHost/GUI/pluginmanager.cpp | 2 +- LunaHost/GUI/pluginmanager.h | 2 +- LunaHost/LunaHostCLI.cpp | 91 +- LunaHost/LunaHostDll.cpp | 6 +- LunaHost/host.cpp | 273 +- LunaHost/host.h | 25 +- LunaHost/textthread.cpp | 55 +- LunaHost/textthread.h | 14 +- include/const.h | 3 +- include/types.h | 6 + 61 files changed, 4928 insertions(+), 3780 deletions(-) create mode 100644 LunaHook/engine64/yuzu.cpp create mode 100644 LunaHook/engine64/yuzu.h delete mode 100644 LunaHook/engine64/yuzusuyu.cpp delete mode 100644 LunaHook/engine64/yuzusuyu.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c99890..aad0a4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/version) include(generate_product_version) set(VERSION_MAJOR 3) -set(VERSION_MINOR 13) +set(VERSION_MINOR 14) set(VERSION_PATCH 0) set(VERSION_REVISION 0) diff --git a/LunaHook/CMakeLists.txt b/LunaHook/CMakeLists.txt index 39c72db..47554ac 100644 --- a/LunaHook/CMakeLists.txt +++ b/LunaHook/CMakeLists.txt @@ -1,6 +1,6 @@ include_directories(. util engines) if(${CMAKE_SIZEOF_VOID_P} EQUAL 8) - set(enginessrc MKXPZ Ryujinx livecaptions Kincaid vita3k rpcs3 yuzusuyu TYPEMOON ENTERGRAM AGES7 mono Godot 5pb lucasystem LightVN V8 pchooks Artemis KiriKiri YOX PPSSPP CMVS Suika2 ) + set(enginessrc MKXPZ Ryujinx livecaptions Kincaid vita3k rpcs3 yuzu TYPEMOON ENTERGRAM AGES7 mono Godot 5pb lucasystem LightVN V8 pchooks Artemis KiriKiri YOX PPSSPP CMVS Suika2 ) set(enginepath "engine64") set(collector "enginecollection64.cpp") else() diff --git a/LunaHook/engine64/5pb.cpp b/LunaHook/engine64/5pb.cpp index 270ba06..af69da3 100644 --- a/LunaHook/engine64/5pb.cpp +++ b/LunaHook/engine64/5pb.cpp @@ -1,29 +1,34 @@ -#include"5pb.h" -#include"mages/mages.h" -namespace{ - //https://vndb.org/v46553 - //新宿葬命 - bool _strncat(){ +#include "5pb.h" +#include "mages/mages.h" +namespace +{ + // https://vndb.org/v46553 + // 新宿葬命 + bool _strncat() + { HookParam hp; - hp.address=(uintptr_t)GetProcAddress(GetModuleHandleA("ucrtbase.dll"),"strncat"); - hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT; - hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - *data=stack->ARG2; - *len=stack->ARG3; - *split=stack->ARG1; + hp.address = (uintptr_t)GetProcAddress(GetModuleHandleA("ucrtbase.dll"), "strncat"); + hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; + hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + *data = stack->ARG2; + *len = stack->ARG3; + *split = stack->ARG1; }; - hp.filter_fun=[](void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - strReplace(s,"%N","\n"); - //sub_140096E80 + hp.filter_fun = [](void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + strReplace(s, "%N", "\n"); + // sub_140096E80 //%I %B %C %R( %Z %% - return write_string_overwrite(data,len,s); + return write_string_overwrite(data, len, s); }; - return NewHook(hp,"strncat"); + return NewHook(hp, "strncat"); } } -bool _5pb::attach_function() { - //CHAOS;HEAD_NOAH - bool b3=hookmages::MAGES(); - return b3||_strncat(); +bool _5pb::attach_function() +{ + // CHAOS;HEAD_NOAH + bool b3 = hookmages::MAGES(); + return b3 || _strncat(); } \ No newline at end of file diff --git a/LunaHook/engine64/5pb.h b/LunaHook/engine64/5pb.h index 0d16dff..ad52fca 100644 --- a/LunaHook/engine64/5pb.h +++ b/LunaHook/engine64/5pb.h @@ -1,13 +1,13 @@ -class _5pb:public ENGINE{ - public: - _5pb(){ - is_engine_certain=false; - check_by=CHECK_BY::FILE_ANY; - check_by_target=check_by_list{ L"data\\*.cpk",L"*.cpk"}; - +class _5pb : public ENGINE +{ +public: + _5pb() + { + is_engine_certain = false; + check_by = CHECK_BY::FILE_ANY; + check_by_target = check_by_list{L"data\\*.cpk", L"*.cpk"}; }; - bool attach_function(); + bool attach_function(); }; - \ No newline at end of file diff --git a/LunaHook/engine64/AGES7.cpp b/LunaHook/engine64/AGES7.cpp index abea848..eca59b0 100644 --- a/LunaHook/engine64/AGES7.cpp +++ b/LunaHook/engine64/AGES7.cpp @@ -1,80 +1,97 @@ -#include"AGES7.h" -namespace{ - //Muv-Luv Alternative - Total Eclipse - //https://vndb.org/v7052 - bool _1(){ - //HSN65001#-44@234699:te-win64vc14-release.exe - BYTE b1[]={ - 0x48,XX2,0xb0,0xfe,0xff,0xff, - 0x4c,XX2,0xb8,0x01,0x00,0x00, +#include "AGES7.h" +namespace +{ + // Muv-Luv Alternative - Total Eclipse + // https://vndb.org/v7052 + bool _1() + { + // HSN65001#-44@234699:te-win64vc14-release.exe + BYTE b1[] = { + //clang-format off + 0x48, XX2, 0xb0, 0xfe, 0xff, 0xff, + 0x4c, XX2, 0xb8, 0x01, 0x00, 0x00, + //clang-format on }; - auto addr=MemDbg::findBytes(b1,sizeof(b1),processStartAddress,processStopAddress); - if(addr==0)return false; + auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress); + if (addr == 0) + return false; HookParam hp; - hp.address=addr; - hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT; - hp.offset=get_reg(regs::rdi); - auto succ=NewHook(hp,"Ages7_1"); - if(addr=MemDbg::findEnclosingAlignedFunction(addr)){ - hp.address=addr; - hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT; - hp.offset=get_reg(regs::rbx); - succ|=NewHook(hp,"Ages7_3"); + hp.address = addr; + hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; + hp.offset = get_reg(regs::rdi); + auto succ = NewHook(hp, "Ages7_1"); + if (addr = MemDbg::findEnclosingAlignedFunction(addr)) + { + hp.address = addr; + hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; + hp.offset = get_reg(regs::rbx); + succ |= NewHook(hp, "Ages7_3"); } return succ; } - bool _2(){ - //HSN65001#-44@2346AC:te-win64vc14-release.exe - BYTE b1[]={ - 0x48,XX2,0x10, - 0x48,XX2,0xb0,0x01,0x00,0x00, - XX2,0xc0,0x08,0x00,0x00 + bool _2() + { + // HSN65001#-44@2346AC:te-win64vc14-release.exe + BYTE b1[] = { + //clang-format off + 0x48, XX2, 0x10, + 0x48, XX2, 0xb0, 0x01, 0x00, 0x00, + XX2, 0xc0, 0x08, 0x00, 0x00 + //clang-format on }; - auto addr=MemDbg::findBytes(b1,sizeof(b1),processStartAddress,processStopAddress); - if(addr==0)return false; + auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress); + if (addr == 0) + return false; HookParam hp; - hp.address=addr; - hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT; - hp.offset=get_reg(regs::rdi); - auto suc=NewHook(hp,"Ages7_2"); - if(addr=MemDbg::findEnclosingAlignedFunction(addr)){ - hp.address=addr; - hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT; - hp.offset=get_reg(regs::rbx); - suc|=NewHook(hp,"Ages7_3"); + hp.address = addr; + hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; + hp.offset = get_reg(regs::rdi); + auto suc = NewHook(hp, "Ages7_2"); + if (addr = MemDbg::findEnclosingAlignedFunction(addr)) + { + hp.address = addr; + hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; + hp.offset = get_reg(regs::rbx); + suc |= NewHook(hp, "Ages7_3"); } return suc; - } - bool _3(){ - //HSN65001#-14@3D9814:te-win64vc14-release.exe - BYTE b1[]={ - 0x48,0x8b,0x1b, - 0x48,0x8b,0x01, - 0x48,0x8b,0xd3, - 0xff,0x10, - 0x48,0x8b,0x45,0xc8, - 0x48,0x8b,0x4d,0xc0, - 0x48,0x2b,0xc1, - 0x48,0xc1,0xf8,0x03, - 0x48,0x85,0xc0, + } + bool _3() + { + // HSN65001#-14@3D9814:te-win64vc14-release.exe + BYTE b1[] = { + //clang-format off + 0x48, 0x8b, 0x1b, + 0x48, 0x8b, 0x01, + 0x48, 0x8b, 0xd3, + 0xff, 0x10, + 0x48, 0x8b, 0x45, 0xc8, + 0x48, 0x8b, 0x4d, 0xc0, + 0x48, 0x2b, 0xc1, + 0x48, 0xc1, 0xf8, 0x03, + 0x48, 0x85, 0xc0, + //clang-format on }; - auto addr=MemDbg::findBytes(b1,sizeof(b1),processStartAddress,processStopAddress); - if(addr==0)return false; + auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress); + if (addr == 0) + return false; HookParam hp; - hp.address=addr+3; - hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT; - hp.offset=get_reg(regs::rbx); - return NewHook(hp,"Ages7_4"); - } - bool all(){ - auto _=_1(); - _=_2()||_; - _=_3()||_; + hp.address = addr + 3; + hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; + hp.offset = get_reg(regs::rbx); + return NewHook(hp, "Ages7_4"); + } + bool all() + { + auto _ = _1(); + _ = _2() || _; + _ = _3() || _; return _; } } -bool AGES7::attach_function(){ +bool AGES7::attach_function() +{ return all(); } \ No newline at end of file diff --git a/LunaHook/engine64/AGES7.h b/LunaHook/engine64/AGES7.h index 8ef5d6f..41d8c64 100644 --- a/LunaHook/engine64/AGES7.h +++ b/LunaHook/engine64/AGES7.h @@ -1,12 +1,13 @@ -class AGES7:public ENGINE{ - public: - AGES7(){ - - check_by=CHECK_BY::FILE_ALL; - check_by_target=check_by_list{L"obb\\pack.bin",L"erc_nospfx.dll"}; +class AGES7 : public ENGINE +{ +public: + AGES7() + { + check_by = CHECK_BY::FILE_ALL; + check_by_target = check_by_list{L"obb\\pack.bin", L"erc_nospfx.dll"}; }; - bool attach_function(); + bool attach_function(); }; \ No newline at end of file diff --git a/LunaHook/engine64/Artemis.cpp b/LunaHook/engine64/Artemis.cpp index 3011274..e5fd94b 100644 --- a/LunaHook/engine64/Artemis.cpp +++ b/LunaHook/engine64/Artemis.cpp @@ -54,8 +54,8 @@ bool Artemis64() bool Artemis64x() { - //https://vndb.org/v50832 - //きら☆かの 体验版 + // https://vndb.org/v50832 + // きら☆かの 体验版 /* __int64 __fastcall sub_1401B13F0(__int64 a1, unsigned __int64 a2, char **a3) diff --git a/LunaHook/engine64/Artemis.h b/LunaHook/engine64/Artemis.h index 9100516..95d97d2 100644 --- a/LunaHook/engine64/Artemis.h +++ b/LunaHook/engine64/Artemis.h @@ -1,11 +1,13 @@ -class Artemis:public ENGINE{ - public: - Artemis(){ - - check_by=CHECK_BY::FILE; - check_by_target=L"*.pfs"; +class Artemis : public ENGINE +{ +public: + Artemis() + { + + check_by = CHECK_BY::FILE; + check_by_target = L"*.pfs"; }; - bool attach_function(); + bool attach_function(); }; \ No newline at end of file diff --git a/LunaHook/engine64/CMVS.cpp b/LunaHook/engine64/CMVS.cpp index 2109fba..5e92004 100644 --- a/LunaHook/engine64/CMVS.cpp +++ b/LunaHook/engine64/CMVS.cpp @@ -1,57 +1,68 @@ -#include"CMVS.h" - namespace{ -bool EMbed(){ - //有多个,但是只有最后一个是有效的 - const uint8_t bytes[] = { - 0xB8,0x42,0x81,0x00,0x00, - 0x66,XX2,0x74,XX, - 0xB8,0x76,0x81,0x00,0x00, - 0x66,XX2,0x74,XX, - 0xB8,0x78,0x81,0x00,0x00, - 0x66,XX2,0x74,XX, - }; - bool res=false; - auto addr=processStartAddress; - - std::vectoralready; - - while(addr){ - addr = MemDbg::findBytes(bytes,sizeof(bytes),addr+1,processStopAddress); - if(addr==0)continue; +#include "CMVS.h" +namespace +{ + bool EMbed() + { + // 有多个,但是只有最后一个是有效的 + const uint8_t bytes[] = { + //clang-format off + 0xB8, 0x42, 0x81, 0x00, 0x00, + 0x66, XX2, 0x74, XX, + 0xB8, 0x76, 0x81, 0x00, 0x00, + 0x66, XX2, 0x74, XX, + 0xB8, 0x78, 0x81, 0x00, 0x00, + 0x66, XX2, 0x74, XX, + //clang-format on + }; + bool res = false; + auto addr = processStartAddress; + + std::vector already; + + while (addr) + { + addr = MemDbg::findBytes(bytes, sizeof(bytes), addr + 1, processStopAddress); + if (addr == 0) + continue; auto f = MemDbg::findEnclosingAlignedFunction(addr); - if(f==0)continue; - if(std::find(already.begin(),already.end(),f)!=already.end())continue; + if (f == 0) + continue; + if (std::find(already.begin(), already.end(), f) != already.end()) + continue; already.push_back(f); - + } + if (already.size()) + { + HookParam hp; + hp.address = already.back(); + hp.offset = get_reg(regs::rdx); + + hp.type = EMBED_ABLE | USING_STRING | EMBED_BEFORE_SIMPLE | EMBED_AFTER_NEW | EMBED_DYNA_SJIS; + hp.hook_font = F_GetGlyphOutlineA; + res |= NewHook(hp, "EmbedCMVS"); + } + return res; } - if(already.size()){ + + bool CMVSh() + { + + DWORD align = 0xCCCCCCCC; + auto addr = MemDbg::findCallerAddress((uintptr_t)::GetGlyphOutlineA, align, processStartAddress, processStopAddress); + if (!addr) + return false; + HookParam hp; - hp.address = already.back() ; - hp.offset=get_reg(regs::rdx); - - hp.type=EMBED_ABLE|USING_STRING|EMBED_BEFORE_SIMPLE|EMBED_AFTER_NEW|EMBED_DYNA_SJIS; - hp.hook_font=F_GetGlyphOutlineA; - res|=NewHook(hp, "EmbedCMVS"); + hp.address = addr + 4; + hp.offset = get_reg(regs::r8); + hp.type = CODEC_ANSI_BE; + + return NewHook(hp, "CMVS"); } - return res; } - -bool CMVSh() { - - DWORD align = 0xCCCCCCCC; - auto addr = MemDbg::findCallerAddress((uintptr_t)::GetGlyphOutlineA, align, processStartAddress, processStopAddress); - if (!addr) return false; - - HookParam hp; - hp.address = addr+4; - hp.offset=get_reg(regs::r8); - hp.type = CODEC_ANSI_BE; - - return NewHook(hp, "CMVS"); -} -} -bool CMVS::attach_function(){ - bool b1=CMVSh(); - bool b2=EMbed(); - return b1||b2; +bool CMVS::attach_function() +{ + bool b1 = CMVSh(); + bool b2 = EMbed(); + return b1 || b2; } \ No newline at end of file diff --git a/LunaHook/engine64/CMVS.h b/LunaHook/engine64/CMVS.h index 9d4b3c0..65fca6a 100644 --- a/LunaHook/engine64/CMVS.h +++ b/LunaHook/engine64/CMVS.h @@ -1,18 +1,19 @@ -class CMVS:public ENGINE{ - public: - CMVS(){ - - check_by=CHECK_BY::FILE; - check_by_target=L"data\\pack\\*.cpz"; +class CMVS : public ENGINE +{ +public: + CMVS() + { - - // jichi 8/19/2013: DO NOT WORK for games like「ハピメア」 - //if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) { - // InsertCMVSHook(); - // return true; - //} - }; - bool attach_function(); + check_by = CHECK_BY::FILE; + check_by_target = L"data\\pack\\*.cpz"; + + // jichi 8/19/2013: DO NOT WORK for games like「ハピメア」 + // if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) { + // InsertCMVSHook(); + // return true; + //} + }; + bool attach_function(); }; \ No newline at end of file diff --git a/LunaHook/engine64/Godot.cpp b/LunaHook/engine64/Godot.cpp index d42b9ab..385567c 100644 --- a/LunaHook/engine64/Godot.cpp +++ b/LunaHook/engine64/Godot.cpp @@ -1,26 +1,29 @@ -#include"Godot.h" +#include "Godot.h" -bool InsertGodotHook_X64() { - const BYTE bytes[] = { 0x8B,0x40,0xFC,0x83,0xF8,0x01,0x83,0xD0,0xFF,0x41,0x39,0xC6 }; +bool InsertGodotHook_X64() +{ + const BYTE bytes[] = {0x8B, 0x40, 0xFC, 0x83, 0xF8, 0x01, 0x83, 0xD0, 0xFF, 0x41, 0x39, 0xC6}; ULONG64 range = min(processStopAddress - processStartAddress, MAX_REL_ADDR); - for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) { + for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) + { HookParam myhp; myhp.address = addr; myhp.type = USING_STRING | CODEC_UTF16 | NO_CONTEXT; // /HQ 不使用上下文区分 把所有线程的文本都提取 - //myhp.padding = 0xc;//[esp+4]+padding - // data_offset - myhp.offset=get_reg(regs::rax); - myhp.text_fun = [](hook_stack* stack, HookParam *hp, uintptr_t* data, uintptr_t* split, size_t* count) + // myhp.padding = 0xc;//[esp+4]+padding + // data_offset + myhp.offset = get_reg(regs::rax); + myhp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *count) { - *data=(stack->rax); - int len = *(int*)(*data - 4); - if(len!=wcslen((wchar_t*)*data))return; - *count=len*2; + *data = (stack->rax); + int len = *(int *)(*data - 4); + if (len != wcslen((wchar_t *)*data)) + return; + *count = len * 2; }; char nameForUser[HOOK_NAME_SIZE] = "RichTextLabel_add_text"; - + ConsoleOutput("Insert: Godot_add_text_X64 Hook "); return NewHook(myhp, nameForUser); } @@ -28,27 +31,29 @@ bool InsertGodotHook_X64() { ConsoleOutput("Godot_x64: pattern not found"); return false; } -bool InsertGodotHook2_X64() { - +bool InsertGodotHook2_X64() +{ + /* - * Sample games: - * https://vndb.org/r109138 - */ + * Sample games: + * https://vndb.org/r109138 + */ const BYTE bytes[] = { - 0x48, 0x8B, 0x94, 0x24, XX4, // mov rdx,[rsp+000001C0] <- hook here - 0x4C, 0x89, 0xE1, // mov rcx,r12 - 0xE8, XX4, // call NULL-Windows.exe+D150 - 0x49, 0x8B, 0x06, // mov rax,[r14] - 0x48, 0x85, 0xC0, // test rax,rax - 0x0F, 0x85, XX4 // jne NULL-Windows.exe+A359D4 + 0x48, 0x8B, 0x94, 0x24, XX4, // mov rdx,[rsp+000001C0] <- hook here + 0x4C, 0x89, 0xE1, // mov rcx,r12 + 0xE8, XX4, // call NULL-Windows.exe+D150 + 0x49, 0x8B, 0x06, // mov rax,[r14] + 0x48, 0x85, 0xC0, // test rax,rax + 0x0F, 0x85, XX4 // jne NULL-Windows.exe+A359D4 }; ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR); - for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) { + for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) + { HookParam hp; hp.address = addr; - hp.offset=get_reg(regs::rcx); + hp.offset = get_reg(regs::rcx); hp.type = USING_STRING | CODEC_UTF16; ConsoleOutput("INSERT Godot2_x64 Hook "); return NewHook(hp, "Godot2_x64"); @@ -57,8 +62,9 @@ bool InsertGodotHook2_X64() { ConsoleOutput("Godot2_x64: pattern not found"); return false; } -bool Godot::attach_function(){ - auto _= InsertGodotHook_X64(); - _=InsertGodotHook2_X64()||_; +bool Godot::attach_function() +{ + auto _ = InsertGodotHook_X64(); + _ = InsertGodotHook2_X64() || _; return _; } \ No newline at end of file diff --git a/LunaHook/engine64/Godot.h b/LunaHook/engine64/Godot.h index 5f4c093..c86ad2a 100644 --- a/LunaHook/engine64/Godot.h +++ b/LunaHook/engine64/Godot.h @@ -1,11 +1,13 @@ -class Godot:public ENGINE{ - public: - Godot(){ - - check_by=CHECK_BY::FILE; - check_by_target=L"*.pck"; - }; - bool attach_function(); +class Godot : public ENGINE +{ +public: + Godot() + { + + check_by = CHECK_BY::FILE; + check_by_target = L"*.pck"; + }; + bool attach_function(); }; diff --git a/LunaHook/engine64/Kincaid.cpp b/LunaHook/engine64/Kincaid.cpp index 6499ade..91ce293 100644 --- a/LunaHook/engine64/Kincaid.cpp +++ b/LunaHook/engine64/Kincaid.cpp @@ -1,38 +1,42 @@ -#include"Kincaid.h" -namespace{ - bool _1(){ -// .text:0000000140230D80 mov rsi, rax -// .text:0000000140230D83 mov edx, 1 -// .text:0000000140230D88 mov rcx, rdi -// .text:0000000140230D8B call sub_1402B35B0 -// .text:0000000140230D90 lea ebx, [rax-1] -// .text:0000000140230D93 mov edx, 2 -// .text:0000000140230D98 mov rcx, rdi -// .text:0000000140230D9B call sub_1402B35B0 - BYTE b1[]={ - 0x48,0x8b,0xf0, - 0xba,0x01,0x00,0x00,0x00, - 0x48,0x8b,0xcf, - 0xe8,XX4, - 0x8d,0x58,0xff, - 0xba,0x02,0x00,0x00,0x00, - 0x48,0x8b,0xcf, - 0xe8,XX4 - }; - auto addr=MemDbg::findBytes(b1,sizeof(b1),processStartAddress,processStopAddress); - if(addr==0)return false; +#include "Kincaid.h" +namespace +{ + bool _1() + { + // .text:0000000140230D80 mov rsi, rax + // .text:0000000140230D83 mov edx, 1 + // .text:0000000140230D88 mov rcx, rdi + // .text:0000000140230D8B call sub_1402B35B0 + // .text:0000000140230D90 lea ebx, [rax-1] + // .text:0000000140230D93 mov edx, 2 + // .text:0000000140230D98 mov rcx, rdi + // .text:0000000140230D9B call sub_1402B35B0 + BYTE b1[] = { + 0x48, 0x8b, 0xf0, + 0xba, 0x01, 0x00, 0x00, 0x00, + 0x48, 0x8b, 0xcf, + 0xe8, XX4, + 0x8d, 0x58, 0xff, + 0xba, 0x02, 0x00, 0x00, 0x00, + 0x48, 0x8b, 0xcf, + 0xe8, XX4}; + auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress); + if (addr == 0) + return false; HookParam hp; - hp.address=addr; - hp.type=USING_STRING|CODEC_UTF8; - hp.offset=get_reg(regs::rax); - hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - *data=stack->rax; - if(stack->retaddr==(DWORD)-1) - *len=strlen((char*)*data); + hp.address = addr; + hp.type = USING_STRING | CODEC_UTF8; + hp.offset = get_reg(regs::rax); + hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + *data = stack->rax; + if (stack->retaddr == (DWORD)-1) + *len = strlen((char *)*data); }; - return NewHook(hp,"Kincaid"); + return NewHook(hp, "Kincaid"); } } -bool Kincaid::attach_function(){ +bool Kincaid::attach_function() +{ return _1(); } \ No newline at end of file diff --git a/LunaHook/engine64/Kincaid.h b/LunaHook/engine64/Kincaid.h index a03af25..387492c 100644 --- a/LunaHook/engine64/Kincaid.h +++ b/LunaHook/engine64/Kincaid.h @@ -26,15 +26,17 @@ // } // } -class Kincaid:public ENGINE{ - public: - Kincaid(){ - - check_by=CHECK_BY::CUSTOM; - check_by_target=[](){ - return Util::SearchResourceString(L"Cookiedraggy")|| Util::SearchResourceString(L"The Adventures of Kincaid"); - }; +class Kincaid : public ENGINE +{ +public: + Kincaid() + { + check_by = CHECK_BY::CUSTOM; + check_by_target = []() + { + return Util::SearchResourceString(L"Cookiedraggy") || Util::SearchResourceString(L"The Adventures of Kincaid"); + }; }; bool attach_function(); }; \ No newline at end of file diff --git a/LunaHook/engine64/KiriKiri.cpp b/LunaHook/engine64/KiriKiri.cpp index 546cf14..2f3cdd5 100644 --- a/LunaHook/engine64/KiriKiri.cpp +++ b/LunaHook/engine64/KiriKiri.cpp @@ -1,68 +1,70 @@ -#include"KiriKiri.h" +#include "KiriKiri.h" bool InsertKiriKiriZHook() - { - - /* - * Sample games: - * RJ351843 - */ - const BYTE bytes[] = { - 0xCC, // int 3 - 0x4C, 0x89, 0x44, 0x24, 0x18, // mov [rsp+18],r8 <- hook here - 0x48, 0x89, 0x54, 0x24, 0x10, // mov [rsp+10],rdx - 0x53, // push rbx - 0x56, // push rsi - 0x57, // push rdi - 0x41, 0x54, // push r12 - 0x41, 0x55, // push r13 - 0x41, 0x56, // push r14 - 0x41, 0x57, // push r15 - 0x48, 0x83, 0xEC, 0x40, // sub rsp,40 - 0x48, 0xC7, 0x44, 0x24, 0x30, 0xFE, 0xFF, 0xFF, 0xFF // mov qword ptr [rsp+30],FFFFFFFFFFFFFFFE - }; +{ - ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR); - for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) { - HookParam hp; - hp.address = addr + 1; - hp.offset=get_reg(regs::rcx); - hp.index = 0x18; - hp.type = CODEC_UTF16 | DATA_INDIRECT; - return NewHook(hp, "KiriKiriZ"); - } - return false; + /* + * Sample games: + * RJ351843 + */ + const BYTE bytes[] = { + 0xCC, // int 3 + 0x4C, 0x89, 0x44, 0x24, 0x18, // mov [rsp+18],r8 <- hook here + 0x48, 0x89, 0x54, 0x24, 0x10, // mov [rsp+10],rdx + 0x53, // push rbx + 0x56, // push rsi + 0x57, // push rdi + 0x41, 0x54, // push r12 + 0x41, 0x55, // push r13 + 0x41, 0x56, // push r14 + 0x41, 0x57, // push r15 + 0x48, 0x83, 0xEC, 0x40, // sub rsp,40 + 0x48, 0xC7, 0x44, 0x24, 0x30, 0xFE, 0xFF, 0xFF, 0xFF // mov qword ptr [rsp+30],FFFFFFFFFFFFFFFE + }; + + ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR); + for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) + { + HookParam hp; + hp.address = addr + 1; + hp.offset = get_reg(regs::rcx); + hp.index = 0x18; + hp.type = CODEC_UTF16 | DATA_INDIRECT; + return NewHook(hp, "KiriKiriZ"); } + return false; +} bool Insertkrkrz64Hook() { - const BYTE BYTES[] = { - 0x41,0x0F,0xB7,0x44,0x24,0x04, - 0x89,0x43,0x20, - 0x41,0x0F,0xB7,0x44,0x24,0x06, - 0x89,0x43,0x24, - 0x41,0x0F,0xBF,0x44,0x24,0x0C, - 0x89,0x43,0x14 - }; - auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress); - ConsoleOutput("%p %p", processStartAddress, processStopAddress); - for (auto addr : addrs) { - ConsoleOutput("krkrz64 %p", addr); - const BYTE funcstart[] = { 0xcc,0xcc,0xcc,0xcc }; - addr = reverseFindBytes(funcstart, sizeof(funcstart), addr - 0x1000, addr); - if (addr == 0)continue; - addr += 4; - HookParam hp; - hp.address = addr; - hp.type = CODEC_UTF16| DATA_INDIRECT; - hp.offset=get_reg(regs::rcx); - hp.index = 0x18; - ConsoleOutput("krkrz64 %p %x", addr); - return NewHook(hp, "krkrz64"); - } + const BYTE BYTES[] = { + 0x41, 0x0F, 0xB7, 0x44, 0x24, 0x04, + 0x89, 0x43, 0x20, + 0x41, 0x0F, 0xB7, 0x44, 0x24, 0x06, + 0x89, 0x43, 0x24, + 0x41, 0x0F, 0xBF, 0x44, 0x24, 0x0C, + 0x89, 0x43, 0x14}; + auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress); + ConsoleOutput("%p %p", processStartAddress, processStopAddress); + for (auto addr : addrs) + { + ConsoleOutput("krkrz64 %p", addr); + const BYTE funcstart[] = {0xcc, 0xcc, 0xcc, 0xcc}; + addr = reverseFindBytes(funcstart, sizeof(funcstart), addr - 0x1000, addr); + if (addr == 0) + continue; + addr += 4; + HookParam hp; + hp.address = addr; + hp.type = CODEC_UTF16 | DATA_INDIRECT; + hp.offset = get_reg(regs::rcx); + hp.index = 0x18; + ConsoleOutput("krkrz64 %p %x", addr); + return NewHook(hp, "krkrz64"); + } - ConsoleOutput("krkrz64 failed"); - return false; + ConsoleOutput("krkrz64 failed"); + return false; +} +bool KiriKiri::attach_function() +{ + return Insertkrkrz64Hook() || InsertKiriKiriZHook(); } -bool KiriKiri::attach_function() { - return Insertkrkrz64Hook()||InsertKiriKiriZHook(); -} - \ No newline at end of file diff --git a/LunaHook/engine64/KiriKiri.h b/LunaHook/engine64/KiriKiri.h index 29600c2..50f51cc 100644 --- a/LunaHook/engine64/KiriKiri.h +++ b/LunaHook/engine64/KiriKiri.h @@ -1,15 +1,17 @@ -class KiriKiri:public ENGINE{ - public: - KiriKiri(){ - - check_by=CHECK_BY::CUSTOM; - is_engine_certain=false; - check_by_target=[](){ - return Util::CheckFile(L"*.xp3") || Util::SearchResourceString(L"TVP(KIRIKIRI)"); +class KiriKiri : public ENGINE +{ +public: + KiriKiri() + { + + check_by = CHECK_BY::CUSTOM; + is_engine_certain = false; + check_by_target = []() + { + return Util::CheckFile(L"*.xp3") || Util::SearchResourceString(L"TVP(KIRIKIRI)"); }; - }; - bool attach_function(); + }; + bool attach_function(); }; - \ No newline at end of file diff --git a/LunaHook/engine64/LightVN.h b/LunaHook/engine64/LightVN.h index 866f98a..cfd67b6 100644 --- a/LunaHook/engine64/LightVN.h +++ b/LunaHook/engine64/LightVN.h @@ -1,13 +1,14 @@ -class LightVN:public ENGINE{ - public: - LightVN(){ - - check_by=CHECK_BY::FILE_ANY; - is_engine_certain=false; - check_by_target=check_by_list{L"Data/Scripts/title.txt",L"Data/data*.vndat",L"Scripts/000_title.txt"}; - }; - bool attach_function(); +class LightVN : public ENGINE +{ +public: + LightVN() + { + + check_by = CHECK_BY::FILE_ANY; + is_engine_certain = false; + check_by_target = check_by_list{L"Data/Scripts/title.txt", L"Data/data*.vndat", L"Scripts/000_title.txt"}; + }; + bool attach_function(); }; - \ No newline at end of file diff --git a/LunaHook/engine64/PPSSPP.cpp b/LunaHook/engine64/PPSSPP.cpp index 27c91cc..d88eebf 100644 --- a/LunaHook/engine64/PPSSPP.cpp +++ b/LunaHook/engine64/PPSSPP.cpp @@ -1,5 +1,5 @@ -#include"PPSSPP.h" -#include"ppsspp/psputils.hpp" +#include "PPSSPP.h" +#include "ppsspp/psputils.hpp" bool PPSSPPengine::attach_function() { diff --git a/LunaHook/engine64/PPSSPP.h b/LunaHook/engine64/PPSSPP.h index 1ef6fb1..22a2358 100644 --- a/LunaHook/engine64/PPSSPP.h +++ b/LunaHook/engine64/PPSSPP.h @@ -1,12 +1,14 @@ -class PPSSPPengine:public ENGINE{ - public: - PPSSPPengine(){ - - check_by=CHECK_BY::FILE; - is_engine_certain=false; - check_by_target=L"PPSSPP*.exe"; - }; - bool attach_function(); +class PPSSPPengine : public ENGINE +{ +public: + PPSSPPengine() + { + + check_by = CHECK_BY::FILE; + is_engine_certain = false; + check_by_target = L"PPSSPP*.exe"; + }; + bool attach_function(); }; diff --git a/LunaHook/engine64/Ryujinx.cpp b/LunaHook/engine64/Ryujinx.cpp index a7a8ea4..e9910ab 100644 --- a/LunaHook/engine64/Ryujinx.cpp +++ b/LunaHook/engine64/Ryujinx.cpp @@ -44,6 +44,8 @@ namespace } bool Ryujinx::attach_function() { + WarningOutput("not support ryuujinx, please use yuzu/sudachi instead."); + return true; auto invokeCompileMethodHelper = processStartAddress + 0x84CC0; getMethodNameFromMetadata = (decltype(getMethodNameFromMetadata))(processStartAddress + 0x7AED0); HookParam hp; diff --git a/LunaHook/engine64/Suika2.cpp b/LunaHook/engine64/Suika2.cpp index 4798206..f7ea54f 100644 --- a/LunaHook/engine64/Suika2.cpp +++ b/LunaHook/engine64/Suika2.cpp @@ -1,18 +1,21 @@ -#include"Suika2.h" - -bool Suika2_msvcrt() { - auto msvcrt=GetModuleHandle(L"msvcrt.dll"); - if(msvcrt==0)return 0; - auto _strdup=GetProcAddress(msvcrt,"_strdup"); - if(_strdup==0)return 0; +#include "Suika2.h" + +bool Suika2_msvcrt() +{ + auto msvcrt = GetModuleHandle(L"msvcrt.dll"); + if (msvcrt == 0) + return 0; + auto _strdup = GetProcAddress(msvcrt, "_strdup"); + if (_strdup == 0) + return 0; HookParam hp; - hp.address=(uintptr_t)_strdup; - hp.type=USING_STRING|CODEC_UTF8; - hp.offset=get_reg(regs::rcx); - return NewHook(hp,"Suika2_msvcrt"); - -} -bool Suika2::attach_function() { - auto _1=Suika2_msvcrt(); - return _1 ; + hp.address = (uintptr_t)_strdup; + hp.type = USING_STRING | CODEC_UTF8; + hp.offset = get_reg(regs::rcx); + return NewHook(hp, "Suika2_msvcrt"); +} +bool Suika2::attach_function() +{ + auto _1 = Suika2_msvcrt(); + return _1; } \ No newline at end of file diff --git a/LunaHook/engine64/Suika2.h b/LunaHook/engine64/Suika2.h index 0f59fe0..3cc5a38 100644 --- a/LunaHook/engine64/Suika2.h +++ b/LunaHook/engine64/Suika2.h @@ -1,11 +1,13 @@ -class Suika2:public ENGINE{ - public: - Suika2(){ - is_engine_certain=false; - check_by=CHECK_BY::FILE_ANY; - check_by_target=check_by_list{L"suika.exe",L"conf/config.txt"}; +class Suika2 : public ENGINE +{ +public: + Suika2() + { + is_engine_certain = false; + check_by = CHECK_BY::FILE_ANY; + check_by_target = check_by_list{L"suika.exe", L"conf/config.txt"}; }; - bool attach_function(); + bool attach_function(); }; \ No newline at end of file diff --git a/LunaHook/engine64/TYPEMOON.cpp b/LunaHook/engine64/TYPEMOON.cpp index b06b05d..8422967 100644 --- a/LunaHook/engine64/TYPEMOON.cpp +++ b/LunaHook/engine64/TYPEMOON.cpp @@ -1,25 +1,29 @@ -#include"TYPEMOON.h" -namespace{ -bool _h() { - //TYPE-MOON 魔法使いの夜 多国語版 中文-英文-日文 - BYTE bytes[]={ - 0xBA,0x08,0xFF,0x00,0x00, - 0x41,0xB8,0x1C,0x20,0x00,0x00, - 0x66,0x90 - }; - auto addr=MemDbg::findBytes(bytes,sizeof(bytes),processStartAddress, processStopAddress); - ConsoleOutput("%p",addr); - if(addr==0)return false; - addr=MemDbg::findEnclosingAlignedFunction(addr);ConsoleOutput("%p",addr); - if(addr==0)return false; - HookParam hp; - hp.address=addr; - hp.type=CODEC_UTF16|USING_STRING|EMBED_ABLE|EMBED_AFTER_NEW|EMBED_BEFORE_SIMPLE; - hp.offset=get_reg(regs::r8); - return NewHook(hp,"typemoon"); +#include "TYPEMOON.h" +namespace +{ + bool _h() + { + // TYPE-MOON 魔法使いの夜 多国語版 中文-英文-日文 + BYTE bytes[] = { + 0xBA, 0x08, 0xFF, 0x00, 0x00, + 0x41, 0xB8, 0x1C, 0x20, 0x00, 0x00, + 0x66, 0x90}; + auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); + ConsoleOutput("%p", addr); + if (addr == 0) + return false; + addr = MemDbg::findEnclosingAlignedFunction(addr); + ConsoleOutput("%p", addr); + if (addr == 0) + return false; + HookParam hp; + hp.address = addr; + hp.type = CODEC_UTF16 | USING_STRING | EMBED_ABLE | EMBED_AFTER_NEW | EMBED_BEFORE_SIMPLE; + hp.offset = get_reg(regs::r8); + return NewHook(hp, "typemoon"); + } } -} -bool TYPEMOON::attach_function() { +bool TYPEMOON::attach_function() +{ return _h(); -} - \ No newline at end of file +} diff --git a/LunaHook/engine64/TYPEMOON.h b/LunaHook/engine64/TYPEMOON.h index 7ffd140..244b1f6 100644 --- a/LunaHook/engine64/TYPEMOON.h +++ b/LunaHook/engine64/TYPEMOON.h @@ -1,13 +1,14 @@ -class TYPEMOON:public ENGINE{ - public: - TYPEMOON(){ - - check_by=CHECK_BY::FILE; - is_engine_certain=false; - check_by_target=L"data*.hfa"; - }; - bool attach_function(); +class TYPEMOON : public ENGINE +{ +public: + TYPEMOON() + { + + check_by = CHECK_BY::FILE; + is_engine_certain = false; + check_by_target = L"data*.hfa"; + }; + bool attach_function(); }; - \ No newline at end of file diff --git a/LunaHook/engine64/V8.cpp b/LunaHook/engine64/V8.cpp index 09b2179..912d2f9 100644 --- a/LunaHook/engine64/V8.cpp +++ b/LunaHook/engine64/V8.cpp @@ -1,5 +1,5 @@ -#include"V8.h" -#include"v8/v8.h" +#include "V8.h" +#include "v8/v8.h" #if 0 // Artikash 6/23/2019: V8 (JavaScript runtime) has rcx = string** at v8::String::Write // sample game https://www.freem.ne.jp/dl/win/18963 @@ -113,7 +113,7 @@ namespace{ } return save; } - #if 0 +#if 0 std::vector v8hook1(HMODULE module) { const BYTE BYTES[] = { @@ -155,7 +155,7 @@ namespace{ } return save; } - #endif +#endif bool innerHTML(HMODULE module) { //花葬 //result = sub_142DF3CA0(a2, v5, 1u, (__int64)"innerHTML", a3); @@ -208,8 +208,8 @@ namespace{ } #endif -bool V8::attach_function_() { - - return tryhookv8(); -} +bool V8::attach_function_() +{ + return tryhookv8(); +} diff --git a/LunaHook/engine64/V8.h b/LunaHook/engine64/V8.h index 7c779f1..e357f9d 100644 --- a/LunaHook/engine64/V8.h +++ b/LunaHook/engine64/V8.h @@ -1,12 +1,14 @@ -class V8:public ENGINE{ - public: - V8(){ - check_by=CHECK_BY::CUSTOM; - check_by_target=[this](){return attach_function_();}; +class V8 : public ENGINE +{ +public: + V8() + { + check_by = CHECK_BY::CUSTOM; + check_by_target = [this]() + { return attach_function_(); }; }; - bool attach_function_(); - bool attach_function(){return true;} + bool attach_function_(); + bool attach_function() { return true; } }; - diff --git a/LunaHook/engine64/YOX.cpp b/LunaHook/engine64/YOX.cpp index 537a992..df72667 100644 --- a/LunaHook/engine64/YOX.cpp +++ b/LunaHook/engine64/YOX.cpp @@ -1,21 +1,22 @@ -#include"YOX.h" +#include "YOX.h" bool YOX::attach_function() { const BYTE BYTES[] = { - 0x48,0x8B,0x0F, - 0x48,0x8d,0x54,0x24,0x50 - }; + 0x48, 0x8B, 0x0F, + 0x48, 0x8d, 0x54, 0x24, 0x50}; auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress); ConsoleOutput("%p %p", processStartAddress, processStopAddress); - for (auto addr : addrs) { - if (addr == 0)continue; + for (auto addr : addrs) + { + if (addr == 0) + continue; HookParam hp; hp.address = addr; - hp.type = USING_STRING ; + hp.type = USING_STRING; hp.offset = get_stack(26); ConsoleOutput("yox64 %p", addr); return NewHook(hp, "yox64"); } ConsoleOutput("yox64 failed"); return false; -} \ No newline at end of file +} \ No newline at end of file diff --git a/LunaHook/engine64/YOX.h b/LunaHook/engine64/YOX.h index 3ffde6b..55a3782 100644 --- a/LunaHook/engine64/YOX.h +++ b/LunaHook/engine64/YOX.h @@ -1,13 +1,14 @@ -class YOX:public ENGINE{ - public: - YOX(){ - - check_by=CHECK_BY::FILE; - is_engine_certain=false; - check_by_target=L"base/*.dat"; - }; - bool attach_function(); +class YOX : public ENGINE +{ +public: + YOX() + { + + check_by = CHECK_BY::FILE; + is_engine_certain = false; + check_by_target = L"base/*.dat"; + }; + bool attach_function(); }; - \ No newline at end of file diff --git a/LunaHook/engine64/livecaptions.cpp b/LunaHook/engine64/livecaptions.cpp index 0c5c385..66c73e0 100644 --- a/LunaHook/engine64/livecaptions.cpp +++ b/LunaHook/engine64/livecaptions.cpp @@ -1,49 +1,50 @@ #include "livecaptions.h" - bool livecaptions::attach_function() { - -// .text:0000000180001C98 push rbx -// .text:0000000180001C9A sub rsp, 20h -// .text:0000000180001C9E mov rbx, rcx -// .text:0000000180001CA1 call memmove_0 -// .text:0000000180001CA6 mov rax, rbx -// .text:0000000180001CA9 add rsp, 20h -// .text:0000000180001CAD pop rbx -// .text:0000000180001CAE retn - HookParam hp; - hp.address=(uintptr_t)GetProcAddress(GetModuleHandle(L"vcruntime140_app.dll"),"memmove"); - hp.text_fun=[](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len){ - BYTE sig[]={ - 0x40,0x53,0x48,0x83,0xEC,0x20,0x48,0x8B,0xD9, - 0xE8,XX4 - }; - auto a1=stack->retaddr-sizeof(sig); - if((stack->retaddr>(uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll"))) - if(memcmp((void*)a1,&sig,sizeof(sig)-4)==0){ - static std::setonce; - if(once.find(stack->retaddr)!=once.end())return; - once.insert(stack->retaddr); - // hp->text_fun=nullptr; - // hp->type=HOOK_EMPTY; - HookParam hpinternal; - hpinternal.address =a1;// 0xE551+(uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll"); - hpinternal.type = USING_STRING | CODEC_UTF8|FULL_STRING; - hpinternal.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + // .text:0000000180001C98 push rbx + // .text:0000000180001C9A sub rsp, 20h + // .text:0000000180001C9E mov rbx, rcx + // .text:0000000180001CA1 call memmove_0 + // .text:0000000180001CA6 mov rax, rbx + // .text:0000000180001CA9 add rsp, 20h + // .text:0000000180001CAD pop rbx + // .text:0000000180001CAE retn + HookParam hp; + hp.address = (uintptr_t)GetProcAddress(GetModuleHandle(L"vcruntime140_app.dll"), "memmove"); + hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + BYTE sig[] = { + 0x40, 0x53, 0x48, 0x83, 0xEC, 0x20, 0x48, 0x8B, 0xD9, + 0xE8, XX4}; + auto a1 = stack->retaddr - sizeof(sig); + if ((stack->retaddr > (uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll"))) + if (memcmp((void *)a1, &sig, sizeof(sig) - 4) == 0) { - auto ptr = stack->rdx; - auto size = stack->r8; - if (size == strnlen((char *)ptr, TEXT_BUFFER_SIZE) )//否则有短acsii + static std::set once; + if (once.find(stack->retaddr) != once.end()) + return; + once.insert(stack->retaddr); + // hp->text_fun=nullptr; + // hp->type=HOOK_EMPTY; + + HookParam hpinternal; + hpinternal.address = a1; // 0xE551+(uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll"); + hpinternal.type = USING_STRING | CODEC_UTF8 | FULL_STRING; + hpinternal.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) { - *data = ptr; - *len = size; - } - }; - NewHook(hpinternal, "std::_Char_traits::copy(void *, const void *, size_t)"); - } + auto ptr = stack->rdx; + auto size = stack->r8; + if (size == strnlen((char *)ptr, TEXT_BUFFER_SIZE)) // 否则有短acsii + { + *data = ptr; + *len = size; + } + }; + NewHook(hpinternal, "std::_Char_traits::copy(void *, const void *, size_t)"); + } }; - - return NewHook(hp,"vcruntime140_app:memmove"); + + return NewHook(hp, "vcruntime140_app:memmove"); } \ No newline at end of file diff --git a/LunaHook/engine64/livecaptions.h b/LunaHook/engine64/livecaptions.h index e0fbaba..4a3f461 100644 --- a/LunaHook/engine64/livecaptions.h +++ b/LunaHook/engine64/livecaptions.h @@ -9,7 +9,7 @@ public: check_by = CHECK_BY::CUSTOM; check_by_target = []() { - return GetModuleHandle(L"vcruntime140_app.dll")&&GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll"); + return GetModuleHandle(L"vcruntime140_app.dll") && GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll"); }; }; bool attach_function(); diff --git a/LunaHook/engine64/lucasystem.h b/LunaHook/engine64/lucasystem.h index ddc0502..7d0ff4a 100644 --- a/LunaHook/engine64/lucasystem.h +++ b/LunaHook/engine64/lucasystem.h @@ -1,13 +1,14 @@ -class lucasystem:public ENGINE{ - public: - lucasystem(){ - - check_by=CHECK_BY::FILE; - is_engine_certain=false; - check_by_target=L"files/*.PAK"; - }; - bool attach_function(); +class lucasystem : public ENGINE +{ +public: + lucasystem() + { + + check_by = CHECK_BY::FILE; + is_engine_certain = false; + check_by_target = L"files/*.PAK"; + }; + bool attach_function(); }; - \ No newline at end of file diff --git a/LunaHook/engine64/mono.cpp b/LunaHook/engine64/mono.cpp index 5050593..e339749 100644 --- a/LunaHook/engine64/mono.cpp +++ b/LunaHook/engine64/mono.cpp @@ -1,82 +1,90 @@ -#include"mono.h" -#include"mono/monocommon.hpp" - -namespace{ - bool monobdwgc() { - +#include "mono.h" +#include "mono/monocommon.hpp" + +namespace +{ + bool monobdwgc() + { + HMODULE module = GetModuleHandleW(L"mono-2.0-bdwgc.dll"); - if (module == 0)return false; + if (module == 0) + return false; auto [minAddress, maxAddress] = Util::QueryModuleLimits(module); BYTE bytes[] = { - 0x81,0xF9,0x80,0x00,0x00,0x00, - 0x73,0x05, - 0x49,0x8B,0xCC - /* -_BYTE *__fastcall sub_18005B290( - _WORD *a1, - int a2, - __int64 a3, - _DWORD *a4, - __int64 (__fastcall *a5)(__int64, __int64), - __int64 a6, - __int64 a7) + 0x81, 0xF9, 0x80, 0x00, 0x00, 0x00, + 0x73, 0x05, + 0x49, 0x8B, 0xCC + /* + _BYTE *__fastcall sub_18005B290( + _WORD *a1, + int a2, + __int64 a3, + _DWORD *a4, + __int64 (__fastcall *a5)(__int64, __int64), + __int64 a6, + __int64 a7) - if ( (_DWORD)v26 ) - { - if ( (unsigned int)v26 >= 0x80 ) + if ( (_DWORD)v26 ) { - if ( (unsigned int)v26 >= 0x800 ) + if ( (unsigned int)v26 >= 0x80 ) { - if ( (unsigned int)v26 >= 0x10000 ) + if ( (unsigned int)v26 >= 0x800 ) { - if ( (unsigned int)v26 >= 0x200000 ) + if ( (unsigned int)v26 >= 0x10000 ) { - if ( (unsigned int)v26 >= 0x4000000 ) + if ( (unsigned int)v26 >= 0x200000 ) { - v17 = 6i64; - if ( (unsigned int)v26 >= 0x80000000 ) - */ + if ( (unsigned int)v26 >= 0x4000000 ) + { + v17 = 6i64; + if ( (unsigned int)v26 >= 0x80000000 ) + */ }; - auto addrs =Util::SearchMemory(bytes, sizeof(bytes),PAGE_EXECUTE, minAddress, maxAddress); - auto suc=false; - for (auto addr : addrs) { - const BYTE align[]={0xCC,0xCC,0xCC,0xCC}; - addr=reverseFindBytes(align,sizeof(align),addr-0x100,addr); - if(addr==0)continue; - + auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, minAddress, maxAddress); + auto suc = false; + for (auto addr : addrs) + { + const BYTE align[] = {0xCC, 0xCC, 0xCC, 0xCC}; + addr = reverseFindBytes(align, sizeof(align), addr - 0x100, addr); + if (addr == 0) + continue; + ConsoleOutput("monobdwgcdll %p", addr); HookParam hp; - hp.address = addr+4; - hp.offset=get_reg(regs::rcx); - hp.type = CODEC_UTF16|USING_STRING; - hp.text_fun=[](auto, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - - std::wstring str = std::wstring((LPWSTR)*data ); - *split=str.find(L"OnShowComplete")!=str.npos; - - *len = wcslen((wchar_t*)*data) * 2 ; + hp.address = addr + 4; + hp.offset = get_reg(regs::rcx); + hp.type = CODEC_UTF16 | USING_STRING; + hp.text_fun = [](auto, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + std::wstring str = std::wstring((LPWSTR)*data); + *split = str.find(L"OnShowComplete") != str.npos; + + *len = wcslen((wchar_t *)*data) * 2; }; - hp.filter_fun=[](void* data, size_t* len, HookParam* hp){ - std::wstring str = std::wstring((LPWSTR)data ,*len/2); - if(str.find(L"OnShowComplete")!=str.npos){ + hp.filter_fun = [](void *data, size_t *len, HookParam *hp) + { + std::wstring str = std::wstring((LPWSTR)data, *len / 2); + if (str.find(L"OnShowComplete") != str.npos) + { str = std::regex_replace(str, std::wregex(L"\n"), L""); std::wregex reg1(L"\\((.*?)\\)"); - std::wsmatch match; - std::regex_search(str, match,reg1 ); - auto result1= match[1].str(); - - std::regex_search(str, match,std::wregex(L" Text:(.*?)Next:(.*?)") ); - result1= match[1].str(); - write_string_overwrite(data,len,result1); + std::wsmatch match; + std::regex_search(str, match, reg1); + auto result1 = match[1].str(); + + std::regex_search(str, match, std::wregex(L" Text:(.*?)Next:(.*?)")); + result1 = match[1].str(); + write_string_overwrite(data, len, result1); } return true; }; - suc|=NewHook(hp, "monobdwgcdll"); + suc |= NewHook(hp, "monobdwgcdll"); } return suc; - } + } } -bool mono::attach_function(){ - bool common=monocommon::hook_mono_il2cpp(); +bool mono::attach_function() +{ + bool common = monocommon::hook_mono_il2cpp(); return common; } \ No newline at end of file diff --git a/LunaHook/engine64/mono.h b/LunaHook/engine64/mono.h index b3efd09..333f835 100644 --- a/LunaHook/engine64/mono.h +++ b/LunaHook/engine64/mono.h @@ -1,10 +1,12 @@ -class mono:public ENGINE{ - public: - mono(){ - - check_by=CHECK_BY::ALL_TRUE; +class mono : public ENGINE +{ +public: + mono() + { + + check_by = CHECK_BY::ALL_TRUE; }; - bool attach_function(); + bool attach_function(); }; diff --git a/LunaHook/engine64/pchooks.cpp b/LunaHook/engine64/pchooks.cpp index 0d6c1f7..5588737 100644 --- a/LunaHook/engine64/pchooks.cpp +++ b/LunaHook/engine64/pchooks.cpp @@ -1,12 +1,16 @@ -#include"pchooks.h" - -bool pchooks::attach_function() { - for (std::wstring DXVersion : { L"d3dx9", L"d3dx10" }) - if (HMODULE module = GetModuleHandleW(DXVersion.c_str())) PcHooks::hookD3DXFunctions(module); - else for (int i = 0; i < 50; ++i) - if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str())) PcHooks::hookD3DXFunctions(module); +#include "pchooks.h" + +bool pchooks::attach_function() +{ + for (std::wstring DXVersion : {L"d3dx9", L"d3dx10"}) + if (HMODULE module = GetModuleHandleW(DXVersion.c_str())) + PcHooks::hookD3DXFunctions(module); + else + for (int i = 0; i < 50; ++i) + if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str())) + PcHooks::hookD3DXFunctions(module); PcHooks::hookGDIFunctions(); PcHooks::hookGDIPlusFunctions(); return true; -} \ No newline at end of file +} \ No newline at end of file diff --git a/LunaHook/engine64/pchooks.h b/LunaHook/engine64/pchooks.h index 8bc4239..8fe116e 100644 --- a/LunaHook/engine64/pchooks.h +++ b/LunaHook/engine64/pchooks.h @@ -1,11 +1,13 @@ -class pchooks:public ENGINE{ - public: - pchooks(){ - - check_by=CHECK_BY::ALL_TRUE; - dontstop=true; - }; - bool attach_function(); +class pchooks : public ENGINE +{ +public: + pchooks() + { + + check_by = CHECK_BY::ALL_TRUE; + dontstop = true; + }; + bool attach_function(); }; diff --git a/LunaHook/engine64/rpcs3.cpp b/LunaHook/engine64/rpcs3.cpp index f1b2740..8b52f6f 100644 --- a/LunaHook/engine64/rpcs3.cpp +++ b/LunaHook/engine64/rpcs3.cpp @@ -1,6 +1,7 @@ -#include"rpcs3.h" -namespace{ - #if 0 //only support0.0.20-0.0.27 +#include "rpcs3.h" +namespace +{ +#if 0 // only support0.0.20-0.0.27 int emoffset; int jitoffset; uintptr_t getDoJitAddress_() { @@ -113,10 +114,11 @@ namespace{ return DoJitPtr+6; } - #endif - - uintptr_t getDoJitAddress() { - //rpcs3/Emu/Cell/PPUThread.cpp +#endif + + uintptr_t getDoJitAddress() + { + // rpcs3/Emu/Cell/PPUThread.cpp /* extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr = nullptr) { @@ -138,130 +140,147 @@ namespace{ } …… */ - char log[]="ppu_register_function_at(0x%x): empty range"; - auto logstrptr=MemDbg::findBytes(log,sizeof(log),processStartAddress,processStopAddress); - ConsoleOutput("%p",logstrptr); - if(logstrptr==0)return 0; - auto addr=MemDbg::findleaaddr(logstrptr, processStartAddress, processStopAddress); - ConsoleOutput("%p",addr); - if(addr==0)return 0; - //ff cc cc cc,find不到。。 - BYTE start[]={XX,0xCC,0xCC,0xCC}; - addr=reverseFindBytes(start,sizeof(start),addr-0x200,addr,4,true); - ConsoleOutput("%p",addr); + char log[] = "ppu_register_function_at(0x%x): empty range"; + auto logstrptr = MemDbg::findBytes(log, sizeof(log), processStartAddress, processStopAddress); + ConsoleOutput("%p", logstrptr); + if (logstrptr == 0) + return 0; + auto addr = MemDbg::findleaaddr(logstrptr, processStartAddress, processStopAddress); + ConsoleOutput("%p", addr); + if (addr == 0) + return 0; + // ff cc cc cc,find不到。。 + BYTE start[] = {XX, 0xCC, 0xCC, 0xCC}; + addr = reverseFindBytes(start, sizeof(start), addr - 0x200, addr, 4, true); + ConsoleOutput("%p", addr); return addr; - } -struct emfuncinfo{ - uint64_t type; - int argidx;int padding; - void* hookfunc; - void* filterfun; - const char* _id; - }; -std::unordered_mapemfunctionhooks; - -bool checkiscurrentgame(const emfuncinfo& em){ - auto wininfos=get_proc_windows(); - for(auto&& info:wininfos){ - if(info.title.find(acastw(em._id))!=info.title.npos)return true; - } - return false; -} - -static std::set> timeoutbreaks; - -void dohookemaddr(uintptr_t em_address,uintptr_t ret){ - jitaddraddr(em_address,ret,JITTYPE::RPCS3); - if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return; - if(!(checkiscurrentgame(emfunctionhooks.at(em_address))))return; - timeoutbreaks.insert(std::make_pair(em_address,ret)); - auto op=emfunctionhooks.at(em_address); - HookParam hpinternal; - hpinternal.address=ret; - hpinternal.emu_addr=em_address;//用于生成hcode - hpinternal.type=USING_STRING|NO_CONTEXT|BREAK_POINT|op.type; - hpinternal.text_fun=(decltype(hpinternal.text_fun))op.hookfunc; - hpinternal.filter_fun=(decltype(hpinternal.filter_fun))op.filterfun; - hpinternal.argidx=op.argidx; - hpinternal.padding=op.padding; - hpinternal.jittype=JITTYPE::RPCS3; - NewHook(hpinternal,op._id); -} - -bool unsafeinithooks(){ - //rpcs0.0.30,不知道为什么ppu_register_function_at不全。不过看代码得到映射表了,直接弄吧。 - //rpcs3/Emu/Cell/PPUThread.cpp - // Get pointer to executable cache - /* - static inline u8* ppu_ptr(u32 addr) + struct emfuncinfo { - return vm::g_exec_addr + u64{addr} * 2; - } - */ - HookParam hp; - hp.type=DIRECT_READ; - hp.address=0x500000000; - hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len) - { - for(auto [addr,info]:emfunctionhooks){ - auto table=addr*2+0x500000000; - if(IsBadReadPtr((void*)table,sizeof(uintptr_t)))continue; - auto funcaddr=*(uintptr_t*)table; - funcaddr&=0x0000ffffffffffff; - if(!funcaddr)continue; - auto p=std::make_pair(addr,funcaddr); - if(timeoutbreaks.find(p)!=timeoutbreaks.end())continue; - dohookemaddr(addr,funcaddr); - delayinsertNewHook(addr); + uint64_t type; + int argidx; + int padding; + void *hookfunc; + void *filterfun; + const char *_id; + }; + std::unordered_map emfunctionhooks; + + bool checkiscurrentgame(const emfuncinfo &em) + { + auto wininfos = get_proc_windows(); + for (auto &&info : wininfos) + { + if (info.title.find(acastw(em._id)) != info.title.npos) + return true; } - }; - return NewHook(hp,"g_exec_addr"); - -} + return false; + } + + static std::set> timeoutbreaks; + + void dohookemaddr(uintptr_t em_address, uintptr_t ret) + { + jitaddraddr(em_address, ret, JITTYPE::RPCS3); + if (emfunctionhooks.find(em_address) == emfunctionhooks.end()) + return; + if (!(checkiscurrentgame(emfunctionhooks.at(em_address)))) + return; + timeoutbreaks.insert(std::make_pair(em_address, ret)); + auto op = emfunctionhooks.at(em_address); + HookParam hpinternal; + hpinternal.address = ret; + hpinternal.emu_addr = em_address; // 用于生成hcode + hpinternal.type = USING_STRING | NO_CONTEXT | BREAK_POINT | op.type; + hpinternal.text_fun = (decltype(hpinternal.text_fun))op.hookfunc; + hpinternal.filter_fun = (decltype(hpinternal.filter_fun))op.filterfun; + hpinternal.argidx = op.argidx; + hpinternal.padding = op.padding; + hpinternal.jittype = JITTYPE::RPCS3; + NewHook(hpinternal, op._id); + } + + bool unsafeinithooks() + { + // rpcs0.0.30,不知道为什么ppu_register_function_at不全。不过看代码得到映射表了,直接弄吧。 + // rpcs3/Emu/Cell/PPUThread.cpp + // Get pointer to executable cache + /* + static inline u8* ppu_ptr(u32 addr) + { + return vm::g_exec_addr + u64{addr} * 2; + } + */ + HookParam hp; + hp.type = DIRECT_READ; + hp.address = 0x500000000; + hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + for (auto [addr, info] : emfunctionhooks) + { + auto table = addr * 2 + 0x500000000; + if (IsBadReadPtr((void *)table, sizeof(uintptr_t))) + continue; + auto funcaddr = *(uintptr_t *)table; + funcaddr &= 0x0000ffffffffffff; + if (!funcaddr) + continue; + auto p = std::make_pair(addr, funcaddr); + if (timeoutbreaks.find(p) != timeoutbreaks.end()) + continue; + dohookemaddr(addr, funcaddr); + delayinsertNewHook(addr); + } + }; + return NewHook(hp, "g_exec_addr"); + } } bool rpcs3::attach_function() { - ConsoleOutput("[Compatibility] RPCS3"); - auto DoJitPtr=getDoJitAddress(); - if(DoJitPtr==0)return false; + ConsoleOutput("[Compatibility] RPCS3"); + auto DoJitPtr = getDoJitAddress(); + if (DoJitPtr == 0) + return false; unsafeinithooks(); - spDefault.jittype=JITTYPE::RPCS3; + spDefault.jittype = JITTYPE::RPCS3; spDefault.minAddress = 0; spDefault.maxAddress = -1; HookParam hp; - hp.address=DoJitPtr; - hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - - auto em_address =stack->rcx;// *(uint32_t*)*(uintptr_t*)(stack->base+emoffset); - auto entrypoint=stack->r8;//*(uintptr_t*)*(uintptr_t*)(stack->base+jitoffset)-0x0008000000000000; - if(!em_address||!entrypoint)return; - dohookemaddr(em_address,entrypoint); + hp.address = DoJitPtr; + hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto em_address = stack->rcx; // *(uint32_t*)*(uintptr_t*)(stack->base+emoffset); + auto entrypoint = stack->r8; //*(uintptr_t*)*(uintptr_t*)(stack->base+jitoffset)-0x0008000000000000; + if (!em_address || !entrypoint) + return; + dohookemaddr(em_address, entrypoint); delayinsertNewHook(em_address); }; - return NewHook(hp,"vita3kjit"); + return NewHook(hp, "vita3kjit"); } +namespace +{ -namespace{ + bool FBLJM61131(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex pattern("\\[[^\\]]+."); + s = std::regex_replace(s, pattern, ""); + s = std::regex_replace(s, std::regex("\\\\k|\\\\x|%C|%B"), ""); + s = std::regex_replace(s, std::regex("\\%\\d+\\#[0-9a-fA-F]*\\;"), ""); + s = std::regex_replace(s, std::regex("\\n+"), " "); + return write_string_overwrite(data, len, s); + } + auto _ = []() + { + emfunctionhooks = { + //'&' -Sora no Mukou de Sakimasu you ni- + {0x46328, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM61131"}}, + // Dunamis15 + {0x42c90, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM60347"}}, -bool FBLJM61131(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - std::regex pattern("\\[[^\\]]+."); - s = std::regex_replace(s, pattern, ""); - s = std::regex_replace(s, std::regex("\\\\k|\\\\x|%C|%B"), ""); - s = std::regex_replace(s, std::regex("\\%\\d+\\#[0-9a-fA-F]*\\;"), ""); - s = std::regex_replace(s, std::regex("\\n+"), " "); - return write_string_overwrite(data,len,s); -} -auto _=[](){ - emfunctionhooks={ - //'&' -Sora no Mukou de Sakimasu you ni- - {0x46328,{CODEC_UTF8,1,0,0,FBLJM61131,"BLJM61131"}}, - //Dunamis15 - {0x42c90,{CODEC_UTF8,1,0,0,FBLJM61131,"BLJM60347"}}, - - }; - return 1; -}(); + }; + return 1; + }(); } \ No newline at end of file diff --git a/LunaHook/engine64/rpcs3.h b/LunaHook/engine64/rpcs3.h index 945e7a8..fc8ae09 100644 --- a/LunaHook/engine64/rpcs3.h +++ b/LunaHook/engine64/rpcs3.h @@ -1,13 +1,14 @@ -class rpcs3:public ENGINE{ - public: - rpcs3(){ - - check_by=CHECK_BY::FILE; - is_engine_certain=false; - check_by_target=L"rpcs3.exe"; - }; - bool attach_function(); +class rpcs3 : public ENGINE +{ +public: + rpcs3() + { + + check_by = CHECK_BY::FILE; + is_engine_certain = false; + check_by_target = L"rpcs3.exe"; + }; + bool attach_function(); }; - \ No newline at end of file diff --git a/LunaHook/engine64/vita3k.cpp b/LunaHook/engine64/vita3k.cpp index fc80643..42bbdbb 100644 --- a/LunaHook/engine64/vita3k.cpp +++ b/LunaHook/engine64/vita3k.cpp @@ -1,12 +1,15 @@ -#include"vita3k.h" -namespace{ +#include "vita3k.h" +namespace +{ auto isVirtual = true; auto idxDescriptor = isVirtual == true ? 2 : 1; auto idxEntrypoint = idxDescriptor + 1; - uintptr_t getDoJitAddress() { + uintptr_t getDoJitAddress() + { auto RegisterBlockSig1 = "40 55 53 56 57 41 54 41 56 41 57 48 8D 6C 24 E9 48 81 EC 90 00 00 00 48 8B ?? ?? ?? ?? ?? 48 33 C4 48 89 45 07 4D 8B F1 49 8B F0 48 8B FA 48 8B D9 4C 8B 7D 77 48 8B 01 48 8D 55 C7 FF 50 10"; - auto first=find_pattern(RegisterBlockSig1,processStartAddress,processStopAddress); - if (first) return first; + auto first = find_pattern(RegisterBlockSig1, processStartAddress, processStopAddress); + if (first) + return first; /* // DebugSymbol: RegisterBlock // ?RegisterBlock@EmitX64@X64@Backend@Dynarmic@@IEAA?AUBlockDescriptor@1234@AEBVLocationDescriptor@IR@4@PEBX_K@Z <- new @@ -19,346 +22,544 @@ namespace{ return symbols[0]; } */ - auto PatchBlockSig1 = "4C 8B DC 49 89 5B 10 49 89 6B 18 56 57 41 54 41 56 41 57";// "4C 8B DC 49 89 5B ?? 49 89 6B ?? 56 57 41 54 41 56 41 57"; - first = find_pattern(PatchBlockSig1,processStartAddress,processStopAddress); - if (first) { + auto PatchBlockSig1 = "4C 8B DC 49 89 5B 10 49 89 6B 18 56 57 41 54 41 56 41 57"; // "4C 8B DC 49 89 5B ?? 49 89 6B ?? 56 57 41 54 41 56 41 57"; + first = find_pattern(PatchBlockSig1, processStartAddress, processStopAddress); + if (first) + { idxDescriptor = 1; idxEntrypoint = 2; return first; } return 0; } -struct emfuncinfo{ - uint64_t type; - int argidx;int padding; - void* hookfunc; - void* filterfun; - const char* _id; - }; -std::unordered_mapemfunctionhooks; + struct emfuncinfo + { + uint64_t type; + int argidx; + int padding; + void *hookfunc; + void *filterfun; + const char *_id; + }; + std::unordered_map emfunctionhooks; -bool checkiscurrentgame(const emfuncinfo& em){ - auto wininfos=get_proc_windows(); - for(auto&& info:wininfos){ - if(info.title.find(acastw(em._id))!=info.title.npos)return true; + bool checkiscurrentgame(const emfuncinfo &em) + { + auto wininfos = get_proc_windows(); + for (auto &&info : wininfos) + { + if (info.title.find(acastw(em._id)) != info.title.npos) + return true; + } + return false; } - return false; -} } bool vita3k::attach_function() { - ConsoleOutput("[Compatibility] Vita3k 0.1.9 3520+"); - auto DoJitPtr=getDoJitAddress(); - if(DoJitPtr==0)return false; - ConsoleOutput("DoJitPtr %p",DoJitPtr); - spDefault.jittype=JITTYPE::VITA3K; + ConsoleOutput("[Compatibility] Vita3k 0.1.9 3520+"); + auto DoJitPtr = getDoJitAddress(); + if (DoJitPtr == 0) + return false; + ConsoleOutput("DoJitPtr %p", DoJitPtr); + spDefault.jittype = JITTYPE::VITA3K; spDefault.minAddress = 0; spDefault.maxAddress = -1; HookParam hp; - hp.address=DoJitPtr; - hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto descriptor = *argidx(stack,idxDescriptor+1); // r8 - auto entrypoint = *argidx(stack,idxEntrypoint+1); // r9 - auto em_address = *(uint32_t*)descriptor; - if(!entrypoint)return; - // ConsoleOutput("%p",em_address); - jitaddraddr(em_address,entrypoint,JITTYPE::VITA3K); - [&](){ - if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return; - auto op=emfunctionhooks.at(em_address); - if(!(checkiscurrentgame(op)))return; - - HookParam hpinternal; - hpinternal.address=entrypoint; - hpinternal.emu_addr=em_address;//用于生成hcode - hpinternal.type=USING_STRING|NO_CONTEXT|BREAK_POINT|op.type; - hpinternal.text_fun=(decltype(hpinternal.text_fun))op.hookfunc; - hpinternal.filter_fun=(decltype(hpinternal.filter_fun))op.filterfun; - hpinternal.argidx=op.argidx; - hpinternal.padding=op.padding; - hpinternal.jittype=JITTYPE::VITA3K; - NewHook(hpinternal,op._id); - }(); - delayinsertNewHook(em_address); + hp.address = DoJitPtr; + hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto descriptor = *argidx(stack, idxDescriptor + 1); // r8 + auto entrypoint = *argidx(stack, idxEntrypoint + 1); // r9 + auto em_address = *(uint32_t *)descriptor; + if (!entrypoint) + return; + // ConsoleOutput("%p",em_address); + jitaddraddr(em_address, entrypoint, JITTYPE::VITA3K); + [&]() + { + if (emfunctionhooks.find(em_address) == emfunctionhooks.end()) + return; + auto op = emfunctionhooks.at(em_address); + if (!(checkiscurrentgame(op))) + return; + + HookParam hpinternal; + hpinternal.address = entrypoint; + hpinternal.emu_addr = em_address; // 用于生成hcode + hpinternal.type = USING_STRING | NO_CONTEXT | BREAK_POINT | op.type; + hpinternal.text_fun = (decltype(hpinternal.text_fun))op.hookfunc; + hpinternal.filter_fun = (decltype(hpinternal.filter_fun))op.filterfun; + hpinternal.argidx = op.argidx; + hpinternal.padding = op.padding; + hpinternal.jittype = JITTYPE::VITA3K; + NewHook(hpinternal, op._id); + }(); + delayinsertNewHook(em_address); }; - return NewHook(hp,"vita3kjit"); + return NewHook(hp, "vita3kjit"); } - -namespace{ -bool FPCSG01023(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("
"), ""); - s = std::regex_replace(s, std::regex("%CF11F"), ""); - s = std::regex_replace(s, std::regex("%CFFFF"), ""); - s = std::regex_replace(s, std::regex("%K%P"), ""); - s = std::regex_replace(s, std::regex("%K%N"), ""); - s = std::regex_replace(s, std::regex("\n"), ""); - return write_string_overwrite(data,len,s); -} -template -bool FPCSG01282(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("(\\n)+"), " "); - s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), ""); - static std::string last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} - -template -void ReadU16TextAndLenDW(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address=VITA3K::emu_arg(stack)[index]; - *len=(*(DWORD*)(address+0x8))*2; - *data=address+0xC; -} - -bool FPCSG00410(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); - s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); - s = std::regex_replace(s, std::regex("#n"), " "); - // .replaceAll("④", "!?").replaceAll("②", "!!").replaceAll("⑥", "。").replaceAll("⑪", "【") - // .replaceAll("⑫", "】").replaceAll("⑤", "、").replaceAll("①", "・・・") - strReplace(s,"\x87\x43","!?");strReplace(s,"\x87\x41","!!");strReplace(s,"\x87\x45","\x81\x42");strReplace(s,"\x87\x4a","\x81\x79"); - strReplace(s,"\x87\x4b","\x81\x7a");strReplace(s,"\x87\x44","\x81\x41");strReplace(s,"\x87\x40","\x81\x45\x81\x45\x81\x45"); - return write_string_overwrite(data,len,s); -} -bool FPCSG00448(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("[\\s]"), ""); - s = std::regex_replace(s, std::regex("(#n)+"), ""); - s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); - s = std::regex_replace(s, std::regex("#Pos[\\s\\S]*?\\]"), ""); - return write_string_overwrite(data,len,s); -} -bool FPCSG01008(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("#Ruby\\[([^,]+)\\.([^\\]]+)\\]."), "$1"); - s = std::regex_replace(s, std::regex("(#n)+"), " "); - s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); - return write_string_overwrite(data,len,s); -} -void TPCSG00903(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address=VITA3K::emu_arg(stack)[0]; - *len=(*(DWORD*)(address+0x14)); - *data=address+0x1C; -} -bool FPCSG00903(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("\\\\n"), " "); - return write_string_overwrite(data,len,s); -} -bool FPCSG00839(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\[[^\\]]+."), L""); - s = std::regex_replace(s, std::wregex(L"\\\\k|\\\\x|%C|%B|%p-1;"), L""); - s = std::regex_replace(s, std::wregex(L"#[0-9a-fA-F]+;([^%#]+)(%r)?"), L"$1"); - s = std::regex_replace(s, std::wregex(L"\\\\n"), L""); - static std::wstring last; - if(last.find(s)!=last.npos)return false; - last=s; - return write_string_overwrite(data,len,s); -} -bool FPCSG00751(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("[\\s]"), ""); - s = std::regex_replace(s, std::regex("@[a-z]"), ""); - //s = std::regex_replace(s, std::regex("$"), ""); - strReplace(s,"\x81\x90",""); - return write_string_overwrite(data,len,s); -} -bool FPCSG00706(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"
"), L""); - return write_string_overwrite(data,len,s); -} -bool FPCSG00696(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - //.replace(/㌔/g, '⁉') - //.replace(/㍉/g, '!!') - strReplace(s,"\x87\x60",""); - strReplace(s,"\x87\x5f",""); - return write_string_overwrite(data,len,s); -} -bool FPCSG00389(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("[\\s]"), ""); - s = std::regex_replace(s, std::regex("(#n)+"), ""); - s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); - s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); - return write_string_overwrite(data,len,s); -} -bool FPCSG00216(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("[\\s]"), ""); - s = std::regex_replace(s, std::regex("(#n)+"), ""); - s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); - s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); - return write_string_overwrite(data,len,s); -} -bool FPCSG00405(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("[\\s]"), ""); - return write_string_overwrite(data,len,s); -} -bool PCSG00776(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - auto ws=StringToWideString(s,932).value(); - strReplace(ws,L"\x02",L""); - Trim(ws); - return write_string_overwrite(data,len,WideStringToString(ws)); -} - -void PCSG00911(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address = VITA3K::emu_arg(stack)[1]; - std::string final_string = ""; - BYTE pattern[] = {0x47,0xff,0xff}; - auto results = MemDbg::findBytes(pattern,sizeof(pattern),address,address+0x50); - if (!results) return; - - address = results+5; - - while (true) { - std::string text= (char*)address; - final_string += text; - address = address+(text.size() + 1); - - auto bytes=(BYTE*)address; - - if (!(bytes[0] == 0x48 && bytes[1] == 0xFF && bytes[2] == 0xFF)) break; - address = address+(3); - bytes=(BYTE*)address; - if (!(bytes[0] == 0x47 && bytes[1] == 0xFF && bytes[2] == 0xFF)) break; - - address = address+(5); - +namespace +{ + bool FPCSG01023(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("
"), ""); + s = std::regex_replace(s, std::regex("%CF11F"), ""); + s = std::regex_replace(s, std::regex("%CFFFF"), ""); + s = std::regex_replace(s, std::regex("%K%P"), ""); + s = std::regex_replace(s, std::regex("%K%N"), ""); + s = std::regex_replace(s, std::regex("\n"), ""); + return write_string_overwrite(data, len, s); + } + template + bool FPCSG01282(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("(\\n)+"), " "); + s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), ""); + static std::string last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); } - write_string_new(data,len,final_string); -} -void TPCSG00291(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto a2= VITA3K::emu_arg(stack)[0]; - auto vm = *(DWORD*)(a2+(0x28)); - vm=*(DWORD*)VITA3K::emu_addr(stack,vm); - vm=*(DWORD*)VITA3K::emu_addr(stack,vm+8); - uintptr_t address=VITA3K::emu_addr(stack,vm); - auto len1=*(DWORD*)(address+4); - auto p=address+0x20; - if(len1>4 && *(WORD*)(p+2)==0){ - auto p1=*(DWORD*)(address+8); - vm=*(DWORD*)VITA3K::emu_addr(stack,vm); - vm=*(DWORD*)VITA3K::emu_addr(stack,vm+0xC); - p=VITA3K::emu_addr(stack,vm); - } - static int fm=0; - static std::string pre; - auto b=fm; - auto s=[](uintptr_t address){ - auto frist = *(WORD*)address; - auto lo = frist & 0xFF; // uppercase: 41->5A - auto hi = frist >> 8; - if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */) { - return std::string(); - } - std::string s ;int i = 0;WORD c; - char buf[3]={0}; - while ((c = *(WORD*)(address+i)) != 0) { - // reverse endian: ShiftJIS BE => LE - buf[0] = c >> 8; - buf[1] = c & 0xFF; + template + void ReadU16TextAndLenDW(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = VITA3K::emu_arg(stack)[index]; + *len = (*(DWORD *)(address + 0x8)) * 2; + *data = address + 0xC; + } - if (c == 0x815e /* / */) { - s += ' '; // single line - } - else if (buf[0] == 0) { - //// UTF16 LE turned BE: 5700=>0057, 3100, 3500 - //// 4e00 6d00=>PLAYER - // do nothing - if (buf[1] == 0x4e) { - s += "PLAYER"; - fm++; - } - } - else { - s+=buf; - } - i += 2; - } - return s; - }(p); - if(b>0){ - fm--; - return; - } - if(s==pre)return ; - pre=s; - write_string_new(data,len,s); -} + bool FPCSG00410(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); + s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); + s = std::regex_replace(s, std::regex("#n"), " "); + // .replaceAll("④", "!?").replaceAll("②", "!!").replaceAll("⑥", "。").replaceAll("⑪", "【") + // .replaceAll("⑫", "】").replaceAll("⑤", "、").replaceAll("①", "・・・") + strReplace(s, "\x87\x43", "!?"); + strReplace(s, "\x87\x41", "!!"); + strReplace(s, "\x87\x45", "\x81\x42"); + strReplace(s, "\x87\x4a", "\x81\x79"); + strReplace(s, "\x87\x4b", "\x81\x7a"); + strReplace(s, "\x87\x44", "\x81\x41"); + strReplace(s, "\x87\x40", "\x81\x45\x81\x45\x81\x45"); + return write_string_overwrite(data, len, s); + } + bool FPCSG00448(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("[\\s]"), ""); + s = std::regex_replace(s, std::regex("(#n)+"), ""); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); + s = std::regex_replace(s, std::regex("#Pos[\\s\\S]*?\\]"), ""); + return write_string_overwrite(data, len, s); + } + bool FPCSG01008(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("#Ruby\\[([^,]+)\\.([^\\]]+)\\]."), "$1"); + s = std::regex_replace(s, std::regex("(#n)+"), " "); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); + return write_string_overwrite(data, len, s); + } + void TPCSG00903(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = VITA3K::emu_arg(stack)[0]; + *len = (*(DWORD *)(address + 0x14)); + *data = address + 0x1C; + } + bool FPCSG00903(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("\\\\n"), " "); + return write_string_overwrite(data, len, s); + } + bool FPCSG01180(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(\\n)"), " "); + s = std::regex_replace(s, std::regex(R"(,.*$)"), " "); + return write_string_overwrite(data, len, s); + } + bool FPCSG00839(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\[[^\\]]+."), L""); + s = std::regex_replace(s, std::wregex(L"\\\\k|\\\\x|%C|%B|%p-1;"), L""); + s = std::regex_replace(s, std::wregex(L"#[0-9a-fA-F]+;([^%#]+)(%r)?"), L"$1"); + s = std::regex_replace(s, std::wregex(L"\\\\n"), L""); + static std::wstring last; + if (last.find(s) != last.npos) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool FPCSG00751(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("[\\s]"), ""); + s = std::regex_replace(s, std::regex("@[a-z]"), ""); + // s = std::regex_replace(s, std::regex("$"), ""); + strReplace(s, "\x81\x90", ""); + return write_string_overwrite(data, len, s); + } + bool FPCSG00401(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"([\s])"), ""); + s = std::regex_replace(s, std::regex(R"(\c)"), ""); + s = std::regex_replace(s, std::regex(R"(\\n)"), ""); + return write_string_overwrite(data, len, s); + } + bool FPCSG00912(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("%N"), ""); + return write_string_overwrite(data, len, s); + } + bool FPCSG00706(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"
"), L""); + return write_string_overwrite(data, len, s); + } + bool FPCSG00696(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + //.replace(/㌔/g, '⁉') + //.replace(/㍉/g, '!!') + strReplace(s, "\x87\x60", ""); + strReplace(s, "\x87\x5f", ""); + return write_string_overwrite(data, len, s); + } + bool FPCSG00389(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("[\\s]"), ""); + s = std::regex_replace(s, std::regex("(#n)+"), ""); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); + s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); + return write_string_overwrite(data, len, s); + } + bool FPCSG00216(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("[\\s]"), ""); + s = std::regex_replace(s, std::regex("(#n)+"), ""); + s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); + s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); + return write_string_overwrite(data, len, s); + } + bool FPCSG00405(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("[\\s]"), ""); + return write_string_overwrite(data, len, s); + } + bool PCSG00776(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + auto ws = StringToWideString(s, 932).value(); + strReplace(ws, L"\x02", L""); + Trim(ws); + return write_string_overwrite(data, len, WideStringToString(ws)); + } + void PCSG00912(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = VITA3K::emu_arg(stack)[1]; + std::string final_string = ""; + BYTE pattern[] = {0x47, 0xff, 0xff}; + auto results = MemDbg::findBytes(pattern, sizeof(pattern), address, address + 0x50); + if (!results) + return; -auto _=[](){ - emfunctionhooks={ - //Tsuihou Senkyo - {0x8002e176,{0,0,0,0,FPCSG01023,"PCSG01023"}},//dialogue+name,sjis - //死神と少女 Shinigami to Shoujo - {0x800204ba,{0,2,0,0,FPCSG01282<0>,"PCSG01282"}},//dialogueNVL,sjis - {0x8000f00e,{0,1,0,0,FPCSG01282<1>,"PCSG01282"}},//dialogue main - {0x80011f1a,{0,0,0,0,FPCSG01282<2>,"PCSG01282"}},//Name - {0x8001ebac,{0,1,0,0,FPCSG01282<3>,"PCSG01282"}},//choices - //神凪ノ杜 Kannagi no Mori Satsukiame Tsuzuri - {0x828bb50c,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,0,"PCSG01268"}},//dialogue - {0x828ba9b6,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,0,"PCSG01268"}},//name - {0x8060D376,{CODEC_UTF8,0,0,0,0,"PCSG01268"}},//vita3k v0.2.0 can't find 0x828bb50c && 0x828ba9b6, unknown reason. - //Sanzen Sekai Yuugi ~MultiUniverse Myself~ - {0x8005ae24,{0,0,0,0,0,"PCSG01194"}},//dialouge+name,sjis,need remap jis char,to complex - // Marginal #4 Road to Galaxy - {0x8002ff90,{CODEC_UTF8,0,0,0,FPCSG01008,"PCSG01008"}},//text - //BLACK WOLVES SAGA -Weiβ und Schwarz- - // {0x8004ed22,{CODEC_UTF8,0,0,0,FPCSG01008,"PCSG00935"}},//name - // {0x8006d202,{CODEC_UTF8,1,2,0,FPCSG01008,"PCSG00935"}},//text - {0x800581a2,{CODEC_UTF8,0,0,0,FPCSG01008,"PCSG00935"}},//text - //New Game! The Challenge Stage! - {0x8012674c,{CODEC_UTF8,0,0,TPCSG00903,FPCSG00903,"PCSG00903"}}, - //Kenka Banchou Otome - {0x80009722,{CODEC_UTF16,0,0,0,FPCSG00839,"PCSG00839"}}, - //Arcana famiglia -La storia della Arcana Famiglia- - {0x80070e30,{0,2,0,0,FPCSG00751,"PCSG00751"}},//all,sjis - {0x80070cdc,{0,1,0,0,FPCSG00751,"PCSG00751"}},//text - //もし、この世界に神様がいるとするならば。 Moshi, Kono Sekai ni Kami-sama ga Iru to Suru Naraba. - {0x80c1f270,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,FPCSG00706,"PCSG00706"}},//dialogue - {0x80d48bfc,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<1>,FPCSG00706,"PCSG00706"}},//Dictionary1 - {0x80d48c20,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,FPCSG00706,"PCSG00706"}},//Dictionary2 - //Angelique Retour - {0x8008bd1a,{0,1,0,0,FPCSG00696,"PCSG00696"}},//text1,sjis - {0x8008cd48,{0,0,0,0,FPCSG00696,"PCSG00696"}},//text2 - {0x8008f75a,{0,0,0,0,FPCSG00696,"PCSG00696"}},//choice - //Tsuki ni Yorisou Otome no Sahou - {0x8002aefa,{0,2,0,0,0,"PCSG00648"}},//dialogue,sjis - //MARGINAL#4 IDOL OF SUPERNOVA - {0x800718f8,{0,0,0,0,FPCSG00448,"PCSG00448"}},//dialogue,sjis - //Nekketsu Inou Bukatsu-tan Trigger Kiss - {0x8004e44a,{0,0,0,0,FPCSG00410,"PCSG00410"}},//dialogue,sjis - //バイナリースター Binary Star - {0x80058608,{0,1,0,0,FPCSG00389,"PCSG00389"}},//dialogue,sjis - {0x80021292,{0,0,0,0,FPCSG00389,"PCSG00389"}},//name - //Amagami - {0x80070658,{0,0,0,TPCSG00291,0,"PCSG00291"}}, - //Rui wa Tomo o Yobu - {0x81003db0,{CODEC_UTF8,1,0,0,FPCSG00839,"PCSG00216"}},//dialogue - //Reine des Fleurs - {0x8001bff2,{0,0,0,0,FPCSG00405,"PCSG00405"}},//dialogue,sjis - //Muv-Luv - {0x80118f10,{0,5,0,0,PCSG00776,"PCSG00776"}},//dialogue, choices - {0x80126e7e,{0,0,0,0,PCSG00776,"PCSG00776"}},//dialogue - //Re:Birthday Song ~Koi o Utau Shinigami~ - {0x80033af6,{0,0,2,0,0,"PCSG00911"}},//dialogue - //Un:Birthday Song ~Ai o Utau Shinigami~ - {0x80038538,{0,0,0,PCSG00911,0,"PCSG00911"}}, - {0x80004b52,{0,3,5,0,0,"PCSG00911"}}, + address = results + 5; - }; - return 1; -}(); + while (true) + { + std::string text = (char *)address; + final_string += text; + address = address + (text.size() + 1); + + auto bytes = (BYTE *)address; + + if (!(bytes[0] == 0x48 && bytes[1] == 0xFF && bytes[2] == 0xFF)) + break; + address = address + (3); + bytes = (BYTE *)address; + if (!(bytes[0] == 0x47 && bytes[1] == 0xFF && bytes[2] == 0xFF)) + break; + + address = address + (5); + } + write_string_new(data, len, final_string); + } + void TPCSG00291(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto a2 = VITA3K::emu_arg(stack)[0]; + + auto vm = *(DWORD *)(a2 + (0x28)); + vm = *(DWORD *)VITA3K::emu_addr(stack, vm); + vm = *(DWORD *)VITA3K::emu_addr(stack, vm + 8); + uintptr_t address = VITA3K::emu_addr(stack, vm); + auto len1 = *(DWORD *)(address + 4); + auto p = address + 0x20; + if (len1 > 4 && *(WORD *)(p + 2) == 0) + { + auto p1 = *(DWORD *)(address + 8); + vm = *(DWORD *)VITA3K::emu_addr(stack, vm); + vm = *(DWORD *)VITA3K::emu_addr(stack, vm + 0xC); + p = VITA3K::emu_addr(stack, vm); + } + static int fm = 0; + static std::string pre; + auto b = fm; + auto s = [](uintptr_t address) + { + auto frist = *(WORD *)address; + auto lo = frist & 0xFF; // uppercase: 41->5A + auto hi = frist >> 8; + if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */) + { + return std::string(); + } + std::string s; + int i = 0; + WORD c; + char buf[3] = {0}; + while ((c = *(WORD *)(address + i)) != 0) + { + // reverse endian: ShiftJIS BE => LE + buf[0] = c >> 8; + buf[1] = c & 0xFF; + + if (c == 0x815e /* / */) + { + s += ' '; // single line + } + else if (buf[0] == 0) + { + //// UTF16 LE turned BE: 5700=>0057, 3100, 3500 + //// 4e00 6d00=>PLAYER + // do nothing + if (buf[1] == 0x4e) + { + s += "PLAYER"; + fm++; + } + } + else + { + s += buf; + } + i += 2; + } + return s; + }(p); + if (b > 0) + { + fm--; + return; + } + if (s == pre) + return; + pre = s; + write_string_new(data, len, s); + } + + bool FPCSG00468(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(\\n\u3000*|\\k)"), ""); + s = std::regex_replace(s, std::regex(R"(\[|\*[^\]]+])"), ""); + s = std::regex_replace(s, std::regex(u8"×"), ""); + return write_string_overwrite(data, len, s); + } + bool FPCSG00808(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(^\s+|\s+$)"), ""); + s = std::regex_replace(s, std::regex(R"(\s*(#n)*\s*)"), ""); + s = std::regex_replace(s, std::regex(R"(#\w+(\[.+?\])?)"), ""); + return write_string_overwrite(data, len, s); + } + bool FPCSG00855(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(#n\u3000*)"), ""); + s = std::regex_replace(s, std::regex(R"(#\w.+?])"), ""); + return write_string_overwrite(data, len, s); + } + template + bool FPCSG00855_2(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + static std::string last; + if (last == s) + return false; + last = s; + strReplace(s, u8"Χ", u8"、"); + strReplace(s, u8"Δ", u8"。"); + strReplace(s, u8"Λ", u8"っ"); + strReplace(s, u8"《", u8"("); + strReplace(s, u8"》", u8")"); + strReplace(s, u8"∫", u8"「"); + strReplace(s, u8"∨", u8"」"); + strReplace(s, u8"∴", u8"『"); + strReplace(s, u8"∵", u8"』"); + strReplace(s, u8"П", u8"【"); + strReplace(s, u8"Ц", u8"】"); + if (write_string_overwrite(data, len, s)) + return FPCSG00855(data, len, hp); + else + return false; + } + bool FPCSG00477(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + auto ws = StringToWideString(s, 932).value(); + ws = std::regex_replace(ws, std::wregex(LR"(#n\u3000*)"), L""); + ws = std::regex_replace(ws, std::wregex(LR"(#\w.+?])"), L""); + s = WideStringToString(ws, 932); + return write_string_overwrite(data, len, s); + } + bool FPCSG00852(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + auto ws = StringToWideString(s, 932).value(); + ws = std::regex_replace(ws, std::wregex(LR"(\^)"), L""); + s = WideStringToString(ws, 932); + return write_string_overwrite(data, len, s); + } + bool FPCSG01066(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(\n\u3000*)"), ""); + return write_string_overwrite(data, len, s); + } + bool FPCSG01075(void *data, size_t *len, HookParam *hp) + { + if (!FPCSG00808(data, len, hp)) + return false; + auto s = std::string((char *)data, *len); + static std::string last; + if (last == s) + return false; + last = s; + return true; + } + auto _ = []() + { + emfunctionhooks = { + // Tsuihou Senkyo + {0x8002e176, {0, 0, 0, 0, FPCSG01023, "PCSG01023"}}, // dialogue+name,sjis + // 死神と少女 Shinigami to Shoujo + {0x800204ba, {0, 2, 0, 0, FPCSG01282<0>, "PCSG01282"}}, // dialogueNVL,sjis + {0x8000f00e, {0, 1, 0, 0, FPCSG01282<1>, "PCSG01282"}}, // dialogue main + {0x80011f1a, {0, 0, 0, 0, FPCSG01282<2>, "PCSG01282"}}, // Name + {0x8001ebac, {0, 1, 0, 0, FPCSG01282<3>, "PCSG01282"}}, // choices + // 神凪ノ杜 Kannagi no Mori Satsukiame Tsuzuri + {0x828bb50c, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, 0, "PCSG01268"}}, // dialogue + {0x828ba9b6, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, 0, "PCSG01268"}}, // name + {0x8060D376, {CODEC_UTF8, 0, 0, 0, 0, "PCSG01268"}}, // vita3k v0.2.0 can't find 0x828bb50c && 0x828ba9b6, unknown reason. + // Sanzen Sekai Yuugi ~MultiUniverse Myself~ + {0x8005ae24, {0, 0, 0, 0, 0, "PCSG01194"}}, // dialouge+name,sjis,need remap jis char,to complex + // Marginal #4 Road to Galaxy + {0x8002ff90, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG01008"}}, // text + // BLACK WOLVES SAGA -Weiβ und Schwarz- + {0x800581a2, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG00935"}}, // text + // New Game! The Challenge Stage! + {0x8012674c, {CODEC_UTF8, 0, 0, TPCSG00903, FPCSG00903, "PCSG00903"}}, + // Kenka Banchou Otome + {0x80009722, {CODEC_UTF16, 0, 0, 0, FPCSG00839, "PCSG00839"}}, + // Arcana famiglia -La storia della Arcana Famiglia- + {0x80070e30, {0, 2, 0, 0, FPCSG00751, "PCSG00751"}}, // all,sjis + {0x80070cdc, {0, 1, 0, 0, FPCSG00751, "PCSG00751"}}, // text + // もし、この世界に神様がいるとするならば。 Moshi, Kono Sekai ni Kami-sama ga Iru to Suru Naraba. + {0x80c1f270, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, FPCSG00706, "PCSG00706"}}, // dialogue + {0x80d48bfc, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<1>, FPCSG00706, "PCSG00706"}}, // Dictionary1 + {0x80d48c20, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, FPCSG00706, "PCSG00706"}}, // Dictionary2 + // Angelique Retour + {0x8008bd1a, {0, 1, 0, 0, FPCSG00696, "PCSG00696"}}, // text1,sjis + {0x8008cd48, {0, 0, 0, 0, FPCSG00696, "PCSG00696"}}, // text2 + {0x8008f75a, {0, 0, 0, 0, FPCSG00696, "PCSG00696"}}, // choice + // Tsuki ni Yorisou Otome no Sahou + {0x8002aefa, {0, 2, 0, 0, 0, "PCSG00648"}}, // dialogue,sjis + // MARGINAL#4 IDOL OF SUPERNOVA + {0x800718f8, {0, 0, 0, 0, FPCSG00448, "PCSG00448"}}, // dialogue,sjis + // Nekketsu Inou Bukatsu-tan Trigger Kiss + {0x8004e44a, {0, 0, 0, 0, FPCSG00410, "PCSG00410"}}, // dialogue,sjis + // バイナリースター Binary Star + {0x80058606, {0, 1, 0xd, 0, FPCSG00389, "PCSG00389"}}, // dialogue,sjis + // Amagami + {0x80070658, {0, 0, 0, TPCSG00291, 0, "PCSG00291"}}, + // Rui wa Tomo o Yobu + {0x81003db0, {CODEC_UTF8, 1, 0, 0, FPCSG00839, "PCSG00216"}}, // dialogue + // Reine des Fleurs + {0x8001bff2, {0, 0, 0, 0, FPCSG00405, "PCSG00405"}}, // dialogue,sjis + // Muv-Luv + {0x80118f10, {0, 5, 0, 0, PCSG00776, "PCSG00776"}}, // dialogue, choices + {0x80126e7e, {0, 0, 0, 0, PCSG00776, "PCSG00776"}}, // dialogue + // Re:Birthday Song ~Koi o Utau Shinigami~ + {0x80033af6, {0, 0, 2, 0, 0, "PCSG00911"}}, // dialogue + // Un:Birthday Song ~Ai o Utau Shinigami~ + {0x80038538, {0, 0, 0, PCSG00912, 0, "PCSG00912"}}, + {0x80033d66, {0, 3, 4, 0, FPCSG00912, "PCSG00912"}}, + // Sora*yume + {0x8000bad4, {0, 1, 0, 0, FPCSG00401, "PCSG00401"}}, + // Tengai ni Mau, Iki na Hana + + {0x8006808e, {CODEC_UTF8, 0, 0, 0, FPCSG01180, "PCSG01180"}}, + {0x80089408, {CODEC_UTF8, 0, 0, 0, FPCSG01180, "PCSG01180"}}, + + // Kokuchou no Psychedelica (黒蝶のサイケデリカ) + {0x80043538, {CODEC_UTF8, 1, 0, 0, FPCSG00468, "PCSG00468"}}, + // Haitaka no Psychedelica (灰鷹のサイケデリカ) + {0x80022c06, {CODEC_UTF8, 4, 0, 0, FPCSG00468, "PCSG00812"}}, + // Yuukyuu no Tierblade -Lost Chronicle- (悠久のティアブレイド -Lost Chronicle-) + {0x8003542a, {CODEC_UTF8, 10, 0, 0, FPCSG00808, "PCSG00808"}}, + {0x8002a95a, {CODEC_UTF8, 6, 0, 0, FPCSG00808, "PCSG00808"}}, + {0x801a98aa, {CODEC_UTF8, 9, 0, 0, FPCSG00808, "PCSG00808"}}, + {0x801a42bc, {CODEC_UTF8, 9, 0, 0, FPCSG00808, "PCSG00808"}}, + {0x801a42d0, {CODEC_UTF8, 7, 0, 0, FPCSG00808, "PCSG00808"}}, + // Yuukyuu no Tierblade -Fragments of Memory- (悠久のティアブレイド -Fragments of Memory-) + {0x80035f44, {CODEC_UTF8, 10, 0, 0, FPCSG01075, "PCSG01075"}}, + {0x8000d868, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}}, + {0x8004598e, {CODEC_UTF8, 0, 0, 0, FPCSG01075, "PCSG01075"}}, + {0x801b1d16, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}}, + {0x801ac31e, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}}, + {0x801ac33a, {CODEC_UTF8, 7, 0, 0, FPCSG01075, "PCSG01075"}}, + {0x801b879a, {CODEC_UTF8, 5, 0, 0, FPCSG01075, "PCSG01075"}}, + {0x8009f570, {CODEC_UTF8, 5, 0, 0, FPCSG01075, "PCSG01075"}}, + // Magic Kyun! Renaissance (マジきゅんっ!ルネッサンス) + {0x8008375a, {0, 1, 0, 0, FPCSG00852, "PCSG00852"}}, + {0x8001c194, {0, 1, 0, 0, FPCSG00852, "PCSG00852"}}, + // Chouchou Jiken Lovesodic / Chouchou Jiken Rhapsodic (蝶々事件ラブソディック) + {0x8008dea2, {CODEC_UTF8, 4, 0, 0, FPCSG01066, "PCSG01066"}}, + {0x8008eb38, {CODEC_UTF8, 0, 0, 0, FPCSG01066, "PCSG01066"}}, + // Hyakka Yakou (百華夜光) + {0x80032b30, {0, 8, 0, 0, 0, "PCSG00477"}}, + {0x80019c5a, {0, 5, 0, 0, 0, "PCSG00477"}}, + {0x80031a46, {0, 6, 0, 0, 0, "PCSG00477"}}, + {0x8003a49a, {0, 0, 0, 0, FPCSG00477, "PCSG00477"}}, + {0x80182532, {0, 7, 0, 0, FPCSG00477, "PCSG00477"}}, + {0x8017d1da, {0, 5, 0, 0, 0, "PCSG00477"}}, + {0x8017d478, {0, 4, 0, 0, 0, "PCSG00477"}}, + {0x8017a6aa, {0, 6, 0, 0, 0, "PCSG00477"}}, + // Hana Oboro ~Sengoku-den Ranki~ (花朧 ~戦国伝乱奇~) + {0x80037600, {CODEC_UTF8, 6, 0, 0, FPCSG00855, "PCSG00855"}}, + {0x80036580, {CODEC_UTF8, 6, 0, 0, FPCSG00855, "PCSG00855"}}, + {0x801a2ada, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<0>, "PCSG00855"}}, + {0x801a2ba8, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<1>, "PCSG00855"}}, + {0x801a2d9e, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<2>, "PCSG00855"}}, + {0x801a2e68, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<3>, "PCSG00855"}}, + }; + return 1; + }(); } \ No newline at end of file diff --git a/LunaHook/engine64/vita3k.h b/LunaHook/engine64/vita3k.h index 59269a5..20162d0 100644 --- a/LunaHook/engine64/vita3k.h +++ b/LunaHook/engine64/vita3k.h @@ -1,13 +1,14 @@ -class vita3k:public ENGINE{ - public: - vita3k(){ - - check_by=CHECK_BY::FILE; - is_engine_certain=false; - check_by_target=L"Vita3K.exe"; - }; - bool attach_function(); +class vita3k : public ENGINE +{ +public: + vita3k() + { + + check_by = CHECK_BY::FILE; + is_engine_certain = false; + check_by_target = L"Vita3K.exe"; + }; + bool attach_function(); }; - \ No newline at end of file diff --git a/LunaHook/engine64/yuzu.cpp b/LunaHook/engine64/yuzu.cpp new file mode 100644 index 0000000..de43df6 --- /dev/null +++ b/LunaHook/engine64/yuzu.cpp @@ -0,0 +1,2904 @@ +#include "yuzu.h" +#include "mages/mages.h" +namespace +{ + auto isFastMem = true; + + auto isVirtual = true; // Process.arch === 'x64' && Process.platform === 'windows'; + auto idxDescriptor = isVirtual == true ? 2 : 1; + auto idxEntrypoint = idxDescriptor + 1; + + uintptr_t getDoJitAddress() + { + auto RegisterBlockSig1 = "E8 ?? ?? ?? ?? 4? 8B ?? 4? 8B ?? 4? 8B ?? E8 ?? ?? ?? ?? 4? 89?? 4? 8B???? ???????? 4? 89?? ?? 4? 8B?? 4? 89"; + auto RegisterBlock = find_pattern(RegisterBlockSig1, processStartAddress, processStopAddress); + if (RegisterBlock) + { + auto beginSubSig1 = "CC 40 5? 5? 5?"; + auto lookbackSize = 0x400; + auto address = RegisterBlock - lookbackSize; + auto subs = find_pattern(beginSubSig1, address, address + lookbackSize); + if (subs) + { + return subs + 1; + } + } + + auto PatchSig1 = "4????? 4????? 4????? FF?? ?? 4????? ?? 4????? 75 ?? 4????? ?? 4????? ?? 4?"; + auto Patch = find_pattern(PatchSig1, processStartAddress, processStopAddress); + if (Patch) + { + auto beginSubSig1 = "4883EC ?? 48"; + auto lookbackSize = 0x80; + auto address = Patch - lookbackSize; + auto subs = find_pattern(beginSubSig1, address, address + lookbackSize); + if (subs) + { + idxDescriptor = 1; + idxEntrypoint = 2; + return subs; + } + } + return 0; + /* + 这块不知道怎么实现。 + // DebugSymbol: RegisterBlock + // ?RegisterBlock@EmitX64@X64@Backend@Dynarmic@@IEAA?AUBlockDescriptor@1234@AEBVLocationDescriptor@IR@4@PEBX_K@Z <- new + // ?RegisterBlock@EmitX64@X64@Backend@Dynarmic@@IEAA?AUBlockDescriptor@1234@AEBVLocationDescriptor@IR@4@PEBX1_K@Z + const symbols = DebugSymbol.findFunctionsMatching('Dynarmic::Backend::X64::EmitX64::RegisterBlock'); + if (symbols.length !== 0) { + return symbols[0]; + } + + // DebugSymbol: Patch + // ?Patch@EmitX64@X64@Backend@Dynarmic@@IEAAXAEBVLocationDescriptor@IR@4@PEBX@Z + const patchs = DebugSymbol.findFunctionsMatching('Dynarmic::Backend::X64::EmitX64::Patch'); + if (patchs.length !== 0) { + idxDescriptor = 1; + idxEntrypoint = 2; + return patchs[0]; + } + */ + } + + struct emfuncinfo + { + uint64_t type; + int argidx; + int padding; + void *hookfunc; + void *filterfun; + const char *_id; + const char *_version; + }; + std::unordered_map emfunctionhooks; + + struct GameInfo + { + std::string name{""}; + uint64_t id{0}; + std::string version{""}; + } game_info; + bool checkiscurrentgame(const emfuncinfo &em) + { + auto wininfos = get_proc_windows(); + for (auto &&info : wininfos) + { + if ((game_info.version.size()) && game_info.name.size() && (game_info.id != 0)) + { + // 判断是有效的info + auto checkversion = (em._version == 0) || (std::string(em._version) == (game_info.version)); + auto checkid = (std::stoll(em._id, 0, 16) == game_info.id); + if (checkid && checkversion) + return true; + } + else if ((em._version == 0) || (info.title.find(acastw(em._version)) != info.title.npos)) + return true; + } + return false; + } +} +bool Hook_Network_RoomMember_SendGameInfo() +{ + // void RoomMember::SendGameInfo(const GameInfo& game_info) { + // room_member_impl->current_game_info = game_info; + // if (!IsConnected()) + // return; + + // Packet packet; + // packet.Write(static_cast(IdSetGameInfo)); + // packet.Write(game_info.name); + // packet.Write(game_info.id); + // packet.Write(game_info.version); + // room_member_impl->Send(std::move(packet)); + // } + BYTE pattern[] = { + 0x49, 0x8B, XX, + 0x0F, 0xB6, 0x81, 0x28, 0x01, 0x00, 0x00, + 0x90, + 0x3C, 0x02, + 0x74, 0x1C, + 0x0F, 0xB6, 0x81, 0x28, 0x01, 0x00, 0x00, + 0x90, + 0x3C, 0x03, + 0x74, 0x10, + 0x0F, 0xB6, 0x81, 0x28, 0x01, 0x00, 0x00, + 0x90, + 0x3C, 0x04, + 0x0F, 0x85, XX4}; + for (auto addr : Util::SearchMemory(pattern, sizeof(pattern), PAGE_EXECUTE, processStartAddress, processStopAddress)) + { + addr = MemDbg::findEnclosingAlignedFunction_strict(addr, 0x100); + // 有两个,但另一个离起始很远 + if (addr == 0) + continue; + HookParam hp; + hp.address = addr; + hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + // void __fastcall Network::RoomMember::SendGameInfo( + // Network::RoomMember *this, + // const AnnounceMultiplayerRoom::GameInfo *game_info) + game_info = *(GameInfo *)stack->rdx; + ConsoleOutput("%s %llx %s", game_info.name.c_str(), game_info.id, game_info.version.c_str()); + }; + return NewHook(hp, "yuzuGameInfo"); + } + return false; +} +bool yuzu::attach_function() +{ + Hook_Network_RoomMember_SendGameInfo(); + ConsoleOutput("[Compatibility] Yuzu 1616+"); + auto DoJitPtr = getDoJitAddress(); + if (DoJitPtr == 0) + return false; + spDefault.jittype = JITTYPE::YUZU; + spDefault.minAddress = 0; + spDefault.maxAddress = -1; + ConsoleOutput("DoJitPtr %p", DoJitPtr); + HookParam hp; + hp.address = DoJitPtr; + hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto descriptor = *argidx(stack, idxDescriptor + 1); // r8 + auto entrypoint = *argidx(stack, idxEntrypoint + 1); // r9 + auto em_address = *(uintptr_t *)descriptor; + if (!entrypoint) + return; + jitaddraddr(em_address, entrypoint, JITTYPE::YUZU); + [&]() + { + if (emfunctionhooks.find(em_address) == emfunctionhooks.end()) + return; + auto op = emfunctionhooks.at(em_address); + if (!(checkiscurrentgame(op))) + return; + + HookParam hpinternal; + hpinternal.address = entrypoint; + hpinternal.emu_addr = em_address; // 用于生成hcode + hpinternal.type = USING_STRING | NO_CONTEXT | BREAK_POINT | op.type; + hpinternal.text_fun = (decltype(hpinternal.text_fun))op.hookfunc; + hpinternal.filter_fun = (decltype(hpinternal.filter_fun))op.filterfun; + hpinternal.argidx = op.argidx; + hpinternal.padding = op.padding; + hpinternal.jittype = JITTYPE::YUZU; + NewHook(hpinternal, op._id); + }(); + delayinsertNewHook(em_address); + }; + return NewHook(hp, "YuzuDoJit"); +} + +namespace +{ + int readu8(BYTE *addr) + { + int numBytes = 0; + auto firstByte = *addr; + if (firstByte <= 0x7F) + { + numBytes = 1; + } + else if ((firstByte & 0xE0) == 0xC0) + { + numBytes = 2; + } + else if ((firstByte & 0xF0) == 0xE0) + { + numBytes = 3; + } + else if ((firstByte & 0xF8) == 0xF0) + { + numBytes = 4; + } + return numBytes; + } + void T010012A017F18000(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = YUZU::emu_arg(stack)[2]; + std::string s, bottom; + uint32_t c; + while (true) + { + c = *(BYTE *)(address); + if (c == 0) + break; + if (c >= 0x20) + { + auto l = readu8((BYTE *)address); + s += std::string((char *)address, l); + address += l; + } + else + { + address += 1; + if (c == 1) + { + bottom = ""; + while (true) + { + auto l = readu8((BYTE *)address); + auto ss = std::string((char *)address, l); + address += l; + if (ss[0] < 0xa) + break; + bottom += ss; + s += ss; + } + } + else if (c == 3) + { + while (true) + { + auto l = readu8((BYTE *)address); + auto ss = std::string((char *)address, l); + address += l; + if (ss[0] < 0xa) + break; + } + } + else if (c == 7) + { + address += 1; + } + else if (c == 0xa) + { + return; + } + else if (c == 0xd) + { + c = *(uint32_t *)address; + auto count = c & 0xFF; + c = c & 0xFFFFFF00; + if (c == 0x0692c500) + { + for (int _ = 0; _ < count; _++) + s += '-'; + address += 4; + } + } + } + } + + write_string_new(data, len, s); + } + + template + void ReadTextAndLenDW(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = YUZU::emu_arg(stack)[index]; + *len = (*(DWORD *)(address + 0x10)) * 2; + *data = address + 0x14; + } + + template + void ReadTextAndLenW(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = YUZU::emu_arg(stack)[index]; + *len = (*(WORD *)(address + 0x10)) * 2; + *data = address + 0x14; + } + template + void mages_readstring(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto s = mages::readString(YUZU::emu_arg(stack)[0], idx); + write_string_new(data, len, s); + } + + bool F0100A3A00CC7E000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + + std::wregex pattern1(L"^`([^@]+)."); + s = std::regex_replace(s, pattern1, L"$1: "); + + s = std::regex_replace(s, std::wregex(L"\\$[A-Z]\\d*(,\\d*)*"), L""); + + std::wregex pattern2(L"\\$\\[([^$]+)..([^$]+).."); + s = std::regex_replace(s, pattern2, L"$1"); + return write_string_overwrite(data, len, s); + } + + bool F010045C0109F2000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("#[^\\]]*\\]"), ""); + s = std::regex_replace(s, std::regex("#[^\\n]*\\n"), ""); + s = std::regex_replace(s, std::regex("\\u3000"), ""); + s = std::regex_replace(s, std::regex(u8"Save[\\s\\S]*データ"), ""); + return write_string_overwrite(data, len, s); + } + + bool F0100A1E00BFEA000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); + s = std::regex_replace(s, std::wregex(L"(.+? \")"), L""); + s = std::regex_replace(s, std::wregex(L"(\",.*)"), L""); + s = std::regex_replace(s, std::wregex(L"(\" .*)"), L""); + return write_string_overwrite(data, len, s); + } + + bool F0100A1200CA3C000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\$d"), L"\n"); + s = std::regex_replace(s, std::wregex(L"_"), L" "); + s = std::regex_replace(s, std::wregex(L"@"), L" "); + s = std::regex_replace(s, std::wregex(L"\\[([^\\/\\]]+)\\/[^\\/\\]]+\\]"), L"$1"); + s = std::regex_replace(s, std::wregex(L"[~^$❝.❞'?,(-)!—:;-❛ ❜]"), L""); + s = std::regex_replace(s, std::wregex(L"[A-Za-z0-9]"), L""); + s = std::regex_replace(s, std::wregex(L"^\\s+"), L""); + while (std::regex_search(s, std::wregex(L"^\\s*$"))) + { + s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); + } + return write_string_overwrite(data, len, s); + } + + bool F0100F6A00A684000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + + std::regex regex("(?=@.)"); + std::sregex_token_iterator it(s.begin(), s.end(), regex, -1); + std::sregex_token_iterator end; + + std::vector parts(it, end); + s = ""; + for (auto part : parts) + { + if (startWith(part, "@") == false) + { + s += part; + continue; + } + std::string tag = part.substr(0, 2); + std::string content = part.substr(2); + if (tag == "@r") + { + if (s == "") + s = content; + else + s += '\n' + content; + } + else if (tag == "@u" || tag == "@v" || tag == "@w" || tag == "@o" || tag == "@a" || tag == "@z" || tag == "@c" || tag == "@s") + { + auto splited = strSplit(content, "."); + if (splited.size() == 2) + s += splited[1]; + } + else if (tag == "@b") + { + } + else + { + s += content; + } + } + static auto katakanaMap = std::map{ + {L"「", L"「"}, {L"」", L"」"}, {L"ァ", L"ぁ"}, {L"ィ", L"ぃ"}, {L"ゥ", L"ぅ"}, {L"ェ", L"ぇ"}, {L"ォ", L"ぉ"}, {L"ャ", L"ゃ"}, {L"ュ", L"ゅ"}, {L"ョ", L"ょ"}, {L"ア", L"あ"}, {L"イ", L"い"}, {L"ウ", L"う"}, {L"エ", L"え"}, {L"オ", L"お"}, {L"カ", L"か"}, {L"キ", L"き"}, {L"ク", L"く"}, {L"ケ", L"け"}, {L"コ", L"こ"}, {L"サ", L"さ"}, {L"シ", L"し"}, {L"ス", L"す"}, {L"セ", L"せ"}, {L"ソ", L"そ"}, {L"タ", L"た"}, {L"チ", L"ち"}, {L"ツ", L"つ"}, {L"テ", L"て"}, {L"ト", L"と"}, {L"ナ", L"な"}, {L"ニ", L"に"}, {L"ヌ", L"ぬ"}, {L"ネ", L"ね"}, {L"ノ", L"の"}, {L"ハ", L"は"}, {L"ヒ", L"ひ"}, {L"フ", L"ふ"}, {L"ヘ", L"へ"}, {L"ホ", L"ほ"}, {L"マ", L"ま"}, {L"ミ", L"み"}, {L"ム", L"む"}, {L"メ", L"め"}, {L"モ", L"も"}, {L"ヤ", L"や"}, {L"ユ", L"ゆ"}, {L"ヨ", L"よ"}, {L"ラ", L"ら"}, {L"リ", L"り"}, {L"ル", L"る"}, {L"レ", L"れ"}, {L"ロ", L"ろ"}, {L"ワ", L"わ"}, {L"ヲ", L"を"}, {L"ン", L"ん"}, {L"ー", L"ー"}, {L"ッ", L"っ"}, {L"、", L"、"}, {L"゚", L"?"}, {L"゙", L"!"}, {L"・", L"…"}, {L"?", L" "}, {L"。", L"。"}, {L"\uF8F0", L""}, {L"\uFFFD", L""} // invalid (shift_jis A0 <=> EF A3 B0) | FF FD - F8 F0) + }; + + auto remap = [](std::string s) + { + std::wstring result; + auto ws = StringToWideString(s, 932).value(); + for (auto _c : ws) + { + std::wstring c; + c.push_back(_c); + if (katakanaMap.find(c) != katakanaMap.end()) + { + result += katakanaMap[c]; + } + else + result += c; + } + return WideStringToString(result, 932); + }; + return write_string_overwrite(data, len, remap(s)); + } + bool F01006590155AC000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + + std::regex regex("(?=@.)"); + std::sregex_token_iterator it(s.begin(), s.end(), regex, -1); + std::sregex_token_iterator end; + + std::vector parts(it, end); + s = ""; + int counter = 0; + while (counter < parts.size()) + { + std::string part = parts[counter]; + if (part[0] != '@') + { + s += part; + counter++; + continue; + } + std::string tag = part.substr(0, 2); + std::string content = part.substr(2); + if (tag == "@s" || tag == "@t") + { + s += content.substr(4); + counter++; + continue; + } + else if (tag == "@m") + { + s += content.substr(2); + counter++; + continue; + } + else if (tag == "@n") + { + s += '\n' + content; + counter++; + continue; + } + else if (tag == "@b" || tag == "@a" || tag == "@p" || tag == "@k") + { + s += content; + counter++; + continue; + } + else if (tag == "@v" || tag == "@h") + { + std::regex regex("[\\w_-]+"); + s += std::regex_replace(content, regex, ""); + counter++; + continue; + } + else if (tag == "@r") + { + s += content + parts[counter + 2].substr(1); + counter += 3; + continue; + } + else if (tag == "@I") + { + if (content == "@" || parts[counter + 1].substr(0, 2) == "@r") + { + counter++; + continue; + } + std::regex regex(u8"[\\d+─]"); + s += std::regex_replace(content, regex, ""); + counter += 3; + continue; + } + else + { + s += content; + counter++; + continue; + } + } + return write_string_overwrite(data, len, s); + } + bool F01000200194AE000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + + static std::string readString_savedSentence = ""; + static bool readString_playerNameFlag = false; + static std::string readString_playerName = u8"ラピス"; + + std::regex regex("(?=@.)"); + std::sregex_token_iterator it(s.begin(), s.end(), regex, -1); + std::sregex_token_iterator end; + + std::vector parts(it, end); + s = ""; + size_t counter = 0; + + while (counter < parts.size()) + { + const std::string &part = parts[counter]; + + if (part.empty() || part[0] != '@') + { + s += part; + counter++; + continue; + } + + std::string tag = part.substr(0, 2); + std::string content = part.substr(2); + + if (tag == "@*") + { + if (content.find("name") == 0) + { + if (readString_playerName == u8"ラピス") + { + s += content.substr(4) + readString_playerName + parts[counter + 4].substr(1); + } + else + { + s += content.substr(4) + parts[counter + 3].substr(1) + parts[counter + 4].substr(1); + } + counter += 5; + continue; + } + } + else if (tag == "@s" || tag == "@t") + { + s += content.substr(4); + counter++; + continue; + } + else if (tag == "@m") + { + s += content.substr(2); + counter++; + continue; + } + else if (tag == "@u") + { + readString_playerNameFlag = true; + readString_savedSentence = ""; + counter++; + return write_string_overwrite(data, len, ""); + } + else if (tag == "@n" || tag == "@b" || tag == "@a" || tag == "@p" || tag == "@k") + { + s += content; + counter++; + continue; + } + else if (tag == "@v" || tag == "@h") + { + std::regex regex("[\\w_-]+"); + s += std::regex_replace(content, regex, ""); + counter++; + continue; + } + else if (tag == "@r") + { + s += content + parts[counter + 2].substr(1); + counter += 3; + continue; + } + else if (tag == "@I") + { + if (content == "@" || parts[counter + 1].substr(0, 2) == "@r") + { + counter++; + continue; + } + std::regex regex(u8"[\\d+─]"); + s += std::regex_replace(content, regex, ""); + counter += 3; + continue; + } + else + { + s += content; + counter++; + continue; + } + } + + if (!readString_playerNameFlag) + { + ; + } + else if (readString_savedSentence.empty()) + { + readString_savedSentence = s; + s = ""; + } + else + { + std::string savedSentence = readString_savedSentence; + readString_playerNameFlag = false; + readString_savedSentence = ""; + readString_playerName = s; + s = s + "\n" + savedSentence; + } + return write_string_overwrite(data, len, s); + } + bool F0100EA001A626000(void *data, size_t *len, HookParam *hp) + { + auto s = utf32_to_utf16((uint32_t *)data, *len / 4); + if (s == L"  ") + { + return false; + } + s = std::regex_replace(s, std::wregex(L"\n+"), L" "); + + s = std::regex_replace(s, std::wregex(L"\\$\\{FirstName\\}"), L"ナーヤ"); + + if (startWith(s, L"#T")) + { + s = std::regex_replace(s, std::wregex(L"#T2[^#]+"), L""); + s = std::regex_replace(s, std::wregex(L"#T\\d"), L""); + } + auto u32 = utf16_to_utf32(s.c_str(), s.size()); + return write_string_overwrite(data, len, u32); + } + bool F010093800DB1C000(void *data, size_t *len, HookParam *hp) + { + auto s = utf32_to_utf16((uint32_t *)data, *len / 4); + s = std::regex_replace(s, std::wregex(L"\\n+"), L" "); + s = std::regex_replace(s, std::wregex(L"\\$\\{FirstName\\}"), L"シリーン"); + if (startWith(s, L"#T")) + { + s = std::regex_replace(s, std::wregex(L"\\#T2[^#]+"), L""); + s = std::regex_replace(s, std::wregex(L"\\#T\\d"), L""); + } + auto u32 = utf16_to_utf32(s.c_str(), s.size()); + return write_string_overwrite(data, len, u32); + } + bool F0100F7E00DFC8000(void *data, size_t *len, HookParam *hp) + { + auto s = utf32_to_utf16((uint32_t *)data, *len / 4); + s = std::regex_replace(s, std::wregex(L"[\\s]"), L" "); + s = std::regex_replace(s, std::wregex(L"#KW"), L""); + s = std::regex_replace(s, std::wregex(L"#C\\(TR,0xff0000ff\\)"), L""); + s = std::regex_replace(s, std::wregex(L"#P\\(.*\\)"), L""); + auto u32 = utf16_to_utf32(s.c_str(), s.size()); + return write_string_overwrite(data, len, u32); + } + + bool F0100982015606000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\n+|(\\\\n)+"), L" "); + return write_string_overwrite(data, len, s); + } + bool F0100C4E013E5E000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\\\n"), L" "); + return write_string_overwrite(data, len, s); + } + + bool F010001D015260000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + if (startWith(s, "#Key")) + return false; + strReplace(s, "#n", "\n"); + return write_string_overwrite(data, len, s); + } + bool F0100E1E00E2AE000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("#n"), "\n"); + s = std::regex_replace(s, std::regex("[A-Za-z0-9]"), ""); + s = std::regex_replace(s, std::regex("[~^,\\-\\[\\]#]"), ""); + return write_string_overwrite(data, len, s); + } + bool F0100DE200C0DA000(void *data, size_t *len, HookParam *hp) + { + StringReplacer((char *)data, len, "#n", 2, " ", 1); + StringReplacer((char *)data, len, "\n", 1, " ", 1); + return true; + } + bool F0100AEC013DDA000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + static std::string ss; + if (ss == s) + return false; + ss = s; + return true; + } + + bool F0100F7801B5DC000(void *data, size_t *len, HookParam *hp) + { + if (!all_ascii((wchar_t *)data)) + return false; // chaos on first load. + StringReplacer((wchar_t *)data, len, L"
", 4, L"\n", 1); + return true; + } + + bool F0100925014864000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("(#n)+"), " "); + s = std::regex_replace(s, std::regex("(#[A-Za-z]+\\[(\\d*[.])?\\d+\\])+"), ""); + return write_string_overwrite(data, len, s); + } + + bool F0100936018EB4000(void *data, size_t *len, HookParam *hp) + { + auto s = utf32_to_utf16((uint32_t *)data, *len / 4); + s = std::regex_replace(s, std::wregex(L"<[^>]+>"), L""); + s = std::regex_replace(s, std::wregex(L"\n+"), L" "); + auto u32 = utf16_to_utf32(s.c_str(), s.size()); + return write_string_overwrite(data, len, u32); + } + template + void T01000BB01CB8A000(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = YUZU::emu_arg(stack)[index]; + std::wstring s; + while (auto c = *(uint16_t *)address) + { + if (c == 0x0 || c == 0xcccc) + { + break; + } + else if (c == 0xa || c == 0xd) + ; + else + { + s += (wchar_t)c + (wchar_t) * (uint16_t *)(address + 1); + } + address += 4; + } + write_string_new(data, len, s); + } + std::unordered_map T0100DEF01D0C6000_dict; + + void T0100DEF01D0C6000_2(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address1 = YUZU::emu_arg(stack)[0] + 0x14; + auto address2 = YUZU::emu_arg(stack)[1] + 0x14; + auto word = std::wstring((wchar_t *)address1); + auto meaning = std::wstring((wchar_t *)address2); + T0100DEF01D0C6000_dict[word] = meaning; + } + void T010061300DF48000(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address1 = YUZU::emu_arg(stack)[0]; + auto address2 = YUZU::emu_arg(stack)[1]; + auto word = std::string((char *)address1); + word = std::regex_replace(word, std::regex(R"(\w+\.\w+)"), ""); + while (!(*(BYTE *)address2)) + address2 += 1; + auto meaning = std::string((char *)address2); + meaning = std::regex_replace(meaning, std::regex(R"(%\w+)"), ""); + write_string_new(data, len, word + '\n' + meaning); + } + + template + void T0100B0100E26C000(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = YUZU::emu_arg(stack)[index]; + if (type == 2) + address += 0xA; + auto length = (*(DWORD *)(address + 0x10)) * 2; + *len = length; + *data = address + 0x14; + } + + bool F010045C014650000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex pattern("(@(\\/)?[a-zA-Z#](\\(\\d+\\))?|)[*<>]+"); + s = std::regex_replace(s, pattern, ""); + return write_string_overwrite(data, len, s); + } + + bool F0100AB100E2FA000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(LR"(\n)"), L""); + s = std::regex_replace(s, std::wregex(LR"(\u3000)"), L""); + s = std::regex_replace(s, std::wregex(LR"(<[^>]*>)"), L""); + return write_string_overwrite(data, len, s); + } + bool F01008C0016544000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"<[^>]+>"), L" "); + return write_string_overwrite(data, len, s); + } + bool F0100FB7019ADE000(void *data, size_t *len, HookParam *hp) + { + static int idx = 0; + return ((++idx) % 2 == 1); + } + bool F01006F000B056000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\[.*?\\]"), L" "); + return write_string_overwrite(data, len, s); + } + bool F0100068019996000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("%N"), "\n"); + return write_string_overwrite(data, len, s); + } + bool F0100ADC014DA0000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + std::wregex symbolRegex(L"[~^$(,)]"); + std::wregex alphanumericRegex(L"[A-Za-z0-9]"); + std::wregex atRegex(L"@"); + std::wregex leadingSpaceRegex(L"^\\s+"); + s = std::regex_replace(s, symbolRegex, L""); + s = std::regex_replace(s, alphanumericRegex, L""); + s = std::regex_replace(s, atRegex, L" "); + s = std::regex_replace(s, leadingSpaceRegex, L""); + return write_string_overwrite(data, len, s); + } + bool F0100AFA01750C000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex newlineRegex("(\\\\n)+"); + std::regex specialCharsRegex("\\\\d$|^\\@[a-z]+|#.*?#|\\$"); + s = std::regex_replace(s, newlineRegex, " "); + s = std::regex_replace(s, specialCharsRegex, ""); + return write_string_overwrite(data, len, s); + } + bool F0100B6900A668000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("#N"), "\n"); + std::regex colorRegex("#Color\\[[\\d]+\\]"); + s = std::regex_replace(s, colorRegex, ""); + return write_string_overwrite(data, len, s); + } + bool F0100BD700E648000(void *data, size_t *len, HookParam *hp) + { + StringReplacer((char *)data, len, "*", 1, " ", 1); + StringReplacer((char *)data, len, u8"ゞ", sizeof(u8"ゞ"), u8"!?", sizeof(u8"!?")); + return true; + } + bool F0100D9500A0F6000(void *data, size_t *len, HookParam *hp) + { + StringReplacer((char *)data, len, u8"㊤", sizeof(u8"㊤"), u8"―", sizeof(u8"―")); + StringReplacer((char *)data, len, u8"㊥", sizeof(u8"㊥"), u8"―", sizeof(u8"―")); + StringReplacer((char *)data, len, u8"^㌻", sizeof(u8"^㌻"), u8" ", sizeof(u8" ")); // \n + return true; + } + + bool F0100DA201E0DA000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); + return write_string_overwrite(data, len, s); + } + bool F01002C0008E52000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("(YUR)"), u8"ユーリ"); + s = std::regex_replace(s, std::regex("(FRE)"), u8"フレン"); + s = std::regex_replace(s, std::regex("(RAP)"), u8"ラピード"); + s = std::regex_replace(s, std::regex("(EST|ESU)"), u8"エステル"); + s = std::regex_replace(s, std::regex("(KAR)"), u8"カロル"); + s = std::regex_replace(s, std::regex("(RIT)"), u8"リタ"); + s = std::regex_replace(s, std::regex("(RAV|REI)"), u8"レイヴン"); + s = std::regex_replace(s, std::regex("(JUD)"), u8"ジュディス"); + s = std::regex_replace(s, std::regex("(PAT)"), u8"パティ"); + s = std::regex_replace(s, std::regex("(DUK|DYU)"), u8"デューク"); + s = std::regex_replace(s, std::regex("[A-Za-z0-9]"), ""); + s = std::regex_replace(s, std::regex("[,(-)_]"), ""); + s = std::regex_replace(s, std::regex("^\\s+"), ""); + while (std::regex_search(s, std::regex("^\\s*$"))) + { + s = std::regex_replace(s, std::regex("^\\s*$"), ""); + } + return write_string_overwrite(data, len, s); + } + + bool F01005940182EC000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + std::wregex whitespaceRegex(L"\\s"); + s = std::regex_replace(s, whitespaceRegex, L""); + std::wregex colorRegex(L"(.*?)<\\/color>"); + s = std::regex_replace(s, colorRegex, L"$1"); + return write_string_overwrite(data, len, s); + } + void T01005940182EC000(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = YUZU::emu_arg(stack)[0]; + *data = address + 0x14; + *len = wcslen((wchar_t *)*data) * 2; + } + bool F0100B0601852A000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + static std::wstring last; + if (last == s) + return false; + last = s; + return true; + } + bool F010027100C79A000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + static std::string last; + if (last == s) + return false; + last = s; + return true; + } + bool F0100B0C016164000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + std::wregex htmlTagsPattern(L"<[^>]*>"); + std::wregex lettersAndNumbersPattern(L"[A-Za-z0-9]"); + s = std::regex_replace(s, htmlTagsPattern, L""); + s = std::regex_replace(s, lettersAndNumbersPattern, L""); + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + + bool F010043B013C5C000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + std::wregex htmlTagsPattern(L"<[^>]*>"); + s = std::regex_replace(s, htmlTagsPattern, L""); + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F010055D009F78000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex pattern3("\\d+"); + s = std::regex_replace(s, pattern3, ""); + static std::string last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + + bool F010080C01AA22000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex furiganaRegex("#\\d+R.*?#"); + s = std::regex_replace(s, furiganaRegex, ""); + std::regex lettersNumbersRegex("[A-Za-z0-9]"); + s = std::regex_replace(s, lettersNumbersRegex, ""); + std::regex symbolsRegex(u8"[().%,_!#©&:?/]"); + s = std::regex_replace(s, symbolsRegex, ""); + return write_string_overwrite(data, len, s); + } + bool F0100CB700D438000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex furiganaRegex("(.*?)<\\/RB>(.*?)<\\/RT><\\/RUBY>"); + s = std::regex_replace(s, furiganaRegex, "$1"); + std::regex htmlTagRegex("<[^>]*>"); + s = std::regex_replace(s, htmlTagRegex, ""); + static std::string last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F01005C301AC5E000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(".*_.*_.*"), ""); // SIR_C01_016,ERU_C00_000 + s = std::regex_replace(s, std::regex("\\.mp4"), ""); + s = std::regex_replace(s, std::regex("@v"), ""); + s = std::regex_replace(s, std::regex("@n"), "\n"); + return write_string_overwrite(data, len, s); + } + bool F0100815019488000_text(void *data, size_t *len, HookParam *hp) + { + //@n@vaoi_s01_0110「うんうん、そうかも!」 + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("@.*_.*_\\d+"), ""); + s = std::regex_replace(s, std::regex("@n"), ""); + return write_string_overwrite(data, len, s); + } + bool F0100815019488000_name(void *data, size_t *len, HookParam *hp) + { + // あおい@n@vaoi_s01_0110「うんうん、そうかも!」 + auto s = std::string((char *)data, *len); + if (s.find("@n") == s.npos) + return false; + s = std::regex_replace(s, std::regex("(.*)@n.*"), "$1"); + return write_string_overwrite(data, len, s); + } + bool F010072000BD32000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex lineBreakRegex("\\[~\\]"); + s = std::regex_replace(s, lineBreakRegex, "\n"); + std::regex romRegex("rom:[\\s\\S]*$"); + s = std::regex_replace(s, romRegex, ""); + std::regex furiganaRegex("\\[[\\w\\d]*\\[[\\w\\d]*\\].*?\\[\\/\\[\\w\\d]*\\]\\]"); + s = std::regex_replace(s, furiganaRegex, ""); + std::regex bracketsRegex("\\[.*?\\]"); + s = std::regex_replace(s, bracketsRegex, ""); + static std::string last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F01009B50139A8000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + std::wregex htmlTagRegex(L"<[^>]*>"); + s = std::regex_replace(s, htmlTagRegex, L""); + std::wregex hoursRegex(L"\\b\\d{2}:\\d{2}\\b"); + s = std::regex_replace(s, hoursRegex, L""); + + auto _ = L"^(?:スキップ|むしる|取り出す|話す|選ぶ|ならびかえ|閉じる|やめる|undefined|決定|ボロのクワ|拾う)$(\\r?\\n|\\r)?"; + while (std::regex_search(s, std::wregex(_))) + { + s = std::regex_replace(s, std::wregex(_), L""); + } + while (std::regex_search(s, std::wregex(L"^\\s*$"))) + { + s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); + } + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F010032300C562000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + static std::string last; + s = std::regex_replace(s, std::regex(R"((#Ruby\[)([^,]+),(#\w+\[.\])?(.+?]))"), "$2"); + s = std::regex_replace(s, std::regex(R"(#\w+(\[.+?\])?)"), ""); + s = std::regex_replace(s, std::regex(R"(\u3000)"), ""); + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F010088B01A8FC000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + static std::string last; + s = std::regex_replace(s, std::regex(R"(#\w+(\[.+?\])?)"), ""); + s = std::regex_replace(s, std::regex(R"(\u3000)"), ""); + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool FF010061300DF48000_2(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + static std::string last; + if (last == s) + return false; + last = s; + return true; + } + bool F0100DEF01D0C6000_2(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + static std::wstring last; + if (last == s) + return false; + last = s; + if (T0100DEF01D0C6000_dict.find(s) == T0100DEF01D0C6000_dict.end()) + return false; + s += L'\n' + T0100DEF01D0C6000_dict[s]; + return write_string_overwrite(data, len, s); + } + bool F0100CEF0152DE000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(\u3000)"), ""); + s = std::regex_replace(s, std::regex(R"(#n)"), ""); + s = std::regex_replace(s, std::regex(R"(#\w.+?])"), ""); + return write_string_overwrite(data, len, s); + } + bool F010061300DF48000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(%\w+)"), ""); + s = std::regex_replace(s, std::regex(R"(\u3000)"), ""); + return write_string_overwrite(data, len, s); + } + bool F0100E4000F616000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + auto ws = StringToWideString(s, 932).value(); + ws = std::regex_replace(ws, std::wregex(LR"(\\\w)"), L""); + s = WideStringToString(ws, 932); + return write_string_overwrite(data, len, s); + } + bool F010027300A660000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(#n\u3000*)"), ""); + return write_string_overwrite(data, len, s); + } + bool F0100FA10185B0000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(#.+?])"), ""); + return write_string_overwrite(data, len, s); + } + bool F010095E01581C000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(\n)"), ""); + s = std::regex_replace(s, std::regex(R"(\\\w+)"), ""); + return write_string_overwrite(data, len, s); + } + bool F0100943010310000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + strReplace(s, u8"❞", "\""); + strReplace(s, u8"❝", "\""); + s = std::regex_replace(s, std::regex("@(.*?)@"), "$1\n"); + return write_string_overwrite(data, len, s); + } + template + bool F010027401A2A2000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + std::wregex dicRegex(L"\\[dic.*?text="); + s = std::regex_replace(s, dicRegex, L""); + std::wregex rubyRegex(L"\\[|'.*?\\]"); + s = std::regex_replace(s, rubyRegex, L""); + std::wregex closingBraceRegex(L"\\]"); + s = std::regex_replace(s, closingBraceRegex, L""); + if (choice) + { + std::wregex whitespaceRegex(L"\\s| "); + s = std::regex_replace(s, whitespaceRegex, L""); + } + else + { + std::wregex whitespaceRegex(LR"([^\S\n]| )"); + s = std::regex_replace(s, whitespaceRegex, L""); + } + return write_string_overwrite(data, len, s); + } + bool F0100BD4014D8C000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); + s = std::regex_replace(s, std::wregex(L".*?_"), L""); + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F010021D01474E000(void *data, size_t *len, HookParam *hp) + { + auto s = utf32_to_utf16((uint32_t *)data, *len / 4); + s = std::regex_replace(s, std::wregex(LR"(#\w\(.+?\)|#\w{2})"), L""); + s = std::regex_replace(s, std::wregex(LR"(\n)"), L""); + s = std::regex_replace(s, std::wregex(LR"(\u3000)"), L""); + static std::wstring last; + if (last == s) + return false; + last = s; + auto u32 = utf16_to_utf32(s.c_str(), s.size()); + return write_string_overwrite(data, len, u32); + } + bool F010021D01474E000_2(void *data, size_t *len, HookParam *hp) + { + auto s = utf32_to_utf16((uint32_t *)data, *len / 4); + s = std::regex_replace(s, std::wregex(LR"(\u3000)"), L""); + s = std::regex_replace(s, std::wregex(LR"(#\w.+?\)|#\w+)"), L""); + static std::wstring last; + if (last == s) + return false; + last = s; + auto u32 = utf16_to_utf32(s.c_str(), s.size()); + return write_string_overwrite(data, len, u32); + } + bool F01002C00177AE000(void *data, size_t *len, HookParam *hp) + { + auto s = utf32_to_utf16((uint32_t *)data, *len / 4); + s = std::regex_replace(s, std::wregex(LR"(\u3000)"), L""); + s = std::regex_replace(s, std::wregex(LR"(\n)"), L""); + static std::wstring last; + if (last == s) + return false; + last = s; + auto u32 = utf16_to_utf32(s.c_str(), s.size()); + return write_string_overwrite(data, len, u32); + } + bool F0100EA100DF92000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + static std::string last; + if (last.find(s) != last.npos) + return false; + last = s; + s = std::regex_replace(s, std::regex(R"([~^$(,)R])"), ""); + s = std::regex_replace(s, std::regex(R"(\\n)"), ""); + return write_string_overwrite(data, len, s); + } + template + bool F010079200C26E000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(#n)"), ""); + static std::string last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F010037500DF38000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(LR"(\n)"), L""); + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F0100C7400CFB4000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\d"), L""); + s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); + while (std::regex_search(s, std::wregex(L"^\\s*$"))) + { + s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); + } + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F0100CB9018F5A000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); + s = std::regex_replace(s, std::wregex(L"\\{([^{}]+):[^{}]+\\}"), L"$1"); + return write_string_overwrite(data, len, s); + } + + bool F010028D0148E6000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("{|\\/.*?}|\\[.*?]", std::regex_constants::grep), ""); + s = std::regex_replace(s, std::regex("(\\\\\\\\c|\\\\\\\\n)+"), " "); + s = std::regex_replace(s, std::regex(",.*$"), " "); + return write_string_overwrite(data, len, s); + } + + bool F0100F4401940A000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"[\\r\\n]+"), L""); + s = std::regex_replace(s, std::wregex(L"<[^>]+>|\\[\\[[^]]+\\]\\]"), L""); + return write_string_overwrite(data, len, s); + } + + bool F0100B5500CA0C000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex pattern1("\\\\u0000+$"); + std::regex pattern2("\\\\"); + std::regex pattern3("\\$"); + s = std::regex_replace(s, pattern1, ""); + s = std::regex_replace(s, pattern2, ""); + s = std::regex_replace(s, pattern3, ""); + return write_string_overwrite(data, len, s); + } + void T0100B5500CA0C000(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = YUZU::emu_arg(stack)[6]; + *data = address; + *len = *(WORD *)(address - 2); + } + bool F0100A8401A0A8000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + std::wregex samePageNewLineRegex(L"[\r\n]+"); + s = std::regex_replace(s, samePageNewLineRegex, L""); + std::wregex newPageTextRegex(L"(<.+?>)+"); + s = std::regex_replace(s, newPageTextRegex, L"\r\n"); + strReplace(s, L"", L"(L)"); + strReplace(s, L"", L"(ZL)"); + strReplace(s, L"", L"(Y)"); + strReplace(s, L"", L"(X)"); + strReplace(s, L"", L"(A)"); + strReplace(s, L"", L"(B)"); + strReplace(s, L"", L"(+)"); + strReplace(s, L"", L"(-)"); + strReplace(s, L"", L"(DPAD_DOWN)"); + strReplace(s, L"", L"(DPAD_LEFT)"); + strReplace(s, L"", L"(LSTICK)"); + strReplace(s, L"", L"(L3)"); + return write_string_overwrite(data, len, s); + } + bool F0100BC0018138000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + std::wregex tagContentRegex(L"<[^>]*>([^<]*)<\\/[^>]*>"); + s = std::regex_replace(s, tagContentRegex, L""); + s = std::regex_replace(s, std::wregex(L""), L"L"); + s = std::regex_replace(s, std::wregex(L""), L"R"); + s = std::regex_replace(s, std::wregex(L""), L"A"); + s = std::regex_replace(s, std::wregex(L""), L"B"); + s = std::regex_replace(s, std::wregex(L""), L"X"); + s = std::regex_replace(s, std::wregex(L""), L"Y"); + s = std::regex_replace(s, std::wregex(L""), L"+"); + s = std::regex_replace(s, std::wregex(L""), L"-"); + s = std::regex_replace(s, std::wregex(L"<[^>]+>"), L""); + return write_string_overwrite(data, len, s); + } + bool F0100D7800E9E0000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"[A-Za-z0-9]"), L""); + s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); + s = std::regex_replace(s, std::wregex(L"^二十五字二.*(\r?\n|\r)?"), L""); + s = std::regex_replace(s, std::wregex(L"^操作を割り当てる.*(\r?\n|\r)?"), L""); + s = std::regex_replace(s, std::wregex(L"^上記アイコンが出.*(\r?\n|\r)?"), L""); + s = std::regex_replace(s, std::wregex(L"[()~^,ö.!]"), L""); + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + template + void T0100CF400F7CE000(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = YUZU::emu_arg(stack)[idx]; + std::string s; + int i = 0; + while (1) + { + auto c = *(BYTE *)(address + i); + if (c == 0) + break; + if (c < 0x20 && c > 0x10) + { + auto command = *(BYTE *)(address + i + 1); + if (command == 0x80) + i += 3; + else if (command == 0xb8) + i += 4; + else + { + auto sz = *(BYTE *)(address + i + 2); + i += 3 + sz; + } + } + else if (c == 0xaa) + { + i += 1; + } + else if (c == 0xff) + { + i += 0x30; + } + else + { + auto l = 1 + IsDBCSLeadByteEx(932, c); + s += std::string((char *)(address + i), l); + i += l; + } + } + write_string_new(data, len, s); + } + void T0100DB300B996000(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = YUZU::emu_arg(stack)[8] + 1; + std::string s; + int i = 0; + while (1) + { + auto c = *(BYTE *)(address + i); + if (c == 0) + break; + if (c < 0x20 && c > 0x10) + { + auto sz = *(BYTE *)(address + i + 2); + i += 3 + sz; + } + else + { + auto l = 1 + IsDBCSLeadByteEx(932, c); + s += std::string((char *)(address + i), l); + i += l; + } + } + write_string_new(data, len, s); + } + bool F0100CBA014014000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(u8"《.*?》"), ""); + s = std::regex_replace(s, std::regex("<[^>]*>"), ""); + return write_string_overwrite(data, len, s); + } + template + bool F0100CC401A16C000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("<[^>]*>"), ""); + s = std::regex_replace(s, std::regex("\\d+"), ""); + if (s == "") + return false; + static std::string last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F0100BDD01AAE4000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("(#Ruby\\[)([^,]+).([^\\]]+)."), "$2"); + s = std::regex_replace(s, std::regex("(#n)+"), " "); + s = std::regex_replace(s, std::regex("(#[A-Za-z]+[(\\d*[.])?\\d+])+"), ""); + return write_string_overwrite(data, len, s); + } + bool F0100C310110B4000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("(#Ruby\\[)([^,]+).([^\\]]+)."), "$2"); + s = std::regex_replace(s, std::regex("#Color\\[[\\d]+\\]"), ""); + s = std::regex_replace(s, std::regex(u8"( #n)+"), "#n"); + s = std::regex_replace(s, std::regex("#n+"), " "); + return write_string_overwrite(data, len, s); + } + bool F010003F003A34000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"[\\s\\S]*$"), L""); + s = std::regex_replace(s, std::wregex(L"\n+"), L" "); + s = std::regex_replace(s, std::wregex(L"\\s"), L""); + s = std::regex_replace(s, std::wregex(L"[＀븅]"), L""); + return write_string_overwrite(data, len, s); + } + + bool F01007B601C608000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); + s = std::regex_replace(s, std::wregex(L"\\[.*?\\]"), L""); + std::vector lines = strSplit(s, L"\n"); + std::wstring result; + for (const std::wstring &line : lines) + { + if (result.empty() == false) + result += L"\n"; + std::wregex commandRegex(L"^(?:メニュー|システム|Ver\\.)$(\\r?\\n|\\r)?"); + s = std::regex_replace(s, commandRegex, L""); + std::wregex emptyLineRegex(L"^\\s*$"); + s = std::regex_replace(s, emptyLineRegex, L""); + } + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + + bool F010046601125A000(void *data, size_t *len, HookParam *hp) + { + auto s = utf32_to_utf16((uint32_t *)data, *len / 4); + s = std::regex_replace(s, std::wregex(L"(.+?).+?"), L"$1"); + s = std::regex_replace(s, std::wregex(L"\n+"), L" "); + auto u32 = utf16_to_utf32(s.c_str(), s.size()); + return write_string_overwrite(data, len, u32); + } + bool F0100771013FA8000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"
"), L"\n"); + s = std::regex_replace(s, std::wregex(L"^(\\s+)"), L""); + return write_string_overwrite(data, len, s); + } + bool F0100556015CCC000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex rubiRegex("\\[[^\\]]+."); + s = std::regex_replace(s, rubiRegex, ""); + s = std::regex_replace(s, std::regex("\\\\k|\\\\x|%C|%B|%p-1;"), ""); + std::regex colorRegex("#[0-9a-fA-F]+;([^%#]+)(%r)?"); + s = std::regex_replace(s, colorRegex, "$1"); + static std::set dump; + if (dump.find(s) != dump.end()) + return false; + dump.insert(s); + return write_string_overwrite(data, len, s); + } + template + bool F0100CC80140F8000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"^(?:スキップ|メニュー|バックログ|ズームイン|ズームアウト|ガイド OFF|早送り|オート|人物情報|ユニット表示切替|カメラリセット|ガイド表示切替|ページ切替|閉じる|コマンド選択|詳細|シミュレーション|移動)$([\\r?\\n|\\r])?"), L""); + + s = std::regex_replace(s, std::wregex(L"[A-Za-z0-9]"), L""); + s = std::regex_replace(s, std::wregex(L"[().%,_!#©&:?/]"), L""); + while (std::regex_search(s, std::wregex(L"^\\s*$"))) + { + s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); + } + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + + bool F0100D9A01BD86000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); + s = std::regex_replace(s, std::wregex(L"\\\\n"), L""); + return write_string_overwrite(data, len, s); + } + bool F010042300C4F6000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); + s = std::regex_replace(s, std::wregex(L"(.+?/)"), L""); + s = std::regex_replace(s, std::wregex(L"(\" .*)"), L""); + s = std::regex_replace(s, std::wregex(L"^(.+?\")"), L""); + return write_string_overwrite(data, len, s); + } + bool F010044800D2EC000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\n+"), L" "); + s = std::regex_replace(s, std::wregex(L"\\"), L"???"); + s = std::regex_replace(s, std::wregex(L"<.+?>"), L""); + return write_string_overwrite(data, len, s); + } + template + bool F010021300F69E000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\$[a-z]"), L""); + s = std::regex_replace(s, std::wregex(L"@"), L""); + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F010050000705E000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("\\s"), ""); + s = std::regex_replace(s, std::regex("
"), "\n"); + s = std::regex_replace(s, std::regex("<([^:>]+):[^>]+>"), "$1"); + s = std::regex_replace(s, std::regex("<[^>]+>"), ""); + return write_string_overwrite(data, len, s); + } + bool F01001B900C0E2000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex whitespaceRegex("\\s"); + s = std::regex_replace(s, whitespaceRegex, ""); + std::regex hashRegex("#[A-Za-z]+(\\[(\\d*\\.)?\\d+\\])+"); + s = std::regex_replace(s, hashRegex, ""); + std::regex hashLetterRegex("#[a-z]"); + s = std::regex_replace(s, hashLetterRegex, ""); + std::regex lowercaseRegex("[a-z]"); + s = std::regex_replace(s, lowercaseRegex, ""); + return write_string_overwrite(data, len, s); + } + + bool F0100217014266000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + std::wregex htmlTagRegex(L"<[^>]*>"); + s = std::regex_replace(s, htmlTagRegex, L""); + std::wregex furiganaRegex(L"{([^{}]+):[^{}]+}"); + s = std::regex_replace(s, furiganaRegex, L"$1"); + while (std::regex_search(s, std::wregex(L"^\\s+"))) + { + s = std::regex_replace(s, std::wregex(L"^\\s+"), L""); + } + return write_string_overwrite(data, len, s); + } + bool F010007500F27C000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + std::wregex htmlTagRegex(L"<[^>]*>"); + s = std::regex_replace(s, htmlTagRegex, L""); + auto _ = L"^(?:決定|進む|ページ移動|ノート全体図|閉じる|もどる|セーブ中)$(\\r?\\n|\\r)?"; + while (std::regex_search(s, std::wregex(_))) + { + s = std::regex_replace(s, std::wregex(_), L""); + } + while (std::regex_search(s, std::wregex(L"^\\s*$"))) + { + s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); + } + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F0100874017BE2000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\n+|(\\\\n)+"), L" "); + s = std::regex_replace(s, std::wregex(L"#n"), L""); + return write_string_overwrite(data, len, s); + } + bool F010094601D910000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\<.*?\\>"), L""); + s = std::regex_replace(s, std::wregex(L"\\[.*?\\]"), L""); + s = std::regex_replace(s, std::wregex(L"\\s"), L""); + return write_string_overwrite(data, len, s); + } + bool F010079201BD88000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); + s = std::regex_replace(s, std::wregex(L"\\\\n"), L""); + return write_string_overwrite(data, len, s); + } + bool F010086C00AF7C000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("\\[([^\\]]+)\\/[^\\]]+\\]"), "$1"); + s = std::regex_replace(s, std::regex("\\s+"), " "); + s = std::regex_replace(s, std::regex("\\\\n"), " "); + s = std::regex_replace(s, std::regex("<[^>]+>|\\[[^\\]]+\\]"), ""); + return write_string_overwrite(data, len, s); + } + bool F010079C017B98000(void *data, size_t *len, HookParam *hp) + { + auto s = utf32_to_utf16((uint32_t *)data, *len / 4); + s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); + s = std::regex_replace(s, std::wregex(L"#KW"), L""); + s = std::regex_replace(s, std::wregex(L"#C\\(TR,0xff0000ff\\)"), L""); + s = std::regex_replace(s, std::wregex(L"【SW】"), L""); + s = std::regex_replace(s, std::wregex(L"【SP】"), L""); + s = std::regex_replace(s, std::wregex(L"#P\\(.*\\)"), L""); + auto u32 = utf16_to_utf32(s.c_str(), s.size()); + return write_string_overwrite(data, len, u32); + } + bool F010061A01C1CE000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); + s = std::regex_replace(s, std::wregex(L"sound"), L" "); + return write_string_overwrite(data, len, s); + } + bool F0100F7401AA74000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("[\\s]"), ""); + s = std::regex_replace(s, std::regex("@[a-z]"), ""); + s = std::regex_replace(s, std::regex("@[0-9]"), ""); + return write_string_overwrite(data, len, s); + } + + bool F0100FC2019346000(void *data, size_t *len, HookParam *hp) + { + StringReplacer((char *)data, len, "#n", 2, " ", 1); + return true; + } + + bool F0100FDB00AA80000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("\\[([^\\]]+)\\/[^\\]]+\\]"), "$1"); + s = std::regex_replace(s, std::regex("<[^>]*>"), ""); + return write_string_overwrite(data, len, s); + } + bool F0100FF500E34A000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("\\[.*?\\]"), ""); + s = std::regex_replace(s, std::regex("\\n+"), " "); + return write_string_overwrite(data, len, s); + } + bool F01005E9016BDE000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex patt("/\\/\\/ remove rubi\\n\\ss = s.replace\\(patt, ''\\);/"); + s = std::regex_replace(s, patt, ""); + s = std::regex_replace(s, std::regex("\\\\k|\\\\x|%C|%B|%p-1;"), ""); + s = std::regex_replace(s, std::regex("#[0-9a-fA-F]+;([^%#]+)(%r)?"), "$1"); + s = std::regex_replace(s, std::regex("\\\\n"), " "); + return write_string_overwrite(data, len, s); + } + + bool F010065301A2E0000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\d+"), L""); + s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); + return write_string_overwrite(data, len, s); + } + bool F01002AE00F442000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + std::wregex pattern1(L"\\[([^\\]\\/]+)\\/[^\\]]+\\]"); + s = std::regex_replace(s, pattern1, L"$1"); + std::wregex pattern2(L"(\\S*)@"); + s = std::regex_replace(s, pattern2, L"$1"); + std::wregex pattern3(L"\\$"); + s = std::regex_replace(s, pattern3, L""); + return write_string_overwrite(data, len, s); + } + bool F01000A400AF2A000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"@[a-zA-Z]|%[a-zA-Z]+"), L""); + static std::wstring last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + + bool F01006B5014E2E000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("@r(.*?)@(.*?)@"), "$1"); + s = std::regex_replace(s, std::regex("@n"), ""); + s = std::regex_replace(s, std::regex("@v"), ""); + s = std::regex_replace(s, std::regex("TKY[0-9]{6}_[A-Z][0-9]{2}"), ""); + return write_string_overwrite(data, len, s); + } + bool F0100CF400F7CE000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("\\n+"), " "); + return write_string_overwrite(data, len, s); + } + bool F01000AE01954A000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("[A-Za-z0-9]"), ""); + s = std::regex_replace(s, std::regex("[~^(-).%,!:#@$/*&;+_]"), ""); + return write_string_overwrite(data, len, s); + } + bool F01003BD013E30000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("{|\\/.*?}|\\[.*?]"), ""); + return write_string_overwrite(data, len, s); + } + bool F010074F013262000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("\\[.*?]"), ""); + return write_string_overwrite(data, len, s); + } + bool F010057E00AC56000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("<[^>]*>"), ""); + s = std::regex_replace(s, std::regex(u8"ズーム|回転|身長|体重"), ""); + s = std::regex_replace(s, std::regex("[A-Za-z0-9]"), ""); + s = std::regex_replace(s, std::regex("[().%,!#/]"), ""); + while (std::regex_search(s, std::regex("^\\s*$"))) + { + s = std::regex_replace(s, std::regex("^\\s*$"), ""); + } + static std::string last; + if (last == s) + return false; + last = s; + return write_string_overwrite(data, len, s); + } + bool F010051D010FC2000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex("\\[([^\\]]+)\\/[^\\]]+\\]"), "$1"); + s = std::regex_replace(s, std::regex("\\s+"), " "); + s = std::regex_replace(s, std::regex("\\\\n"), " "); + s = std::regex_replace(s, std::regex("<[^>]+>|\\[[^\\]]+\\]"), ""); + return write_string_overwrite(data, len, s); + } + + bool F010096000CA38000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(LR"(\$\w{1,2})"), L""); + s = std::regex_replace(s, std::wregex(LR"(\$\[|\$\/.+?])"), L""); + return write_string_overwrite(data, len, s); + } + bool F0100EC001DE7E000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(LR"(<\w+=[^>]+>|<\/\w+>)"), L""); + return write_string_overwrite(data, len, s); + } + bool F0100DEF01D0C6000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(LR"(\n)"), L""); + s = std::regex_replace(s, std::wregex(LR"(\u3000)"), L""); + s = std::regex_replace(s, std::wregex(LR"(<.+?>)"), L""); + return write_string_overwrite(data, len, s); + } + bool F01005AF00E9DC000(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + s = std::regex_replace(s, std::regex(R"(#n)"), ""); + s = std::regex_replace(s, std::regex(R"(#\w+(\[.+?\])?)"), ""); + return write_string_overwrite(data, len, s); + } + bool F01001BA01EBFC000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(LR"(#n)"), L""); + s = std::regex_replace(s, std::wregex(LR"(#\w+(\[.+?\])?)"), L""); + return write_string_overwrite(data, len, s); + } + bool F01000BB01CB8A000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + static std::wstring last; + if (last == s) + return false; + last = s; + s = std::regex_replace(s, std::wregex(LR"(\u3000)"), L""); + return write_string_overwrite(data, len, s); + } + bool F010044701E9BC000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(LR"(\<.*?\>)"), L""); + s = std::regex_replace(s, std::wregex(LR"(\s)"), L""); + return write_string_overwrite(data, len, s); + } + bool F01003BB01DF54000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(LR"(\\\u3000*)"), L""); + s = std::regex_replace(s, std::wregex(LR"(\$)"), L""); + return write_string_overwrite(data, len, s); + } + bool F01004E5017C54000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(LR"(<.+?>)"), L""); + s = std::regex_replace(s, std::wregex(LR"(\u3000)"), L""); + return write_string_overwrite(data, len, s); + } + bool F0100FA001E160000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(LR"(\r\n)"), L""); + s = std::regex_replace(s, std::wregex(LR"(\u3000)"), L""); + return write_string_overwrite(data, len, s); + } + bool F0100B1F0123B6000(void *data, size_t *len, HookParam *hp) + { + if (all_ascii((wchar_t *)data)) + return false; + return F010096000CA38000(data, len, hp); + } + bool F0100A62019078000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(LR"([\s])"), L""); + s = std::regex_replace(s, std::wregex(LR"($$R)"), L""); + s = std::regex_replace(s, std::wregex(LR"(%)"), L""); + return write_string_overwrite(data, len, s); + } + bool F01001EF017BE6000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + while (std::regex_search(s, std::wregex(L"^\\s*$"))) + { + s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); + } + return write_string_overwrite(data, len, s); + } + bool F01000EA00D2EE000(void *data, size_t *len, HookParam *hp) + { + auto s = std::wstring((wchar_t *)data, *len / 2); + s = std::regex_replace(s, std::wregex(L"\\n+"), L" "); + s = std::regex_replace(s, std::wregex(L"\\"), L"???"); + s = std::regex_replace(s, std::wregex(L"\\"), L"chiaki_washa"); + s = std::regex_replace(s, std::wregex(L"<.+?>"), L""); + return write_string_overwrite(data, len, s); + } + auto _ = []() + { + emfunctionhooks = { + // Memories Off + {0x8003eeac, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100978013276000", "1.0.0"}}, + {0x8003eebc, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100978013276000", "1.0.1"}}, + // Memories Off ~Sorekara~ + {0x8003fb7c, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100B4A01326E000", "1.0.0"}}, + {0x8003fb8c, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100B4A01326E000", "1.0.1"}}, + // Famicom Tantei Club: Kieta Koukeisha + {0x80052a10, {CODEC_UTF16, 0, 0, mages_readstring<3>, 0, "0100B4500F7AE000", "1.0.0"}}, + // Famicom Tantei Club Part: Ushiro ni Tatsu Shoujo + {0x8004cb30, {CODEC_UTF16, 0, 0, mages_readstring<3>, 0, "010078400F7B0000", "1.0.0"}}, + // Memories Off 2nd + {0x8003ee0c, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100D31013274000", "1.0.0"}}, + {0x8003ee1c, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100D31013274000", "1.0.1"}}, + // Omoide ni Kawaru Kimi ~Memories Off~ + {0x8003ef6c, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100FFA013272000", "1.0.0"}}, + {0x8003ef7c, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100FFA013272000", "1.0.1"}}, + // Memories Off 6 ~T-Wave~ + {0x80043d7c, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "010047A013268000", "1.0.0"}}, + {0x80043d5c, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "010047A013268000", "1.0.1"}}, + // Memories Off: Yubikiri no Kioku + {0x800440ec, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "010079C012896000", "1.0.0"}}, + // Memories Off #5 Togireta Film + {0x8003f6ac, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "010073901326C000", "1.0.0"}}, + {0x8003f5fc, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "010073901326C000", "1.0.1"}}, + // SINce Memories: Hoshi no Sora no Shita de + {0x80048cc8, {CODEC_UTF16, 0, 0, mages_readstring<4>, 0, "0100E94014792000", 0}}, // line + name => join + {0x8004f44c, {CODEC_UTF16, 0, 0, mages_readstring<4>, 0, "0100E94014792000", 0}}, // fast trophy + {0x8004f474, {CODEC_UTF16, 0, 0, mages_readstring<4>, 0, "0100E94014792000", 0}}, // prompt + {0x80039dc0, {CODEC_UTF16, 0, 0, mages_readstring<4>, 0, "0100E94014792000", 0}}, // choice + + // Yahari Game demo Ore no Seishun Love Come wa Machigatteiru. + {0x8005DFB8, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100E0D0154BC000", "1.0.0"}}, + // CHAOS;HEAD NOAH + {0x80046700, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100957016B90000", "1.0.0"}}, + {0x8003A2c0, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100957016B90000", "1.0.0"}}, // choice + {0x8003EAB0, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100957016B90000", "1.0.0"}}, // TIPS list (menu) + {0x8004C648, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100957016B90000", "1.0.0"}}, // system message + {0x80050374, {CODEC_UTF16, 0, 0, mages_readstring<0>, 0, "0100957016B90000", "1.0.0"}}, // TIPS (red) + // Shiro to Kuro no Alice + {0x80013f20, {CODEC_UTF8, 0, 0, 0, NewLineCharFilterW, "0100A460141B8000", "1.0.0"}}, + {0x80013f94, {CODEC_UTF8, 0, 0, 0, NewLineCharFilterW, "0100A460141B8000", "1.0.0"}}, + {0x8001419c, {CODEC_UTF8, 0, 0, 0, NewLineCharFilterW, "0100A460141B8000", "1.0.0"}}, + // Shiro to Kuro no Alice -Twilight line- + {0x80014260, {CODEC_UTF8, 0, 0, 0, NewLineCharFilterW, "0100A460141B8000", "1.0.0"}}, + {0x800142d4, {CODEC_UTF8, 0, 0, 0, NewLineCharFilterW, "0100A460141B8000", "1.0.0"}}, + {0x800144dc, {CODEC_UTF8, 0, 0, 0, NewLineCharFilterW, "0100A460141B8000", "1.0.0"}}, + // CLANNAD + {0x80072d00, {CODEC_UTF16 | FULL_STRING, 1, 0, 0, F0100A3A00CC7E000, "0100A3A00CC7E000", "1.0.0"}}, + {0x80072d30, {CODEC_UTF16 | FULL_STRING, 1, 0, 0, F0100A3A00CC7E000, "0100A3A00CC7E000", "1.0.7"}}, + // VARIABLE BARRICADE NS + {0x800e3424, {CODEC_UTF8, 0, 0, 0, F010045C0109F2000, "010045C0109F2000", "1.0.1"}}, //"System Messages + Choices"), //Also includes the names of characters, + {0x800fb080, {CODEC_UTF8, 3, 0, 0, F010045C0109F2000, "010045C0109F2000", "1.0.1"}}, // Main Text + // AMNESIA for Nintendo Switch + {0x805bba5c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<2>, F0100A1E00BFEA000, "0100A1E00BFEA000", "1.0.1"}}, // dialogue + {0x805e9930, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100A1E00BFEA000, "0100A1E00BFEA000", "1.0.1"}}, // choice + {0x805e7fd8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100A1E00BFEA000, "0100A1E00BFEA000", "1.0.1"}}, // name + + // Chou no Doku Hana no Kusari Taishou Tsuya Koi Ibun + {0x80095010, {CODEC_UTF16, 1, 0, 0, F0100A1200CA3C000, "0100A1200CA3C000", "2.0.1"}}, // Main Text + Names + // Live a Live + {0x80a05170, {CODEC_UTF16, 0, 0, 0, F0100982015606000, "0100C29017106000", "1.0.0"}}, + // Sakura no Kumo * Scarlet no Koi + {0x804e4858, {CODEC_UTF8, 3, 1, 0, F01006590155AC000, "01006590155AC000", "1.0.0"}}, // name + {0x804e4870, {CODEC_UTF8, 0, 0, 0, F01006590155AC000, "01006590155AC000", "1.0.0"}}, // dialogue + // Majestic Majolical + {0x80557408, {CODEC_UTF8, 0, 0, 0, F01000200194AE000, "01000200194AE000", "1.0.0"}}, // name + {0x8059ee94, {CODEC_UTF8, 3, 0, 0, F01000200194AE000, "01000200194AE000", "1.0.0"}}, // player name + {0x80557420, {CODEC_UTF8, 0, 0, 0, F01000200194AE000, "01000200194AE000", "1.0.0"}}, // dialogue + + // Matsurika no Kei + {0x8017ad54, {CODEC_UTF32, 1, 0, 0, F0100EA001A626000, "0100EA001A626000", "1.0.0"}}, // text + {0x80174d4c, {CODEC_UTF32, 1, 0, 0, F0100EA001A626000, "0100EA001A626000", "1.0.0"}}, // name + // Cupid Parasite + {0x80057910, {CODEC_UTF32, 2, 0, 0, F0100F7E00DFC8000, "0100F7E00DFC8000", "1.0.1"}}, // name + text + {0x80169df0, {CODEC_UTF32, 0, 0, 0, F0100F7E00DFC8000, "0100F7E00DFC8000", "1.0.1"}}, // choice + // Radiant Tale + {0x80075190, {CODEC_UTF8, 1, 0, 0, F0100925014864000, "0100925014864000", "1.0.0"}}, // prompt + {0x8002fb18, {CODEC_UTF8, 0, 0, 0, F0100925014864000, "0100925014864000", "1.0.0"}}, // name + {0x8002fd7c, {CODEC_UTF8, 0, 0, 0, F0100925014864000, "0100925014864000", "1.0.0"}}, // text + {0x8004cf28, {CODEC_UTF8, 1, 0, 0, F0100925014864000, "0100925014864000", "1.0.0"}}, // text + // MUSICUS + {0x80462DD4, {CODEC_UTF8, 0, 1, 0, F01006590155AC000, "01000130150FA000", "1.0.0"}}, // name + {0x80462DEC, {CODEC_UTF8, 0, 0, 0, F01006590155AC000, "01000130150FA000", "1.0.0"}}, // dialogue 1 + {0x80480d4c, {CODEC_UTF8, 0, 0, 0, F01006590155AC000, "01000130150FA000", "1.0.0"}}, // dialogue 2 + {0x804798e0, {CODEC_UTF8, 0, 0, 0, F01006590155AC000, "01000130150FA000", "1.0.0"}}, // choice + + // Story of Seasons a Wonderful Life + {0x80ac4d88, {CODEC_UTF32, 0, 0, F0100936018EB4000, "0100936018EB4000", "1.0.3"}}, // Main text + {0x808f7e84, {CODEC_UTF32, 0, 0, F0100936018EB4000, "0100936018EB4000", "1.0.3"}}, // Item name + {0x80bdf804, {CODEC_UTF32, 0, 0, F0100936018EB4000, "0100936018EB4000", "1.0.3"}}, // Item description + // Hamefura Pirates + {0x81e75940, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100982015606000, "0100982015606000", "1.0.0"}}, // Hamekai.TalkPresenter$$AddMessageBacklog + {0x81c9ae60, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100982015606000, "0100982015606000", "1.0.0"}}, // Hamekai.ChoicesText$$SetText + {0x81eb7dc0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100982015606000, "0100982015606000", "1.0.0"}}, // Hamekai.ShortStoryTextView$$AddText + // Death end re;Quest 2 + {0x80225C3C, {CODEC_UTF8, 8, 0, 0, F010001D015260000, "010001D015260000", "1.0.0"}}, + // Death end re;Quest + {0x80241088, {CODEC_UTF8, 8, 0, 0, F0100AEC013DDA000, "0100AEC013DDA000", "1.0.0"}}, // english ver + // Meta Meet Cute!!!+ + {0x81DD6010, {CODEC_UTF16, 1, -32, 0, 0, "01009A401C1B0000", "1.02"}}, // english ver, only long string, short string can't find. + // Of the Red, the Light, and the Ayakashi Tsuzuri + {0x8176D78C, {CODEC_UTF16, 3, 0, 0, 0, "0100F7801B5DC000", "1.0.0"}}, + // Tokimeki Memorial Girl's Side: 4th Heart + {0x817e7da8, {CODEC_UTF16, 0, 0, T0100B0100E26C000<2, 0>, 0, "0100B0100E26C000", "1.0.0"}}, // name (x1) + dialogue (x2) + {0x81429f54, {CODEC_UTF16, 0, 0, T0100B0100E26C000<0, 1>, 0, "0100B0100E26C000", "1.0.0"}}, // choice (x0) + {0x8180633c, {CODEC_UTF16, 0, 0, T0100B0100E26C000<1, 2>, 0, "0100B0100E26C000", "1.0.0"}}, // help (x1) + // 13 Sentinels: Aegis Rim + {0x80057d18, {CODEC_UTF8, 0, 0, 0, F010045C014650000, "010045C014650000", "1.0.0"}}, // cutscene text + {0x8026fec0, {CODEC_UTF8, 1, 0, 0, F010045C014650000, "010045C014650000", "1.0.0"}}, // prompt + {0x8014eab4, {CODEC_UTF8, 0, 0, 0, F010045C014650000, "010045C014650000", "1.0.0"}}, // name (combat) + {0x801528ec, {CODEC_UTF8, 3, 0, 0, F010045C014650000, "010045C014650000", "1.0.0"}}, // dialogue (combat) + {0x80055acc, {CODEC_UTF8, 0, 0, 0, F010045C014650000, "010045C014650000", "1.0.0"}}, // dialogue 2 (speech bubble) + {0x802679c8, {CODEC_UTF8, 1, 0, 0, F010045C014650000, "010045C014650000", "1.0.0"}}, // notification + {0x8025e210, {CODEC_UTF8, 2, 0, 0, F010045C014650000, "010045C014650000", "1.0.0"}}, // scene context example: 数日前 咲良高校 1年B組 教室 1985年5月" + {0x8005c518, {CODEC_UTF8, 0, 0, 0, F010045C014650000, "010045C014650000", "1.0.0"}}, // game help + // Sea of Stars + {0x83e93ca0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01008C0016544000, "01008C0016544000", "1.0.45861"}}, // Main text + {0x820c3fa0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01008C0016544000, "01008C0016544000", "1.0.47140"}}, // Main text + // Final Fantasy I + {0x81e88040, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01000EA014150000", "1.0.1"}}, // Main text + {0x81cae54c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01000EA014150000", "1.0.1"}}, // Intro text + {0x81a3e494, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01000EA014150000", "1.0.1"}}, // battle text + {0x81952c28, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01000EA014150000", "1.0.1"}}, // Location + // Final Fantasy II + {0x8208f4cc, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01006B7014156000", "1.0.1"}}, // Main text + {0x817e464c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01006B7014156000", "1.0.1"}}, // Intro text + {0x81fb6414, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01006B7014156000", "1.0.1"}}, // battle text + // Final Fantasy III + {0x82019e84, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01002E2014158000", "1.0.1"}}, // Main text1 + {0x817ffcfc, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01002E2014158000", "1.0.1"}}, // Main text2 + {0x81b8b7e4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01002E2014158000", "1.0.1"}}, // battle text + {0x8192c4a8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01002E2014158000", "1.0.1"}}, // Location + // Final Fantasy IV + {0x81e44bf4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01004B301415A000", "1.0.2"}}, // Main text + {0x819f92c4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01004B301415A000", "1.0.2"}}, // Rolling text + {0x81e2e798, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01004B301415A000", "1.0.2"}}, // Battle text + {0x81b1e6a8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01004B301415A000", "1.0.2"}}, // Location + // Final Fantasy V + {0x81d63e24, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "0100AA201415C000", "1.0.2"}}, // Main text + {0x81adfb3c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "0100AA201415C000", "1.0.2"}}, // Location + {0x81a8fda8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "0100AA201415C000", "1.0.2"}}, // Battle text + // Final Fantasy VI + {0x81e6b350, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "0100AA001415E000", "1.0.2"}}, // Main text + {0x81ab40ec, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "0100AA001415E000", "1.0.2"}}, // Location + {0x819b8c88, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "0100AA001415E000", "1.0.2"}}, // Battle text + // Final Fantasy IX + {0x80034b90, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F01006F000B056000, "01006F000B056000", "1.0.1"}}, // Main Text + {0x802ade64, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01006F000B056000, "01006F000B056000", "1.0.1"}}, // Battle Text + {0x801b1b84, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01006F000B056000, "01006F000B056000", "1.0.1"}}, // Descriptions + {0x805aa0b0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01006F000B056000, "01006F000B056000", "1.0.1"}}, // Key Item Name + {0x805a75d8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01006F000B056000, "01006F000B056000", "1.0.1"}}, // Key Item Content + {0x8002f79c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01006F000B056000, "01006F000B056000", "1.0.1"}}, // Menu + {0x80ca88b0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01006F000B056000, "01006F000B056000", "1.0.1"}}, // Tutorial1 + {0x80ca892c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01006F000B056000, "01006F000B056000", "1.0.1"}}, // Tutorial2 + {0x80008d88, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F01006F000B056000, "01006F000B056000", "1.0.1"}}, // Location + // Norn9 Var Commons + {0x8003E874, {CODEC_UTF8, 0, 0, 0, F0100068019996000, "0100068019996000", "1.0.0"}}, // English + // 薄桜鬼 真改 万葉ノ抄 + {0x8004E8F0, {CODEC_UTF8, 1, 0, 0, F010001D015260000, "0100EA601A0A0000", "1.0.0"}}, + // Hakuouki Shinkai: Tsukikage no Shou / 薄桜鬼 真改 月影ノ抄 + {0x8019ecd0, {CODEC_UTF8, 1, 0, 0, F0100E1E00E2AE000, "0100E1E00E2AE000", "1.0.0"}}, // Text + // Chrono Cross: The Radical Dreamers Edition + {0x802b1254, {CODEC_UTF32, 1, 0, 0, 0, "0100AC20128AC000", "1.0.2"}}, // Text + // AIR + {0x800a6b10, {CODEC_UTF16, 1, 0, 0, F0100ADC014DA0000, "0100ADC014DA0000", "1.0.1"}}, // Text + Name + // Shinigami to Shoujo + {0x21cb08 - 0x204000 + 0x80004000, {0, 1, 0, 0, F0100AFA01750C000, "0100AFA01750C000", "1.0.2"}}, // Text,sjis + // Octopath Traveler II + {0x8088a4d4, {CODEC_UTF16, 0, 0, 0, 0, "0100A3501946E000", "1.0.0"}}, // main text + // NieR:Automata The End of YoRHa Edition + {0x808e7068, {CODEC_UTF16, 3, 0, 0, 0, "0100B8E016F76000", "1.0.2"}}, // Text + // Reine des Fleurs + {0x80026434, {CODEC_UTF8, 0, 0, 0, 0, "0100B5800C0E4000", "1.0.0"}}, // Dialogue text + // Code : Realize - Saikou no Hanataba + {0x80024eac, {CODEC_UTF8, 0, 0, 0, F0100B6900A668000, "0100B6900A668000", "1.0.0"}}, + // Diabolik Lovers Grand Edition + {0x80041080, {CODEC_UTF8, 1, 0, 0, F0100BD700E648000, "0100BD700E648000", "1.0.0"}}, // name + {0x80041080, {CODEC_UTF8, 0, 0, 0, F0100BD700E648000, "0100BD700E648000", "1.0.0"}}, // dialogue + {0x80041080, {CODEC_UTF8, 2, 0, 0, F0100BD700E648000, "0100BD700E648000", "1.0.0"}}, // choice1 + // Shinobi, Koi Utsutsu + {0x8002aca0, {CODEC_UTF8, 0, 0, 0, F0100B6900A668000, "0100C1E0102B8000", "1.0.0"}}, // name + {0x8002aea4, {CODEC_UTF8, 0, 0, 0, F0100B6900A668000, "0100C1E0102B8000", "1.0.0"}}, // dialogue1 + {0x8001ca90, {CODEC_UTF8, 2, 0, 0, F0100B6900A668000, "0100C1E0102B8000", "1.0.0"}}, // dialogue2 + {0x80049dbc, {CODEC_UTF8, 1, 0, 0, F0100B6900A668000, "0100C1E0102B8000", "1.0.0"}}, // choice + // Yoru, Tomosu + {0xe2748eb0, {CODEC_UTF32, 1, 0, 0, 0, "0100C2901153C000", "1.0.0"}}, // text1 + // Closed Nightmare + {0x800c0918, {CODEC_UTF8, 0, 0, 0, F0100D9500A0F6000, "0100D9500A0F6000", "1.0.0"}}, // line + name + {0x80070b98, {CODEC_UTF8, 0, 0, 0, F0100D9500A0F6000, "0100D9500A0F6000", "1.0.0"}}, // fast trophy + {0x800878fc, {CODEC_UTF8, 0, 0, 0, F0100D9500A0F6000, "0100D9500A0F6000", "1.0.0"}}, // prompt + {0x80087aa0, {CODEC_UTF8, 0, 0, 0, F0100D9500A0F6000, "0100D9500A0F6000", "1.0.0"}}, // choice + // Yuru Camp△ - Have a Nice Day! + {0x816d03f8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100982015606000, "0100D12014FC2000", "1.0.0"}}, // dialog / backlog + // Akuyaku Reijou wa Ringoku no Outaishi ni Dekiai Sareru + {0x817b35c4, {CODEC_UTF8, 1, 0, 0, F0100DA201E0DA000, "0100DA201E0DA000", "1.0.0"}}, // Dialogue + // Yunohana Spring! ~Mellow Times~ + {0x80028178, {CODEC_UTF8, 0, 0, 0, F0100DE200C0DA000, "0100DE200C0DA000", "1.0.0"}}, // name + {0x8001b9d8, {CODEC_UTF8, 2, 0, 0, F0100DE200C0DA000, "0100DE200C0DA000", "1.0.0"}}, // dialogue1 + {0x8001b9b0, {CODEC_UTF8, 2, 0, 0, F0100DE200C0DA000, "0100DE200C0DA000", "1.0.0"}}, // dialogue2 + {0x8004b940, {CODEC_UTF8, 2, 0, 0, F0100DE200C0DA000, "0100DE200C0DA000", "1.0.0"}}, // dialogue3 + {0x8004a8d0, {CODEC_UTF8, 1, 0, 0, F0100DE200C0DA000, "0100DE200C0DA000", "1.0.0"}}, // choice + // サマータイムレンダ Another Horizon + {0x818ebaf0, {CODEC_UTF16, 0, 0, T01005940182EC000, F01005940182EC000, "01005940182EC000", "1.0.0"}}, // dialogue + // Aquarium + {0x8051a990, {CODEC_UTF8, 0, 1, 0, F01006590155AC000, "0100D11018A7E000", "1.0.0"}}, // name + {0x8051a9a8, {CODEC_UTF8, 0, 0, 0, F01006590155AC000, "0100D11018A7E000", "1.0.0"}}, // dialogue + {0x80500178, {CODEC_UTF8, 0, 0, 0, F01006590155AC000, "0100D11018A7E000", "1.0.0"}}, // choice + // AKA + {0x8166eb80, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0601852A000, "0100B0601852A000", "1.0.0"}}, // Main text + {0x817d44a4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0601852A000, "0100B0601852A000", "1.0.0"}}, // Letter + {0x815cb0f4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0601852A000, "0100B0601852A000", "1.0.0"}}, // Mission title + {0x815cde30, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0601852A000, "0100B0601852A000", "1.0.0"}}, // Mission description + {0x8162a910, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0601852A000, "0100B0601852A000", "1.0.0"}}, // Craft description + {0x817fdca8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0601852A000, "0100B0601852A000", "1.0.0"}}, // Inventory item name + // Etrian Odyssey I HD + {0x82d57550, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "01008A3016162000", "1.0.2"}}, // Text + {0x824ff408, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "01008A3016162000", "1.0.2"}}, // Config Description + {0x8296b4e4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "01008A3016162000", "1.0.2"}}, // Class Description + {0x81b2204c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "01008A3016162000", "1.0.2"}}, // Item Description + // Etrian Odyssey II HD + {0x82f24c70, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "0100B0C016164000", "1.0.2"}}, // Text + {0x82cc0988, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "0100B0C016164000", "1.0.2"}}, // Config Description + {0x8249acd4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "0100B0C016164000", "1.0.2"}}, // Class Description + {0x81b27644, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "0100B0C016164000", "1.0.2"}}, // Item Description + // Etrian Odyssey III HD + {0x83787f04, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "0100D32015A52000", "1.0.2"}}, // Text + {0x8206915c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "0100D32015A52000", "1.0.2"}}, // Config Description + {0x82e6d1d4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "0100D32015A52000", "1.0.2"}}, // Class Description + {0x82bf5d48, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100B0C016164000, "0100D32015A52000", "1.0.2"}}, // Item Description + // Fire Emblem Engage + {0x8248c550, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<2>, 0, "0100A6301214E000", "1.3.0"}}, // App.Talk3D.TalkLog$$AddLog + {0x820C6530, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<2>, 0, "0100A6301214E000", "2.0.0"}}, // App.Talk3D.TalkLog$$AddLog + // AMNESIA LATER×CROWD for Nintendo Switch + {0x800ebc34, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100982015606000, "0100B5700CDFC000", "1.0.0"}}, // waterfall + {0x8014dc64, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100982015606000, "0100B5700CDFC000", "1.0.0"}}, // name + {0x80149b10, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100982015606000, "0100B5700CDFC000", "1.0.0"}}, // dialogue + {0x803add50, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100982015606000, "0100B5700CDFC000", "1.0.0"}}, // choice + // Hanayaka Nari, Waga Ichizoku Gentou Nostalgie + {0x27ca10 - 0x204000 + 0x80004000, {CODEC_UTF8, 0, 0, T0100B5500CA0C000, F0100B5500CA0C000, "0100B5500CA0C000", "1.0.0"}}, // x3 (double trigged), name+text, onscreen + // Natsumon! 20th Century Summer Vacation + {0x80db5d34, {CODEC_UTF16, 0, 0, 0, F0100A8401A0A8000, "0100A8401A0A8000", "1.1.0"}}, // tutorial + {0x846fa578, {CODEC_UTF16, 0, 0, 0, F0100A8401A0A8000, "0100A8401A0A8000", "1.1.0"}}, // choice + {0x8441e800, {CODEC_UTF16, 0, 0, 0, F0100A8401A0A8000, "0100A8401A0A8000", "1.1.0"}}, // examine + dialog + // Super Mario RPG + {0x81d78c58, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Main Text + {0x81dc9cf8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Name + {0x81c16b80, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Cutscene + {0x821281f0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Special/Item/Menu/Objective Description + {0x81cd8148, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Special Name + {0x81fc2820, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Item Name Battle + {0x81d08d28, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Item Name Off-battle + {0x82151aac, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Shop Item Name + {0x81fcc870, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Objective Title + {0x821bd328, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Monster List - Name + {0x820919b8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Monster List - Description + {0x81f56518, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Info + {0x82134ce0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Help Category + {0x82134f30, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Help Name + {0x821372e4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Help Description 1 + {0x82137344, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Help Description 2 + {0x81d0ee80, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<2>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Location + {0x82128f64, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Album Title + {0x81f572a0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<3>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Load/Save Text + {0x81d040a8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Levelup First Part + {0x81d043fc, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Levelup Second Part + {0x81d04550, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Levelup New Ability Description + {0x81fbfa18, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Yoshi Mini-Game Header + {0x81fbfa74, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Yoshi Mini-Game Text + {0x81cf41b4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BC0018138000, "0100BC0018138000", "1.0.0"}}, // Enemy Special Attacks + // Trials of Mana + {0x800e8abc, {CODEC_UTF16, 1, 0, 0, F0100D7800E9E0000, "0100D7800E9E0000", "1.1.1"}}, // Text + // Utsusemi no Meguri + {0x821b452c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "0100DA101D9AA000", "1.0.0"}}, // text1 + {0x821b456c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "0100DA101D9AA000", "1.0.0"}}, // text2 + {0x821b45ac, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "0100DA101D9AA000", "1.0.0"}}, // text3 + // Buddy Mission BOND + {0x80046dd0, {0, 0, 0, T0100DB300B996000, 0, "0100DB300B996000", 0}}, // 1.0.0, 1.0.1,sjis + {0x80046de0, {0, 0, 0, T0100DB300B996000, 0, "0100DB300B996000", 0}}, + // Bravely Default II + {0x80b97700, {CODEC_UTF16, 0, 0, 0, 0, "010056F00C7B4000", "1.0.0"}}, // Main Text + {0x80bb8d3c, {CODEC_UTF16, 0, 0, 0, 0, "010056F00C7B4000", "1.0.0"}}, // Main Ptc Text + {0x810add68, {CODEC_UTF16, 0, 0, 0, 0, "010056F00C7B4000", "1.0.0"}}, // Secondary Text + // Tantei Bokumetsu / 探偵撲滅 + {0x8011c340, {CODEC_UTF8, 1, 0, 0, F0100CBA014014000, "0100CBA014014000", "1.0.0"}}, // Text + {0x80064f20, {CODEC_UTF8, 1, 0, 0, F0100CBA014014000, "0100CBA014014000", "1.0.0"}}, // Choices + // Ys X: Nordics + {0x80817758, {CODEC_UTF8, 1, 0, 0, F0100CC401A16C000<0>, "0100CC401A16C000", "1.0.4"}}, // Main Text + {0x80981e3c, {CODEC_UTF8, 0, 0, 0, F0100CC401A16C000<1>, "0100CC401A16C000", "1.0.4"}}, // Secondary Text + // 9 R.I.P + {0x80025360, {CODEC_UTF8, 2, 0, 0, F0100BDD01AAE4000, "0100BDD01AAE4000", "1.0.0"}}, // name + {0x80023c60, {CODEC_UTF8, 0, 0, 0, F0100BDD01AAE4000, "0100BDD01AAE4000", "1.0.0"}}, // text + {0x8005388c, {CODEC_UTF8, 1, 0, 0, F0100BDD01AAE4000, "0100BDD01AAE4000", "1.0.0"}}, // choice + {0x80065010, {CODEC_UTF8, 0, 0, 0, F0100BDD01AAE4000, "0100BDD01AAE4000", "1.0.0"}}, // character description + {0x8009c780, {CODEC_UTF8, 0, 0, 0, F0100BDD01AAE4000, "0100BDD01AAE4000", "1.0.0"}}, // prompt + // Kiss Bell - Let's sound the kissing-bell of the promise / キスベル + {0x8049d958, {CODEC_UTF8, 1, 0, 0, F01006590155AC000, "0100BD7015E6C000", "1.0.0"}}, // text + // Piofiore no Banshou -Ricordo- CN + {0x80015fa0, {CODEC_UTF8, 2, 0, 0, F0100C310110B4000, "0100C310110B4000", "1.0.0"}}, // handlerMsg + {0x80050d50, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "0100C310110B4000", "1.0.0"}}, // handlerName + {0x8002F430, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "0100C310110B4000", "1.0.0"}}, // handlerPrompt + {0x8002F4F0, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "0100C310110B4000", "1.0.0"}}, // handlerPrompt + {0x8002F540, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "0100C310110B4000", "1.0.0"}}, // handlerPrompt + // Piofiore no Banshou -Ricordo- + {0x800141d0, {CODEC_UTF8, 2, 0, 0, F0100C310110B4000, "01005F700DC56000", "1.0.0"}}, // handlerMsg + {0x8004ce20, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "01005F700DC56000", "1.0.0"}}, // handlerName + {0x8002be90, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "01005F700DC56000", "1.0.0"}}, // handlerPrompt + {0x8002bf50, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "01005F700DC56000", "1.0.0"}}, // handlerPrompt + {0x8002bfa0, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "01005F700DC56000", "1.0.0"}}, // handlerPrompt + // Piofiore no Banshou -Episodio1926- + {0x80019630, {CODEC_UTF8, 2, 0, 0, F0100C310110B4000, "01009E30120F4000", "1.0.0"}}, // handlerMsg + {0x8005B7B0, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "01009E30120F4000", "1.0.0"}}, // handlerName + {0x80039230, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "01009E30120F4000", "1.0.0"}}, // handlerPrompt + {0x800392F0, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "01009E30120F4000", "1.0.0"}}, // handlerPrompt + {0x80039340, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "01009E30120F4000", "1.0.0"}}, // handlerPrompt + // Pokémon Let’s Go, Pikachu! + {0x8067d9fc, {CODEC_UTF16, 0, 0, 0, F010003F003A34000, "010003F003A34000", "1.0.2"}}, // Text + // Ikemen Sengoku Toki o Kakeru Koi / イケメン戦国◆時をかける恋 新たなる出逢い + {0x813e4fb4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01008BE016CE2000", "1.0.0"}}, // Main Text + {0x813e4c60, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01008BE016CE2000", "1.0.0"}}, // Name + {0x813b5360, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "01008BE016CE2000", "1.0.0"}}, // Choices + {0x81bab9ac, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, 0, "01008BE016CE2000", "1.0.0"}}, // Info + // Shin Megami Tensei V + {0x80ce01a4, {CODEC_UTF16, 0, 0, 0, 0, "01006BD0095F4000", "1.0.2"}}, // Text + // The Legend of Zelda: Link's Awakening + {0x80f57910, {CODEC_UTF8, 1, 0, 0, 0, "01006BB00C6F0000", "1.0.1"}}, // Main Text + // Cendrillon palikA + {0x8001ab8c, {CODEC_UTF8, 2, 0, 0, F0100DE200C0DA000, "01006B000A666000", "1.0.0"}}, // name + {0x80027b30, {CODEC_UTF8, 0, 0, 0, F0100DE200C0DA000, "01006B000A666000", "1.0.0"}}, // dialogue + // Crayon Shin-chan Shiro of Coal Town + {0x83fab4bc, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F01007B601C608000, "01007B601C608000", "1.0.1"}}, + // Fuuraiki 4 + {0x80008c80, {CODEC_UTF32, 1, 0, 0, F010046601125A000, "010046601125A000", "1.0.0"}}, // Main + {0x80012b1c, {CODEC_UTF32, 1, 0, 0, F010046601125A000, "010046601125A000", "1.0.0"}}, // Wordpad + {0x80012ccc, {CODEC_UTF32, 1, 0, 0, F010046601125A000, "010046601125A000", "1.0.0"}}, // Comments + {0x80009f74, {CODEC_UTF32, 1, 0, 0, F010046601125A000, "010046601125A000", "1.0.0"}}, // Choices + {0x80023d64, {CODEC_UTF32, 0, 0, 0, F010046601125A000, "010046601125A000", "1.0.0"}}, // Location + // Ken ga Kimi for S / 剣が君 for S + {0x81477128, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100771013FA8000, "0100771013FA8000", "1.1"}}, // Main Text + {0x81470e38, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100771013FA8000, "0100771013FA8000", "1.1"}}, // Secondary Text + // ANONYMOUS;CODE + {0x80011608, {CODEC_UTF8, 1, 0, 0, F0100556015CCC000, "0100556015CCC000", "1.0.0"}}, // dialouge, menu + // Sugar * Style (シュガー*スタイル) + {0x800ccbc8, {0, 0, 0, 0, 0, "0100325012B70000", "1.0.0"}}, // ret x0 name + text (readShiftJisString), filter is to complex, quit. + // Nightshade/百花百狼 + {0x802999c8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F010042300C4F6000, "010042300C4F6000", "1.0.1"}}, // dialogue + {0x8015b544, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010042300C4F6000, "010042300C4F6000", "1.0.1"}}, // name + {0x802a2fd4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F010042300C4F6000, "010042300C4F6000", "1.0.1"}}, // choice1 + {0x802b7900, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F010042300C4F6000, "010042300C4F6000", "1.0.1"}}, // choice2 + // Toraware no Paruma + {0x8015b7a8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010044800D2EC000, "010044800D2EC000", "1.0.0"}}, // text x0 + {0x8015b46c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F010044800D2EC000, "010044800D2EC000", "1.0.0"}}, // name x1 + // Brothers Conflict: Precious Baby + {0x8016aecc, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100982015606000, "010037400DAAE000", "1.0.0"}}, // name + {0x80126b9c, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100982015606000, "010037400DAAE000", "1.0.0"}}, // dialogue + {0x80129160, {CODEC_UTF16, 0, 0, ReadTextAndLenW<2>, F0100982015606000, "010037400DAAE000", "1.0.0"}}, // choice + // Zettai Kaikyu Gakuen + {0x80067b5c, {CODEC_UTF16, 1, 0, 0, F010021300F69E000<0>, "010021300F69E000", "1.0.0"}}, // name+ dialogue main(ADV)+choices + {0x80067cd4, {CODEC_UTF16, 1, 0, 0, F010021300F69E000<1>, "010021300F69E000", "1.0.0"}}, // dialogueNVL + // Dragon Quest Builders 2 + {0x805f8900, {CODEC_UTF8, 1, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Main text textbox + {0x8068a698, {CODEC_UTF8, 0, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Not press to continue text + {0x806e4118, {CODEC_UTF8, 3, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Character creation text + {0x8067459c, {CODEC_UTF8, 1, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Objective progress1 + {0x800a4f90, {CODEC_UTF8, 0, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Objective progress2 + {0x8060a1c0, {CODEC_UTF8, 0, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Infos1 + {0x805f6130, {CODEC_UTF8, 1, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Infos2 + {0x80639b6c, {CODEC_UTF8, 2, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Item description + {0x807185ac, {CODEC_UTF8, 1, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Mission1 + {0x80657e4c, {CODEC_UTF8, 1, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Mission2 + {0x80713be0, {CODEC_UTF8, 1, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Mission3 + {0x8076ab04, {CODEC_UTF8, 1, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Tutorial header + {0x8076ab2c, {CODEC_UTF8, 1, 0, 0, F010050000705E000, "010050000705E000", "1.7.3"}}, // Tutorial explanation + // BUSTAFELLOWS season2 + {0x819ed3e4, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100874017BE2000, "010037400DAAE000", "1.0.0"}}, // dialogue + {0x82159cd0, {CODEC_UTF16, 0, 0, ReadTextAndLenW<1>, F0100874017BE2000, "010037400DAAE000", "1.0.0"}}, // textmessage + {0x81e17530, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100874017BE2000, "010037400DAAE000", "1.0.0"}}, // option + {0x81e99d64, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100874017BE2000, "010037400DAAE000", "1.0.0"}}, // choice + {0x8186f81c, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100874017BE2000, "010037400DAAE000", "1.0.0"}}, // archives + // 5分後に意外な結末 モノクロームの図書館 + {0x81fa4890, {CODEC_UTF16, 1, 0X14, 0, F010094601D910000, "010094601D910000", "1.0.1"}}, // book text + {0x81fa5250, {CODEC_UTF16, 1, 0X14, 0, F010094601D910000, "010094601D910000", "1.0.1"}}, // book text + {0x81b1c68c, {CODEC_UTF16, 0, 0X14, 0, F010094601D910000, "010094601D910000", "1.0.1"}}, // choice1 + {0x81b1c664, {CODEC_UTF16, 0, 0X14, 0, F010094601D910000, "010094601D910000", "1.0.1"}}, // choice2 + {0x81b1e5b0, {CODEC_UTF16, 3, 0X14, 0, F010094601D910000, "010094601D910000", "1.0.1"}}, // dialogue + // Tokimeki Memorial Girl’s Side 2nd Season for Nintendo Switch + {0x82058848, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010079201BD88000, "010079201BD88000", "1.0.1"}}, // dialogue1 + {0x82058aa0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010079201BD88000, "010079201BD88000", "1.0.1"}}, // dialogue2 + {0x8205a244, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010079201BD88000, "010079201BD88000", "1.0.1"}}, // dialogue3 + {0x826ee1d8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010079201BD88000, "010079201BD88000", "1.0.1"}}, // choice + {0x8218e258, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010079201BD88000, "010079201BD88000", "1.0.1"}}, // news + {0x823b61d4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010079201BD88000, "010079201BD88000", "1.0.1"}}, // mail + {0x82253454, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010079201BD88000, "010079201BD88000", "1.0.1"}}, // luckyitem + {0x82269240, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010079201BD88000, "010079201BD88000", "1.0.1"}}, // profile1 + {0x82269138, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010079201BD88000, "010079201BD88000", "1.0.1"}}, // profile2 + {0x822691ec, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010079201BD88000, "010079201BD88000", "1.0.1"}}, // profile3 + {0x82269198, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010079201BD88000, "010079201BD88000", "1.0.1"}}, // profile4 + // Uta no☆Prince-sama♪ Repeat Love / うたの☆プリンスさまっ♪Repeat LOVE + {0x800374a0, {0, 0, 0, 0, F0100068019996000, "010024200E00A000", "1.0.0"}}, // Main Text + Name,sjis + {0x8002ea08, {0, 0, 0, 0, F0100068019996000, "010024200E00A000", "1.0.0"}}, // Choices,sjis + // ワンド オブ フォーチュン R2 ~時空に沈む黙示録~ for Nintendo Switch + {0x821540c4, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100DA201E0DA000, "010088A01A774000", "1.0.0"}}, // dialogue + {0x8353e674, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100DA201E0DA000, "010088A01A774000", "1.0.0"}}, // choice + {0x835015e8, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100DA201E0DA000, "010088A01A774000", "1.0.0"}}, // name + // Yo-kai Watch 4++ + {0x80a88080, {CODEC_UTF8, 1, 0, 0, F010086C00AF7C000, "010086C00AF7C000", "2.2.0"}}, // All Text + // Cupid Parasite -Sweet & Spicy Darling- + {0x80138150, {CODEC_UTF32, 2, 0, 0, F010079C017B98000, "010079C017B98000", "1.0.0"}}, // name + text + {0x801a1bf0, {CODEC_UTF32, 0, 0, 0, F010079C017B98000, "010079C017B98000", "1.0.0"}}, // choice + // DesperaDrops + {0x8199c95c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F010061A01C1CE000, "010061A01C1CE000", "1.0.0"}}, // text1 + {0x81d5c900, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F010061A01C1CE000, "010061A01C1CE000", "1.0.0"}}, // text2 + {0x820d6324, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F010061A01C1CE000, "010061A01C1CE000", "1.0.0"}}, // choice + // Dragon Ball Z: Kakarot + {0x812a8e28, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Main Text + {0x812a8c90, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Name + {0x80bfbff0, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Ptc Text + {0x80bfbfd4, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Ptc Name + {0x8126a538, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Info + {0x8106fcbc, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // More Info + {0x80fad204, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Hint Part1 + {0x80fad2d0, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Hint Part2 + {0x80facf1c, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Loading Title + {0x80fad018, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Loading Description + {0x81250c50, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Tutorial h1 + {0x81250df0, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Tutorial h2 + {0x81251e80, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Tutorial Description1 + {0x81252214, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Tutorial Description2 + {0x810ae1c4, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Config Description + {0x812a9bb8, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Menu Talk + {0x812a9b78, {CODEC_UTF16, 0, 0, 0, F01008C0016544000, "0100EF00134F4000", "1.50"}}, // Menu Name + // Harvestella + {0x80af7abc, {CODEC_UTF16, 0, 0, 0, F0100B0601852A000, "0100EDD018032000", "1.0.1"}}, // Main Text + {0x80c0beb8, {CODEC_UTF16, 0, 0, 0, F0100B0601852A000, "0100EDD018032000", "1.0.1"}}, // Tutorial + News + {0x80b87f94, {CODEC_UTF16, 0, 0, 0, F0100B0601852A000, "0100EDD018032000", "1.0.1"}}, // Tutorial Part 2 + {0x80e1c378, {CODEC_UTF16, 0, 0, 0, F0100B0601852A000, "0100EDD018032000", "1.0.1"}}, // Mission Title + {0x80a7d7f4, {CODEC_UTF16, 0, 0, 0, F0100B0601852A000, "0100EDD018032000", "1.0.1"}}, // Mission Description + {0x80e39130, {CODEC_UTF16, 0, 0, 0, F0100B0601852A000, "0100EDD018032000", "1.0.1"}}, // Item Name + {0x80e38f80, {CODEC_UTF16, 0, 0, 0, F0100B0601852A000, "0100EDD018032000", "1.0.1"}}, // Item Description Part1 + {0x80e38ea8, {CODEC_UTF16, 0, 0, 0, F0100B0601852A000, "0100EDD018032000", "1.0.1"}}, // Item Description Part2 + // Sen no Hatou, Tsukisome no Kouki + {0x8003fc90, {CODEC_UTF8, 1, 0, 0, 0, "0100F8A017BAA000", "1.0.0"}}, // text1 + {0x8017a740, {CODEC_UTF8, 0, 0, 0, 0, "0100F8A017BAA000", "1.0.0"}}, // text2 + // Olympia Soiree + {0x8002ad04, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "0100F9D00C186000", "1.0.0"}}, + // Getsuei no Kusari -Sakuran Paranoia- + {0x21801c - 0x204000 + 0x80004000, {0, 2, 0, 0, F0100F7401AA74000, "0100F7401AA74000", "1.0.0"}}, // text,sjis + {0x228fac - 0x204000 + 0x80004000, {0, 1, 0, 0, F0100F7401AA74000, "0100F7401AA74000", "1.0.0"}}, // choices + {0x267f24 - 0x204000 + 0x80004000, {0, 1, 0, 0, F0100F7401AA74000, "0100F7401AA74000", "1.0.0"}}, // dictionary + // Xenoblade Chronicles 2 + {0x8010b180, {CODEC_UTF8, 1, 0, 0, F01006F000B056000, "0100F3400332C000", "2.0.2"}}, // Text + // Kanon + {0x800dc524, {CODEC_UTF16, 0, 0, 0, F0100FB7019ADE000, "0100FB7019ADE000", "1.0.0"}}, // Text + // Princess Arthur + {0x80066e10, {0, 2, 0, 0, F0100FC2019346000, "0100FC2019346000", "1.0.0"}}, // Dialogue text ,sjis + {0x8001f7d0, {0, 0, 0, 0, F0100FC2019346000, "0100FC2019346000", "1.0.0"}}, // Name + // Layton’s Mystery Journey: Katrielle and the Millionaires’ Conspiracy + {0x8025d520, {0, 2, 0, 0, F0100FDB00AA80000, "0100FDB00AA80000", "1.1.0"}}, // All Text ,sjis + // Xenoblade Chronicles: Definitive Edition + {0x808a5670, {CODEC_UTF8, 1, 0, 0, F0100FF500E34A000, "0100FF500E34A000", "1.1.2"}}, // Main Text + {0x80305968, {CODEC_UTF8, 1, 0, 0, F0100FF500E34A000, "0100FF500E34A000", "1.1.2"}}, // Choices + {0x8029edc8, {CODEC_UTF8, 0, 0, 0, F0100FF500E34A000, "0100FF500E34A000", "1.1.2"}}, // Item Name + {0x8029ede8, {CODEC_UTF8, 0, 0, 0, F0100FF500E34A000, "0100FF500E34A000", "1.1.2"}}, // Item Description + {0x8026a454, {CODEC_UTF8, 0, 0, 0, F0100FF500E34A000, "0100FF500E34A000", "1.1.2"}}, // Acquired Item Name + {0x803c725c, {CODEC_UTF8, 0, 0, 0, F0100FF500E34A000, "0100FF500E34A000", "1.1.2"}}, // Acquired Item Notification + {0x802794cc, {CODEC_UTF8, 0, 0, 0, F0100FF500E34A000, "0100FF500E34A000", "1.1.2"}}, // Location Discovered + // Unicorn Overlord + {0x805ae1f8, {CODEC_UTF8, 1, 0, 0, F01000AE01954A000, "01000AE01954A000", "1.00"}}, // Text + // Octopath Traveler + {0x8005ef78, {CODEC_UTF32, 0, 0, 0, 0, "01000E200DC58000", "1.0.0"}}, // Text + // The World Ends with You: Final Remix + {0x80706ab8, {CODEC_UTF16, 2, 0, 0, F01006F000B056000, "01001C1009892000", "1.0.0"}}, // Text + // JackJanne + {0x81f02cd8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100982015606000, "01001DD010A2E800", "1.0.5"}}, // Text + {0x821db028, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100982015606000, "01001DD010A2E800", "1.0.5"}}, // choice + // Collar x Malice + {0x800444c4, {CODEC_UTF8, 0, 0, 0, 0, "01002B400E9DA000", "1.0.0"}}, // Text + // Kanda Alice mo Suiri Suru. + {0x80041db0, {0, 0, 0, 0, F01003BD013E30000, "01003BD013E30000", "1.0.0"}}, // sjis + // Rune Factory 3 Special + {0x81fb3364, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01001EF017BE6000, "01001EF017BE6000", "1.0.4"}}, // Main Text + {0x826c0f20, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F01001EF017BE6000, "01001EF017BE6000", "1.0.4"}}, // Aproach + {0x81fb3320, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01001EF017BE6000, "01001EF017BE6000", "1.0.4"}}, // Choices + {0x821497e8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F01001EF017BE6000, "01001EF017BE6000", "1.0.4"}}, // Calendar + {0x826ba1a0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F01001EF017BE6000, "01001EF017BE6000", "1.0.4"}}, // Info + {0x823f6200, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01001EF017BE6000, "01001EF017BE6000", "1.0.4"}}, // More Info + {0x826c381c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F01001EF017BE6000, "01001EF017BE6000", "1.0.4"}}, // Item Select Name + // Toraware no Paruma -Refrain- + {0x80697300, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F01000EA00D2EE000, "01000EA00D2EE000", "1.0.0"}}, // text x1 + {0x806f43c0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01000EA00D2EE000, "01000EA00D2EE000", "1.0.0"}}, // name x0 + {0x80d2aca4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01000EA00D2EE000, "01000EA00D2EE000", "1.0.0"}}, // choice x0 + {0x804b04c8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01000EA00D2EE000, "01000EA00D2EE000", "1.0.0"}}, // alert x0 + {0x804b725c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01000EA00D2EE000, "01000EA00D2EE000", "1.0.0"}}, // prompt x0 + // Aiyoku no Eustia + {0x804BEFD0, {CODEC_UTF8, 0, 0, 0, F01006590155AC000, "01001CC017BB2000", "1.0.0"}}, // x0 - name + {0x804BEFE8, {CODEC_UTF8, 0, 0, 0, F01006590155AC000, "01001CC017BB2000", "1.0.0"}}, // x0 - dialogue + {0x804d043c, {CODEC_UTF8, 0, 0, 0, F01006590155AC000, "01001CC017BB2000", "1.0.0"}}, // x0 - choice + // ワンド オブ フォーチュン R~ for Nintendo Switch + {0x81ed0580, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100DA201E0DA000, "01000C7019E1C000", "1.0.0"}}, // dialogue + {0x81f96bac, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100DA201E0DA000, "01000C7019E1C000", "1.0.0"}}, // name + {0x8250ac28, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100DA201E0DA000, "01000C7019E1C000", "1.0.0"}}, // choice + // Jakou no Lyla ~Trap of MUSK~ + {0x80167100, {CODEC_UTF32, 1, 0, 0, F010093800DB1C000, "010093800DB1C000", "1.0.0"}}, // x1 text + name (unformated), #T1 #T2, #T0/* 1. European night */ + {0x801589a0, {CODEC_UTF32, 1, 0, 0, F010093800DB1C000, "010093800DB1C000", "1.0.0"}}, // x0=x1=choice (sig=SltAdd) + {0x801b4300, {CODEC_UTF32, 1, 0, 0, F010093800DB1C000, "010093800DB1C000", "1.0.0"}}, // x1 text + name (unformated), #T1 #T2, #T0/* 2. Asian night */ + {0x802a9170, {CODEC_UTF32, 1, 0, 0, F010093800DB1C000, "010093800DB1C000", "1.0.0"}}, // x0=x1=choice (sig=SltAdd) + {0x80301e80, {CODEC_UTF32, 1, 0, 0, F010093800DB1C000, "010093800DB1C000", "1.0.0"}}, // x1 text + name (unformated), #T1 #T2, #T0/* 3. Arabic night */ + {0x803f7a90, {CODEC_UTF32, 1, 0, 0, F010093800DB1C000, "010093800DB1C000", "1.0.0"}}, // x0=x1=choice (sig=SltAdd) + // Galleria no Chika Meikyuu to Majo no Ryodan ガレリアの地下迷宮と魔女ノ旅団 + {0x8002f64c, {CODEC_UTF8, 0, 0, 0, 0, "01007010157B4000", "1.0.1"}}, // Main Text + // Dragon's Dogma: Dark Arisen + {0x81023a80, {CODEC_UTF8, 1, 0, 0, F010057E00AC56000, "010057E00AC56000", "1.0.1"}}, // Main Text + {0x8103e140, {CODEC_UTF8, 1, 0, 0, F010057E00AC56000, "010057E00AC56000", "1.0.1"}}, // Allies + Cutscene Text + {0x8103bb10, {CODEC_UTF8, 1, 0, 0, F010057E00AC56000, "010057E00AC56000", "1.0.1"}}, // NPC Text + {0x80150720, {CODEC_UTF8, 0, 0, 0, F010057E00AC56000, "010057E00AC56000", "1.0.1"}}, // Intro Message + {0x80df90a8, {CODEC_UTF8, 0, 0, 0, F010057E00AC56000, "010057E00AC56000", "1.0.1"}}, // Info1 + {0x80ce2bb8, {CODEC_UTF8, 0, 0, 0, F010057E00AC56000, "010057E00AC56000", "1.0.1"}}, // Info2 + {0x80292d84, {CODEC_UTF8, 0, 0, 0, F010057E00AC56000, "010057E00AC56000", "1.0.1"}}, // Info Popup1 + {0x80cfac6c, {CODEC_UTF8, 0, 0, 0, F010057E00AC56000, "010057E00AC56000", "1.0.1"}}, // Info Popup2 + {0x8102d460, {CODEC_UTF8, 1, 0, 0, F010057E00AC56000, "010057E00AC56000", "1.0.1"}}, // Description + // Yo-kai Watch Jam - Yo-kai Academy Y: Waiwai Gakuen + {0x80dd0cec, {CODEC_UTF8, 0, 0, 0, F010051D010FC2000, "010051D010FC2000", "4.0.0"}}, // Dialogue text + {0x80e33450, {CODEC_UTF8, 3, 0, 0, F010051D010FC2000, "010051D010FC2000", "4.0.0"}}, // Other Dialogue text + {0x80c807c0, {CODEC_UTF8, 0, 0, 0, F010051D010FC2000, "010051D010FC2000", "4.0.0"}}, // Item description etc text + {0x808d9a30, {CODEC_UTF8, 0, 0, 0, F010051D010FC2000, "010051D010FC2000", "4.0.0"}}, // Tutorial Text + {0x811b95ac, {CODEC_UTF8, 3, 0, 0, F010051D010FC2000, "010051D010FC2000", "4.0.0"}}, // Menu screen + {0x80e20290, {CODEC_UTF8, 3, 0, 0, F010051D010FC2000, "010051D010FC2000", "4.0.0"}}, // Opening Song Text etc + {0x80c43680, {CODEC_UTF8, 3, 0, 0, F010051D010FC2000, "010051D010FC2000", "4.0.0"}}, // Cutscene Text + // NEO: The World Ends With You + {0x81581d6c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F010043B013C5C000, "010043B013C5C000", "1.03"}}, // Text + {0x818eb248, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010043B013C5C000, "010043B013C5C000", "1.03"}}, // Objective + {0x81db84a4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010043B013C5C000, "010043B013C5C000", "1.03"}}, // Menu: Collection Item Name + {0x81db8660, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F010043B013C5C000, "010043B013C5C000", "1.03"}}, // Menu: Collection Item Description + {0x81c71a48, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010043B013C5C000, "010043B013C5C000", "1.03"}}, // Tutorial Title + {0x81c71b28, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F010043B013C5C000, "010043B013C5C000", "1.03"}}, // Tutorial Description + // Eiyuden Chronicle: Rising + {0x82480190, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, 0, "010039B015CB6000", "1.02"}}, // Main Text + {0x824805d0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, 0, "010039B015CB6000", "1.02"}}, // Name + {0x81f05c44, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Intro Text + {0x82522ac4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Character Info + {0x81b715f4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Info + {0x825274d0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, 0, "010039B015CB6000", "1.02"}}, // Info2 + {0x825269b0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Tutorial Title + {0x82526a0c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Tutorial Description + {0x82523e04, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Objective Title + {0x82524160, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Objective Description + {0x81f0351c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Location Selection Title + {0x81f0358c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Location Selection Description + {0x81f0d520, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Quest Title + {0x81f0d58c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Quest Description + {0x81f00318, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Help Title + {0x81f00368, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Help Description + {0x81f0866c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, 0, "010039B015CB6000", "1.02"}}, // Config Description + // Ghost Trick: Phantom Detective + {0x81448898, {CODEC_UTF16, 0, 0, 0, F010043B013C5C000, "010029B018432000", "1.0.0"}}, // Main Text + {0x80c540d4, {CODEC_UTF16, 0, 0, 0, F010043B013C5C000, "010029B018432000", "1.0.0"}}, // Secondary Text + {0x80e50dd4, {CODEC_UTF16, 0, 0, 0, F010043B013C5C000, "010029B018432000", "1.0.0"}}, // Object Name + {0x80f91c08, {CODEC_UTF16, 0, 0, 0, F010043B013C5C000, "010029B018432000", "1.0.0"}}, // Language Selection + {0x805c9014, {CODEC_UTF16, 0, 0, 0, F010043B013C5C000, "010029B018432000", "1.0.0"}}, // Story/Character Info + // Higurashi no Naku Koro ni Hou + {0x800bd6c8, {0, 0, 0, 0, F0100F6A00A684000, "0100F6A00A684000", "1.0.0"}}, // sjis + {0x800c2d20, {0, 0, 0, 0, F0100F6A00A684000, "0100F6A00A684000", "1.2.0"}}, // sjis + // Umineko no Naku Koro ni Saku ~Nekobako to Musou no Koukyoukyoku~ + {0x800b4560, {CODEC_UTF8, 0, 0, 0, 0, "01006A300BA2C000", "1.0.0"}}, // x0 name + text (bottom, center) - whole line. filter is to complex, quit. + {0x801049c0, {CODEC_UTF8, 0, 0, 0, 0, "01006A300BA2C000", "1.0.0"}}, // x0 prompt, bottomLeft + {0x80026378, {CODEC_UTF8, 0, 0, 0, 0, "01006A300BA2C000", "1.0.0"}}, // x0 Yes|No + {0x801049a8, {CODEC_UTF8, 0, 0, 0, 0, "01006A300BA2C000", "1.0.0"}}, // x0 topLeft (double: ♪ + text) + + // Koroshiya to Strawberry- Plus + {0x81322cec, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F010042300C4F6000, "0100E390145C8000", "1.0.0"}}, // dialogue + {0x819b1a78, {CODEC_UTF16, 0, 0, ReadTextAndLenW<2>, F010042300C4F6000, "0100E390145C8000", "1.0.0"}}, // dialogue + {0x81314e8c, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F010042300C4F6000, "0100E390145C8000", "1.0.0"}}, // dialogue + // Tokimeki Memorial Girl's Side 1st Love for Nintendo Switch + {0x822454a4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // dialogue1 + {0x82247138, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // dialogue2 + {0x822472e0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // dialogue3 + {0x82156988, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // choice + {0x82642200, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<2>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // option1 + {0x81ecd758, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // option2 + {0x823185e4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // mail + {0x823f2edc, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // roomDescript + {0x821e3cf0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // dateDescript + {0x81e20050, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // characterDesc1 + {0x81e1fe50, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // characterDesc2 + {0x81e1feb0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // characterDesc3 + {0x81e1ff04, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // characterDesc4 + {0x821d03b0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<3>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // news + {0x82312008, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100D9A01BD86000, "0100D9A01BD86000", "1.0.1"}}, // luckyitem + // Triangle Strategy + {0x80aadebc, {CODEC_UTF16, 0, 0, 0, F0100CC80140F8000<0>, "0100CC80140F8000", "1.1.0"}}, // Main Text + {0x81358ce4, {CODEC_UTF16, 3, 0, 0, F0100CC80140F8000<1>, "0100CC80140F8000", "1.1.0"}}, // Secondary Text + {0x80a38988, {CODEC_UTF16, 0, 0, 0, F0100CC80140F8000<2>, "0100CC80140F8000", "1.1.0"}}, // Info Contents + {0x80aa4aec, {CODEC_UTF16, 0, 0, 0, F0100CC80140F8000<3>, "0100CC80140F8000", "1.1.0"}}, // Info + {0x80b1f300, {CODEC_UTF16, 0, 0, 0, F0100CC80140F8000<4>, "0100CC80140F8000", "1.1.0"}}, // Difficulty Selection Part1 + {0x80b1f670, {CODEC_UTF16, 0, 0, 0, F0100CC80140F8000<5>, "0100CC80140F8000", "1.1.0"}}, // Difficulty Selection Part2 + {0x80aa48f0, {CODEC_UTF16, 0, 0, 0, F0100CC80140F8000<6>, "0100CC80140F8000", "1.1.0"}}, // PopUp Message + // Xenoblade Chronicles 3 + {0x80cf6ddc, {CODEC_UTF8, 0, 0, 0, F010074F013262000, "010074F013262000", "2.2.0"}}, // Main Text + {0x80e76150, {CODEC_UTF8, 0, 0, 0, F010074F013262000, "010074F013262000", "2.2.0"}}, // Secondary Text + {0x807b4ee4, {CODEC_UTF8, 1, 0, 0, F010074F013262000, "010074F013262000", "2.2.0"}}, // Tutorial Description + {0x80850218, {CODEC_UTF8, 0, 0, 0, F010074F013262000, "010074F013262000", "2.2.0"}}, // Objective + // CLOCK ZERO ~Shuuen no Ichibyou~ Devote + {0x8003c290, {0, 0, 0, 0, F0100BDD01AAE4000, "01008C100C572000", "1.0.0"}}, // name,sjis + {0x8003c184, {0, 0, 0, 0, F0100BDD01AAE4000, "01008C100C572000", "1.0.0"}}, // dialogue + {0x8001f6d0, {0, 0, 0, 0, F0100BDD01AAE4000, "01008C100C572000", "1.0.0"}}, // prompt + // Shuuen no Virche -ErroR:salvation + {0x8001f594, {CODEC_UTF8, 0, 0x1C, 0, F0100C310110B4000, "01005B9014BE0000", "1.0.0"}}, // dialog + {0x8001f668, {CODEC_UTF8, 0, 0x1C, 0, F0100C310110B4000, "01005B9014BE0000", "1.0.0"}}, // center + {0x8003d540, {CODEC_UTF8, 0, 0, 0, F0100C310110B4000, "01005B9014BE0000", "1.0.0"}}, // choice + // Spade no Kuni no Alice ~Wonderful White World~ / スペードの国のアリス ~Wonderful White World~ + {0x8135d018, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F01008C0016544000, "01003FE00E2F8000", "1.0.0"}}, // Text + Name + // Spade no Kuni no Alice ~Wonderful Black World~ (スペードの国のアリス ~Wonderful Black World~) + {0x819dbdc8, {CODEC_UTF16, 0, 0x14, 0, F0100AB100E2FA000, "0100AB100E2FA000", "1.0.0"}}, + {0x81f8e564, {CODEC_UTF16, 1, 0x14, 0, F0100AB100E2FA000, "0100AB100E2FA000", "1.0.0"}}, + // 十三支演義 偃月三国伝1・2 for Nintendo Switch (Juuzaengi ~Engetsu Sangokuden~) + {0x82031f20, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<2>, F0100DA201E0DA000, "01003D2017FEA000", "1.0.0"}}, // name + {0x82ef9550, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100DA201E0DA000, "01003D2017FEA000", "1.0.0"}}, // dialogue + {0x83252e0c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100DA201E0DA000, "01003D2017FEA000", "1.0.0"}}, // choice + // Tales of Vesperia: Definitive Edition + {0x802de170, {CODEC_UTF8, 2, 0, 0, F01002C0008E52000, "01002C0008E52000", "1.0.2"}}, // Ptc Text + {0x802cf170, {CODEC_UTF8, 3, 0, 0, F01002C0008E52000, "01002C0008E52000", "1.0.2"}}, // Cutscene + {0x8019957c, {CODEC_UTF8, 0, 0, 0, F01002C0008E52000, "01002C0008E52000", "1.0.2"}}, // Conversation + {0x802c0600, {CODEC_UTF8, 2, 0, 0, F01002C0008E52000, "01002C0008E52000", "1.0.2"}}, // Info + {0x801135fc, {CODEC_UTF8, 0, 0, 0, F01002C0008E52000, "01002C0008E52000", "1.0.2"}}, // Post Battle Text + // Nil Adminari no Tenbin Irodori Nadeshiko + {0x8005fd5c, {CODEC_UTF8, 0, 0, 0, F0100BDD01AAE4000, "01002BB00A662000", "1.0.0"}}, // name + {0x800db0d8, {CODEC_UTF8, 0, 20, 0, F0100BDD01AAE4000, "01002BB00A662000", "1.0.0"}}, // name + // Hanayaka Nari, Waga Ichizoku Modern Nostalgie + {0x2509ac - 0x204000 + 0x80004000, {CODEC_UTF8, 0, 0, T0100B5500CA0C000, F0100B5500CA0C000, "01008DE00C022000", "1.0.0"}}, + // Master Detective Archives: Rain Code + {0x80bf2034, {CODEC_UTF16, 0, 0, 0, F0100F4401940A000, "0100F4401940A000", "1.3.3"}}, // Dialogue text + {0x80c099d4, {CODEC_UTF16, 0, 0, 0, F0100F4401940A000, "0100F4401940A000", "1.3.3"}}, // Cutscene text + {0x80cbf1f4, {CODEC_UTF16, 0, 0, 0, F0100F4401940A000, "0100F4401940A000", "1.3.3"}}, // Menu + {0x80cbc11c, {CODEC_UTF16, 0, 0, 0, F0100DA201E0DA000, "0100F4401940A000", "1.3.3"}}, // Menu Item Description + {0x80cacc14, {CODEC_UTF16, 0, 0, 0, F0100DA201E0DA000, "0100F4401940A000", "1.3.3"}}, // Menu Item Description 2 + {0x80cd6410, {CODEC_UTF16, 0, 0, 0, F0100DA201E0DA000, "0100F4401940A000", "1.3.3"}}, // Menu Item Description 3 + {0x80c214d4, {CODEC_UTF16, 0, 0, 0, F0100F4401940A000, "0100F4401940A000", "1.3.3"}}, // Description + {0x80cc9908, {CODEC_UTF16, 0, 0, 0, F0100DA201E0DA000, "0100F4401940A000", "1.3.3"}}, // Mini game item description + {0x80bce36c, {CODEC_UTF16, 0, 0, 0, F0100F4401940A000, "0100F4401940A000", "1.3.3"}}, // Tutorial + {0x80bcb7d4, {CODEC_UTF16, 0, 0, 0, F0100F4401940A000, "0100F4401940A000", "1.3.3"}}, // Loading Screen information + {0x80bf32d8, {CODEC_UTF16, 0, 0, 0, F0100F4401940A000, "0100F4401940A000", "1.3.3"}}, // Choices + // Fire Emblem: Three Houses + {0x8041e6bc, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Main Text + {0x805ca570, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Cutscene Text + {0x8049f1e8, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Cutscene Text Scroll + {0x805ee730, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Info + {0x805ee810, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Info Choice + {0x80467a60, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Location First Part + {0x805f0340, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Location Second Part + {0x801faae4, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Action Location + {0x803375e8, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Objective + {0x805fd870, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Tutorial + {0x804022f8, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Request + {0x802f7df4, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Quest Description + {0x8031af0c, {CODEC_UTF8, 0, 0, 0, F010055D009F78000, "010055D009F78000", "1.2.0"}}, // Aproach Text + // Sweet Clown ~Gozen San-ji no Okashi na Doukeshi~ + {0x20dbfc - 0x204000 + 0x80004000, {0, 0, 0x28, 0, F010028D0148E6000, "010028D0148E6000", "1.2.0"}}, // dialog, sjis + {0x214978 - 0x204000 + 0x80004000, {0, 2, 0xC, 0, F010028D0148E6000, "010028D0148E6000", "1.2.0"}}, // choices + // Another Code: Recollection + {0x82dcad30, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Main Text + {0x82f2cfb0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Item Description + {0x82dcc5fc, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Tutorial PopUp Header + {0x82dcc61c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Tutorial PopUp Description + {0x82f89e78, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Aproach Text + {0x82973300, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Chapter + {0x82dd2604, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Location + {0x82bcb77c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Save Message + {0x828ccfec, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Acquired Item + {0x83237b14, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Question Options + {0x82dcee10, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Tutorial Header + {0x82dcee38, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Tutorial Description + {0x82e5cadc, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Character Info Name + {0x82e5cc38, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Character Info Description + {0x82871ac8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Letter Message + {0x82e4dad4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // アナザーキー + {0x82bd65d0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Message Title + {0x82bd65f0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Message Content + {0x82c1ccf0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Decision Header + {0x82c1d218, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Decision1 + {0x82c1e43c, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100CB9018F5A000, "0100CB9018F5A000", "1.0.0"}}, // Decision2 + // AI: The Somnium Files + {0x8165a9a4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100C7400CFB4000, "0100C7400CFB4000", "1.0.2"}}, // Main Text + Tutorial + {0x80320dd4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100C7400CFB4000, "0100C7400CFB4000", "1.0.2"}}, // Menu Interface Text1 + {0x80320e20, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F0100C7400CFB4000, "0100C7400CFB4000", "1.0.2"}}, // Menu Interface Text2 + // AI: The Somnium Files - nirvanA Initiative + {0x8189ae64, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BD4014D8C000, "0100BD4014D8C000", "1.0.1"}}, // Main Text + Tutorial + {0x81813428, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BD4014D8C000, "0100BD4014D8C000", "1.0.1"}}, // Hover Investigation Text + {0x82e122b8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BD4014D8C000, "0100BD4014D8C000", "1.0.1"}}, // Info + {0x82cffff8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BD4014D8C000, "0100BD4014D8C000", "1.0.1"}}, // Config Description + {0x818c3cd8, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BD4014D8C000, "0100BD4014D8C000", "1.0.1"}}, // File: Names + {0x82ea1a38, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BD4014D8C000, "0100BD4014D8C000", "1.0.1"}}, // File: Contents + {0x82cbb1fc, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F0100BD4014D8C000, "0100BD4014D8C000", "1.0.1"}}, // Investigation Choices + // Fata morgana no Yakata ~Dreams of the Revenants Edition~ / ファタモ + {0x8025a998, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01008C0016544000, "0100BE40138B8000", "1.0.1"}}, // Main Text + {0x801d6050, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01008C0016544000, "0100BE40138B8000", "1.0.1"}}, // Choices + // Ni no Kuni II: Revenant Kingdom + {0x80ac651c, {CODEC_UTF8, 0, 0, 0, F0100C4E013E5E000, "0100C4E013E5E000", "1.0.0"}}, // Main Text + {0x80335ea0, {CODEC_UTF8, 0, 0, 0, F0100C4E013E5E000, "0100C4E013E5E000", "1.0.0"}}, // Name + // Harukanaru Toki no Naka de 7 + {0x800102bc, {0, 0, 0, T0100CF400F7CE000<0>, F0100CF400F7CE000, "0100CF400F7CE000", "1.0.0"}}, // name, sjis + {0x80051f90, {0, 0, 0, T0100CF400F7CE000<1>, F0100CF400F7CE000, "0100CF400F7CE000", "1.0.0"}}, // text + {0x80010b48, {0, 0, 0, T0100CF400F7CE000<0>, F0100CF400F7CE000, "0100CF400F7CE000", "1.0.0"}}, // prompt + {0x80010c80, {0, 0, 0, T0100CF400F7CE000<0>, F0100CF400F7CE000, "0100CF400F7CE000", "1.0.0"}}, // choice + // Angelique Luminarise + {0x80046c04, {0, 0, 0, T0100CF400F7CE000<0>, F0100CF400F7CE000, "0100D11018A7E000", "1.0.0"}}, // ingameDialogue, sjis + {0x80011284, {0, 0, 0, T0100CF400F7CE000<0>, F0100CF400F7CE000, "0100D11018A7E000", "1.0.0"}}, // choice + {0x80011140, {0, 0, 0, T0100CF400F7CE000<0>, F0100CF400F7CE000, "0100D11018A7E000", "1.0.0"}}, // prompt first + // Star Ocean The Second Story R + {0x81d5e4d0, {0, 0, 0, ReadTextAndLenDW<1>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Main Text + Tutorial + {0x81d641b4, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Intro Cutscene + {0x824b1f00, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Character Selection Name + {0x81d4c670, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Character Selection Lore + {0x8203a048, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // General Description + {0x82108cd0, {0, 0, 0, ReadTextAndLenDW<1>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Unique Spot Title + {0x827a9848, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Chest Item + {0x82756890, {0, 0, 0, ReadTextAndLenDW<1>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Info + {0x82241410, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Menu Talk + {0x81d76404, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Secondary Talk + {0x821112e0, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Location + {0x82111320, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Location Interior + {0x81d6ea24, {0, 0, 0, ReadTextAndLenDW<1>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Special Arts/Spells Name + {0x81d6ea68, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Special Arts/Spells Description + {0x81d6ed48, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Special Arts/Spells Range + {0x81d6eb3c, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Special Arts/Spells Effect + {0x81d6f880, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Special Arts/Spells Bonus + {0x8246d81c, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Tactics Name + {0x8246d83c, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Tactics Description + {0x8212101c, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Achievements Name + {0x82121088, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Achievements Description + {0x81d6c480, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Acquired Item1 + {0x821143f0, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Acquired Item2 + {0x81d6fb18, {0, 0, 0, ReadTextAndLenDW<1>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Battle Skill Name + {0x81d6fb4c, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Battle Skill Description + {0x81d6fb7c, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Battle Skill Bonus Description + {0x8212775c, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Battle Item Name + {0x82127788, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Battle Item Description + {0x821361ac, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Battle Ability Name + {0x821361f4, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Battle Ability Range + {0x82136218, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Battle Ability Effect + {0x8238451c, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Battle Strategy Name + {0x82134610, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Battle Acquired Item + {0x824b5eac, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Item Name + {0x824b5f04, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Item Description + {0x824b5f54, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Item Effect + {0x81d71790, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Item Factor Title + {0x824b62c0, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Item Factor Description + {0x824c2e2c, {0, 0, 0, ReadTextAndLenDW<1>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // IC/Specialty Skills Name + {0x824c2e54, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // IC/Specialty Skills Description + {0x824c2fbc, {0, 0, 0, ReadTextAndLenDW<1>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // IC/Specialty Skills Level + {0x823e7230, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // IC/Specialty Name + {0x823e94bc, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // IC/Specialty Description + {0x823e9980, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // IC/Specialty Talent + {0x823ea9c4, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // IC/Specialty Support Item + {0x82243b18, {0, 0, 0, ReadTextAndLenDW<1>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Enemy Info Skills + {0x81d64540, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Guild Mission Description + {0x823b4f6c, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Guild Mission Reward + {0x826facd8, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Challenge Mission Description + {0x826f98f8, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Challenge Mission Reward + {0x8244af2c, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Formation Name + {0x8244ae90, {0, 0, 0, ReadTextAndLenDW<0>, F010065301A2E0000, "010065301A2E0000", "1.0.2"}}, // Formation Description + // 魔法使いの夜 通常版 + {0x80086ba0, {CODEC_UTF8, 0, 0, T010012A017F18000, 0, "010012A017F18000", "1.0.0"}}, + {0x80086e70, {CODEC_UTF8, 0, 0, T010012A017F18000, 0, "010012A017F18000", "1.0.2"}}, + // 月姫 -A piece of blue glass moon- + {0x800ac290, {CODEC_UTF8, 0, 0, T010012A017F18000, 0, "01001DC01486A000", 0}}, // 1.0.1,1.0.2 + // The Quintessential Quintuplets the Movie: Five Memories of My Time with You (JP) + {0x80011688, {CODEC_UTF8, 1, 0, 0, F01005E9016BDE000, "01005E9016BDE000", "1.0.0"}}, // dialogue, menu, choice, name + // Flowers: Les Quatre Saisons + {0x8006f940, {CODEC_UTF16, 1, 0, 0, F01002AE00F442000, "01002AE00F442000", "1.0.1"}}, + // 最悪なる災厄人間に捧ぐ eSHOP [01000A400AF2A000][v0] + {0x8034EB44, {CODEC_UTF16, 8, 0, 0, F01000A400AF2A000, "01000A400AF2A000", "1.0.0"}}, // text + // 神様のような君へ + {0x80487CD0, {CODEC_UTF8, 0, 0, 0, F01006B5014E2E000, "01006B5014E2E000", "1.0.0"}}, // text + // BUSTAFELLOWS + {0x80191b18, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100874017BE2000, "010060800B7A8000", "1.1.3"}}, // Dialogue + {0x80191f88, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100874017BE2000, "010060800B7A8000", "1.1.3"}}, // Choice + {0x801921a4, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100874017BE2000, "010060800B7A8000", "1.1.3"}}, // Choice 2 + {0x801935f0, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F0100874017BE2000, "010060800B7A8000", "1.1.3"}}, // option + // Moujuutsukai to Ouji-sama ~Flower & Snow~ + {0x800a1a10, {CODEC_UTF8, 1, 0, 0, F01001B900C0E2000, "01001B900C0E2000", "1.0.0"}}, // Dialogue 1 + {0x80058f80, {CODEC_UTF8, 1, 0, 0, F01001B900C0E2000, "01001B900C0E2000", "1.0.0"}}, // Dialogue 2 + // Detective Pikachu Returns + {0x81585750, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<2>, F010007500F27C000, "010007500F27C000", "1.0.0"}}, // All Text + // Dragon Quest Treasures + {0x80bd62c4, {CODEC_UTF16, 0, 0, 0, F0100217014266000, "0100217014266000", "1.0.1"}}, // Cutscene + {0x80a74b64, {CODEC_UTF16, 0, 0, 0, F0100217014266000, "0100217014266000", "1.0.1"}}, // Ptc Text + {0x80a36d18, {CODEC_UTF16, 0, 0, 0, F0100217014266000, "0100217014266000", "1.0.1"}}, // Info + {0x80c43878, {CODEC_UTF16, 0, 0, 0, F0100217014266000, "0100217014266000", "1.0.1"}}, // Tutorial Title + {0x80c43d50, {CODEC_UTF16, 0, 0, 0, F0100217014266000, "0100217014266000", "1.0.1"}}, // Tutorial Description + {0x80a72598, {CODEC_UTF16, 0, 0, 0, F0100217014266000, "0100217014266000", "1.0.1"}}, // Aproach Text + // Rune Factory 4 Special + {0x48b268 - 0x204000 + 0x80004000, {CODEC_UTF8, 3, 0, 0, F010027100C79A000, "010027100C79A000", "1.0.1"}}, // All Text + // The Legend of Zelda: Skyward Sword HD + {0x80dc36dc, {CODEC_UTF16 | FULL_STRING, 3, 0, 0, F01001EF017BE6000, "01002DA013484000", "1.0.1"}}, // All Text + // World of Final Fantasy Maxima + {0x8068fea0, {CODEC_UTF8, 0, 0, 0, F010072000BD32000, "010072000BD32000", "1.0.0"}}, // Cutscene + {0x802c6a48, {CODEC_UTF8, 0, 0, 0, F010072000BD32000, "010072000BD32000", "1.0.0"}}, // Action Text + {0x803a523c, {CODEC_UTF8, 1, 0, 0, F010072000BD32000, "010072000BD32000", "1.0.0"}}, // Location + {0x8041ed64, {CODEC_UTF8, 0, 0, 0, F010072000BD32000, "010072000BD32000", "1.0.0"}}, // Info + {0x802c9f1c, {CODEC_UTF8, 0, 0, 0, F010072000BD32000, "010072000BD32000", "1.0.0"}}, // Chapter First Part + {0x802c9f6c, {CODEC_UTF8, 0, 0, 0, F010072000BD32000, "010072000BD32000", "1.0.0"}}, // Chapter Second Part + // Tokyo Xanadu eX+ + {0x8025135c, {CODEC_UTF8, 1, 0, 0, F010080C01AA22000, "010080C01AA22000", "1.0.0"}}, // Name + {0x80251068, {CODEC_UTF8, 0, 0, 0, F010080C01AA22000, "010080C01AA22000", "1.0.0"}}, // Main Text + {0x802ac86c, {CODEC_UTF8, 0, 0, 0, F010080C01AA22000, "010080C01AA22000", "1.0.0"}}, // Action Text + {0x802b04b4, {CODEC_UTF8, 0, 0, 0, F010080C01AA22000, "010080C01AA22000", "1.0.0"}}, // Choices + {0x8013243c, {CODEC_UTF8, 0, 0, 0, F010080C01AA22000, "010080C01AA22000", "1.0.0"}}, // Location + {0x802b1f3c, {CODEC_UTF8, 0, 0, 0, F010080C01AA22000, "010080C01AA22000", "1.0.0"}}, // Info + {0x802ab46c, {CODEC_UTF8, 0, 0, 0, F010080C01AA22000, "010080C01AA22000", "1.0.0"}}, // Documents + // DORAEMON STORY OF SEASONS: Friends of the Great Kingdom + {0x839558e4, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<1>, F01009B50139A8000, "01009B50139A8000", "1.1.1"}}, // Text + {0x8202a9b0, {CODEC_UTF16, 0, 0, ReadTextAndLenDW<0>, F01009B50139A8000, "01009B50139A8000", "1.1.1"}}, // Tutorial + // Monster Hunter Stories 2: Wings of Ruin + {0x8042fe60, {CODEC_UTF8, 1, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Cutscene + {0x804326c0, {CODEC_UTF8, 1, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Ptc Text + {0x804d3d44, {CODEC_UTF8, 0, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Info + {0x8045e7c8, {CODEC_UTF8, 0, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Info Choice + {0x805cec4c, {CODEC_UTF8, 0, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Config Header + {0x8078c2d0, {CODEC_UTF8, 0, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Config Name+ + {0x805d0858, {CODEC_UTF8, 0, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Config Description + {0x807612d4, {CODEC_UTF8, 0, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Notice + {0x807194a0, {CODEC_UTF8, 1, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Update Content + Tutorial + {0x804d687c, {CODEC_UTF8, 0, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Objective Title + {0x804d6a7c, {CODEC_UTF8, 0, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Objective Description + {0x80509900, {CODEC_UTF8, 0, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Aproach Text + {0x8060ee90, {CODEC_UTF8, 1, 0, 0, F0100CB700D438000, "0100CB700D438000", "1.5.2"}}, // Acquired Item + // 2045、月より。 + {0x80016334, {CODEC_UTF8, 1, 0, 0, F01005C301AC5E000, "01005C301AC5E000", "1.0.1"}}, + // ヤマノススメ Next Summit ~あの山に、もう一度~ + {0x806E1444, {CODEC_UTF8, 0, 0, 0, F0100815019488000_text, "0100815019488000", "1.0.0"}}, + {0x80659EE0, {CODEC_UTF8, 1, 0, 0, F0100815019488000_name, "0100815019488000", "1.0.0"}}, + // Prison Princess + {0x800eba00, {CODEC_UTF16, 2, 0x14, 0, 0, "0100F4800F872000", "1.0.0"}}, + // Utakata no Uchronia + {0x8180de40, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F010027401A2A2000, "010027401A2A2000", "1.0.0"}}, // text box + {0x816b61c0, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F010027401A2A2000, "010027401A2A2000", "1.0.0"}}, // dictionary + {0x815fe594, {CODEC_UTF16, 0, 0, ReadTextAndLenW<0>, F010027401A2A2000, "010027401A2A2000", "1.0.0"}}, // choices + // Little Busters! Converted Edition + {0x800A97C8, {CODEC_UTF8, 9, 0, 0, F0100943010310000, "0100943010310000", "1.0.0"}}, + // GrimGrimoire OnceMore + {0x80020bd4, {CODEC_UTF8, 0, 0, 0, 0, "01003F5017760000", "1.0.0"}}, + {0x800375a0, {CODEC_UTF8, 2, 0, 0, 0, "01003F5017760000", "1.0.0"}}, // tutorial + {0x800781dc, {CODEC_UTF8, 0, 0, 0, 0, "01003F5017760000", "1.0.0"}}, // Chapter + // Temirana Koku no Tsuiteru Hime to Tsuitenai Kishidan + {0x82457970, {CODEC_UTF16, 0, 0X14, 0, F0100A62019078000, "0100A62019078000", "1.0.1"}}, + // Doukoku Soshite + {0x8008171c, {0, 0, 0, 0, 0, "01007F000EB36000", "1.0.0"}}, + // Mistonia no Kibou - The Lost Delight + {0x8246c4ac, {CODEC_UTF16, 0, 0, 0, 0, "01007AD01CB42000", "1.0.0"}}, + // even if TEMPEST: Tsuranaru Toki no Akatsuki + {0x80031008, {CODEC_UTF8, 0, 0, 0, F010095E01581C000, "0100DEF01D0C2000", "1.0.2"}}, + {0x8002e2cc, {CODEC_UTF8, 0, 0, 0, F010095E01581C000, "0100DEF01D0C2000", "1.0.2"}}, + {0x8002e2cc, {CODEC_UTF8, 0, 0, 0, F010095E01581C000, "0100DEF01D0C2000", "1.0.2"}}, + // even if TEMPEST: Yoiyami ni Kaku Katariki Majo + {0x8001cf80, {CODEC_UTF8, 0, 0, 0, F010095E01581C000, "010095E01581C000", "1.0.8"}}, + {0x800297d0, {CODEC_UTF8, 0, 0, 0, F010095E01581C000, "010095E01581C000", "1.0.8"}}, + {0x8000edcc, {CODEC_UTF8, 0, 0, 0, F010095E01581C000, "010095E01581C000", "1.0.8"}}, + // Taishou x Alice all in one + {0x80064ab8, {CODEC_UTF16, 1, 0, 0, F010096000CA38000, "010096000CA38000", "1.0.2"}}, + {0x80064bd4, {CODEC_UTF16, 1, 0, 0, F010096000CA38000, "010096000CA38000", "1.0.2"}}, + {0x8015f968, {CODEC_UTF16, 0, 0, 0, F010096000CA38000, "010096000CA38000", "1.0.2"}}, + // Taishou x Alice: HEADS & TAILS + {0x8009bb3c, {CODEC_UTF16, 1, 0, 0, F0100B1F0123B6000, "0100B1F0123B6000", "2.0.0"}}, + {0x8009bc58, {CODEC_UTF16, 1, 0, 0, F0100B1F0123B6000, "0100B1F0123B6000", "2.0.0"}}, + // Hiiro_no_Kakera_Tamayorihime_Kitan_Omoiiro_no_Kioku + {0x81922ce8, {CODEC_UTF16, 0, 0x14, 0, F0100EC001DE7E000, "0100EC001DE7E000", "1.0.0"}}, + // Gensou Manège + {0x8124f690, {CODEC_UTF16, 0, 0x14, 0, F010037500DF38000, "010037500DF38000", "1.0.4"}}, + {0x811f63f0, {CODEC_UTF16, 0, 0x14, 0, F010037500DF38000, "010037500DF38000", "1.0.4"}}, + {0x811917f4, {CODEC_UTF16, 0, 0x14, 0, F010037500DF38000, "010037500DF38000", "1.0.4"}}, + {0x81595f90, {CODEC_UTF16, 0, 0x14, 0, F010037500DF38000, "010037500DF38000", "1.0.4"}}, + // Gensou Kissa Enchanté + {0x8002863c, {CODEC_UTF8, 0, 0, 0, 0, "010079200C26E000", "1.0.0"}}, + {0x80044360, {CODEC_UTF8, 1, 0, 0, 0, "010079200C26E000", "1.0.0"}}, + {0x8004a1a4, {CODEC_UTF8, 0, 0, 0, F010079200C26E000<0>, "010079200C26E000", "1.0.0"}}, + {0x8004a394, {CODEC_UTF8, 0, 0, 0, F010079200C26E000<1>, "010079200C26E000", "1.0.0"}}, + // Tengoku Struggle -strayside- + {0x801bc678, {CODEC_UTF32, 0, 0, 0, F01002C00177AE000, "01002C00177AE000", "1.0.0"}}, + {0x8016a05c, {CODEC_UTF32, 0, 0, 0, F01002C00177AE000, "01002C00177AE000", "1.0.0"}}, + {0x80140cac, {CODEC_UTF32, 1, 0, 0, F01002C00177AE000, "01002C00177AE000", "1.0.0"}}, + {0x800e08dc, {CODEC_UTF32, 0, 0, 0, F01002C00177AE000, "01002C00177AE000", "1.0.0"}}, + // Meiji Katsugeki Haikara Ryuuseigumi -Seibai Shimaseu, Yonaoshi Kagyou- + {0x802ab2fc, {CODEC_UTF8, 6, 0, 0, F0100EA100DF92000, "0100EA100DF92000", "1.0.0"}}, + // 7'scarlet + {0x8177ec00, {CODEC_UTF16, 0, 0x14, 0, F0100FA001E160000, "0100FA001E160000", "1.0.0"}}, + {0x817754ac, {CODEC_UTF16, 0, 0x14, 0, F0100FA001E160000, "0100FA001E160000", "1.0.0"}}, + // SympathyKiss / Sympathy Kiss (JP) + {0x80037d90, {CODEC_UTF8, 0, 0, 0, F0100FA10185B0000, "0100FA10185B0000", "1.0.0"}}, + {0x80030f24, {CODEC_UTF8, 0, 0, 0, F0100FA10185B0000, "0100FA10185B0000", "1.0.0"}}, + {0x80054804, {CODEC_UTF8, 1, 0, 0, F0100FA10185B0000, "0100FA10185B0000", "1.0.0"}}, + {0x80054290, {CODEC_UTF8, 1, 0, 0, F0100FA10185B0000, "0100FA10185B0000", "1.0.0"}}, + // Kimi wa Yukima ni Koinegau (君は雪間に希う) + {0x8013a0f0, {CODEC_UTF32, 0, 0, 0, F010021D01474E000, "010021D01474E000", "1.0.0"}}, + {0x800319f8, {CODEC_UTF32, 0, 0, 0, F010021D01474E000_2, "010021D01474E000", "1.0.0"}}, + {0x800488e4, {CODEC_UTF32, 1, 0, 0, F010021D01474E000, "010021D01474E000", "1.0.0"}}, + {0x800bdb84, {CODEC_UTF32, 0, 0, 0, F010021D01474E000, "010021D01474E000", "1.0.0"}}, + {0x800e4540, {CODEC_UTF32, 0, 0, 0, F010021D01474E000, "010021D01474E000", "1.0.0"}}, + // Dairoku: Ayakashimori (DAIROKU:AYAKASHIMORI) + {0x800e35ec, {CODEC_UTF8, 0, 0, 0, F010061300DF48000, "010061300DF48000", "1.0.1"}}, + {0x800d103c, {CODEC_UTF8, 0, 0, 0, F010061300DF48000, "010061300DF48000", "1.0.1"}}, + {0x800f1320, {CODEC_UTF8, 0, 0, T010061300DF48000, FF010061300DF48000_2, "010061300DF48000", "1.0.1"}}, + // Charade Maniacs / CharadeManiacs + {0x8001c460, {CODEC_UTF8, 0, 0x5c, 0, F0100CEF0152DE000, "0100CEF0152DE000", "1.0.0"}}, + {0x8004c390, {CODEC_UTF8, 1, 0, 0, F0100CEF0152DE000, "0100CEF0152DE000", "1.0.0"}}, + {0x80050d60, {CODEC_UTF8, 0, 0, 0, F0100CEF0152DE000, "0100CEF0152DE000", "1.0.0"}}, + {0x8007ee20, {CODEC_UTF8, 0, 0, 0, F0100CEF0152DE000, "0100CEF0152DE000", "1.0.0"}}, + // Hanaemu Kare to & bloom (花笑む彼と & bloom) + {0x833e4d84, {CODEC_UTF16, 0, 0x14, 0, F0100DEF01D0C6000, "0100DEF01D0C6000", "1.0.0"}}, + {0x8335f650, {CODEC_UTF16, 0, 0x14, 0, F0100DEF01D0C6000, "0100DEF01D0C6000", "1.0.0"}}, + {0x81729520, {CODEC_UTF16, 1, 0x14, 0, F0100DEF01D0C6000_2, "0100DEF01D0C6000", "1.0.0"}}, + {0x83375938, {CODEC_UTF16, 0, 0, T0100DEF01D0C6000_2, 0, "0100DEF01D0C6000", "1.0.0"}}, + // Dance with Devils + {0x81616034, {CODEC_UTF16, 0, 0x14, 0, F01004E5017C54000, "01004E5017C54000", "1.0.0"}}, + {0x8185a800, {CODEC_UTF16, 0, 0x14, 0, F01004E5017C54000, "01004E5017C54000", "1.0.0"}}, + // My9Swallows TOPSTARS LEAGUE + {0x818554ac, {CODEC_UTF16, 0, 0x14, 0, F01003BB01DF54000, "01003BB01DF54000", "1.0.0"}}, + {0x817b76d4, {CODEC_UTF16, 0, 0x14, 0, F01003BB01DF54000, "01003BB01DF54000", "1.0.0"}}, + {0x8187882c, {CODEC_UTF16, 0, 0x14, 0, F01003BB01DF54000, "01003BB01DF54000", "1.0.1"}}, + {0x817b8f64, {CODEC_UTF16, 0, 0x14, 0, F01003BB01DF54000, "01003BB01DF54000", "1.0.1"}}, + // Tokeijikake no Apocalypse (時計仕掛けのアポカリプス) + {0x8001d9c4, {CODEC_UTF8, 0, 0x1c, 0, F01005AF00E9DC000, "01005AF00E9DC000", "1.0.0"}}, + {0x8004ca84, {CODEC_UTF8, 1, 0, 0, F01005AF00E9DC000, "01005AF00E9DC000", "1.0.0"}}, + {0x8005b304, {CODEC_UTF8, 0, 0, 0, F01005AF00E9DC000, "01005AF00E9DC000", "1.0.0"}}, + {0x8005b310, {CODEC_UTF8, 0, 0, 0, F01005AF00E9DC000, "01005AF00E9DC000", "1.0.0"}}, + // Shuuen no Virche -EpiC:lycoris- + {0x8002bf6c, {CODEC_UTF8, 0, 0x1c, 0, FF010061300DF48000_2, "01004D601B0AA000", "1.0.1"}}, + {0x8004e720, {CODEC_UTF8, 1, 0, 0, FF010061300DF48000_2, "01004D601B0AA000", "1.0.1"}}, + // Radiant Tale ~Fanfare!~ (ラディアンテイル ~ファンファーレ!~) + {0x8003a880, {CODEC_UTF8, 0, 0, 0, F010088B01A8FC000, "010088B01A8FC000", "1.0.1"}}, + {0x8004eb08, {CODEC_UTF8, 1, 0, 0, F010088B01A8FC000, "010088B01A8FC000", "1.0.1"}}, + {0x8005bff4, {CODEC_UTF8, 0, 0, 0, F010088B01A8FC000, "010088B01A8FC000", "1.0.1"}}, + {0x8005f0d4, {CODEC_UTF8, 3, 0, 0, F010088B01A8FC000, "010088B01A8FC000", "1.0.1"}}, + // LoverPretend / Lover Pretend + {0x80034ad0, {CODEC_UTF8, 0, 0, 0, F010032300C562000, "010032300C562000", "1.0.0"}}, + {0x8004e950, {CODEC_UTF8, 1, 0, 0, F010032300C562000, "010032300C562000", "1.0.0"}}, + {0x8002e6c4, {CODEC_UTF8, 0, 0, 0, F010032300C562000, "010032300C562000", "1.0.0"}}, + {0x8005f6ec, {CODEC_UTF8, 0, 0, 0, F010032300C562000, "010032300C562000", "1.0.0"}}, + // Norn9 ~Norn + Nonette~ LOFN (NORN9 ~ノルン+ノネット~ LOFN) + {0x8002b200, {CODEC_UTF8, 1, 0x18, 0, F010061300DF48000, "01001A500AD6A000", "1.0.0"}}, + {0x8003d83c, {CODEC_UTF8, 0, 0, 0, F010061300DF48000, "01001A500AD6A000", "1.0.0"}}, + {0x80047850, {CODEC_UTF8, 0, 0, 0, F010061300DF48000, "01001A500AD6A000", "1.0.0"}}, + // Shiritsu Berubara Gakuen ~Versailles no Bara Re*imagination~ (私立ベルばら学園 ~ベルサイユのばらRe*imagination~) + {0x8001b68c, {CODEC_UTF8, 0, 0x1c, 0, F010027300A660000, "010027300A660000", "1.0.0"}}, + {0x800460f0, {CODEC_UTF8, 1, 0, 0, F010027300A660000, "010027300A660000", "1.0.0"}}, + // Himehibi Another Princess Days -White or Black- (ひめひび Another Princess Days – White or Black –) + {0x219ed0 - 0x204000 + 0x80004000, {0, 0, 0, 0, F0100E4000F616000, "0100E4000F616000", "1.0.0"}}, + {0x21a3e0 - 0x204000 + 0x80004000, {0, 0, 0, 0, F0100E4000F616000, "0100E4000F616000", "1.0.0"}}, + // Himehibi -Princess Days- (ひめひび -Princess Days-) + {0x20d7b8 - 0x204000 + 0x80004000, {0, 0, 0, 0, F0100E4000F616000, "0100F8D0129F4000", "1.0.0"}}, + {0x20da9c - 0x204000 + 0x80004000, {0, 0, 0, 0, F0100E4000F616000, "0100E4000F616000", "1.0.0"}}, + {0x20d834 - 0x204000 + 0x80004000, {0, 0, 0, 0, F0100E4000F616000, "0100F8D0129F4000", "1.0.1"}}, + {0x20dae8 - 0x204000 + 0x80004000, {0, 0, 0, 0, F0100E4000F616000, "0100E4000F616000", "1.0.1"}}, + // オホーツクに消ゆ ~追憶の流氷・涙のニポポ人形~ + {0x83d4bda0, {CODEC_UTF16, 1, 0x14, 0, F010044701E9BC000, "010044701E9BC000", "1.2.0"}}, + {0x83d59320, {CODEC_UTF16, 0, 0x14, 0, F010044701E9BC000, "010044701E9BC000", "1.2.0"}}, + {0x83d22530, {CODEC_UTF16, 0, 0x14, 0, F010044701E9BC000, "010044701E9BC000", "1.2.0"}}, + {0x83d225c0, {CODEC_UTF16, 0, 0x14, 0, F010044701E9BC000, "010044701E9BC000", "1.2.0"}}, + {0x83d26fd8, {CODEC_UTF16, 0, 0x14, 0, F010044701E9BC000, "010044701E9BC000", "1.2.0"}}, + // Trouble Magia ~Wakeari Shoujo wa Mirai o Kachitoru Tame ni Ikoku no Mahou Gakkou e Ryuugaku Shimasu~ (トラブル・マギア ~訳アリ少女は未来を勝ち取るために異国の魔法学校へ留学します~) + {0x8017e6b0, {CODEC_UTF16, 0, 0, T01000BB01CB8A000<1>, F01000BB01CB8A000, "01000BB01CB8A000", "1.0.0"}}, + {0x80177ae0, {CODEC_UTF16, 0, 0, T01000BB01CB8A000<0>, F01000BB01CB8A000, "01000BB01CB8A000", "1.0.0"}}, + {0x80122a4c, {CODEC_UTF16, 0, 0, T01000BB01CB8A000<0>, F01000BB01CB8A000, "01000BB01CB8A000", "1.0.0"}}, + {0x800ba088, {CODEC_UTF16, 0, 0, T01000BB01CB8A000<0>, F01000BB01CB8A000, "01000BB01CB8A000", "1.0.0"}}, + // Moeyo! Otome Doushi ~Kayuu Koigatari~ (燃えよ! 乙女道士 ~華遊恋語~) + {0x8005c698, {CODEC_UTF16, 1, 0x20, 0, F01001BA01EBFC000, "01001BA01EBFC000", "1.0.0"}}, + {0x80051cd0, {CODEC_UTF16, 1, 0, 0, F01001BA01EBFC000, "01001BA01EBFC000", "1.0.0"}}, + + }; + return 1; + }(); +} \ No newline at end of file diff --git a/LunaHook/engine64/yuzu.h b/LunaHook/engine64/yuzu.h new file mode 100644 index 0000000..e7cfdb8 --- /dev/null +++ b/LunaHook/engine64/yuzu.h @@ -0,0 +1,17 @@ + + +class yuzu : public ENGINE +{ +public: + yuzu() + { + + is_engine_certain = false; + check_by = CHECK_BY::CUSTOM; + check_by_target = []() + { + return (wcscmp(processName_lower, L"suyu.exe") == 0 || wcscmp(processName_lower, L"yuzu.exe") == 0 || wcscmp(processName_lower, L"sudachi.exe") == 0); + }; + }; + bool attach_function(); +}; diff --git a/LunaHook/engine64/yuzusuyu.cpp b/LunaHook/engine64/yuzusuyu.cpp deleted file mode 100644 index 927ee88..0000000 --- a/LunaHook/engine64/yuzusuyu.cpp +++ /dev/null @@ -1,2236 +0,0 @@ -#include"yuzusuyu.h" -#include"mages/mages.h" -namespace{ - auto isFastMem = true; - - auto isVirtual = true;//Process.arch === 'x64' && Process.platform === 'windows'; - auto idxDescriptor = isVirtual == true ? 2 : 1; - auto idxEntrypoint = idxDescriptor + 1; - -uintptr_t getDoJitAddress() { - auto RegisterBlockSig1 = "E8 ?? ?? ?? ?? 4? 8B ?? 4? 8B ?? 4? 8B ?? E8 ?? ?? ?? ?? 4? 89?? 4? 8B???? ???????? 4? 89?? ?? 4? 8B?? 4? 89"; - auto RegisterBlock=find_pattern(RegisterBlockSig1,processStartAddress,processStopAddress); - if (RegisterBlock) { - auto beginSubSig1 = "CC 40 5? 5? 5?"; - auto lookbackSize = 0x400; - auto address=RegisterBlock-lookbackSize; - auto subs=find_pattern(beginSubSig1,address,address+lookbackSize); - if(subs){ - return subs+1; - } - } - - auto PatchSig1 = "4????? 4????? 4????? FF?? ?? 4????? ?? 4????? 75 ?? 4????? ?? 4????? ?? 4?"; - auto Patch = find_pattern(PatchSig1,processStartAddress,processStopAddress); - if (Patch) { - auto beginSubSig1 = "4883EC ?? 48"; - auto lookbackSize = 0x80; - auto address = Patch-lookbackSize; - auto subs = find_pattern(beginSubSig1,address,address+lookbackSize); - if (subs) { - idxDescriptor = 1; - idxEntrypoint = 2; - return subs; - } - } - return 0; - /* - 这块不知道怎么实现。 - // DebugSymbol: RegisterBlock - // ?RegisterBlock@EmitX64@X64@Backend@Dynarmic@@IEAA?AUBlockDescriptor@1234@AEBVLocationDescriptor@IR@4@PEBX_K@Z <- new - // ?RegisterBlock@EmitX64@X64@Backend@Dynarmic@@IEAA?AUBlockDescriptor@1234@AEBVLocationDescriptor@IR@4@PEBX1_K@Z - const symbols = DebugSymbol.findFunctionsMatching('Dynarmic::Backend::X64::EmitX64::RegisterBlock'); - if (symbols.length !== 0) { - return symbols[0]; - } - - // DebugSymbol: Patch - // ?Patch@EmitX64@X64@Backend@Dynarmic@@IEAAXAEBVLocationDescriptor@IR@4@PEBX@Z - const patchs = DebugSymbol.findFunctionsMatching('Dynarmic::Backend::X64::EmitX64::Patch'); - if (patchs.length !== 0) { - idxDescriptor = 1; - idxEntrypoint = 2; - return patchs[0]; - } - */ -} - - -struct emfuncinfo{ - uint64_t type; - int argidx;int padding; - void* hookfunc; - void* filterfun; - const char* _id; - const char* _version; -}; -std::unordered_mapemfunctionhooks; - -struct GameInfo { - std::string name{""}; - uint64_t id{0}; - std::string version{""}; -} game_info; -bool checkiscurrentgame(const emfuncinfo& em){ - auto wininfos=get_proc_windows(); - for(auto&& info:wininfos){ - if((game_info.version.size())&&game_info.name.size()&&(game_info.id!=0)){ - //判断是有效的info - auto checkversion=(em._version==0)||(std::string(em._version)==(game_info.version)); - auto checkid=(std::stoll(em._id,0,16)==game_info.id); - if(checkid&&checkversion)return true; - } - else if((em._version==0)||(info.title.find(acastw(em._version))!=info.title.npos))return true; - } - return false; -} -} -bool Hook_Network_RoomMember_SendGameInfo(){ - // void RoomMember::SendGameInfo(const GameInfo& game_info) { - // room_member_impl->current_game_info = game_info; - // if (!IsConnected()) - // return; - - // Packet packet; - // packet.Write(static_cast(IdSetGameInfo)); - // packet.Write(game_info.name); - // packet.Write(game_info.id); - // packet.Write(game_info.version); - // room_member_impl->Send(std::move(packet)); - // } - BYTE pattern[]={ - 0x49,0x8B,XX, - 0x0F,0xB6,0x81,0x28,0x01,0x00,0x00, - 0x90, - 0x3C,0x02, - 0x74,0x1C, - 0x0F,0xB6,0x81,0x28,0x01,0x00,0x00, - 0x90, - 0x3C,0x03, - 0x74,0x10, - 0x0F,0xB6,0x81,0x28,0x01,0x00,0x00, - 0x90, - 0x3C,0x04, - 0x0F,0x85,XX4 - }; - for(auto addr:Util::SearchMemory(pattern,sizeof(pattern),PAGE_EXECUTE,processStartAddress,processStopAddress)) - { - addr=MemDbg::findEnclosingAlignedFunction_strict(addr,0x100); - //有两个,但另一个离起始很远 - if(addr==0)continue; - HookParam hp; - hp.address=addr; - hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - // void __fastcall Network::RoomMember::SendGameInfo( - // Network::RoomMember *this, - // const AnnounceMultiplayerRoom::GameInfo *game_info) - game_info=*(GameInfo*)stack->rdx; - ConsoleOutput("%s %llx %s",game_info.name.c_str(),game_info.id,game_info.version.c_str()); - }; - return NewHook(hp,"yuzuGameInfo"); - } - return false; -} -bool yuzusuyu::attach_function() -{ - Hook_Network_RoomMember_SendGameInfo(); - ConsoleOutput("[Compatibility] Yuzu 1616+"); - auto DoJitPtr=getDoJitAddress(); - if(DoJitPtr==0)return false; - spDefault.jittype=JITTYPE::YUZU; - spDefault.minAddress = 0; - spDefault.maxAddress = -1; - ConsoleOutput("DoJitPtr %p",DoJitPtr); - HookParam hp; - hp.address=DoJitPtr; - hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto descriptor = *argidx(stack,idxDescriptor+1); // r8 - auto entrypoint = *argidx(stack,idxEntrypoint+1); // r9 - auto em_address = *(uintptr_t*)descriptor; - if(!entrypoint)return; - jitaddraddr(em_address,entrypoint,JITTYPE::YUZU); - [&](){ - if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return; - auto op=emfunctionhooks.at(em_address); - if(!(checkiscurrentgame(op)))return; - - HookParam hpinternal; - hpinternal.address=entrypoint; - hpinternal.emu_addr=em_address;//用于生成hcode - hpinternal.type=USING_STRING|NO_CONTEXT|BREAK_POINT|op.type; - hpinternal.text_fun=(decltype(hpinternal.text_fun))op.hookfunc; - hpinternal.filter_fun=(decltype(hpinternal.filter_fun))op.filterfun; - hpinternal.argidx=op.argidx; - hpinternal.padding=op.padding; - hpinternal.jittype=JITTYPE::YUZU; - NewHook(hpinternal,op._id); - }(); - delayinsertNewHook(em_address); - }; - return NewHook(hp,"YuzuDoJit"); -} - - -namespace{ -int readu8(BYTE* addr){ - int numBytes = 0; - auto firstByte=*addr; - if (firstByte <= 0x7F) { - numBytes = 1; - } else if ((firstByte & 0xE0) == 0xC0) { - numBytes = 2; - } else if ((firstByte & 0xF0) == 0xE0) { - numBytes = 3; - } else if ((firstByte & 0xF8) == 0xF0) { - numBytes = 4; - } - return numBytes; -} -void T010012A017F18000(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address=YUZU::emu_arg(stack)[2]; - std::string s,bottom;uint32_t c; - while (true) - { - c=*(BYTE*)(address); - if(c==0)break; - if(c>=0x20){ - auto l=readu8((BYTE*)address); - s+=std::string((char*)address,l); - address+=l; - } - else{ - address+=1; - if(c==1){ - bottom=""; - while(true){ - auto l=readu8((BYTE*)address); - auto ss=std::string((char*)address,l); - address+=l; - if(ss[0]<0xa)break; - bottom+=ss; - s+=ss; - } - } - else if(c==3){ - while (true) { - auto l=readu8((BYTE*)address); - auto ss=std::string((char*)address,l); - address+=l; - if(ss[0]<0xa)break; - } - } - else if(c==7){ - address+=1; - } - else if(c==0xa){ - return; - } - else if(c==0xd){ - c = *(uint32_t*)address; - auto count = c & 0xFF; - c = c & 0xFFFFFF00; - if (c == 0x0692c500) { - for(int _=0;_ -void ReadTextAndLenDW(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address=YUZU::emu_arg(stack)[index]; - *len=(*(DWORD*)(address+0x10))*2; - *data=address+0x14; -} - -template -void ReadTextAndLenW(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address=YUZU::emu_arg(stack)[index]; - *len=(*(WORD*)(address+0x10))*2; - *data=address+0x14; -} -template -void mages_readstring(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto s=mages::readString(YUZU::emu_arg(stack)[0],idx); - write_string_new(data,len,s); -} - - -bool F0100A3A00CC7E000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - - std::wregex pattern1(L"^`([^@]+)."); - s = std::regex_replace(s, pattern1, L"$1: "); - - s = std::regex_replace(s, std::wregex(L"\\$[A-Z]\\d*(,\\d*)*"), L""); - - std::wregex pattern2(L"\\$\\[([^$]+)..([^$]+).."); - s = std::regex_replace(s, pattern2, L"$1"); - return write_string_overwrite(data,len,s); -} - -bool F010045C0109F2000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("#[^\\]]*\\]"), ""); - s = std::regex_replace(s, std::regex("#[^\\n]*\\n"), ""); - s = std::regex_replace(s, std::regex("\\u3000"), ""); - s = std::regex_replace(s, std::regex(u8"Save[\\s\\S]*データ"), ""); - return write_string_overwrite(data,len,s); -} - -bool F0100A1E00BFEA000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); - s = std::regex_replace(s, std::wregex(L"(.+? \")"), L""); - s = std::regex_replace(s, std::wregex(L"(\",.*)"), L""); - s = std::regex_replace(s, std::wregex(L"(\" .*)"), L""); - return write_string_overwrite(data,len,s); -} - - - -bool F0100A1200CA3C000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\$d"), L"\n"); - s = std::regex_replace(s, std::wregex(L"_"), L" "); - s = std::regex_replace(s, std::wregex(L"@"), L" "); - s = std::regex_replace(s, std::wregex(L"\\[([^\\/\\]]+)\\/[^\\/\\]]+\\]"), L"$1"); - s = std::regex_replace(s, std::wregex(L"[~^$❝.❞'?,(-)!—:;-❛ ❜]"), L""); - s = std::regex_replace(s, std::wregex(L"[A-Za-z0-9]"), L""); - s = std::regex_replace(s, std::wregex(L"^\\s+"), L""); - while (std::regex_search(s, std::wregex(L"^\\s*$"))) { - s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); - } - return write_string_overwrite(data,len,s); -} - - -bool F0100F6A00A684000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - - std::regex regex("(?=@.)"); - std::sregex_token_iterator it(s.begin(), s.end(), regex, -1); - std::sregex_token_iterator end; - - std::vector parts(it, end); - s=""; - for(auto part:parts){ - if (startWith(part,"@")==false) { - s += part; - continue; - } - std::string tag = part.substr(0, 2); - std::string content = part.substr(2); - if (tag == "@r") { - if(s=="")s=content; - else s+='\n'+content; - } else if (tag == "@u"||tag == "@v"||tag == "@w"||tag == "@o"||tag == "@a"||tag == "@z"||tag == "@c"||tag == "@s") { - auto splited=strSplit(content,"."); - if(splited.size()==2) - s += splited[1]; - } else if (tag == "@b") { - } else { - s += content; - } - } - static auto katakanaMap =std::map{ - {L"「",L"「"},{L"」",L"」"},{L"ァ",L"ぁ"},{L"ィ",L"ぃ"},{L"ゥ",L"ぅ"},{L"ェ",L"ぇ"},{L"ォ",L"ぉ"},{L"ャ",L"ゃ"},{ - L"ュ",L"ゅ"},{L"ョ",L"ょ"},{L"ア",L"あ"},{L"イ",L"い"},{L"ウ",L"う"},{L"エ",L"え"},{L"オ",L"お"},{L"カ",L"か"},{ - L"キ",L"き"},{L"ク",L"く"},{L"ケ",L"け"},{L"コ",L"こ"},{L"サ",L"さ"},{L"シ",L"し"},{L"ス",L"す"},{L"セ",L"せ"},{ - L"ソ",L"そ"},{L"タ",L"た"},{L"チ",L"ち"},{L"ツ",L"つ"},{L"テ",L"て"},{L"ト",L"と"},{L"ナ",L"な"},{L"ニ",L"に"},{ - L"ヌ",L"ぬ"},{L"ネ",L"ね"},{L"ノ",L"の"},{L"ハ",L"は"},{L"ヒ",L"ひ"},{L"フ",L"ふ"},{L"ヘ",L"へ"},{L"ホ",L"ほ"},{ - L"マ",L"ま"},{L"ミ",L"み"},{L"ム",L"む"},{L"メ",L"め"},{L"モ",L"も"},{L"ヤ",L"や"},{L"ユ",L"ゆ"},{L"ヨ",L"よ"},{ - L"ラ",L"ら"},{L"リ",L"り"},{L"ル",L"る"},{L"レ",L"れ"},{L"ロ",L"ろ"},{L"ワ",L"わ"},{L"ヲ",L"を"},{L"ン",L"ん"},{ - L"ー",L"ー"},{L"ッ",L"っ"},{L"、",L"、"},{L"゚",L"?"},{L"゙",L"!"},{L"・",L"…"},{L"?",L" "},{L"。",L"。"},{ - L"\uF8F0",L""},{L"\uFFFD",L""} // invalid (shift_jis A0 <=> EF A3 B0) | FF FD - F8 F0) - }; - - auto remap=[](std::string s) { - std::wstring result; - auto ws=StringToWideString(s,932).value(); - for (auto _c:ws) { - std::wstring c; - c.push_back(_c); - if(katakanaMap.find(c)!=katakanaMap.end()){ - result += katakanaMap[c]; - } - else - result+=c; - } - return WideStringToString(result,932); - }; - return write_string_overwrite(data,len,remap(s)); -} -bool F01006590155AC000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - - std::regex regex("(?=@.)"); - std::sregex_token_iterator it(s.begin(), s.end(), regex, -1); - std::sregex_token_iterator end; - - std::vector parts(it, end); - s=""; - int counter = 0; - while (counter < parts.size()) { - std::string part = parts[counter]; - if (part[0] != '@') { - s += part; - counter++; - continue; - } - std::string tag = part.substr(0, 2); - std::string content = part.substr(2); - if (tag == "@s" || tag == "@t") { - s += content.substr(4); - counter++; - continue; - } else if (tag == "@m") { - s += content.substr(2); - counter++; - continue; - } else if (tag == "@n") { - s += '\n' + content; - counter++; - continue; - } else if (tag == "@b" || tag == "@a" || tag == "@p" || tag == "@k") { - s += content; - counter++; - continue; - } else if (tag == "@v" || tag == "@h") { - std::regex regex("[\\w_-]+"); - s += std::regex_replace(content, regex, ""); - counter++; - continue; - } else if (tag == "@r") { - s += content + parts[counter + 2].substr(1); - counter += 3; - continue; - } else if (tag == "@I") { - if (content == "@" || parts[counter + 1].substr(0, 2) == "@r") { - counter++; - continue; - } - std::regex regex(u8"[\\d+─]"); - s += std::regex_replace(content, regex, ""); - counter += 3; - continue; - } else { - s += content; - counter++; - continue; - } - } - return write_string_overwrite(data,len,s); -} -bool F01000200194AE000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - - static std::string readString_savedSentence=""; - static bool readString_playerNameFlag=false; - static std::string readString_playerName=u8"ラピス"; - - std::regex regex("(?=@.)"); - std::sregex_token_iterator it(s.begin(), s.end(), regex, -1); - std::sregex_token_iterator end; - - std::vector parts(it, end); - s = ""; - size_t counter = 0; - - while (counter < parts.size()) { - const std::string& part = parts[counter]; - - if (part.empty() || part[0] != '@') { - s += part; - counter++; - continue; - } - - std::string tag = part.substr(0, 2); - std::string content = part.substr(2); - - if (tag == "@*") { - if (content.find("name") == 0) { - if (readString_playerName == u8"ラピス") { - s += content.substr(4) + readString_playerName + parts[counter + 4].substr(1); - } else { - s += content.substr(4) + parts[counter + 3].substr(1) + parts[counter + 4].substr(1); - } - counter += 5; - continue; - } - } else if (tag == "@s" || tag == "@t") { - s += content.substr(4); - counter++; - continue; - } else if (tag == "@m") { - s += content.substr(2); - counter++; - continue; - } else if (tag == "@u") { - readString_playerNameFlag = true; - readString_savedSentence = ""; - counter++; - return write_string_overwrite(data,len,""); - } else if (tag == "@n" || tag == "@b" || tag == "@a" || tag == "@p" || tag == "@k") { - s += content; - counter++; - continue; - } else if (tag == "@v" || tag == "@h") { - std::regex regex("[\\w_-]+"); - s += std::regex_replace(content, regex, ""); - counter++; - continue; - } else if (tag == "@r") { - s += content + parts[counter + 2].substr(1); - counter += 3; - continue; - } else if (tag == "@I") { - if (content == "@" || parts[counter + 1].substr(0, 2) == "@r") { - counter++; - continue; - } - std::regex regex(u8"[\\d+─]"); - s += std::regex_replace(content, regex, ""); - counter += 3; - continue; - } else { - s += content; - counter++; - continue; - } - } - - if (!readString_playerNameFlag) { - ; - } else if (readString_savedSentence.empty()) { - readString_savedSentence = s; - s= ""; - } else { - std::string savedSentence = readString_savedSentence; - readString_playerNameFlag = false; - readString_savedSentence = ""; - readString_playerName = s; - s= s + "\n" + savedSentence; - } - return write_string_overwrite(data,len,s); -} -bool F0100EA001A626000(void* data, size_t* len, HookParam* hp){ - auto s=utf32_to_utf16((uint32_t*)data,*len/4); - if (s == L"  ") { - return false; - } - s = std::regex_replace(s, std::wregex(L"\n+"), L" "); - - s = std::regex_replace(s, std::wregex(L"\\$\\{FirstName\\}"), L"ナーヤ"); - - if (startWith(s,L"#T")){ - s = std::regex_replace(s, std::wregex(L"#T2[^#]+"), L""); - s = std::regex_replace(s, std::wregex(L"#T\\d"), L""); - } - auto u32=utf16_to_utf32(s.c_str(),s.size()); - return write_string_overwrite(data,len,u32); -} -bool F010093800DB1C000(void* data, size_t* len, HookParam* hp){ - auto s=utf32_to_utf16((uint32_t*)data,*len/4); - s = std::regex_replace(s, std::wregex(L"\\n+"), L" "); - s = std::regex_replace(s, std::wregex(L"\\$\\{FirstName\\}"), L"シリーン"); - if (startWith(s,L"#T")) { - s = std::regex_replace(s, std::wregex(L"\\#T2[^#]+"), L""); - s = std::regex_replace(s, std::wregex(L"\\#T\\d"), L""); - } - auto u32=utf16_to_utf32(s.c_str(),s.size()); - return write_string_overwrite(data,len,u32); -} -bool F0100F7E00DFC8000(void* data, size_t* len, HookParam* hp){ - auto s=utf32_to_utf16((uint32_t*)data,*len/4); - s = std::regex_replace(s, std::wregex(L"[\\s]"), L" "); - s = std::regex_replace(s, std::wregex(L"#KW"), L""); - s = std::regex_replace(s, std::wregex(L"#C\\(TR,0xff0000ff\\)"), L""); - s = std::regex_replace(s, std::wregex(L"#P\\(.*\\)"), L""); - auto u32=utf16_to_utf32(s.c_str(),s.size()); - return write_string_overwrite(data,len,u32); -} - -bool F0100982015606000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\n+|(\\\\n)+"), L" "); - return write_string_overwrite(data,len,s); -} -bool F0100C4E013E5E000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\\\n"), L" "); - return write_string_overwrite(data,len,s); -} - -bool F010001D015260000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - if(startWith(s,"#Key"))return false; - strReplace(s,"#n","\n"); - return write_string_overwrite(data,len,s); -} -bool F0100E1E00E2AE000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("#n"), "\n"); - s = std::regex_replace(s, std::regex("[A-Za-z0-9]"), ""); - s = std::regex_replace(s, std::regex("[~^,\\-\\[\\]#]"), ""); - return write_string_overwrite(data,len,s); -} -bool F0100DE200C0DA000(void* data, size_t* len, HookParam* hp){ - StringReplacer((char*)data,len,"#n",2," ",1); - StringReplacer((char*)data,len,"\n",1," ",1); - return true; -} -bool F0100AEC013DDA000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - static std::string ss; - if(ss==s)return false; - ss=s; - return true; -} - -bool F0100F7801B5DC000(void* data, size_t* len, HookParam* hp){ - if(!all_ascii((wchar_t*)data))return false;//chaos on first load. - StringReplacer((wchar_t*)data,len,L"
",4,L"\n",1); - return true; -} - -bool F0100925014864000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("(#n)+"), " "); - s = std::regex_replace(s, std::regex("(#[A-Za-z]+\\[(\\d*[.])?\\d+\\])+"), ""); - return write_string_overwrite(data,len,s); -} - -bool F0100936018EB4000(void* data, size_t* len, HookParam* hp){ - auto s=utf32_to_utf16((uint32_t*)data,*len/4); - s = std::regex_replace(s, std::wregex(L"<[^>]+>"), L""); - s = std::regex_replace(s, std::wregex(L"\n+"), L" "); - auto u32=utf16_to_utf32(s.c_str(),s.size()); - return write_string_overwrite(data,len,u32); -} - -template -void T0100B0100E26C000(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address=YUZU::emu_arg(stack)[index]; - if(type==2) - address+=0xA; - auto length=(*(DWORD*)(address+0x10))*2; - *len=length; - *data=address+0x14; -} - -bool F010045C014650000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - std::regex pattern("(@(\\/)?[a-zA-Z#](\\(\\d+\\))?|)[*<>]+"); - s = std::regex_replace(s, pattern, ""); - return write_string_overwrite(data,len,s); -} - -bool F01008C0016544000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"<[^>]+>"), L" "); - return write_string_overwrite(data,len,s); -} -bool F0100FB7019ADE000(void* data, size_t* len, HookParam* hp){ - static int idx=0; - return ((++idx)%2==1); -} -bool F01006F000B056000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\[.*?\\]"), L" "); - return write_string_overwrite(data,len,s); -} -bool F0100068019996000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("%N"), "\n"); - return write_string_overwrite(data,len,s); -} -bool F0100ADC014DA0000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - std::wregex symbolRegex(L"[~^$(,)]"); - std::wregex alphanumericRegex(L"[A-Za-z0-9]"); - std::wregex atRegex(L"@"); - std::wregex leadingSpaceRegex(L"^\\s+"); - s = std::regex_replace(s, symbolRegex, L""); - s = std::regex_replace(s, alphanumericRegex, L""); - s = std::regex_replace(s, atRegex, L" "); - s = std::regex_replace(s, leadingSpaceRegex, L""); - return write_string_overwrite(data,len,s); -} -bool F0100AFA01750C000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - std::regex newlineRegex("(\\\\n)+"); - std::regex specialCharsRegex("\\\\d$|^\\@[a-z]+|#.*?#|\\$"); - s = std::regex_replace(s, newlineRegex, " "); - s = std::regex_replace(s, specialCharsRegex, ""); - return write_string_overwrite(data,len,s); -} -bool F0100B6900A668000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("#N"), "\n"); - std::regex colorRegex("#Color\\[[\\d]+\\]"); - s = std::regex_replace(s, colorRegex, ""); - return write_string_overwrite(data,len,s); -} -bool F0100BD700E648000(void* data, size_t* len, HookParam* hp){ - StringReplacer((char*)data,len,"*",1," ",1); - StringReplacer((char*)data,len,u8"ゞ",sizeof(u8"ゞ"),u8"!?",sizeof(u8"!?")); - return true; -} -bool F0100D9500A0F6000(void* data, size_t* len, HookParam* hp){ - StringReplacer((char*)data,len,u8"㊤",sizeof(u8"㊤"),u8"―",sizeof(u8"―")); - StringReplacer((char*)data,len,u8"㊥",sizeof(u8"㊥"),u8"―",sizeof(u8"―")); - StringReplacer((char*)data,len,u8"^㌻",sizeof(u8"^㌻"),u8" ",sizeof(u8" "));// \n - return true; -} - -bool F0100DA201E0DA000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); - return write_string_overwrite(data,len,s); -} -bool F01002C0008E52000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("(YUR)"), u8"ユーリ"); - s = std::regex_replace(s, std::regex("(FRE)"), u8"フレン"); - s = std::regex_replace(s, std::regex("(RAP)"), u8"ラピード"); - s = std::regex_replace(s, std::regex("(EST|ESU)"), u8"エステル"); - s = std::regex_replace(s, std::regex("(KAR)"), u8"カロル"); - s = std::regex_replace(s, std::regex("(RIT)"), u8"リタ"); - s = std::regex_replace(s, std::regex("(RAV|REI)"), u8"レイヴン"); - s = std::regex_replace(s, std::regex("(JUD)"), u8"ジュディス"); - s = std::regex_replace(s, std::regex("(PAT)"), u8"パティ"); - s = std::regex_replace(s, std::regex("(DUK|DYU)"), u8"デューク"); - s = std::regex_replace(s, std::regex("[A-Za-z0-9]"), ""); - s = std::regex_replace(s, std::regex("[,(-)_]"), ""); - s = std::regex_replace(s, std::regex("^\\s+"), ""); - while (std::regex_search(s, std::regex("^\\s*$"))) { - s = std::regex_replace(s, std::regex("^\\s*$"), ""); - } - return write_string_overwrite(data,len,s); -} - -bool F01005940182EC000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - std::wregex whitespaceRegex(L"\\s"); - s = std::regex_replace(s, whitespaceRegex, L""); - std::wregex colorRegex(L"(.*?)<\\/color>"); - s = std::regex_replace(s, colorRegex, L"$1"); - return write_string_overwrite(data,len,s); -} -void T01005940182EC000(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address=YUZU::emu_arg(stack)[0]; - *data=address+0x14; - *len=wcslen((wchar_t*)*data)*2; -} -template -bool F0100B0601852A000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - static std::wstring last; - if(last==s)return false; - last=s; - return true; -} -bool F010027100C79A000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - static std::string last; - if(last==s)return false; - last=s; - return true; -} -template -bool F0100B0C016164000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - std::wregex htmlTagsPattern(L"<[^>]*>"); - std::wregex lettersAndNumbersPattern(L"[A-Za-z0-9]"); - s = std::regex_replace(s, htmlTagsPattern, L""); - s = std::regex_replace(s, lettersAndNumbersPattern, L""); - static std::wstring last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} - -template -bool F010043B013C5C000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - std::wregex htmlTagsPattern(L"<[^>]*>"); - s = std::regex_replace(s, htmlTagsPattern, L""); - static std::wstring last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} -template -bool F010055D009F78000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - std::regex pattern3("\\d+"); - s = std::regex_replace(s, pattern3, ""); - static std::string last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} - -bool F010080C01AA22000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - std::regex furiganaRegex("#\\d+R.*?#"); - s = std::regex_replace(s, furiganaRegex, ""); - std::regex lettersNumbersRegex("[A-Za-z0-9]"); - s = std::regex_replace(s, lettersNumbersRegex, ""); - std::regex symbolsRegex(u8"[().%,_!#©&:?/]"); - s = std::regex_replace(s, symbolsRegex, ""); - return write_string_overwrite(data,len,s); -} -template -bool F0100CB700D438000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - std::regex furiganaRegex("(.*?)<\\/RB>(.*?)<\\/RT><\\/RUBY>"); - s = std::regex_replace(s, furiganaRegex, "$1"); - std::regex htmlTagRegex("<[^>]*>"); - s = std::regex_replace(s, htmlTagRegex, ""); - static std::string last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} -bool F01005C301AC5E000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex(".*_.*_.*"), "");//SIR_C01_016,ERU_C00_000 - s = std::regex_replace(s, std::regex("\\.mp4"), ""); - s = std::regex_replace(s, std::regex("@v"), ""); - s = std::regex_replace(s, std::regex("@n"), "\n"); - return write_string_overwrite(data,len,s); -} -bool F0100815019488000_text(void* data, size_t* len, HookParam* hp){ - //@n@vaoi_s01_0110「うんうん、そうかも!」 - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("@.*_.*_\\d+"), ""); - s = std::regex_replace(s, std::regex("@n"), ""); - return write_string_overwrite(data,len,s); -} -bool F0100815019488000_name(void* data, size_t* len, HookParam* hp){ - // あおい@n@vaoi_s01_0110「うんうん、そうかも!」 - auto s = std::string((char*)data,*len); - if(s.find("@n")==s.npos)return false; - s = std::regex_replace(s, std::regex("(.*)@n.*"), "$1"); - return write_string_overwrite(data,len,s); -} -template -bool F010072000BD32000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - std::regex lineBreakRegex("\\[~\\]"); - s = std::regex_replace(s, lineBreakRegex, "\n"); - std::regex romRegex("rom:[\\s\\S]*$"); - s = std::regex_replace(s, romRegex, ""); - std::regex furiganaRegex("\\[[\\w\\d]*\\[[\\w\\d]*\\].*?\\[\\/\\[\\w\\d]*\\]\\]"); - s = std::regex_replace(s, furiganaRegex, ""); - std::regex bracketsRegex("\\[.*?\\]"); - s = std::regex_replace(s, bracketsRegex, ""); - static std::string last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} -template -bool F01009B50139A8000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - std::wregex htmlTagRegex(L"<[^>]*>"); - s = std::regex_replace(s, htmlTagRegex, L""); - std::wregex hoursRegex(L"\\b\\d{2}:\\d{2}\\b"); - s = std::regex_replace(s, hoursRegex, L""); - - auto _=L"^(?:スキップ|むしる|取り出す|話す|選ぶ|ならびかえ|閉じる|やめる|undefined|決定|ボロのクワ|拾う)$(\\r?\\n|\\r)?"; - while (std::regex_search(s, std::wregex(_))) { - s = std::regex_replace(s, std::wregex(_), L""); - } - while (std::regex_search(s, std::wregex(L"^\\s*$"))) { - s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); - } - static std::wstring last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} -bool F0100943010310000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - strReplace(s,u8"❞","\""); - strReplace(s,u8"❝","\""); - s = std::regex_replace(s, std::regex("@(.*?)@"), "$1\n"); - return write_string_overwrite(data,len,s); -} -bool F010027401A2A2000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - std::wregex dicRegex(L"\\[dic.*?text="); - s = std::regex_replace(s, dicRegex, L""); - std::wregex rubyRegex(L"\\[|'.*?\\]"); - s = std::regex_replace(s, rubyRegex, L""); - std::wregex closingBraceRegex(L"\\]"); - s = std::regex_replace(s, closingBraceRegex, L""); - std::wregex whitespaceRegex(L"\\s| "); - s = std::regex_replace(s, whitespaceRegex, L""); - return write_string_overwrite(data,len,s); -} -template -bool F0100BD4014D8C000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); - s = std::regex_replace(s, std::wregex(L".*?_"), L""); - static std::wstring last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} -template -bool F0100C7400CFB4000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\d"), L""); - s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); - while (std::regex_search(s, std::wregex(L"^\\s*$"))) { - s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); - } - static std::wstring last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} -bool F0100CB9018F5A000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); - s = std::regex_replace(s, std::wregex(L"\\{([^{}]+):[^{}]+\\}"), L"$1"); - return write_string_overwrite(data,len,s); -} - -bool F010028D0148E6000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("{|\\/.*?}|\\[.*?]", std::regex_constants::grep), ""); - s = std::regex_replace(s, std::regex("(\\\\\\\\c|\\\\\\\\n)+"), " "); - s = std::regex_replace(s, std::regex(",.*$"), " "); - return write_string_overwrite(data,len,s); -} - -bool F0100F4401940A000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"[\\r\\n]+"), L""); - s = std::regex_replace(s, std::wregex(L"<[^>]+>|\\[\\[[^]]+\\]\\]"), L""); - return write_string_overwrite(data,len,s); -} - -bool F0100B5500CA0C000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - std::regex pattern1("\\\\u0000+$"); - std::regex pattern2("\\\\"); - std::regex pattern3("\\$"); - s = std::regex_replace(s, pattern1, ""); - s = std::regex_replace(s, pattern2, ""); - s = std::regex_replace(s, pattern3, ""); - return write_string_overwrite(data,len,s); -} -void T0100B5500CA0C000(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address=YUZU::emu_arg(stack)[6]; - *data=address; - *len=*(WORD*)(address-2); -} -bool F0100A8401A0A8000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - std::wregex samePageNewLineRegex(L"[\r\n]+"); - s = std::regex_replace(s, samePageNewLineRegex, L""); - std::wregex newPageTextRegex(L"(<.+?>)+"); - s = std::regex_replace(s, newPageTextRegex, L"\r\n"); - strReplace(s,L"",L"(L)"); - strReplace(s,L"",L"(ZL)"); - strReplace(s,L"",L"(Y)"); - strReplace(s,L"",L"(X)"); - strReplace(s,L"",L"(A)"); - strReplace(s,L"",L"(B)"); - strReplace(s,L"",L"(+)"); - strReplace(s,L"",L"(-)"); - strReplace(s,L"",L"(DPAD_DOWN)"); - strReplace(s,L"",L"(DPAD_LEFT)"); - strReplace(s,L"",L"(LSTICK)"); - strReplace(s,L"",L"(L3)"); - return write_string_overwrite(data,len,s); -} -bool F0100BC0018138000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - std::wregex tagContentRegex(L"<[^>]*>([^<]*)<\\/[^>]*>"); - s = std::regex_replace(s, tagContentRegex, L""); - s = std::regex_replace(s, std::wregex(L""), L"L"); - s = std::regex_replace(s, std::wregex(L""), L"R"); - s = std::regex_replace(s, std::wregex(L""), L"A"); - s = std::regex_replace(s, std::wregex(L""), L"B"); - s = std::regex_replace(s, std::wregex(L""), L"X"); - s = std::regex_replace(s, std::wregex(L""), L"Y"); - s = std::regex_replace(s, std::wregex(L""), L"+"); - s = std::regex_replace(s, std::wregex(L""), L"-"); - s = std::regex_replace(s, std::wregex(L"<[^>]+>"), L""); - return write_string_overwrite(data,len,s); -} -bool F0100D7800E9E0000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"[A-Za-z0-9]"), L""); - s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); - s = std::regex_replace(s, std::wregex(L"^二十五字二.*(\r?\n|\r)?"), L""); - s = std::regex_replace(s, std::wregex(L"^操作を割り当てる.*(\r?\n|\r)?"), L""); - s = std::regex_replace(s, std::wregex(L"^上記アイコンが出.*(\r?\n|\r)?"), L""); - s = std::regex_replace(s, std::wregex(L"[()~^,ö.!]"), L""); - static std::wstring last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} -template -void T0100CF400F7CE000(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address=YUZU::emu_arg(stack)[idx]; - std::string s; - int i=0; - while(1){ - auto c=*(BYTE*)(address+i); - if(c==0)break; - if(c<0x20&&c>0x10){ - auto command=*(BYTE*)(address+i+1); - if(command==0x80) - i+=3; - else if(command==0xb8) - i+=4; - else{ - auto sz=*(BYTE*)(address+i+2); - i+=3+sz; - } - } - else if(c==0xaa){ - i+=1; - } - else if(c==0xff){ - i+=0x30; - } - else{ - auto l=1+IsDBCSLeadByteEx(932,c); - s+=std::string((char*)(address+i),l); - i+=l; - } - } - write_string_new(data,len,s); -} -void T0100DB300B996000(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address=YUZU::emu_arg(stack)[8]+1; - std::string s; - int i=0; - while(1){ - auto c=*(BYTE*)(address+i); - if(c==0)break; - if(c<0x20&&c>0x10){ - auto sz=*(BYTE*)(address+i+2); - i+=3+sz; - } - else{ - auto l=1+IsDBCSLeadByteEx(932,c); - s+=std::string((char*)(address+i),l); - i+=l; - } - } - write_string_new(data,len,s); -} -bool F0100CBA014014000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex(u8"《.*?》"), ""); - s = std::regex_replace(s, std::regex("<[^>]*>"), ""); - return write_string_overwrite(data,len,s); -} -template -bool F0100CC401A16C000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("<[^>]*>"), ""); - s = std::regex_replace(s, std::regex("\\d+"), ""); - if(s=="")return false; - static std::string last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} -bool F0100BDD01AAE4000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("(#Ruby\\[)([^,]+).([^\\]]+)."), "$2"); - s = std::regex_replace(s, std::regex("(#n)+"), " "); - s = std::regex_replace(s, std::regex("(#[A-Za-z]+[(\\d*[.])?\\d+])+"), ""); - return write_string_overwrite(data,len,s); -} -bool F0100C310110B4000(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("(#Ruby\\[)([^,]+).([^\\]]+)."), "$2"); - s = std::regex_replace(s, std::regex("#Color\\[[\\d]+\\]"), ""); - s = std::regex_replace(s, std::regex(u8"( #n)+"), "#n"); - s = std::regex_replace(s, std::regex("#n+"), " "); - return write_string_overwrite(data,len,s); -} -bool F010003F003A34000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"[\\s\\S]*$"), L""); - s = std::regex_replace(s, std::wregex(L"\n+"), L" "); - s = std::regex_replace(s, std::wregex(L"\\s"), L""); - s = std::regex_replace(s, std::wregex(L"[＀븅]"), L""); - return write_string_overwrite(data,len,s); -} - - -bool F01007B601C608000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); - s = std::regex_replace(s, std::wregex(L"\\[.*?\\]"), L""); - std::vector lines = strSplit(s, L"\n"); - std::wstring result; - for (const std::wstring& line : lines) { - if(result.empty()==false)result+=L"\n"; - std::wregex commandRegex(L"^(?:メニュー|システム|Ver\\.)$(\\r?\\n|\\r)?"); - s = std::regex_replace(s, commandRegex, L""); - std::wregex emptyLineRegex(L"^\\s*$"); - s = std::regex_replace(s, emptyLineRegex, L""); - } - static std::wstring last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} - -bool F010046601125A000(void* data, size_t* len, HookParam* hp){ - auto s=utf32_to_utf16((uint32_t*)data,*len/4); - s = std::regex_replace(s, std::wregex(L"(.+?).+?"), L"$1"); - s = std::regex_replace(s, std::wregex(L"\n+"), L" "); - auto u32=utf16_to_utf32(s.c_str(),s.size()); - return write_string_overwrite(data,len,u32); -} -bool F0100771013FA8000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"
"), L"\n"); - s = std::regex_replace(s, std::wregex(L"^(\\s+)"), L""); - return write_string_overwrite(data,len,s); -} -bool F0100556015CCC000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - std::regex rubiRegex("\\[[^\\]]+."); - s = std::regex_replace(s, rubiRegex, ""); - s = std::regex_replace(s, std::regex("\\\\k|\\\\x|%C|%B|%p-1;"), ""); - std::regex colorRegex("#[0-9a-fA-F]+;([^%#]+)(%r)?"); - s = std::regex_replace(s, colorRegex, "$1"); - static std::setdump; - if(dump.find(s)!=dump.end())return false; - dump.insert(s); - return write_string_overwrite(data,len,s); -} -template -bool F0100CC80140F8000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"^(?:スキップ|メニュー|バックログ|ズームイン|ズームアウト|ガイド OFF|早送り|オート|人物情報|ユニット表示切替|カメラリセット|ガイド表示切替|ページ切替|閉じる|コマンド選択|詳細|シミュレーション|移動)$([\\r?\\n|\\r])?"), L""); - - s = std::regex_replace(s, std::wregex(L"[A-Za-z0-9]"), L""); - s = std::regex_replace(s, std::wregex(L"[().%,_!#©&:?/]"), L""); - while (std::regex_search(s, std::wregex(L"^\\s*$"))) { - s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); - } - static std::wstring last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} - -bool F0100D9A01BD86000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); - s = std::regex_replace(s, std::wregex(L"\\\\n"), L""); - return write_string_overwrite(data,len,s); -} -bool F010042300C4F6000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); - s = std::regex_replace(s, std::wregex(L"(.+?/)"), L""); - s = std::regex_replace(s, std::wregex(L"(\" .*)"), L""); - s = std::regex_replace(s, std::wregex(L"^(.+?\")"), L""); - return write_string_overwrite(data,len,s); -} -bool F010044800D2EC000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\n+"), L" "); - s = std::regex_replace(s, std::wregex(L"\\"), L"???"); - s = std::regex_replace(s, std::wregex(L"<.+?>"), L""); - return write_string_overwrite(data,len,s); -} -template -bool F010021300F69E000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\$[a-z]"), L""); - s = std::regex_replace(s, std::wregex(L"@"), L""); - static std::wstring last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} -bool F010050000705E000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("\\s"), ""); - s = std::regex_replace(s, std::regex("
"), "\n"); - s = std::regex_replace(s, std::regex("<([^:>]+):[^>]+>"), "$1"); - s = std::regex_replace(s, std::regex("<[^>]+>"), ""); - return write_string_overwrite(data,len,s); -} -bool F01001B900C0E2000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - std::regex whitespaceRegex("\\s"); - s = std::regex_replace(s, whitespaceRegex, ""); - std::regex hashRegex("#[A-Za-z]+(\\[(\\d*\\.)?\\d+\\])+"); - s = std::regex_replace(s, hashRegex, ""); - std::regex hashLetterRegex("#[a-z]"); - s = std::regex_replace(s, hashLetterRegex, ""); - std::regex lowercaseRegex("[a-z]"); - s = std::regex_replace(s, lowercaseRegex, ""); - return write_string_overwrite(data,len,s); -} - -bool F0100217014266000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - std::wregex htmlTagRegex(L"<[^>]*>"); - s = std::regex_replace(s, htmlTagRegex, L""); - std::wregex furiganaRegex(L"{([^{}]+):[^{}]+}"); - s = std::regex_replace(s, furiganaRegex, L"$1"); - while (std::regex_search(s, std::wregex(L"^\\s+"))) { - s = std::regex_replace(s, std::wregex(L"^\\s+"), L""); - } - return write_string_overwrite(data,len,s); -} -bool F010007500F27C000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - std::wregex htmlTagRegex(L"<[^>]*>"); - s = std::regex_replace(s, htmlTagRegex, L""); - auto _=L"^(?:決定|進む|ページ移動|ノート全体図|閉じる|もどる|セーブ中)$(\\r?\\n|\\r)?"; - while (std::regex_search(s, std::wregex(_))) { - s = std::regex_replace(s, std::wregex(_), L""); - } - while (std::regex_search(s, std::wregex(L"^\\s*$"))) { - s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); - } - static std::wstring last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} -bool F0100874017BE2000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\n+|(\\\\n)+"), L" "); - s = std::regex_replace(s, std::wregex(L"#n"), L""); - return write_string_overwrite(data,len,s); -} -bool F010094601D910000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\<.*?\\>"), L""); - s = std::regex_replace(s, std::wregex(L"\\[.*?\\]"), L""); - s = std::regex_replace(s, std::wregex(L"\\s"), L""); - return write_string_overwrite(data,len,s); -} -bool F010079201BD88000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); - s = std::regex_replace(s, std::wregex(L"\\\\n"), L""); - return write_string_overwrite(data,len,s); -} -bool F010086C00AF7C000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("\\[([^\\]]+)\\/[^\\]]+\\]"), "$1"); - s = std::regex_replace(s, std::regex("\\s+"), " "); - s = std::regex_replace(s, std::regex("\\\\n"), " "); - s = std::regex_replace(s, std::regex("<[^>]+>|\\[[^\\]]+\\]"), ""); - return write_string_overwrite(data,len,s); -} -bool F010079C017B98000(void* data, size_t* len, HookParam* hp){ - auto s=utf32_to_utf16((uint32_t*)data,*len/4); - s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); - s = std::regex_replace(s, std::wregex(L"#KW"), L""); - s = std::regex_replace(s, std::wregex(L"#C\\(TR,0xff0000ff\\)"), L""); - s = std::regex_replace(s, std::wregex(L"【SW】"), L""); - s = std::regex_replace(s, std::wregex(L"【SP】"), L""); - s = std::regex_replace(s, std::wregex(L"#P\\(.*\\)"), L""); - auto u32=utf16_to_utf32(s.c_str(),s.size()); - return write_string_overwrite(data,len,u32); -} -bool F010061A01C1CE000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"[\\s]"), L""); - s = std::regex_replace(s, std::wregex(L"sound"), L" "); - return write_string_overwrite(data,len,s); -} -bool F0100F7401AA74000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("[\\s]"), ""); - s = std::regex_replace(s, std::regex("@[a-z]"), ""); - s = std::regex_replace(s, std::regex("@[0-9]"), ""); - return write_string_overwrite(data,len,s); -} - -bool F0100FC2019346000(void* data, size_t* len, HookParam* hp){ - StringReplacer((char*)data,len,"#n",2," ",1); - return true; -} - -bool F0100FDB00AA80000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("\\[([^\\]]+)\\/[^\\]]+\\]"), "$1"); - s = std::regex_replace(s, std::regex("<[^>]*>"), ""); - return write_string_overwrite(data,len,s); -} -bool F0100FF500E34A000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("\\[.*?\\]"), ""); - s = std::regex_replace(s, std::regex("\\n+"), " "); - return write_string_overwrite(data,len,s); -} -bool F01005E9016BDE000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - std::regex patt("/\\/\\/ remove rubi\\n\\ss = s.replace\\(patt, ''\\);/"); - s = std::regex_replace(s, patt, ""); - s = std::regex_replace(s, std::regex("\\\\k|\\\\x|%C|%B|%p-1;"), ""); - s = std::regex_replace(s, std::regex("#[0-9a-fA-F]+;([^%#]+)(%r)?"), "$1"); - s = std::regex_replace(s, std::regex("\\\\n"), " "); - return write_string_overwrite(data,len,s); -} - -bool F010065301A2E0000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\d+"), L""); - s = std::regex_replace(s, std::wregex(L"<[^>]*>"), L""); - return write_string_overwrite(data,len,s); -} -bool F01002AE00F442000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - std::wregex pattern1(L"\\[([^\\]\\/]+)\\/[^\\]]+\\]"); - s = std::regex_replace(s, pattern1, L"$1"); - std::wregex pattern2(L"(\\S*)@"); - s = std::regex_replace(s, pattern2, L"$1"); - std::wregex pattern3(L"\\$"); - s = std::regex_replace(s, pattern3, L""); - return write_string_overwrite(data,len,s); -} -bool F01000A400AF2A000(void* data, size_t* len, HookParam* hp){ - auto s=std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"@[a-zA-Z]|%[a-zA-Z]+"), L""); - static std::wstring last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} - -bool F01006B5014E2E000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("@r(.*?)@(.*?)@"), "$1"); - s = std::regex_replace(s, std::regex("@n"), ""); - s = std::regex_replace(s, std::regex("@v"), ""); - s = std::regex_replace(s, std::regex("TKY[0-9]{6}_[A-Z][0-9]{2}"), ""); - return write_string_overwrite(data,len,s); -} -bool F0100CF400F7CE000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("\\n+"), " "); - return write_string_overwrite(data,len,s); -} -bool F01000AE01954A000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("[A-Za-z0-9]"), ""); - s = std::regex_replace(s, std::regex("[~^(-).%,!:#@$/*&;+_]"), ""); - return write_string_overwrite(data,len,s); -} -bool F01003BD013E30000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("{|\\/.*?}|\\[.*?]"), ""); - return write_string_overwrite(data,len,s); -} -bool F010074F013262000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("\\[.*?]"), ""); - return write_string_overwrite(data,len,s); -} -template -bool F010057E00AC56000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("<[^>]*>"), ""); - s = std::regex_replace(s, std::regex(u8"ズーム|回転|身長|体重"), ""); - s = std::regex_replace(s, std::regex("[A-Za-z0-9]"), ""); - s = std::regex_replace(s, std::regex("[().%,!#/]"), ""); - while (std::regex_search(s, std::regex("^\\s*$"))) { - s = std::regex_replace(s, std::regex("^\\s*$"), ""); - } - static std::string last; - if(last==s)return false; - last=s; - return write_string_overwrite(data,len,s); -} -bool F010051D010FC2000(void* data, size_t* len, HookParam* hp){ - auto s=std::string((char*)data,*len); - s = std::regex_replace(s, std::regex("\\[([^\\]]+)\\/[^\\]]+\\]"), "$1"); - s = std::regex_replace(s, std::regex("\\s+"), " "); - s = std::regex_replace(s, std::regex("\\\\n"), " "); - s = std::regex_replace(s, std::regex("<[^>]+>|\\[[^\\]]+\\]"), ""); - return write_string_overwrite(data,len,s); -} - -bool F01001EF017BE6000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - while (std::regex_search(s, std::wregex(L"^\\s*$"))) { - s = std::regex_replace(s, std::wregex(L"^\\s*$"), L""); - } - return write_string_overwrite(data,len,s); -} -bool F01000EA00D2EE000(void* data, size_t* len, HookParam* hp){ - auto s = std::wstring((wchar_t*)data,*len/2); - s = std::regex_replace(s, std::wregex(L"\\n+"), L" "); - s = std::regex_replace(s, std::wregex(L"\\"), L"???"); - s = std::regex_replace(s, std::wregex(L"\\"), L"chiaki_washa"); - s = std::regex_replace(s, std::wregex(L"<.+?>"), L""); - return write_string_overwrite(data,len,s); -} -auto _=[](){ - emfunctionhooks={ - //Memories Off - {0x8003eeac,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100978013276000","1.0.0"}}, - {0x8003eebc,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100978013276000","1.0.1"}}, - //Memories Off ~Sorekara~ - {0x8003fb7c,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100B4A01326E000","1.0.0"}}, - {0x8003fb8c,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100B4A01326E000","1.0.1"}}, - //Famicom Tantei Club: Kieta Koukeisha - {0x80052a10,{CODEC_UTF16,0,0,mages_readstring<3>,0,"0100B4500F7AE000","1.0.0"}}, - //Famicom Tantei Club Part: Ushiro ni Tatsu Shoujo - {0x8004cb30,{CODEC_UTF16,0,0,mages_readstring<3>,0,"010078400F7B0000","1.0.0"}}, - //Memories Off 2nd - {0x8003ee0c,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100D31013274000","1.0.0"}}, - {0x8003ee1c,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100D31013274000","1.0.1"}}, - //Omoide ni Kawaru Kimi ~Memories Off~ - {0x8003ef6c,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100FFA013272000","1.0.0"}}, - {0x8003ef7c,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100FFA013272000","1.0.1"}}, - //Memories Off 6 ~T-Wave~ - {0x80043d7c,{CODEC_UTF16,0,0,mages_readstring<0>,0,"010047A013268000","1.0.0"}}, - {0x80043d5c,{CODEC_UTF16,0,0,mages_readstring<0>,0,"010047A013268000","1.0.1"}}, - //Memories Off: Yubikiri no Kioku - {0x800440ec,{CODEC_UTF16,0,0,mages_readstring<0>,0,"010079C012896000","1.0.0"}}, - //Memories Off #5 Togireta Film - {0x8003f6ac,{CODEC_UTF16,0,0,mages_readstring<0>,0,"010073901326C000","1.0.0"}}, - {0x8003f5fc,{CODEC_UTF16,0,0,mages_readstring<0>,0,"010073901326C000","1.0.1"}}, - //SINce Memories: Hoshi no Sora no Shita de - {0x80048cc8,{CODEC_UTF16,0,0,mages_readstring<4>,0,"0100E94014792000",0}},//line + name => join - {0x8004f44c,{CODEC_UTF16,0,0,mages_readstring<4>,0,"0100E94014792000",0}},//fast trophy - {0x8004f474,{CODEC_UTF16,0,0,mages_readstring<4>,0,"0100E94014792000",0}},//prompt - {0x80039dc0,{CODEC_UTF16,0,0,mages_readstring<4>,0,"0100E94014792000",0}},//choice - - //Yahari Game demo Ore no Seishun Love Come wa Machigatteiru. - {0x8005DFB8,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100E0D0154BC000","1.0.0"}}, - //CHAOS;HEAD NOAH - {0x80046700,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100957016B90000","1.0.0"}}, - {0x8003A2c0,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100957016B90000","1.0.0"}},// choice - {0x8003EAB0,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100957016B90000","1.0.0"}},// TIPS list (menu) - {0x8004C648,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100957016B90000","1.0.0"}},// system message - {0x80050374,{CODEC_UTF16,0,0,mages_readstring<0>,0,"0100957016B90000","1.0.0"}},// TIPS (red) - // Shiro to Kuro no Alice - {0x80013f20,{CODEC_UTF8,0,0,0,NewLineCharFilterW,"0100A460141B8000","1.0.0"}}, - {0x80013f94,{CODEC_UTF8,0,0,0,NewLineCharFilterW,"0100A460141B8000","1.0.0"}}, - {0x8001419c,{CODEC_UTF8,0,0,0,NewLineCharFilterW,"0100A460141B8000","1.0.0"}}, - // Shiro to Kuro no Alice -Twilight line- - {0x80014260,{CODEC_UTF8,0,0,0,NewLineCharFilterW,"0100A460141B8000","1.0.0"}}, - {0x800142d4,{CODEC_UTF8,0,0,0,NewLineCharFilterW,"0100A460141B8000","1.0.0"}}, - {0x800144dc,{CODEC_UTF8,0,0,0,NewLineCharFilterW,"0100A460141B8000","1.0.0"}}, - //CLANNAD - {0x80072d00,{CODEC_UTF16|FULL_STRING,1,0,0, F0100A3A00CC7E000,"0100A3A00CC7E000","1.0.0"}}, - {0x80072d30,{CODEC_UTF16|FULL_STRING,1,0,0,F0100A3A00CC7E000,"0100A3A00CC7E000","1.0.7"}}, - //VARIABLE BARRICADE NS - {0x800e3424,{CODEC_UTF8,0,0,0,F010045C0109F2000,"010045C0109F2000","1.0.1"}},//"System Messages + Choices"), //Also includes the names of characters, - {0x800fb080,{CODEC_UTF8,3,0,0,F010045C0109F2000,"010045C0109F2000","1.0.1"}},//Main Text - //AMNESIA for Nintendo Switch - {0x805bba5c,{CODEC_UTF16,0,0,ReadTextAndLenDW<2>,F0100A1E00BFEA000,"0100A1E00BFEA000","1.0.1"}},//dialogue - {0x805e9930,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100A1E00BFEA000,"0100A1E00BFEA000","1.0.1"}},//choice - {0x805e7fd8,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100A1E00BFEA000,"0100A1E00BFEA000","1.0.1"}},//name - - //Chou no Doku Hana no Kusari Taishou Tsuya Koi Ibun - {0x80095010,{CODEC_UTF16,1,0,0,F0100A1200CA3C000,"0100A1200CA3C000","2.0.1"}},//Main Text + Names - //Live a Live - {0x80a05170,{CODEC_UTF16,0,0,0,F0100982015606000,"0100C29017106000","1.0.0"}}, - //Sakura no Kumo * Scarlet no Koi - {0x8049d968,{CODEC_UTF8,0,1,0,F01006590155AC000,"01006590155AC000","1.0.0"}},//name - {0x8049d980,{CODEC_UTF8,0,0,0,F01006590155AC000,"01006590155AC000","1.0.0"}},//dialogue - //Majestic Majolical - {0x80557408,{CODEC_UTF8,0,0,0,F01000200194AE000,"01000200194AE000","1.0.0"}},//name - {0x8059ee94,{CODEC_UTF8,3,0,0,F01000200194AE000,"01000200194AE000","1.0.0"}},//player name - {0x80557420,{CODEC_UTF8,0,0,0,F01000200194AE000,"01000200194AE000","1.0.0"}},//dialogue - - //Matsurika no Kei - {0x8017ad54,{CODEC_UTF32,1,0,0,F0100EA001A626000,"0100EA001A626000","1.0.0"}},// text - {0x80174d4c,{CODEC_UTF32,1,0,0,F0100EA001A626000,"0100EA001A626000","1.0.0"}},// name - //Cupid Parasite - {0x80057910,{CODEC_UTF32,2,0,0,F0100F7E00DFC8000,"0100F7E00DFC8000","1.0.1"}},// name + text - {0x80169df0,{CODEC_UTF32,0,0,0,F0100F7E00DFC8000,"0100F7E00DFC8000","1.0.1"}},// choice - //Radiant Tale - {0x80075190,{CODEC_UTF8,1,0,0,F0100925014864000,"0100925014864000","1.0.0"}},// prompt - {0x8002fb18,{CODEC_UTF8,0,0,0,F0100925014864000,"0100925014864000","1.0.0"}},// name - {0x8002fd7c,{CODEC_UTF8,0,0,0,F0100925014864000,"0100925014864000","1.0.0"}},// text - //MUSICUS - {0x80462DD4,{CODEC_UTF8,0,1,0,F01006590155AC000,"01000130150FA000","1.0.0"}},// name - {0x80462DEC,{CODEC_UTF8,0,0,0,F01006590155AC000,"01000130150FA000","1.0.0"}},// dialogue 1 - {0x80480d4c,{CODEC_UTF8,0,0,0,F01006590155AC000,"01000130150FA000","1.0.0"}},// dialogue 2 - {0x804798e0,{CODEC_UTF8,0,0,0,F01006590155AC000,"01000130150FA000","1.0.0"}},// choice - - - //Story of Seasons a Wonderful Life - {0x80ac4d88,{CODEC_UTF32,0,0,F0100936018EB4000,"0100936018EB4000","1.0.3"}},// Main text - {0x808f7e84,{CODEC_UTF32,0,0,F0100936018EB4000,"0100936018EB4000","1.0.3"}},// Item name - {0x80bdf804,{CODEC_UTF32,0,0,F0100936018EB4000,"0100936018EB4000","1.0.3"}},// Item description - //Hamefura Pirates - {0x81e75940,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100982015606000,"0100982015606000","1.0.0"}},// Hamekai.TalkPresenter$$AddMessageBacklog - {0x81c9ae60,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100982015606000,"0100982015606000","1.0.0"}},// Hamekai.ChoicesText$$SetText - {0x81eb7dc0,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100982015606000,"0100982015606000","1.0.0"}},// Hamekai.ShortStoryTextView$$AddText - //Death end re;Quest 2 - {0x80225C3C,{CODEC_UTF8,8,0,0,F010001D015260000,"010001D015260000","1.0.0"}}, - //Death end re;Quest - {0x80241088,{CODEC_UTF8,8,0,0,F0100AEC013DDA000,"0100AEC013DDA000","1.0.0"}},//english ver - //Meta Meet Cute!!!+ - {0x81DD6010,{CODEC_UTF16,1,-32,0,0,"01009A401C1B0000","1.02"}},//english ver, only long string, short string can't find. - //Of the Red, the Light, and the Ayakashi Tsuzuri - {0x8176D78C,{CODEC_UTF16,3,0,0,0,"0100F7801B5DC000","1.0.0"}}, - //Tokimeki Memorial Girl's Side: 4th Heart - {0x817e7da8,{CODEC_UTF16,0,0,T0100B0100E26C000<2,0>,0,"0100B0100E26C000","1.0.0"}},// name (x1) + dialogue (x2) - {0x81429f54,{CODEC_UTF16,0,0,T0100B0100E26C000<0,1>,0,"0100B0100E26C000","1.0.0"}},// choice (x0) - {0x8180633c,{CODEC_UTF16,0,0,T0100B0100E26C000<1,2>,0,"0100B0100E26C000","1.0.0"}},// help (x1) - //13 Sentinels: Aegis Rim - {0x80057d18,{CODEC_UTF8,0,0,0,F010045C014650000,"010045C014650000","1.0.0"}},// cutscene text - {0x8026fec0,{CODEC_UTF8,1,0,0,F010045C014650000,"010045C014650000","1.0.0"}},// prompt - {0x8014eab4,{CODEC_UTF8,0,0,0,F010045C014650000,"010045C014650000","1.0.0"}},// name (combat) - {0x801528ec,{CODEC_UTF8,3,0,0,F010045C014650000,"010045C014650000","1.0.0"}},// dialogue (combat) - {0x80055acc,{CODEC_UTF8,0,0,0,F010045C014650000,"010045C014650000","1.0.0"}},// dialogue 2 (speech bubble) - {0x802679c8,{CODEC_UTF8,1,0,0,F010045C014650000,"010045C014650000","1.0.0"}},// notification - {0x8025e210,{CODEC_UTF8,2,0,0,F010045C014650000,"010045C014650000","1.0.0"}},// scene context example: 数日前 咲良高校 1年B組 教室 1985年5月" - {0x8005c518,{CODEC_UTF8,0,0,0,F010045C014650000,"010045C014650000","1.0.0"}},// game help - //Sea of Stars - {0x83e93ca0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01008C0016544000,"01008C0016544000","1.0.45861"}},// Main text - {0x820c3fa0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01008C0016544000,"01008C0016544000","1.0.47140"}},// Main text - //Final Fantasy I - {0x81e88040,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01000EA014150000","1.0.1"}},// Main text - {0x81cae54c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01000EA014150000","1.0.1"}},// Intro text - {0x81a3e494,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01000EA014150000","1.0.1"}},// battle text - {0x81952c28,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01000EA014150000","1.0.1"}},// Location - //Final Fantasy II - {0x8208f4cc,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01006B7014156000","1.0.1"}},// Main text - {0x817e464c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01006B7014156000","1.0.1"}},// Intro text - {0x81fb6414,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01006B7014156000","1.0.1"}},// battle text - //Final Fantasy III - {0x82019e84,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01002E2014158000","1.0.1"}},// Main text1 - {0x817ffcfc,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01002E2014158000","1.0.1"}},// Main text2 - {0x81b8b7e4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01002E2014158000","1.0.1"}},// battle text - {0x8192c4a8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01002E2014158000","1.0.1"}},// Location - //Final Fantasy IV - {0x81e44bf4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01004B301415A000","1.0.2"}},// Main text - {0x819f92c4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01004B301415A000","1.0.2"}},// Rolling text - {0x81e2e798,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01004B301415A000","1.0.2"}},// Battle text - {0x81b1e6a8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01004B301415A000","1.0.2"}},// Location - //Final Fantasy V - {0x81d63e24,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"0100AA201415C000","1.0.2"}},// Main text - {0x81adfb3c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"0100AA201415C000","1.0.2"}},// Location - {0x81a8fda8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"0100AA201415C000","1.0.2"}},// Battle text - //Final Fantasy VI - {0x81e6b350,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"0100AA001415E000","1.0.2"}},// Main text - {0x81ab40ec,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"0100AA001415E000","1.0.2"}},// Location - {0x819b8c88,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"0100AA001415E000","1.0.2"}},// Battle text - //Final Fantasy IX - {0x80034b90,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F01006F000B056000,"01006F000B056000","1.0.1"}},// Main Text - {0x802ade64,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01006F000B056000,"01006F000B056000","1.0.1"}},// Battle Text - {0x801b1b84,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01006F000B056000,"01006F000B056000","1.0.1"}},// Descriptions - {0x805aa0b0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01006F000B056000,"01006F000B056000","1.0.1"}},// Key Item Name - {0x805a75d8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01006F000B056000,"01006F000B056000","1.0.1"}},// Key Item Content - {0x8002f79c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01006F000B056000,"01006F000B056000","1.0.1"}},// Menu - {0x80ca88b0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01006F000B056000,"01006F000B056000","1.0.1"}},// Tutorial1 - {0x80ca892c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01006F000B056000,"01006F000B056000","1.0.1"}},// Tutorial2 - {0x80008d88,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F01006F000B056000,"01006F000B056000","1.0.1"}},// Location - //Norn9 Var Commons - {0x8003E874,{CODEC_UTF8,0,0,0,F0100068019996000,"0100068019996000","1.0.0"}},//English - //薄桜鬼 真改 万葉ノ抄 - {0x8004E8F0,{CODEC_UTF8,1,0,0,F010001D015260000,"0100EA601A0A0000","1.0.0"}}, - //Hakuouki Shinkai: Tsukikage no Shou / 薄桜鬼 真改 月影ノ抄 - {0x8019ecd0,{CODEC_UTF8,1,0,0,F0100E1E00E2AE000,"0100E1E00E2AE000","1.0.0"}},//Text - //Chrono Cross: The Radical Dreamers Edition - {0x802b1254,{CODEC_UTF32,1,0,0,0,"0100AC20128AC000","1.0.2"}},//Text - //AIR - {0x800a6b10,{CODEC_UTF16,1,0,0,F0100ADC014DA0000,"0100ADC014DA0000","1.0.1"}},//Text + Name - //Shinigami to Shoujo - {0x21cb08-0x204000+0x80004000,{0,1,0,0,F0100AFA01750C000,"0100AFA01750C000","1.0.2"}},//Text,sjis - //Octopath Traveler II - {0x8088a4d4,{CODEC_UTF16,0,0,0,0,"0100A3501946E000","1.0.0"}},//main text - //NieR:Automata The End of YoRHa Edition - {0x808e7068,{CODEC_UTF16,3,0,0,0,"0100B8E016F76000","1.0.2"}},//Text - //Reine des Fleurs - {0x80026434,{CODEC_UTF8,0,0,0,0,"0100B5800C0E4000","1.0.0"}},//Dialogue text - //Code : Realize - Saikou no Hanataba - {0x80024eac,{CODEC_UTF8,0,0,0,F0100B6900A668000,"0100B6900A668000","1.0.0"}}, - //Diabolik Lovers Grand Edition - {0x80041080,{CODEC_UTF8,1,0,0,F0100BD700E648000,"0100BD700E648000","1.0.0"}},//name - {0x80041080,{CODEC_UTF8,0,0,0,F0100BD700E648000,"0100BD700E648000","1.0.0"}},//dialogue - {0x80041080,{CODEC_UTF8,2,0,0,F0100BD700E648000,"0100BD700E648000","1.0.0"}},//choice1 - //Shinobi, Koi Utsutsu - {0x8002aca0,{CODEC_UTF8,0,0,0,F0100B6900A668000,"0100C1E0102B8000","1.0.0"}},//name - {0x8002aea4,{CODEC_UTF8,0,0,0,F0100B6900A668000,"0100C1E0102B8000","1.0.0"}},//dialogue1 - {0x8001ca90,{CODEC_UTF8,2,0,0,F0100B6900A668000,"0100C1E0102B8000","1.0.0"}},//dialogue2 - {0x80049dbc,{CODEC_UTF8,1,0,0,F0100B6900A668000,"0100C1E0102B8000","1.0.0"}},//choice - //Yoru, Tomosu - {0xe2748eb0,{CODEC_UTF32,1,0,0,0,"0100C2901153C000","1.0.0"}},// text1 - //Closed Nightmare - {0x800c0918,{CODEC_UTF8,0,0,0,F0100D9500A0F6000,"0100D9500A0F6000","1.0.0"}},// line + name - {0x80070b98,{CODEC_UTF8,0,0,0,F0100D9500A0F6000,"0100D9500A0F6000","1.0.0"}},// fast trophy - {0x800878fc,{CODEC_UTF8,0,0,0,F0100D9500A0F6000,"0100D9500A0F6000","1.0.0"}},// prompt - {0x80087aa0,{CODEC_UTF8,0,0,0,F0100D9500A0F6000,"0100D9500A0F6000","1.0.0"}},// choice - //Yuru Camp△ - Have a Nice Day! - {0x816d03f8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100982015606000,"0100D12014FC2000","1.0.0"}},// dialog / backlog - //Akuyaku Reijou wa Ringoku no Outaishi ni Dekiai Sareru - {0x817b35c4,{CODEC_UTF8,1,0,0,F0100DA201E0DA000,"0100DA201E0DA000","1.0.0"}},// Dialogue - //Yunohana Spring! ~Mellow Times~ - {0x80028178,{CODEC_UTF8,0,0,0,F0100DE200C0DA000,"0100DE200C0DA000","1.0.0"}},// name - {0x8001b9d8,{CODEC_UTF8,2,0,0,F0100DE200C0DA000,"0100DE200C0DA000","1.0.0"}},// dialogue1 - {0x8001b9b0,{CODEC_UTF8,2,0,0,F0100DE200C0DA000,"0100DE200C0DA000","1.0.0"}},// dialogue2 - {0x8004b940,{CODEC_UTF8,2,0,0,F0100DE200C0DA000,"0100DE200C0DA000","1.0.0"}},// dialogue3 - {0x8004a8d0,{CODEC_UTF8,1,0,0,F0100DE200C0DA000,"0100DE200C0DA000","1.0.0"}},// choice - //サマータイムレンダ Another Horizon - {0x818ebaf0,{CODEC_UTF16,0,0,T01005940182EC000,F01005940182EC000,"01005940182EC000","1.0.0"}},//dialogue - //Aquarium - {0x8051a990,{CODEC_UTF8,0,1,0,F01006590155AC000,"0100D11018A7E000","1.0.0"}},//name - {0x8051a9a8,{CODEC_UTF8,0,0,0,F01006590155AC000,"0100D11018A7E000","1.0.0"}},//dialogue - {0x80500178,{CODEC_UTF8,0,0,0,F01006590155AC000,"0100D11018A7E000","1.0.0"}},//choice - //AKA - {0x8166eb80,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0601852A000<0>,"0100B0601852A000","1.0.0"}},//Main text - {0x817d44a4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0601852A000<1>,"0100B0601852A000","1.0.0"}},//Letter - {0x815cb0f4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0601852A000<2>,"0100B0601852A000","1.0.0"}},//Mission title - {0x815cde30,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0601852A000<3>,"0100B0601852A000","1.0.0"}},//Mission description - {0x8162a910,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0601852A000<4>,"0100B0601852A000","1.0.0"}},//Craft description - {0x817fdca8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0601852A000<5>,"0100B0601852A000","1.0.0"}},//Inventory item name - //Etrian Odyssey I HD - {0x82d57550,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<8>,"01008A3016162000","1.0.2"}},//Text - {0x824ff408,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<9>,"01008A3016162000","1.0.2"}},//Config Description - {0x8296b4e4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<10>,"01008A3016162000","1.0.2"}},//Class Description - {0x81b2204c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<11>,"01008A3016162000","1.0.2"}},//Item Description - //Etrian Odyssey II HD - {0x82f24c70,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<0>,"0100B0C016164000","1.0.2"}},//Text - {0x82cc0988,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<1>,"0100B0C016164000","1.0.2"}},//Config Description - {0x8249acd4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<2>,"0100B0C016164000","1.0.2"}},//Class Description - {0x81b27644,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<3>,"0100B0C016164000","1.0.2"}},//Item Description - //Etrian Odyssey III HD - {0x83787f04,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<4>,"0100D32015A52000","1.0.2"}},//Text - {0x8206915c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<5>,"0100D32015A52000","1.0.2"}},//Config Description - {0x82e6d1d4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<6>,"0100D32015A52000","1.0.2"}},//Class Description - {0x82bf5d48,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100B0C016164000<7>,"0100D32015A52000","1.0.2"}},//Item Description - //Fire Emblem Engage - {0x8248c550,{CODEC_UTF16,0,0,ReadTextAndLenDW<2>,0,"0100A6301214E000","1.3.0"}},// App.Talk3D.TalkLog$$AddLog - {0x820C6530,{CODEC_UTF16,0,0,ReadTextAndLenDW<2>,0,"0100A6301214E000","2.0.0"}},// App.Talk3D.TalkLog$$AddLog - //AMNESIA LATER×CROWD for Nintendo Switch - {0x800ebc34,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100982015606000,"0100B5700CDFC000","1.0.0"}},// waterfall - {0x8014dc64,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100982015606000,"0100B5700CDFC000","1.0.0"}},// name - {0x80149b10,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100982015606000,"0100B5700CDFC000","1.0.0"}},// dialogue - {0x803add50,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100982015606000,"0100B5700CDFC000","1.0.0"}},// choice - //Hanayaka Nari, Waga Ichizoku Gentou Nostalgie - {0x27ca10-0x204000+0x80004000,{CODEC_UTF8,0,0,T0100B5500CA0C000,F0100B5500CA0C000,"0100B5500CA0C000","1.0.0"}},// x3 (double trigged), name+text, onscreen - //Natsumon! 20th Century Summer Vacation - {0x80db5d34,{CODEC_UTF16,0,0,0,F0100A8401A0A8000,"0100A8401A0A8000","1.1.0"}},// tutorial - {0x846fa578,{CODEC_UTF16,0,0,0,F0100A8401A0A8000,"0100A8401A0A8000","1.1.0"}},// choice - {0x8441e800,{CODEC_UTF16,0,0,0,F0100A8401A0A8000,"0100A8401A0A8000","1.1.0"}},// examine + dialog - //Super Mario RPG - {0x81d78c58,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Main Text - {0x81dc9cf8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Name - {0x81c16b80,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Cutscene - {0x821281f0,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Special/Item/Menu/Objective Description - {0x81cd8148,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Special Name - {0x81fc2820,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Item Name Battle - {0x81d08d28,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Item Name Off-battle - {0x82151aac,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Shop Item Name - {0x81fcc870,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Objective Title - {0x821bd328,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Monster List - Name - {0x820919b8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Monster List - Description - {0x81f56518,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Info - {0x82134ce0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Help Category - {0x82134f30,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Help Name - {0x821372e4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Help Description 1 - {0x82137344,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Help Description 2 - {0x81d0ee80,{CODEC_UTF16,0,0,ReadTextAndLenDW<2>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Location - {0x82128f64,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Album Title - {0x81f572a0,{CODEC_UTF16,0,0,ReadTextAndLenDW<3>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Load/Save Text - {0x81d040a8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Levelup First Part - {0x81d043fc,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Levelup Second Part - {0x81d04550,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Levelup New Ability Description - {0x81fbfa18,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Yoshi Mini-Game Header - {0x81fbfa74,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Yoshi Mini-Game Text - {0x81cf41b4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BC0018138000,"0100BC0018138000","1.0.0"}},// Enemy Special Attacks - //Trials of Mana - {0x800e8abc,{CODEC_UTF16,1,0,0,F0100D7800E9E0000,"0100D7800E9E0000","1.1.1"}},// Text - //Utsusemi no Meguri - {0x821b452c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"0100DA101D9AA000","1.0.0"}},// text1 - {0x821b456c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"0100DA101D9AA000","1.0.0"}},// text2 - {0x821b45ac,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"0100DA101D9AA000","1.0.0"}},// text3 - //Buddy Mission BOND - {0x80046dd0,{0,0,0,T0100DB300B996000,0,"0100DB300B996000",0}},//1.0.0, 1.0.1,sjis - {0x80046de0,{0,0,0,T0100DB300B996000,0,"0100DB300B996000",0}}, - //Bravely Default II - {0x80b97700,{CODEC_UTF16,0,0,0,0,"010056F00C7B4000","1.0.0"}},//Main Text - {0x80bb8d3c,{CODEC_UTF16,0,0,0,0,"010056F00C7B4000","1.0.0"}},//Main Ptc Text - {0x810add68,{CODEC_UTF16,0,0,0,0,"010056F00C7B4000","1.0.0"}},//Secondary Text - //Tantei Bokumetsu / 探偵撲滅 - {0x8011c340,{CODEC_UTF8,1,0,0,F0100CBA014014000,"0100CBA014014000","1.0.0"}},//Text - {0x80064f20,{CODEC_UTF8,1,0,0,F0100CBA014014000,"0100CBA014014000","1.0.0"}},//Choices - //Ys X: Nordics - {0x80817758,{CODEC_UTF8,1,0,0,F0100CC401A16C000<0>,"0100CC401A16C000","1.0.4"}},//Main Text - {0x80981e3c,{CODEC_UTF8,0,0,0,F0100CC401A16C000<1>,"0100CC401A16C000","1.0.4"}},//Secondary Text - //9 R.I.P - {0x80025360,{CODEC_UTF8,2,0,0,F0100BDD01AAE4000,"0100BDD01AAE4000","1.0.0"}},//name - {0x80023c60,{CODEC_UTF8,0,0,0,F0100BDD01AAE4000,"0100BDD01AAE4000","1.0.0"}},//text - {0x8005388c,{CODEC_UTF8,1,0,0,F0100BDD01AAE4000,"0100BDD01AAE4000","1.0.0"}},//choice - {0x80065010,{CODEC_UTF8,0,0,0,F0100BDD01AAE4000,"0100BDD01AAE4000","1.0.0"}},//character description - {0x8009c780,{CODEC_UTF8,0,0,0,F0100BDD01AAE4000,"0100BDD01AAE4000","1.0.0"}},//prompt - //Kiss Bell - Let's sound the kissing-bell of the promise / キスベル - {0x8049d958,{CODEC_UTF8,1,0,0,F01006590155AC000,"0100BD7015E6C000","1.0.0"}},//text - //Piofiore no Banshou -Ricordo- CN - {0x80015fa0,{CODEC_UTF8,2,0,0,F0100C310110B4000,"0100C310110B4000","1.0.0"}},//handlerMsg - {0x80050d50,{CODEC_UTF8,0,0,0,F0100C310110B4000,"0100C310110B4000","1.0.0"}},//handlerName - {0x8002F430,{CODEC_UTF8,0,0,0,F0100C310110B4000,"0100C310110B4000","1.0.0"}},//handlerPrompt - {0x8002F4F0,{CODEC_UTF8,0,0,0,F0100C310110B4000,"0100C310110B4000","1.0.0"}},//handlerPrompt - {0x8002F540,{CODEC_UTF8,0,0,0,F0100C310110B4000,"0100C310110B4000","1.0.0"}},//handlerPrompt - //Piofiore no Banshou -Ricordo- - {0x800141d0,{CODEC_UTF8,2,0,0,F0100C310110B4000,"01005F700DC56000","1.0.0"}},//handlerMsg - {0x8004ce20,{CODEC_UTF8,0,0,0,F0100C310110B4000,"01005F700DC56000","1.0.0"}},//handlerName - {0x8002be90,{CODEC_UTF8,0,0,0,F0100C310110B4000,"01005F700DC56000","1.0.0"}},//handlerPrompt - {0x8002bf50,{CODEC_UTF8,0,0,0,F0100C310110B4000,"01005F700DC56000","1.0.0"}},//handlerPrompt - {0x8002bfa0,{CODEC_UTF8,0,0,0,F0100C310110B4000,"01005F700DC56000","1.0.0"}},//handlerPrompt - //Piofiore no Banshou -Episodio1926- - {0x80019630,{CODEC_UTF8,2,0,0,F0100C310110B4000,"01009E30120F4000","1.0.0"}},//handlerMsg - {0x8005B7B0,{CODEC_UTF8,0,0,0,F0100C310110B4000,"01009E30120F4000","1.0.0"}},//handlerName - {0x80039230,{CODEC_UTF8,0,0,0,F0100C310110B4000,"01009E30120F4000","1.0.0"}},//handlerPrompt - {0x800392F0,{CODEC_UTF8,0,0,0,F0100C310110B4000,"01009E30120F4000","1.0.0"}},//handlerPrompt - {0x80039340,{CODEC_UTF8,0,0,0,F0100C310110B4000,"01009E30120F4000","1.0.0"}},//handlerPrompt - //Pokémon Let’s Go, Pikachu! - {0x8067d9fc,{CODEC_UTF16,0,0,0,F010003F003A34000,"010003F003A34000","1.0.2"}},//Text - //Ikemen Sengoku Toki o Kakeru Koi / イケメン戦国◆時をかける恋 新たなる出逢い - {0x813e4fb4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01008BE016CE2000","1.0.0"}},//Main Text - {0x813e4c60,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01008BE016CE2000","1.0.0"}},//Name - {0x813b5360,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"01008BE016CE2000","1.0.0"}},//Choices - {0x81bab9ac,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,0,"01008BE016CE2000","1.0.0"}},//Info - //Shin Megami Tensei V - {0x80ce01a4,{CODEC_UTF16,0,0,0,0,"01006BD0095F4000","1.0.2"}},//Text - //The Legend of Zelda: Link's Awakening - {0x80f57910,{CODEC_UTF8,1,0,0,0,"01006BB00C6F0000","1.0.1"}},//Main Text - //Cendrillon palikA - {0x8001ab8c,{CODEC_UTF8,2,0,0,F0100DE200C0DA000,"01006B000A666000","1.0.0"}},//name - {0x80027b30,{CODEC_UTF8,0,0,0,F0100DE200C0DA000,"01006B000A666000","1.0.0"}},//dialogue - //Crayon Shin-chan Shiro of Coal Town - {0x83fab4bc,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F01007B601C608000,"01007B601C608000","1.0.1"}}, - //Fuuraiki 4 - {0x80008c80,{CODEC_UTF32,1,0,0,F010046601125A000,"010046601125A000","1.0.0"}},//Main - {0x80012b1c,{CODEC_UTF32,1,0,0,F010046601125A000,"010046601125A000","1.0.0"}},//Wordpad - {0x80012ccc,{CODEC_UTF32,1,0,0,F010046601125A000,"010046601125A000","1.0.0"}},//Comments - {0x80009f74,{CODEC_UTF32,1,0,0,F010046601125A000,"010046601125A000","1.0.0"}},//Choices - {0x80023d64,{CODEC_UTF32,0,0,0,F010046601125A000,"010046601125A000","1.0.0"}},//Location - //Ken ga Kimi for S / 剣が君 for S - {0x81477128,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100771013FA8000,"0100771013FA8000","1.1"}},//Main Text - {0x81470e38,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100771013FA8000,"0100771013FA8000","1.1"}},//Secondary Text - //ANONYMOUS;CODE - {0x80011608,{CODEC_UTF8,1,0,0,F0100556015CCC000,"0100556015CCC000","1.0.0"}},//dialouge, menu - //Sugar * Style (シュガー*スタイル) - {0x800ccbc8,{0,0,0,0,0,"0100325012B70000","1.0.0"}},// ret x0 name + text (readShiftJisString), filter is to complex, quit. - //Nightshade/百花百狼 - {0x802999c8,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F010042300C4F6000,"010042300C4F6000","1.0.1"}},//dialogue - {0x8015b544,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010042300C4F6000,"010042300C4F6000","1.0.1"}},//name - {0x802a2fd4,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F010042300C4F6000,"010042300C4F6000","1.0.1"}},//choice1 - {0x802b7900,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F010042300C4F6000,"010042300C4F6000","1.0.1"}},//choice2 - //Toraware no Paruma - {0x8015b7a8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010044800D2EC000,"010044800D2EC000","1.0.0"}},//text x0 - {0x8015b46c,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F010044800D2EC000,"010044800D2EC000","1.0.0"}},//name x1 - //Brothers Conflict: Precious Baby - {0x8016aecc,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100982015606000,"010037400DAAE000","1.0.0"}},//name - {0x80126b9c,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100982015606000,"010037400DAAE000","1.0.0"}},//dialogue - {0x80129160,{CODEC_UTF16,0,0,ReadTextAndLenW<2>,F0100982015606000,"010037400DAAE000","1.0.0"}},//choice - //Zettai Kaikyu Gakuen - {0x80067b5c,{CODEC_UTF16,1,0,0,F010021300F69E000<0>,"010021300F69E000","1.0.0"}},//name+ dialogue main(ADV)+choices - {0x80067cd4,{CODEC_UTF16,1,0,0,F010021300F69E000<1>,"010021300F69E000","1.0.0"}},//dialogueNVL - //Dragon Quest Builders 2 - {0x805f8900,{CODEC_UTF8,1,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Main text textbox - {0x8068a698,{CODEC_UTF8,0,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Not press to continue text - {0x806e4118,{CODEC_UTF8,3,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Character creation text - {0x8067459c,{CODEC_UTF8,1,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Objective progress1 - {0x800a4f90,{CODEC_UTF8,0,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Objective progress2 - {0x8060a1c0,{CODEC_UTF8,0,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Infos1 - {0x805f6130,{CODEC_UTF8,1,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Infos2 - {0x80639b6c,{CODEC_UTF8,2,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Item description - {0x807185ac,{CODEC_UTF8,1,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Mission1 - {0x80657e4c,{CODEC_UTF8,1,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Mission2 - {0x80713be0,{CODEC_UTF8,1,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Mission3 - {0x8076ab04,{CODEC_UTF8,1,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Tutorial header - {0x8076ab2c,{CODEC_UTF8,1,0,0,F010050000705E000,"010050000705E000","1.7.3"}},//Tutorial explanation - //BUSTAFELLOWS season2 - {0x819ed3e4,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100874017BE2000,"010037400DAAE000","1.0.0"}},//dialogue - {0x82159cd0,{CODEC_UTF16,0,0,ReadTextAndLenW<1>,F0100874017BE2000,"010037400DAAE000","1.0.0"}},//textmessage - {0x81e17530,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100874017BE2000,"010037400DAAE000","1.0.0"}},//option - {0x81e99d64,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100874017BE2000,"010037400DAAE000","1.0.0"}},//choice - {0x8186f81c,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100874017BE2000,"010037400DAAE000","1.0.0"}},//archives - //5分後に意外な結末 モノクロームの図書館 - {0x81fa4890,{CODEC_UTF16,1,0X14,0,F010094601D910000,"010094601D910000","1.0.1"}},//book text - {0x81fa5250,{CODEC_UTF16,1,0X14,0,F010094601D910000,"010094601D910000","1.0.1"}},//book text - {0x81b1c68c,{CODEC_UTF16,0,0X14,0,F010094601D910000,"010094601D910000","1.0.1"}},//choice1 - {0x81b1c664,{CODEC_UTF16,0,0X14,0,F010094601D910000,"010094601D910000","1.0.1"}},//choice2 - {0x81b1e5b0,{CODEC_UTF16,3,0X14,0,F010094601D910000,"010094601D910000","1.0.1"}},//dialogue - //Tokimeki Memorial Girl’s Side 2nd Season for Nintendo Switch - {0x82058848,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010079201BD88000,"010079201BD88000","1.0.1"}},//dialogue1 - {0x82058aa0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010079201BD88000,"010079201BD88000","1.0.1"}},//dialogue2 - {0x8205a244,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010079201BD88000,"010079201BD88000","1.0.1"}},//dialogue3 - {0x826ee1d8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010079201BD88000,"010079201BD88000","1.0.1"}},//choice - {0x8218e258,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010079201BD88000,"010079201BD88000","1.0.1"}},//news - {0x823b61d4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010079201BD88000,"010079201BD88000","1.0.1"}},//mail - {0x82253454,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010079201BD88000,"010079201BD88000","1.0.1"}},//luckyitem - {0x82269240,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010079201BD88000,"010079201BD88000","1.0.1"}},//profile1 - {0x82269138,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010079201BD88000,"010079201BD88000","1.0.1"}},//profile2 - {0x822691ec,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010079201BD88000,"010079201BD88000","1.0.1"}},//profile3 - {0x82269198,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010079201BD88000,"010079201BD88000","1.0.1"}},//profile4 - //Uta no☆Prince-sama♪ Repeat Love / うたの☆プリンスさまっ♪Repeat LOVE - {0x800374a0,{0,0,0,0,F0100068019996000,"010024200E00A000","1.0.0"}},//Main Text + Name,sjis - {0x8002ea08,{0,0,0,0,F0100068019996000,"010024200E00A000","1.0.0"}},//Choices,sjis - //ワンド オブ フォーチュン R2 ~時空に沈む黙示録~ for Nintendo Switch - {0x821540c4,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100DA201E0DA000,"010088A01A774000","1.0.0"}},//dialogue - {0x8353e674,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100DA201E0DA000,"010088A01A774000","1.0.0"}},//choice - {0x835015e8,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100DA201E0DA000,"010088A01A774000","1.0.0"}},//name - //Yo-kai Watch 4++ - {0x80a88080,{CODEC_UTF8,1,0,0,F010086C00AF7C000,"010086C00AF7C000","2.2.0"}},//All Text - //Cupid Parasite -Sweet & Spicy Darling- - {0x80138150,{CODEC_UTF32,2,0,0,F010079C017B98000,"010079C017B98000","1.0.0"}},//name + text - {0x801a1bf0,{CODEC_UTF32,0,0,0,F010079C017B98000,"010079C017B98000","1.0.0"}},//choice - //DesperaDrops - {0x8199c95c,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F010061A01C1CE000,"010061A01C1CE000","1.0.0"}},//text1 - {0x81d5c900,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F010061A01C1CE000,"010061A01C1CE000","1.0.0"}},//text2 - {0x820d6324,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F010061A01C1CE000,"010061A01C1CE000","1.0.0"}},//choice - //Dragon Ball Z: Kakarot - {0x812a8e28,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Main Text - {0x812a8c90,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Name - {0x80bfbff0,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Ptc Text - {0x80bfbfd4,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Ptc Name - {0x8126a538,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Info - {0x8106fcbc,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//More Info - {0x80fad204,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Hint Part1 - {0x80fad2d0,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Hint Part2 - {0x80facf1c,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Loading Title - {0x80fad018,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Loading Description - {0x81250c50,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Tutorial h1 - {0x81250df0,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Tutorial h2 - {0x81251e80,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Tutorial Description1 - {0x81252214,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Tutorial Description2 - {0x810ae1c4,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Config Description - {0x812a9bb8,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Menu Talk - {0x812a9b78,{CODEC_UTF16,0,0,0,F01008C0016544000,"0100EF00134F4000","1.50"}},//Menu Name - //Harvestella - {0x80af7abc,{CODEC_UTF16,0,0,0,F0100B0601852A000<6>,"0100EDD018032000","1.0.1"}},//Main Text - {0x80c0beb8,{CODEC_UTF16,0,0,0,F0100B0601852A000<7>,"0100EDD018032000","1.0.1"}},//Tutorial + News - {0x80b87f94,{CODEC_UTF16,0,0,0,F0100B0601852A000<8>,"0100EDD018032000","1.0.1"}},//Tutorial Part 2 - {0x80e1c378,{CODEC_UTF16,0,0,0,F0100B0601852A000<9>,"0100EDD018032000","1.0.1"}},//Mission Title - {0x80a7d7f4,{CODEC_UTF16,0,0,0,F0100B0601852A000<10>,"0100EDD018032000","1.0.1"}},//Mission Description - {0x80e39130,{CODEC_UTF16,0,0,0,F0100B0601852A000<11>,"0100EDD018032000","1.0.1"}},//Item Name - {0x80e38f80,{CODEC_UTF16,0,0,0,F0100B0601852A000<12>,"0100EDD018032000","1.0.1"}},//Item Description Part1 - {0x80e38ea8,{CODEC_UTF16,0,0,0,F0100B0601852A000<13>,"0100EDD018032000","1.0.1"}},//Item Description Part2 - //Sen no Hatou, Tsukisome no Kouki - {0x8003fc90,{CODEC_UTF8,1,0,0,0,"0100F8A017BAA000","1.0.0"}},//text1 - {0x8017a740,{CODEC_UTF8,0,0,0,0,"0100F8A017BAA000","1.0.0"}},//text2 - //Olympia Soiree - {0x8002ad04,{CODEC_UTF8,0,0,0,F0100C310110B4000,"0100F9D00C186000","1.0.0"}}, - //Getsuei no Kusari -Sakuran Paranoia- - {0x21801c-0x204000+0x80004000,{0,2,0,0,F0100F7401AA74000,"0100F7401AA74000","1.0.0"}},//text,sjis - {0x228fac-0x204000+0x80004000,{0,1,0,0,F0100F7401AA74000,"0100F7401AA74000","1.0.0"}},//choices - {0x267f24-0x204000+0x80004000,{0,1,0,0,F0100F7401AA74000,"0100F7401AA74000","1.0.0"}},//dictionary - //Xenoblade Chronicles 2 - {0x8010b180,{CODEC_UTF8,1,0,0,F01006F000B056000,"0100F3400332C000","2.0.2"}},//Text - //Kanon - {0x800dc524,{CODEC_UTF16,0,0,0,F0100FB7019ADE000,"0100FB7019ADE000","1.0.0"}},//Text - //Princess Arthur - {0x80066e10,{0,2,0,0,F0100FC2019346000,"0100FC2019346000","1.0.0"}},//Dialogue text ,sjis - {0x8001f7d0,{0,0,0,0,F0100FC2019346000,"0100FC2019346000","1.0.0"}},//Name - //Layton’s Mystery Journey: Katrielle and the Millionaires’ Conspiracy - {0x8025d520,{0,2,0,0,F0100FDB00AA80000,"0100FDB00AA80000","1.1.0"}},//All Text ,sjis - // Xenoblade Chronicles: Definitive Edition - {0x808a5670,{CODEC_UTF8,1,0,0,F0100FF500E34A000,"0100FF500E34A000","1.1.2"}},//Main Text - {0x80305968,{CODEC_UTF8,1,0,0,F0100FF500E34A000,"0100FF500E34A000","1.1.2"}},//Choices - {0x8029edc8,{CODEC_UTF8,0,0,0,F0100FF500E34A000,"0100FF500E34A000","1.1.2"}},//Item Name - {0x8029ede8,{CODEC_UTF8,0,0,0,F0100FF500E34A000,"0100FF500E34A000","1.1.2"}},//Item Description - {0x8026a454,{CODEC_UTF8,0,0,0,F0100FF500E34A000,"0100FF500E34A000","1.1.2"}},//Acquired Item Name - {0x803c725c,{CODEC_UTF8,0,0,0,F0100FF500E34A000,"0100FF500E34A000","1.1.2"}},//Acquired Item Notification - {0x802794cc,{CODEC_UTF8,0,0,0,F0100FF500E34A000,"0100FF500E34A000","1.1.2"}},//Location Discovered - //Unicorn Overlord - {0x805ae1f8,{CODEC_UTF8,1,0,0,F01000AE01954A000,"01000AE01954A000","1.00"}},//Text - //Octopath Traveler - {0x8005ef78,{CODEC_UTF32,0,0,0,0,"01000E200DC58000","1.0.0"}},//Text - //The World Ends with You: Final Remix - {0x80706ab8,{CODEC_UTF16,2,0,0,F01006F000B056000,"01001C1009892000","1.0.0"}},//Text - //JackJanne - {0x81f02cd8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100982015606000,"01001DD010A2E800","1.0.5"}},//Text - {0x821db028,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100982015606000,"01001DD010A2E800","1.0.5"}},//choice - //Collar x Malice - {0x800444c4,{CODEC_UTF8,0,0,0,0,"01002B400E9DA000","1.0.0"}},//Text - //Kanda Alice mo Suiri Suru. - {0x80041db0,{0,0,0,0,F01003BD013E30000,"01003BD013E30000","1.0.0"}},//sjis - //Rune Factory 3 Special - {0x81fb3364,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01001EF017BE6000,"01001EF017BE6000","1.0.4"}},//Main Text - {0x826c0f20,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F01001EF017BE6000,"01001EF017BE6000","1.0.4"}},//Aproach - {0x81fb3320,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01001EF017BE6000,"01001EF017BE6000","1.0.4"}},//Choices - {0x821497e8,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F01001EF017BE6000,"01001EF017BE6000","1.0.4"}},//Calendar - {0x826ba1a0,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F01001EF017BE6000,"01001EF017BE6000","1.0.4"}},//Info - {0x823f6200,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01001EF017BE6000,"01001EF017BE6000","1.0.4"}},//More Info - {0x826c381c,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F01001EF017BE6000,"01001EF017BE6000","1.0.4"}},//Item Select Name - //Toraware no Paruma -Refrain- - {0x80697300,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F01000EA00D2EE000,"01000EA00D2EE000","1.0.0"}},//text x1 - {0x806f43c0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01000EA00D2EE000,"01000EA00D2EE000","1.0.0"}},//name x0 - {0x80d2aca4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01000EA00D2EE000,"01000EA00D2EE000","1.0.0"}},//choice x0 - {0x804b04c8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01000EA00D2EE000,"01000EA00D2EE000","1.0.0"}},//alert x0 - {0x804b725c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01000EA00D2EE000,"01000EA00D2EE000","1.0.0"}},//prompt x0 - //Aiyoku no Eustia - {0x804BEFD0,{CODEC_UTF8,0,0,0,F01006590155AC000,"01001CC017BB2000","1.0.0"}},//x0 - name - {0x804BEFE8,{CODEC_UTF8,0,0,0,F01006590155AC000,"01001CC017BB2000","1.0.0"}},//x0 - dialogue - {0x804d043c,{CODEC_UTF8,0,0,0,F01006590155AC000,"01001CC017BB2000","1.0.0"}},//x0 - choice - //ワンド オブ フォーチュン R~ for Nintendo Switch - {0x81ed0580,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100DA201E0DA000,"01000C7019E1C000","1.0.0"}},//dialogue - {0x81f96bac,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100DA201E0DA000,"01000C7019E1C000","1.0.0"}},//name - {0x8250ac28,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100DA201E0DA000,"01000C7019E1C000","1.0.0"}},//choice - //Jakou no Lyla ~Trap of MUSK~ - {0x80167100,{CODEC_UTF32,1,0,0,F010093800DB1C000,"010093800DB1C000","1.0.0"}},// x1 text + name (unformated), #T1 #T2, #T0/* 1. European night */ - {0x801589a0,{CODEC_UTF32,1,0,0,F010093800DB1C000,"010093800DB1C000","1.0.0"}},// x0=x1=choice (sig=SltAdd) - {0x801b4300,{CODEC_UTF32,1,0,0,F010093800DB1C000,"010093800DB1C000","1.0.0"}},// x1 text + name (unformated), #T1 #T2, #T0/* 2. Asian night */ - {0x802a9170,{CODEC_UTF32,1,0,0,F010093800DB1C000,"010093800DB1C000","1.0.0"}},// x0=x1=choice (sig=SltAdd) - {0x80301e80,{CODEC_UTF32,1,0,0,F010093800DB1C000,"010093800DB1C000","1.0.0"}},// x1 text + name (unformated), #T1 #T2, #T0/* 3. Arabic night */ - {0x803f7a90,{CODEC_UTF32,1,0,0,F010093800DB1C000,"010093800DB1C000","1.0.0"}},// x0=x1=choice (sig=SltAdd) - //Galleria no Chika Meikyuu to Majo no Ryodan ガレリアの地下迷宮と魔女ノ旅団 - {0x8002f64c,{CODEC_UTF8,0,0,0,0,"01007010157B4000","1.0.1"}},//Main Text - //Dragon's Dogma: Dark Arisen - {0x81023a80,{CODEC_UTF8,1,0,0,F010057E00AC56000<0>,"010057E00AC56000","1.0.1"}},//Main Text - {0x8103e140,{CODEC_UTF8,1,0,0,F010057E00AC56000<1>,"010057E00AC56000","1.0.1"}},//Allies + Cutscene Text - {0x8103bb10,{CODEC_UTF8,1,0,0,F010057E00AC56000<2>,"010057E00AC56000","1.0.1"}},//NPC Text - {0x80150720,{CODEC_UTF8,0,0,0,F010057E00AC56000<3>,"010057E00AC56000","1.0.1"}},//Intro Message - {0x80df90a8,{CODEC_UTF8,0,0,0,F010057E00AC56000<4>,"010057E00AC56000","1.0.1"}},//Info1 - {0x80ce2bb8,{CODEC_UTF8,0,0,0,F010057E00AC56000<5>,"010057E00AC56000","1.0.1"}},//Info2 - {0x80292d84,{CODEC_UTF8,0,0,0,F010057E00AC56000<6>,"010057E00AC56000","1.0.1"}},//Info Popup1 - {0x80cfac6c,{CODEC_UTF8,0,0,0,F010057E00AC56000<7>,"010057E00AC56000","1.0.1"}},//Info Popup2 - {0x8102d460,{CODEC_UTF8,1,0,0,F010057E00AC56000<8>,"010057E00AC56000","1.0.1"}},//Description - //Yo-kai Watch Jam - Yo-kai Academy Y: Waiwai Gakuen - {0x80dd0cec,{CODEC_UTF8,0,0,0,F010051D010FC2000,"010051D010FC2000","4.0.0"}},//Dialogue text - {0x80e33450,{CODEC_UTF8,3,0,0,F010051D010FC2000,"010051D010FC2000","4.0.0"}},//Other Dialogue text - {0x80c807c0,{CODEC_UTF8,0,0,0,F010051D010FC2000,"010051D010FC2000","4.0.0"}},//Item description etc text - {0x808d9a30,{CODEC_UTF8,0,0,0,F010051D010FC2000,"010051D010FC2000","4.0.0"}},//Tutorial Text - {0x811b95ac,{CODEC_UTF8,3,0,0,F010051D010FC2000,"010051D010FC2000","4.0.0"}},//Menu screen - {0x80e20290,{CODEC_UTF8,3,0,0,F010051D010FC2000,"010051D010FC2000","4.0.0"}},//Opening Song Text etc - {0x80c43680,{CODEC_UTF8,3,0,0,F010051D010FC2000,"010051D010FC2000","4.0.0"}},//Cutscene Text - //NEO: The World Ends With You - {0x81581d6c,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F010043B013C5C000<0>,"010043B013C5C000","1.03"}},//Text - {0x818eb248,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010043B013C5C000<1>,"010043B013C5C000","1.03"}},//Objective - {0x81db84a4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010043B013C5C000<2>,"010043B013C5C000","1.03"}},//Menu: Collection Item Name - {0x81db8660,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F010043B013C5C000<3>,"010043B013C5C000","1.03"}},//Menu: Collection Item Description - {0x81c71a48,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010043B013C5C000<4>,"010043B013C5C000","1.03"}},//Tutorial Title - {0x81c71b28,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F010043B013C5C000<5>,"010043B013C5C000","1.03"}},//Tutorial Description - //Eiyuden Chronicle: Rising - {0x82480190,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,0,"010039B015CB6000","1.02"}},//Main Text - {0x824805d0,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,0,"010039B015CB6000","1.02"}},//Name - {0x81f05c44,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Intro Text - {0x82522ac4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Character Info - {0x81b715f4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Info - {0x825274d0,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,0,"010039B015CB6000","1.02"}},//Info2 - {0x825269b0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Tutorial Title - {0x82526a0c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Tutorial Description - {0x82523e04,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Objective Title - {0x82524160,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Objective Description - {0x81f0351c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Location Selection Title - {0x81f0358c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Location Selection Description - {0x81f0d520,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Quest Title - {0x81f0d58c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Quest Description - {0x81f00318,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Help Title - {0x81f00368,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Help Description - {0x81f0866c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,0,"010039B015CB6000","1.02"}},//Config Description - //Ghost Trick: Phantom Detective - {0x81448898,{CODEC_UTF16,0,0,0,F010043B013C5C000<6>,"010029B018432000","1.0.0"}},//Main Text - {0x80c540d4,{CODEC_UTF16,0,0,0,F010043B013C5C000<7>,"010029B018432000","1.0.0"}},//Secondary Text - {0x80e50dd4,{CODEC_UTF16,0,0,0,F010043B013C5C000<8>,"010029B018432000","1.0.0"}},//Object Name - {0x80f91c08,{CODEC_UTF16,0,0,0,F010043B013C5C000<9>,"010029B018432000","1.0.0"}},//Language Selection - {0x805c9014,{CODEC_UTF16,0,0,0,F010043B013C5C000<10>,"010029B018432000","1.0.0"}},//Story/Character Info - //Higurashi no Naku Koro ni Hou - {0x800bd6c8,{0,0,0,0,F0100F6A00A684000,"0100F6A00A684000","1.0.0"}},//sjis - {0x800c2d20,{0,0,0,0,F0100F6A00A684000,"0100F6A00A684000","1.2.0"}},//sjis - //Umineko no Naku Koro ni Saku ~Nekobako to Musou no Koukyoukyoku~ - {0x800b4560,{CODEC_UTF8,0,0,0,0,"01006A300BA2C000","1.0.0"}},// x0 name + text (bottom, center) - whole line. filter is to complex, quit. - {0x801049c0,{CODEC_UTF8,0,0,0,0,"01006A300BA2C000","1.0.0"}},// x0 prompt, bottomLeft - {0x80026378,{CODEC_UTF8,0,0,0,0,"01006A300BA2C000","1.0.0"}},// x0 Yes|No - {0x801049a8,{CODEC_UTF8,0,0,0,0,"01006A300BA2C000","1.0.0"}},// x0 topLeft (double: ♪ + text) - - //Koroshiya to Strawberry- Plus - {0x81322cec,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F010042300C4F6000,"0100E390145C8000","1.0.0"}},//dialogue - {0x819b1a78,{CODEC_UTF16,0,0,ReadTextAndLenW<2>,F010042300C4F6000,"0100E390145C8000","1.0.0"}},//dialogue - {0x81314e8c,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F010042300C4F6000,"0100E390145C8000","1.0.0"}},//dialogue - //Tokimeki Memorial Girl's Side 1st Love for Nintendo Switch - {0x822454a4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//dialogue1 - {0x82247138,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//dialogue2 - {0x822472e0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//dialogue3 - {0x82156988,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//choice - {0x82642200,{CODEC_UTF16,0,0,ReadTextAndLenDW<2>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//option1 - {0x81ecd758,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//option2 - {0x823185e4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//mail - {0x823f2edc,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//roomDescript - {0x821e3cf0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//dateDescript - {0x81e20050,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//characterDesc1 - {0x81e1fe50,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//characterDesc2 - {0x81e1feb0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//characterDesc3 - {0x81e1ff04,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//characterDesc4 - {0x821d03b0,{CODEC_UTF16,0,0,ReadTextAndLenDW<3>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//news - {0x82312008,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100D9A01BD86000,"0100D9A01BD86000","1.0.1"}},//luckyitem - //Triangle Strategy - {0x80aadebc,{CODEC_UTF16,0,0,0,F0100CC80140F8000<0>,"0100CC80140F8000","1.1.0"}},//Main Text - {0x81358ce4,{CODEC_UTF16,3,0,0,F0100CC80140F8000<1>,"0100CC80140F8000","1.1.0"}},//Secondary Text - {0x80a38988,{CODEC_UTF16,0,0,0,F0100CC80140F8000<2>,"0100CC80140F8000","1.1.0"}},//Info Contents - {0x80aa4aec,{CODEC_UTF16,0,0,0,F0100CC80140F8000<3>,"0100CC80140F8000","1.1.0"}},//Info - {0x80b1f300,{CODEC_UTF16,0,0,0,F0100CC80140F8000<4>,"0100CC80140F8000","1.1.0"}},//Difficulty Selection Part1 - {0x80b1f670,{CODEC_UTF16,0,0,0,F0100CC80140F8000<5>,"0100CC80140F8000","1.1.0"}},//Difficulty Selection Part2 - {0x80aa48f0,{CODEC_UTF16,0,0,0,F0100CC80140F8000<6>,"0100CC80140F8000","1.1.0"}},//PopUp Message - //Xenoblade Chronicles 3 - {0x80cf6ddc,{CODEC_UTF8,0,0,0,F010074F013262000,"010074F013262000","2.2.0"}},//Main Text - {0x80e76150,{CODEC_UTF8,0,0,0,F010074F013262000,"010074F013262000","2.2.0"}},//Secondary Text - {0x807b4ee4,{CODEC_UTF8,1,0,0,F010074F013262000,"010074F013262000","2.2.0"}},//Tutorial Description - {0x80850218,{CODEC_UTF8,0,0,0,F010074F013262000,"010074F013262000","2.2.0"}},//Objective - //CLOCK ZERO ~Shuuen no Ichibyou~ Devote - {0x8003c290,{0,0,0,0,F0100BDD01AAE4000,"01008C100C572000","1.0.0"}},//name,sjis - {0x8003c184,{0,0,0,0,F0100BDD01AAE4000,"01008C100C572000","1.0.0"}},//dialogue - {0x8001f6d0,{0,0,0,0,F0100BDD01AAE4000,"01008C100C572000","1.0.0"}},//prompt - //Shuuen no Virche -ErroR:salvation - {0x8001f594,{CODEC_UTF8,0,0x1C,0,F0100C310110B4000,"01005B9014BE0000","1.0.0"}},//dialog - {0x8001f668,{CODEC_UTF8,0,0x1C,0,F0100C310110B4000,"01005B9014BE0000","1.0.0"}},//center - {0x8003d540,{CODEC_UTF8,0,0,0,F0100C310110B4000,"01005B9014BE0000","1.0.0"}},//choice - //Spade no Kuni no Alice ~Wonderful White World~ / スペードの国のアリス ~Wonderful White World~ - {0x8135d018,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F01008C0016544000,"01003FE00E2F8000","1.0.0"}},//Text + Name - //十三支演義 偃月三国伝1・2 for Nintendo Switch - {0x82031f20,{CODEC_UTF16,0,0,ReadTextAndLenDW<2>,F0100DA201E0DA000,"01003D2017FEA000","1.0.0"}},//name - {0x82ef9550,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100DA201E0DA000,"01003D2017FEA000","1.0.0"}},//dialogue - {0x83252e0c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100DA201E0DA000,"01003D2017FEA000","1.0.0"}},//choice - //Tales of Vesperia: Definitive Edition - {0x802de170,{CODEC_UTF8,2,0,0,F01002C0008E52000,"01002C0008E52000","1.0.2"}},//Ptc Text - {0x802cf170,{CODEC_UTF8,3,0,0,F01002C0008E52000,"01002C0008E52000","1.0.2"}},//Cutscene - {0x8019957c,{CODEC_UTF8,0,0,0,F01002C0008E52000,"01002C0008E52000","1.0.2"}},//Conversation - {0x802c0600,{CODEC_UTF8,2,0,0,F01002C0008E52000,"01002C0008E52000","1.0.2"}},//Info - {0x801135fc,{CODEC_UTF8,0,0,0,F01002C0008E52000,"01002C0008E52000","1.0.2"}},//Post Battle Text - //Nil Adminari no Tenbin Irodori Nadeshiko - {0x8005fd5c,{CODEC_UTF8,0,0,0,F0100BDD01AAE4000,"01002BB00A662000","1.0.0"}},//name - {0x800db0d8,{CODEC_UTF8,0,20,0,F0100BDD01AAE4000,"01002BB00A662000","1.0.0"}},//name - //Hanayaka Nari, Waga Ichizoku Modern Nostalgie - {0x2509ac-0x204000+0x80004000,{CODEC_UTF8,0,0,T0100B5500CA0C000,F0100B5500CA0C000,"01008DE00C022000","1.0.0"}}, - //Master Detective Archives: Rain Code - {0x80bf2034,{CODEC_UTF16,0,0,0,F0100F4401940A000,"0100F4401940A000","1.3.3"}},//Dialogue text - {0x80c099d4,{CODEC_UTF16,0,0,0,F0100F4401940A000,"0100F4401940A000","1.3.3"}},//Cutscene text - {0x80cbf1f4,{CODEC_UTF16,0,0,0,F0100F4401940A000,"0100F4401940A000","1.3.3"}},//Menu - {0x80cbc11c,{CODEC_UTF16,0,0,0,F0100DA201E0DA000,"0100F4401940A000","1.3.3"}},//Menu Item Description - {0x80cacc14,{CODEC_UTF16,0,0,0,F0100DA201E0DA000,"0100F4401940A000","1.3.3"}},//Menu Item Description 2 - {0x80cd6410,{CODEC_UTF16,0,0,0,F0100DA201E0DA000,"0100F4401940A000","1.3.3"}},//Menu Item Description 3 - {0x80c214d4,{CODEC_UTF16,0,0,0,F0100F4401940A000,"0100F4401940A000","1.3.3"}},//Description - {0x80cc9908,{CODEC_UTF16,0,0,0,F0100DA201E0DA000,"0100F4401940A000","1.3.3"}},//Mini game item description - {0x80bce36c,{CODEC_UTF16,0,0,0,F0100F4401940A000,"0100F4401940A000","1.3.3"}},//Tutorial - {0x80bcb7d4,{CODEC_UTF16,0,0,0,F0100F4401940A000,"0100F4401940A000","1.3.3"}},//Loading Screen information - {0x80bf32d8,{CODEC_UTF16,0,0,0,F0100F4401940A000,"0100F4401940A000","1.3.3"}},//Choices - //Fire Emblem: Three Houses - {0x8041e6bc,{CODEC_UTF8,0,0,0,F010055D009F78000<0>,"010055D009F78000","1.2.0"}},//Main Text - {0x805ca570,{CODEC_UTF8,0,0,0,F010055D009F78000<1>,"010055D009F78000","1.2.0"}},//Cutscene Text - {0x8049f1e8,{CODEC_UTF8,0,0,0,F010055D009F78000<2>,"010055D009F78000","1.2.0"}},//Cutscene Text Scroll - {0x805ee730,{CODEC_UTF8,0,0,0,F010055D009F78000<3>,"010055D009F78000","1.2.0"}},//Info - {0x805ee810,{CODEC_UTF8,0,0,0,F010055D009F78000<4>,"010055D009F78000","1.2.0"}},//Info Choice - {0x80467a60,{CODEC_UTF8,0,0,0,F010055D009F78000<5>,"010055D009F78000","1.2.0"}},//Location First Part - {0x805f0340,{CODEC_UTF8,0,0,0,F010055D009F78000<6>,"010055D009F78000","1.2.0"}},//Location Second Part - {0x801faae4,{CODEC_UTF8,0,0,0,F010055D009F78000<7>,"010055D009F78000","1.2.0"}},//Action Location - {0x803375e8,{CODEC_UTF8,0,0,0,F010055D009F78000<8>,"010055D009F78000","1.2.0"}},//Objective - {0x805fd870,{CODEC_UTF8,0,0,0,F010055D009F78000<9>,"010055D009F78000","1.2.0"}},//Tutorial - {0x804022f8,{CODEC_UTF8,0,0,0,F010055D009F78000<10>,"010055D009F78000","1.2.0"}},//Request - {0x802f7df4,{CODEC_UTF8,0,0,0,F010055D009F78000<11>,"010055D009F78000","1.2.0"}},//Quest Description - {0x8031af0c,{CODEC_UTF8,0,0,0,F010055D009F78000<12>,"010055D009F78000","1.2.0"}},//Aproach Text - //Sweet Clown ~Gozen San-ji no Okashi na Doukeshi~ - {0x20dbfc-0x204000+0x80004000,{0,0,0x28,0,F010028D0148E6000,"010028D0148E6000","1.2.0"}},//dialog, sjis - {0x214978-0x204000+0x80004000,{0,2,0xC,0,F010028D0148E6000,"010028D0148E6000","1.2.0"}},//choices - //Another Code: Recollection - {0x82dcad30,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Main Text - {0x82f2cfb0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Item Description - {0x82dcc5fc,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Tutorial PopUp Header - {0x82dcc61c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Tutorial PopUp Description - {0x82f89e78,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Aproach Text - {0x82973300,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Chapter - {0x82dd2604,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Location - {0x82bcb77c,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Save Message - {0x828ccfec,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Acquired Item - {0x83237b14,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Question Options - {0x82dcee10,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Tutorial Header - {0x82dcee38,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Tutorial Description - {0x82e5cadc,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Character Info Name - {0x82e5cc38,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Character Info Description - {0x82871ac8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Letter Message - {0x82e4dad4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//アナザーキー - {0x82bd65d0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Message Title - {0x82bd65f0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Message Content - {0x82c1ccf0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Decision Header - {0x82c1d218,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Decision1 - {0x82c1e43c,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100CB9018F5A000,"0100CB9018F5A000","1.0.0"}},//Decision2 - //AI: The Somnium Files - {0x8165a9a4,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100C7400CFB4000<0>,"0100C7400CFB4000","1.0.2"}},//Main Text + Tutorial - {0x80320dd4,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100C7400CFB4000<1>,"0100C7400CFB4000","1.0.2"}},//Menu Interface Text1 - {0x80320e20,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F0100C7400CFB4000<2>,"0100C7400CFB4000","1.0.2"}},//Menu Interface Text2 - //AI: The Somnium Files - nirvanA Initiative - {0x8189ae64,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BD4014D8C000<0>,"0100BD4014D8C000","1.0.1"}},//Main Text + Tutorial - {0x81813428,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BD4014D8C000<1>,"0100BD4014D8C000","1.0.1"}},//Hover Investigation Text - {0x82e122b8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BD4014D8C000<2>,"0100BD4014D8C000","1.0.1"}},//Info - {0x82cffff8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BD4014D8C000<3>,"0100BD4014D8C000","1.0.1"}},//Config Description - {0x818c3cd8,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BD4014D8C000<4>,"0100BD4014D8C000","1.0.1"}},//File: Names - {0x82ea1a38,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BD4014D8C000<5>,"0100BD4014D8C000","1.0.1"}},//File: Contents - {0x82cbb1fc,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F0100BD4014D8C000<6>,"0100BD4014D8C000","1.0.1"}},//Investigation Choices - //Fata morgana no Yakata ~Dreams of the Revenants Edition~ / ファタモ - {0x8025a998,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01008C0016544000,"0100BE40138B8000","1.0.1"}},//Main Text - {0x801d6050,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01008C0016544000,"0100BE40138B8000","1.0.1"}},//Choices - //Ni no Kuni II: Revenant Kingdom - {0x80ac651c,{CODEC_UTF8,0,0,0,F0100C4E013E5E000,"0100C4E013E5E000","1.0.0"}},//Main Text - {0x80335ea0,{CODEC_UTF8,0,0,0,F0100C4E013E5E000,"0100C4E013E5E000","1.0.0"}},//Name - //Harukanaru Toki no Naka de 7 - {0x800102bc,{0,0,0,T0100CF400F7CE000<0>,F0100CF400F7CE000,"0100CF400F7CE000","1.0.0"}},//name, sjis - {0x80051f90,{0,0,0,T0100CF400F7CE000<1>,F0100CF400F7CE000,"0100CF400F7CE000","1.0.0"}},//text - {0x80010b48,{0,0,0,T0100CF400F7CE000<0>,F0100CF400F7CE000,"0100CF400F7CE000","1.0.0"}},//prompt - {0x80010c80,{0,0,0,T0100CF400F7CE000<0>,F0100CF400F7CE000,"0100CF400F7CE000","1.0.0"}},//choice - //Angelique Luminarise - {0x80046c04,{0,0,0,T0100CF400F7CE000<0>,F0100CF400F7CE000,"0100D11018A7E000","1.0.0"}},//ingameDialogue, sjis - {0x80011284,{0,0,0,T0100CF400F7CE000<0>,F0100CF400F7CE000,"0100D11018A7E000","1.0.0"}},//choice - {0x80011140,{0,0,0,T0100CF400F7CE000<0>,F0100CF400F7CE000,"0100D11018A7E000","1.0.0"}},//prompt first - //Star Ocean The Second Story R - {0x81d5e4d0,{0,0,0,ReadTextAndLenDW<1>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Main Text + Tutorial - {0x81d641b4,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Intro Cutscene - {0x824b1f00,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Character Selection Name - {0x81d4c670,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Character Selection Lore - {0x8203a048,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//General Description - {0x82108cd0,{0,0,0,ReadTextAndLenDW<1>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Unique Spot Title - {0x827a9848,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Chest Item - {0x82756890,{0,0,0,ReadTextAndLenDW<1>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Info - {0x82241410,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Menu Talk - {0x81d76404,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Secondary Talk - {0x821112e0,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Location - {0x82111320,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Location Interior - {0x81d6ea24,{0,0,0,ReadTextAndLenDW<1>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Special Arts/Spells Name - {0x81d6ea68,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Special Arts/Spells Description - {0x81d6ed48,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Special Arts/Spells Range - {0x81d6eb3c,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Special Arts/Spells Effect - {0x81d6f880,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Special Arts/Spells Bonus - {0x8246d81c,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Tactics Name - {0x8246d83c,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Tactics Description - {0x8212101c,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Achievements Name - {0x82121088,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Achievements Description - {0x81d6c480,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Acquired Item1 - {0x821143f0,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Acquired Item2 - {0x81d6fb18,{0,0,0,ReadTextAndLenDW<1>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Battle Skill Name - {0x81d6fb4c,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Battle Skill Description - {0x81d6fb7c,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Battle Skill Bonus Description - {0x8212775c,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Battle Item Name - {0x82127788,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Battle Item Description - {0x821361ac,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Battle Ability Name - {0x821361f4,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Battle Ability Range - {0x82136218,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Battle Ability Effect - {0x8238451c,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Battle Strategy Name - {0x82134610,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Battle Acquired Item - {0x824b5eac,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Item Name - {0x824b5f04,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Item Description - {0x824b5f54,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Item Effect - {0x81d71790,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Item Factor Title - {0x824b62c0,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Item Factor Description - {0x824c2e2c,{0,0,0,ReadTextAndLenDW<1>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//IC/Specialty Skills Name - {0x824c2e54,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//IC/Specialty Skills Description - {0x824c2fbc,{0,0,0,ReadTextAndLenDW<1>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//IC/Specialty Skills Level - {0x823e7230,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//IC/Specialty Name - {0x823e94bc,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//IC/Specialty Description - {0x823e9980,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//IC/Specialty Talent - {0x823ea9c4,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//IC/Specialty Support Item - {0x82243b18,{0,0,0,ReadTextAndLenDW<1>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Enemy Info Skills - {0x81d64540,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Guild Mission Description - {0x823b4f6c,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Guild Mission Reward - {0x826facd8,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Challenge Mission Description - {0x826f98f8,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Challenge Mission Reward - {0x8244af2c,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Formation Name - {0x8244ae90,{0,0,0,ReadTextAndLenDW<0>,F010065301A2E0000,"010065301A2E0000","1.0.2"}},//Formation Description - //魔法使いの夜 通常版 - {0x80086ba0,{CODEC_UTF8,0,0,T010012A017F18000,0,"010012A017F18000","1.0.0"}}, - {0x80086e70,{CODEC_UTF8,0,0,T010012A017F18000,0,"010012A017F18000","1.0.2"}}, - //月姫 -A piece of blue glass moon- - {0x800ac290,{CODEC_UTF8,0,0,T010012A017F18000,0,"01001DC01486A000",0}},//1.0.1,1.0.2 - //The Quintessential Quintuplets the Movie: Five Memories of My Time with You (JP) - {0x80011688,{CODEC_UTF8,1,0,0,F01005E9016BDE000,"01005E9016BDE000","1.0.0"}},//dialogue, menu, choice, name - // Flowers: Les Quatre Saisons - {0x8006f940,{CODEC_UTF16,1,0,0,F01002AE00F442000,"01002AE00F442000","1.0.1"}}, - //最悪なる災厄人間に捧ぐ eSHOP [01000A400AF2A000][v0] - {0x8034EB44,{CODEC_UTF16,8,0,0,F01000A400AF2A000,"01000A400AF2A000","1.0.0"}},//text - //神様のような君へ - {0x80487CD0,{CODEC_UTF8,0,0,0,F01006B5014E2E000,"01006B5014E2E000","1.0.0"}},//text - //BUSTAFELLOWS - {0x80191b18,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100874017BE2000,"010060800B7A8000","1.1.3"}},//Dialogue - {0x80191f88,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100874017BE2000,"010060800B7A8000","1.1.3"}},//Choice - {0x801921a4,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100874017BE2000,"010060800B7A8000","1.1.3"}},//Choice 2 - {0x801935f0,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F0100874017BE2000,"010060800B7A8000","1.1.3"}},//option - //Moujuutsukai to Ouji-sama ~Flower & Snow~ - {0x800a1a10,{CODEC_UTF8,1,0,0,F01001B900C0E2000,"01001B900C0E2000","1.0.0"}},//Dialogue 1 - {0x80058f80,{CODEC_UTF8,1,0,0,F01001B900C0E2000,"01001B900C0E2000","1.0.0"}},//Dialogue 2 - //Detective Pikachu Returns - {0x81585750,{CODEC_UTF16,0,0,ReadTextAndLenDW<2>,F010007500F27C000,"010007500F27C000","1.0.0"}},//All Text - //Dragon Quest Treasures - {0x80bd62c4,{CODEC_UTF16,0,0,0,F0100217014266000,"0100217014266000","1.0.1"}},//Cutscene - {0x80a74b64,{CODEC_UTF16,0,0,0,F0100217014266000,"0100217014266000","1.0.1"}},//Ptc Text - {0x80a36d18,{CODEC_UTF16,0,0,0,F0100217014266000,"0100217014266000","1.0.1"}},//Info - {0x80c43878,{CODEC_UTF16,0,0,0,F0100217014266000,"0100217014266000","1.0.1"}},//Tutorial Title - {0x80c43d50,{CODEC_UTF16,0,0,0,F0100217014266000,"0100217014266000","1.0.1"}},//Tutorial Description - {0x80a72598,{CODEC_UTF16,0,0,0,F0100217014266000,"0100217014266000","1.0.1"}},//Aproach Text - //Rune Factory 4 Special - {0x48b268-0x204000+0x80004000,{CODEC_UTF8,3,0,0,F010027100C79A000,"010027100C79A000","1.0.1"}},//All Text - //The Legend of Zelda: Skyward Sword HD - {0x80dc36dc,{CODEC_UTF16|FULL_STRING,3,0,0,F01001EF017BE6000,"01002DA013484000","1.0.1"}},//All Text - //World of Final Fantasy Maxima - {0x8068fea0,{CODEC_UTF8,0,0,0,F010072000BD32000<0>,"010072000BD32000","1.0.0"}},//Cutscene - {0x802c6a48,{CODEC_UTF8,0,0,0,F010072000BD32000<1>,"010072000BD32000","1.0.0"}},//Action Text - {0x803a523c,{CODEC_UTF8,1,0,0,F010072000BD32000<2>,"010072000BD32000","1.0.0"}},//Location - {0x8041ed64,{CODEC_UTF8,0,0,0,F010072000BD32000<3>,"010072000BD32000","1.0.0"}},//Info - {0x802c9f1c,{CODEC_UTF8,0,0,0,F010072000BD32000<4>,"010072000BD32000","1.0.0"}},//Chapter First Part - {0x802c9f6c,{CODEC_UTF8,0,0,0,F010072000BD32000<5>,"010072000BD32000","1.0.0"}},//Chapter Second Part - //Tokyo Xanadu eX+ - {0x8025135c,{CODEC_UTF8,1,0,0,F010080C01AA22000,"010080C01AA22000","1.0.0"}},//Name - {0x80251068,{CODEC_UTF8,0,0,0,F010080C01AA22000,"010080C01AA22000","1.0.0"}},//Main Text - {0x802ac86c,{CODEC_UTF8,0,0,0,F010080C01AA22000,"010080C01AA22000","1.0.0"}},//Action Text - {0x802b04b4,{CODEC_UTF8,0,0,0,F010080C01AA22000,"010080C01AA22000","1.0.0"}},//Choices - {0x8013243c,{CODEC_UTF8,0,0,0,F010080C01AA22000,"010080C01AA22000","1.0.0"}},//Location - {0x802b1f3c,{CODEC_UTF8,0,0,0,F010080C01AA22000,"010080C01AA22000","1.0.0"}},//Info - {0x802ab46c,{CODEC_UTF8,0,0,0,F010080C01AA22000,"010080C01AA22000","1.0.0"}},//Documents - //DORAEMON STORY OF SEASONS: Friends of the Great Kingdom - {0x839558e4,{CODEC_UTF16,0,0,ReadTextAndLenDW<1>,F01009B50139A8000<0>,"01009B50139A8000","1.1.1"}},//Text - {0x8202a9b0,{CODEC_UTF16,0,0,ReadTextAndLenDW<0>,F01009B50139A8000<1>,"01009B50139A8000","1.1.1"}},//Tutorial - //Monster Hunter Stories 2: Wings of Ruin - {0x8042fe60,{CODEC_UTF8,1,0,0,F0100CB700D438000<0>,"0100CB700D438000","1.5.2"}},//Cutscene - {0x804326c0,{CODEC_UTF8,1,0,0,F0100CB700D438000<1>,"0100CB700D438000","1.5.2"}},//Ptc Text - {0x804d3d44,{CODEC_UTF8,0,0,0,F0100CB700D438000<2>,"0100CB700D438000","1.5.2"}},//Info - {0x8045e7c8,{CODEC_UTF8,0,0,0,F0100CB700D438000<3>,"0100CB700D438000","1.5.2"}},//Info Choice - {0x805cec4c,{CODEC_UTF8,0,0,0,F0100CB700D438000<4>,"0100CB700D438000","1.5.2"}},//Config Header - {0x8078c2d0,{CODEC_UTF8,0,0,0,F0100CB700D438000<5>,"0100CB700D438000","1.5.2"}},//Config Name+ - {0x805d0858,{CODEC_UTF8,0,0,0,F0100CB700D438000<6>,"0100CB700D438000","1.5.2"}},//Config Description - {0x807612d4,{CODEC_UTF8,0,0,0,F0100CB700D438000<7>,"0100CB700D438000","1.5.2"}},//Notice - {0x807194a0,{CODEC_UTF8,1,0,0,F0100CB700D438000<8>,"0100CB700D438000","1.5.2"}},//Update Content + Tutorial - {0x804d687c,{CODEC_UTF8,0,0,0,F0100CB700D438000<9>,"0100CB700D438000","1.5.2"}},//Objective Title - {0x804d6a7c,{CODEC_UTF8,0,0,0,F0100CB700D438000<10>,"0100CB700D438000","1.5.2"}},//Objective Description - {0x80509900,{CODEC_UTF8,0,0,0,F0100CB700D438000<11>,"0100CB700D438000","1.5.2"}},//Aproach Text - {0x8060ee90,{CODEC_UTF8,1,0,0,F0100CB700D438000<12>,"0100CB700D438000","1.5.2"}},//Acquired Item - //2045、月より。 - {0x80016334,{CODEC_UTF8,1,0,0,F01005C301AC5E000,"01005C301AC5E000","1.0.1"}}, - //ヤマノススメ Next Summit ~あの山に、もう一度~ - {0x806E1444,{CODEC_UTF8,0,0,0,F0100815019488000_text,"0100815019488000","1.0.0"}}, - {0x80659EE0,{CODEC_UTF8,1,0,0,F0100815019488000_name,"0100815019488000","1.0.0"}}, - //Prison Princess - {0x800eba00,{CODEC_UTF16,2,0x14,0,0,"0100F4800F872000","1.0.0"}}, - //Utakata no Uchronia - {0x8180de40,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F010027401A2A2000,"010027401A2A2000","1.0.0"}},//text box - {0x816b61c0,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F010027401A2A2000,"010027401A2A2000","1.0.0"}},//dictionary - {0x815fe594,{CODEC_UTF16,0,0,ReadTextAndLenW<0>,F010027401A2A2000,"010027401A2A2000","1.0.0"}},//choices - //GrimGrimoire OnceMore - {0x80020bd4,{CODEC_UTF8,0,0,0,0,"01003F5017760000","1.0.0"}}, - {0x800375a0,{CODEC_UTF8,2,0,0,0,"01003F5017760000","1.0.0"}},//tutorial - {0x800781dc,{CODEC_UTF8,0,0,0,0,"01003F5017760000","1.0.0"}}, - //Little Busters! Converted Edition - {0x800A97C8,{CODEC_UTF8,9,0,0,F0100943010310000,"0100943010310000","1.0.0"}}, - }; - return 1; -}(); -} \ No newline at end of file diff --git a/LunaHook/engine64/yuzusuyu.h b/LunaHook/engine64/yuzusuyu.h deleted file mode 100644 index 455db7a..0000000 --- a/LunaHook/engine64/yuzusuyu.h +++ /dev/null @@ -1,16 +0,0 @@ - - -class yuzusuyu:public ENGINE{ - public: - yuzusuyu(){ - - is_engine_certain=false; - check_by=CHECK_BY::CUSTOM; - check_by_target=[](){ - - return (wcscmp(processName_lower, L"suyu.exe")==0 || wcscmp(processName_lower, L"yuzu.exe")==0|| wcscmp(processName_lower, L"sudachi.exe")==0); - }; - }; - bool attach_function(); -}; - \ No newline at end of file diff --git a/LunaHook/enginecollection64.cpp b/LunaHook/enginecollection64.cpp index f42eabc..eb2d12c 100644 --- a/LunaHook/enginecollection64.cpp +++ b/LunaHook/enginecollection64.cpp @@ -16,7 +16,7 @@ #include "engine64/TYPEMOON.h" #include "engine64/Kincaid.h" #include "engine64/LightVN.h" -#include "engine64/yuzusuyu.h" +#include "engine64/yuzu.h" #include "engine64/Ryujinx.h" #include "engine64/vita3k.h" #include "engine64/rpcs3.h" @@ -42,7 +42,7 @@ std::vector check_engines() new _5pb, new TYPEMOON, new ENTERGRAM, - new yuzusuyu, + new yuzu, new PPSSPPengine, new vita3k, new rpcs3, diff --git a/LunaHook/engines/ppsspp/specialgames.hpp b/LunaHook/engines/ppsspp/specialgames.hpp index a752f10..2db1301 100644 --- a/LunaHook/engines/ppsspp/specialgames.hpp +++ b/LunaHook/engines/ppsspp/specialgames.hpp @@ -1,329 +1,377 @@ -#include -#include"emujitarg.hpp" +#include +#include "emujitarg.hpp" -namespace ppsspp{ -bool ULJS00403_filter(void* data, size_t* len, HookParam* hp){ - std::string result = std::string((char*)data,*len); - std::regex newlinePattern(R"((\\n)+)"); - result = std::regex_replace(result, newlinePattern, " "); - std::regex pattern(R"((\\d$|^\@[a-z]+|#.*?#|\$))"); - result = std::regex_replace(result, pattern, ""); - return write_string_overwrite(data,len,result); -} - - -void ULJS00339(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto a2= PPSSPP::emu_arg(stack)[0]; - - auto vm = *(DWORD*)(a2+(0x28)); - vm=*(DWORD*)PPSSPP::emu_addr(stack,vm); - vm=*(DWORD*)PPSSPP::emu_addr(stack,vm+8); - uintptr_t address=PPSSPP::emu_addr(stack,vm); - auto len1=*(DWORD*)(address+4); - auto p=address+0x20; - if(len1>4 && *(WORD*)(p+2)==0){ - auto p1=*(DWORD*)(address+8); - vm=*(DWORD*)PPSSPP::emu_addr(stack,vm); - vm=*(DWORD*)PPSSPP::emu_addr(stack,vm+0xC); - p=PPSSPP::emu_addr(stack,vm); +namespace ppsspp +{ + bool ULJS00403_filter(void *data, size_t *len, HookParam *hp) + { + std::string result = std::string((char *)data, *len); + std::regex newlinePattern(R"((\\n)+)"); + result = std::regex_replace(result, newlinePattern, " "); + std::regex pattern(R"((\\d$|^\@[a-z]+|#.*?#|\$))"); + result = std::regex_replace(result, pattern, ""); + return write_string_overwrite(data, len, result); } - static int fm=0; - static std::string pre; - auto b=fm; - auto s=[](uintptr_t address){ - auto frist = *(WORD*)address; - auto lo = frist & 0xFF; // uppercase: 41->5A - auto hi = frist >> 8; - if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */) { - return std::string(); - } - std::string s ;int i = 0;WORD c; - char buf[3]={0}; - while ((c = *(WORD*)(address+i)) != 0) { - // reverse endian: ShiftJIS BE => LE - buf[0] = c >> 8; - buf[1] = c & 0xFF; - if (c == 0x815e /* / */) { - s += ' '; // single line + void ULJS00339(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto a2 = PPSSPP::emu_arg(stack)[0]; + + auto vm = *(DWORD *)(a2 + (0x28)); + vm = *(DWORD *)PPSSPP::emu_addr(stack, vm); + vm = *(DWORD *)PPSSPP::emu_addr(stack, vm + 8); + uintptr_t address = PPSSPP::emu_addr(stack, vm); + auto len1 = *(DWORD *)(address + 4); + auto p = address + 0x20; + if (len1 > 4 && *(WORD *)(p + 2) == 0) + { + auto p1 = *(DWORD *)(address + 8); + vm = *(DWORD *)PPSSPP::emu_addr(stack, vm); + vm = *(DWORD *)PPSSPP::emu_addr(stack, vm + 0xC); + p = PPSSPP::emu_addr(stack, vm); + } + static int fm = 0; + static std::string pre; + auto b = fm; + auto s = [](uintptr_t address) + { + auto frist = *(WORD *)address; + auto lo = frist & 0xFF; // uppercase: 41->5A + auto hi = frist >> 8; + if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */) + { + return std::string(); } - else if (buf[0] == 0) { - //// UTF16 LE turned BE: 5700=>0057, 3100, 3500 - //// 4e00 6d00=>PLAYER - // do nothing - if (buf[1] == 0x4e) { - s += "PLAYER"; - fm++; + std::string s; + int i = 0; + WORD c; + char buf[3] = {0}; + while ((c = *(WORD *)(address + i)) != 0) + { + // reverse endian: ShiftJIS BE => LE + buf[0] = c >> 8; + buf[1] = c & 0xFF; + + if (c == 0x815e /* / */) + { + s += ' '; // single line + } + else if (buf[0] == 0) + { + //// UTF16 LE turned BE: 5700=>0057, 3100, 3500 + //// 4e00 6d00=>PLAYER + // do nothing + if (buf[1] == 0x4e) + { + s += "PLAYER"; + fm++; + } + } + else + { + s += buf; + } + i += 2; + } + return s; + }(p); + if (b > 0) + { + fm--; + return; + } + if (s == pre) + return; + pre = s; + write_string_new(data, len, s); + } + + bool NPJH50909_filter(void *data, size_t *len, HookParam *hp) + { + std::string result = std::string((char *)data, *len); + auto ws = StringToWideString(result, 932).value(); + // Remove single line markers + ws = std::regex_replace(ws, std::wregex(L"(\\%N)+"), L" "); + + // Remove scale marker + ws = std::regex_replace(ws, std::wregex(L"\\%\\@\\%\\d+"), L""); + + // Reformat name + std::wsmatch match; + if (std::regex_search(ws, match, std::wregex(L"(^[^「]+)「"))) + { + std::wstring name = match[1].str(); + ws = std::regex_replace(ws, std::wregex(L"^[^「]+"), L""); + ws = name + L"\n" + ws; + } + return write_string_overwrite(data, len, WideStringToString(ws, 932)); + } + + bool ULJM06119_filter(void *data, size_t *len, HookParam *hp) + { + std::string s = std::string((char *)data, *len); + + std::regex pattern(R"(/\[[^\]]+./g)"); + s = std::regex_replace(s, pattern, ""); + + std::regex tagPattern(R"(/\\k|\\x|%C|%B)"); + s = std::regex_replace(s, tagPattern, ""); + + std::regex colorPattern(R"(/\%\d+\#[0-9a-fA-F]*\;)"); + s = std::regex_replace(s, colorPattern, ""); + + std::regex newlinePattern(R"(/\n+)"); + s = std::regex_replace(s, newlinePattern, " "); + return write_string_overwrite(data, len, s); + } + + bool ULJM06036_filter(void *data, size_t *len, HookParam *hp) + { + std::wstring result = std::wstring((wchar_t *)data, *len / 2); + std::wregex pattern(LR"(]+).>)"); + result = std::regex_replace(result, pattern, L"$2"); + std::wregex tagPattern(LR"(<[A-Z]+>)"); + result = std::regex_replace(result, tagPattern, L""); + return write_string_overwrite(data, len, result); + } + + namespace Corda + { + std::string readBinaryString(uintptr_t address, bool *haveName) + { + *haveName = false; + if ((*(WORD *)address & 0xF0FF) == 0x801b) + { + *haveName = true; + address = address + 2; // (1) + } + std::string s; + int i = 0; + uint8_t c; + while ((c = *(uint8_t *)(address + i)) != 0) + { + if (c == 0x1b) + { + if (*haveName) + return s; // (1) skip junk after name + + c = *(uint8_t *)(address + (i + 1)); + if (c == 0x7f) + i += 5; + else + i += 2; + } + else if (c == 0x0a) + { + s += '\n'; + i += 1; + } + else if (c == 0x20) + { + s += ' '; + i += 1; + } + else + { + auto len = 1 + (IsDBCSLeadByteEx(932, *(BYTE *)(address + i))); + s += std::string((char *)(address + i), len); + i += len; // encoder.encode(c).byteLength; } } - else { - s+=buf; - } - i += 2; + return s; } - return s; - }(p); - if(b>0){ - fm--; - return; } - if(s==pre)return ; - pre=s; - write_string_new(data,len,s); -} + void ULJM05428(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + auto address = PPSSPP::emu_arg(stack)[1]; + bool haveNamve; + auto s = Corda::readBinaryString(address, &haveNamve); + *split = haveNamve; + write_string_new(data, len, s); + } -bool NPJH50909_filter(void* data, size_t* len, HookParam* hp){ - std::string result = std::string((char*)data,*len); - auto ws=StringToWideString(result,932).value(); - // Remove single line markers - ws = std::regex_replace(ws, std::wregex(L"(\\%N)+"), L" "); - - // Remove scale marker - ws = std::regex_replace(ws, std::wregex(L"\\%\\@\\%\\d+"), L""); - - // Reformat name - std::wsmatch match; - if (std::regex_search(ws, match, std::wregex(L"(^[^「]+)「"))) { - std::wstring name = match[1].str(); - ws = std::regex_replace(ws, std::wregex(L"^[^「]+"), L""); - ws = name + L"\n" + ws; - } - return write_string_overwrite(data,len,WideStringToString(ws,932)); -} - -bool ULJM06119_filter(void* data, size_t* len, HookParam* hp){ - std::string s = std::string((char*)data,*len); - - std::regex pattern(R"(/\[[^\]]+./g)"); - s = std::regex_replace(s, pattern, ""); - - std::regex tagPattern(R"(/\\k|\\x|%C|%B)"); - s = std::regex_replace(s, tagPattern, ""); - - std::regex colorPattern(R"(/\%\d+\#[0-9a-fA-F]*\;)"); - s = std::regex_replace(s, colorPattern, ""); - - std::regex newlinePattern(R"(/\n+)"); - s = std::regex_replace(s, newlinePattern, " "); - return write_string_overwrite(data,len,s); -} - -bool ULJM06036_filter(void* data, size_t* len, HookParam* hp){ - std::wstring result = std::wstring((wchar_t*)data,*len/2); - std::wregex pattern(LR"(]+).>)"); - result = std::regex_replace(result, pattern, L"$2"); - std::wregex tagPattern(LR"(<[A-Z]+>)"); - result = std::regex_replace(result, tagPattern, L""); - return write_string_overwrite(data,len,result); -} - -namespace Corda{ - std::string readBinaryString(uintptr_t address,bool* haveName){ - * haveName=false; - if ((*(WORD*)address & 0xF0FF) == 0x801b) { - *haveName = true; - address = address+2; // (1) - } - std::string s;int i=0;uint8_t c; - while ((c = *(uint8_t*)(address+i)) != 0) { - if (c == 0x1b) { - if (*haveName) - return s; // (1) skip junk after name - - c = *(uint8_t*)(address+(i + 1)); - if (c == 0x7f) - i += 5; - else - i += 2; - } - else if (c == 0x0a) { - s += '\n'; - i += 1; - } - else if (c == 0x20) { - s += ' '; - i += 1; - } - else { - auto len=1+(IsDBCSLeadByteEx(932,*(BYTE*)(address+i))); - s += std::string((char*)(address+i),len); - i += len;//encoder.encode(c).byteLength; - } + void ULJM05054(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + if (hp->emu_addr != 0x886162c) + { + auto addr = PPSSPP::emu_arg(stack)[0] + 0x3c; + *data = addr; + *len = strlen((char *)addr); + return; } - return s; + auto address = PPSSPP::emu_arg(stack)[1]; + bool haveNamve; + auto s = Corda::readBinaryString(address, &haveNamve); + *split = haveNamve; + write_string_new(data, len, s); } -} -void ULJM05428(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - auto address= PPSSPP::emu_arg(stack)[1]; - bool haveNamve; - auto s=Corda::readBinaryString(address,&haveNamve); - *split=haveNamve; - write_string_new(data,len,s); -} + bool ULJM05943F(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex pattern1("#n+"); + std::string replacement1 = " "; + std::string result1 = std::regex_replace(s, pattern1, replacement1); + std::regex pattern2("#[A-Za-z]+\\[(\\d*\\.)?\\d+\\]+"); + std::string replacement2 = ""; + std::string result2 = std::regex_replace(result1, pattern2, replacement2); + return write_string_overwrite(data, len, result2); + } -void ULJM05054(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - if (hp->emu_addr != 0x886162c) { - auto addr=PPSSPP::emu_arg(stack)[0]+0x3c; - *data=addr;*len=strlen((char*)addr); - return; - } - auto address= PPSSPP::emu_arg(stack)[1]; - bool haveNamve; - auto s=Corda::readBinaryString(address,&haveNamve); - *split=haveNamve; - write_string_new(data,len,s); -} + bool FULJM05603(LPVOID data, size_t *size, HookParam *) + { + auto text = reinterpret_cast(data); + auto len = reinterpret_cast(size); + StringCharReplacer(text, len, "%N", 2, ' '); + StringFilter(text, len, "%K", 2); + StringFilter(text, len, "%P", 2); -bool ULJM05943F(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - std::regex pattern1("#n+"); - std::string replacement1 = " "; - std::string result1 = std::regex_replace(s, pattern1, replacement1); - std::regex pattern2("#[A-Za-z]+\\[(\\d*\\.)?\\d+\\]+"); - std::string replacement2 = ""; - std::string result2 = std::regex_replace(result1, pattern2, replacement2); - return write_string_overwrite(data,len,result2); -} - -bool FULJM05603(LPVOID data, size_t* size, HookParam*) -{ - auto text = reinterpret_cast(data); - auto len = reinterpret_cast(size); - - StringCharReplacer(text, len, "%N", 2, ' '); - StringFilter(text, len, "%K", 2); - StringFilter(text, len, "%P", 2); - - return true; -} -namespace NPJH50530{ - std::string current; -bool T(LPVOID data, size_t* size, HookParam*) -{ - current=std::string((char*)data,*size); - return true; -} -bool N(LPVOID data, size_t* size, HookParam*) -{ - auto current1=std::string((char*)data,*size); - return current!=current1; -} -} -bool FULJM05889(LPVOID data, size_t* size, HookParam*) -{ - auto text = reinterpret_cast(data); - auto len = reinterpret_cast(size); - for(size_t i=0;i<*len;){ - if(IsDBCSLeadByteEx(932,(text[i]))){ - i+=2; - continue; + return true; + } + namespace NPJH50530 + { + std::string current; + bool T(LPVOID data, size_t *size, HookParam *) + { + current = std::string((char *)data, *size); + return true; + } + bool N(LPVOID data, size_t *size, HookParam *) + { + auto current1 = std::string((char *)data, *size); + return current != current1; } - if(text[i]=='^') - text[i]='\n'; - - i+=1; } - return true; -} + bool FNPJH50243(LPVOID data, size_t *size, HookParam *) + { + auto s = std::wstring((wchar_t *)data, *size / 2); + s = std::regex_replace(s, std::wregex(LR"(<(.*?)\|(.*?)>)"), L"$1"); + return write_string_overwrite(data, size, s); + } + bool FULJM05889(LPVOID data, size_t *size, HookParam *) + { + auto text = reinterpret_cast(data); + auto len = reinterpret_cast(size); + for (size_t i = 0; i < *len;) + { + if (IsDBCSLeadByteEx(932, (text[i]))) + { + i += 2; + continue; + } + if (text[i] == '^') + text[i] = '\n'; -bool NPJH50619F(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - std::regex pattern1("[\\r\\n]+"); - std::string replacement1 = ""; - std::string result1 = std::regex_replace(s, pattern1, replacement1); - std::regex pattern2("^(.*?)\\)+"); - std::string replacement2 = ""; - std::string result2 = std::regex_replace(result1, pattern2, replacement2); - std::regex pattern3("#ECL+"); - std::string replacement3 = ""; - std::string result3 = std::regex_replace(result2, pattern3, replacement3); - std::regex pattern4("(#.+?\\))+"); - std::string replacement4 = ""; - std::string result4 = std::regex_replace(result3, pattern4, replacement4); - return write_string_overwrite(data,len,result4); -} + i += 1; + } + return true; + } + bool NPJH50619F(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); + std::regex pattern1("[\\r\\n]+"); + std::string replacement1 = ""; + std::string result1 = std::regex_replace(s, pattern1, replacement1); + std::regex pattern2("^(.*?)\\)+"); + std::string replacement2 = ""; + std::string result2 = std::regex_replace(result1, pattern2, replacement2); + std::regex pattern3("#ECL+"); + std::string replacement3 = ""; + std::string result3 = std::regex_replace(result2, pattern3, replacement3); + std::regex pattern4("(#.+?\\))+"); + std::string replacement4 = ""; + std::string result4 = std::regex_replace(result3, pattern4, replacement4); + return write_string_overwrite(data, len, result4); + } -bool NPJH50505F(void* data, size_t* len, HookParam* hp){ - auto s = std::string((char*)data,*len); - - std::regex pattern2("#RUBS(#[A-Z0-9]+)*[^#]+"); - std::string replacement2 = ""; - std::string result2 = std::regex_replace(s, pattern2, replacement2); + bool NPJH50505F(void *data, size_t *len, HookParam *hp) + { + auto s = std::string((char *)data, *len); - std::regex pattern3("#FAMILY"); - std::string replacement3 = "$FAMILY"; - std::string result3 = std::regex_replace(result2, pattern3, replacement3); + std::regex pattern2("#RUBS(#[A-Z0-9]+)*[^#]+"); + std::string replacement2 = ""; + std::string result2 = std::regex_replace(s, pattern2, replacement2); - std::regex pattern4("#GIVE"); - std::string replacement4 = "$GIVE"; - std::string result4 = std::regex_replace(result3, pattern4, replacement4); + std::regex pattern3("#FAMILY"); + std::string replacement3 = "$FAMILY"; + std::string result3 = std::regex_replace(result2, pattern3, replacement3); - std::regex pattern5("(#[A-Z0-9\\-]+)+"); - std::string replacement5 = ""; - std::string result5 = std::regex_replace(result4, pattern5, replacement5); + std::regex pattern4("#GIVE"); + std::string replacement4 = "$GIVE"; + std::string result4 = std::regex_replace(result3, pattern4, replacement4); - std::regex pattern6("\\n+"); - std::string replacement6 = " "; - std::string result6 = std::regex_replace(result5, pattern6, replacement6); + std::regex pattern5("(#[A-Z0-9\\-]+)+"); + std::string replacement5 = ""; + std::string result5 = std::regex_replace(result4, pattern5, replacement5); - return write_string_overwrite(data,len,result6); -} + std::regex pattern6("\\n+"); + std::string replacement6 = " "; + std::string result6 = std::regex_replace(result5, pattern6, replacement6); + + return write_string_overwrite(data, len, result6); + } + + void QNPJH50909(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) + { + uintptr_t addr = PPSSPP::emu_addr(stack, 0x08975110); + *data = addr + 0x20; + *len = *(DWORD *)(addr + 0x14) * 2; + + if (0x6e87 == *(WORD *)*data) + *len = 0; + if (0x000a == *(WORD *)*data) + *len = 0; + } + std::unordered_map emfunctionhooks = { + // Shinigami to Shoujo + {0x883bf34, {0, 1, 0, 0, ULJS00403_filter, "ULJS00403"}}, + // Amagami + {0x0886775c, {0, 0, 0, ULJS00339, 0, "ULJS00339"}}, // String.length() + // Sekai de Ichiban Dame na Koi + {0x8814adc, {0, 0, 0, 0, NPJH50909_filter, "ULJM05878"}}, // name + dialouge + {0x8850b2c, {0, 0, 0, 0, NPJH50909_filter, "ULJM05878"}}, // onscreen toast + // Dunamis15 + {0x0891D72C, {CODEC_UTF8, 0, 0, 0, ULJM06119_filter, "ULJM06119"}}, + // Princess Evangile Portable + {0x88506d0, {CODEC_UTF16, 2, 0, 0, ULJM06036_filter, "ULJM06036"}}, // [0x88506d0(2)...0x088507C0(?)] // name text text (line doubled) + // Kin'iro no Corda 2f + {0x89b59dc, {0, 0, 0, ULJM05428, 0, "ULJM05428"}}, + // Kin'iro no Corda + {0x886162c, {0, 0, 0, ULJM05054, 0, "ULJM05054"}}, // dialogue: 0x886162c (x1), 0x889d5fc-0x889d520(a2) fullLine + {0x8899e90, {0, 0, 0, ULJM05054, 0, "ULJM05054"}}, // name 0x88da57c, 0x8899ca4 (x0, oneTime), 0x8899e90 + // Sol Trigger + {0x8952cfc, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // dialog + {0x884aad4, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // description + {0x882e1b0, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // system + {0x88bb108, {CODEC_UTF8, 2, 0, 0, NPJH50619F, "NPJH50619"}}, // battle tutorial + {0x89526a0, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // battle info + {0x88bcef8, {CODEC_UTF8, 1, 0, 0, NPJH50619F, "NPJH50619"}}, // battle talk + // Fate/EXTRA CCC + {0x8958490, {0, 0, 0, 0, NPJH50505F, "NPJH50505"}}, + // Kamigami no Asobi InFinite + {0x088630f8, {0, 0, 0, QNPJH50909, 0, "NPJH50909"}}, // text, choice (debounce trailing 400ms), TODO: better hook + {0x0887813c, {0, 3, 4, 0, 0, "NPJH50909"}}, // Question YN + // Gekka Ryouran Romance + {0x88eeba4, {0, 0, 0, 0, ULJM05943F, "ULJM05943"}}, // a0 - monologue text + {0x8875e0c, {0, 1, 6, 0, ULJM05943F, "ULJM05943"}}, // a1 - dialogue text + // My Merry May with be + {0x886F014, {0, 3, 0, 0, FULJM05603, "ULJM05603"}}, + // Corpse Party -The Anthology- Sachiko no Ren'ai Yuugi ♥ Hysteric Birthday 2U - Regular Edition + {0x88517C8, {0, 1, 0, 0, FULJM05603, "ULJM06114"}}, + // Himawari_no_Kyoukai_to_Nagai_Natsuyasumi_Extra_Vacation_JPN_PSP-MOEMOE + {0x881c444, {FULL_STRING, 0, 0, 0, 0, "ULJM06321"}}, // name+text,sjit,FULL_STRING to split name and text + // ましろ色シンフォニー *mutsu-no-hana + {0x8868AB8, {0, 0, 0, 0, FULJM05889, "ULJM05889"}}, + // シャイニング・ブレイド + {0x8AA3B70, {0, 0xC, 0, 0, NPJH50530::T, "NPJH50530"}}, // text only + {0x884DB44, {0, 1, 0, 0, NPJH50530::N, "NPJH50530"}}, // text+name + // ティアーズ・トゥ・ティアラ 外伝 アヴァロンの謎 PORTABLE + {0x890A4BC, {CODEC_UTF16, 1, 0, 0, FNPJH50243, "NPJH50243"}}, + // 薔薇ノ木ニ薔薇ノ花咲ク + {0x881E560, {0, 1, 0, 0, 0, "ULJM05802"}}, + }; -void QNPJH50909(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ - uintptr_t addr = PPSSPP::emu_addr(stack,0x08975110); - *data=addr+0x20; - *len=*(DWORD*)(addr+0x14)*2; - - if(0x6e87==*(WORD*)*data)*len=0; - if(0x000a==*(WORD*)*data)*len=0; -} -std::unordered_mapemfunctionhooks= { - //Shinigami to Shoujo - {0x883bf34,{0,1,0,0,ULJS00403_filter,"ULJS00403"}}, - //Amagami - {0x0886775c,{0,0,0,ULJS00339,0,"ULJS00339"}},// String.length() - //Sekai de Ichiban Dame na Koi - {0x8814adc,{0,0,0,0,NPJH50909_filter,"ULJM05878"}},// name + dialouge - {0x8850b2c,{0,0,0,0,NPJH50909_filter,"ULJM05878"}},// onscreen toast - //Dunamis15 - {0x0891D72C,{CODEC_UTF8,0,0,0,ULJM06119_filter,"ULJM06119"}}, - //Princess Evangile Portable - {0x88506d0,{CODEC_UTF16,2,0,0,ULJM06036_filter,"ULJM06036"}},// [0x88506d0(2)...0x088507C0(?)] // name text text (line doubled) - //Kin'iro no Corda 2f - {0x89b59dc,{0,0,0,ULJM05428,0,"ULJM05428"}}, - //Kin'iro no Corda - {0x886162c,{0,0,0,ULJM05054,0,"ULJM05054"}},// dialogue: 0x886162c (x1), 0x889d5fc-0x889d520(a2) fullLine - {0x8899e90,{0,0,0,ULJM05054,0,"ULJM05054"}},// name 0x88da57c, 0x8899ca4 (x0, oneTime), 0x8899e90 - //Sol Trigger - {0x8952cfc,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//dialog - {0x884aad4,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//description - {0x882e1b0,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//system - {0x88bb108,{CODEC_UTF8,2,0,0,NPJH50619F,"NPJH50619"}},//battle tutorial - {0x89526a0,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//battle info - {0x88bcef8,{CODEC_UTF8,1,0,0,NPJH50619F,"NPJH50619"}},//battle talk - //Fate/EXTRA CCC - {0x8958490,{0,0,0,0,NPJH50505F,"NPJH50505"}}, - //Kamigami no Asobi InFinite - {0x088630f8,{0,0,0,QNPJH50909,0,"NPJH50909"}}, // text, choice (debounce trailing 400ms), TODO: better hook - {0x0887813c,{0,3,4,0,0,"NPJH50909"}}, // Question YN - //Gekka Ryouran Romance - {0x88eeba4,{0,0,0,0,ULJM05943F,"ULJM05943"}},// a0 - monologue text - {0x8875e0c,{0,1,6,0,ULJM05943F,"ULJM05943"}},// a1 - dialogue text - //My Merry May with be - {0x886F014,{0,3,0,0,FULJM05603,"ULJM05603"}}, - //Corpse Party -The Anthology- Sachiko no Ren'ai Yuugi ♥ Hysteric Birthday 2U - Regular Edition - {0x88517C8,{0,1,0,0,FULJM05603,"ULJM06114"}}, - //Himawari_no_Kyoukai_to_Nagai_Natsuyasumi_Extra_Vacation_JPN_PSP-MOEMOE - {0x881c444,{FULL_STRING,0,0,0,0,"ULJM06321"}},//name+text,sjit,FULL_STRING to split name and text - //ましろ色シンフォニー *mutsu-no-hana - {0x8868AB8,{0,0,0,0,FULJM05889,"ULJM05889"}}, - //シャイニング・ブレイド - {0x8AA3B70,{0,0xC,0,0,NPJH50530::T,"NPJH50530"}},//text only - {0x884DB44,{0,1,0,0,NPJH50530::N,"NPJH50530"}},//text+name -}; - } \ No newline at end of file diff --git a/LunaHook/hookfinder.cc b/LunaHook/hookfinder.cc index 6e7105c..fb7aad1 100644 --- a/LunaHook/hookfinder.cc +++ b/LunaHook/hookfinder.cc @@ -222,7 +222,6 @@ void SafeSendJitVeh(hook_stack *stack, uintptr_t address, uintptr_t em_addr, JIT } } std::unordered_map addresscalledtime; -bool safeautoleaveveh = false; bool SendJitVeh(PCONTEXT context, uintptr_t address, uintptr_t em_addr, JITTYPE jittype) { if (safeautoleaveveh) @@ -295,7 +294,7 @@ void SearchForHooks_Return() if (!records[i].em_addr) continue; hp.emu_addr = records[i].em_addr; - hp.type = CODEC_UTF16 | USING_STRING | BREAK_POINT; + hp.type = CODEC_UTF16 | USING_STRING | BREAK_POINT | NO_CONTEXT; hp.argidx = records[i].argidx; } NotifyHookFound(hp, (wchar_t *)records[i].text); diff --git a/LunaHook/main.cc b/LunaHook/main.cc index 4ce5718..d5a8cf5 100644 --- a/LunaHook/main.cc +++ b/LunaHook/main.cc @@ -101,6 +101,15 @@ void ConsoleOutput(LPCSTR text, ...) vsnprintf(buffer.message, MESSAGE_SIZE, text, args); WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr); } + +void WarningOutput(LPCSTR text, ...) +{ + WarningNotif buffer; + va_list args; + va_start(args, text); + vsnprintf(buffer.message, MESSAGE_SIZE, text, args); + WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr); +} Synchronized> modulecache; std::wstring &querymodule(uintptr_t addr) { diff --git a/LunaHook/main.h b/LunaHook/main.h index ca8998a..80c9a31 100644 --- a/LunaHook/main.h +++ b/LunaHook/main.h @@ -6,6 +6,7 @@ void TextOutput(const ThreadParam &tp, const HookParam &hp, TextOutput_T(*buffer), int len); void ConsoleOutput(LPCSTR text, ...); +void WarningOutput(LPCSTR text, ...); void NotifyHookFound(HookParam hp, wchar_t *text); void NotifyHookRemove(uint64_t addr, LPCSTR name); bool NewHook(HookParam hp, LPCSTR name); @@ -27,6 +28,6 @@ void context_set(hook_stack *, PCONTEXT); inline std::map> delayinserthook; void delayinsertadd(HookParam, std::string); void delayinsertNewHook(uintptr_t); - +inline bool safeautoleaveveh = false; inline bool dont_detach = false; inline bool host_connected = false; \ No newline at end of file diff --git a/LunaHook/texthook.cc b/LunaHook/texthook.cc index 72b3742..1ad6607 100644 --- a/LunaHook/texthook.cc +++ b/LunaHook/texthook.cc @@ -127,7 +127,13 @@ bool TextHook::Insert(HookParam hp) if (hp.type & DIRECT_READ) return InsertReadCode(); if (hp.type & BREAK_POINT) - return InsertBreakPoint(); + { + if (InsertBreakPoint()) + return true; + if (safeautoleaveveh) + return InsertBreakPoint(); // 搜索特殊码后,不会释放,导致virtualprotect查询失败,重试。 + return false; + } return InsertHookCode(); } uintptr_t win64find0000(uintptr_t addr) diff --git a/LunaHost/GUI/LunaHost.cpp b/LunaHost/GUI/LunaHost.cpp index b71373b..6c70c82 100644 --- a/LunaHost/GUI/LunaHost.cpp +++ b/LunaHost/GUI/LunaHost.cpp @@ -292,12 +292,16 @@ LunaHost::LunaHost() hooksearchwindow->show(); }; - Host::Start( + Host::StartEx( std::bind(&LunaHost::on_proc_connect, this, std::placeholders::_1), std::bind(&LunaHost::on_proc_disconnect, this, std::placeholders::_1), std::bind(&LunaHost::on_thread_create, this, std::placeholders::_1), std::bind(&LunaHost::on_thread_delete, this, std::placeholders::_1), - std::bind(&LunaHost::on_text_recv, this, std::placeholders::_1, std::placeholders::_2)); + std::bind(&LunaHost::on_text_recv, this, std::placeholders::_1, std::placeholders::_2), + {}, + {}, + {}, + std::bind(&LunaHost::on_warning, this, std::placeholders::_1)); mainlayout = new gridlayout(); mainlayout->addcontrol(g_selectprocessbutton, 0, 0); @@ -448,6 +452,10 @@ bool LunaHost::on_text_recv(TextThread &thread, std::wstring &output) } return true; } +void LunaHost::on_warning(const std::wstring &warning) +{ + MessageBoxW(winId, warning.c_str(), L"warning", 0); +} void LunaHost::on_thread_create(TextThread &thread) { wchar_t buff[65535]; diff --git a/LunaHost/GUI/LunaHost.h b/LunaHost/GUI/LunaHost.h index 641125a..d17c4f5 100644 --- a/LunaHost/GUI/LunaHost.h +++ b/LunaHost/GUI/LunaHost.h @@ -116,6 +116,7 @@ class LunaHost : public mainwindow void on_thread_delete(TextThread &thread); void on_proc_connect(DWORD pid); void on_proc_disconnect(DWORD pid); + void on_warning(const std::wstring &); void showtext(const std::wstring &text, bool clear); void updatelisttext(const std::wstring &text, LONG_PTR data); diff --git a/LunaHost/GUI/pluginmanager.cpp b/LunaHost/GUI/pluginmanager.cpp index 04520b1..590ca26 100644 --- a/LunaHost/GUI/pluginmanager.cpp +++ b/LunaHost/GUI/pluginmanager.cpp @@ -464,7 +464,7 @@ std::array Pluginmanager::GetSentenceInfo(TextThread &thre static DWORD SelectedProcessId; auto currthread = (TextThread *)host->currentselect; SelectedProcessId = (currthread != 0) ? currthread->tp.processId : 0; - DWORD (*GetSelectedProcessId) + DWORD(*GetSelectedProcessId) () = [] { return SelectedProcessId; }; diff --git a/LunaHost/GUI/pluginmanager.h b/LunaHost/GUI/pluginmanager.h index d8c781d..db5c00e 100644 --- a/LunaHost/GUI/pluginmanager.h +++ b/LunaHost/GUI/pluginmanager.h @@ -35,7 +35,7 @@ struct plugindata VisSetting_t VisSetting; HMODULE hmodule; void clear(); - plugindata(){}; + plugindata() {}; plugindata(const std::wstring &, Pluginmanager *, bool, HMODULE); bool valid(); void initstatus(const pluginitem &); diff --git a/LunaHost/LunaHostCLI.cpp b/LunaHost/LunaHostCLI.cpp index c6cbadf..fce452e 100644 --- a/LunaHost/LunaHostCLI.cpp +++ b/LunaHost/LunaHostCLI.cpp @@ -2,15 +2,14 @@ #include #include - int main() { _setmode(_fileno(stdout), _O_U16TEXT); _setmode(_fileno(stdin), _O_U16TEXT); wprintf_s(L"Usage: {'attach'|'detach'|hookcode} -Pprocessid\n"); fflush(stdout); - Host::Start([](auto) {}, [](auto) {}, [](auto&) {}, [](auto&) {}, [](TextThread& thread, std::wstring& output) - { + Host::Start([](auto) {}, [](auto) {}, [](auto &) {}, [](auto &) {}, [](TextThread &thread, std::wstring &output) + { wprintf_s(L"[%I64X:%I32X:%I64X:%I64X:%I64X:%s:%s] %s\n", thread.handle, thread.tp.processId, @@ -22,53 +21,67 @@ int main() output.c_str() ); fflush(stdout); - return false; - }); + return false; }); wchar_t input[500] = {}; SearchParam sp = {}; sp.codepage = Host::defaultCodepage; sp.length = 0; while (fgetws(input, 500, stdin)) { - if(wcslen(input)<=1)continue;//\r\n,第二行会直接只有一个\n + if (wcslen(input) <= 1) + continue; //\r\n,第二行会直接只有一个\n wchar_t command[500] = {}; DWORD processId = 0; int split; - for (split = wcslen(input) - 1; split >= 1; split--) { - if (input[split] == L'P' && input[split-1]=='-') { + for (split = wcslen(input) - 1; split >= 1; split--) + { + if (input[split] == L'P' && input[split - 1] == '-') + { processId = _wtoi(input + split + 1); break; } } - if (split == 1)continue;// ExitProcess(0); + if (split == 1) + continue; // ExitProcess(0); split -= 2; - while (split > 0 && input[split] == L' ')split -= 1; - if (split == 0)continue;//ExitProcess(0); + while (split > 0 && input[split] == L' ') + split -= 1; + if (split == 0) + continue; // ExitProcess(0); input[split + 1] = 0; wcscpy(command, input); - //if (swscanf(input, L"%500s -P%d", command, &processId) != 2) ExitProcess(0); - if (_wcsicmp(command, L"attach") == 0) Host::InjectProcess(processId); - else if (_wcsicmp(command, L"detach") == 0) { Host::DetachProcess(processId); } - else if (_wcsicmp(command, L"find") == 0) { + // if (swscanf(input, L"%500s -P%d", command, &processId) != 2) ExitProcess(0); + if (_wcsicmp(command, L"attach") == 0) + Host::InjectProcess(processId); + else if (_wcsicmp(command, L"detach") == 0) + { + Host::DetachProcess(processId); + } + else if (_wcsicmp(command, L"find") == 0) + { std::shared_ptr> hooks = std::make_shared>(); try { Host::FindHooks(processId, sp, - [hooks](HookParam hp, std::wstring text) { - //if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]"))) { - if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]"))) { - hooks->push_back(std::wstring(hp.hookcode) + L"=>" + text + L"\n"); + [hooks](HookParam hp, std::wstring text) + { + // if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]"))) { + if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]"))) + { + hooks->push_back(std::wstring(hp.hookcode) + L"=>" + text + L"\n"); - - // *hooks << sanitize(S(HookCode::Generate(hp) + L" => " + text)); - } - }); + // *hooks << sanitize(S(HookCode::Generate(hp) + L" => " + text)); + } + }); + } + catch (wchar_t c) + { + std::wcout << c; } - catch (wchar_t c) { std::wcout << c; } std::thread([hooks] - { + { for (int lastSize = 0; hooks->size() == 0 || hooks->size() != lastSize; Sleep(2000)) lastSize = hooks->size(); FILE* out = fopen("hook.txt", "a+,ccs=UTF-8"); @@ -76,34 +89,40 @@ int main() fwrite(hook.c_str(), wcslen(hook.c_str()) * sizeof(wchar_t), 1, out); } - fclose(out); - }).detach(); - + fclose(out); }) + .detach(); } - else { - if (command[0] == L'-') { + else + { + if (command[0] == L'-') + { try { unsigned long long address; swscanf_s(command, L"-%llu", &address); Host::RemoveHook(processId, address); - } - catch (std::out_of_range) {} + catch (std::out_of_range) + { + } } - else if (command[0] == L'=') { + else if (command[0] == L'=') + { int codepage; swscanf_s(command, L"=%d", &codepage); Host::defaultCodepage = codepage; } - else if (command[0] == L'+') { + else if (command[0] == L'+') + { int flushDelay; swscanf_s(command, L"+%d", &flushDelay); TextThread::flushDelay = flushDelay; } - else if (auto hp = HookCode::Parse(command)) Host::InsertHook(processId, hp.value()); - else ExitProcess(0); + else if (auto hp = HookCode::Parse(command)) + Host::InsertHook(processId, hp.value()); + else + ExitProcess(0); } } ExitProcess(0); diff --git a/LunaHost/LunaHostDll.cpp b/LunaHost/LunaHostDll.cpp index 29ba8dd..14dbf26 100644 --- a/LunaHost/LunaHostDll.cpp +++ b/LunaHost/LunaHostDll.cpp @@ -26,7 +26,7 @@ typedef void (*EmbedCallback)(const wchar_t *, ThreadParam); wchar_t hookcode[HOOKCODE_LEN]; \ wcscpy_s(hookcode, HOOKCODE_LEN, thread.hp.hookcode); \ strcpy_s(name, HOOK_NAME_SIZE, thread.hp.name); -C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, ThreadEvent Create, ThreadEvent Destroy, OutputCallback Output, ConsoleHandler console, HookInsertHandler hookinsert, EmbedCallback embed) +C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, ThreadEvent Create, ThreadEvent Destroy, OutputCallback Output, ConsoleHandler console, HookInsertHandler hookinsert, EmbedCallback embed, ConsoleHandler Warning) { Host::StartEx( Connect, @@ -56,6 +56,10 @@ C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, Thread [=](const std::wstring &output, const ThreadParam &tp) { embed(output.c_str(), tp); + }, + [=](const std::wstring &output) + { + Warning(output.c_str()); }); } C_LUNA_API void Luna_Inject(DWORD pid, LPCWSTR basepath) diff --git a/LunaHost/host.cpp b/LunaHost/host.cpp index 0de8010..88977c9 100644 --- a/LunaHost/host.cpp +++ b/LunaHost/host.cpp @@ -1,20 +1,19 @@ #include "host.h" typedef LONG NTSTATUS; -#include"yapi.hpp" -#include"Lang/Lang.h" +#include "yapi.hpp" +#include "Lang/Lang.h" namespace { class ProcessRecord { public: - ProcessRecord(DWORD processId, HANDLE pipe) : - pipe(pipe), - mappedFile2(OpenFileMappingW(FILE_MAP_READ|FILE_MAP_WRITE, FALSE, (EMBED_SHARED_MEM + std::to_wstring(processId)).c_str())), - viewMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId)) - - { - embedsharedmem=(EmbedSharedMem*)MapViewOfFile(mappedFile2, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(EmbedSharedMem)); - //放到构造表里就不行,不知道为何。 + ProcessRecord(DWORD processId, HANDLE pipe) : pipe(pipe), + mappedFile2(OpenFileMappingW(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, (EMBED_SHARED_MEM + std::to_wstring(processId)).c_str())), + viewMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId)) + + { + embedsharedmem = (EmbedSharedMem *)MapViewOfFile(mappedFile2, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(EmbedSharedMem)); + // 放到构造表里就不行,不知道为何。 } ~ProcessRecord() @@ -27,18 +26,17 @@ namespace { static_assert(sizeof(data) < PIPE_BUFFER_SIZE); std::thread([=] - { - WriteFile(pipe, &data, sizeof(data), DUMMY, nullptr); - }).detach(); + { WriteFile(pipe, &data, sizeof(data), DUMMY, nullptr); }) + .detach(); } Host::HookEventHandler OnHookFound = [](HookParam hp, std::wstring text) { Host::AddConsoleOutput(std::wstring(hp.hookcode) + L": " + text); }; - - + EmbedSharedMem *embedsharedmem; + private: HANDLE pipe; AutoHandle<> mappedFile2; @@ -51,13 +49,16 @@ namespace Host::ProcessEventHandler OnConnect, OnDisconnect; Host::ThreadEventHandler OnCreate, OnDestroy; - Host::ConsoleHandler OnConsole=0; - Host::HookInsertHandler HookInsert=0; - Host::EmbedCallback embedcallback=0; + Host::ConsoleHandler OnConsole = 0; + Host::ConsoleHandler OnWarning = 0; + Host::HookInsertHandler HookInsert = 0; + Host::EmbedCallback embedcallback = 0; void RemoveThreads(std::function removeIf) { - std::vector threadsToRemove; - for (auto& [tp, thread] : textThreadsByParams.Acquire().contents) if (removeIf(tp)) threadsToRemove.push_back(&thread); + std::vector threadsToRemove; + for (auto &[tp, thread] : textThreadsByParams.Acquire().contents) + if (removeIf(tp)) + threadsToRemove.push_back(&thread); for (auto thread : threadsToRemove) { OnDestroy(*thread); @@ -76,14 +77,14 @@ namespace void CreatePipe(int pid) { HANDLE - hookPipe = CreateNamedPipeW((std::wstring(HOOK_PIPE)+std::to_wstring(pid)).c_str(), PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, 0, PIPE_BUFFER_SIZE, MAXDWORD, &allAccess), - hostPipe = CreateNamedPipeW((std::wstring(HOST_PIPE)+std::to_wstring(pid)).c_str(), PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, 0, MAXDWORD, &allAccess); - HANDLE pipeAvailableEvent = CreateEventW(&allAccess, FALSE, FALSE, (std::wstring(PIPE_AVAILABLE_EVENT)+std::to_wstring(pid)).c_str()); + hookPipe = CreateNamedPipeW((std::wstring(HOOK_PIPE) + std::to_wstring(pid)).c_str(), PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, 0, PIPE_BUFFER_SIZE, MAXDWORD, &allAccess), + hostPipe = CreateNamedPipeW((std::wstring(HOST_PIPE) + std::to_wstring(pid)).c_str(), PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, 0, MAXDWORD, &allAccess); + HANDLE pipeAvailableEvent = CreateEventW(&allAccess, FALSE, FALSE, (std::wstring(PIPE_AVAILABLE_EVENT) + std::to_wstring(pid)).c_str()); - Host::AddConsoleOutput((std::wstring(PIPE_AVAILABLE_EVENT)+std::to_wstring(pid))); + Host::AddConsoleOutput((std::wstring(PIPE_AVAILABLE_EVENT) + std::to_wstring(pid))); SetEvent(pipeAvailableEvent); - std::thread([hookPipe,hostPipe,pipeAvailableEvent] - { + std::thread([hookPipe, hostPipe, pipeAvailableEvent] + { ConnectNamedPipe(hookPipe, nullptr); CloseHandle(pipeAvailableEvent); BYTE buffer[PIPE_BUFFER_SIZE] = {}; @@ -141,6 +142,12 @@ namespace Host::AddConsoleOutput(StringToWideString(info.message)); } break; + case HOST_NOTIFICATION_WARNING: + { + auto info = *(WarningNotif*)buffer; + Host::Warning(StringToWideString(info.message)); + } + break; default: { auto data=(TextOutput_T*)buffer; @@ -179,8 +186,8 @@ namespace RemoveThreads([&](ThreadParam tp) { return tp.processId == processId; }); OnDisconnect(processId); Host::AddConsoleOutput(FormatString(PROC_DISCONN,processId)); - processRecordsByIds->erase(processId); - }).detach(); + processRecordsByIds->erase(processId); }) + .detach(); } } @@ -189,156 +196,200 @@ namespace Host std::mutex threadmutex; std::mutex outputmutex; std::mutex procmutex; - void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,bool createconsole) + void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, bool createconsole) { - OnConnect = [=](auto &&...args){std::lock_guard _(procmutex);Connect(std::forward(args)...);}; - OnDisconnect = [=](auto &&...args){std::lock_guard _(procmutex);Disconnect(std::forward(args)...);}; - OnCreate = [=](TextThread& thread) {{std::lock_guard _(threadmutex); Create(thread);} thread.Start(); }; - OnDestroy = [=](TextThread& thread) {thread.Stop(); {std::lock_guard _(threadmutex); Destroy(thread);} }; - TextThread::Output = [=](auto &&...args){std::lock_guard _(outputmutex);return Output(std::forward(args)...);}; + OnConnect = [=](auto &&...args) + {std::lock_guard _(procmutex);Connect(std::forward(args)...); }; + OnDisconnect = [=](auto &&...args) + {std::lock_guard _(procmutex);Disconnect(std::forward(args)...); }; + OnCreate = [=](TextThread &thread) + {{std::lock_guard _(threadmutex); Create(thread);} thread.Start(); }; + OnDestroy = [=](TextThread &thread) + {thread.Stop(); {std::lock_guard _(threadmutex); Destroy(thread);} }; + TextThread::Output = [=](auto &&...args) + {std::lock_guard _(outputmutex);return Output(std::forward(args)...); }; - if(createconsole){ - OnCreate(textThreadsByParams->try_emplace(console, console, HookParam{} ,CONSOLE ).first->second); + if (createconsole) + { + OnCreate(textThreadsByParams->try_emplace(console, console, HookParam{}, CONSOLE).first->second); Host::AddConsoleOutput(ProjectHomePage); } - //CreatePipe(); - + // CreatePipe(); } - void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,ConsoleHandler console,HookInsertHandler hookinsert,EmbedCallback embed){ - Start(Connect,Disconnect,Create,Destroy,Output,false); - - OnConsole=[=](auto &&...args){std::lock_guard _(outputmutex);console(std::forward(args)...);}; - HookInsert=[=](auto &&...args){std::lock_guard _(threadmutex);hookinsert(std::forward(args)...);}; - embedcallback=[=](auto &&...args){std::lock_guard _(outputmutex);embed(std::forward(args)...);}; + void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, std::optional console, std::optional hookinsert, std::optional embed, std::optional warning) + { + Start(Connect, Disconnect, Create, Destroy, Output, !console.has_value()); + if (warning.has_value()) + OnWarning = warning.value(); + if (console.has_value()) + OnConsole = [=](auto &&...args) + {std::lock_guard _(outputmutex);console.value()(std::forward(args)...); }; + if (hookinsert.has_value()) + HookInsert = [=](auto &&...args) + {std::lock_guard _(threadmutex);hookinsert.value()(std::forward(args)...); }; + if (embed.has_value()) + embedcallback = [=](auto &&...args) + {std::lock_guard _(outputmutex);embed.value()(std::forward(args)...); }; } - constexpr auto PROCESS_INJECT_ACCESS=( - PROCESS_CREATE_THREAD | - PROCESS_QUERY_INFORMATION | - PROCESS_VM_OPERATION | - PROCESS_VM_WRITE | - PROCESS_VM_READ); - bool SafeInject(HANDLE process,const std::wstring &location){ -//#ifdef _WIN64 + constexpr auto PROCESS_INJECT_ACCESS = (PROCESS_CREATE_THREAD | + PROCESS_QUERY_INFORMATION | + PROCESS_VM_OPERATION | + PROCESS_VM_WRITE | + PROCESS_VM_READ); + bool SafeInject(HANDLE process, const std::wstring &location) + { +// #ifdef _WIN64 #if 0 BOOL invalidProcess = FALSE; IsWow64Process(process, &invalidProcess); if (invalidProcess) return AddConsoleOutput(NEED_32_BIT); #endif - bool succ=false; - if (LPVOID remoteData = VirtualAllocEx(process, nullptr, (location.size() + 1) * sizeof(wchar_t), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) + bool succ = false; + if (LPVOID remoteData = VirtualAllocEx(process, nullptr, (location.size() + 1) * sizeof(wchar_t), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) + { + WriteProcessMemory(process, remoteData, location.c_str(), (location.size() + 1) * sizeof(wchar_t), nullptr); + if (AutoHandle<> thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr)) { - WriteProcessMemory(process, remoteData, location.c_str(), (location.size() + 1) * sizeof(wchar_t), nullptr); - if (AutoHandle<> thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr)){ - WaitForSingleObject(thread, INFINITE); - succ=true; - } - else if (GetLastError() == ERROR_ACCESS_DENIED){ - AddConsoleOutput(NEED_64_BIT); // https://stackoverflow.com/questions/16091141/createremotethread-access-denied - succ=false; - } - VirtualFreeEx(process, remoteData, 0, MEM_RELEASE); - + WaitForSingleObject(thread, INFINITE); + succ = true; } - return succ; + else if (GetLastError() == ERROR_ACCESS_DENIED) + { + AddConsoleOutput(NEED_64_BIT); // https://stackoverflow.com/questions/16091141/createremotethread-access-denied + succ = false; + } + VirtualFreeEx(process, remoteData, 0, MEM_RELEASE); + } + return succ; } - bool UnSafeInject(HANDLE process,const std::wstring &location){ - + bool UnSafeInject(HANDLE process, const std::wstring &location) + { + DWORD64 injectedDll; yapi::YAPICall LoadLibraryW(process, _T("kernel32.dll"), "LoadLibraryW"); - if(x64)injectedDll = LoadLibraryW.Dw64()(location.c_str()); - else injectedDll = LoadLibraryW(location.c_str()); - if(injectedDll)return true; - return false; - + if (x64) + injectedDll = LoadLibraryW.Dw64()(location.c_str()); + else + injectedDll = LoadLibraryW(location.c_str()); + if (injectedDll) + return true; + return false; } - bool CheckProcess(DWORD processId){ - if (processId == GetCurrentProcessId()) return false; + bool CheckProcess(DWORD processId) + { + if (processId == GetCurrentProcessId()) + return false; WinMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId)); - if (GetLastError() == ERROR_ALREADY_EXISTS){AddConsoleOutput(ALREADY_INJECTED); return false;} + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + AddConsoleOutput(ALREADY_INJECTED); + return false; + } return true; } - bool InjectDll(DWORD processId,const std::wstring locationX){ + bool InjectDll(DWORD processId, const std::wstring locationX) + { AutoHandle<> process = OpenProcess(PROCESS_INJECT_ACCESS, FALSE, processId); - if(!process)return false; - bool proc64=Is64BitProcess(process); - auto dllname=proc64?LUNA_HOOK_DLL_64:LUNA_HOOK_DLL_32; - std::wstring location =locationX.size()?(locationX+L"\\"+dllname): std::filesystem::path(getModuleFilename().value()).replace_filename(dllname); + if (!process) + return false; + bool proc64 = Is64BitProcess(process); + auto dllname = proc64 ? LUNA_HOOK_DLL_64 : LUNA_HOOK_DLL_32; + std::wstring location = locationX.size() ? (locationX + L"\\" + dllname) : std::filesystem::path(getModuleFilename().value()).replace_filename(dllname); AddConsoleOutput(location); - if(proc64==x64){ - return (SafeInject(process,location)); + if (proc64 == x64) + { + return (SafeInject(process, location)); + } + else + { + return (UnSafeInject(process, location)); } - else{ - return (UnSafeInject(process,location)); - } } - bool CreatePipeAndCheck(DWORD processId){ + bool CreatePipeAndCheck(DWORD processId) + { CreatePipe(processId); return CheckProcess(processId); } - void InjectProcess(DWORD processId,const std::wstring locationX) + void InjectProcess(DWORD processId, const std::wstring locationX) { - - auto check=CreatePipeAndCheck(processId); - if(check==false)return; + + auto check = CreatePipeAndCheck(processId); + if (check == false) + return; std::thread([=] - { + { if(InjectDll(processId,locationX))return ; - AddConsoleOutput(INJECT_FAILED); - }).detach(); + AddConsoleOutput(INJECT_FAILED); }) + .detach(); } void DetachProcess(DWORD processId) { - auto &prs=processRecordsByIds.Acquire().contents; - if(prs.find(processId)==prs.end())return; + auto &prs = processRecordsByIds.Acquire().contents; + if (prs.find(processId) == prs.end()) + return; prs.at(processId).Send(HOST_COMMAND_DETACH); } void InsertHook(DWORD processId, HookParam hp) { - auto &prs=processRecordsByIds.Acquire().contents; - if(prs.find(processId)==prs.end())return; + auto &prs = processRecordsByIds.Acquire().contents; + if (prs.find(processId) == prs.end()) + return; prs.at(processId).Send(InsertHookCmd(hp)); } void RemoveHook(DWORD processId, uint64_t address) { - auto &prs=processRecordsByIds.Acquire().contents; - if(prs.find(processId)==prs.end())return; + auto &prs = processRecordsByIds.Acquire().contents; + if (prs.find(processId) == prs.end()) + return; prs.at(processId).Send(RemoveHookCmd(address)); } void FindHooks(DWORD processId, SearchParam sp, HookEventHandler HookFound) { - auto &prs=processRecordsByIds.Acquire().contents; - if(prs.find(processId)==prs.end())return; - if (HookFound) prs.at(processId).OnHookFound = HookFound; + auto &prs = processRecordsByIds.Acquire().contents; + if (prs.find(processId) == prs.end()) + return; + if (HookFound) + prs.at(processId).OnHookFound = HookFound; prs.at(processId).Send(FindHookCmd(sp)); } - TextThread& GetThread(ThreadParam tp) + TextThread &GetThread(ThreadParam tp) { return textThreadsByParams->at(tp); } - TextThread* GetThread(int64_t handle) + TextThread *GetThread(int64_t handle) { - for (auto& [tp, thread] : textThreadsByParams.Acquire().contents) if (thread.handle == handle) return &thread; - return nullptr; + for (auto &[tp, thread] : textThreadsByParams.Acquire().contents) + if (thread.handle == handle) + return &thread; + return nullptr; } - EmbedSharedMem* GetEmbedSharedMem(DWORD processId){ - auto &prs=processRecordsByIds.Acquire().contents; - if(prs.find(processId)==prs.end())return 0; + EmbedSharedMem *GetEmbedSharedMem(DWORD processId) + { + auto &prs = processRecordsByIds.Acquire().contents; + if (prs.find(processId) == prs.end()) + return 0; return prs.at(processId).embedsharedmem; } void AddConsoleOutput(std::wstring text) { - if(OnConsole) + if (OnConsole) OnConsole(std::move(text)); else GetThread(console).AddSentence(std::move(text)); } + void Warning(std::wstring text) + { + if (OnWarning) + OnWarning(text); + AddConsoleOutput(L"[Warning] " + text); + } } diff --git a/LunaHost/host.h b/LunaHost/host.h index 093cba8..3b53e4f 100644 --- a/LunaHost/host.h +++ b/LunaHost/host.h @@ -3,15 +3,15 @@ #include "textthread.h" namespace Host { - using ConsoleHandler =std::function; + using ConsoleHandler = std::function; using ProcessEventHandler = std::function; - using ThreadEventHandler = std::function; - using HookEventHandler = std::function; - using HookInsertHandler= std::function; - using EmbedCallback= std::function; - void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,bool createconsole=true); - void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,ConsoleHandler console,HookInsertHandler hookinsert,EmbedCallback embed); - void InjectProcess(DWORD processId,const std::wstring locationX=L""); + using ThreadEventHandler = std::function; + using HookEventHandler = std::function; + using HookInsertHandler = std::function; + using EmbedCallback = std::function; + void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, bool createconsole = true); + void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, std::optional console, std::optional hookinsert, std::optional embed, std::optional warning); + void InjectProcess(DWORD processId, const std::wstring locationX = L""); bool CreatePipeAndCheck(DWORD processId); void DetachProcess(DWORD processId); @@ -19,13 +19,14 @@ namespace Host void InsertHook(DWORD processId, HookParam hp); void RemoveHook(DWORD processId, uint64_t address); void FindHooks(DWORD processId, SearchParam sp, HookEventHandler HookFound = {}); - EmbedSharedMem* GetEmbedSharedMem(DWORD pid); - TextThread* GetThread(int64_t handle); - TextThread& GetThread(ThreadParam tp); + EmbedSharedMem *GetEmbedSharedMem(DWORD pid); + TextThread *GetThread(int64_t handle); + TextThread &GetThread(ThreadParam tp); void AddConsoleOutput(std::wstring text); + void Warning(std::wstring text); inline int defaultCodepage = SHIFT_JIS; - constexpr ThreadParam console{ 0, 0, 0, 0 }; + constexpr ThreadParam console{0, 0, 0, 0}; } diff --git a/LunaHost/textthread.cpp b/LunaHost/textthread.cpp index af5292e..5eceb97 100644 --- a/LunaHost/textthread.cpp +++ b/LunaHost/textthread.cpp @@ -1,27 +1,28 @@ #include "textthread.h" #include "host.h" -#include"Lang/Lang.h" +#include "Lang/Lang.h" // return true if repetition found (see https://github.com/Artikash/Textractor/issues/40) -static bool RemoveRepetition(std::wstring& text) +static bool RemoveRepetition(std::wstring &text) { - wchar_t* end = text.data() + text.size(); + wchar_t *end = text.data() + text.size(); for (int length = text.size() / 3; length > 6; --length) if (memcmp(end - length * 3, end - length * 2, length * sizeof(wchar_t)) == 0 && memcmp(end - length * 3, end - length * 1, length * sizeof(wchar_t)) == 0) return RemoveRepetition(text = std::wstring(end - length, length)), true; return false; } -TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional name) : - handle(threadCounter++), - name(name.value_or(StringToWideString(hp.name))), - tp(tp), - hp(hp) -{} +TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional name) : handle(threadCounter++), + name(name.value_or(StringToWideString(hp.name))), + tp(tp), + hp(hp) +{ +} void TextThread::Start() { - CreateTimerQueueTimer(&timer, NULL, [](void* This, auto) { ((TextThread*)This)->Flush(); }, this, 10, 10, WT_EXECUTELONGFUNCTION); + CreateTimerQueueTimer(&timer, NULL, [](void *This, auto) + { ((TextThread *)This)->Flush(); }, this, 10, 10, WT_EXECUTELONGFUNCTION); } void TextThread::Stop() @@ -34,9 +35,10 @@ void TextThread::AddSentence(std::wstring sentence) queuedSentences->emplace_back(std::move(sentence)); } -void TextThread::Push(BYTE* data, int length) +void TextThread::Push(BYTE *data, int length) { - if (length < 0) return; + if (length < 0) + return; std::scoped_lock lock(bufferMutex); BYTE doubleByteChar[2]; @@ -56,19 +58,23 @@ void TextThread::Push(BYTE* data, int length) length = 0; } } - auto converted = commonparsestring(data,length,&hp,Host::defaultCodepage); - if(converted) + auto converted = commonparsestring(data, length, &hp, Host::defaultCodepage); + if (converted) { buffer.append(converted.value()); - if (hp.type & FULL_STRING && converted.value().size()>1) buffer.push_back(L'\n'); + if (hp.type & FULL_STRING && converted.value().size() > 1) + buffer.push_back(L'\n'); } - else Host::AddConsoleOutput(INVALID_CODEPAGE); + else + Host::AddConsoleOutput(INVALID_CODEPAGE); lastPushTime = GetTickCount64(); - + if (filterRepetition) { - if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t ch) { return repeatingChars.find(ch) != repeatingChars.end(); })) buffer.clear(); + if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t ch) + { return repeatingChars.find(ch) != repeatingChars.end(); })) + buffer.clear(); if (RemoveRepetition(buffer)) // sentence repetition detected, which means the entire sentence has already been received { repeatingChars = std::unordered_set(buffer.begin(), buffer.end()); @@ -84,7 +90,7 @@ void TextThread::Push(BYTE* data, int length) } } -void TextThread::Push(const wchar_t* data) +void TextThread::Push(const wchar_t *data) { std::scoped_lock lock(bufferMutex); // not sure if this should filter repetition @@ -96,21 +102,24 @@ void TextThread::Flush() { { auto storage = this->storage.Acquire(); - if (storage->size() > maxHistorySize) storage->erase(0, storage->size() - maxHistorySize); // https://github.com/Artikash/Textractor/issues/127#issuecomment-486882983 + if (storage->size() > maxHistorySize) + storage->erase(0, storage->size() - maxHistorySize); // https://github.com/Artikash/Textractor/issues/127#issuecomment-486882983 } std::vector sentences; queuedSentences->swap(sentences); int totalSize = 0; - for (auto& sentence : sentences) + for (auto &sentence : sentences) { totalSize += sentence.size(); sentence.erase(std::remove(sentence.begin(), sentence.end(), 0), sentence.end()); - if (Output(*this, sentence)) storage->append(sentence+L"\n"); + if (Output(*this, sentence)) + storage->append(sentence + L"\n"); } std::scoped_lock lock(bufferMutex); - if (buffer.empty()) return; + if (buffer.empty()) + return; if (buffer.size() > maxBufferSize || GetTickCount64() - lastPushTime > flushDelay) { AddSentence(std::move(buffer)); diff --git a/LunaHost/textthread.h b/LunaHost/textthread.h index dcc0b27..9cb829e 100644 --- a/LunaHost/textthread.h +++ b/LunaHost/textthread.h @@ -1,14 +1,13 @@ #pragma once - class TextThread { public: - using OutputCallback = std::function; + using OutputCallback = std::function; inline static OutputCallback Output; inline static bool filterRepetition = false; - inline static int flushDelay = 100; + inline static int flushDelay = 100; inline static int maxBufferSize = 3000; inline static int maxHistorySize = 10'000'000; @@ -17,8 +16,8 @@ public: void Start(); void Stop(); void AddSentence(std::wstring sentence); - void Push(BYTE* data, int length); - void Push(const wchar_t* data); + void Push(BYTE *data, int length); + void Push(const wchar_t *data); Synchronized storage; const int64_t handle; @@ -37,6 +36,9 @@ private: std::mutex bufferMutex; DWORD64 lastPushTime = 0; Synchronized> queuedSentences; - struct TimerDeleter { void operator()(HANDLE h) { DeleteTimerQueueTimer(NULL, h, INVALID_HANDLE_VALUE); } }; + struct TimerDeleter + { + void operator()(HANDLE h) { DeleteTimerQueueTimer(NULL, h, INVALID_HANDLE_VALUE); } + }; AutoHandle timer = NULL; }; diff --git a/include/const.h b/include/const.h index 476b189..3031e4a 100644 --- a/include/const.h +++ b/include/const.h @@ -38,7 +38,8 @@ enum HostNotificationType HOST_NOTIFICATION_FOUND_HOOK, HOST_NOTIFICATION_RMVHOOK, HOST_NOTIFICATION_INSERTING_HOOK, - HOST_SETTEXTTHREADTYPE + HOST_SETTEXTTHREADTYPE, + HOST_NOTIFICATION_WARNING }; #define NEXT_MASK(x) \ DUMMY1_##x, \ diff --git a/include/types.h b/include/types.h index cb96d58..0ffff47 100644 --- a/include/types.h +++ b/include/types.h @@ -183,6 +183,12 @@ struct ConsoleOutputNotif // From dll HostNotificationType command = HOST_NOTIFICATION_TEXT; char message[MESSAGE_SIZE] = {}; }; +struct WarningNotif // From dll +{ + WarningNotif(std::string message = "") { strncpy_s(this->message, message.c_str(), MESSAGE_SIZE - 1); } + HostNotificationType command = HOST_NOTIFICATION_WARNING; + char message[MESSAGE_SIZE] = {}; +}; struct HookFoundNotif // From dll {