Forward console output to in-game console

Light cleanup. Hook RSON loading for debugging and improvements for console overlay.

TODO: fix thread lock on concomand execute from Present(..)
This commit is contained in:
Amos 2021-06-16 16:43:03 -07:00
parent d424c75081
commit cb0e72fc0a
8 changed files with 142 additions and 37 deletions

View File

@ -1,9 +1,17 @@
#pragma once
/////////////////////////////////////////////////////////////////////////////
// Initialization
void SetupConsole();
/////////////////////////////////////////////////////////////////////////////
// Hooks
bool Hook_ConVar_IsFlagSet(int** cvar, int flag);
bool Hook_ConCommand_IsFlagSet(int* cmd, int flag);
/////////////////////////////////////////////////////////////////////////////
// Globals
inline bool g_bDebugConsole = false;
inline bool g_bReturnAllFalse = false;
/////////////////////////////////////////////////////////////////////////////

View File

@ -1,8 +1,14 @@
#pragma once
/////////////////////////////////////////////////////////////////////////////
// Initialization
void InstallHooks();
void RemoveHooks();
void ToggleDevCommands();
void ToggleNetHooks();
/////////////////////////////////////////////////////////////////////////////
// Globals
inline bool g_bDebugLog = false;
/////////////////////////////////////////////////////////////////////////////

View File

@ -9,7 +9,7 @@ void DrawImGui();
void DestroyRenderTarget();
/////////////////////////////////////////////////////////////////////////////
// Management
// Internals
void PrintDXAddress();
void InstallDXHooks();
void RemoveDXHooks();
@ -22,3 +22,5 @@ extern HRESULT __stdcall Present(IDXGISwapChain* pSwapChain, UINT nSyncInterval,
/////////////////////////////////////////////////////////////////////////////
// Globals
extern DWORD g_dThreadId;
/////////////////////////////////////////////////////////////////////////////

View File

@ -1,15 +1,22 @@
#pragma once
#include "imgui.h"
/////////////////////////////////////////////////////////////////////////////
// Initialization
void PrintDXAddress();
void InstallDXHooks();
void RemoveDXHooks();
void ShowGameConsole(bool* p_open);
extern ImVector<char*> Items;
/////////////////////////////////////////////////////////////////////////////
// Utility
static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; }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) { s1++; s2++; n--; }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) { 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; }
static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
/////////////////////////////////////////////////////////////////////////////
// Globals
inline ImVector<char*> Items;
/////////////////////////////////////////////////////////////////////////////

View File

@ -23,6 +23,9 @@ namespace
//DWORD64 p_SQVM_LoadScript = FindPattern("r5apex.exe", "\x48\x8B\xC4\x48\x89\x48\x08\x55\x41\x56\x48\x8D\x68", "xxxxxxxxxxxxx"); // For anything S2 and above (current S8)
bool (*SQVM_LoadScript)(void* sqvm, const char* script_path, const char* script_name, int flag) = (bool (*)(void*, const char*, const char*, int))p_SQVM_LoadScript; /*E8 ?? ?? ?? ?? 84 C0 74 1C 41 B9 ?? ?? ?? ??*/
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,7 +36,7 @@ namespace
/* ==== 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
void (*SetCursorPosition)(int a1, INT64 posX, INT64 posY) = (void (*)(int, INT64, INT64))p_SetCursorPosition; /*48 85 D2 0F ?? ?? ?? ?? ?? 48 89 6C 24 ?? 56 48 83 EC 40 4C*/
void (*SetCursorPosition)(INT64 nFlag, LONG posX, LONG posY) = (void (*)(INT64, LONG, LONG))p_SetCursorPosition; /*48 85 D2 0F ?? ?? ?? ?? ?? 48 89 6C 24 ?? 56 48 83 EC 40 4C*/
//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*/
@ -42,20 +45,21 @@ namespace
void PrintHAddress() // Test the sigscan results
{
std::cout << "--------------------------------------------------" << std::endl;
std::cout << " p_CommandExecute : " << std::hex << p_CommandExecute << std::endl;
std::cout << " p_ConVar_IsFlagSet : " << std::hex << p_ConVar_IsFlagSet << std::endl;
std::cout << " p_ConCommand_IsFlagSet : " << std::hex << p_ConCommand_IsFlagSet << std::endl;
std::cout << "--------------------------------------------------" << std::endl;
std::cout << " p_SQVM_Print : " << std::hex << p_SQVM_Print << std::endl;
std::cout << " p_SQVM_LoadScript : " << std::hex << p_SQVM_LoadScript << std::endl;
std::cout << "--------------------------------------------------" << std::endl;
std::cout << " p_NET_ReceiveDatagram : " << std::hex << p_NET_ReceiveDatagram << std::endl;
std::cout << " p_NET_SendDatagram : " << std::hex << p_NET_SendDatagram << std::endl;
std::cout << "--------------------------------------------------" << std::endl;
std::cout << " p_SetCursorPosition : " << std::hex << p_SetCursorPosition << std::endl;
//std::cout << " p_GameWindowProc : " << std::hex << p_GameWindowProc << std::endl;
std::cout << "--------------------------------------------------" << std::endl;
std::cout << "+--------------------------------------------------------+" << std::endl;
std::cout << "| p_CommandExecute : " << std::hex << p_CommandExecute << std::endl;
std::cout << "| p_ConVar_IsFlagSet : " << std::hex << p_ConVar_IsFlagSet << std::endl;
std::cout << "| p_ConCommand_IsFlagSet : " << std::hex << p_ConCommand_IsFlagSet << std::endl;
std::cout << "+--------------------------------------------------------+" << std::endl;
std::cout << "| p_SQVM_Print : " << std::hex << p_SQVM_Print << std::endl;
std::cout << "| p_SQVM_LoadScript : " << std::hex << p_SQVM_LoadScript << std::endl;
std::cout << "| p_SQVM_LoadRson : " << std::hex << p_SQVM_LoadRson << std::endl;
std::cout << "+--------------------------------------------------------+" << std::endl;
std::cout << "| p_NET_ReceiveDatagram : " << std::hex << p_NET_ReceiveDatagram << std::endl;
std::cout << "| p_NET_SendDatagram : " << std::hex << p_NET_SendDatagram << std::endl;
std::cout << "+--------------------------------------------------------+" << std::endl;
std::cout << "| p_SetCursorPosition : " << std::hex << p_SetCursorPosition << std::endl;
//std::cout << "| p_GameWindowProc : " << std::hex << p_GameWindowProc << std::endl;
std::cout << "+--------------------------------------------------------+" << std::endl;
// TODO implement error handling when sigscan fails or result is 0
}

