From a78484b5c51581e6bfd5d4eddb12cb1fcf864fd1 Mon Sep 17 00:00:00 2001 From: IcePixelx <41352111+PixieCore@users.noreply.github.com> Date: Sun, 15 Aug 2021 19:57:33 +0200 Subject: [PATCH] Read description for changes. * Updated r5net. Checking for version number now. * Added SQVM_Warning hook. * Adjusted IsFlagSet, will only mask off DEV_FLAGS in Release compile now. * Empty hostname cvars. --- r5dev/include/CCompanion.h | 2 + r5dev/include/enums.h | 50 +++++++++++++++++- r5dev/include/hooks.h | 18 ++++++- r5dev/include/patterns.h | 4 ++ r5dev/src/CCompanion.cpp | 30 ++++++++--- r5dev/src/CGameConsole.cpp | 4 ++ r5dev/src/gameclasses.cpp | 32 +++++++++++- r5dev/src/hooks/hooks.cpp | 6 ++- r5dev/src/hooks/iconvar.cpp | 90 +++++++++++++++++++------------- r5dev/src/hooks/sqvm.cpp | 66 ++++++++++++++++++++--- r5net/include/r5/r5net.h | 3 +- r5net/include/r5/serverlisting.h | 2 + r5net/src/r5net.cpp | 47 +++++++++++++---- 13 files changed, 287 insertions(+), 67 deletions(-) diff --git a/r5dev/include/CCompanion.h b/r5dev/include/CCompanion.h index 817ab31b..5a7ef11c 100644 --- a/r5dev/include/CCompanion.h +++ b/r5dev/include/CCompanion.h @@ -40,6 +40,7 @@ public: std::vector ServerList; ImGuiTextFilter ServerBrowserFilter; char ServerConnStringBuffer[256] = { 0 }; + std::string ServerListMessage = std::string(); //////////////////// // Settings // @@ -56,6 +57,7 @@ public: ImVec4 HostRequestMessageColor = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); bool StartAsDedi = false; bool BroadCastServer = false; + bool OverridePlaylist = false; //////////////////// // Private Server // diff --git a/r5dev/include/enums.h b/r5dev/include/enums.h index e51e8569..6a4d4ff7 100644 --- a/r5dev/include/enums.h +++ b/r5dev/include/enums.h @@ -368,5 +368,53 @@ enum FileWarningLevel_t FILESYSTEM_WARNING_REPORTALLACCESSES_READ, FILESYSTEM_WARNING_REPORTALLACCESSES_READWRITE, FILESYSTEM_WARNING_REPORTALLACCESSES_ASYNC +}; -}; \ No newline at end of file +#define FCVAR_NONE 0 + +// Command to ConVars and ConCommands +// ConVar Systems +#define FCVAR_UNREGISTERED (1<<0) // If this is set, don't add to linked list, etc. +#define FCVAR_DEVELOPMENTONLY (1<<1) // Hidden in released products. Flag is removed automatically if ALLOW_DEVELOPMENT_CVARS is defined. +#define FCVAR_GAMEDLL (1<<2) // defined by the game DLL +#define FCVAR_CLIENTDLL (1<<3) // defined by the client DLL +#define FCVAR_HIDDEN (1<<4) // Hidden. Doesn't appear in find or auto complete. Like DEVELOPMENTONLY, but can't be compiled out. + +// ConVar only +#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value +#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. +#define FCVAR_ARCHIVE (1<<7) // set to cause it to be saved to vars.rc +#define FCVAR_NOTIFY (1<<8) // notifies players when changed +#define FCVAR_USERINFO (1<<9) // changes the client's info string + +#define FCVAR_PRINTABLEONLY (1<<10) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). + +#define FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS (1<<10) // When on concommands this allows remote clients to execute this cmd on the server. + // We are changing the default behavior of concommands to disallow execution by remote clients without + // this flag due to the number existing concommands that can lag or crash the server when clients abuse them. + +#define FCVAR_UNLOGGED (1<<11) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log +#define FCVAR_NEVER_AS_STRING (1<<12) // never try to print that cvar + +// It's a ConVar that's shared between the client and the server. +// At signon, the values of all such ConVars are sent from the server to the client (skipped for local +// client, of course ) +// If a change is requested it must come from the console (i.e., no remote client changes) +// If a value is changed while a server is active, it's replicated to all connected clients +#define FCVAR_REPLICATED (1<<13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time +#define FCVAR_CHEAT (1<<14) // Only useable in singleplayer / debug / multiplayer & sv_cheats +#define FCVAR_SS (1<<15) // causes varnameN where N == 2 through max splitscreen slots for mod to be autogenerated +#define FCVAR_DEMO (1<<16) // record this cvar when starting a demo file +#define FCVAR_DONTRECORD (1<<17) // don't record these command in demofiles +#define FCVAR_SS_ADDED (1<<18) // This is one of the "added" FCVAR_SS variables for the splitscreen players +#define FCVAR_RELEASE (1<<19) // Cvars tagged with this are the only cvars avaliable to customers +#define FCVAR_RELOAD_MATERIALS (1<<20) // If this cvar changes, it forces a material reload +#define FCVAR_RELOAD_TEXTURES (1<<21) // If this cvar changes, if forces a texture reload + +#define FCVAR_NOT_CONNECTED (1<<22) // cvar cannot be changed by a client that is connected to a server +#define FCVAR_MATERIAL_SYSTEM_THREAD (1<<23) // Indicates this cvar is read from the material system thread +#define FCVAR_ARCHIVE_GAMECONSOLE (1<<24) // cvar written to config.cfg on the Xbox + +#define FCVAR_SERVER_CAN_EXECUTE (1<<28)// the server is allowed to execute this command on clients via ClientCommand/NET_StringCmd/CBaseClientState::ProcessStringCmd. +#define FCVAR_SERVER_CANNOT_QUERY (1<<29)// If this is set, then the server is not allowed to query this cvar's value (via IServerPluginHelpers::StartQueryCvarValue). +#define FCVAR_CLIENTCMD_CAN_EXECUTE (1<<30) // IVEngineClient::ClientCmd is allowed to execute this command. diff --git a/r5dev/include/hooks.h b/r5dev/include/hooks.h index 6b33a004..b4bc2f0e 100644 --- a/r5dev/include/hooks.h +++ b/r5dev/include/hooks.h @@ -22,9 +22,13 @@ namespace Hooks #pragma region Squirrel void* SQVM_Print(void* sqvm, char* fmt, ...); + __int64 SQVM_Warning(void* sqvm, int a2, int a3, int* stringSize, void** string); __int64 SQVM_LoadRson(const char* rson_name); bool SQVM_LoadScript(void* sqvm, const char* script_path, const char* script_name, int flag); + using SQVM_WarningFn = __int64(*)(void*, int, int, int*, void**); + extern SQVM_WarningFn originalSQVM_Warning; + using SQVM_LoadRsonFn = __int64(*)(const char*); extern SQVM_LoadRsonFn originalSQVM_LoadRson; @@ -58,8 +62,18 @@ namespace Hooks #pragma endregion #pragma region ConVar - bool ConVar_IsFlagSet(int** cvar, int flag); - bool ConCommand_IsFlagSet(int* cmd, int flag); + bool ConVar_IsFlagSet(ConVar* cvar, int flag); + bool ConCommand_IsFlagSet(ConCommandBase* cmd, int flag); + void Map_Callback(void* args); + + using ConVar_IsFlagSetFn = bool(*)(ConVar*, int); + extern ConVar_IsFlagSetFn originalConVar_IsFlagSet; + + using ConCommand_IsFlagSetFn = bool(*)(ConCommandBase*, int); + extern ConCommand_IsFlagSetFn originalConCommand_IsFlagSet; + + using Map_CallbackFn = void(*)(void*); + extern Map_CallbackFn originalMap_Callback; #pragma endregion #pragma region WinAPI diff --git a/r5dev/include/patterns.h b/r5dev/include/patterns.h index 592a5c58..fe68f6a0 100644 --- a/r5dev/include/patterns.h +++ b/r5dev/include/patterns.h @@ -23,6 +23,10 @@ namespace /*0x141057FD0*/ FUNC_AT_ADDRESS(addr_SQVM_Print, void*, r5_patterns.PatternSearch("83 F8 01 48 8D 3D ? ? ? ?").OffsetSelf(0x3).FollowNearCallSelf(0x3, 0x7).GetPtr()); + FUNC_AT_ADDRESS(addr_SQVM_Warning, __int64(*)(__int64, int, int, const char*, std::size_t*), r5_patterns.PatternSearch("E8 ? ? ? ? 85 C0 0F 99 C3").FollowNearCallSelf().GetPtr()); + + FUNC_AT_ADDRESS(addr_SQVM_Warning_ReturnAddr, void*, r5_patterns.PatternSearch("E8 ? ? ? ? 85 C0 0F 99 C3").OffsetSelf(0x5).GetPtr()); + //DWORD64 p_SQVM_LoadScript = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x89\x5C\x24\x10\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x48\x89\x4C\x24\x08\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\x6C", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); // For S0 and S1 /*0x141055630*/ diff --git a/r5dev/src/CCompanion.cpp b/r5dev/src/CCompanion.cpp index 4f6ec9b2..32de67d6 100644 --- a/r5dev/src/CCompanion.cpp +++ b/r5dev/src/CCompanion.cpp @@ -54,7 +54,7 @@ void CCompanion::UpdateHostingStatus() if (!GameGlobals::HostState || !GameGlobals::Cvar) // Is HostState and Cvar valid? return; - GameGlobals::HostState->m_bActiveGame ? HostingStatus = EHostStatus::Hosting : HostingStatus = EHostStatus::NotHosting; // Are we hosting a server? + HostingStatus = GameGlobals::HostState->m_bActiveGame ? EHostStatus::Hosting : EHostStatus::NotHosting; // Are we hosting a server? switch (HostingStatus) { @@ -94,7 +94,7 @@ void CCompanion::RefreshServerList() std::cout << " [+CCompanion+] Refreshing server list with string " << MatchmakingServerStringBuffer << "\n"; #endif bThreadLocked = true; - ServerList = r5net->GetServersList(); + ServerList = r5net->GetServersList(ServerListMessage); bThreadLocked = false; }); @@ -105,7 +105,17 @@ void CCompanion::RefreshServerList() void CCompanion::SendHostingPostRequest() { HostToken = std::string(); - bool result = r5net->PostServerHost(HostRequestMessage, HostToken, ServerListing{ MyServer.name, std::string(GameGlobals::HostState->m_levelName), "", GameGlobals::Cvar->FindVar("hostport")->m_pzsCurrentValue, MyServer.password, std::to_string(*reinterpret_cast(0x1656057E0)) /* checksum */}); + bool result = r5net->PostServerHost(HostRequestMessage,HostToken, + ServerListing{ MyServer.name, + std::string(GameGlobals::HostState->m_levelName), + "", + GameGlobals::Cvar->FindVar("hostport")->m_pzsCurrentValue, + GameGlobals::Cvar->FindVar("mp_gamemode")->m_pzsCurrentValue, + MyServer.password, + std::to_string(*reinterpret_cast(0x1656057E0)), + std::string()} + ); + if (result) { HostRequestMessageColor = ImVec4(0.00f, 1.00f, 0.00f, 1.00f); @@ -152,16 +162,18 @@ void CCompanion::ServerBrowserSection() RefreshServerList(); } ImGui::EndGroup(); + ImGui::TextColored(ImVec4(1.00f, 0.00f, 0.00f, 1.00f), ServerListMessage.c_str()); ImGui::Separator(); const float FooterHeight = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); ImGui::BeginChild("ServerListChild", { 0, -FooterHeight }, true, ImGuiWindowFlags_AlwaysVerticalScrollbar); - if (ImGui::BeginTable("##ServerBrowser_ServerList", 4, ImGuiTableFlags_Resizable)) + if (ImGui::BeginTable("##ServerBrowser_ServerList", 5, ImGuiTableFlags_Resizable)) { - ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 35); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 20); ImGui::TableSetupColumn("Map", ImGuiTableColumnFlags_WidthStretch, 25); - ImGui::TableSetupColumn("Port", ImGuiTableColumnFlags_WidthStretch, 10); - ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 8); + ImGui::TableSetupColumn("Port", ImGuiTableColumnFlags_WidthStretch, 5); + ImGui::TableSetupColumn("Gamemode", ImGuiTableColumnFlags_WidthStretch, 5); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 5); ImGui::TableHeadersRow(); for (ServerListing& server : ServerList) @@ -169,6 +181,7 @@ void CCompanion::ServerBrowserSection() const char* name = server.name.c_str(); const char* map = server.map.c_str(); const char* port = server.port.c_str(); + const char* gamemode = server.gamemode.c_str(); if (ServerBrowserFilter.PassFilter(name) || ServerBrowserFilter.PassFilter(map) @@ -183,6 +196,9 @@ void CCompanion::ServerBrowserSection() ImGui::TableNextColumn(); ImGui::Text(port); + ImGui::TableNextColumn(); + ImGui::Text(gamemode); + ImGui::TableNextColumn(); std::string selectButtonText = "Connect##"; selectButtonText += (server.name + server.ip + server.map); diff --git a/r5dev/src/CGameConsole.cpp b/r5dev/src/CGameConsole.cpp index 0b253347..0fe76f43 100644 --- a/r5dev/src/CGameConsole.cpp +++ b/r5dev/src/CGameConsole.cpp @@ -155,6 +155,10 @@ void CGameConsole::Draw(const char* title) if (strstr(item, "Script(C):")) { color = ImVec4(0.59f, 0.58f, 0.63f, 1.00f); has_color = true; } if (strstr(item, "Script(U):")) { color = ImVec4(0.59f, 0.48f, 0.53f, 1.00f); has_color = true; } + if (strstr(item, "Script(S) Warning:")) { color = ImVec4(0.80f, 0.80f, 0.73f, 1.00f); has_color = true; } + if (strstr(item, "Script(C) Warning:")) { color = ImVec4(0.80f, 0.80f, 0.63f, 1.00f); has_color = true; } + if (strstr(item, "Script(U) Warning:")) { color = ImVec4(0.80f, 0.80f, 0.53f, 1.00f); has_color = true; } + /////////////////////////////////////////////////////////////////// // Callbacks //if (strstr(item, "CodeCallback_")) { color = ImVec4(0.00f, 0.30f, 1.00f, 1.00f); has_color = true; } diff --git a/r5dev/src/gameclasses.cpp b/r5dev/src/gameclasses.cpp index 2a5eb024..84da7d83 100644 --- a/r5dev/src/gameclasses.cpp +++ b/r5dev/src/gameclasses.cpp @@ -8,6 +8,36 @@ namespace GameGlobals CInputSystem* InputSystem = nullptr; CCVar* Cvar = nullptr; + void EmptyHostNames() + { + const char* hostnameArray[] = + { + "pin_telemetry_hostname", + "assetdownloads_hostname", + "users_hostname", + "persistence_hostname", + "speechtotexttoken_hostname", + "communities_hostname", + "persistenceDef_hostname", + "party_hostname", + "speechtotext_hostname", + "serverReports_hostname", + "subscription_hostname", + "steamlink_hostname", + "staticfile_hostname", + "matchmaking_hostname", + "skill_hostname", + "publication_hostname", + "stats_hostname" + }; + + for (int i = 0; i < 17; i++) + { + const char* name = hostnameArray[i]; + Cvar->FindVar(name)->m_pzsCurrentValue = "0.0.0.0"; + } + } + void InitGameGlobals() { HostState = reinterpret_cast(0x141736120); // Get CHostState from memory. @@ -19,7 +49,7 @@ namespace GameGlobals // { // printf("%s: %p\n", current->InterfaceName, current->InterfacePtr); // } - + EmptyHostNames(); IsInitialized = true; } } \ No newline at end of file diff --git a/r5dev/src/hooks/hooks.cpp b/r5dev/src/hooks/hooks.cpp index c255b3ab..08dbee96 100644 --- a/r5dev/src/hooks/hooks.cpp +++ b/r5dev/src/hooks/hooks.cpp @@ -18,6 +18,7 @@ void Hooks::InstallHooks() /////////////////////////////////////////////////////////////////////////////// // Hook Squirrel functions MH_CreateHook(addr_SQVM_Print, &Hooks::SQVM_Print, NULL); + MH_CreateHook(addr_SQVM_Warning, &Hooks::SQVM_Warning, reinterpret_cast(&originalSQVM_Warning)); MH_CreateHook(addr_SQVM_LoadRson, &Hooks::SQVM_LoadRson, reinterpret_cast(&originalSQVM_LoadRson)); MH_CreateHook(addr_SQVM_LoadScript, &Hooks::SQVM_LoadScript, reinterpret_cast(&originalSQVM_LoadScript)); @@ -35,8 +36,8 @@ void Hooks::InstallHooks() /////////////////////////////////////////////////////////////////////////////// // Hook ConVar | ConCommand functions. - MH_CreateHook(addr_ConVar_IsFlagSet, &Hooks::ConVar_IsFlagSet, NULL); - MH_CreateHook(addr_ConCommand_IsFlagSet, &Hooks::ConCommand_IsFlagSet, NULL); + MH_CreateHook(addr_ConVar_IsFlagSet, &Hooks::ConVar_IsFlagSet, reinterpret_cast(&originalConVar_IsFlagSet)); + MH_CreateHook(addr_ConCommand_IsFlagSet, &Hooks::ConCommand_IsFlagSet, reinterpret_cast(&originalConCommand_IsFlagSet)); /////////////////////////////////////////////////////////////////////////////// // Hooks CBaseFileSystem functions. @@ -71,6 +72,7 @@ void Hooks::InstallHooks() /////////////////////////////////////////////////////////////////////////////// // Enable Squirrel hooks MH_EnableHook(addr_SQVM_Print); + MH_EnableHook(addr_SQVM_Warning); MH_EnableHook(addr_SQVM_LoadRson); MH_EnableHook(addr_SQVM_LoadScript); diff --git a/r5dev/src/hooks/iconvar.cpp b/r5dev/src/hooks/iconvar.cpp index fcefe2fb..b57c180e 100644 --- a/r5dev/src/hooks/iconvar.cpp +++ b/r5dev/src/hooks/iconvar.cpp @@ -1,65 +1,85 @@ #include "pch.h" #include "hooks.h" -bool Hooks::ConVar_IsFlagSet(int** cvar, int flag) +namespace Hooks { - int real_flags = *(*(cvar + (72 / (sizeof(void*)))) + (56 / sizeof(int))); - if (g_bDebugConsole) - { - printf("--------------------------------------------------\n"); - printf(" Flaged: %08X\n", real_flags); - } - // Mask off FCVAR_CHEATS and FCVAR_DEVELOPMENTONLY - real_flags &= 0xFFFFBFFD; - if (g_bDebugConsole) - { - printf(" Masked: %08X\n", real_flags); - printf(" Verify: %08X\n", flag); - printf("--------------------------------------------------\n"); - } - if (flag & 0x80000) - { - return true; - } - - if (!g_bReturnAllFalse) - { - return (real_flags & flag) != 0; - } - else - { - return false; - } + ConVar_IsFlagSetFn originalConVar_IsFlagSet = nullptr; + ConCommand_IsFlagSetFn originalConCommand_IsFlagSet = nullptr; + Map_CallbackFn originalMap_Callback = nullptr; } -bool Hooks::ConCommand_IsFlagSet(int* cmd, int flag) +bool Hooks::ConVar_IsFlagSet(ConVar* cvar, int flag) { - int real_flags = *((cmd + (56 / sizeof(int)))); +#ifdef _DEBUG if (g_bDebugConsole) { printf("--------------------------------------------------\n"); - printf(" Flaged: %08X\n", real_flags); + printf(" Flaged: %08X\n", cvar->m_ConCommandBase.m_nFlags); } // Mask off FCVAR_CHEATS and FCVAR_DEVELOPMENTONLY - real_flags &= 0xFFFFBFFD; + cvar->m_ConCommandBase.m_nFlags &= 0xFFFFBFFD; if (g_bDebugConsole) { - printf(" Masked: %08X\n", real_flags); + printf(" Masked: %08X\n", cvar->m_ConCommandBase.m_nFlags); printf(" Verify: %08X\n", flag); printf("--------------------------------------------------\n"); } - if (flag & 0x80000) + if (flag & FCVAR_RELEASE) { return true; } if (!g_bReturnAllFalse) { - return (real_flags & flag) != 0; + return (cvar->m_ConCommandBase.m_nFlags & flag) != 0; } else { return false; } +#else + // Mask off FCVAR_DEVELOPMENTONLY if existing. + cvar->m_ConCommandBase.m_nFlags &= ~FCVAR_DEVELOPMENTONLY; + + return originalConVar_IsFlagSet(cvar, flag); +#endif +} + +bool Hooks::ConCommand_IsFlagSet(ConCommandBase* cmd, int flag) +{ +#ifdef _DEBUG + if (g_bDebugConsole) + { + printf("--------------------------------------------------\n"); + printf(" Flaged: %08X\n", cmd->m_nFlags); + } + // Mask off FCVAR_CHEATS and FCVAR_DEVELOPMENTONLY + cmd->m_nFlags &= 0xFFFFBFFD; + if (g_bDebugConsole) + { + printf(" Masked: %08X\n", cmd->m_nFlags); + printf(" Verify: %08X\n", flag); + printf("--------------------------------------------------\n"); + } + + if (flag & FCVAR_RELEASE) + { + return true; + } + + if (!g_bReturnAllFalse) + { + return (cmd->m_nFlags & flag) != 0; + } + else + { + return false; + } +#else + // Mask off FCVAR_DEVELOPMENTONLY if existing. + cmd->m_nFlags &= ~FCVAR_DEVELOPMENTONLY; + + return originalConCommand_IsFlagSet(cmd, flag); +#endif } \ No newline at end of file diff --git a/r5dev/src/hooks/sqvm.cpp b/r5dev/src/hooks/sqvm.cpp index 5589caf7..1ffba120 100644 --- a/r5dev/src/hooks/sqvm.cpp +++ b/r5dev/src/hooks/sqvm.cpp @@ -3,12 +3,13 @@ namespace Hooks { + SQVM_WarningFn originalSQVM_Warning = nullptr; SQVM_LoadRsonFn originalSQVM_LoadRson = nullptr; SQVM_LoadScriptFn originalSQVM_LoadScript = nullptr; } -static std::ostringstream oss; -static auto ostream_sink = std::make_shared(oss); +static std::ostringstream oss_print; +static auto ostream_sink_print = std::make_shared(oss_print); //--------------------------------------------------------------------------------- // Purpose: prints the output of each VM to the console @@ -21,17 +22,17 @@ void* Hooks::SQVM_Print(void* sqvm, char* fmt, ...) static char buf[1024]; static std::string vmType[3] = { "Script(S):", "Script(C):", "Script(U):" }; - static auto iconsole = spdlog::stdout_logger_mt("sqvm_iconsole"); // in-game console - static auto wconsole = spdlog::stdout_logger_mt("sqvm_wconsole"); // windows console + static auto iconsole = spdlog::stdout_logger_mt("sqvm_print_iconsole"); // in-game console + static auto wconsole = spdlog::stdout_logger_mt("sqvm_print_wconsole"); // windows console std::string vmStr = vmType[vmIdx].c_str(); - oss.str(""); - oss.clear(); + oss_print.str(""); + oss_print.clear(); if (!initialized) { - iconsole = std::make_shared("ostream", ostream_sink); + iconsole = std::make_shared("ostream", ostream_sink_print); iconsole->set_pattern("[%S.%e] %v"); iconsole->set_level(spdlog::level::debug); wconsole->set_pattern("[%S.%e] %v"); @@ -52,13 +53,62 @@ void* Hooks::SQVM_Print(void* sqvm, char* fmt, ...) iconsole->debug(vmStr); wconsole->debug(vmStr); - std::string s = oss.str(); + std::string s = oss_print.str(); const char* c = s.c_str(); Items.push_back(Strdup((const char*)c)); return NULL; } +static std::ostringstream oss_warning; +static auto ostream_sink_warning = std::make_shared(oss_warning); + +__int64 Hooks::SQVM_Warning(void* sqvm, int a2, int a3, int* stringSize, void** string) +{ + __int64 result = originalSQVM_Warning(sqvm, a2, a3, stringSize, string); + + void* retaddr = _ReturnAddress(); // Get return address. + + if (retaddr != addr_SQVM_Warning_ReturnAddr) // Check if its SQVM_Warning calling. + return result; // If not return. + + static bool initialized = false; + static auto iconsole = spdlog::stdout_logger_mt("sqvm_warning_iconsole"); // in-game console + static auto wconsole = spdlog::stdout_logger_mt("sqvm_warning_wconsole"); // windows console + + static std::string vmType[3] = { "Script(S) Warning:", "Script(C) Warning:", "Script(U) Warning:" }; + + int vmIdx = *(int*)((std::uintptr_t)sqvm + 0x18); // Get vm index. + + std::string vmStr = vmType[vmIdx].c_str(); // Get string prefix for vm. + + oss_warning.str(""); + oss_warning.clear(); + + if (!initialized) + { + iconsole = std::make_shared("ostream", ostream_sink_warning); + iconsole->set_pattern("[%S.%e] %v"); + iconsole->set_level(spdlog::level::debug); + wconsole->set_pattern("[%S.%e] %v\n"); + wconsole->set_level(spdlog::level::debug); + initialized = true; + } + + std::string stringConstructor((char*)*string, *stringSize); // Get string from memory via std::string constructor. + vmStr.append(stringConstructor); + + iconsole->debug(vmStr.c_str()); + wconsole->debug(vmStr.c_str()); + + std::string s = oss_warning.str(); + const char* c = s.c_str(); + + Items.push_back(Strdup((const char*)c)); + + return result; +} + //--------------------------------------------------------------------------------- // Purpose: loads the include file from the mods directory //--------------------------------------------------------------------------------- diff --git a/r5net/include/r5/r5net.h b/r5net/include/r5/r5net.h index dadf9124..dd77c6ad 100644 --- a/r5net/include/r5/r5net.h +++ b/r5net/include/r5/r5net.h @@ -20,8 +20,9 @@ namespace R5Net m_HttpClient.set_connection_timeout(10); } - std::vector GetServersList(); + std::vector GetServersList(std::string& outMessage); bool PostServerHost(std::string& outMessage, std::string& outToken, const ServerListing& serverListing); bool GetServerByToken(ServerListing& outServer, std::string& outError, const std::string& token, const std::string& password = ""); + std::string GetVersionString(); }; } \ No newline at end of file diff --git a/r5net/include/r5/serverlisting.h b/r5net/include/r5/serverlisting.h index dbc5972c..8db411c3 100644 --- a/r5net/include/r5/serverlisting.h +++ b/r5net/include/r5/serverlisting.h @@ -6,7 +6,9 @@ struct ServerListing std::string map; std::string ip; std::string port; + std::string gamemode; std::string password; std::string checksum; + std::string version; }; diff --git a/r5net/src/r5net.cpp b/r5net/src/r5net.cpp index 7c4a16ef..852ca936 100644 --- a/r5net/src/r5net.cpp +++ b/r5net/src/r5net.cpp @@ -4,22 +4,47 @@ #include "netpch.h" #include "r5\r5net.h" -std::vector R5Net::Client::GetServersList() +std::string R5Net::Client::GetVersionString() +{ + return "beta 1.5"; +} + +std::vector R5Net::Client::GetServersList(std::string& outMessage) { std::vector list{ }; - - auto res = m_HttpClient.Get("/servers"); - if (!res) return std::vector(); + nlohmann::json reqBody = nlohmann::json::object(); + reqBody["version"] = GetVersionString(); + + std::string reqBodyStr = reqBody.dump();; + + httplib::Result res = m_HttpClient.Post("/servers", reqBody.dump().c_str(), reqBody.dump().length(), "application/json"); + + if (res) { - nlohmann::json root = nlohmann::json::parse(res->body); - for (auto obj : root["servers"]) + nlohmann::json resBody = nlohmann::json::parse(res->body); + if (resBody["success"].is_boolean() && resBody["success"].get()) { - list.push_back( - ServerListing{ obj["name"].get(), obj["map"].get(), obj["ip"].get(), obj["port"].get() } - ); + for (auto obj : resBody["servers"]) + { + list.push_back( + ServerListing{ obj["name"].get(), obj["map"].get(), obj["ip"].get(), obj["port"].get(), obj["gamemode"].get() } + ); + } + } + else + { + if (resBody["err"].is_string()) + outMessage = resBody["err"].get(); + else + outMessage = "An unknown error occured!"; } } + else + { + outMessage = "Failed to reach comp-server"; + } + return list; } @@ -31,6 +56,8 @@ bool R5Net::Client::PostServerHost(std::string& outMessage, std::string& outToke reqBody["port"] = serverListing.port; reqBody["password"] = serverListing.password; reqBody["remote_checksum"] = serverListing.checksum; + reqBody["version"] = GetVersionString(); + reqBody["gamemode"] = serverListing.gamemode; std::string reqBodyStr = reqBody.dump(); @@ -44,7 +71,7 @@ bool R5Net::Client::PostServerHost(std::string& outMessage, std::string& outToke } nlohmann::json resBody = nlohmann::json::parse(res->body); - if (resBody["success"].is_boolean() && resBody["success"]) + if (resBody["success"].is_boolean() && resBody["success"].get()) { if (resBody["token"].is_string()) outToken = resBody["token"].get();