From 62a0b5cebb78920f3fe7abb8ad81b605c3728326 Mon Sep 17 00:00:00 2001 From: Amos Date: Thu, 17 Jun 2021 17:07:26 -0700 Subject: [PATCH] Improvements to GameConsole class * Improvements to GameConsole quality * Add post-build events for renaming release executables to allow debugging "Debug" and "Release" from the same install * Segmentate codeblocks for easier reading and scrolling --- r5dev/include/id3dx.h | 1 + r5dev/include/patterns.h | 5 + r5dev/r5dev.vcxproj | 5 +- r5dev/src/console.cpp | 14 ++- r5dev/src/dllmain.cpp | 2 +- r5dev/src/hooks.cpp | 31 ++++-- r5dev/src/id3dx.cpp | 17 ++-- r5dev/src/opcptc.cpp | 4 + r5dev/src/overlay.cpp | 184 ++++++++++++++++++---------------- r5dev/src/utility.cpp | 12 +-- r5launcher/main.cpp | 22 +++- r5launcher/r5launcher.vcxproj | 4 +- 12 files changed, 180 insertions(+), 121 deletions(-) diff --git a/r5dev/include/id3dx.h b/r5dev/include/id3dx.h index 7ab14c01..3cb8c6b0 100644 --- a/r5dev/include/id3dx.h +++ b/r5dev/include/id3dx.h @@ -22,5 +22,6 @@ extern HRESULT __stdcall Present(IDXGISwapChain* pSwapChain, UINT nSyncInterval, ///////////////////////////////////////////////////////////////////////////// // Globals extern DWORD g_dThreadId; +extern BOOL g_bShowMenu; ///////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/include/patterns.h b/r5dev/include/patterns.h index 6e036ad4..30340b3a 100644 --- a/r5dev/include/patterns.h +++ b/r5dev/include/patterns.h @@ -5,6 +5,7 @@ // Define the signatures or offsets to be searched and hooked namespace { + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* ==== CONSOLE ========================================================================================================================================================= */ DWORD64 p_CommandExecute = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x8D\x0D\x27\x61\xa5\x1E\x41\x8B\xD8", "xxxx?xxxxxxxx????xxx"); void (*CommandExecute)(void* self, const char* cmd) = (void (*)(void*, const char*))p_CommandExecute; /*48 89 5C 24 ?? 57 48 83 EC 20 48 8D 0D ?? ?? ?? ?? 41 8B D8*/ @@ -15,6 +16,7 @@ namespace LONGLONG p_ConCommand_IsFlagSet = FindPattern("r5apex.exe", (const unsigned char*)"\x85\x51\x38\x0F\x95\xC0\xC3", "xxxxxxx"); bool (*ConCommand_IsFlagSet)(int* cmd, int flag) = (bool (*)(int*, int))p_ConCommand_IsFlagSet; /*85 51 38 0F 95 C0 C3*/ + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* ==== SQUIRREL ======================================================================================================================================================== */ DWORD64 p_SQVM_Print = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x8B\xC4\x48\x89\x50\x10\x4C\x89\x40\x18\x4C\x89\x48\x20\x53\x56\x57\x48\x81\xEC\x30\x08\x00\x00\x48\x8B\xDA\x48\x8D\x70\x18\x48\x8B\xF9\xE8\x00\x00\x00\xFF\x48\x89\x74\x24\x28\x48\x8D\x54\x24\x30\x33", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx???xxxxxxxxxxxx"); void* SQVM_Print = (void*)p_SQVM_Print; /*48 8B C4 48 89 50 10 4C 89 40 18 4C 89 48 20 53 56 57 48 81 EC 30 08 00 00 48 8B DA 48 8D 70 18 48 8B F9 E8 ?? ?? ?? FF 48 89 74 24 28 48 8D 54 24 30 33*/ @@ -26,6 +28,7 @@ namespace DWORD64 p_SQVM_LoadRson = FindPattern("r5apex.exe", (const unsigned char*)"\x4C\x8B\xDC\x49\x89\x5B\x08\x57\x48\x81\xEC\xA0\x00\x00\x00\x33", "xxxxxxxxxxxxxxxx"); int (*SQVM_LoadRson)(const char* rson_name) = (int (*)(const char*))p_SQVM_LoadRson; /*4C 8B DC 49 89 5B 08 57 48 81 EC A0 00 00 00 33*/ + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* ==== NETCHAN ========================================================================================================================================================= */ DWORD64 p_NET_ReceiveDatagram = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\xAC\x24\x50\xEB", "xxxxxxxxxxxxxxxxxxxxxxxxx"); bool (*NET_ReceiveDatagram)(int, void*, bool) = (bool (*)(int, void*, bool))p_NET_ReceiveDatagram; /*E8 ?? ?? ?? ?? 84 C0 75 35 48 8B D3*/ @@ -33,6 +36,7 @@ namespace DWORD64 p_NET_SendDatagram = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x89\x5C\x24\x08\x48\x89\x6C\x24\x10\x48\x89\x74\x24\x18\x57\x41\x56\x41\x57\x48\x81\xEC\x00\x05\x00\x00", "xxxxxxxxxxxxxxxxxxxxxxx?xxx"); unsigned int (*NET_SendDatagram)(SOCKET s, const char* buf, int len, int flags) = (unsigned int (*)(SOCKET, const char*, int, int))p_NET_SendDatagram; /*48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 41 56 41 57 48 81 EC ?? 05 00 00*/ + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* ==== WINAPI ========================================================================================================================================================== */ DWORD64 p_SetCursorPosition = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x85\xD2\x0F\x00\x00\x00\x00\x00\x48\x89\x6C\x24\x00\x56\x48\x83\xEC\x40\x4C", "xxxx?????xxxx?xxxxxx"); // Uncomment for anything that is not between S1 build 525 and S4 build 856 //DWORD64 p_SetCursorPosition = FindPattern("r5apex.exe", "\x48\x89\x6C\x24\x18\x48\x89\x74\x24\x20\x57\x48\x83\xEC\x40\x48\x8B\xF9", "xxxxxxxxxxxxxxxxxx"); // Uncomment for anything that is between S1 build 525 and S4 build 856 @@ -41,6 +45,7 @@ namespace //DWORD64 p_GameWindowProc = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x89\x4C\x24\x00\x56\x41\x54\x41\x56\x41\x57\x48\x83\xEC\x48", "xxxx?xxxxxxxxxxx"); //unsigned int (*GameWindowProc)(int game, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) = (unsigned int (*)(int, HWND, UINT, WPARAM, LPARAM))p_GameWindowProc; /*48 89 4C 24 ?? 56 41 54 41 56 41 57 48 83 EC 48*/ + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* ==== ------- ========================================================================================================================================================= */ void PrintHAddress() // Test the sigscan results diff --git a/r5dev/r5dev.vcxproj b/r5dev/r5dev.vcxproj index 7dfd8c34..fd871a4a 100644 --- a/r5dev/r5dev.vcxproj +++ b/r5dev/r5dev.vcxproj @@ -24,6 +24,7 @@ {28cc6b4f-7a95-4933-ada9-65e38d48516d} r5dev 10.0 + r5dev @@ -51,6 +52,7 @@ v142 true MultiByte + false @@ -176,8 +178,7 @@ detours.lib;%(AdditionalDependencies) - - + del "$(TargetDir)\r5detours.dll" && rename "$(TargetPath)" "r5detours.dll" diff --git a/r5dev/src/console.cpp b/r5dev/src/console.cpp index 89ff38c2..ba7f0c62 100644 --- a/r5dev/src/console.cpp +++ b/r5dev/src/console.cpp @@ -16,6 +16,7 @@ void SetupConsole() { + /////////////////////////////////////////////////////////////////////////////// // Create the console window if (AllocConsole() == FALSE) { @@ -23,6 +24,7 @@ void SetupConsole() return; } + /////////////////////////////////////////////////////////////////////////////// // Set the window title FILE* sBuildTxt; CHAR sBuildBuf[1024] = { 0 }; @@ -37,12 +39,14 @@ void SetupConsole() } SetConsoleTitle(sBuildBuf); + /////////////////////////////////////////////////////////////////////////////// // Open input/output streams FILE* fDummy; freopen_s(&fDummy, "CONIN$", "r", stdin); freopen_s(&fDummy, "CONOUT$", "w", stdout); freopen_s(&fDummy, "CONOUT$", "w", stderr); + /////////////////////////////////////////////////////////////////////////////// // Create a worker thread to process console commands DWORD threadId0; DWORD __stdcall ProcessConsoleWorker(LPVOID); @@ -67,6 +71,7 @@ bool Hook_ConVar_IsFlagSet(int** cvar, int flag) printf("--------------------------------------------------\n"); printf(" Flaged: %08X\n", real_flags); } + /////////////////////////////////////////////////////////////////////////////// // Mask off FCVAR_CHEATS and FCVAR_DEVELOPMENTONLY real_flags &= 0xFFFFBFFD; if (g_bDebugConsole) @@ -89,6 +94,7 @@ bool Hook_ConCommand_IsFlagSet(int* cmd, int flag) printf("--------------------------------------------------\n"); printf(" Flaged: %08X\n", real_flags); } + /////////////////////////////////////////////////////////////////////////////// // Mask off FCVAR_CHEATS and FCVAR_DEVELOPMENTONLY real_flags &= 0xFFFFBFFD; if (g_bDebugConsole) @@ -114,27 +120,31 @@ DWORD __stdcall ProcessConsoleWorker(LPVOID) { std::string sCommand; + /////////////////////////////////////////////////////////////////////////// // Get the user input on the debug console printf(">"); std::getline(std::cin, sCommand); + /////////////////////////////////////////////////////////////////////////// // Engine toggles if (sCommand == "toggle net") { ToggleNetHooks(); continue; } if (sCommand == "toggle dev") { ToggleDevCommands(); continue; } if (sCommand == "toggle fal") { g_bReturnAllFalse = !g_bReturnAllFalse; continue; } - + /////////////////////////////////////////////////////////////////////////// // Debug toggles if (sCommand == "pattern test") { PrintHAddress(); PrintOAddress(); continue; } if (sCommand == "console test") { g_bDebugConsole = !g_bDebugConsole; continue; } - + /////////////////////////////////////////////////////////////////////////// // Exec toggles if (sCommand == "1") { ToggleDevCommands(); CommandExecute(NULL, "exec autoexec_dev"); } if (sCommand == "2") { g_bDebugLog = !g_bDebugLog; continue; } + /////////////////////////////////////////////////////////////////////////// // Execute the command in the r5 SQVM CommandExecute(NULL, sCommand.c_str()); sCommand.clear(); + /////////////////////////////////////////////////////////////////////////// // Sleep and loop Sleep(50); } diff --git a/r5dev/src/dllmain.cpp b/r5dev/src/dllmain.cpp index 82399fe2..1e170819 100644 --- a/r5dev/src/dllmain.cpp +++ b/r5dev/src/dllmain.cpp @@ -30,7 +30,7 @@ void TerminateR5Dev() } //--------------------------------------------------------------------------------- -// Main +// Entry //--------------------------------------------------------------------------------- BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) diff --git a/r5dev/src/hooks.cpp b/r5dev/src/hooks.cpp index 80bea1b2..7b939bc4 100644 --- a/r5dev/src/hooks.cpp +++ b/r5dev/src/hooks.cpp @@ -23,6 +23,7 @@ bool Hook_NET_ReceiveDatagram(int sock, void* inpacket, bool raw) int i = NULL; netpacket_t* pkt = (netpacket_t*)inpacket; + /////////////////////////////////////////////////////////////////////////// // Log received packet data HexDump("[+] NET_ReceiveDatagram", "platform\\log\\netchan.log", "a", 0, &pkt->data[i], pkt->wiresize); } @@ -35,6 +36,7 @@ unsigned int Hook_NET_SendDatagram(SOCKET s, const char* buf, int len, int flags unsigned int result = NET_SendDatagram(s, buf, len, flags); if (result) { + /////////////////////////////////////////////////////////////////////////// // Log transmitted packet data HexDump("[+] NET_SendDatagram", "platform\\log\\netchan.log", "a", 0, buf, len); } @@ -74,6 +76,7 @@ bool Hook_SQVM_LoadScript(void* sqvm, const char* script_path, const char* scrip char filepath[MAX_PATH] = { 0 }; sprintf_s(filepath, MAX_PATH, "platform\\%s", script_path); + /////////////////////////////////////////////////////////////////////////////// // Flip forward slashes in filepath to windows-style backslash for (int i = 0; i < strlen(filepath); i++) { @@ -82,14 +85,20 @@ bool Hook_SQVM_LoadScript(void* sqvm, const char* script_path, const char* scrip filepath[i] = '\\'; } } - - if (g_bDebugLog) { printf(" [+] Loading SQVM Script '%s' ...\n", filepath); } + if (g_bDebugLog) + { + printf(" [+] Loading SQVM Script '%s' ...\n", filepath); + } + /////////////////////////////////////////////////////////////////////////////// + // Returns true if the script exists on the disk if (FileExists(filepath) && SQVM_LoadScript(sqvm, filepath, script_name, flag)) { - return true; // Redirect to disk worked / script exists on disk.. + return true; + } + if (g_bDebugLog) + { + printf(" [!] FAILED. Try SP / VPK for '%s'\n", filepath); } - - if (g_bDebugLog) { printf(" [!] FAILED. Try SP / VPK for '%s'\n", filepath); } return SQVM_LoadScript(sqvm, script_path, script_name, flag); } @@ -99,15 +108,16 @@ bool Hook_SQVM_LoadScript(void* sqvm, const char* script_path, const char* scrip void InstallHooks() { + /////////////////////////////////////////////////////////////////////////////// // Begin the detour transaction DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); - + /////////////////////////////////////////////////////////////////////////////// // Hook Engine functions DetourAttach((LPVOID*)&SQVM_Print, &Hook_SQVM_Print); DetourAttach((LPVOID*)&SQVM_LoadRson, &Hook_SQVM_LoadRson); DetourAttach((LPVOID*)&SQVM_LoadScript, &Hook_SQVM_LoadScript); - + /////////////////////////////////////////////////////////////////////////////// // Commit the transaction if (DetourTransactionCommit() != NO_ERROR) { @@ -118,21 +128,24 @@ void InstallHooks() void RemoveHooks() { + /////////////////////////////////////////////////////////////////////////////// // Begin the detour transaction, to unhook the the process DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); - + /////////////////////////////////////////////////////////////////////////////// // Unhook Squirrel functions DetourDetach((LPVOID*)&SQVM_Print, &Hook_SQVM_Print); DetourDetach((LPVOID*)&SQVM_LoadRson, &Hook_SQVM_LoadRson); DetourDetach((LPVOID*)&SQVM_LoadScript, &Hook_SQVM_LoadScript); + /////////////////////////////////////////////////////////////////////////////// // Unhook Netchan functions DetourDetach((LPVOID*)&NET_SendDatagram, &Hook_NET_SendDatagram); DetourDetach((LPVOID*)&NET_ReceiveDatagram, &Hook_NET_ReceiveDatagram); + /////////////////////////////////////////////////////////////////////////////// // Unhook Console functions DetourDetach((LPVOID*)&ConVar_IsFlagSet, &Hook_ConVar_IsFlagSet); DetourDetach((LPVOID*)&ConCommand_IsFlagSet, &Hook_ConCommand_IsFlagSet); - + /////////////////////////////////////////////////////////////////////////////// // Commit the transaction DetourTransactionCommit(); } diff --git a/r5dev/src/id3dx.cpp b/r5dev/src/id3dx.cpp index df515eb7..d5417450 100644 --- a/r5dev/src/id3dx.cpp +++ b/r5dev/src/id3dx.cpp @@ -26,14 +26,13 @@ typedef HRESULT(__stdcall* IDXGISwapChainPresent)(IDXGISwapChain* pSwapChain, UI typedef HRESULT(__stdcall* IDXGIResizeBuffers) (IDXGISwapChain* pSwapChain, UINT nBufferCount, UINT nWidth, UINT nHeight, DXGI_FORMAT dxFormat, UINT nSwapChainFlags); /////////////////////////////////////////////////////////////////////////////////// -static BOOL g_bShowMenu = false; -static BOOL g_bInitialized = false; -static BOOL g_bPresentHooked = false; -static BOOL g_bListener[256] = { 0 }; +extern BOOL g_bShowMenu = false; +static BOOL g_bInitialized = false; +static BOOL g_bPresentHooked = false; -static HWND g_hGameWindow = NULL; -static WNDPROC g_oWndProc = NULL; -extern DWORD g_dThreadId = NULL; +static WNDPROC g_oWndProc = NULL; +static HWND g_hGameWindow = NULL; +extern DWORD g_dThreadId = NULL; /////////////////////////////////////////////////////////////////////////////////// static IDXGISwapChainPresent g_fnIDXGISwapChainPresent = nullptr; @@ -62,7 +61,7 @@ LRESULT CALLBACK hWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { ImGuiIO& io = ImGui::GetIO(); - if (uMsg == WM_KEYUP) + if (uMsg == WM_KEYDOWN) { if (wParam == VK_OEM_3) { @@ -79,7 +78,7 @@ LRESULT CALLBACK hWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) return true; } - /////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////// return CallWindowProc(g_oWndProc, hWnd, uMsg, wParam, lParam); } diff --git a/r5dev/src/opcptc.cpp b/r5dev/src/opcptc.cpp index 63e1debb..3a5602c9 100644 --- a/r5dev/src/opcptc.cpp +++ b/r5dev/src/opcptc.cpp @@ -11,17 +11,21 @@ void InstallOpcodes() // JNZ --> JMP | Prevent OriginSDK from initializing on the client //WriteProcessMemory(GetCurrentProcess(), LPVOID(dst000 + 0x0B), "\xE9\x63\x02\x00\x00\x00", 6, NULL); + /////////////////////////////////////////////////////////////////////////// // JE --> NOP | Allow execution of map commands even if the OriginSDK is not running WriteProcessMemory(GameProcess, LPVOID(dst001 + 0x2B), "\x90\x90\x90\x90\x90\x90", 6, NULL); WriteProcessMemory(GameProcess, LPVOID(dst001 + 0x39), "\x90\x90\x90\x90\x90\x90", 6, NULL); WriteProcessMemory(GameProcess, LPVOID(dst001 + 0x46), "\x90\x90\x90\x90\x90\x90", 6, NULL); + /////////////////////////////////////////////////////////////////////////// // JL --> NOP | Enable clientcommand callbacks without persistent player data WriteProcessMemory(GameProcess, LPVOID(dst002 + 0x76), "\x90\x90", 2, NULL); + /////////////////////////////////////////////////////////////////////////// // JE --> NOP | Disable server-side verification for duplicate accounts on the server WriteProcessMemory(GameProcess, LPVOID(dst003 + 0x23A), "\x90\x90", 2, NULL); + /////////////////////////////////////////////////////////////////////////// // JA --> JMP | Prevent FairFight anti-cheat from initializing on the server WriteProcessMemory(GameProcess, LPVOID(dst004 + 0x72), "\xE9\xE4\x00\x00\x00\x00", 6, NULL); } diff --git a/r5dev/src/overlay.cpp b/r5dev/src/overlay.cpp index 937387ad..18f05d05 100644 --- a/r5dev/src/overlay.cpp +++ b/r5dev/src/overlay.cpp @@ -22,30 +22,32 @@ class CGameConsole { private: - char InputBuf[256]; - ImVector Commands; - ImVector History; - int HistoryPos; // -1: new line, 0..History.Size-1 browsing history. - ImGuiTextFilter Filter; - bool AutoScroll; - bool ScrollToBottom; + /////////////////////////////////////////////////////////////////////////// + char InputBuf[256] = { 0 }; + ImVector Commands; + ImVector History; + int HistoryPos = -1; + ImGuiTextFilter Filter; + bool AutoScroll = true; + bool ScrollToBottom = false; public: - ///////////////////////////////////////////////////////////////////////////// - // Init + /////////////////////////////////////////////////////////////////////////// CGameConsole() { ClearLog(); memset(InputBuf, 0, sizeof(InputBuf)); + HistoryPos = -1; AutoScroll = true; ScrollToBottom = false; + Commands.push_back("HELP"); Commands.push_back("HISTORY"); Commands.push_back("CLEAR"); Commands.push_back("CLASSIFY"); - AddLog("[DEBUG] THREAD ID: %ld\n", g_dThreadId); + AddLog("[DEBUG] THREAD ID: %ld\n", g_dThreadId); } ~CGameConsole() { @@ -53,9 +55,8 @@ public: for (int i = 0; i < History.Size; i++) { free(History[i]); } } - ///////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// // Helpers - static int Stricmp(const char* s1, const char* s2) { int d; @@ -65,7 +66,6 @@ public: } return d; } - static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) @@ -74,7 +74,6 @@ public: } return d; } - static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); if (buf != NULL) @@ -82,12 +81,13 @@ public: return (char*)memcpy(buf, (const void*)s, len); } } - static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; } + /////////////////////////////////////////////////////////////////////////// + // Utility void ClearLog() { for (int i = 0; i < Items.Size; i++) { free(Items[i]); } @@ -106,18 +106,24 @@ public: Items.push_back(Strdup(buf)); } - ///////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// // Draw void Draw(const char* title, bool* p_open) { ImGui::SetNextWindowSize(ImVec2(840, 600), ImGuiCond_FirstUseEver); - ImGui::SetWindowPos(ImVec2(1000, 50), ImGuiCond_FirstUseEver); - if (!ImGui::Begin(title, p_open)) { ImGui::End(); return; } - if (ImGui::BeginPopupContextItem()) + ImGui::SetWindowPos(ImVec2(-1000, 50), ImGuiCond_FirstUseEver); + if (!ImGui::Begin(title, p_open)) { - if (ImGui::MenuItem("Close Console")) { *p_open = false; } - ImGui::EndPopup(); + g_bShowMenu = false; + ImGui::End(); return; } + + if (*p_open == NULL) + { + g_bShowMenu = false; + } + + /////////////////////////////////////////////////////////////////////// if (ImGui::SmallButton("Developer mode")) { ToggleDevCommands(); @@ -136,21 +142,34 @@ public: ExecCommand("exec netchan"); } - ///////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////// ImGui::SameLine(); - if (ImGui::SmallButton("Clear")) { ClearLog(); } + if (ImGui::SmallButton("Clear")) + { + ClearLog(); + } ImGui::SameLine(); bool copy_to_clipboard = ImGui::SmallButton("Copy"); ImGui::Separator(); - if (ImGui::BeginPopup("Options")) { ImGui::Checkbox("Auto-scroll", &AutoScroll); ImGui::EndPopup(); } - if (ImGui::Button("Options")) { ImGui::OpenPopup("Options"); } + if (ImGui::BeginPopup("Options")) + { + ImGui::Checkbox("Auto-scroll", &AutoScroll); ImGui::EndPopup(); + } + if (ImGui::Button("Options")) + { + ImGui::OpenPopup("Options"); + } ImGui::SameLine(); Filter.Draw("Filter [\"-incl,-excl\"] [\"error\"]", 180); ImGui::Separator(); + /////////////////////////////////////////////////////////////////////// // Reserve enough left-over height for 1 separator + 1 input text const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); - ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); + + /////////////////////////////////////////////////////////////////////// + ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), true, ImGuiWindowFlags_None); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 4.f, 6.f }); if (ImGui::BeginPopupContextWindow()) { if (ImGui::Selectable("Clear")) @@ -165,10 +184,11 @@ public: const char* item = Items[i]; if (!Filter.PassFilter(item)) { continue; } - ///////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// ImVec4 color; bool has_color = false; + /////////////////////////////////////////////////////////////////// // General if (strstr(item, "[INFO]")) { color = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); has_color = true; } if (strstr(item, "[ERROR]")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } @@ -176,31 +196,37 @@ public: if (strstr(item, "[WARNING]")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.00f, 0.80f, 0.60f, 1.00f); has_color = true; } - // Script errors - if (strstr(item, "[CLIENT]")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, "[SERVER]")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, "[UI]")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, "SCRIPT ERROR")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, "SCRIPT COMPILE ERROR")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - if (strstr(item, " -> ")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } - - - // Script debug - if (strstr(item, "CALLSTACK")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } - if (strstr(item, "LOCALS")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } - if (strstr(item, "*FUNCTION")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } - if (strstr(item, "DIAGPRINTS")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } - if (strstr(item, " File : ")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } - if (strstr(item, "<><>GRX<><>")){ color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } - + /////////////////////////////////////////////////////////////////// // Callbacks - if (strstr(item, "CodeCallback_")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } + if (strstr(item, "CodeCallback_")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } + /////////////////////////////////////////////////////////////////// + // Script errors + if (strstr(item, "[CLIENT]")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } + if (strstr(item, "[SERVER]")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } + if (strstr(item, "[UI]")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } + if (strstr(item, "SCRIPT ERROR")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } + if (strstr(item, "SCRIPT COMPILE")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } + if (strstr(item, ".gnut #")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } + if (strstr(item, ".nut #")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } + if (strstr(item, " -> ")) { color = ImVec4(1.00f, 0.00f, 0.00f, 1.00f); has_color = true; } + + /////////////////////////////////////////////////////////////////// + // Script debug + if (strstr(item, "CALLSTACK")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } + if (strstr(item, "LOCALS")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } + if (strstr(item, "*FUNCTION")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } + if (strstr(item, "DIAGPRINTS")) { color = ImVec4(1.00f, 1.00f, 0.00f, 0.80f); has_color = true; } + if (strstr(item, " File : ")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } + if (strstr(item, "<><>GRX<><>")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } + + /////////////////////////////////////////////////////////////////// // Filters - if (strstr(item, ") -> ")) { color = ImVec4(1.00f, 1.00f, 1.00f, 0.60f); has_color = true; } + if (strstr(item, ") -> ")) { color = ImVec4(1.00f, 1.00f, 1.00f, 0.60f); has_color = true; } + /////////////////////////////////////////////////////////////////// if (has_color) { ImGui::PushStyleColor(ImGuiCol_Text, color); } - ImGui::TextUnformatted(item); + ImGui::TextWrapped(item); if (has_color) { ImGui::PopStyleColor(); } } if (copy_to_clipboard) { ImGui::LogFinish(); } @@ -208,7 +234,7 @@ public: if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) { ImGui::SetScrollHereY(1.0f); } ScrollToBottom = false; - ///////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////// // Style void SetStyleVar(); { @@ -271,33 +297,34 @@ public: colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.5f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarRounding, 1.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.5f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_ScrollbarRounding, 1.0f); //ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 2.5f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 2.5f); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing } + /////////////////////////////////////////////////////////////////////// ImGui::PopStyleVar(); ImGui::EndChild(); ImGui::Separator(); - ///////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////// // Console bool reclaim_focus = false; - bool clear_inputbuf = false; ImGui::PushItemWidth(750); if (ImGui::IsWindowAppearing()) { ImGui::SetKeyboardFocusHere(); } ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory; + if (ImGui::InputText("##input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this)) { char* s = InputBuf; + if (strstr(InputBuf, "`")) { strcpy(s, ""); } Strtrim(s); if (s[0]) { ExecCommand(s); } strcpy(s, ""); reclaim_focus = true; - clear_inputbuf = false; } ImGui::SameLine(); if (ImGui::Button("Submit")) @@ -306,27 +333,19 @@ public: if (s[0]) { ExecCommand(s); } strcpy(s, ""); reclaim_focus = true; - clear_inputbuf = false; - } - if (GetKeyState(VK_OEM_3) & 0x8000) { clear_inputbuf = true; } - if (clear_inputbuf == true) - { - char* s = InputBuf; - strcpy(s, ""); - clear_inputbuf = false; } + /////////////////////////////////////////////////////////////////////// // Auto-focus on window apparition ImGui::SetItemDefaultFocus(); if (reclaim_focus) { ImGui::SetKeyboardFocusHere(-1); }// Auto focus previous widget ImGui::End(); } + /////////////////////////////////////////////////////////////////////////// + // Exec void ExecCommand(const char* command_line) { - using namespace std; - ifstream file("convar.txt"); - AddLog("# %s\n", command_line); CommandExecute(NULL, command_line); @@ -344,9 +363,10 @@ public: } History.push_back(Strdup(command_line)); - - // Process command TODO: compare command with convar/concommand list else return unknown - if (Stricmp(command_line, "CLEAR") == 0) { ClearLog(); } + if (Stricmp(command_line, "CLEAR") == 0) + { + ClearLog(); + } else if (Stricmp(command_line, "HELP") == 0) { AddLog("Commands:"); @@ -357,26 +377,12 @@ public: int first = History.Size - 10; for (int i = first > 0 ? first : 0; i < History.Size; i++) { AddLog("%3d: %s\n", i, History[i]); } } - //char input[256]; - //bool found = false; - //while (file.good()) - //{ - // file >> input; - // if (file.good() && strcmp(input, command_line) == 0) - // { - // bool found = true; - // } - //} - //if (!found) - //{ - // AddLog("[WARNING] Unknown command: '%s'\n", command_line); - //} - //// On command input, we scroll to bottom even if AutoScroll==false - //ScrollToBottom = true; - //found = false; + + // On command input, we scroll to bottom even if AutoScroll==false + ScrollToBottom = true; } - ///////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// // History static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) { @@ -384,6 +390,8 @@ public: return console->TextEditCallback(data); } + /////////////////////////////////////////////////////////////////////////// + // Edit int TextEditCallback(ImGuiInputTextCallbackData* data) { switch (data->EventFlag) @@ -428,6 +436,8 @@ public: } }; +/////////////////////////////////////////////////////////////////////////////// +// Entry void ShowGameConsole(bool* p_open) { static CGameConsole console; diff --git a/r5dev/src/utility.cpp b/r5dev/src/utility.cpp index 1b50599f..e8352802 100644 --- a/r5dev/src/utility.cpp +++ b/r5dev/src/utility.cpp @@ -8,7 +8,7 @@ * _utility.cpp *-----------------------------------------------------------------------------*/ - ///////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// // BOOL FileExists(LPCTSTR szPath) { @@ -18,7 +18,7 @@ BOOL FileExists(LPCTSTR szPath) !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); } -///////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // For getting information about the specified module MODULEINFO GetModuleInfo(const char* szModule) { @@ -32,7 +32,7 @@ MODULEINFO GetModuleInfo(const char* szModule) return modinfo; } -///////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // For finding a byte pattern in memory of the game process BOOL Compare(const unsigned char* pData, const unsigned char* szPattern, const char* szMask) { @@ -62,7 +62,7 @@ DWORD64 FindPattern(const char* szModule, const unsigned char* szPattern, const return 0; } -///////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // void DbgPrint(LPCSTR sFormat, ...) { @@ -80,7 +80,7 @@ void DbgPrint(LPCSTR sFormat, ...) OutputDebugString(sBuffer); } -///////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// // For dumping data from a buffer to a file on the disk void HexDump(const char* szHeader, const char* szFile, const char* szMode, int nFunc, const void* pData, int nSize) { @@ -128,6 +128,6 @@ void HexDump(const char* szHeader, const char* szFile, const char* szMode, int n } } } - + /////////////////////////////////////////////////////////////////////////// fclose(sTraceLog); } diff --git a/r5launcher/main.cpp b/r5launcher/main.cpp index 38d44dbf..5547ea3f 100644 --- a/r5launcher/main.cpp +++ b/r5launcher/main.cpp @@ -3,8 +3,13 @@ #include #include +/*----------------------------------------------------------------------------- + * _main.cpp + *-----------------------------------------------------------------------------*/ + void PrintLastError() { + /////////////////////////////////////////////////////////////////////////// //Get the error message, if any. DWORD errorMessageID = ::GetLastError(); if (errorMessageID == 0) @@ -27,6 +32,7 @@ bool LaunchR5Apex() CHAR sCommandDirectory[MAX_PATH]; LPSTR sCommandLine = sCommandDirectory; + /////////////////////////////////////////////////////////////////////////// // '+exec autoexec -dev -fnf -noplatform' fopen_s(&sLaunchParams, "platform\\cfg\\startup_debug.cfg", "r"); @@ -39,9 +45,11 @@ bool LaunchR5Apex() STARTUPINFO StartupInfo = { 0 }; PROCESS_INFORMATION ProcInfo = { 0 }; + /////////////////////////////////////////////////////////////////////////// // Initialize the startup info structure. StartupInfo.cb = sizeof(STARTUPINFO); + /////////////////////////////////////////////////////////////////////////// // Load command line arguments from a file on the disk. if (sLaunchParams) { @@ -51,10 +59,11 @@ bool LaunchR5Apex() } } + /////////////////////////////////////////////////////////////////////////// // Format the file paths for the game exe and dll. GetCurrentDirectory(MAX_PATH, sGameDirectory); snprintf(sGameExe, sizeof(sGameExe), "%s\\r5apex.exe", sGameDirectory); - snprintf(sDevDll, sizeof(sDevDll), "%s\\r5dev.dll", sGameDirectory); + snprintf(sDevDll, sizeof(sDevDll), "%s\\r5detours.dll", sGameDirectory); snprintf(sCommandLine, sizeof(sCommandDirectory), "%s\\r5apex.exe %s", sGameDirectory, sArgumentBuffer); printf("Launching Apex Dev...\n"); @@ -63,12 +72,14 @@ bool LaunchR5Apex() printf(" - DLL: %s\n", sDevDll); printf(" - CLI: %s\n", sCommandLine); + /////////////////////////////////////////////////////////////////////////// // Build our list of dlls to inject. LPCSTR DllsToInject[1] = { sDevDll }; + /////////////////////////////////////////////////////////////////////////// // Create the game process in a suspended state with our dll. result = DetourCreateProcessWithDllsA( sGameExe, // lpApplicationName @@ -86,16 +97,19 @@ bool LaunchR5Apex() NULL // pfCreateProcessA ); - // Failed to create the game process. + /////////////////////////////////////////////////////////////////////////// + // Failed to create the process. if (!result) { PrintLastError(); return false; } + /////////////////////////////////////////////////////////////////////////// // Resume the process. ResumeThread(ProcInfo.hThread); + /////////////////////////////////////////////////////////////////////////// // Close the process and thread handles. CloseHandle(ProcInfo.hProcess); CloseHandle(ProcInfo.hThread); @@ -103,9 +117,11 @@ bool LaunchR5Apex() return true; } +/////////////////////////////////////////////////////////////////////////////// +// Entry point. int main(int argc, char* argv[], char* envp[]) { LaunchR5Apex(); Sleep(1000); return 0; -} \ No newline at end of file +} diff --git a/r5launcher/r5launcher.vcxproj b/r5launcher/r5launcher.vcxproj index d776c1c6..9b79364d 100644 --- a/r5launcher/r5launcher.vcxproj +++ b/r5launcher/r5launcher.vcxproj @@ -51,6 +51,7 @@ v142 true MultiByte + false @@ -158,8 +159,7 @@ detours.lib;%(AdditionalDependencies) - - + del "$(TargetDir)\launcher.exe" && rename "$(TargetPath)" "launcher.exe"