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
This commit is contained in:
Amos 2021-06-17 17:07:26 -07:00
parent 181f88d902
commit 62a0b5cebb
12 changed files with 180 additions and 121 deletions

View File

@ -22,5 +22,6 @@ extern HRESULT __stdcall Present(IDXGISwapChain* pSwapChain, UINT nSyncInterval,
/////////////////////////////////////////////////////////////////////////////
// Globals
extern DWORD g_dThreadId;
extern BOOL g_bShowMenu;
/////////////////////////////////////////////////////////////////////////////

View File

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

View File

@ -24,6 +24,7 @@
<ProjectGuid>{28cc6b4f-7a95-4933-ada9-65e38d48516d}</ProjectGuid>
<RootNamespace>r5dev</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>r5dev</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -51,6 +52,7 @@
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -176,8 +178,7 @@
<AdditionalDependencies>detours.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>
</Command>
<Command>del "$(TargetDir)\r5detours.dll" &amp;&amp; rename "$(TargetPath)" "r5detours.dll"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>

View File

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

View File

@ -30,7 +30,7 @@ void TerminateR5Dev()
}
//---------------------------------------------------------------------------------
// Main
// Entry
//---------------------------------------------------------------------------------
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)

View File

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

View File

@ -26,13 +26,12 @@ 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;
extern BOOL g_bShowMenu = false;
static BOOL g_bInitialized = false;
static BOOL g_bPresentHooked = false;
static BOOL g_bListener[256] = { 0 };
static HWND g_hGameWindow = NULL;
static WNDPROC g_oWndProc = NULL;
static HWND g_hGameWindow = NULL;
extern DWORD g_dThreadId = NULL;
///////////////////////////////////////////////////////////////////////////////////
@ -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);
}

View File

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

View File

@ -22,30 +22,32 @@
class CGameConsole
{
private:
char InputBuf[256];
///////////////////////////////////////////////////////////////////////////
char InputBuf[256] = { 0 };
ImVector<const char*> Commands;
ImVector<char*> History;
int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
int HistoryPos = -1;
ImGuiTextFilter Filter;
bool AutoScroll;
bool ScrollToBottom;
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,15 +196,22 @@ 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; }
///////////////////////////////////////////////////////////////////
// Callbacks
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 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; }
@ -193,14 +220,13 @@ public:
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);
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();
{
@ -279,25 +305,26 @@ public:
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;

View File

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

View File

@ -3,8 +3,13 @@
#include <Windows.h>
#include <detours.h>
/*-----------------------------------------------------------------------------
* _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,6 +117,8 @@ bool LaunchR5Apex()
return true;
}
///////////////////////////////////////////////////////////////////////////////
// Entry point.
int main(int argc, char* argv[], char* envp[])
{
LaunchR5Apex();

View File

@ -51,6 +51,7 @@
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -158,8 +159,7 @@
<AdditionalDependencies>detours.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>
</Command>
<Command>del "$(TargetDir)\launcher.exe" &amp;&amp; rename "$(TargetPath)" "launcher.exe"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>