This commit is contained in:
恍兮惚兮 2024-11-28 16:59:08 +08:00
parent e12089c21a
commit 0c3949811c
21 changed files with 223 additions and 143 deletions

View File

@ -67,7 +67,7 @@ struct passinfo
};
bool Ryujinx::attach_function()
{
WarningOutput("not support ryuujinx, please use yuzu/sudachi instead.");
HostInfo(HOSTINFO::Warning, "not support ryuujinx, please use yuzu/sudachi instead.");
return true;
/*
UnsafeJitFunction

View File

@ -16,8 +16,6 @@ namespace
}
uintptr_t getDoJitAddress() {
auto DoJitPtr=getDoJitAddress_();
ConsoleOutput("DoJitPtr %p",DoJitPtr);
if(!DoJitPtr)return 0;
//<--DoJitPtr
//0f85 1b050000 // jbe 0x00 ; long jump
@ -242,7 +240,7 @@ bool rpcs3::attach_function()
if (DoJitPtr == 0)
return false;
unsafeinithooks();
spDefault.jittype = JITTYPE::RPCS3;
spDefault.isjithook = true;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
HookParam hp;

View File

@ -63,8 +63,7 @@ bool vita3k::attach_function()
auto DoJitPtr = getDoJitAddress();
if (DoJitPtr == 0)
return false;
ConsoleOutput("DoJitPtr %p", DoJitPtr);
spDefault.jittype = JITTYPE::VITA3K;
spDefault.isjithook = true;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
HookParam hp;

View File

@ -122,13 +122,16 @@ bool Hook_Network_RoomMember_SendGameInfo()
// Network::RoomMember *this,
// const AnnounceMultiplayerRoom::GameInfo *game_info)
game_info = *(GameInfo *)stack->rdx;
if (game_info.id)
{
std::stringstream num;
num << std::uppercase
<< std::hex
<< std::setw(16)
<< std::setfill('0')
<< game_info.id;
ConsoleOutput("%s %s %s", game_info.name.c_str(), num.str().c_str(), game_info.version.c_str());
HostInfo(HOSTINFO::EmuGameName, "%s %s %s", game_info.name.c_str(), num.str().c_str(), game_info.version.c_str());
}
jitaddrclear();
};
return NewHook(hp, "yuzuGameInfo");
@ -137,15 +140,14 @@ bool Hook_Network_RoomMember_SendGameInfo()
}
bool yuzu::attach_function()
{
Hook_Network_RoomMember_SendGameInfo();
ConsoleOutput("[Compatibility] Yuzu 1616+");
auto DoJitPtr = getDoJitAddress();
if (DoJitPtr == 0)
if (!DoJitPtr)
return false;
spDefault.jittype = JITTYPE::YUZU;
Hook_Network_RoomMember_SendGameInfo();
spDefault.isjithook = true;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
ConsoleOutput("DoJitPtr %p", DoJitPtr);
HookParam hp;
hp.address = DoJitPtr;
hp.text_fun = [](hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
@ -310,7 +312,7 @@ namespace
s = std::regex_replace(s, std::regex(R"(#[^\]]*\])"), "");
s = std::regex_replace(s, std::regex(R"(#[^n]*n)"), "");
s = std::regex_replace(s, std::regex(u8" "), "");
s = std::regex_replace(s, std::regex(u8R"(Save(.|\s)*データ)"), "");
s = std::regex_replace(s, std::regex(u8R"(Save[\s\S]*データ)"), "");
buffer->from(s);
}
@ -676,6 +678,16 @@ namespace
strReplace(s, R"(\n)", "");
buffer->from(s);
}
template <int _1>
void F010053F0128DC000(TextBuffer *buffer, HookParam *hp)
{
CharFilter(buffer, '\n');
auto s = buffer->strA();
char __[] = "$1";
__[1] += _1 - 1;
s = std::regex_replace(s, std::regex(R"(<CLY2>(.*?)<CLNA>([\s\S]*))"), __);
buffer->from(s);
}
namespace
{
static std::string F0100FB50156E6000;
@ -1062,7 +1074,7 @@ namespace
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex(R"(\[~\])"), "\n");
s = std::regex_replace(s, std::regex(R"(rom:(.|\s)*$)"), "");
s = std::regex_replace(s, std::regex(R"(rom:[\s\S]*$)"), "");
s = std::regex_replace(s, std::regex(R"(\[[\w\d]*\[[\w\d]*\].*?\[\/[\w\d]*\]\])"), "");
s = std::regex_replace(s, std::regex(R"(\[.*?\])"), "");
static std::string last;
@ -1204,7 +1216,6 @@ namespace
template <bool choice>
void F010027401A2A2000(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strW();
s = std::regex_replace(s, std::wregex(L"\\[dic.*?text="), L"");
s = std::regex_replace(s, std::wregex(L"\\[|'.*?\\]"), L"");
@ -1561,7 +1572,7 @@ namespace
{
auto s = buffer->strW();
s = std::regex_replace(s, std::wregex(LR"((.|\s)*$)"), L"");
s = std::regex_replace(s, std::wregex(LR"([\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"");
@ -3443,6 +3454,11 @@ namespace
// 神凪ノ杜
{0x8205e150, {CODEC_UTF16, 0, 0x14, 0, F0100B5801D7CE000, "0100B5801D7CE000", "1.0.0"}},
{0x820e2e6c, {CODEC_UTF16, 0, 0x14, 0, 0, "0100B5801D7CE000", "1.0.0"}},
// シェルノサージュ ~失われた星へ捧ぐ詩~ DX
{0x801A1140, {CODEC_UTF8, 1, 0, 0, F010053F0128DC000<1>, "010053F0128DC000", "1.0.0"}},
{0x801A10A4, {CODEC_UTF8, 1, 0, 0, F010053F0128DC000<2>, "010053F0128DC000", "1.0.0"}},
{0x801A04F4, {CODEC_UTF8, 1, 0, 0, F010053F0128DC000<1>, "010053F0128DC000", "1.0.1"}},
{0x801A0590, {CODEC_UTF8, 1, 0, 0, F010053F0128DC000<2>, "010053F0128DC000", "1.0.1"}},
};
return 1;

View File

@ -65,7 +65,7 @@ struct PPSSPPFunction
namespace
{
uintptr_t findleapushaddr(uintptr_t addr)
uintptr_t findleapushalignfuncaddr(uintptr_t addr)
{
#ifndef _WIN64
addr = MemDbg::findPushAddress(addr, processStartAddress, processStopAddress);
@ -148,7 +148,7 @@ bool InsertPPSSPPHLEHooks()
auto addr = MemDbg::findBytes(function.pattern, ::strlen(function.pattern), processStartAddress, processStopAddress);
if (!addr)
continue;
addr = findleapushaddr(addr);
addr = findleapushalignfuncaddr(addr);
if (!addr)
continue;
@ -268,13 +268,23 @@ uintptr_t getDoJitAddress()
namespace ppsspp
{
struct GameInfo
{
std::string DISC_ID{""};
std::string TITLE{""};
} game_info;
bool checkiscurrentgame(const emfuncinfo &em)
{
auto wininfos = get_proc_windows();
for (auto &&info : wininfos)
{
if (std::regex_search(info.title, std::wregex(acastw(em._id))))
if (game_info.DISC_ID.size())
{
std::smatch match;
if (std::regex_match(game_info.DISC_ID, match, std::regex(em._id)))
return true;
}
else if (std::regex_search(info.title, std::wregex(acastw(em._id))))
return true;
}
return false;
@ -476,17 +486,61 @@ namespace ppsspp
}
return true;
}
void Load_PSP_ISO_StringFromFormat()
{
/*
bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string) {
// Mounting stuff relocated to InitMemoryForGameISO due to HD Remaster restructuring of code.
std::string sfoPath("disc0:/PSP_GAME/PARAM.SFO");
PSPFileInfo fileInfo = pspFileSystem.GetFileInfo(sfoPath.c_str());
if (fileInfo.exists) {
std::vector<u8> paramsfo;
pspFileSystem.ReadEntireFile(sfoPath, paramsfo);
if (g_paramSFO.ReadSFO(paramsfo)) {
std::string title = StringFromFormat("%s : %s", g_paramSFO.GetValueString("DISC_ID").c_str(), g_paramSFO.GetValueString("TITLE").c_str());
INFO_LOG(Log::Loader, "%s", title.c_str());
System_SetWindowTitle(title);
}
}
------>StringFromFormat
*/
BYTE sig[] = {
#ifndef _WIN64
0x55, 0x8B, 0xEC, 0x6A, 0xFF, 0x68, XX4, 0x64, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x50, 0x64, 0x89, 0x25, 0x00, 0x00, 0x00, 0x00, 0x83, 0xEC, 0x14, 0x56, 0x8B, 0x75, 0x08, 0x0F, 0x57, 0xC0, 0xC7, 0x45, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x46, 0x10, 0x57, 0x89, 0x45, 0xF0, 0x0F, 0x11, 0x06, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x46, 0x14, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x46, 0x14, 0x0F, 0x00, 0x00, 0x00, 0xC6, 0x06, 0x00, 0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x45, 0xE8, 0x01, 0x00, 0x00, 0x00, 0xE8, XX4, 0x8B, 0xC8, 0x8D, 0x45, 0x10, 0x50, 0x6A, 0x00, 0xFF, 0x75, 0x0C, 0x8B, 0x01, 0x6A, 0x00, 0x6A, 0x00, 0xFF, 0x71, 0x04, 0x83, 0xC8, 0x02, 0x89, 0x4D, 0xE0, 0x50, 0xE8, XX4
#else
0x48, 0x8B, 0xC4, 0x48, 0x89, 0x50, 0x10, 0x48, 0x89, 0x48, 0x08, 0x4C, 0x89, 0x40, 0x18, 0x4C, 0x89, 0x48, 0x20, 0x53, 0x55, 0x56, 0x57, 0x41, 0x56, 0x41, 0x57, 0x48, 0x83, 0xEC, 0x48, 0x48, 0x8B, 0xDA, 0x48, 0x8B, 0xF9, 0x33, 0xED, 0x89, 0x68, 0xB8, 0x0F, 0x57, 0xC0, 0x0F, 0x11, 0x01, 0x48, 0x89, 0x69, 0x10, 0x48, 0xC7, 0x41, 0x18, 0x0F, 0x00, 0x00, 0x00, 0x40, 0x88, 0x29, 0xC7, 0x40, 0xB8, 0x01, 0x00, 0x00, 0x00, 0x4C, 0x8D, 0x70, 0x18, 0xE8, XX4, 0x48, 0x8B, 0xF0, 0x48, 0x8B, 0x08, 0x48, 0x83, 0xC9, 0x02, 0x4C, 0x89, 0x74, 0x24, 0x28, 0x48, 0x89, 0x6C, 0x24, 0x20, 0x4C, 0x8B, 0xCB, 0x45, 0x33, 0xC0, 0x33, 0xD2, 0xE8, XX4
#endif
};
auto addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
if (!addr)
return;
HookParam hp;
hp.address = addr;
hp.text_fun = [](hook_stack *stack, HookParam *hp, auto *buff, auto *split)
{
if (strcmp((char *)stack->ARG2, "%s : %s") != 0)
return;
game_info.DISC_ID = (char *)stack->ARG3;
game_info.TITLE = (char *)stack->ARG4;
HostInfo(HOSTINFO::EmuGameName, "%s %s", stack->ARG3, stack->ARG4);
jitaddrclear();
};
NewHook(hp, "PPSSPPGameInfo");
}
bool hookPPSSPPDoJit()
{
auto DoJitPtr = getDoJitAddress();
if (DoJitPtr == 0)
if (!DoJitPtr)
return false;
spDefault.jittype = JITTYPE::PPSSPP;
Load_PSP_ISO_StringFromFormat();
spDefault.isjithook = true;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
HookParam hp;
hp.address = DoJitPtr; // Jit::DoJit
ConsoleOutput("DoJitPtr %p", DoJitPtr);
hp.user_value = (uintptr_t) new uintptr_t;
hp.text_fun = [](hook_stack *stack, HookParam *hp, auto *, auto *)
{
@ -529,7 +583,7 @@ namespace
auto addr = MemDbg::findBytes(GetPointer, sizeof(GetPointer), processStartAddress, processStopAddress);
if (!addr)
return nullptr;
addr = findleapushaddr(addr);
addr = findleapushalignfuncaddr(addr);
return (void *)addr;
}
bool Replace_memcpy()

View File

@ -177,14 +177,6 @@ namespace ppsspp
*split = haveNamve;
buffer->from(s);
}
void ULJM05054(hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
{
auto address = PPSSPP::emu_arg(stack)[1];
bool haveNamve;
auto s = Corda::readBinaryString(address, &haveNamve);
*split = haveNamve;
buffer->from(s);
}
void ULJM05943F(TextBuffer *buffer, HookParam *hp)
{
@ -426,10 +418,12 @@ namespace ppsspp
{0x0891D72C, {CODEC_UTF8, 0, 0, 0, ULJM06119_filter, "ULJM06119"}},
// Princess Evangile
{0x88506d0, {CODEC_UTF16, 2, 0, 0, ULJM06036_filter, "ULJM06036"}}, // [0x88506d0(2)...0x088507C0(?)] // name text text (line doubled)
// 金色のコルダ3
{0x896C3B8, {0, 0, 0, ULJM05428, 0, "ULJM05624"}},
// 金色のコルダ2 f
{0x89b59dc, {0, 0, 0, ULJM05428, 0, "ULJM05428"}},
// 金色のコルダ
{0x886162c, {0, 0, 0, ULJM05054, 0, "ULJM05054"}}, // dialogue: 0x886162c (x1), 0x889d5fc-0x889d520(a2) fullLine
{0x886162c, {0, 0, 0, ULJM05428, 0, "ULJM05054"}}, // dialogue: 0x886162c (x1), 0x889d5fc-0x889d520(a2) fullLine
{0x8899e90, {0, 0, 0x3c, 0, 0, "ULJM05054"}}, // name 0x88da57c, 0x8899ca4 (x0, oneTime), 0x8899e90
// Sol Trigger
{0x8952cfc, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // dialog

View File

@ -335,7 +335,7 @@ void SearchForHooks(SearchParam spUser)
initrecords();
std::vector<uintptr_t> addresses;
if( sp.jittype==JITTYPE::PC)
if( !sp.isjithook)
{
if (*sp.boundaryModule) {
auto [minaddr,maxaddr]=Util::QueryModuleLimits(GetModuleHandleW(sp.boundaryModule));

View File

@ -105,21 +105,12 @@ void TextOutput(const ThreadParam &tp, const HookParam &hp, TextOutput_T *buffer
memcpy(&buffer->hp, &hp, sizeof(hp));
WriteFile(hookPipe, buffer, sizeof(TextOutput_T) + len, DUMMY, nullptr);
}
void ConsoleOutput(LPCSTR text, ...)
void HostInfo(HOSTINFO type, LPCSTR text, ...)
{
ConsoleOutputNotif buffer;
va_list args;
va_start(args, text);
vsnprintf(buffer.message, MESSAGE_SIZE, text, args);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
void WarningOutput(LPCSTR text, ...)
{
WarningNotif buffer;
HostInfoNotif buffer;
va_list args;
va_start(args, text);
buffer.type = type;
vsnprintf(buffer.message, MESSAGE_SIZE, text, args);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}

View File

@ -5,8 +5,8 @@
// Branch: ITH/IHF_DLL.h, rev 66
void TextOutput(const ThreadParam &tp, const HookParam &hp, TextOutput_T(*buffer), int len);
void ConsoleOutput(LPCSTR text, ...);
void WarningOutput(LPCSTR text, ...);
void HostInfo(HOSTINFO type, LPCSTR text, ...);
#define ConsoleOutput(text, ...) HostInfo(HOSTINFO::Console, text, ##__VA_ARGS__, -1)
void NotifyHookFound(HookParam hp, wchar_t *text);
void NotifyHookRemove(uint64_t addr, LPCSTR name);
bool NewHook(HookParam hp, LPCSTR name);
@ -15,7 +15,6 @@ bool NewHookJit(HookParam hp, LPCSTR name);
void RemoveHook(uint64_t addr, int maxOffset = 9);
std::string LoadResData(LPCWSTR pszResID, LPCWSTR _type);
inline SearchParam spDefault;
// EOF
int HookStrLen(HookParam *, BYTE *data);

View File

@ -113,6 +113,7 @@ inline uintptr_t regof(regs reg, hook_stack *stack)
#define ARG1 stack[1]
#define ARG2 stack[2]
#define ARG3 stack[3]
#define ARG4 stack[4]
#define LASTRETVAL eax
#define THISCALL __thiscall
#define THISCALLTHIS ecx
@ -125,6 +126,7 @@ inline uintptr_t regof(regs reg, hook_stack *stack)
#define ARG1 rcx
#define ARG2 rdx
#define ARG3 r8
#define ARG4 r9
#define LASTRETVAL rax
#define THISCALLTHIS rcx
#define THISCALLARG1 rdx

View File

@ -260,10 +260,11 @@ LunaHost::LunaHost()
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),
true,
[=](HOSTINFO type, const std::wstring &output)
{ on_info(type, output); },
{},
{},
{},
std::bind(&LunaHost::on_warning, this, std::placeholders::_1));
{});
mainlayout = new gridlayout();
mainlayout->addcontrol(g_selectprocessbutton, 0, 0);
@ -411,9 +412,14 @@ bool LunaHost::on_text_recv(TextThread &thread, std::wstring &output)
}
return true;
}
void LunaHost::on_warning(const std::wstring &warning)
void LunaHost::on_info(HOSTINFO type, const std::wstring &warning)
{
switch (type)
{
case HOSTINFO::Warning:
MessageBoxW(winId, warning.c_str(), L"warning", 0);
break;
}
}
void LunaHost::on_thread_create(TextThread &thread)
{

View File

@ -116,7 +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 on_info(HOSTINFO type, const std::wstring &);
void showtext(const std::wstring &text, bool clear);
void updatelisttext(const std::wstring &text, LONG_PTR data);

View File

@ -19,7 +19,7 @@ typedef void (*ProcessEvent)(DWORD pid);
typedef void (*ThreadEvent_maybe_embed)(const wchar_t *hookcode, const char *hookname, ThreadParam, bool isembedable);
typedef void (*ThreadEvent)(const wchar_t *hookcode, const char *hookname, ThreadParam);
typedef bool (*OutputCallback)(const wchar_t *hookcode, const char *hookname, ThreadParam, const wchar_t *text);
typedef void (*ConsoleHandler)(const wchar_t *log);
typedef void (*HostInfoHandler)(HOSTINFO type, const wchar_t *log);
typedef void (*HookInsertHandler)(DWORD pid, uint64_t address, const wchar_t *hookcode);
typedef void (*EmbedCallback)(const wchar_t *text, ThreadParam);
typedef void (*findhookcallback_t)(wchar_t *hookcode, const wchar_t *text);
@ -30,7 +30,7 @@ std::optional<T> checkoption(bool check, T &&t)
return std::move(t);
return {};
}
C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, ThreadEvent_maybe_embed Create, ThreadEvent Destroy, OutputCallback Output, ConsoleHandler console, HookInsertHandler hookinsert, EmbedCallback embed, ConsoleHandler Warning)
C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, ThreadEvent_maybe_embed Create, ThreadEvent Destroy, OutputCallback Output, HostInfoHandler hostinfo, HookInsertHandler hookinsert, EmbedCallback embed)
{
Host::StartEx(
checkoption(Connect, std::function<void(DWORD)>(Connect)),
@ -41,14 +41,13 @@ C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, Thread
{ Destroy(thread.hp.hookcode, thread.hp.name, thread.tp); }),
checkoption(Output, [=](const TextThread &thread, std::wstring &output)
{ return Output(thread.hp.hookcode, thread.hp.name, thread.tp, output.c_str()); }),
checkoption(console, [=](const std::wstring &output)
{ console(output.c_str()); }),
false,
checkoption(hostinfo, [=](HOSTINFO type, const std::wstring &output)
{ hostinfo(type, output.c_str()); }),
checkoption(hookinsert, [=](DWORD pid, uint64_t addr, const std::wstring &hookcode)
{ hookinsert(pid, addr, hookcode.c_str()); }),
checkoption(embed, [=](const std::wstring &output, const ThreadParam &tp)
{ embed(output.c_str(), tp); }),
checkoption(Warning, [=](const std::wstring &output)
{ Warning(output.c_str()); }));
{ embed(output.c_str(), tp); }));
}
C_LUNA_API void Luna_Inject(DWORD pid, LPCWSTR basepath)
{

View File

@ -49,8 +49,8 @@ namespace
Host::ProcessEventHandler OnConnect, OnDisconnect;
Host::ThreadEventHandler OnCreate, OnDestroy;
Host::ConsoleHandler OnConsole = 0;
Host::ConsoleHandler OnWarning = 0;
Host::HostInfoHandler OnHostInfo = 0;
bool has_consolethread = false;
Host::HookInsertHandler HookInsert = 0;
Host::EmbedCallback embedcallback = 0;
void RemoveThreads(std::function<bool(ThreadParam)> removeIf)
@ -104,7 +104,7 @@ namespace
WORD hookversion[4];
if( ReadFile(hookPipe, hookversion, sizeof(hookversion), &bytesRead, nullptr)){
if(memcmp(hookversion,LUNA_VERSION,sizeof(hookversion))!=0)
Host::Warning(UNMATCHABLEVERSION);
Host::InfoOutput(HOSTINFO::Warning, UNMATCHABLEVERSION);
}
while (ReadFile(hookPipe, buffer, PIPE_BUFFER_SIZE, &bytesRead, nullptr))
@ -150,14 +150,8 @@ namespace
break;
case HOST_NOTIFICATION_TEXT:
{
auto info = *(ConsoleOutputNotif*)buffer;
Host::AddConsoleOutput(StringToWideString(info.message));
}
break;
case HOST_NOTIFICATION_WARNING:
{
auto info = *(WarningNotif*)buffer;
Host::Warning(StringToWideString(info.message));
auto info = *(HostInfoNotif*)buffer;
Host::InfoOutput(info.type, StringToWideString(info.message));
}
break;
default:
@ -225,20 +219,27 @@ namespace Host
{
OnCreate(textThreadsByParams->try_emplace(console, console, HookParam{}, CONSOLE).first->second);
Host::AddConsoleOutput(ProjectHomePage);
has_consolethread = true;
}
// CreatePipe();
}
void StartEx(std::optional<ProcessEventHandler> Connect, std::optional<ProcessEventHandler> Disconnect, std::optional<ThreadEventHandler> Create, std::optional<ThreadEventHandler> Destroy, std::optional<TextThread::OutputCallback> Output, std::optional<ConsoleHandler> console, std::optional<HookInsertHandler> hookinsert, std::optional<EmbedCallback> embed, std::optional<ConsoleHandler> warning)
void StartEx(std::optional<ProcessEventHandler> Connect,
std::optional<ProcessEventHandler> Disconnect,
std::optional<ThreadEventHandler> Create,
std::optional<ThreadEventHandler> Destroy,
std::optional<TextThread::OutputCallback> Output,
bool consolethread,
std::optional<HostInfoHandler> hostinfo,
std::optional<HookInsertHandler> hookinsert,
std::optional<EmbedCallback> embed)
{
Start(Connect.value_or([](auto) {}), Disconnect.value_or([](auto) {}), Create.value_or([](auto &) {}), Destroy.value_or([](auto &) {}), Output.value_or([](auto &, auto &)
{ return false; }),
!console);
if (warning)
OnWarning = warning.value();
if (console)
OnConsole = [=](auto &&...args)
{std::lock_guard _(outputmutex);console.value()(std::forward<decltype(args)>(args)...); };
consolethread);
if (hostinfo)
OnHostInfo = [=](auto &&...args)
{std::lock_guard _(outputmutex);hostinfo.value()(std::forward<decltype(args)>(args)...); };
if (hookinsert)
HookInsert = [=](auto &&...args)
{std::lock_guard _(threadmutex);hookinsert.value()(std::forward<decltype(args)>(args)...); };
@ -403,16 +404,29 @@ namespace Host
}
void AddConsoleOutput(std::wstring text)
{
if (OnConsole)
OnConsole(std::move(text));
else
GetThread(console).AddSentence(std::move(text));
InfoOutput(HOSTINFO::Console, text);
}
void Warning(std::wstring text)
void InfoOutput(HOSTINFO type, std::wstring text)
{
if (OnWarning)
OnWarning(text);
AddConsoleOutput(L"[Warning] " + text);
if (OnHostInfo)
OnHostInfo(type, std::move(text));
if (has_consolethread || (type != HOSTINFO::Console))
{
switch (type)
{
case HOSTINFO::Warning:
text = L"[Warning] " + text;
break;
case HOSTINFO::EmuGameName:
text = L"[Game] " + text;
break;
}
if (has_consolethread)
GetThread(console).AddSentence(std::move(text));
else if (type != HOSTINFO::Console)
OnHostInfo(HOSTINFO::Console, std::move(text));
}
}
bool CheckIsUsingEmbed(ThreadParam tp)
{

View File

@ -3,14 +3,14 @@
#include "textthread.h"
namespace Host
{
using ConsoleHandler = std::function<void(const std::wstring &)>;
using HostInfoHandler = std::function<void(HOSTINFO type, const std::wstring &)>;
using ProcessEventHandler = std::function<void(DWORD)>;
using ThreadEventHandler = std::function<void(TextThread &)>;
using HookEventHandler = std::function<void(const HookParam &, const std::wstring &text)>;
using HookInsertHandler = std::function<void(DWORD, uint64_t, const std::wstring &)>;
using EmbedCallback = std::function<void(const std::wstring &, const ThreadParam &)>;
void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, bool createconsole = true);
void StartEx(std::optional<ProcessEventHandler> Connect, std::optional<ProcessEventHandler> Disconnect, std::optional<ThreadEventHandler> Create, std::optional<ThreadEventHandler> Destroy, std::optional<TextThread::OutputCallback> Output, std::optional<ConsoleHandler> console, std::optional<HookInsertHandler> hookinsert, std::optional<EmbedCallback> embed, std::optional<ConsoleHandler> warning);
void StartEx(std::optional<ProcessEventHandler> Connect, std::optional<ProcessEventHandler> Disconnect, std::optional<ThreadEventHandler> Create, std::optional<ThreadEventHandler> Destroy, std::optional<TextThread::OutputCallback> Output, bool consolethread, std::optional<HostInfoHandler> hostinfo, std::optional<HookInsertHandler> hookinsert, std::optional<EmbedCallback> embed);
void InjectProcess(DWORD processId, const std::wstring locationX = L"");
bool CreatePipeAndCheck(DWORD processId);
@ -23,9 +23,8 @@ namespace Host
CommonSharedMem *GetCommonSharedMem(DWORD pid);
TextThread *GetThread(int64_t handle);
TextThread &GetThread(ThreadParam tp);
void InfoOutput(HOSTINFO type, std::wstring text);
void AddConsoleOutput(std::wstring text);
void Warning(std::wstring text);
inline int defaultCodepage = SHIFT_JIS;

View File

@ -36,7 +36,12 @@ enum HostNotificationType
HOST_NOTIFICATION_RMVHOOK,
HOST_NOTIFICATION_INSERTING_HOOK,
HOST_SETTEXTTHREADTYPE,
HOST_NOTIFICATION_WARNING
};
enum class HOSTINFO
{
Console,
Warning,
EmuGameName
};
#define NEXT_MASK(x) \
DUMMY1_##x, \

