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,
-};