From a963692d0225b1da57094418f687beb57b48f771 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: Fri, 11 Oct 2024 18:42:53 +0800
Subject: [PATCH] some
---
Lang/en.h | 2 +-
Lang/ru.h | 2 +-
Lang/zh.h | 2 +-
LunaHook/engine64/vita3k.cpp | 10 ++
LunaHook/engine64/yuzu.cpp | 146 +++++++++++++-----
LunaHook/engines/emujitarg.hpp | 180 +++++++++++++----------
LunaHook/engines/ppsspp/specialgames.hpp | 8 +
LunaHook/hookfinder.cc | 2 +-
LunaHook/texthook.cc | 2 +-
LunaHost/LunaHostDll.cpp | 2 +-
10 files changed, 242 insertions(+), 114 deletions(-)
diff --git a/Lang/en.h b/Lang/en.h
index 9c64b2a..dd1dcc9 100644
--- a/Lang/en.h
+++ b/Lang/en.h
@@ -35,7 +35,7 @@
#define ProcessRange "hijacking process located from 0x%p to 0x%p"
#define WarningDummy "WARNING injected process is very small, possibly a dummy!"
#define WndSelectProcess L"SelectProcess"
-#define WndLunaHostGui L"LunaHost Gui"
+#define WndLunaHostGui L"LunaHost GUI"
#define WndSetting L"Setting"
#define WndPlugins L"Plugins"
#define NotifyInvalidHookCode L"Invalid HookCode"
diff --git a/Lang/ru.h b/Lang/ru.h
index 8414cd0..05f5215 100644
--- a/Lang/ru.h
+++ b/Lang/ru.h
@@ -35,7 +35,7 @@
#define ProcessRange u8"Перехват процесса в диапазоне адресов с 0x%p по 0x%p"
#define WarningDummy u8"ПРЕДУПРЕЖДЕНИЕ: внедренный процесс очень мал, возможно, это пустышка!"
#define WndSelectProcess L"Выбор процесса"
-#define WndLunaHostGui L"LunaHost - Gui"
+#define WndLunaHostGui L"LunaHost - GUI"
#define WndSetting L"Настройки"
#define WndPlugins L"Плагины"
#define NotifyInvalidHookCode L"Неверный код хука"
diff --git a/Lang/zh.h b/Lang/zh.h
index 8911ad0..bf25179 100644
--- a/Lang/zh.h
+++ b/Lang/zh.h
@@ -35,7 +35,7 @@
#define ProcessRange u8"获取到进程内存地址范围 0x%p 到 0x%p"
#define WarningDummy u8"警告,注入的进程内存很小,可能是无用进程!"
#define WndSelectProcess L"选择进程"
-#define WndLunaHostGui L"LunaHost Gui"
+#define WndLunaHostGui L"LunaHost GUI"
#define WndSetting L"设置"
#define WndPlugins L"插件"
#define NotifyInvalidHookCode L"特殊码无效"
diff --git a/LunaHook/engine64/vita3k.cpp b/LunaHook/engine64/vita3k.cpp
index 42bbdbb..86e70fa 100644
--- a/LunaHook/engine64/vita3k.cpp
+++ b/LunaHook/engine64/vita3k.cpp
@@ -389,6 +389,13 @@ namespace
s = std::regex_replace(s, std::regex(R"(#\w+(\[.+?\])?)"), "");
return write_string_overwrite(data, len, s);
}
+ bool FPCSG00815(void *data, size_t *len, HookParam *hp)
+ {
+ auto s = std::string((char *)data, *len);
+ 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);
@@ -559,6 +566,9 @@ namespace
{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"}},
+ // PsychicEmotion6 (サイキックエモーション ムー)
+ {0x80035948, {CODEC_UTF8, 9, 0, 0, FPCSG00815, "PCSG00815"}},
+ {0x80034580, {CODEC_UTF8, 6, 0, 0, FPCSG00815, "PCSG00815"}},
};
return 1;
}();
diff --git a/LunaHook/engine64/yuzu.cpp b/LunaHook/engine64/yuzu.cpp
index 55500a3..7060952 100644
--- a/LunaHook/engine64/yuzu.cpp
+++ b/LunaHook/engine64/yuzu.cpp
@@ -178,7 +178,9 @@ bool yuzu::attach_function()
HookParam hpinternal;
hpinternal.address = entrypoint;
hpinternal.emu_addr = em_address; // 用于生成hcode
- hpinternal.type = USING_STRING | NO_CONTEXT | BREAK_POINT | op.type;
+ hpinternal.type = NO_CONTEXT | BREAK_POINT | op.type;
+ if (!(op.type & USING_CHAR))
+ hpinternal.type |= USING_STRING;
hpinternal.text_fun = (decltype(hpinternal.text_fun))op.hookfunc;
hpinternal.filter_fun = (decltype(hpinternal.filter_fun))op.filterfun;
hpinternal.argidx = op.argidx;
@@ -720,6 +722,11 @@ namespace
return true;
}
+ bool F01006CC015ECA000(void *data, size_t *len, HookParam *hp)
+ {
+ StringCharReplacer((wchar_t *)data, len, L"#
", 5, L'\n');
+ return true;
+ }
bool F0100925014864000(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
@@ -751,7 +758,7 @@ namespace
;
else
{
- s += (wchar_t)c + (wchar_t) * (uint16_t *)(address + 1);
+ s += c;
}
address += 4;
}
@@ -1130,6 +1137,13 @@ namespace
s = WideStringToString(ws, 932);
return write_string_overwrite(data, len, s);
}
+ bool F01005A401D766000(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"(\|(.*?)\|(.*?)\|)"), "$1");
+ return write_string_overwrite(data, len, s);
+ }
bool F010027300A660000(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
@@ -1169,16 +1183,27 @@ namespace
s = std::regex_replace(s, closingBraceRegex, L"");
if (choice)
{
- std::wregex whitespaceRegex(L"\\s| ");
+ std::wregex whitespaceRegex(LR"([^\S\n]| )");
s = std::regex_replace(s, whitespaceRegex, L"");
}
else
{
- std::wregex whitespaceRegex(LR"([^\S\n]| )");
+ std::wregex whitespaceRegex(L"\\s| ");
s = std::regex_replace(s, whitespaceRegex, L"");
}
return write_string_overwrite(data, len, s);
}
+ bool F010027401A2A2000_2(void *data, size_t *len, HookParam *hp)
+ {
+ auto s = std::wstring((wchar_t *)data, *len / 2);
+ static std::wstring last;
+ auto x = endWith(last, s);
+ last = s;
+ if (x)
+ return false;
+ return F010027401A2A2000(data, len, hp);
+ }
+
bool F0100BD4014D8C000(void *data, size_t *len, HookParam *hp)
{
auto s = std::wstring((wchar_t *)data, *len / 2);
@@ -1312,7 +1337,7 @@ namespace
}
void T0100B5500CA0C000(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
- auto address = YUZU::emu_arg(stack)[6];
+ auto address = YUZU::emu_arg(stack, hp->emu_addr)[6];
*data = address;
*len = *(WORD *)(address - 2);
}
@@ -1705,7 +1730,7 @@ namespace
bool F0100FC2019346000(void *data, size_t *len, HookParam *hp)
{
- StringReplacer((char *)data, len, "#n", 2, " ", 1);
+ StringFilter((char *)data, len, "#n", 2);
return true;
}
@@ -1723,6 +1748,11 @@ namespace
s = std::regex_replace(s, std::regex("\\n+"), " ");
return write_string_overwrite(data, len, s);
}
+ bool F010076501DAEA000(void *data, size_t *len, HookParam *hp)
+ {
+ StringFilter((char *)data, len, "\\n", 2);
+ return true;
+ }
bool F01005E9016BDE000(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
@@ -1858,6 +1888,31 @@ namespace
s += L"\n";
return write_string_overwrite(data, len, s);
}
+ namespace
+ {
+#pragma optimize("", off)
+ // 必须禁止优化这个函数,或者引用一下参数,否则参数被优化没了。
+ void F01006530151F0000_collect(const wchar_t *_) {}
+#pragma optimize("", on)
+ bool F01006530151F0000(void *data, size_t *len, HookParam *)
+ {
+ auto s = std::wstring((wchar_t *)data, *len / 2);
+ strReplace(s, L"/player", L"");
+ HookParam hp;
+ hp.address = (uintptr_t)F01006530151F0000_collect;
+ hp.offset = GETARG1;
+ hp.type = CODEC_UTF16 | USING_STRING;
+ static auto _ = NewHook(hp, "01006530151F0000");
+ F01006530151F0000_collect(s.c_str());
+ return false;
+ }
+ }
+ bool F010043901E972000(void *data, size_t *len, HookParam *hp)
+ {
+ auto s = std::wstring((wchar_t *)data, *len / 2);
+ strReplace(s, L"
", L"\n");
+ return write_string_overwrite(data, len, s);
+ }
bool wF0100A9B01D4AE000(void *data, size_t *len, HookParam *hp)
{
auto s = std::wstring((wchar_t *)data, *len / 2);
@@ -2062,12 +2117,11 @@ namespace
{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
+ // 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
@@ -2146,7 +2200,7 @@ namespace
// 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
+ {0x21cb08, {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
@@ -2217,8 +2271,6 @@ namespace
{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
@@ -2379,6 +2431,10 @@ namespace
// 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
+ // ワンド オブ フォーチュン 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
// ワンド オブ フォーチュン 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
@@ -2425,9 +2481,9 @@ namespace
// 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
+ {0x21801c, {0, 2, 0, 0, F0100F7401AA74000, "0100F7401AA74000", "1.0.0"}}, // text,sjis
+ {0x228fac, {0, 1, 0, 0, F0100F7401AA74000, "0100F7401AA74000", "1.0.0"}}, // choices
+ {0x267f24, {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
@@ -2476,10 +2532,6 @@ namespace
{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)
@@ -2588,6 +2640,9 @@ namespace
{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
+ // 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"}},
// 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~)
@@ -2607,7 +2662,9 @@ namespace
{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"}},
+ {0x2509ac, {CODEC_UTF8, 0, 0, T0100B5500CA0C000, F0100B5500CA0C000, "01008DE00C022000", "1.0.0"}},
+ // Hanayaka Nari, Waga Ichizoku Gentou Nostalgie
+ {0x27ca10, {CODEC_UTF8, 0, 0, T0100B5500CA0C000, F0100B5500CA0C000, "0100B5500CA0C000", "1.0.0"}}, // x3 (double trigged), name+text, onscreen
// 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
@@ -2635,8 +2692,8 @@ namespace
{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
+ {0x20dbfc, {0, 0, 0x28, 0, F010028D0148E6000, "010028D0148E6000", "1.2.0"}}, // dialog, sjis
+ {0x214978, {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
@@ -2770,7 +2827,7 @@ namespace
{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
+ {0x48b268, {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
@@ -2812,10 +2869,11 @@ namespace
{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
+ // 泡沫のユークロニア 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
+ {0x81836E0C, {CODEC_UTF16, 1, 0, 0, F010027401A2A2000_2, "010027401A2A2000", "1.0.1"}},
// Little Busters! Converted Edition
{0x800A97C8, {CODEC_UTF8, 9, 0, 0, F0100943010310000, "0100943010310000", "1.0.0"}},
// GrimGrimoire OnceMore
@@ -2823,7 +2881,7 @@ namespace
{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"}},
+ {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
@@ -2903,9 +2961,6 @@ namespace
{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"}},
@@ -2924,13 +2979,13 @@ namespace
{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"}},
+ {0x219ed0, {0, 0, 0, 0, F0100E4000F616000, "0100E4000F616000", "1.0.0"}},
+ {0x21a3e0, {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"}},
+ {0x20d7b8, {0, 0, 0, 0, F0100E4000F616000, "0100F8D0129F4000", "1.0.0"}},
+ {0x20da9c, {0, 0, 0, 0, F0100E4000F616000, "0100E4000F616000", "1.0.0"}},
+ {0x20d834, {0, 0, 0, 0, F0100E4000F616000, "0100F8D0129F4000", "1.0.1"}},
+ {0x20dae8, {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"}},
@@ -2960,6 +3015,31 @@ namespace
// Hatsumira -From the Future Undying-
{0x8017BE0C, {CODEC_UTF8, 8, 0, 0, aF0100A9B01D4AE000, "0100A9B01D4AE000", "1.0.0"}}, // 英文
{0x8017C0B4, {CODEC_UTF16, 8, 0, 0, wF0100A9B01D4AE000, "0100A9B01D4AE000", "1.0.0"}}, // 日文
+ // Meiji Tokyo Renka Full Moon
+ {0x81898840, {CODEC_UTF16, 3, 0, 0, F010043901E972000, "010043901E972000", "1.0.0"}}, // 日文
+ // 月影の鎖~狂爛モラトリアム~
+ {0x2170B4, {0, 1, 0, 0, F010076501DAEA000, "010076501DAEA000", "1.0.0"}}, // text
+ {0x2179A8, {0, 2, 0, 0, 0, "010076501DAEA000", "1.0.0"}}, // name+text
+ // 神々の悪戯 Unite Edition
+ {0x812BFF40, {CODEC_UTF16, 1, -2, 0, F01006530151F0000, "01006530151F0000", "1.0.0"}}, // 只有第一行
+ {0x812BCEB8, {CODEC_UTF16, 1, -2, 0, F01006530151F0000, "01006530151F0000", "1.0.0"}}, // 只有2&3行
+ // 新宿羅生門 ―Rashomon of Shinjuku―
+ {0x80062158, {CODEC_UTF8, 0, 0, 0, F01005A401D766000, "01005A401D766000", "1.0.0"}},
+ // 夏空のモノローグ ~Another Memory~
+ {0x8005D8D0, {0, 1, 0, 0, F0100FC2019346000, "01000E701DAE8000", "1.0.0"}},
+ // 真紅の焔 真田忍法帳 for Nintendo Switch
+ {0x80021E10, {CODEC_UTF8, 2, 0, 0, 0, "01008A001C79A000", "1.0.0"}},
+ // 神さまと恋ゴコロ
+ {0x20D838, {0, 7, 0, 0, 0, "0100612019F12000", "1.0.0"}}, // name+text
+ {0x20D030, {0, 1, 0, 0, 0, "0100612019F12000", "1.0.0"}},
+ // KLAP!! for Nintendo Switch
+ {0x8001C6F0, {CODEC_UTF8, 2, 0, 0, 0, "0100E8E016D82000", "1.0.0"}},
+ // PSYCHIC ECLIPSE -reload-
+ {0x8091B41C, {CODEC_UTF8, 8, 0, 0, 0, "0100A0001B9F0000", "1.0.0"}}, // 提取不到短字符串
+ {0x804FAF5C, {CODEC_UTF8 | FULL_STRING, 1, 0, 0, 0, "0100A0001B9F0000", "1.1.0"}}, // 提取不到短字符串 text+name
+ {0x80887ABC, {CODEC_UTF8, 8, 0, 0, 0, "0100A0001B9F0000", "1.1.0"}}, // 提取不到短字符串
+ // アイ★チュウ
+ {0x824865C4, {CODEC_UTF16, 3, 0, 0, F01006CC015ECA000, "01006CC015ECA000", "1.14"}},
};
return 1;
}();
diff --git a/LunaHook/engines/emujitarg.hpp b/LunaHook/engines/emujitarg.hpp
index 5e541d6..0f892f3 100644
--- a/LunaHook/engines/emujitarg.hpp
+++ b/LunaHook/engines/emujitarg.hpp
@@ -2,89 +2,119 @@
#ifdef _WIN64
namespace RPCS3
{
-class emu_arg{
- hook_stack* stack;
-public:
- emu_arg(hook_stack* stack_):stack(stack_){};
- uintptr_t operator [](int idx){
- auto base=stack->rbx;
- auto args=(uintptr_t*)(stack->rbp+0x18+8*3);
- return base+args[idx];
- }
-};
+ class emu_arg
+ {
+ hook_stack *stack;
+
+ public:
+ emu_arg(hook_stack *stack_) : stack(stack_) {};
+ uintptr_t operator[](int idx)
+ {
+ auto base = stack->rbx;
+ auto args = (uintptr_t *)(stack->rbp + 0x18 + 8 * 3);
+ return base + args[idx];
+ }
+ };
}
namespace YUZU
{
-class emu_arg{
- hook_stack* stack;
-public:
- emu_arg(hook_stack* stack_):stack(stack_){};
- uintptr_t operator [](int idx){
- auto base=stack->r13;
- auto args=(uintptr_t*)stack->r15;
- return base+args[idx];
- }
-};
+ class emu_arg
+ {
+ hook_stack *stack;
+ bool is64;
+
+ public:
+ emu_arg(hook_stack *stack_, uintptr_t em_addr = 0) : stack(stack_), is64(em_addr == 0 || em_addr > 0x80004000) {};
+ uintptr_t operator[](int idx)
+ {
+ auto base = stack->r13;
+ if (is64)
+ {
+ auto args = (uintptr_t *)stack->r15;
+ return base + args[idx];
+ }
+ else
+ {
+ // 0x204000
+ auto args = (DWORD *)stack->r15;
+ return base + args[idx];
+ }
+ }
+ };
}
namespace VITA3K
{
-class emu_addr{
- hook_stack* stack;
- DWORD addr;
-public:
- emu_addr(hook_stack* stack_,DWORD addr_):stack(stack_),addr(addr_){};
- operator uintptr_t(){
- auto base=stack->r13;
- return base+addr;
- }
- operator DWORD*(){
- return (DWORD*)(uintptr_t)*this;
- }
-};
-class emu_arg{
- hook_stack* stack;
-public:
- emu_arg(hook_stack* stack_):stack(stack_){};
- uintptr_t operator [](int idx){
- auto args=(uint32_t*)stack->r15;
- return emu_addr(stack,args[idx]);
- }
-};
+ class emu_addr
+ {
+ hook_stack *stack;
+ DWORD addr;
+
+ public:
+ emu_addr(hook_stack *stack_, DWORD addr_) : stack(stack_), addr(addr_) {};
+ operator uintptr_t()
+ {
+ auto base = stack->r13;
+ return base + addr;
+ }
+ operator DWORD *()
+ {
+ return (DWORD *)(uintptr_t) * this;
+ }
+ };
+ class emu_arg
+ {
+ hook_stack *stack;
+
+ public:
+ emu_arg(hook_stack *stack_) : stack(stack_) {};
+ uintptr_t operator[](int idx)
+ {
+ auto args = (uint32_t *)stack->r15;
+ return emu_addr(stack, args[idx]);
+ }
+ };
}
#endif
-namespace PPSSPP{
+namespace PPSSPP
+{
inline DWORD x86_baseaddr;
-class emu_addr{
- hook_stack* stack;
- DWORD addr;
-public:
- emu_addr(hook_stack* stack_,DWORD addr_):stack(stack_),addr(addr_){};
- operator uintptr_t(){
- #ifndef _WIN64
- auto base=x86_baseaddr;
- #else
- auto base=stack->rbx;
- #endif
- return base+addr;
- }
- operator DWORD*(){
- return (DWORD*)(uintptr_t)*this;
- }
-};
-class emu_arg{
- hook_stack* stack;
-public:
+ class emu_addr
+ {
+ hook_stack *stack;
+ DWORD addr;
- emu_arg(hook_stack* stack_):stack(stack_){};
- uintptr_t operator [](int idx){
- #ifndef _WIN64
- auto args=stack->ebp;
- #else
- auto args=stack->r14;
- #endif
- auto offR = -0x80;
- auto offset = offR + 0x10 + idx * 4;
- return (uintptr_t)emu_addr(stack,*(uint32_t*)(args+offset));
- }
-};
+ public:
+ emu_addr(hook_stack *stack_, DWORD addr_) : stack(stack_), addr(addr_) {};
+ operator uintptr_t()
+ {
+#ifndef _WIN64
+ auto base = x86_baseaddr;
+#else
+ auto base = stack->rbx;
+#endif
+ return base + addr;
+ }
+ operator DWORD *()
+ {
+ return (DWORD *)(uintptr_t) * this;
+ }
+ };
+ class emu_arg
+ {
+ hook_stack *stack;
+
+ public:
+ emu_arg(hook_stack *stack_) : stack(stack_) {};
+ uintptr_t operator[](int idx)
+ {
+#ifndef _WIN64
+ auto args = stack->ebp;
+#else
+ auto args = stack->r14;
+#endif
+ auto offR = -0x80;
+ auto offset = offR + 0x10 + idx * 4;
+ return (uintptr_t)emu_addr(stack, *(uint32_t *)(args + offset));
+ }
+ };
}
\ No newline at end of file
diff --git a/LunaHook/engines/ppsspp/specialgames.hpp b/LunaHook/engines/ppsspp/specialgames.hpp
index 7147d02..9fa9a2f 100644
--- a/LunaHook/engines/ppsspp/specialgames.hpp
+++ b/LunaHook/engines/ppsspp/specialgames.hpp
@@ -257,6 +257,11 @@ namespace ppsspp
strReplace(s, "\n\r\n", "\n");
return write_string_overwrite(data, len, s);
}
+ bool FNPJH50127(void *data, size_t *len, HookParam *hp)
+ {
+ StringCharReplacer((char *)data, len, "\\n", 2, '\n');
+ return true;
+ }
bool FULJM05690(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
@@ -400,6 +405,9 @@ namespace ppsspp
{0x8889CCC, {CODEC_UTF8, 1, 0, 0, FNPJH50459, "NPJH50716"}}, // 会有两三条后续文本都被一次性提取到。
// マイナスエイト
{0x88DC218, {0, 0, 0, 0, FULJM05690, "ULJM06341"}},
+ // Tokimeki Memorial 4
+ {0x899a510, {0, 2, 0, 0, FNPJH50127, "NPJH50127"}},
+ {0x88719dc, {0, 1, 0, 0, FNPJH50127, "NPJH50127"}},
};
}
\ No newline at end of file
diff --git a/LunaHook/hookfinder.cc b/LunaHook/hookfinder.cc
index fb7aad1..23cc775 100644
--- a/LunaHook/hookfinder.cc
+++ b/LunaHook/hookfinder.cc
@@ -199,7 +199,7 @@ void SafeSendJitVeh(hook_stack *stack, uintptr_t address, uintptr_t em_addr, JIT
{
#ifdef _WIN64
case JITTYPE::YUZU:
- str = (char *)YUZU::emu_arg(stack)[i];
+ str = (char *)YUZU::emu_arg(stack, em_addr)[i];
break;
case JITTYPE::VITA3K:
str = (char *)VITA3K::emu_arg(stack)[i];
diff --git a/LunaHook/texthook.cc b/LunaHook/texthook.cc
index 1ad6607..c366465 100644
--- a/LunaHook/texthook.cc
+++ b/LunaHook/texthook.cc
@@ -190,7 +190,7 @@ uintptr_t jitgetaddr(hook_stack *stack, HookParam *hp)
case JITTYPE::VITA3K:
return VITA3K::emu_arg(stack)[hp->argidx];
case JITTYPE::YUZU:
- return YUZU::emu_arg(stack)[hp->argidx];
+ return YUZU::emu_arg(stack, hp->emu_addr)[hp->argidx];
#endif
case JITTYPE::PPSSPP:
return PPSSPP::emu_arg(stack)[hp->argidx];
diff --git a/LunaHost/LunaHostDll.cpp b/LunaHost/LunaHostDll.cpp
index cdf0c68..58e230e 100644
--- a/LunaHost/LunaHostDll.cpp
+++ b/LunaHost/LunaHostDll.cpp
@@ -178,7 +178,7 @@ C_LUNA_API void Luna_embedcallback(DWORD pid, LPCWSTR text, LPCWSTR trans)
auto sm = Host::GetEmbedSharedMem(pid);
if (!sm)
return;
- wcscpy_s(sm->text, 1000, trans);
+ wcsncpy(sm->text, trans, ARRAYSIZE(sm->text));
char eventname[1000];
sprintf(eventname, LUNA_EMBED_notify_event, pid, djb2_n2((const unsigned char *)(text), wcslen(text) * 2));
win_event event1(eventname);