View File

@ -155,7 +155,7 @@ struct SearchParam
wchar_t boundaryModule[MAX_MODULE_SIZE] = {}; // hook all functions within this module (middle priority)
wchar_t exportModule[MAX_MODULE_SIZE] = {}; // hook the exports of this module (highest priority)
wchar_t text[PATTERN_SIZE] = {}; // text to search for
JITTYPE jittype;
bool isjithook;
};
struct InsertPCHooksCmd
{
@ -183,16 +183,11 @@ struct FindHookCmd // From host
SearchParam sp;
};
struct ConsoleOutputNotif // From dll
struct HostInfoNotif // From dll
{
ConsoleOutputNotif(std::string message = "") { strncpy_s(this->message, message.c_str(), MESSAGE_SIZE - 1); }
HostInfoNotif(std::string message = "") { strncpy_s(this->message, message.c_str(), MESSAGE_SIZE - 1); }
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;
HOSTINFO type;
char message[MESSAGE_SIZE] = {};
};

View File

@ -83,13 +83,14 @@ struct ThreadParam
uint64_t ctx; // The context of the hook: by default the first value on stack, usually the return address
uint64_t ctx2; // The subcontext of the hook: 0 by default, generated in a method specific to the hook
};
typedef void (*ProcessEvent)(DWORD);
typedef void (*HookInsertHandler)(DWORD, uint64_t, const wchar_t *);
typedef void (*EmbedCallback)(const wchar_t *, ThreadParam);
typedef void (*ProcessEvent)(DWORD pid);
typedef void (*HookInsertHandler)(DWORD pid, uint64_t address, const wchar_t *hookcode);
typedef void (*EmbedCallback)(const wchar_t *text, ThreadParam);
nlohmann::json config;
std::map<std::string, std::string> translation;
std::unordered_set<DWORD> connectedpids;
void (*Luna_Start)(ProcessEvent Connect, ProcessEvent Disconnect, void *, void *, void *, void *, HookInsertHandler hookinsert, EmbedCallback embed, void *);
void (*Luna_Start)(ProcessEvent Connect, ProcessEvent Disconnect, void *, void *, void *, void *, HookInsertHandler hookinsert, EmbedCallback embed);
void (*Luna_Inject)(DWORD pid, LPCWSTR basepath);
void (*Luna_EmbedSettings)(DWORD pid, UINT32 waittime, UINT8 fontCharSet, bool fontCharSetEnabled, wchar_t *fontFamily, UINT32 keeprawtext, bool fastskipignore);
void (*Luna_useembed)(ThreadParam, bool use);
@ -150,8 +151,7 @@ public:
std::wstring text = output;
auto trans = findtranslation(text);
Luna_embedcallback(tp, output, trans.c_str());
},
0);
});
}
void run()
{

View File

@ -1,7 +1,7 @@
set(VERSION_MAJOR 6)
set(VERSION_MINOR 6)
set(VERSION_PATCH 10)
set(VERSION_MINOR 7)
set(VERSION_PATCH 0)
set(VERSION_REVISION 0)
set(LUNA_VERSION "{${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_REVISION}}")
add_library(VERSION_DEF ${CMAKE_CURRENT_LIST_DIR}/version_def.cpp)

View File

@ -29,6 +29,12 @@ from gui.dynalang import (
)
class HOSTINFO:
Console = 0
Warning = 1
EmuGameName = 2
def getformlayoutw(w=None, cls=LFormLayout, hide=False):
if w is None:
_w = QWidget()
@ -155,7 +161,7 @@ class searchhookparam(LDialog):
usestruct.boundaryModule = dumpvalues["module"][:120]
usestruct.address_method = self.search_addr_range.idx()
usestruct.search_method = self.search_method.idx()
usestruct.jittype = dumpvalues["jittype"]
usestruct.isjithook = bool(dumpvalues["isjithook"])
if self.search_addr_range.idx() == 0:
usestruct.minAddress = self.safehex(
dumpvalues["startaddr"], usestruct.minAddress
@ -336,7 +342,7 @@ class searchhookparam(LDialog):
self.layoutsettings.addRow("搜索方式", _typelayout)
_jitcombo = FocusCombo()
_jitcombo.addItems(["PC", "YUZU", "PPSSPP", "VITA3K", "RPCS3"])
_jitcombo.addItems(["PC", "JIT"])
self.search_method = QButtonGroup_switch_widegt(self)
_jitcombo.currentIndexChanged.connect(
lambda idx: [
@ -344,7 +350,7 @@ class searchhookparam(LDialog):
self.resize(self.width(), 1),
]
)
self.regists["jittype"] = lambda: _jitcombo.currentIndex()
self.regists["isjithook"] = lambda: bool(_jitcombo.currentIndex())
_typelayout.addRow("类型", _jitcombo)
@ -384,11 +390,10 @@ class searchhookparam(LDialog):
class hookselect(closeashidewindow):
addnewhooksignal = pyqtSignal(tuple, bool, bool)
getnewsentencesignal = pyqtSignal(str)
sysmessagesignal = pyqtSignal(str)
sysmessagesignal = pyqtSignal(int, str)
removehooksignal = pyqtSignal(tuple)
getfoundhooksignal = pyqtSignal(dict)
update_item_new_line = pyqtSignal(tuple, str)
warning = pyqtSignal(str)
SaveTextThreadRole = Qt.ItemDataRole.UserRole + 1
@ -402,17 +407,9 @@ class hookselect(closeashidewindow):
self.sysmessagesignal.connect(self.sysmessage)
self.update_item_new_line.connect(self.update_item_new_line_function)
self.getfoundhooksignal.connect(self.getfoundhook)
self.warning.connect(self.warningf)
self.setWindowTitle("选择文本")
self.changeprocessclear()
def warningf(self, text):
getQMessageBox(
self,
"警告",
text,
)
def querykeyofrow(self, row):
if isinstance(row, QModelIndex):
row = row.row()
@ -557,7 +554,9 @@ class hookselect(closeashidewindow):
self.widget = QWidget()
self.setCentralWidget(self.widget)
self.setWindowIcon(qtawesome.icon(globalconfig["toolbutton"]["buttons"]["selecttext"]["icon"]))
self.setWindowIcon(
qtawesome.icon(globalconfig["toolbutton"]["buttons"]["selecttext"]["icon"])
)
self.hboxlayout = QHBoxLayout()
self.widget.setLayout(self.hboxlayout)
self.vboxlayout = QVBoxLayout()
@ -861,11 +860,19 @@ class hookselect(closeashidewindow):
if atBottom:
scrollbar.setValue(scrollbar.maximum())
def sysmessage(self, sentence):
def sysmessage(self, info, sentence):
if info == HOSTINFO.Console:
self.textbrowappendandmovetoend(
self.sysOutput, get_time_stamp() + " " + sentence
)
elif info == HOSTINFO.Warning:
getQMessageBox(
self,
"警告",
sentence,
)
elif info == HOSTINFO.EmuGameName:
gobject.baseobject.displayinfomessage(sentence, "<msg_info_refresh>")
def getnewsentence(self, sentence):
if self.at1 == 2:

View File

@ -85,7 +85,7 @@ class SearchParam(Structure):
("boundaryModule", c_wchar * 120),
("exportModule", c_wchar * 120),
("text", c_wchar * 30),
("jittype", c_int),
("isjithook", c_bool),
]
@ -94,7 +94,7 @@ ProcessEvent = CFUNCTYPE(None, DWORD)
ThreadEvent_maybe_embed = CFUNCTYPE(None, c_wchar_p, c_char_p, ThreadParam, c_bool)
ThreadEvent = CFUNCTYPE(None, c_wchar_p, c_char_p, ThreadParam)
OutputCallback = CFUNCTYPE(c_bool, c_wchar_p, c_char_p, ThreadParam, c_wchar_p)
ConsoleHandler = CFUNCTYPE(None, c_wchar_p)
HostInfoHandler = CFUNCTYPE(None, c_int, c_wchar_p)
HookInsertHandler = CFUNCTYPE(None, DWORD, c_uint64, c_wchar_p)
EmbedCallback = CFUNCTYPE(None, c_wchar_p, ThreadParam)
QueryHistoryCallback = CFUNCTYPE(None, c_wchar_p)
@ -206,7 +206,6 @@ class texthook(basetext):
c_void_p,
c_void_p,
c_void_p,
c_void_p,
)
self.Luna_Inject = LunaHost.Luna_Inject
self.Luna_Inject.argtypes = DWORD, LPCWSTR
@ -252,10 +251,9 @@ class texthook(basetext):
ThreadEvent_maybe_embed(self.onnewhook),
ThreadEvent(self.onremovehook),
OutputCallback(self.handle_output),
ConsoleHandler(gobject.baseobject.hookselectdialog.sysmessagesignal.emit),
HostInfoHandler(gobject.baseobject.hookselectdialog.sysmessagesignal.emit),
HookInsertHandler(self.newhookinsert),
EmbedCallback(self.getembedtext),
ConsoleHandler(gobject.baseobject.hookselectdialog.warning.emit),
]
self.keepref += procs
ptrs = [cast(_, c_void_p).value for _ in procs]
@ -342,7 +340,9 @@ class texthook(basetext):
self.gameuid = gameuid
self.detachall()
_filename, _ = os.path.splitext(os.path.basename(gamepath))
sqlitef = gobject.gettranslationrecorddir("{}_{}.sqlite".format(_filename, gameuid))
sqlitef = gobject.gettranslationrecorddir(
"{}_{}.sqlite".format(_filename, gameuid)
)
if os.path.exists(sqlitef) == False:
md5 = getfilemd5(gamepath)
f2 = gobject.gettranslationrecorddir("{}_{}.sqlite".format(_filename, md5))
@ -396,7 +396,9 @@ class texthook(basetext):
injectpids.append(pid)
if len(injectpids):
arch = ["32", "64"][self.is64bit]
dll = os.path.abspath("./files/plugins/LunaHook/LunaHook{}.dll".format(arch))
dll = os.path.abspath(
"./files/plugins/LunaHook/LunaHook{}.dll".format(arch)
)
injectdll(injectpids, arch, dll)
@threader
@ -605,7 +607,7 @@ class texthook(basetext):
usestruct.maxRecords = 100000
usestruct.codepage = self.codepage()
usestruct.boundaryModule = os.path.basename(self.gamepath)
usestruct.jittype = 0
usestruct.isjithook = False
return usestruct
@threader