Read description for changes.

* Completely re-wrote the DirectX creation and hooks.
* Using spdlog mostly everywhere now.
* Added prints for when compiled in debug.
* Using LockCursor now to prevent input to the game while in the gui.
* Patched the game to call CMatSystemSurface::LockCursor instead of it calling the inlined version.
* Added rebuild CHostState::FrameUpdate (Not finished yet)
* Added option to print to command prompt again.
* Added log Auto-Clear.
* Added scan for NetChan Encryption Key Pointer.
* Added more error handling when loading gui config.
This commit is contained in:
IcePixelx 2021-10-05 00:25:58 +02:00
parent 27536741f8
commit 17d45a02aa
21 changed files with 695 additions and 483 deletions

View File

@ -8,7 +8,7 @@ void DrawConsole();
///////////////////////////////////////////////////////////////////////////////
// Globals
inline ImVector<char*> Items;
extern ImVector<char*> Items;
class CGameConsole
{
@ -33,6 +33,7 @@ public:
void ProcessCommand(const char* command_line);
void ExecCommand(const char* command_line);
int TextEditCallback(ImGuiInputTextCallbackData* data);
bool ShouldPrintToCommandPrompt() { return g_GuiConfig.CGameConsoleConfig.printCmd; };
///////////////////////////////////////////////////////////////////////////
// History
@ -46,9 +47,9 @@ public:
// Utility
void ClearLog()
{
for (int i = 0; i < Items.Size; i++) { free(Items[i]); }
Items.clear();
}
void AddLog(const char* fmt, ...) IM_FMTARGS(2)
{
char buf[1024];

View File

@ -332,7 +332,7 @@ enum ClientFrameStage_t
FRAME_NET_FULL_FRAME_UPDATE_ON_REMOVE
};
enum HostStates_t
enum class HostStates_t : int
{
HS_NEW_GAME = 0x0,
HS_LOAD_GAME = 0x1,

View File

@ -239,8 +239,8 @@ struct QAngle // Implement the proper class of this at some point.
class CHostState
{
public:
int m_iCurrentState; //0x0000
int m_iNextState; //0x0004
HostStates_t m_iCurrentState; //0x0000
HostStates_t m_iNextState; //0x0004
Vector3 m_vecLocation; //0x0008
QAngle m_angLocation; //0x0014
char m_levelName[64]; //0x0020

View File

@ -14,6 +14,9 @@ public:
{
int bind1 = VK_OEM_3;
int bind2 = VK_INSERT;
int autoClearLimit = 300;
bool autoClear = true;
bool printCmd = false;
} CGameConsoleConfig;
struct
@ -24,13 +27,13 @@ public:
void Load()
{
spdlog::debug("Loading the Gui Config..\n");
std::filesystem::path path = std::filesystem::current_path() /= "gui.config"; // Get current path + gui.config
nlohmann::json in;
std::ifstream configFile(path, std::ios::in); // Parse config file.
if (configFile.good() && configFile) // Check if it parsed.
try
{
std::ifstream configFile(path, std::ios::binary); // Parse config file.
configFile >> in;
configFile.close();
@ -41,6 +44,9 @@ public:
// CGameConsole
CGameConsoleConfig.bind1 = in["config"]["CGameConsole"]["bind1"].get<int>();
CGameConsoleConfig.bind2 = in["config"]["CGameConsole"]["bind2"].get<int>();
CGameConsoleConfig.autoClearLimit = in["config"]["CGameConsole"]["autoClearLimit"].get<int>();
CGameConsoleConfig.autoClear = in["config"]["CGameConsole"]["autoClear"].get<bool>();
CGameConsoleConfig.printCmd = in["config"]["CGameConsole"]["printCmd"].get<bool>();
// CCompanion
CCompanionConfig.bind1 = in["config"]["CCompanion"]["bind1"].get<int>();
@ -48,6 +54,11 @@ public:
}
}
}
catch (const std::exception& ex)
{
spdlog::critical("Gui Config loading failed. Perhaps re-create it by messing with Options in CGameConsole. Reason: {}\n", ex.what());
return;
}
}
void Save()
@ -57,6 +68,9 @@ public:
// CGameConsole
out["config"]["CGameConsole"]["bind1"] = CGameConsoleConfig.bind1;
out["config"]["CGameConsole"]["bind2"] = CGameConsoleConfig.bind2;
out["config"]["CGameConsole"]["autoClearLimit"] = CGameConsoleConfig.autoClearLimit;
out["config"]["CGameConsole"]["autoClear"] = CGameConsoleConfig.autoClear;
out["config"]["CGameConsole"]["printCmd"] = CGameConsoleConfig.printCmd;
// CCompanion
out["config"]["CCompanion"]["bind1"] = CCompanionConfig.bind1;

View File

@ -87,6 +87,13 @@ namespace Hooks
extern ConCommand_IsFlagSetFn originalConCommand_IsFlagSet;
#pragma endregion
#pragma region CMatSystemSurface
void LockCursor(void* thisptr);
using LockCursorFn = void(*)(void*);
extern LockCursorFn originalLockCursor;
#pragma endregion
#pragma region WinAPI
BOOL WINAPI GetCursorPos(LPPOINT lpPoint);
BOOL WINAPI SetCursorPos(int X, int Y);
@ -113,6 +120,13 @@ namespace Hooks
extern FileSystemWarningFn originalFileSystemWarning;
#pragma endregion
#pragma region HostState
void FrameUpdate(void* rcx, void* rdx, float time);
using FrameUpdateFn = void(*)(void*, void*, float);
extern FrameUpdateFn originalFrameUpdate;
#pragma endregion
#pragma region Other
int MSG_EngineError(char* fmt, va_list args);
bool LoadPlaylist(const char* playlist);

View File

@ -2,10 +2,7 @@
/////////////////////////////////////////////////////////////////////////////
// Initialization
void SetupImGui();
void SetupDXSwapChain();
void DrawImGui();
void DestroyRenderTarget();
/////////////////////////////////////////////////////////////////////////////
// Internals
@ -17,16 +14,14 @@ void RemoveDXHooks();
// Handlers
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
extern HRESULT __stdcall Present(IDXGISwapChain* pSwapChain, UINT nSyncInterval, UINT nFlags);
extern HRESULT __stdcall GetResizeBuffers(IDXGISwapChain* pSwapChain, UINT nBufferCount, UINT nWidth, UINT nHeight, DXGI_FORMAT dxFormat, UINT nSwapChainFlags);
/////////////////////////////////////////////////////////////////////////////
// Globals
extern DWORD g_dThreadId;
extern BOOL g_bShowConsole;
extern BOOL g_bShowBrowser;
extern bool g_bShowConsole;
extern bool g_bShowBrowser;
/////////////////////////////////////////////////////////////////////////////
//#################################################################################
// UTILS
//#################################################################################
// Utils
bool LoadTextureFromByteArray(unsigned char* image_data, const int& image_width, const int& image_height, ID3D11ShaderResourceView** out_srv);

View File

@ -80,8 +80,8 @@ namespace
FUNC_AT_ADDRESS(addr_NetChan_Shutdown, void(*)(void*, const char*, unsigned __int8, char), r5_patterns.StringSearch("Disconnect by server.\n").FindPatternSelf("E8 ? ? ? ? 4C 89 B3 ? ? ? ?", MemoryAddress::Direction::DOWN).FollowNearCallSelf().GetPtr());
/*0x160686DC0*/
MemoryAddress addr_NetChan_EncKeyPtr = MemoryAddress(0x160686DC0);
char* addr_NetChan_EncKey = addr_NetChan_EncKeyPtr.Offset(4816).RCast<char*>();
MemoryAddress addr_NetChan_EncKeyPtr = r5_patterns.StringSearch("client:NetEncryption_NewKey").FindPatternSelf("48 8D ? ? ? ? ? 48 3B", MemoryAddress::Direction::UP, 150).ResolveRelativeAddressSelf(0x3, 0x7);
char* addr_NetChan_EncKey = addr_NetChan_EncKeyPtr.Offset(0x12D0).RCast<char*>();
/*0x140263E70*/
FUNC_AT_ADDRESS(addr_NetChan_SetEncKey, void(*)(uintptr_t, const char*), MemoryAddress(0x140263E70).GetPtr());
@ -121,6 +121,12 @@ namespace
FUNC_AT_ADDRESS(addr_CBaseFileSystem_FileSystemWarning, void(*)(void*, FileWarningLevel_t, const char*, ...), r5_patterns.PatternSearch("E8 ? ? ? ? 33 C0 80 3B 2A").FollowNearCallSelf().GetPtr());
#pragma endregion
#pragma region CMatSystemSurface
/*0x140548A00*/
FUNC_AT_ADDRESS(addr_CMatSystemSurface_LockCursor, void(*)(void*), MemoryAddress(0x140548A00).GetPtr()); // Maybe sigscan this via RTTI.
/*0x1405489C0*/
FUNC_AT_ADDRESS(addr_CMatSystemSurface_UnlockCursor, void(*)(void*), MemoryAddress(0x1405489C0).GetPtr()); // Maybe sigscan this via RTTI.
#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());
@ -174,7 +180,7 @@ namespace
PRINT_ADDRESS("CClient::Clear", addr_CClient_Clear);
PRINT_ADDRESS("INetChannel::Shutdown", addr_NetChan_Shutdown);
PRINT_ADDRESS("INetChannel::SetEncryptionKey", addr_NetChan_SetEncKey);
PRINT_ADDRESS("INetChannel::EncryptionKey", addr_NetChan_EncKey)
PRINT_ADDRESS("INetChannel::EncryptionKey", addr_NetChan_EncKey);
PRINT_ADDRESS("CHLClient::FrameStageNotify", addr_CHLClient_FrameStageNotify);
PRINT_ADDRESS("CVEngineServer::IsPersistenceDataAvailable", addr_CVEngineServer_IsPersistenceDataAvailable);
PRINT_ADDRESS("CServer::ConnectClient", addr_CServer_ConnectClient);

View File

@ -388,8 +388,10 @@ if not EXIST $(SolutionDir)r5net\lib\$(Configuration)\r5net.lib (
<ClCompile Include="src\hooks\connectclient.cpp" />
<ClCompile Include="src\hooks\cvengineserver.cpp" />
<ClCompile Include="src\hooks\hooks.cpp" />
<ClCompile Include="src\hooks\hoststate.cpp" />
<ClCompile Include="src\hooks\iconvar.cpp" />
<ClCompile Include="src\hooks\loadplaylist.cpp" />
<ClCompile Include="src\hooks\lockcursor.cpp" />
<ClCompile Include="src\hooks\msgbox.cpp" />
<ClCompile Include="src\hooks\net.cpp" />
<ClCompile Include="src\hooks\netchannel.cpp" />

View File

@ -106,6 +106,12 @@
<Filter Include="hooks\src\cserver">
<UniqueIdentifier>{10edfee7-8c10-41de-b8f3-424826d2614a}</UniqueIdentifier>
</Filter>
<Filter Include="hooks\src\hoststate">
<UniqueIdentifier>{02d83321-09fe-4a60-86d9-b1e8d5e165f4}</UniqueIdentifier>
</Filter>
<Filter Include="hooks\src\cmatsystemsurface">
<UniqueIdentifier>{a2663195-c4f2-4d5f-8d65-cfed54976e4c}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\dllmain.cpp">
@ -204,6 +210,12 @@
<ClCompile Include="src\squirrel.cpp">
<Filter>r5-sdk\src</Filter>
</ClCompile>
<ClCompile Include="src\hooks\hoststate.cpp">
<Filter>hooks\src\hoststate</Filter>
</ClCompile>
<ClCompile Include="src\hooks\lockcursor.cpp">
<Filter>hooks\src\cmatsystemsurface</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\external\imgui\include\imgui_impl_win32.h">

View File

@ -7,8 +7,6 @@
#include "CCompanion.h"
#include "r5net.h"
//#define OVERLAY_DEBUG
CCompanion* g_ServerBrowser = nullptr;
bool g_CheckCompBanDB = true;
@ -92,16 +90,17 @@ void CCompanion::UpdateHostingStatus()
if (*reinterpret_cast<std::int32_t*>(0x1656057E0) == NULL) // Check if script checksum is valid yet.
break;
switch (ServerVisibility) {
switch (ServerVisibility)
{
case EServerVisibility::Hidden:
MyServer.hidden = true;
break;
break;
case EServerVisibility::Public:
MyServer.hidden = false;
break;
default:
break;
}
SendHostingPostRequest();
@ -122,9 +121,7 @@ void CCompanion::RefreshServerList()
{
std::thread t([this]()
{
#ifdef OVERLAY_DEBUG
std::cout << " [+CCompanion+] Refreshing server list with string " << MatchmakingServerStringBuffer << "\n";
#endif
spdlog::debug("[+CCompanion+] Refreshing server list with string {}\n", MatchmakingServerStringBuffer);
bThreadLocked = true;
ServerList = r5net->GetServersList(ServerListMessage);
bThreadLocked = false;
@ -137,6 +134,7 @@ void CCompanion::RefreshServerList()
void CCompanion::SendHostingPostRequest()
{
HostToken = std::string();
spdlog::debug("[+CCompanion+] Sending PostServerHost request now..\n");
bool result = r5net->PostServerHost(HostRequestMessage,HostToken,
ServerListing{
MyServer.name,
@ -255,10 +253,11 @@ void CCompanion::ServerBrowserSection()
{
ImGui::InputTextWithHint("##ServerBrowser_ServerConnString", "Enter IP address or \"localhost\"", ServerConnStringBuffer, IM_ARRAYSIZE(ServerConnStringBuffer));
ImGui::SameLine(); ImGui::InputTextWithHint("##ServerBrowser_ServerEncKey", "Enter the encryption key", ServerEncKeyBuffer, IM_ARRAYSIZE(ServerEncKeyBuffer));
ImGui::SameLine();
ImGui::InputTextWithHint("##ServerBrowser_ServerEncKey", "Enter the encryption key", ServerEncKeyBuffer, IM_ARRAYSIZE(ServerEncKeyBuffer));
ImGui::SameLine();
if (ImGui::SameLine(); ImGui::Button("Connect##ServerBrowser_ConnectByIp", ImVec2(ImGui::GetWindowContentRegionWidth() / 4, 18.5)))
if (ImGui::Button("Connect##ServerBrowser_ConnectByIp", ImVec2(ImGui::GetWindowContentRegionWidth() / 4, 18.5)))
{
ConnectToServer(ServerConnStringBuffer, ServerEncKeyBuffer);
}
@ -274,8 +273,6 @@ void CCompanion::ServerBrowserSection()
}
ImGui::PopItemWidth();
}
void CCompanion::HiddenServersModal()
@ -465,6 +462,7 @@ void CCompanion::HostServerSection()
{
if (!MyServer.name.empty() && !MyServer.playlist.empty())
{
spdlog::debug("[+CCompanion+] Starting Server with name {}, map {} and playlist {}..\n", MyServer.name, ServerMap, MyServer.playlist);
ServerNameErr = std::string();
UpdateHostingStatus();
@ -482,11 +480,6 @@ void CCompanion::HostServerSection()
std::stringstream cmd;
cmd << "map " << ServerMap;
ProcessCommand(cmd.str().c_str());
if (StartAsDedi)
{
Hooks::ToggleDevCommands();
}
}
else
{
@ -512,18 +505,21 @@ void CCompanion::HostServerSection()
{
if (ImGui::Button("Reload Scripts##ServerHost_ReloadServerButton", ImVec2(ImGui::GetWindowSize().x, 32)))
{
spdlog::debug("[+CCompanion+] Reloading scripts..\n");
ProcessCommand("reparse_weapons");
ProcessCommand("reload");
}
if (ImGui::Button("Change Level##ServerHost_ChangeLevel", ImVec2(ImGui::GetWindowSize().x, 32)))
{
spdlog::debug("[+CCompanion+] Changing level to {}..\n", ServerMap);
strncpy_s(GameGlobals::HostState->m_levelName, ServerMap.c_str(), 64); // Copy new map into hoststate levelname. 64 is size of m_levelname.
GameGlobals::HostState->m_iNextState = HostStates_t::HS_CHANGE_LEVEL_MP; // Force CHostState::FrameUpdate to change the level.
}
if (ImGui::Button("Stop Server##ServerHost_StopServerButton", ImVec2(ImGui::GetWindowSize().x, 32)))
{
spdlog::debug("[+CCompanion+] Stopping server..\n");
ProcessCommand("LeaveMatch"); // Use script callback instead.
GameGlobals::HostState->m_iNextState = HostStates_t::HS_GAME_SHUTDOWN; // Force CHostState::FrameUpdate to shutdown the server for dedicated.
}
@ -594,6 +590,7 @@ void CCompanion::Draw(const char* title)
void CCompanion::ProcessCommand(const char* command_line)
{
spdlog::debug("[+CCompanion+] Processing command {}\n", command_line);
std::thread t(&CCompanion::ExecCommand, this, command_line);
t.detach();
@ -635,15 +632,16 @@ void CCompanion::ConnectToServer(const std::string connString, const std::string
void CCompanion::RegenerateEncryptionKey()
{
spdlog::debug("[+CCompanion+] Regenerating Encryption Key..\n");
BCRYPT_ALG_HANDLE hAlgorithm;
if (BCryptOpenAlgorithmProvider(&hAlgorithm, L"RNG", 0, 0) < 0)
{
std::cerr << "Failed to open rng algorithm\n";
spdlog::critical("[+CCompanion+] Failed to open rng algorithm\n");
}
unsigned char pBuffer[0x10u];
if (BCryptGenRandom(hAlgorithm, pBuffer, 0x10u, 0) < 0)
{
std::cerr << "Failed to generate random data\n";
spdlog::critical("[+CCompanion+] Failed to generate random data\n");
}
std::string fin;
@ -671,6 +669,7 @@ void DrawBrowser()
static CCompanion browser;
static bool AssignPtr = []() {
g_ServerBrowser = &browser;
spdlog::debug("[+CCompanion+] Created CCompanion Class instance.\n");
return true;
} ();

View File

@ -6,9 +6,8 @@
#include "gameclasses.h"
#include "CGameConsole.h"
#define OVERLAY_DEBUG
CGameConsole* g_GameConsole = nullptr;
ImVector<char*> Items;
/*-----------------------------------------------------------------------------
* _cgameconsole.cpp
@ -35,17 +34,16 @@ CGameConsole::CGameConsole()
CGameConsole::~CGameConsole()
{
ClearLog();
for (int i = 0; i < History.Size; i++)
{
free(History[i]);
}
History.clear();
}
///////////////////////////////////////////////////////////////////////////
// Draw
void CGameConsole::Draw(const char* title)
{
bool copy_to_clipboard = false;
bool CopyToClipboard = false;
static auto cgameconsoleConfig = &g_GuiConfig.CGameConsoleConfig;
static auto ccompanionConfig = &g_GuiConfig.CCompanionConfig;
if (!ThemeSet)
{
@ -53,6 +51,12 @@ void CGameConsole::Draw(const char* title)
ThemeSet = true;
}
if (cgameconsoleConfig->autoClear && Items.Size > cgameconsoleConfig->autoClearLimit) // Check if Auto-Clear is enabled and if its above our limit. If yes then clear.
{
ClearLog();
History.clear();
}
//ImGui::ShowStyleEditor();
ImGui::SetNextWindowSize(ImVec2(1000, 600), ImGuiCond_FirstUseEver);
@ -60,7 +64,6 @@ void CGameConsole::Draw(const char* title)
ImGui::Begin(title, NULL); // ImGui::Begin should never fail, if it does we got another problem.
{
// Reserve enough left-over height and width for 1 separator + 1 input text
const float FooterHeightToReserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
const float FooterWidthtoReserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetWindowWidth();
@ -69,24 +72,38 @@ void CGameConsole::Draw(const char* title)
ImGui::Separator();
if (ImGui::BeginPopup("Options"))
{
ImGui::Checkbox("Auto-scroll", &AutoScroll);
if (ImGui::Checkbox("Print to Cmd", &cgameconsoleConfig->printCmd))
g_GuiConfig.Save();
ImGui::Checkbox("Auto-Scroll", &AutoScroll);
if (ImGui::Checkbox("Auto-Clear", &cgameconsoleConfig->autoClear))
g_GuiConfig.Save();
ImGui::SameLine();
ImGui::PushItemWidth(100);
if (ImGui::InputInt("Auto Clear Limit##AutoClearAfterCertainIndexCGameConsole", &cgameconsoleConfig->autoClearLimit))
g_GuiConfig.Save();
ImGui::PopItemWidth();
if (ImGui::SmallButton("Clear"))
{
ClearLog();
}
copy_to_clipboard = ImGui::SmallButton("Copy");
ImGui::SameLine();
CopyToClipboard = ImGui::SmallButton("Copy");
ImGui::Text("CG Hotkey:");
ImGui::SameLine();
if (ImGui::Hotkey("##OpenCGameConsoleBind1", &g_GuiConfig.CGameConsoleConfig.bind1, ImVec2(80, 80)))
{
if (ImGui::Hotkey("##OpenCGameConsoleBind1", &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)))
{
if (ImGui::Hotkey("##OpenCCompanionBind1", &ccompanionConfig->bind1, ImVec2(80, 80)))
g_GuiConfig.Save();
}
ImGui::EndPopup();
}
if (ImGui::Button("Options"))
@ -139,10 +156,11 @@ void CGameConsole::Draw(const char* title)
///////////////////////////////////////////////////////////////////////
ImGui::BeginChild("ScrollingRegion", ImVec2(0, -FooterHeightToReserve), true, ImGuiWindowFlags_AlwaysVerticalScrollbar);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 4.f, 6.f });
if (copy_to_clipboard)
if (CopyToClipboard)
{
ImGui::LogToClipboard();
}
for (int i = 0; i < Items.Size; i++)
{
const char* item = Items[i];
@ -214,12 +232,15 @@ void CGameConsole::Draw(const char* title)
}
}
if (copy_to_clipboard)
if (CopyToClipboard)
{
ImGui::LogFinish();
}
if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) { ImGui::SetScrollHereY(1.0f); }
if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
{
ImGui::SetScrollHereY(1.0f);
}
ScrollToBottom = false;
///////////////////////////////////////////////////////////////////////
@ -390,6 +411,7 @@ void DrawConsole()
static CGameConsole console;
static bool AssignPtr = []() {
g_GameConsole = &console;
spdlog::debug("[+CGameConsole+] Created CGameConsole Class instance.\n");
return true;
} ();
console.Draw("Console");

View File

@ -52,6 +52,16 @@ void SetupConsole()
printf("THREAD ID: %ld\n\n", threadId0);
CloseHandle(hThread0);
}
// Initialize global spdlog.
auto console = spdlog::stdout_logger_mt("console");
console->set_pattern("[%I:%M:%S:%e] [%L] %v"); // Set pattern.
spdlog::set_default_logger(console); // Set as default.
spdlog::flush_every(std::chrono::seconds(5)); // Flush buffers every 5 seconds for every logger.
#ifdef _DEBUG
console->set_level(spdlog::level::debug);
#endif
spdlog::debug("Console and spdlog are setup now!\n");
}
//#############################################################################

View File

@ -17,10 +17,12 @@ void InitializeR5Dev()
InstallOpcodes();
g_GuiConfig.Load(); // Load gui config.
SetupDXSwapChain();
printf("+-----------------------------------------------------------------------------+\n");
printf("| R5 DEV -- INITIALIZED ------------------------------------------------- |\n");
printf("+-----------------------------------------------------------------------------+\n");
printf("\n");
spdlog::get("console")->set_pattern("%v");
spdlog::info("+-----------------------------------------------------------------------------+\n");
spdlog::info("| R5 DEV -- INITIALIZED ------------------------------------------------- |\n");
spdlog::info("+-----------------------------------------------------------------------------+\n");
spdlog::get("console")->set_pattern("[%I:%M:%S:%e] [%L] %v");
}
void TerminateR5Dev()

View File

@ -326,6 +326,7 @@ namespace GameGlobals
void NullHostNames()
{
spdlog::debug("Nulling host names..\n");
const char* hostnameArray[] =
{
"pin_telemetry_hostname",
@ -356,6 +357,7 @@ namespace GameGlobals
void InitGameGlobals()
{
spdlog::debug("Initializing Game Globals..\n");
HostState = reinterpret_cast<CHostState*>(0x141736120); // Get CHostState from memory.
InputSystem = *reinterpret_cast<CInputSystem**>(0x14D40B380); // Get IInputSystem from memory.
Cvar = *reinterpret_cast<CCVar**>(0x14D40B348); // Get CCVar from memory.
@ -377,6 +379,7 @@ namespace GameGlobals
void InitPlaylist()
{
spdlog::debug("Parsing Playlist..\n");
while (true)
{
if ((*PlaylistKeyValues))
@ -400,6 +403,7 @@ namespace GameGlobals
void InitAllCommandVariations()
{
spdlog::debug("Initializing all Custom ConVars and Commands..\n");
void* CGameConsoleConCommand = CreateCustomConCommand("cgameconsole", "Opens the R5 Reloaded Console.", 0, CustomCommandVariations::CGameConsole_Callback, nullptr);
void* CCompanionConCommand = CreateCustomConCommand("ccompanion", "Opens the R5 Reloaded Server Browser.", 0, CustomCommandVariations::CCompanion_Callback, nullptr);
void* KickConCommand = CreateCustomConCommand("kick", "Kick a client from the Server via name. | Usage: kick (name).", 0, CustomCommandVariations::Kick_Callback, nullptr);

View File

@ -61,8 +61,6 @@ void* Hooks::ConnectClient(void* thisptr, void* packet)
finalIPAddress = ss.str();
}
R5Net::Client* r5net = g_ServerBrowser->GetR5Net();
const char* name = *(const char**)((std::uintptr_t)packet + 0x30);
std::int64_t originID = *(std::int64_t*)((std::uintptr_t)packet + 0x28);
@ -80,6 +78,7 @@ void* Hooks::ConnectClient(void* thisptr, void* packet)
if (g_CheckCompBanDB)
{
R5Net::Client* r5net = g_ServerBrowser->GetR5Net();
if (r5net)
{
std::thread t1(IsClientBanned, r5net, finalIPAddress, originID);

View File

@ -13,6 +13,7 @@ void Hooks::InstallHooks()
{
///////////////////////////////////////////////////////////////////////////////
// Initialize Minhook
spdlog::debug("Hooking game functions now..\n");
MH_Initialize();
///////////////////////////////////////////////////////////////////////////////
@ -25,7 +26,7 @@ void Hooks::InstallHooks()
MH_CreateHook(addr_SQVM_RegisterCreatePlayerTasklist, &Hooks::SQVM_RegisterCreatePlayerTasklist, reinterpret_cast<void**>(&originalSQVM_RegisterCreatePlayerTasklist));
///////////////////////////////////////////////////////////////////////////////
// Hook Game Functions
// Hook Game functions
MH_CreateHook(addr_CHLClient_FrameStageNotify, &Hooks::FrameStageNotify, reinterpret_cast<void**>(&originalFrameStageNotify));
MH_CreateHook(addr_CVEngineServer_IsPersistenceDataAvailable, &Hooks::IsPersistenceDataAvailable, reinterpret_cast<void**>(&originalIsPersistenceDataAvailable));
MH_CreateHook(addr_CServer_ConnectClient, &Hooks::ConnectClient, reinterpret_cast<void**>(&originalConnectClient));
@ -38,14 +39,22 @@ void Hooks::InstallHooks()
MH_CreateHook(addr_NetChan_Shutdown, &Hooks::NetChan_Shutdown, reinterpret_cast<void**>(&originalNetChan_ShutDown));
///////////////////////////////////////////////////////////////////////////////
// Hook ConVar | ConCommand functions.
// Hook ConVar | ConCommand functions
MH_CreateHook(addr_ConVar_IsFlagSet, &Hooks::ConVar_IsFlagSet, reinterpret_cast<void**>(&originalConVar_IsFlagSet));
MH_CreateHook(addr_ConCommand_IsFlagSet, &Hooks::ConCommand_IsFlagSet, reinterpret_cast<void**>(&originalConCommand_IsFlagSet));
///////////////////////////////////////////////////////////////////////////////
// Hooks CBaseFileSystem functions.
// Hook CMatSystemSurface functions
MH_CreateHook(addr_CMatSystemSurface_LockCursor, &LockCursor, reinterpret_cast<void**>(&originalLockCursor));
///////////////////////////////////////////////////////////////////////////////
// Hook CBaseFileSystem functions
//MH_CreateHook(addr_CBaseFileSystem_FileSystemWarning, &Hooks::FileSystemWarning, reinterpret_cast<void**>(&originalFileSystemWarning);
///////////////////////////////////////////////////////////////////////////////
// Hook HostState functions
//MH_CreateHook(MemoryAddress(0x14023EF80).RCast<void*>(), &Hooks::FrameUpdate, reinterpret_cast<void**>(&originalFrameUpdate));
///////////////////////////////////////////////////////////////////////////////
// Hook Utility functions
MH_CreateHook(addr_MSG_EngineError, &Hooks::MSG_EngineError, reinterpret_cast<void**>(&originalMSG_EngineError));
@ -59,12 +68,10 @@ void Hooks::InstallHooks()
void* ClipCursorPtr = user32dll.GetExportedFunction("ClipCursor");
void* GetCursorPosPtr = user32dll.GetExportedFunction("GetCursorPos");
void* ShowCursorPtr = user32dll.GetExportedFunction("ShowCursor");
MH_CreateHook(SetCursorPosPtr, &Hooks::SetCursorPos, reinterpret_cast<void**>(&originalSetCursorPos));
MH_CreateHook(ClipCursorPtr, &Hooks::ClipCursor, reinterpret_cast<void**>(&originalClipCursor));
MH_CreateHook(GetCursorPosPtr, &Hooks::GetCursorPos, reinterpret_cast<void**>(&originalGetCursorPos));
MH_CreateHook(ShowCursorPtr, &Hooks::ShowCursor, reinterpret_cast<void**>(&originalShowCursor));
///////////////////////////////////////////////////////////////////////////
// Enable WinAPI hooks
MH_EnableHook(SetCursorPosPtr);
@ -98,10 +105,18 @@ void Hooks::InstallHooks()
MH_EnableHook(addr_ConVar_IsFlagSet);
MH_EnableHook(addr_ConCommand_IsFlagSet);
///////////////////////////////////////////////////////////////////////////////
// Enable CMatSystemSurface hooks
MH_EnableHook(addr_CMatSystemSurface_LockCursor);
///////////////////////////////////////////////////////////////////////////////
// Enable CBaseFileSystem hooks
//MH_EnableHook(addr_CBaseFileSystem_FileSystemWarning);
///////////////////////////////////////////////////////////////////////////////
// Enable HostState hooks
// MH_EnableHook(MemoryAddress(0x14023EF80).RCast<void*>());
///////////////////////////////////////////////////////////////////////////////
// Enabled Utility hooks
MH_EnableHook(addr_MSG_EngineError);
@ -132,10 +147,19 @@ void Hooks::RemoveHooks()
MH_RemoveHook(addr_NetChan_Shutdown);
///////////////////////////////////////////////////////////////////////////////
// Unhook ConVar | ConCommand functions.
// Unhook ConVar | ConCommand functions
MH_RemoveHook(addr_ConVar_IsFlagSet);
MH_RemoveHook(addr_ConCommand_IsFlagSet);
///////////////////////////////////////////////////////////////////////////////
// Unhook CMatSystemSurface functions
MH_EnableHook(MemoryAddress(0x140548A00).RCast<void*>());
///////////////////////////////////////////////////////////////////////////////
// Unhook Utility functions
MH_RemoveHook(addr_MSG_EngineError);
MH_RemoveHook(addr_LoadPlaylist);
///////////////////////////////////////////////////////////////////////////////
// Unhook WinAPI
if (Module user32dll = Module("user32.dll"); user32dll.GetModuleBase()) // Is user32.dll valid?
@ -144,22 +168,20 @@ void Hooks::RemoveHooks()
void* ClipCursorPtr = user32dll.GetExportedFunction("ClipCursor");
void* GetCursorPosPtr = user32dll.GetExportedFunction("GetCursorPos");
void* ShowCursorPtr = user32dll.GetExportedFunction("ShowCursor");
MH_RemoveHook(SetCursorPosPtr);
MH_RemoveHook(ClipCursorPtr);
MH_RemoveHook(GetCursorPosPtr);
MH_RemoveHook(ShowCursorPtr);
}
///////////////////////////////////////////////////////////////////////////////
// Unhook Utility functions
MH_RemoveHook(addr_MSG_EngineError);
MH_RemoveHook(addr_LoadPlaylist);
///////////////////////////////////////////////////////////////////////////////
// Unhook CBaseFileSystem functions.
//MH_RemoveHook(addr_CBaseFileSystem_FileSystemWarning);
///////////////////////////////////////////////////////////////////////////////
// Unhook HostState hooks
//MH_RemoveHook(MemoryAddress(0x14023EF80).RCast<void*>());
///////////////////////////////////////////////////////////////////////////////
// Reset Minhook
MH_Uninitialize();
@ -171,21 +193,21 @@ void Hooks::ToggleNetTrace()
{
MH_EnableHook(addr_NET_ReceiveDatagram);
MH_EnableHook(addr_NET_SendDatagram);
printf("\n");
printf("+--------------------------------------------------------+\n");
printf("|>>>>>>>>>>>>>| NETCHANNEL TRACE ACTIVATED |<<<<<<<<<<<<<|\n");
printf("+--------------------------------------------------------+\n");
printf("\n");
spdlog::info("\n");
spdlog::info("+--------------------------------------------------------+\n");
spdlog::info("|>>>>>>>>>>>>>| NETCHANNEL TRACE ACTIVATED |<<<<<<<<<<<<<|\n");
spdlog::info("+--------------------------------------------------------+\n");
spdlog::info("\n");
}
else
{
MH_DisableHook(addr_NET_ReceiveDatagram);
MH_DisableHook(addr_NET_SendDatagram);
printf("\n");
printf("+--------------------------------------------------------+\n");
printf("|>>>>>>>>>>>>| NETCHANNEL TRACE DEACTIVATED |<<<<<<<<<<<<|\n");
printf("+--------------------------------------------------------+\n");
printf("\n");
spdlog::info("\n");
spdlog::info("+--------------------------------------------------------+\n");
spdlog::info("|>>>>>>>>>>>>| NETCHANNEL TRACE DEACTIVATED |<<<<<<<<<<<<|\n");
spdlog::info("+--------------------------------------------------------+\n");
spdlog::info("\n");
}
bToggledNetTrace = !bToggledNetTrace;
}
@ -196,21 +218,21 @@ void Hooks::ToggleDevCommands()
{
MH_EnableHook(addr_ConVar_IsFlagSet);
MH_EnableHook(addr_ConCommand_IsFlagSet);
printf("\n");
printf("+--------------------------------------------------------+\n");
printf("|>>>>>>>>>>>>>| DEVONLY COMMANDS ACTIVATED |<<<<<<<<<<<<<|\n");
printf("+--------------------------------------------------------+\n");
printf("\n");
spdlog::info("\n");
spdlog::info("+--------------------------------------------------------+\n");
spdlog::info("|>>>>>>>>>>>>>| DEVONLY COMMANDS ACTIVATED |<<<<<<<<<<<<<|\n");
spdlog::info("+--------------------------------------------------------+\n");
spdlog::info("\n");
}
else
{
MH_DisableHook(addr_ConVar_IsFlagSet);
MH_DisableHook(addr_ConCommand_IsFlagSet);
printf("\n");
printf("+--------------------------------------------------------+\n");
printf("|>>>>>>>>>>>>| DEVONLY COMMANDS DEACTIVATED |<<<<<<<<<<<<|\n");
printf("+--------------------------------------------------------+\n");
printf("\n");
spdlog::info("\n");
spdlog::info("+--------------------------------------------------------+\n");
spdlog::info("|>>>>>>>>>>>>| DEVONLY COMMANDS DEACTIVATED |<<<<<<<<<<<<|\n");
spdlog::info("+--------------------------------------------------------+\n");
spdlog::info("\n");
}
bToggledDevFlags = !bToggledDevFlags;
}

View File

@ -0,0 +1,179 @@
#include "pch.h"
#include "hooks.h"
namespace Hooks
{
FrameUpdateFn originalFrameUpdate = nullptr;
}
void Hooks::FrameUpdate(void* rcx, void* rdx, float time)
{
static auto setjmpFn = MemoryAddress(0x141205460).RCast<__int64(*)(jmp_buf, void*)>();
static auto host_abortserver = MemoryAddress(0x14B37C700).RCast<jmp_buf*>();
static auto CHostState_InitFn = MemoryAddress(0x14023E7D0).RCast<void(*)(CHostState*)>();
static auto g_ServerAbortServer = MemoryAddress(0x14B37CA22).RCast<char*>();
static auto State_RunFn = MemoryAddress(0x14023E870).RCast<void(*)(HostStates_t*,void*,float)>();
static auto Cbuf_ExecuteFn = MemoryAddress(0x14020D5C0).RCast<void(*)()>();
static auto g_ServerGameClients = MemoryAddress(0x14B383428).RCast<__int64*>();
static auto SV_InitGameDLLFn = MemoryAddress(0x140308B90).RCast<void(*)()>();
static auto g_CModelLoader = MemoryAddress(0x14173B210).RCast<void*>();
static auto CModelLoader_Map_IsValidFn = MemoryAddress(0x1402562F0).RCast<bool(*)(void*, const char*)>();
static auto Host_NewGameFn = MemoryAddress(0x140238DA0).RCast<bool(*)(char*, char*, bool, bool, void*)>();
static auto Host_Game_ShutdownFn = MemoryAddress(0x14023EDA0).RCast<void(*)(CHostState*)>();
static auto src_drawloading = MemoryAddress(0x14B37D96B).RCast<char*>();
static auto scr_engineevent_loadingstarted = MemoryAddress(0x1666ED024).RCast<char*>();
static auto gfExtendedError = MemoryAddress(0x14B383391).RCast<char*>();
static auto g_CEngineVGui = MemoryAddress(0x141741310).RCast<void*>();
static auto g_ServerDLL = MemoryAddress(0x141732048).RCast<void**>();
static auto Host_ChangelevelFn = MemoryAddress(0x1402387B0).RCast<void(*)(bool, const char*, const char*)>();
void* placeHolder = nullptr;
if (setjmpFn(*host_abortserver, placeHolder))
{
CHostState_InitFn(GameGlobals::HostState);
return;
}
else
{
*g_ServerAbortServer = true;
while (true)
{
Cbuf_ExecuteFn();
HostStates_t oldState = GameGlobals::HostState->m_iCurrentState;
switch (GameGlobals::HostState->m_iCurrentState)
{
case HostStates_t::HS_NEW_GAME:
{
// Inlined CHostState::State_NewGame
GameGlobals::HostState->m_bSplitScreenConnect = false;
if (!g_ServerGameClients) // Init Game if it ain't valid.
{
SV_InitGameDLLFn();
}
if (!g_ServerGameClients) // SV_InitGameDLL failed its still null.
{
std::cout << "Fatal CHostState::FrameUpdate Error. SV_InitGameDLL() failed." << std::endl;
abort(); // Placeholder.
}
if ( !CModelLoader_Map_IsValidFn(g_CModelLoader, GameGlobals::HostState->m_levelName) // Check if map is valid and if we can start a new game.
|| !Host_NewGameFn(GameGlobals::HostState->m_levelName, nullptr, GameGlobals::HostState->m_bBackgroundLevel, GameGlobals::HostState->m_bSplitScreenConnect, nullptr) )
{
// Inlined SCR_EndLoadingPlaque
if (*src_drawloading)
{
*scr_engineevent_loadingstarted = 0;
using HideLoadingPlaqueFn = void(*)(void*);
(*reinterpret_cast<HideLoadingPlaqueFn**>(g_CEngineVGui))[36](g_CEngineVGui); // (*((void(__fastcall**)(void**))g_CEngineVGui + 36))(&g_CEngineVGui);// HideLoadingPlaque
}
else if (*gfExtendedError)
{
using ShowErrorMessageFn = void(*)(void*);
(*reinterpret_cast<ShowErrorMessageFn**>(g_CEngineVGui))[35](g_CEngineVGui); // (*((void(__fastcall**)(void**))g_CEngineVGui + 35))(&g_CEngineVGui);// ShowErrorMessage
}
// End Inline SCR_EndLoadingPlaque
// Inlined CHostState::GameShutdown
if (GameGlobals::HostState->m_bActiveGame)
{
using GameShutdownFn = void(*)(void*);
(*reinterpret_cast<GameShutdownFn**>(g_ServerDLL))[9](g_ServerDLL); // (*(void(__fastcall**)(void*))(*(_QWORD*)g_ServerDLL + 72i64))(g_ServerDLL);// GameShutdown
GameGlobals::HostState->m_bActiveGame = 0;
}
// End Inline CHostState::GameShutdown
}
// Seems useless so nope.
// if (g_CHLClient)
// (*(void(__fastcall**)(__int64, _QWORD))(*(_QWORD*)g_CHLClient + 1000i64))(g_CHLClient, 0i64);
GameGlobals::HostState->m_iCurrentState = HostStates_t::HS_RUN; // Set current state to run.
// If our next state isn't a shutdown or its a forced shutdown then set next state to run.
if (GameGlobals::HostState->m_iNextState != HostStates_t::HS_SHUTDOWN || !GameGlobals::Cvar->FindVar("host_hasIrreversibleShutdown")->m_iValue)
GameGlobals::HostState->m_iNextState = HostStates_t::HS_RUN;
// End Inline CHostState::State_NewGame
break;
}
case HostStates_t::HS_CHANGE_LEVEL_SP:
{
GameGlobals::HostState->m_flShortFrameTime = 1.5; // Set frame time.
if (CModelLoader_Map_IsValidFn(g_CModelLoader, GameGlobals::HostState->m_levelName)) // Check if map is valid and if we can start a new game.
{
Host_ChangelevelFn(true, GameGlobals::HostState->m_levelName, GameGlobals::HostState->m_mapGroupName); // Call change level as singleplayer level.
}
else
{
std::cout << "Fatal CHostState::FrameUpdate Error. Map is not valid.";
}
// Seems useless so nope.
// if (g_CHLClient)
// (*(void(__fastcall**)(__int64, _QWORD))(*(_QWORD*)g_CHLClient + 1000i64))(g_CHLClient, 0i64);
// If our next state isn't a shutdown or its a forced shutdown then set next state to run.
if (GameGlobals::HostState->m_iNextState != HostStates_t::HS_SHUTDOWN || !GameGlobals::Cvar->FindVar("host_hasIrreversibleShutdown")->m_iValue)
GameGlobals::HostState->m_iNextState = HostStates_t::HS_RUN;
break;
}
case HostStates_t::HS_CHANGE_LEVEL_MP:
{
GameGlobals::HostState->m_flShortFrameTime = 1.5; // Set frame time.
using LevelShutdownFn = void(__thiscall*)(void*);
(*reinterpret_cast<LevelShutdownFn**>(*g_ServerDLL))[8](g_ServerDLL); // (*(void (__fastcall **)(void *))(*(_QWORD *)server_dll_var + 64i64))(server_dll_var);// LevelShutdown
if (CModelLoader_Map_IsValidFn(g_CModelLoader, GameGlobals::HostState->m_levelName)) // Check if map is valid and if we can start a new game.
{
using ShowErrorMessageFn = void(*)(void*);
(*reinterpret_cast<ShowErrorMessageFn**>(g_CEngineVGui))[31](g_CEngineVGui); // (*((void(__fastcall**)(void**))g_CEngineVGUI + 31))(&g_CEngineVGUI);// EnabledProgressBarForNextLoad
Host_ChangelevelFn(false, GameGlobals::HostState->m_levelName, GameGlobals::HostState->m_mapGroupName); // Call change level as singleplayer level.
}
// Seems useless so nope.
// // if (g_CHLClient)
// (*(void(__fastcall**)(__int64, _QWORD))(*(_QWORD*)g_CHLClient + 1000i64))(g_CHLClient, 0i64);
// If our next state isn't a shutdown or its a forced shutdown then set next state to run.
if (GameGlobals::HostState->m_iNextState != HostStates_t::HS_SHUTDOWN || !GameGlobals::Cvar->FindVar("host_hasIrreversibleShutdown")->m_iValue)
GameGlobals::HostState->m_iNextState = HostStates_t::HS_RUN;
break;
}
case HostStates_t::HS_RUN:
{
State_RunFn(&GameGlobals::HostState->m_iCurrentState, nullptr, time);
break;
}
case HostStates_t::HS_GAME_SHUTDOWN:
{
Host_Game_ShutdownFn(GameGlobals::HostState);
break;
}
case HostStates_t::HS_RESTART:
{
break;
}
default:
{
break;
}
}
if (oldState == HostStates_t::HS_RUN)
break;
if (oldState == HostStates_t::HS_SHUTDOWN || oldState == HostStates_t::HS_RESTART)
break;
if (oldState == HostStates_t::HS_GAME_SHUTDOWN)
break;
}
}
// originalFrameUpdate(rcx, rdx, time);
}

View File

@ -0,0 +1,18 @@
#include "pch.h"
#include "hooks.h"
#include "id3dx.h"
namespace Hooks
{
LockCursorFn originalLockCursor = nullptr;
}
void Hooks::LockCursor(void* thisptr)
{
if (g_bShowConsole || g_bShowBrowser)
{
addr_CMatSystemSurface_UnlockCursor(thisptr); // Unlock cursor if our gui is shown.
return;
}
return originalLockCursor(thisptr);
}

View File

@ -51,12 +51,18 @@ void* Hooks::SQVM_Print(void* sqvm, char* fmt, ...)
vmStr.append(buf);
if (g_GameConsole && g_GameConsole->ShouldPrintToCommandPrompt())
{
spdlog::info(vmStr);
}
logger.debug(vmStr);
std::string s = oss_print.str();
const char* c = s.c_str();
Items.push_back(Strdup((const char*)c));
Items.push_back(Strdup(c));
return NULL;
}
@ -97,12 +103,17 @@ __int64 Hooks::SQVM_Warning(void* sqvm, int a2, int a3, int* stringSize, void**
std::string stringConstructor((char*)*string, *stringSize); // Get string from memory via std::string constructor.
vmStr.append(stringConstructor);
if (g_GameConsole && g_GameConsole->ShouldPrintToCommandPrompt())
{
spdlog::info(vmStr);
}
logger.debug(vmStr);
std::string s = oss_warning.str();
const char* c = s.c_str();
Items.push_back(Strdup((const char*)c));
Items.push_back(Strdup(c));
return result;
}
@ -129,20 +140,20 @@ __int64 Hooks::SQVM_LoadRson(const char* rson_name)
// Returns the new path if the rson exists on the disk
if (FileExists(filepath) && originalSQVM_LoadRson(rson_name))
{
printf("\n");
printf("##################################################\n");
printf("] '%s'\n", filepath);
printf("##################################################\n");
printf("\n");
spdlog::info("\n");
spdlog::info("##################################################\n");
spdlog::info("] '{}'\n", filepath);
spdlog::info("##################################################\n");
spdlog::info("\n");
return originalSQVM_LoadRson(filepath);
}
printf("\n");
printf("##################################################\n");
printf("] '%s'\n", rson_name);
printf("##################################################\n");
printf("\n");
spdlog::info("\n");
spdlog::info("##################################################\n");
spdlog::info("] '{}'\n", rson_name);
spdlog::info("##################################################\n");
spdlog::info("\n");
return originalSQVM_LoadRson(rson_name);
}
@ -166,7 +177,7 @@ bool Hooks::SQVM_LoadScript(void* sqvm, const char* script_path, const char* scr
}
if (g_bDebugLoading)
{
printf(" [+] Loading SQVM Script '%s' ...\n", filepath);
spdlog::info(" [+] Loading SQVM Script '{}' ...\n", filepath);
}
///////////////////////////////////////////////////////////////////////////////
// Returns true if the script exists on the disk
@ -176,7 +187,7 @@ bool Hooks::SQVM_LoadScript(void* sqvm, const char* script_path, const char* scr
}
if (g_bDebugLoading)
{
printf(" [!] FAILED. Try SP / VPK for '%s'\n", filepath);
spdlog::info(" [!] FAILED. Try SP / VPK for '%s'\n", filepath);
}
return originalSQVM_LoadScript(sqvm, script_path, script_name, flag);

View File

@ -10,51 +10,29 @@
#include "CGameConsole.h"
#pragma comment(lib, "d3d11.lib")
/*---------------------------------------------------------------------------------
* _id3dx.cpp
*---------------------------------------------------------------------------------*/
///////////////////////////////////////////////////////////////////////////////////
// Type definitions.
typedef HRESULT(__stdcall* IDXGISwapChainPresent)(IDXGISwapChain* pSwapChain, UINT nSyncInterval, UINT nFlags);
typedef HRESULT(__stdcall* IDXGIResizeBuffers) (IDXGISwapChain* pSwapChain, UINT nBufferCount, UINT nWidth, UINT nHeight, DXGI_FORMAT dxFormat, UINT nSwapChainFlags);
///////////////////////////////////////////////////////////////////////////////////
typedef BOOL(WINAPI* IPostMessageA)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
typedef BOOL(WINAPI* IPostMessageW)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
///////////////////////////////////////////////////////////////////////////////////
extern BOOL g_bShowConsole = false;
extern BOOL g_bShowBrowser = false;
static BOOL g_bInitMenu = false;
static BOOL g_bInitialized = false;
///////////////////////////////////////////////////////////////////////////////////
static WNDPROC g_oWndProc = NULL;
static HWND g_hGameWindow = NULL;
extern DWORD g_dThreadId = NULL;
///////////////////////////////////////////////////////////////////////////////////
static IDXGISwapChainPresent g_fnIDXGISwapChainPresent = nullptr;
static IDXGISwapChain* g_pSwapChain = nullptr;
static IDXGIResizeBuffers g_oResizeBuffers = nullptr;
static ID3D11DeviceContext* g_pDeviceContext = nullptr;
static ID3D11Device* g_pDevice = nullptr;
static ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
static ID3D11DepthStencilView* g_pDepthStencilView = nullptr;
static IPostMessageA g_oPostMessageA = nullptr;
static IPostMessageW g_oPostMessageW = nullptr;
//#################################################################################
// WINDOW PROCEDURE
//#################################################################################
// Variables.
bool g_bShowConsole = false;
bool g_bShowBrowser = false;
IDXGISwapChainPresent g_fnIDXGISwapChainPresent = nullptr;
IDXGIResizeBuffers g_fnIDXGIResizeBuffers = nullptr;
ID3D11Device* g_pDevice = nullptr;
ID3D11RenderTargetView* g_pMainRenderTargetView = nullptr;
ID3D11DeviceContext* g_pDeviceContext = nullptr;
WNDPROC originalWndProc = NULL;
DWORD g_dThreadId = NULL;
LRESULT CALLBACK DXGIMsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK HwndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN)
{
@ -70,313 +48,113 @@ LRESULT CALLBACK HwndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
}
if (g_bShowConsole || g_bShowBrowser)
{//////////////////////////////////////////////////////////////////////////////
ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam);
g_bBlockInput = true;
switch (uMsg)
{
case WM_LBUTTONDOWN:
return 1L;
case WM_LBUTTONUP:
return 1L;
case WM_LBUTTONDBLCLK:
return 1L;
case WM_RBUTTONDOWN:
return 1L;
case WM_RBUTTONUP:
return 1L;
case WM_RBUTTONDBLCLK:
return 1L;
case WM_MBUTTONDOWN:
return 1L;
case WM_MBUTTONUP:
return 1L;
case WM_MBUTTONDBLCLK:
return 1L;
case WM_KEYDOWN:
return 1L;
case WM_KEYUP:
return 1L;
case WM_MOUSEACTIVATE:
return 1L;
case WM_MOUSEHOVER:
return 1L;
case WM_MOUSEHWHEEL:
return 1L;
case WM_MOUSELEAVE:
return 1L;
case WM_MOUSEMOVE:
return 1L;
case WM_MOUSEWHEEL:
return 1L;
case WM_SETCURSOR:
return 1L;
default:
break;
}
}//////////////////////////////////////////////////////////////////////////////
else
{
g_bBlockInput = false;
}
///////////////////////////////////////////////////////////////////////////////
return CallWindowProc(g_oWndProc, hWnd, uMsg, wParam, lParam);
}
//#################################################################################
// POST MESSAGE
//#################################################################################
BOOL WINAPI HPostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (g_bBlockInput && Msg == WM_MOUSEMOVE)
{
return TRUE;
}
return g_oPostMessageA(hWnd, Msg, wParam, lParam);
}
BOOL WINAPI HPostMessageW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (g_bBlockInput && Msg == WM_MOUSEMOVE)
{
return TRUE;
}
return g_oPostMessageW(hWnd, Msg, wParam, lParam);
}
//#################################################################################
// IDXGI PRESENT
//#################################################################################
void GetPresent()
{
WNDCLASSEXA wc = { sizeof(WNDCLASSEX), CS_CLASSDC, DXGIMsgProc, 0L, 0L, GetModuleHandleA(NULL), NULL, NULL, NULL, NULL, "DX", NULL };
RegisterClassExA(&wc);
HWND hWnd = CreateWindowA("DX", NULL, WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, NULL, NULL, wc.hInstance, NULL);
DXGI_SWAP_CHAIN_DESC sd = { 0 };
D3D_FEATURE_LEVEL nFeatureLevelsSet = D3D_FEATURE_LEVEL_11_0;
D3D_FEATURE_LEVEL nFeatureLevelsSupported;
ZeroMemory(&sd, sizeof(sd));
///////////////////////////////////////////////////////////////////////////////
sd.BufferCount = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
sd.BufferDesc.Height = 800;
sd.BufferDesc.Width = 600;
sd.BufferDesc.RefreshRate = { 60, 1 };
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
sd.Windowed = TRUE;
sd.OutputWindow = hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
///////////////////////////////////////////////////////////////////////////////
g_hGameWindow = sd.OutputWindow;
UINT nFeatureLevelsRequested = 1;
HRESULT hr = 0;
IDXGISwapChain* pSwapChain = nullptr;
ID3D11Device* pDevice = nullptr;
ID3D11DeviceContext* pContext = nullptr;
///////////////////////////////////////////////////////////////////////////////
if (FAILED(hr = D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
&nFeatureLevelsSet,
nFeatureLevelsRequested,
D3D11_SDK_VERSION,
&sd,
&pSwapChain,
&pDevice,
&nFeatureLevelsSupported,
&pContext)))
{
std::cout << "+--------------------------------------------------------+" << std::endl;
std::cout << "| >>>>>>>>>| VIRTUAL METHOD TABLE HOOK FAILED |<<<<<<<<< |" << std::endl;
std::cout << "+--------------------------------------------------------+" << std::endl;
RemoveDXHooks();
return;
}
///////////////////////////////////////////////////////////////////////////////
DWORD_PTR* pSwapChainVtable = nullptr;
DWORD_PTR* pContextVTable = nullptr;
DWORD_PTR* pDeviceVTable = nullptr;
pSwapChainVtable = (DWORD_PTR*)pSwapChain;
pSwapChainVtable = (DWORD_PTR*)pSwapChainVtable[0];
pContextVTable = (DWORD_PTR*)pContext;
pContextVTable = (DWORD_PTR*)pContextVTable[0];
pDeviceVTable = (DWORD_PTR*)pDevice;
pDeviceVTable = (DWORD_PTR*)pDeviceVTable[0];
g_fnIDXGISwapChainPresent = (IDXGISwapChainPresent)(DWORD_PTR)pSwapChainVtable[(int)DXGISwapChainVTbl::Present];
g_oResizeBuffers = (IDXGIResizeBuffers)(DWORD_PTR)pSwapChainVtable[(int)DXGISwapChainVTbl::ResizeBuffers];
pSwapChain->Release();
pContext->Release();
pDevice->Release();
}
//#################################################################################
// INITIALIZATION
//#################################################################################
void SetupImGui()
{
ImGui::CreateContext();
IMGUI_CHECKVERSION();
ImGuiIO& io = ImGui::GetIO(); (void)io;
ImGui_ImplWin32_Init(g_hGameWindow);
ImGui_ImplDX11_Init(g_pDevice, g_pDeviceContext);
ImGui::GetIO().ImeWindowHandle = g_hGameWindow;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
}
void DrawImGui()
{
if (!GameGlobals::IsInitialized || !GameGlobals::InputSystem) // Check if GameGlobals initialized and if InputSystem is valid.
return;
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
if (g_bShowConsole || g_bShowBrowser)
{
GameGlobals::InputSystem->EnableInput(false); // Disable input.
g_bBlockInput = true; // Prevent mouse cursor from being modified if console is open.
if (ImGui_ImplWin32_WndProcHandler(hwnd, uMsg, wParam, lParam) > 0)
return 1L;
}
else
{
GameGlobals::InputSystem->EnableInput(true); // Enable input.
g_bBlockInput = false; // Allow mouse input.
}
if (g_bShowConsole)
{
DrawConsole();
}
if (g_bShowBrowser)
{
DrawBrowser();
}
ImGui::EndFrame();
ImGui::Render();
g_pDeviceContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
return CallWindowProc(originalWndProc, hwnd, uMsg, wParam, lParam);
}
void CreateRenderTarget(IDXGISwapChain* pSwapChain)
void InitRenderer()
{
///////////////////////////////////////////////////////////////////////////////
DXGI_SWAP_CHAIN_DESC sd = { 0 };
ID3D11Texture2D* pBackBuffer = { 0 };
D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc;
spdlog::debug("Registering temporary Window for DirectX..\n");
// Register temporary window instance to get DirectX 11 relevant virtual function ptr.
WNDCLASSEX ws;
ws.cbSize = sizeof(WNDCLASSEX);
ws.style = CS_HREDRAW | CS_VREDRAW;
ws.lpfnWndProc = DXGIMsgProc;
ws.cbClsExtra = 0;
ws.cbWndExtra = 0;
ws.hInstance = GetModuleHandle(NULL);
ws.hIcon = NULL;
ws.hCursor = NULL;
ws.hbrBackground = NULL;
ws.lpszMenuName = NULL;
ws.lpszClassName = "R5 Reloaded";
ws.hIconSm = NULL;
///////////////////////////////////////////////////////////////////////////////
pSwapChain->GetDesc(&sd);
ZeroMemory(&render_target_view_desc, sizeof(render_target_view_desc));
RegisterClassEx(&ws);
// Create temporary window.
HWND window = CreateWindowA(ws.lpszClassName, "R5 Reloaded Window", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, ws.hInstance, NULL);
g_hGameWindow = sd.OutputWindow;
render_target_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
DXGI_RATIONAL refreshRate;
refreshRate.Numerator = 60;
refreshRate.Denominator = 1;
///////////////////////////////////////////////////////////////////////////////
pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
if (pBackBuffer != NULL) { g_pDevice->CreateRenderTargetView(pBackBuffer, &render_target_view_desc, &g_pRenderTargetView); }
g_pDeviceContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);
pBackBuffer->Release();
}
D3D_FEATURE_LEVEL featureLevel;
const D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 };
void DestroyRenderTarget()
{
if (g_pRenderTargetView)
// Setup buffer description.
DXGI_MODE_DESC bufferDescription;
bufferDescription.Width = 100;
bufferDescription.Height = 100;
bufferDescription.RefreshRate = refreshRate;
bufferDescription.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
bufferDescription.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
bufferDescription.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
DXGI_SAMPLE_DESC sampleDescription;
sampleDescription.Count = 1;
sampleDescription.Quality = 0;
// Setup swap chain description.
DXGI_SWAP_CHAIN_DESC swapChainDescription;
swapChainDescription.BufferDesc = bufferDescription;
swapChainDescription.SampleDesc = sampleDescription;
swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDescription.BufferCount = 1;
swapChainDescription.OutputWindow = window;
swapChainDescription.Windowed = TRUE;
swapChainDescription.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDescription.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
IDXGISwapChain* swapChain;
ID3D11Device* device;
ID3D11DeviceContext* context;
// Create temporary fake device and swap chain.
if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, 1, D3D11_SDK_VERSION, &swapChainDescription, &swapChain, &device, &featureLevel, &context)))
{
g_pRenderTargetView->Release();
g_pRenderTargetView = nullptr;
g_pDeviceContext->OMSetRenderTargets(0, 0, 0);
std::cout << "+--------------------------------------------------------+" << std::endl;
std::cout << "| >>>>>>>>>>>>>>| RENDER TARGET DESTROYED |<<<<<<<<<<<<< |" << std::endl;
std::cout << "+--------------------------------------------------------+" << std::endl;
}
}
//#################################################################################
// INTERNALS
//#################################################################################
HRESULT GetDeviceAndCtxFromSwapchain(IDXGISwapChain* pSwapChain, ID3D11Device** ppDevice, ID3D11DeviceContext** ppContext)
{
HRESULT ret = pSwapChain->GetDevice(__uuidof(ID3D11Device), (PVOID*)ppDevice);
if (SUCCEEDED(ret))
{
(*ppDevice)->GetImmediateContext(ppContext);
}
return ret;
}
IDXGIResizeBuffers originalResizeBuffers = nullptr;
HRESULT __stdcall GetResizeBuffers(IDXGISwapChain* pSwapChain, UINT nBufferCount, UINT nWidth, UINT nHeight, DXGI_FORMAT dxFormat, UINT nSwapChainFlags)
{
g_bShowConsole = false;
g_bShowBrowser = false;
g_bInitialized = false;
///////////////////////////////////////////////////////////////////////////////
DestroyRenderTarget();
///////////////////////////////////////////////////////////////////////////////
return originalResizeBuffers(pSwapChain, nBufferCount, nWidth, nHeight, dxFormat, nSwapChainFlags);
}
IDXGISwapChainPresent originalPresent = nullptr;
HRESULT __stdcall Present(IDXGISwapChain* pSwapChain, UINT nSyncInterval, UINT nFlags)
{
if (!g_bInitialized)
{
if (FAILED(GetDeviceAndCtxFromSwapchain(pSwapChain, &g_pDevice, &g_pDeviceContext)))
{
return originalPresent(pSwapChain, nSyncInterval, nFlags);
std::cout << "+--------------------------------------------------------+" << std::endl;
std::cout << "| >>>>>>>>>>| GET DVS AND CTX FROM SCP FAILED |<<<<<<<<< |" << std::endl;
std::cout << "+--------------------------------------------------------+" << std::endl;
}
CreateRenderTarget(pSwapChain);
SetupImGui();
if (g_oWndProc == nullptr)
{ // Only initialize HwndProc pointer once to avoid stack overflow during ResizeBuffers(..)
g_oWndProc = (WNDPROC)SetWindowLongPtr(g_hGameWindow, GWLP_WNDPROC, (LONG_PTR)HwndProc);
}
g_bInitialized = true;
g_pSwapChain = pSwapChain;
std::cout << "Creating Device and Swap Chain failed." << std::endl;
return;
}
DrawImGui();
g_bInitialized = true;
///////////////////////////////////////////////////////////////////////////////
return originalPresent(pSwapChain, nSyncInterval, nFlags);
DWORD_PTR* swapChainVTable = nullptr;
DWORD_PTR* contextVTable = nullptr;
DWORD_PTR* deviceVTable = nullptr;
// Get vtable by dereferencing once.
swapChainVTable = (DWORD_PTR*)swapChain;
swapChainVTable = (DWORD_PTR*)swapChainVTable[0];
contextVTable = (DWORD_PTR*)context;
contextVTable = (DWORD_PTR*)contextVTable[0];
deviceVTable = (DWORD_PTR*)device;
deviceVTable = (DWORD_PTR*)deviceVTable[0];
// Get virtual functions addresses.
g_fnIDXGISwapChainPresent = (IDXGISwapChainPresent)(DWORD_PTR)swapChainVTable[(int)DXGISwapChainVTbl::Present];
g_fnIDXGIResizeBuffers = (IDXGIResizeBuffers)(DWORD_PTR)swapChainVTable[(int)DXGISwapChainVTbl::ResizeBuffers];
// Safe release all relevant ptrs.
swapChain->Release();
swapChain = nullptr;
device->Release();
device = nullptr;
context->Release();
context = nullptr;
// Destroy Window used for getting the virtual functions addresses and unregister its class.
DestroyWindow(swapChainDescription.OutputWindow);
UnregisterClass(ws.lpszClassName, ws.hInstance);
}
bool LoadTextureFromByteArray(unsigned char* image_data, const int& image_width, const int& image_height, ID3D11ShaderResourceView** out_srv)
@ -431,57 +209,158 @@ bool LoadTextureFromByteArray(unsigned char* image_data, const int& image_width,
return true;
}
//#################################################################################
// MANAGEMENT
//#################################################################################
void DrawMenu()
{
if (!GameGlobals::IsInitialized || !GameGlobals::InputSystem) // Check if GameGlobals initialized and if InputSystem is valid.
return;
// Handle new ImGui frame.
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
// Handle game input if one of the menus is open.
if (g_bShowConsole || g_bShowBrowser)
{
GameGlobals::InputSystem->EnableInput(false);
}
else
{
GameGlobals::InputSystem->EnableInput(true);
}
if (g_bShowConsole)
{
DrawConsole();
}
if (g_bShowBrowser)
{
DrawBrowser();
}
// Handle end of frame and prepare rendering.
ImGui::EndFrame();
ImGui::Render();
// Set new render target.
// This breaks 4:3 in main menu and load screen if not applying the games DepthStencilView. Applying the games DepthStencilView makes ImGui not render tho.
g_pDeviceContext->OMSetRenderTargets(1, &g_pMainRenderTargetView, NULL);
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); // Tell ImGui to render all the draw data.
}
IDXGIResizeBuffers originalResizeBuffers = nullptr;
HRESULT __stdcall GetResizeBuffers(IDXGISwapChain* pSwapChain, UINT nBufferCount, UINT nWidth, UINT nHeight, DXGI_FORMAT dxFormat, UINT nSwapChainFlags)
{
spdlog::debug("Resizing IDXGIResizeBuffers..\n");
// Re-create render target if our window got resized.
if (g_pMainRenderTargetView)
{
g_pDeviceContext->OMSetRenderTargets(0, 0, 0); // Set render target to null.
// Safe release the render target.
g_pMainRenderTargetView->Release();
g_pMainRenderTargetView = nullptr;
}
ImGui_ImplDX11_InvalidateDeviceObjects(); // Invalidate all ImGui DirectX objects.
HRESULT hr = originalResizeBuffers(pSwapChain, nBufferCount, nWidth, nHeight, dxFormat, nSwapChainFlags); // Let DirectX resize all the buffers.
if (!g_pDevice) // Valid device?
return hr;
ID3D11Texture2D* pBuffer;
pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBuffer); // Grab the swapchains buffer.
if (!pBuffer) // Valid buffer?
return hr;
g_pDevice->CreateRenderTargetView(pBuffer, NULL, &g_pMainRenderTargetView); // Create render target again with the new swapchain buffer.
// Safe release the buffer.
pBuffer->Release();
pBuffer = nullptr;
if (!g_pMainRenderTargetView) // Valid render target?
return hr;
g_pDeviceContext->OMSetRenderTargets(1, &g_pMainRenderTargetView, NULL); // Set new render target.
// Set up the viewport.
D3D11_VIEWPORT vp;
vp.Width = nWidth;
vp.Height = nHeight;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pDeviceContext->RSSetViewports(1, &vp);
ImGui_ImplDX11_CreateDeviceObjects(); // Create new DirectX objects for ImGui.
return hr;
}
IDXGISwapChainPresent originalPresent = nullptr;
HRESULT __stdcall Present(IDXGISwapChain* pSwapChain, UINT nSyncInterval, UINT nFlags)
{
static bool InitializedPresent = false;
if (!InitializedPresent)
{
spdlog::debug("Initializing IDXGISwapChainPresent hook..\n");
if (SUCCEEDED(pSwapChain->GetDevice(__uuidof(ID3D11Device), (void**)&g_pDevice))) // Get device via swap chain.
{
g_pDevice->GetImmediateContext(&g_pDeviceContext); // Get device context via device.
DXGI_SWAP_CHAIN_DESC sd;
pSwapChain->GetDesc(&sd); // Get the swap chain description.
ID3D11Texture2D* pBuffer;
pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBuffer); // Get swap chain buffer.
if (!pBuffer) // Valid buffer?
return originalPresent(pSwapChain, nSyncInterval, nFlags);
g_pDevice->CreateRenderTargetView(pBuffer, NULL, &g_pMainRenderTargetView); // Create new render target.
// Safe release the buffer.
pBuffer->Release();
pBuffer = nullptr;
originalWndProc = (WNDPROC)SetWindowLongPtr(sd.OutputWindow, GWLP_WNDPROC, (LONG_PTR)WindowProc); // Hook current output window.
// Initialize ImGui.
ImGui::CreateContext();
ImGui_ImplWin32_Init(sd.OutputWindow);
ImGui_ImplDX11_Init(g_pDevice, g_pDeviceContext);
InitializedPresent = true;
}
else
{
return originalPresent(pSwapChain, nSyncInterval, nFlags);
}
}
DrawMenu();
return originalPresent(pSwapChain, nSyncInterval, nFlags);
}
void InstallDXHooks()
{
///////////////////////////////////////////////////////////////////////////////
// Hook SwapChain
spdlog::debug("Initializing IDXGISwapChainPresent hook..\n");
MH_CreateHook(g_fnIDXGISwapChainPresent, &Present, reinterpret_cast<void**>(&originalPresent));
MH_CreateHook(g_oResizeBuffers, &GetResizeBuffers, reinterpret_cast<void**>(&originalResizeBuffers));
MH_CreateHook(g_fnIDXGIResizeBuffers, &GetResizeBuffers, reinterpret_cast<void**>(&originalResizeBuffers));
///////////////////////////////////////////////////////////////////////////////
// Enable hooks
MH_EnableHook(g_fnIDXGISwapChainPresent);
MH_EnableHook(g_oResizeBuffers);
if (Module user32dll = Module("user32.dll"); user32dll.GetModuleBase()) // Is user32.dll valid?
{
IPostMessageA PostMessageA = user32dll.GetExportedFunction("PostMessageA").RCast<IPostMessageA>();
IPostMessageW PostMessageW = user32dll.GetExportedFunction("PostMessageW").RCast<IPostMessageW>();
///////////////////////////////////////////////////////////////////////////////
// Hook PostMessage
MH_CreateHook(PostMessageA, &HPostMessageA, reinterpret_cast<void**>(&g_oPostMessageA));
MH_CreateHook(PostMessageW, &HPostMessageW, reinterpret_cast<void**>(&g_oPostMessageW));
MH_EnableHook(PostMessageA);
MH_EnableHook(PostMessageW);
}
MH_EnableHook(g_fnIDXGIResizeBuffers);
}
void RemoveDXHooks()
{
///////////////////////////////////////////////////////////////////////////////
// Unhook PostMessage
if (Module user32dll = Module("user32.dll"); user32dll.GetModuleBase()) // Is user32.dll valid?
{
IPostMessageA PostMessageA = user32dll.GetExportedFunction("PostMessageA").RCast<IPostMessageA>();
IPostMessageW PostMessageW = user32dll.GetExportedFunction("PostMessageW").RCast<IPostMessageW>();
MH_RemoveHook(PostMessageA);
MH_RemoveHook(PostMessageW);
}
///////////////////////////////////////////////////////////////////////////////
// Unhook SwapChain
spdlog::debug("Initializing IDXGISwapChainPresent hook..\n");
MH_RemoveHook(g_fnIDXGISwapChainPresent);
MH_RemoveHook(g_oResizeBuffers);
MH_RemoveHook(g_fnIDXGIResizeBuffers);
///////////////////////////////////////////////////////////////////////////////
// Shutdown ImGui
ImGui_ImplWin32_Shutdown();
ImGui_ImplDX11_Shutdown();
}
@ -489,10 +368,9 @@ void RemoveDXHooks()
void PrintDXAddress()
{
std::cout << "+--------------------------------------------------------+" << std::endl;
std::cout << "| ID3D11DeviceContext : " << std::hex << std::uppercase << g_pDeviceContext << std::setw(13) << " |" << std::endl;
std::cout << "| ID3D11Device : " << std::hex << std::uppercase << g_pDevice << std::setw(13) << " |" << std::endl;
std::cout << "| ID3D11RenderTargetView : " << std::hex << std::uppercase << g_pRenderTargetView << std::setw(13) << " |" << std::endl;
std::cout << "| IDXGISwapChain : " << std::hex << std::uppercase << g_pSwapChain << std::setw(13) << " |" << std::endl;
std::cout << "| ID3D11DeviceContext : " << std::hex << std::uppercase << g_pDeviceContext << std::setw(13) << " |" << std::endl;
std::cout << "| ID3D11Device : " << std::hex << std::uppercase << g_pDevice << std::setw(13) << " |" << std::endl;
std::cout << "| ID3D11RenderTargetView : " << std::hex << std::uppercase << g_pMainRenderTargetView << std::setw(13) << " |" << std::endl;
std::cout << "| IDXGISwapChainPresent : " << std::hex << std::uppercase << g_fnIDXGISwapChainPresent << std::setw(13) << " |" << std::endl;
std::cout << "+--------------------------------------------------------+" << std::endl;
}
@ -503,13 +381,14 @@ void PrintDXAddress()
DWORD __stdcall DXSwapChainWorker(LPVOID)
{
GetPresent();
InitRenderer();
InstallDXHooks();
return true;
}
void SetupDXSwapChain()
{
spdlog::debug("Setting up DirectX thread..\n");
// Create a worker thread for the console overlay
DWORD __stdcall DXSwapChainWorker(LPVOID);
HANDLE hThread = CreateThread(NULL, 0, DXSwapChainWorker, NULL, 0, &g_dThreadId);

View File

@ -7,6 +7,7 @@
void InstallOpcodes() /* .TEXT */
{
spdlog::debug("Patching the game executeable..\n");
//-------------------------------------------------------------------------
// JNZ --> JMP | Prevent OriginSDK from initializing
//Origin_Init.Offset(0x0B).Patch({ 0xE9, 0x63, 0x02, 0x00, 0x00, 0x00 });
@ -32,4 +33,26 @@ void InstallOpcodes() /* .TEXT */
//-------------------------------------------------------------------------
// CALL --> NOP | Prevent random netchan encryption key from being overriden by default key
NetChan_EncKey_DefaultAssign.Patch({ 0x90, 0x90, 0x90, 0x90, 0x90 });
//-------------------------------------------------------------------------
// INLINE CALL --> VTABLE CALL | Call LockCursor VTable class function instead of doing it inlined.
//-------------------------------------------------------------------------
// .text:0000000140548E2C 80 3D 5C 2E 1D 01 00 cmp cs:byte_14171BC8F, 0
// .text:0000000140548E33 48 8B 0D 16 25 EC 0C mov rcx, cs:g_InputStackSystem
// .text:0000000140548E3A 48 8B 97 18 01 00 00 mov rdx, [rdi+118h]
// .text:0000000140548E41 C6 05 91 7B EC 0C 01 mov cs:byte_14D4109D9, 1
// .text:0000000140548E48 48 8B 01 mov rax, [rcx]
// .text:0000000140548E4B 74 10 jz short loc_140548E5D
// .text:0000000140548E4D 4C 8B 05 8C 7B EC 0C mov r8, cs:qword_14D4109E0
// .text:0000000140548E54 48 83 C4 30 add rsp, 30h
// .text:0000000140548E58 5F pop rdi
// .text:0000000140548E59 48 FF 60 60 jmp qword ptr[rax+60h]
//-------------------------------------------------------------------------
// TURNS INTO:
//-------------------------------------------------------------------------
// .text:0000000140548E2C 48 8B 07 mov rax, [rdi]
// .text:0000000140548E2F 48 89 F9 mov rcx, rdi
// .text:0000000140548E32 FF 90 90 02 00 00 call qword ptr[rax+290h]
// .text:0000000140548E38 EB 2F jmp short loc_140548E69
//-------------------------------------------------------------------------
MemoryAddress(0x140548E2C).Patch({ 0x48, 0x8B, 0x07, 0x48, 0x89, 0xF9, 0xFF, 0x90, 0x90, 0x02, 0x00, 0x00, 0xEB, 0x2F });
}