diff --git a/external/imgui/include/imgui.h b/external/imgui/include/imgui.h index 44b9922a..72c197e5 100644 --- a/external/imgui/include/imgui.h +++ b/external/imgui/include/imgui.h @@ -548,6 +548,7 @@ namespace ImGui IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0); IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0); + IMGUI_API bool Hotkey(const char* label, int* key, const ImVec2& size); // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little color square that can be left-clicked to open a picker, and right-clicked to open an option menu.) // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. diff --git a/external/imgui/src/imgui_widgets.cpp b/external/imgui/src/imgui_widgets.cpp index d4d39143..2f6b05a2 100644 --- a/external/imgui/src/imgui_widgets.cpp +++ b/external/imgui/src/imgui_widgets.cpp @@ -8048,4 +8048,365 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, } +const char* const KeyNames[] = +{ + "Null", + "Mouse1", + "Mouse2", + "Cancel", + "Mouse3", + "Mouse4", + "Mouse5", + "Undefined", + "Back", + "Tab", + "Reserved", + "Reserved", + "Clear", + "Return", + "Undefined", + "Undefined", + "Shift", + "Control", + "Menu", + "Pause", + "Capital", + "Kana", + "Ime On", + "Junja", + "Final", + "Kanji", + "Ime Off", + "Escape", + "Convert", + "Nonconvert", + "Accept", + "Modechange", + "Space", + "Prior", + "Next", + "End", + "Home", + "Left", + "Up", + "Right", + "Down", + "Select", + "Print", + "Execute", + "Snapshot", + "Insert", + "Delete", + "Help", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "Lwin", + "Rwin", + "Apps", + "Unknown", + "Sleep", + "Numpad0", + "Numpad1", + "Numpad2", + "Numpad3", + "Numpad4", + "Numpad5", + "Numpad6", + "Numpad7", + "Numpad8", + "Numpad9", + "Multiply", + "Add", + "Separator", + "Subtract", + "Decimal", + "Divide", + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "F10", + "F11", + "F12", + "F13", + "F14", + "F15", + "F16", + "F17", + "F18", + "F19", + "F20", + "F21", + "F22", + "F23", + "F24", + "Unassigned", + "Unassigned", + "Unassigned", + "Unassigned", + "Unassigned", + "Unassigned", + "Unassigned", + "Unassigned", + "Numlock", + "Scroll", + "Oem_nec_equal", + "Oem_fj_masshou", + "Oem_fj_touroku", + "Oem_fj_loya", + "Oem_fj_roya", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Unknown", + "Lshift", + "Rshift", + "Lcontrol", + "Rcontrol", + "Lmenu", + "Rmenu", + "Browser Back", + "Browser Stop", + "Browser Refresh", + "Browser Search", + "Browser Favorite", + "Browser Home", + "Volume Mute", + "Volume Down", + "Volume Up", + "Next Track", + "Previous Track", + "Media Stop", + "Play/Pause", + "Mail", + "Media", + "App1", + "App2", + "Reserved", + "Reserved", + "Reserved", + ":;", + "+", + ",", + "-", + ".", + "?", + "~", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined", + "Undefined" +}; + +bool ImGui::Hotkey(const char* label, int* key, const ImVec2& ssize) +{ + ImGuiWindow* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + const ImGuiStyle& style = g.Style; + + float backupPaddingY = style.FramePadding.y; + g.Style.FramePadding.y = 0.0f; + + const ImGuiID id = window->GetID(label); + const ImVec2 labelSize = ImGui::CalcTextSize(label, NULL, true); + const ImVec2 size = ImGui::CalcItemSize(ssize, ImGui::CalcItemWidth(), labelSize.y + style.FramePadding.y * 2.0f); + + const ImRect frameBB(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, labelSize.y + style.FramePadding.y)); + const ImRect total_bb(frameBB.Min, frameBB.Max + ImVec2(labelSize.x > 0.0f ? style.ItemInnerSpacing.x + labelSize.x : 0.0f, 0.0f)); + + ImGui::ItemSize(total_bb, style.FramePadding.y); + if (!ImGui::ItemAdd(total_bb, id)) + { + g.Style.FramePadding.y = backupPaddingY; + return false; + } + + const bool requestedFocus = ImGui::FocusableItemRegister(window, id); + const bool isHovered = ImGui::ItemHoverable(frameBB, id); + + if (isHovered) { + ImGui::SetHoveredID(id); + g.MouseCursor = ImGuiMouseCursor_TextInput; + } + + const bool didClick = isHovered && io.MouseClicked[0]; + + if (requestedFocus || didClick) + { + if (g.ActiveId != id) + { + memset(io.MouseDown, 0, sizeof(io.MouseDown)); + memset(io.KeysDown, 0, sizeof(io.KeysDown)); + *key = 0; + } + ImGui::SetActiveID(id, window); + ImGui::FocusWindow(window); + } + else if (io.MouseClicked[0]) + { + if (g.ActiveId == id) + { + ImGui::ClearActiveID(); + } + } + + bool didValueChange = false; + int kkey = *key; + + if (g.ActiveId == id) + { + for (auto i = 0x1; i <= 0xA5; i++) + { + if (io.KeysDown[i]) + { + kkey = i; + didValueChange = true; + ImGui::ClearActiveID(); + } + } + + if (IsKeyPressedMap(ImGuiKey_Escape)) + { + *key = NULL; + ImGui::ClearActiveID(); + } + else + { + *key = kkey; + } + } + + char displayBuf[24] = "None"; + + if (*key != 0 && g.ActiveId != id) + { + strcpy_s(displayBuf, KeyNames[*key]); + } + else if (g.ActiveId == id) + { + strcpy_s(displayBuf, "Press key"); + } + + const ImRect clip_rect(frameBB.Min.x, frameBB.Min.y, frameBB.Min.x + size.x, frameBB.Min.y + size.y); + ImGui::RenderTextClipped(frameBB.Min + style.FramePadding, frameBB.Max - style.FramePadding, displayBuf, NULL, NULL, style.ButtonTextAlign, &clip_rect); + + g.Style.FramePadding.y = backupPaddingY; + + return didValueChange; +} + #endif // #ifndef IMGUI_DISABLE diff --git a/r5dev/include/gameclasses.h b/r5dev/include/gameclasses.h index 90f343fd..59d962ce 100644 --- a/r5dev/include/gameclasses.h +++ b/r5dev/include/gameclasses.h @@ -291,12 +291,13 @@ public: const char* m_pzsCurrentValue; //0x0058 __int64 m_iStringLength; //0x0060 float m_flValue; //0x0068 - __int64 m_iValue; //0x006C + int m_iValue; //0x006C bool m_bHasMin; //0x0070 float m_flMinValue; //0x0074 bool m_bHasMax; //0x0078 float m_flMaxValue; //0x007C -}; //Size: 0x0080 + char pad_0080[32]; //0x0080 +}; //Size: 0x00A0 class CCVarIteratorInternal // Fully reversed table, just look at the virtual function table and rename the function. { @@ -368,6 +369,7 @@ namespace GameGlobals extern CInputSystem* InputSystem; extern CCVar* Cvar; + ConVar* CreateCustomConVar(const char* name, const char* defaultValue, int flags, const char* helpString, bool bMin, float fMin, bool bMax, float fMax, void* callback, void* unk); void InitGameGlobals(); extern bool IsInitialized; } \ No newline at end of file diff --git a/r5dev/include/gui_utility.h b/r5dev/include/gui_utility.h index a6239c2c..052314ab 100644 --- a/r5dev/include/gui_utility.h +++ b/r5dev/include/gui_utility.h @@ -1,6 +1,74 @@ +#pragma once + ///////////////////////////////////////////////////////////////////////////// // Internals int Stricmp(const char* s1, const char* s2); int Strnicmp(const char* s1, const char* s2, int n); char* Strdup(const char* s); void Strtrim(char* s); + +class GuiConfig +{ +public: + struct + { + int bind1 = VK_OEM_3; + int bind2 = VK_INSERT; + } CGameConsoleConfig; + + struct + { + int bind1 = VK_HOME; + int bind2 = VK_F10; + } CCompanionConfig; + + void Load() + { + std::filesystem::path path = std::filesystem::current_path() /= "gui.config"; // Get current path + gui.config + + nlohmann::json in; + std::ifstream config_file(path, std::ios::in); // Parse config file. + + if (config_file.good() && config_file) // Check if it parsed. + { + config_file >> in; + config_file.close(); + + if (!in.is_null()) + { + if (!in["config"].is_null()) + { + // CGameConsole + CGameConsoleConfig.bind1 = in["config"]["CGameConsole"]["bind1"].get<int>(); + CGameConsoleConfig.bind2 = in["config"]["CGameConsole"]["bind2"].get<int>(); + + // CCompanion + CCompanionConfig.bind1 = in["config"]["CCompanion"]["bind1"].get<int>(); + CCompanionConfig.bind2 = in["config"]["CCompanion"]["bind2"].get<int>(); + } + } + } + } + + void Save() + { + nlohmann::json out; + + // CGameConsole + out["config"]["CGameConsole"]["bind1"] = CGameConsoleConfig.bind1; + out["config"]["CGameConsole"]["bind2"] = CGameConsoleConfig.bind2; + + // CCompanion + out["config"]["CCompanion"]["bind1"] = CCompanionConfig.bind1; + out["config"]["CCompanion"]["bind2"] = CCompanionConfig.bind2; + + std::filesystem::path path = std::filesystem::current_path() /= "gui.config"; // Get current path + gui.config + std::ofstream out_file(path, std::ios::out | std::ios::trunc); // Write config file.. + + out_file << out.dump(4); // Dump it into config file.. + + out_file.close(); // Close the file handle. + }; +}; + +extern GuiConfig g_GuiConfig; diff --git a/r5dev/include/opcptc.h b/r5dev/include/opcptc.h index ae207e25..e563def9 100644 --- a/r5dev/include/opcptc.h +++ b/r5dev/include/opcptc.h @@ -37,7 +37,8 @@ namespace #pragma endregion #pragma region Squirrel - MemoryAddress Squirrel_CompileError = r5_op.PatternSearch("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 56 48 81 EC ? ? ? ? 48 8B D9 4C 8B F2"); + /*0x14105CCA0*/ + MemoryAddress Squirrel_CompileError = r5_op.StringSearch("%s SCRIPT COMPILE ERROR: %s").FindPatternSelf("48 89 5C", MemoryAddress::Direction::UP); #pragma endregion void PrintOAddress() // Test the sigscan results diff --git a/r5dev/include/patterns.h b/r5dev/include/patterns.h index c7f78b70..301ed6e4 100644 --- a/r5dev/include/patterns.h +++ b/r5dev/include/patterns.h @@ -55,7 +55,7 @@ namespace #pragma region CHLClient /*0x1405C0740*/ - FUNC_AT_ADDRESS(addr_CHLClient_FrameStageNotify, void(*)(void* rcx, int curStage), r5_patterns.PatternSearch("48 83 EC 28 89 15 ?? ?? ?? ??").GetPtr()); + FUNC_AT_ADDRESS(addr_CHLClient_FrameStageNotify, void(*)(void*, int), r5_patterns.PatternSearch("48 83 EC 28 89 15 ?? ?? ?? ??").GetPtr()); #pragma endregion #pragma region CVEngineServer @@ -71,6 +71,9 @@ namespace #pragma region Utility /*0x140295600*/ FUNC_AT_ADDRESS(addr_MSG_EngineError, int(*)(char*, va_list), r5_patterns.StringSearch("Engine Error").FindPatternSelf("48 89 ? ? ? 48 89", MemoryAddress::Direction::UP, 500).GetPtr()); + + /*0x1401B31C0*/ + FUNC_AT_ADDRESS(addr_MemAlloc_Wrapper, void*(*)(__int64), r5_patterns.StringSearch("ConversionModeMenu").FindPatternSelf("E8 ? ? ? ? 48", MemoryAddress::Direction::UP).FollowNearCallSelf().GetPtr()); #pragma endregion // Un-used atm. // DWORD64 p_KeyValues_FindKey = /*1404744E0*/ reinterpret_cast<DWORD64>(PatternScan("r5apex.exe", "40 56 57 41 57 48 81 EC ?? ?? ?? ?? 45")); @@ -95,6 +98,7 @@ namespace PRINT_ADDRESS("CVEngineServer::IsPersistenceDataAvailable", addr_CVEngineServer_IsPersistenceDataAvailable); PRINT_ADDRESS("CBaseFileSystem::FileSystemWarning", addr_CBaseFileSystem_FileSystemWarning); PRINT_ADDRESS("MSG_EngineError", addr_MSG_EngineError); + PRINT_ADDRESS("MemAlloc_Wrapper", addr_MemAlloc_Wrapper); std::cout << "+--------------------------------------------------------+" << std::endl; // TODO implement error handling when sigscan fails or result is 0 } diff --git a/r5dev/src/CGameConsole.cpp b/r5dev/src/CGameConsole.cpp index 0fe76f43..dc522f8b 100644 --- a/r5dev/src/CGameConsole.cpp +++ b/r5dev/src/CGameConsole.cpp @@ -75,6 +75,18 @@ void CGameConsole::Draw(const char* title) ClearLog(); } copy_to_clipboard = ImGui::SmallButton("Copy"); + ImGui::Text("CG Hotkey:"); + ImGui::SameLine(); + if (ImGui::Hotkey("##OpenCGameConsoleBind1", &g_GuiConfig.CGameConsoleConfig.bind1, ImVec2(80, 80))) + { + g_GuiConfig.Save(); + } + ImGui::Text("CC Hotkey:"); + ImGui::SameLine(); + if (ImGui::Hotkey("##OpenCCompanionBind1", &g_GuiConfig.CCompanionConfig.bind1, ImVec2(80, 80))) + { + g_GuiConfig.Save(); + } ImGui::EndPopup(); } if (ImGui::Button("Options")) diff --git a/r5dev/src/dllmain.cpp b/r5dev/src/dllmain.cpp index c996b69b..be313cef 100644 --- a/r5dev/src/dllmain.cpp +++ b/r5dev/src/dllmain.cpp @@ -15,6 +15,7 @@ void InitializeR5Dev() SetupConsole(); Hooks::InstallHooks(); InstallOpcodes(); + g_GuiConfig.Load(); // Load gui config. SetupDXSwapChain(); printf("+-----------------------------------------------------------------------------+\n"); printf("| R5 DEV -- INITIALIZED ------------------------------------------------- |\n"); diff --git a/r5dev/src/gameclasses.cpp b/r5dev/src/gameclasses.cpp index 84da7d83..d1dd6cb0 100644 --- a/r5dev/src/gameclasses.cpp +++ b/r5dev/src/gameclasses.cpp @@ -1,8 +1,60 @@ #include "pch.h" #include "gameclasses.h" +#include "id3dx.h" namespace GameGlobals { + namespace CustomConVar + { + void CGameConsole_Callback(void* cmd) + { + std::string szValue = *(const char**)((std::uintptr_t)cmd + 0x18); + try + { + int value = std::stoi(szValue); + switch (value) + { + case 0: + g_bShowConsole = false; + break; + case 1: + g_bShowConsole = true; + break; + default: + break; + } + } + catch (std::exception& e) + { + std::cout << " [+CGameConsole+] Please don't input a character that isn't a number into cgameconsole :(.\n"; + } + } + + void CCompanion_Callback(void* cmd) + { + std::string szValue = *(const char**)((std::uintptr_t)cmd + 0x18); + try + { + int value = std::stoi(szValue); + switch (value) + { + case 0: + g_bShowBrowser = false; + break; + case 1: + g_bShowBrowser = true; + break; + default: + break; + } + } + catch (std::exception& e) + { + std::cout << " [+CCompanion+] Please don't input a character that isn't a number into ccompanion :(.\n"; + }; + } + } + bool IsInitialized = false; CHostState* HostState = nullptr; CInputSystem* InputSystem = nullptr; @@ -49,7 +101,29 @@ namespace GameGlobals // { // printf("%s: %p\n", current->InterfaceName, current->InterfacePtr); // } + + ConVar* CGameConsoleConVar = CreateCustomConVar("cgameconsole", "0", 0, "Opens the R5 Reloaded Console", false, 0.f, false, 0.f, CustomConVar::CGameConsole_Callback, nullptr); + ConVar* CCompanionConVar = CreateCustomConVar("ccompanion", "0", 0, "Opens the R5 Reloaded Server Browser", false, 0.f, false, 0.f, CustomConVar::CCompanion_Callback, nullptr); EmptyHostNames(); IsInitialized = true; } + + ConVar* CreateCustomConVar(const char* name, const char* defaultValue, int flags, const char* helpString, bool bMin, float fMin, bool bMax, float fMax, void* callback, void* unk) + { + static MemoryAddress ConVarVtable = MemoryAddress(0x14046FB50).Offset(0x12).ResolveRelativeAddress(); // Get vtable ptr for ConVar table. + static MemoryAddress ICvarVtable = MemoryAddress(0x14046FB50).Offset(0x29).ResolveRelativeAddress(); // Get vtable ptr for ICvar table. + static MemoryAddress CreateConVar = MemoryAddress(0x140470540); // Get CreateConvar address. + + ConVar* allocatedConvar = reinterpret_cast<ConVar*>(addr_MemAlloc_Wrapper(0xA0)); // Allocate new memory with StdMemAlloc else we crash. + memset(allocatedConvar, 0, 0xA0); // Set all to null. + std::uintptr_t cvarPtr = reinterpret_cast<std::uintptr_t>(allocatedConvar); // To ptr. + + *(void**)(cvarPtr + 0x40) = ICvarVtable.RCast<void*>(); // 0x40 to ICvar table. + *(void**)cvarPtr = ConVarVtable.RCast<void*>(); // 0x0 to ConVar table. + + CreateConVar.RCast<void(*)(ConVar*, const char*, const char*, int, const char*, bool, float, bool, float, void*, void*)>() // Call to create ConVar. + (allocatedConvar, name, defaultValue, flags, helpString, bMin, fMin, bMax, fMax, callback, unk); + + return allocatedConvar; // Return allocated ConVar. + } } \ No newline at end of file diff --git a/r5dev/src/gui_utility.cpp b/r5dev/src/gui_utility.cpp index b1210854..e991c749 100644 --- a/r5dev/src/gui_utility.cpp +++ b/r5dev/src/gui_utility.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "gui_utility.h" +GuiConfig g_GuiConfig; /*----------------------------------------------------------------------------- * _gui_utility.cpp @@ -40,4 +41,4 @@ void Strtrim(char* s) while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; -} +} \ No newline at end of file diff --git a/r5dev/src/id3dx.cpp b/r5dev/src/id3dx.cpp index 31962ca3..827838f0 100644 --- a/r5dev/src/id3dx.cpp +++ b/r5dev/src/id3dx.cpp @@ -56,17 +56,14 @@ LRESULT CALLBACK DXGIMsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK HwndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - if (uMsg == WM_KEYDOWN) + if (uMsg == WM_KEYUP || uMsg == WM_SYSKEYDOWN) { - if (wParam == VK_OEM_3 || wParam == VK_INSERT) // For everyone without a US keyboard layout. + if (wParam == g_GuiConfig.CGameConsoleConfig.bind1 || wParam == g_GuiConfig.CGameConsoleConfig.bind2) { g_bShowConsole = !g_bShowConsole; } - } - if (uMsg == WM_SYSKEYDOWN) - { - if (wParam == VK_F10) + if (wParam == g_GuiConfig.CCompanionConfig.bind1 || wParam == g_GuiConfig.CCompanionConfig.bind2) { g_bShowBrowser = !g_bShowBrowser; } diff --git a/shared/include/address.h b/shared/include/address.h index a595bc55..b3cc6c22 100644 --- a/shared/include/address.h +++ b/shared/include/address.h @@ -284,7 +284,7 @@ public: return ResolveRelativeAddressSelf(opcodeOffset, nextInstructionOffset); } - MemoryAddress ResolveRelativeAddressSelf(std::ptrdiff_t registerOffset = 0x1, std::ptrdiff_t nextInstructionOffset = 0x4) + MemoryAddress ResolveRelativeAddressSelf(std::ptrdiff_t registerOffset = 0x0, std::ptrdiff_t nextInstructionOffset = 0x4) { // Skip register. std::uintptr_t skipRegister = ptr + registerOffset; @@ -300,7 +300,7 @@ public: return *this; } - MemoryAddress ResolveRelativeAddress(std::ptrdiff_t registerOffset = 0x1, std::ptrdiff_t nextInstructionOffset = 0x4) + MemoryAddress ResolveRelativeAddress(std::ptrdiff_t registerOffset = 0x0, std::ptrdiff_t nextInstructionOffset = 0x4) { // Skip register. std::uintptr_t skipRegister = ptr + registerOffset; diff --git a/shared/include/utility.h b/shared/include/utility.h index cc27fa9e..c2075066 100644 --- a/shared/include/utility.h +++ b/shared/include/utility.h @@ -4,7 +4,6 @@ // Internals BOOL FileExists(LPCTSTR szPath); MODULEINFO GetModuleInfo(const char* szModule); -std::uint8_t* PatternScan(const char* module, const char* signature); ///////////////////////////////////////////////////////////////////////////// // Utility