Read description for all changes.

* Added ability to register custom ConVar.
* Added 2 custom ConVars to open the CGameConsole and CCompanion Windows.
* Changed ResolveRelativeAddress.
* Added Config System for the Gui.
* Added ImGui::Hotkey.
* Added the ability to change 2 hotkeys for opening the window for CGameConsole and CCompanion.
* Changed pattern for Squirrel_CompilerError to use a String.
* Added IMemAlloc::AllocWrapper to patterns.h
This commit is contained in:
IcePixelx 2021-08-19 01:27:44 +02:00
parent 06127dee1d
commit 70b4c02a9a
13 changed files with 535 additions and 14 deletions

View File

@ -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.

View File

@ -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

View File

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

View File

@ -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;

View File

@ -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

View File

@ -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
}

View File

@ -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"))

View File

@ -15,6 +15,7 @@ void InitializeR5Dev()
SetupConsole();
Hooks::InstallHooks();
InstallOpcodes();
g_GuiConfig.Load(); // Load gui config.
SetupDXSwapChain();
printf("+-----------------------------------------------------------------------------+\n");
printf("| R5 DEV -- INITIALIZED ------------------------------------------------- |\n");

View File

@ -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.
}
}

View File

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

View File

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

View File

@ -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;

View File

@ -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