diff --git a/source/RDR3.Patches/RDR3.Patches.vcxproj b/source/RDR3.Patches/RDR3.Patches.vcxproj index df21754..9cb1891 100644 --- a/source/RDR3.Patches/RDR3.Patches.vcxproj +++ b/source/RDR3.Patches/RDR3.Patches.vcxproj @@ -111,14 +111,12 @@ - - - + diff --git a/source/RDR3.Patches/RDR3.Patches.vcxproj.filters b/source/RDR3.Patches/RDR3.Patches.vcxproj.filters index a5f2163..9e11537 100644 --- a/source/RDR3.Patches/RDR3.Patches.vcxproj.filters +++ b/source/RDR3.Patches/RDR3.Patches.vcxproj.filters @@ -23,9 +23,6 @@ Source Files - - Source Files - @@ -37,10 +34,7 @@ Header Files - - Header Files - - + Header Files diff --git a/source/RDR3.Patches/dllmain.cpp b/source/RDR3.Patches/dllmain.cpp index 155114e..681644e 100644 --- a/source/RDR3.Patches/dllmain.cpp +++ b/source/RDR3.Patches/dllmain.cpp @@ -6,8 +6,6 @@ #include "nativeCaller.h" #include "natives.h" -#include "mod_enum.h" - HMODULE baseModule{}; #define wstr(s) L#s @@ -31,14 +29,7 @@ static void ReadConfig() { // no ini, lets generate one. std::wstring ini_defaults = L"[Settings]\n" - "; Installs No Legal and Main Menu Mod\n" - "; Mod files:\n" - "; ```\n" - "; /x64/data/startup.meta\n" - "; /x64/main_and_legal_menu_skip_data/legal_screen_patch.ymt\n" - "; /x64/main_and_legal_menu_skip_data/main_menu_patch.ymt\n" - "; ```\n" - "; Source: https://www.rdr2mods.com/downloads/rdr2/other/304-main-and-legal-menu-skip/\n" + "; Thanks to this mod for reference on flowblock: https://www.rdr2mods.com/downloads/rdr2/other/304-main-and-legal-menu-skip/\n" wstr(bSkipLegalMainMenu)" = true\n" "; Start benchmark mode after game loads into autosave\n" wstr(bBenchmarkOnly)" = false\n"; @@ -86,6 +77,8 @@ static void __attribute__((naked)) Opcode6cAsm() jnz not_match; cmp dword ptr[rcx + 0x440], 0x08FA8CCA; jnz not_match; + cmp dword ptr[rcx + 0x1090], 5; + jz not_match; mov dword ptr[rcx + 0x1090], 5; // benchmark sequence override not_match:; jmp qword ptr[rip + g_nextScrOpcodeReturnAddr]; @@ -177,9 +170,8 @@ uint32_t makeHash(const char* str) return makeHash_(nullptr, str); } -static uint32_t* AfterLoadScreenHook1(void* arg1, uint32_t* arg2) +void showConsole() { -#ifdef _DEBUG AllocConsole(); SetConsoleTitleA(PROJECT_NAME " - Debug Console"); freopen_s(reinterpret_cast(stdin), "conin$", "r", stdin); @@ -191,20 +183,7 @@ static uint32_t* AfterLoadScreenHook1(void* arg1, uint32_t* arg2) GetConsoleMode(hConsole, &dwMode); dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; SetConsoleMode(hConsole, dwMode); -#endif - * arg2 = 0; // not valid flow - return arg2; } -bool breakLoop = false; -static uint32_t* AfterLoadScreenHook2(void* arg1, uint32_t* arg2) -{ - // cannot skip this flow for now, must use mod to workaround it - // - *arg2 = makeHash("landing_page/flow/landing_launcher_flow"); - return arg2; -} - -void Install_NoLogo_MainMenu_Patch(int mode); uintptr_t CScript_DoScreenFadeInReturn = 0; uintptr_t CScript_DoScreenFadeOutReturn = 0; @@ -267,12 +246,94 @@ static void DO_SCREEN_FADE_OUT_Hook(CScriptFuncArgs* arg) } CScript_DoScreenFadeOutAsm(arg); } + +uintptr_t ParseFlowBlockReturn = 19; + +typedef struct xml_keys_ +{ + void* not_useful[9]; + char* key; + void* not_useful2[3]; +}xml_keys; + +static void __attribute__((naked)) ParseFlowBlockAsm(void* arg1, xml_keys* keys, const char* prev_key) +{ + __asm + { + MOV RAX, RSP; + MOV qword ptr[RAX + 0x8], RBX; + MOV qword ptr[RAX + 0x10], RBP; + MOV qword ptr[RAX + 0x18], RSI; + MOV qword ptr[RAX + 0x20], RDI; + jmp qword ptr[rip + ParseFlowBlockReturn]; + } +} + +// https://github.com/PLTytus/various_joaat/blob/e06f51b1cfe95c2690b0fb46adce51c7d1f81d8a/joaat.c +// Hash method doesn't really matter +// Its just to prevent using strcmp +constexpr uint32_t joaat(const char* s) +{ + uint32_t hash = 0; + for (; *s; ++s) + { + hash += *s; + hash += (hash << 10); + hash ^= (hash >> 6); + } + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash; +} + +bool patched_flows = false; + +static void ParseFlowBlockHook(void* arg1, xml_keys* keys, const char* prev_key) +{ + uint32_t key_hash = 0; + if (!keys->key || patched_flows) + { + // the compiler will generate similar code if i used call() + return + goto no_match_or_quit; + } + key_hash = joaat(keys->key); + switch (key_hash) + { + case joaat("feedback_context_switch.boot_screen_host.sign_in_flow_activity_sentinel.account_picker_activity_sentinel.account_picker_wrapper"): + { + keys->key = (char*)"feedback_context_switch.boot_screen_host.profile_flow_activity_sentinel.wait_for_profile"; + break; + } + case joaat("input_context_switch.can_access_sp_check"): + case joaat("input_context_switch.boot_flow_startup"): + case joaat("input_context_switch.boot_flow_invite"): + case joaat("input_context_switch.boot_flow_sign_out"): + case joaat("input_context_switch.mp_direct_dispatch_code_event.mp_direct_scene.mp_direct_host"): + { + constexpr uint32_t lastflow = joaat("input_context_switch.mp_direct_dispatch_code_event.mp_direct_scene.mp_direct_host"); + if (lastflow == key_hash) + { + patched_flows = true; + } + keys->key = (char*)"input_context_switch.landing_camera_fader.landing_main.landing_filter.priority_feed_decision_sp.set_feedback_context.from_priority_feed_decision_sp_can_access_sp.sp_menu.launch_sp"; + break; + } + default: + { + break; + } + } +no_match_or_quit: + ParseFlowBlockAsm(arg1, keys, prev_key); +} + static void ApplyPatches() { - Install_NoLogo_MainMenu_Patch((bSkipLegalMainMenu || bBenchmarkOnly) ? ModInstallEnable : ModDisable); if (bBenchmarkOnly) { - baseModule = GetModuleHandle(NULL); void* jumpPattern = (void*)FindAndPrintPatternW(L"cc cc cc cc cc cc cc cc cc cc cc cc cc cc", L"Int3 Array"); void* OpcodePattern = (void*)FindAndPrintPatternW(L"48 83 eb 10 48 ff c7 0f b6 17", L"6c Opcode finder"); g_nextScrOpcodeReturnAddr = FindAndPrintPatternW(L"4c 8b 75 67 4c 8b 7c 24 38 4c 8b c3 48 ff c7", L"nextScrOpcode", +9); @@ -295,38 +356,28 @@ static void ApplyPatches() CScript_DoScreenFadeOutReturn = Cam_DoFadePtrs + 12 + 6; } } + } - // failed attempt at skipping logos and main menu -#ifndef _DEBUG - if (false) -#endif + // generates cleaner diff + { + if (bBenchmarkOnly || bSkipLegalMainMenu) { uintptr_t* boot_flow_vftable = (uintptr_t*)ReadLEA32(L"48 8d 05 ? ? ? ? 33 d2 48 89 03 48 8d 8b 30 01 00 00", L"boot_flow_vftable", 0, 3, 7); - uintptr_t* landing_launcher_flow_vftable = (uintptr_t*)ReadLEA32(L"48 8d 05 ? ? ? ? 48 8b d9 48 89 01 48 81 c1 a8 06 00 00", L"landing_launcher_flow_vftable", 0, 3, 7); printf_s("boot_flow_vftable[30] = 0x%p\n", boot_flow_vftable[30]); - printf_s("landing_launcher_flow_vftable[30] = 0x%p\n", landing_launcher_flow_vftable[30]); - - if (boot_flow_vftable) + uintptr_t ParseXmlBlockAddr = FindAndPrintPatternW(L"48 8b c4 48 89 58 08 48 89 68 10 48 89 70 18 48 89 78 20 41 56 48 83 ec 20 49 8b f0 48 8b da 4c 8b 41 08", L"ParseXmlBlockAddr"); + uintptr_t BogusErrorCheck = FindAndPrintPatternW(L"48 83 ec 28 45 33 c9 e8 ?? ?? ?? ?? cc", L"BogusErrorCheck"); + if (ParseXmlBlockAddr && BogusErrorCheck) { - void* jumpPattern2 = (void*)FindAndPrintPatternW(L"cc cc cc cc cc cc cc cc cc cc cc cc cc cc", L"Int3 Array"); - if (jumpPattern2) - { - BranchFunction32((void*)boot_flow_vftable[30], jumpPattern2, 5); - Memory::DetourFunction64(jumpPattern2, (void*)AfterLoadScreenHook1, 14); - } + ParseFlowBlockReturn += ParseXmlBlockAddr; + Memory::DetourFunction64((void*)ParseXmlBlockAddr, (void*)ParseFlowBlockHook, 14); + // patches sus errors when replacing the pointer in `ParseFlowBlockHook` + // TODO: Check if calling C script from a hook works now + // and also find a c script function that only runs when player is alive and once a frame + // this will hopefully eliminate the need for linking with scriptHook + // just like orbis version + unsigned char ret[] = { 0xc3 }; + Memory::PatchBytes(BogusErrorCheck, ret, sizeof(ret)); } - - /* - if (landing_launcher_flow_vftable) - { - void* jumpPattern2 = (void*)FindAndPrintPatternW(L"cc cc cc cc cc cc cc cc cc cc cc cc cc cc", L"Int3 Array"); - if (jumpPattern2) - { - BranchFunction32((void*)landing_launcher_flow_vftable[30], jumpPattern2, 5); - Memory::DetourFunction64(jumpPattern2, (void*)AfterLoadScreenHook2, 14); - } - } - */ } } } @@ -367,6 +418,10 @@ static void ScriptMain() static void Main(HMODULE hModule) { +#ifdef _DEBUG + showConsole(); +#endif + baseModule = GetModuleHandle(NULL); ReadConfig(); ApplyPatches(); if (bBenchmarkOnly) diff --git a/source/RDR3.Patches/install_mod.cpp b/source/RDR3.Patches/install_mod.cpp deleted file mode 100644 index 92c1dd7..0000000 --- a/source/RDR3.Patches/install_mod.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "mod_data.hpp" -#include "mod_enum.h" -#include -#include -#include - -#define BASE_PATH ".\\x64" -#define BASE_DATA_PATCH_PATH BASE_PATH "\\data" -#define BASE_MENU_PATCH_PATH BASE_PATH "\\main_and_legal_menu_skip_data" - -void Install_NoLogo_MainMenu_Patch(int mode) -{ - switch (mode) - { - case ModInstallEnable: - { - if (_access(BASE_DATA_PATCH_PATH "\\startup.meta", 0) == 0 || - _access(BASE_MENU_PATCH_PATH "\\legal_screen_patch.ymt", 0) == 0 || - _access(BASE_MENU_PATCH_PATH "\\main_menu_patch.ymt", 0) == 0) - { - printf_s("File exists\n"); - } - - if (_access(BASE_DATA_PATCH_PATH "\\startup_disable.meta", 0) == 0) - { - printf_s("startup_disable exists\n"); - rename(BASE_DATA_PATCH_PATH "\\startup_disable.meta", BASE_DATA_PATCH_PATH "\\startup.meta"); - break; - } - - printf_s("no file exists, creating it now\n"); - - _mkdir(BASE_PATH); - _mkdir(BASE_DATA_PATCH_PATH); - _mkdir(BASE_MENU_PATCH_PATH); - - FILE* startup_fp{}; - fopen_s(&startup_fp, BASE_DATA_PATCH_PATH "\\startup.meta", "w"); - if (startup_fp) - { - fputs(STARTUP_META_DATA, startup_fp); - fclose(startup_fp); - } - - FILE* legal_fp{}; - fopen_s(&legal_fp, BASE_MENU_PATCH_PATH "\\legal_screen_patch.ymt", "w"); - if (legal_fp) - { - fputs(LEGAL_YMT_DATA, legal_fp); - fclose(legal_fp); - } - - FILE* mainmenu_fp{}; - fopen_s(&mainmenu_fp, BASE_MENU_PATCH_PATH "\\main_menu_patch.ymt", "w"); - if (mainmenu_fp) - { - fputs(MAIN_MENU_DATA, mainmenu_fp); - fclose(mainmenu_fp); - } - break; - } - case ModDisable: - { - if (_access(BASE_DATA_PATCH_PATH "\\startup.meta", 0) == 0) - { - printf_s("startup exists\n"); - rename(BASE_DATA_PATCH_PATH "\\startup.meta", BASE_DATA_PATCH_PATH "\\startup_disable.meta"); - } - break; - } - } -} diff --git a/source/RDR3.Patches/mod_data.hpp b/source/RDR3.Patches/mod_data.h similarity index 100% rename from source/RDR3.Patches/mod_data.hpp rename to source/RDR3.Patches/mod_data.h diff --git a/source/RDR3.Patches/mod_enum.h b/source/RDR3.Patches/mod_enum.h deleted file mode 100644 index c04732b..0000000 --- a/source/RDR3.Patches/mod_enum.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -enum ModInstall -{ - ModInstallEnable = 1, - ModDisable, -};