View File

@ -2,9 +2,15 @@
#include <Windows.h>
#include <Psapi.h>
/////////////////////////////////////////////////////////////////////////////
// Internals
BOOL FileExists(LPCTSTR szPath);
MODULEINFO GetModuleInfo(const char* szModule);
DWORD64 FindPattern(const char* szModule, const unsigned char* szPattern, const char* szMask);
/////////////////////////////////////////////////////////////////////////////
// Utility
void DbgPrint(LPCSTR sFormat, ...);
void HexDump(const char* szHeader, const char* szFile, const char* szMode, int nFunc, const void* pData, int nSize);
/////////////////////////////////////////////////////////////////////////////

View File

@ -8,6 +8,7 @@
#include "utility.h"
#include "structs.h"
#include "console.h"
#include "overlay.h"
#include "hooks.h"
//---------------------------------------------------------------------------------
@ -42,18 +43,32 @@ unsigned int Hook_NET_SendDatagram(SOCKET s, const char* buf, int len, int flags
}
//---------------------------------------------------------------------------------
// SQVM
// SquirrelVM
//---------------------------------------------------------------------------------
void* Hook_SQVM_Print(void* sqvm, char* fmt, ...)
{
char buf[1024];
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
buf[IM_ARRAYSIZE(buf) - 1] = 0;
va_end(args);
Items.push_back(Strdup(buf));
return NULL;
}
__int64 Hook_SQVM_LoadRson(const char* rson_name)
{
printf("\n");
printf("##################################################\n");
printf("] '%s'\n", rson_name);
printf("##################################################\n");
printf("\n");
return SQVM_LoadRson(rson_name);
}
bool Hook_SQVM_LoadScript(void* sqvm, const char* script_path, const char* script_name, int flag)
{
char filepath[MAX_PATH] = { 0 };
@ -90,6 +105,7 @@ void InstallHooks()
// 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
@ -108,6 +124,7 @@ void RemoveHooks()
// 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);

View File

@ -19,13 +19,10 @@
* _overlay.cpp
*-----------------------------------------------------------------------------*/
ImVector<char*> Items;
class CGameConsole
{
private:
char InputBuf[256];
//ImVector<char*> Items;
ImVector<const char*> Commands;
ImVector<char*> History;
int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
@ -59,6 +56,38 @@ public:
/////////////////////////////////////////////////////////////////////////////
// Helpers
static int Stricmp(const char* s1, const char* s2)
{
int d;
while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1)
{
s1++; s2++;
}
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)
{
s1++; s2++; n--;
}
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)
{
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;
}
void ClearLog()
{
for (int i = 0; i < Items.Size; i++) { free(Items[i]); }
@ -81,23 +110,15 @@ public:
// Draw
void Draw(const char* title, bool* p_open)
{
ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
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())
{
if (ImGui::MenuItem("Close Console")) { *p_open = false; }
ImGui::EndPopup();
}
if (ImGui::SmallButton("Netchan Trace"))
{
ToggleNetHooks();
AddLog("+--------------------------------------------------------+\n");
AddLog("|>>>>>>>>>>>>>>| NETCHANNEL TRACE TOGGLED |<<<<<<<<<<<<<<|\n");
AddLog("+--------------------------------------------------------+\n");
ExecCommand("exec netchan");
}
ImGui::SameLine();
if (ImGui::SmallButton("Flag Override"))
if (ImGui::SmallButton("Developer mode"))
{
ToggleDevCommands();
AddLog("+--------------------------------------------------------+\n");
@ -105,6 +126,15 @@ public:
AddLog("+--------------------------------------------------------+\n");
ExecCommand("exec autoexec");
}
ImGui::SameLine();
if (ImGui::SmallButton("Netchannel Trace"))
{
ToggleNetHooks();
AddLog("+--------------------------------------------------------+\n");
AddLog("|>>>>>>>>>>>>>>| NETCHANNEL TRACE TOGGLED |<<<<<<<<<<<<<<|\n");
AddLog("+--------------------------------------------------------+\n");
ExecCommand("exec netchan");
}
/////////////////////////////////////////////////////////////////////////
ImGui::SameLine();
@ -138,12 +168,37 @@ public:
/////////////////////////////////////////////////////////////////////////
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; }
if (strstr(item, "[DEBUG]")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; }
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; }
// Filters
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);
if (has_color) { ImGui::PopStyleColor(); }
@ -158,7 +213,7 @@ public:
void SetStyleVar();
{
ImVec4* colors = ImGui::GetStyle().Colors;
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 0.50f);
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f);
colors[ImGuiCol_TextDisabled] = ImVec4(1.00f, 1.00f, 1.00f, 0.40f);
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 1.00f);
//colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.86f);
@ -232,7 +287,7 @@ public:
// Console
bool reclaim_focus = false;
bool clear_inputbuf = false;
ImGui::PushItemWidth(600);
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))