mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Alot of changes read description
* Ban list added * Playlist parser added * Kick functions added * Connect uses encryption keys now * Fixed restricted server commands
This commit is contained in:
parent
c89c7c9c6b
commit
2da6d71fb3
@ -26,20 +26,27 @@ public:
|
||||
|
||||
enum class EHostStatus {
|
||||
NotHosting,
|
||||
WaitingForStateChange,
|
||||
Hosting,
|
||||
ConnectedToSomeoneElse
|
||||
Hosting
|
||||
} HostingStatus = EHostStatus::NotHosting;
|
||||
|
||||
enum class EServerVisibility {
|
||||
Offline,
|
||||
Hidden,
|
||||
Public
|
||||
} ServerVisibility = EServerVisibility::Offline;
|
||||
|
||||
////////////////////
|
||||
// Server Browser //
|
||||
////////////////////
|
||||
|
||||
R5Net::Client* r5net;
|
||||
|
||||
R5Net::Client* GetR5Net() { return r5net; }
|
||||
|
||||
std::vector<ServerListing> ServerList;
|
||||
ImGuiTextFilter ServerBrowserFilter;
|
||||
char ServerConnStringBuffer[256] = { 0 };
|
||||
char ServerEncKeyBuffer[30] = { 0 };
|
||||
std::string ServerListMessage = std::string();
|
||||
|
||||
////////////////////
|
||||
@ -56,16 +63,14 @@ public:
|
||||
std::string HostToken = "";
|
||||
ImVec4 HostRequestMessageColor = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
||||
bool StartAsDedi = false;
|
||||
bool BroadCastServer = false;
|
||||
bool OverridePlaylist = false;
|
||||
|
||||
////////////////////
|
||||
// Private Server //
|
||||
////////////////////
|
||||
std::string PrivateServerToken = "";
|
||||
std::string PrivateServerPassword = "";
|
||||
std::string PrivateServerRequestMessage = "";
|
||||
ImVec4 PrivateServerMessageColor = ImVec4(0.00f, 1.00f, 0.00f, 1.00f);
|
||||
std::string HiddenServerToken = "";
|
||||
std::string HiddenServerRequestMessage = "";
|
||||
ImVec4 HiddenServerMessageColor = ImVec4(0.00f, 1.00f, 0.00f, 1.00f);
|
||||
|
||||
/* Texture */
|
||||
ID3D11ShaderResourceView* ApexLockIcon = nullptr;
|
||||
@ -144,14 +149,20 @@ public:
|
||||
void CompMenu();
|
||||
void ServerBrowserSection();
|
||||
void SettingsSection();
|
||||
void HiddenServersModal();
|
||||
void HostServerSection();
|
||||
void Draw(const char* title);
|
||||
void UpdateHostingStatus();
|
||||
void ProcessCommand(const char* command_line);
|
||||
void ExecCommand(const char* command_line);
|
||||
|
||||
void ConnectToServer(const std::string &ip, const std::string &port);
|
||||
void ConnectToServer(const std::string &connString);
|
||||
void RegenerateEncryptionKey();
|
||||
void ChangeEncryptionKeyTo(const std::string str);
|
||||
|
||||
void ConnectToServer(const std::string ip, const std::string port, const std::string encKey);
|
||||
void ConnectToServer(const std::string connString, const std::string encKey);
|
||||
};
|
||||
|
||||
extern CCompanion* g_ServerBrowser;
|
||||
extern CCompanion* g_ServerBrowser;
|
||||
|
||||
extern bool g_CheckCompBanDB;
|
@ -417,4 +417,6 @@ enum FileWarningLevel_t
|
||||
|
||||
#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.
|
||||
#define FCVAR_CLIENTCMD_CAN_EXECUTE (1<<30) // IVEngineClient::ClientCmd is allowed to execute this command.
|
||||
|
||||
#define MAX_PLAYERS 128 // Max R5 players.
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "patterns.h"
|
||||
#include "banlist.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Classes and Structs
|
||||
@ -238,8 +239,8 @@ struct QAngle // Implement the proper class of this at some point.
|
||||
class CHostState
|
||||
{
|
||||
public:
|
||||
__int32 m_iCurrentState; //0x0000
|
||||
__int32 m_iNextState; //0x0004
|
||||
int m_iCurrentState; //0x0000
|
||||
int m_iNextState; //0x0004
|
||||
Vector3 m_vecLocation; //0x0008
|
||||
QAngle m_angLocation; //0x0014
|
||||
char m_levelName[64]; //0x0020
|
||||
@ -265,6 +266,98 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class CClient
|
||||
{
|
||||
public:
|
||||
inline CClient* GetClientInstance(int index)
|
||||
{
|
||||
return (CClient*)(std::uintptr_t)(0x16073B200 + (index * (std::uintptr_t)0x4A4C0));
|
||||
}
|
||||
|
||||
void*& GetNetChan()
|
||||
{
|
||||
return m_nNetChannel;
|
||||
}
|
||||
private:
|
||||
char pad_0000[16]; //0x0000
|
||||
public:
|
||||
int m_iUserID; //0x0010
|
||||
private:
|
||||
char pad_0014[908]; //0x0014
|
||||
public:
|
||||
void* m_nNetChannel; //0x03A0
|
||||
private:
|
||||
char pad_03A8[8]; //0x03A8
|
||||
public:
|
||||
int m_iSignonstate; //0x03B0
|
||||
private:
|
||||
char pad_03B4[4]; //0x03B4
|
||||
public:
|
||||
std::int64_t m_iOriginID; //0x03B8
|
||||
private:
|
||||
char pad_03C0[303360]; //0x03C0
|
||||
};
|
||||
|
||||
class CCommand
|
||||
{
|
||||
private:
|
||||
enum
|
||||
{
|
||||
COMMAND_MAX_ARGC = 64,
|
||||
COMMAND_MAX_LENGTH = 512,
|
||||
};
|
||||
|
||||
public:
|
||||
CCommand() = delete;
|
||||
|
||||
inline int MaxCommandLength()
|
||||
{
|
||||
return COMMAND_MAX_LENGTH - 1;
|
||||
}
|
||||
|
||||
inline int64_t ArgC() const
|
||||
{
|
||||
return m_nArgc;
|
||||
}
|
||||
|
||||
inline const char** ArgV() const
|
||||
{
|
||||
return m_nArgc ? (const char**)m_ppArgv : NULL;
|
||||
}
|
||||
|
||||
inline const char* ArgS() const
|
||||
{
|
||||
return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : "";
|
||||
}
|
||||
|
||||
inline const char* GetCommandString() const
|
||||
{
|
||||
return m_nArgc ? m_pArgSBuffer : "";
|
||||
}
|
||||
|
||||
inline const char* Arg(int nIndex) const
|
||||
{
|
||||
// FIXME: Many command handlers appear to not be particularly careful
|
||||
// about checking for valid argc range. For now, we're going to
|
||||
// do the extra check and return an empty string if it's out of range
|
||||
if (nIndex < 0 || nIndex >= m_nArgc)
|
||||
return "";
|
||||
return m_ppArgv[nIndex];
|
||||
}
|
||||
|
||||
inline const char* operator[](int nIndex) const
|
||||
{
|
||||
return Arg(nIndex);
|
||||
}
|
||||
|
||||
private:
|
||||
std::int64_t m_nArgc;
|
||||
std::int64_t m_nArgv0Size;
|
||||
char m_pArgSBuffer[COMMAND_MAX_LENGTH];
|
||||
char m_pArgvBuffer[COMMAND_MAX_LENGTH];
|
||||
const char* m_ppArgv[COMMAND_MAX_ARGC];
|
||||
};
|
||||
|
||||
class ConCommandBase
|
||||
{
|
||||
public:
|
||||
@ -368,16 +461,27 @@ struct Interface
|
||||
|
||||
namespace GameGlobals
|
||||
{
|
||||
// Class Instances
|
||||
extern CHostState* HostState;
|
||||
extern CInputSystem* InputSystem;
|
||||
extern CCVar* Cvar;
|
||||
extern KeyValues** PlaylistKeyValues;
|
||||
extern CKeyValuesSystem* KeyValuesSystem;
|
||||
extern std::vector<std::string> allPlaylists;
|
||||
|
||||
extern CClient* Client;
|
||||
extern BanList* BanSystem;
|
||||
|
||||
// Var
|
||||
ConVar* CreateCustomConVar(const char* name, const char* defaultValue, int flags, const char* helpString, bool bMin, float fMin, bool bMax, float fMax, void* callback, void* unk);
|
||||
void* CreateCustomConCommand(const char* name, const char* helpString, int flags, void* callback, void* callbackAfterExecution);
|
||||
|
||||
// Init
|
||||
void InitGameGlobals();
|
||||
void InitConVars();
|
||||
void InitAllCommandVariations();
|
||||
void InitPlaylist();
|
||||
|
||||
extern std::vector<std::string> allPlaylists;
|
||||
extern bool IsInitialized;
|
||||
|
||||
// Utility
|
||||
void DisconnectClient(CClient* client, const char* reason, unsigned __int8 unk1, char unk2);
|
||||
}
|
@ -27,12 +27,12 @@ public:
|
||||
std::filesystem::path path = std::filesystem::current_path() /= "gui.config"; // Get current path + gui.config
|
||||
|
||||
nlohmann::json in;
|
||||
std::ifstream config_file(path, std::ios::in); // Parse config file.
|
||||
std::ifstream configFile(path, std::ios::in); // Parse config file.
|
||||
|
||||
if (config_file.good() && config_file) // Check if it parsed.
|
||||
if (configFile.good() && configFile) // Check if it parsed.
|
||||
{
|
||||
config_file >> in;
|
||||
config_file.close();
|
||||
configFile >> in;
|
||||
configFile.close();
|
||||
|
||||
if (!in.is_null())
|
||||
{
|
||||
@ -63,11 +63,11 @@ public:
|
||||
out["config"]["CCompanion"]["bind2"] = CCompanionConfig.bind2;
|
||||
|
||||
std::filesystem::path path = std::filesystem::current_path() /= "gui.config"; // Get current path + gui.config
|
||||
std::ofstream out_file(path, std::ios::out | std::ios::trunc); // Write config file..
|
||||
std::ofstream outFile(path, std::ios::out | std::ios::trunc); // Write config file..
|
||||
|
||||
out_file << out.dump(4); // Dump it into config file..
|
||||
outFile << out.dump(4); // Dump it into config file..
|
||||
|
||||
out_file.close(); // Close the file handle.
|
||||
outFile.close(); // Close the file handle.
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -36,6 +36,13 @@ namespace Hooks
|
||||
extern SQVM_LoadScriptFn originalSQVM_LoadScript;
|
||||
#pragma endregion
|
||||
|
||||
#pragma region CServer
|
||||
void* ConnectClient(void* thisptr, void* packet);
|
||||
|
||||
using ConnectClientFn = void* (*)(void*, void*);
|
||||
extern ConnectClientFn originalConnectClient;
|
||||
#pragma endregion
|
||||
|
||||
#pragma region CVEngineServer
|
||||
bool IsPersistenceDataAvailable(__int64 thisptr, int client);
|
||||
|
||||
@ -47,7 +54,7 @@ namespace Hooks
|
||||
bool NET_ReceiveDatagram(int sock, void* inpacket, bool raw);
|
||||
unsigned int NET_SendDatagram(SOCKET s, const char* buf, int len, int flags);
|
||||
void NET_PrintFunc(const char* fmt, ...);
|
||||
void NetChanShutdown(void* rcx, const char* reason, unsigned __int8 unk1, char unk2);
|
||||
void NetChan_Shutdown(void* rcx, const char* reason, unsigned __int8 unk1, char unk2);
|
||||
|
||||
using NET_PrintFuncFn = void(*)(const char* fmt, ...);
|
||||
extern NET_PrintFuncFn originalNET_PrintFunc;
|
||||
@ -58,7 +65,7 @@ namespace Hooks
|
||||
using NET_SendDatagramFn = unsigned int(*)(SOCKET, const char*, int, int);
|
||||
extern NET_SendDatagramFn originalNET_SendDatagram;
|
||||
using NetChan_ShutDown = void(*)(void*, const char*, unsigned __int8, char);
|
||||
extern NetChan_ShutDown originalNetChanShutDown;
|
||||
extern NetChan_ShutDown originalNetChan_ShutDown;
|
||||
#pragma endregion
|
||||
|
||||
#pragma region ConVar
|
||||
@ -70,9 +77,6 @@ namespace Hooks
|
||||
|
||||
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
|
||||
|
@ -29,6 +29,8 @@ namespace
|
||||
#pragma region NetChannel
|
||||
/*0x14030D000*/
|
||||
MemoryAddress CServer_Auth = r5_op.PatternSearch("40 55 57 41 55 41 57 48 8D AC 24 ? ? ? ?");
|
||||
/*0x1413336F0*/
|
||||
MemoryAddress NetChan_EncKey_DefaultAssign = r5_op.PatternSearch("E8 ? ? ? ? 48 8D 1D ? ? ? ? 4C 39 3D ? ? ? ?");
|
||||
#pragma endregion
|
||||
|
||||
#pragma region FairFight
|
||||
@ -50,6 +52,7 @@ namespace
|
||||
PRINT_ADDRESS("dst004", dst004.GetPtr());
|
||||
PRINT_ADDRESS("Host_NewGame", Host_NewGame.GetPtr());
|
||||
PRINT_ADDRESS("CServer_Auth", CServer_Auth.GetPtr());
|
||||
PRINT_ADDRESS("NetChan_EncKey_DefaultAssign", NetChan_EncKey_DefaultAssign.GetPtr());
|
||||
PRINT_ADDRESS("FairFight_Init", FairFight_Init.GetPtr());
|
||||
PRINT_ADDRESS("Squirrel_CompileError", Squirrel_CompileError.GetPtr());
|
||||
std::cout << "+--------------------------------------------------------+" << std::endl;
|
||||
|
@ -50,7 +50,24 @@ namespace
|
||||
FUNC_AT_ADDRESS(addr_NET_SendDatagram, int(*)(SOCKET, const char*, int, int), r5_patterns.PatternSearch("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 41 56 41 57 48 81 EC ? 05 ? ?").GetPtr());
|
||||
|
||||
/*0x14025F190*/
|
||||
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).FollowNearCall().GetPtr());
|
||||
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*>();
|
||||
|
||||
|
||||
/*0x140263E70*/
|
||||
FUNC_AT_ADDRESS(addr_NetChan_SetEncKey, void(*)(uintptr_t, const char*), MemoryAddress(0x140263E70).GetPtr());
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region CServer
|
||||
/*0x140310230*/
|
||||
FUNC_AT_ADDRESS(addr_CServer_RejectConnection, void(*)(void*, unsigned int, void*, const char*), r5_patterns.StringSearch("#CONNECTION_FAILED_RESERVATION_TIMEOUT").FindPatternSelf("E8", MemoryAddress::Direction::DOWN).FollowNearCallSelf().GetPtr());
|
||||
|
||||
/*0x14030D000*/
|
||||
FUNC_AT_ADDRESS(addr_CServer_ConnectClient, void*(*)(void*, void*), r5_patterns.StringSearch("dedi.connect.fail.total:1|c\n").FindPatternSelf("E8", MemoryAddress::Direction::UP).FollowNearCallSelf().GetPtr());
|
||||
#pragma endregion
|
||||
|
||||
#pragma region CHLClient
|
||||
@ -58,6 +75,16 @@ namespace
|
||||
FUNC_AT_ADDRESS(addr_CHLClient_FrameStageNotify, void(*)(void*, int), r5_patterns.PatternSearch("48 83 EC 28 89 15 ?? ?? ?? ??").GetPtr());
|
||||
#pragma endregion
|
||||
|
||||
#pragma region CClient
|
||||
/*0x140302FD0*/
|
||||
FUNC_AT_ADDRESS(addr_CClient_Clear, void(*)(__int64), r5_patterns.StringSearch("Disconnect by server.\n").FindPatternSelf("40", MemoryAddress::Direction::UP).GetPtr());
|
||||
#pragma endregion
|
||||
|
||||
#pragma region CClientState
|
||||
/*0x1418223E4*/
|
||||
FUNC_AT_ADDRESS(addr_m_bRestrictServerCommands, void*, r5_patterns.StringSearch("DevShotGenerator_Init()").FindPatternSelf("88 05", MemoryAddress::Direction::UP).ResolveRelativeAddressSelf(0x2).OffsetSelf(0x2).GetPtr());
|
||||
#pragma endregion
|
||||
|
||||
#pragma region CVEngineServer
|
||||
/*0x140315CF0*/
|
||||
FUNC_AT_ADDRESS(addr_CVEngineServer_IsPersistenceDataAvailable, bool(*)(__int64, int), r5_patterns.PatternSearch("3B 15 ?? ?? ?? ?? 7D 33").GetPtr());
|
||||
@ -80,7 +107,7 @@ namespace
|
||||
FUNC_AT_ADDRESS(addr_LoadPlaylist, bool(*)(const char*), r5_patterns.PatternSearch("E8 ? ? ? ? 80 3D ? ? ? ? ? 74 0C").FollowNearCallSelf().GetPtr());
|
||||
|
||||
/*0x1671060C0*/
|
||||
FUNC_AT_ADDRESS(addr_MapVPKCache, void*, r5_patterns.StringSearch("PrecacheMTVF").FindPatternSelf("48 8D 1D ? ? ? ? 4C", MemoryAddress::Direction::UP, 900).OffsetSelf(0x3).ResolveRelativeAddress().GetPtr());
|
||||
FUNC_AT_ADDRESS(addr_MapVPKCache, void*, r5_patterns.StringSearch("PrecacheMTVF").FindPatternSelf("48 8D 1D ? ? ? ? 4C", MemoryAddress::Direction::UP, 900).OffsetSelf(0x3).ResolveRelativeAddressSelf().GetPtr());
|
||||
|
||||
/*0x140278C50*/
|
||||
FUNC_AT_ADDRESS(addr_mp_gamemode_Callback, bool(*)(const char*), r5_patterns.StringSearch("Failed to load playlist data\n").FindPatternSelf("E8 ? ? ? ? B0 01", MemoryAddress::Direction::DOWN, 200).FollowNearCallSelf().GetPtr());
|
||||
@ -108,6 +135,7 @@ namespace
|
||||
PRINT_ADDRESS("NET_PrintFunc", addr_NET_PrintFunc);
|
||||
PRINT_ADDRESS("NET_ReceiveDatagram", addr_NET_ReceiveDatagram);
|
||||
PRINT_ADDRESS("NET_SendDatagram ", addr_NET_SendDatagram);
|
||||
PRINT_ADDRESS("CClientState::m_bRestrictServerCommands", addr_m_bRestrictServerCommands);
|
||||
PRINT_ADDRESS("INetChannel::Shutdown", addr_NetChan_Shutdown);
|
||||
PRINT_ADDRESS("CHLClient::FrameStageNotify", addr_CHLClient_FrameStageNotify);
|
||||
PRINT_ADDRESS("CVEngineServer::IsPersistenceDataAvailable", addr_CVEngineServer_IsPersistenceDataAvailable);
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
@ -148,7 +148,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>r5dev.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>Minhook.x64.lib;r5net.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Minhook.x64.lib;r5net.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>del "$(SolutionDir)bin\$(Configuration)\r5dev.dll"
|
||||
@ -189,7 +189,7 @@ if not EXIST $(SolutionDir)r5net\lib\$(Configuration)\r5net.lib (
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<ModuleDefinitionFile>r5dev.def</ModuleDefinitionFile>
|
||||
<AdditionalDependencies>Minhook.x64.lib;r5net.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Minhook.x64.lib;r5net.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
@ -310,6 +310,7 @@ if not EXIST $(SolutionDir)r5net\lib\$(Configuration)\r5net.lib (
|
||||
<ClInclude Include="..\external\spdlog\include\tweakme.h" />
|
||||
<ClInclude Include="..\external\spdlog\include\version.h" />
|
||||
<ClInclude Include="..\shared\include\address.h" />
|
||||
<ClInclude Include="..\shared\include\banlist.h" />
|
||||
<ClInclude Include="..\shared\include\httplib.h" />
|
||||
<ClInclude Include="..\shared\include\json.hpp" />
|
||||
<ClInclude Include="..\shared\include\utility.h" />
|
||||
@ -379,6 +380,7 @@ if not EXIST $(SolutionDir)r5net\lib\$(Configuration)\r5net.lib (
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\hooks\cbasefilesystem.cpp" />
|
||||
<ClCompile Include="src\hooks\chlclient.cpp" />
|
||||
<ClCompile Include="src\hooks\connectclient.cpp" />
|
||||
<ClCompile Include="src\hooks\cvengineserver.cpp" />
|
||||
<ClCompile Include="src\hooks\hooks.cpp" />
|
||||
<ClCompile Include="src\hooks\iconvar.cpp" />
|
||||
|
@ -103,6 +103,9 @@
|
||||
<Filter Include="hooks\src\cbasefilesystem">
|
||||
<UniqueIdentifier>{90ee1072-2d57-4d4e-aa1e-f19a81e6b27f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="hooks\src\cserver">
|
||||
<UniqueIdentifier>{10edfee7-8c10-41de-b8f3-424826d2614a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\dllmain.cpp">
|
||||
@ -195,6 +198,9 @@
|
||||
<ClCompile Include="src\hooks\loadplaylist.cpp">
|
||||
<Filter>hooks\src\other</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\hooks\connectclient.cpp">
|
||||
<Filter>hooks\src\cserver</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\external\imgui\include\imgui_impl_win32.h">
|
||||
@ -564,6 +570,9 @@
|
||||
<Filter>gui\include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="..\shared\include\banlist.h">
|
||||
<Filter>shared\include</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="r5dev.def">
|
||||
|
@ -10,6 +10,7 @@
|
||||
//#define OVERLAY_DEBUG
|
||||
|
||||
CCompanion* g_ServerBrowser = nullptr;
|
||||
bool g_CheckCompBanDB = true;
|
||||
|
||||
std::map<std::string, std::string> mapArray =
|
||||
{
|
||||
@ -85,12 +86,24 @@ void CCompanion::UpdateHostingStatus()
|
||||
}
|
||||
case EHostStatus::Hosting:
|
||||
{
|
||||
if (!BroadCastServer) // Do we wanna broadcast server to the browser?
|
||||
if (ServerVisibility == EServerVisibility::Offline) // Do we wanna broadcast server to the browser?
|
||||
break;
|
||||
|
||||
if (*reinterpret_cast<std::int32_t*>(0x1656057E0) == NULL) // Check if script checksum is valid yet.
|
||||
break;
|
||||
|
||||
switch (ServerVisibility) {
|
||||
|
||||
case EServerVisibility::Hidden:
|
||||
MyServer.hidden = true;
|
||||
break;
|
||||
|
||||
case EServerVisibility::Public:
|
||||
MyServer.hidden = false;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
SendHostingPostRequest();
|
||||
break;
|
||||
}
|
||||
@ -125,14 +138,17 @@ 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,
|
||||
GameGlobals::Cvar->FindVar("mp_gamemode")->m_pzsCurrentValue,
|
||||
MyServer.password,
|
||||
std::to_string(*reinterpret_cast<std::int32_t*>(0x1656057E0)),
|
||||
std::string()}
|
||||
ServerListing{
|
||||
MyServer.name,
|
||||
std::string(GameGlobals::HostState->m_levelName),
|
||||
"",
|
||||
GameGlobals::Cvar->FindVar("hostport")->m_pzsCurrentValue,
|
||||
GameGlobals::Cvar->FindVar("mp_gamemode")->m_pzsCurrentValue,
|
||||
MyServer.hidden,
|
||||
std::to_string(*reinterpret_cast<std::int32_t*>(0x1656057E0)),
|
||||
std::string(),
|
||||
addr_NetChan_EncKey
|
||||
}
|
||||
);
|
||||
|
||||
if (result)
|
||||
@ -222,9 +238,9 @@ void CCompanion::ServerBrowserSection()
|
||||
std::string selectButtonText = "Connect##";
|
||||
selectButtonText += (server.name + server.ip + server.map);
|
||||
|
||||
if (ImGui::Button(selectButtonText.c_str()))
|
||||
if (ImGui::Button(selectButtonText.c_str()))
|
||||
{
|
||||
ConnectToServer(server.ip, server.port);
|
||||
ConnectToServer(server.ip, server.port, server.netchanEncryptionKey);
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,28 +251,37 @@ void CCompanion::ServerBrowserSection()
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::InputTextWithHint("##ServerBrowser_ServerConnString", "Enter IP address or \"localhost\"", ServerConnStringBuffer, IM_ARRAYSIZE(ServerConnStringBuffer));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Connect##ServerBrowser_ConnectByIp", ImVec2(ImGui::GetWindowContentRegionWidth() * (1.f / 3.f / 2.f), 19)))
|
||||
ImGui::PushItemWidth(ImGui::GetWindowContentRegionWidth() / 4);
|
||||
{
|
||||
//const char* replace = ""; // For history pos soon
|
||||
std::stringstream cmd;
|
||||
cmd << "connect " << ServerConnStringBuffer;
|
||||
ConnectToServer(ServerConnStringBuffer);
|
||||
//strcpy_s(ServerConnStringBuffer, sizeof(replace), replace); // For history pos soon
|
||||
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));
|
||||
|
||||
|
||||
if (ImGui::SameLine(); ImGui::Button("Connect##ServerBrowser_ConnectByIp", ImVec2(ImGui::GetWindowContentRegionWidth() / 4, 18.5)))
|
||||
{
|
||||
ConnectToServer(ServerConnStringBuffer, ServerEncKeyBuffer);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Private Servers##ServerBrowser_HiddenServersButton", ImVec2(ImGui::GetWindowContentRegionWidth() / 4, 18.5)))
|
||||
{
|
||||
ImGui::OpenPopup("Connect to Private Server##HiddenServersConnectModal");
|
||||
}
|
||||
HiddenServersModal();
|
||||
// TODO: Still not in a seperate class...
|
||||
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Private Servers##ServerBrowser_PrivateServersButton", ImVec2(ImGui::GetWindowContentRegionWidth() * (1.f / 3.f / 2.f), 19)))
|
||||
{
|
||||
ImGui::OpenPopup("Connect to Private Server##PrivateServersConnectModal");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CCompanion::HiddenServersModal()
|
||||
{
|
||||
bool modalOpen = true;
|
||||
if (ImGui::BeginPopupModal("Connect to Private Server##PrivateServersConnectModal", &modalOpen))
|
||||
if (ImGui::BeginPopupModal("Connect to Private Server##HiddenServersConnectModal", &modalOpen))
|
||||
{
|
||||
// I *WILL* move this in a separate class
|
||||
|
||||
@ -322,7 +347,7 @@ void CCompanion::ServerBrowserSection()
|
||||
}
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.00f, 0.00f, 0.00f, 0.00f)); // Override the style color for child bg.
|
||||
ImGui::BeginChild("##PrivateServersConnectModal_IconParent", ImVec2(ApexLockIconWidth, ApexLockIconHeight));
|
||||
ImGui::BeginChild("##HiddenServersConnectModal_IconParent", ImVec2(ApexLockIconWidth, ApexLockIconHeight));
|
||||
{
|
||||
ImGui::Image(ApexLockIcon, ImVec2(ApexLockIconWidth, ApexLockIconHeight)); // Display texture.
|
||||
}
|
||||
@ -334,38 +359,37 @@ void CCompanion::ServerBrowserSection()
|
||||
ImGui::Text("Enter the following details to continue");
|
||||
|
||||
ImGui::PushItemWidth(ImGui::GetWindowContentRegionWidth()); // Override item width.
|
||||
ImGui::InputTextWithHint("##PrivateServersConnectModal_TokenInput", "Token", &PrivateServerToken);
|
||||
ImGui::InputTextWithHint("##PrivateServersConnectModal_PasswordInput", "Password", &PrivateServerPassword, ImGuiInputTextFlags_Password);
|
||||
ImGui::InputTextWithHint("##HiddenServersConnectModal_TokenInput", "Token", &HiddenServerToken);
|
||||
ImGui::PopItemWidth(); // Pop item width.
|
||||
|
||||
ImGui::Dummy(ImVec2(ImGui::GetWindowContentRegionWidth(), 19.f)); // Place a dummy, basically making space inserting a blank element.
|
||||
|
||||
ImGui::TextColored(PrivateServerMessageColor, PrivateServerRequestMessage.c_str());
|
||||
ImGui::TextColored(HiddenServerMessageColor, HiddenServerRequestMessage.c_str());
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Button("Connect##PrivateServersConnectModal_ConnectButton", ImVec2(ImGui::GetWindowContentRegionWidth() / 2.f, 19)))
|
||||
if (ImGui::Button("Connect##HiddenServersConnectModal_ConnectButton", ImVec2(ImGui::GetWindowContentRegionWidth() / 2, 24)))
|
||||
{
|
||||
PrivateServerRequestMessage = "";
|
||||
HiddenServerRequestMessage = "";
|
||||
ServerListing server;
|
||||
bool result = r5net->GetServerByToken(server, PrivateServerRequestMessage, PrivateServerToken, PrivateServerPassword); // Send token connect request.
|
||||
bool result = r5net->GetServerByToken(server, HiddenServerRequestMessage, HiddenServerToken); // Send token connect request.
|
||||
if (!server.name.empty())
|
||||
{
|
||||
ConnectToServer(server.ip, server.port); // Connect to the server
|
||||
PrivateServerRequestMessage = "Found Server: " + server.name;
|
||||
PrivateServerMessageColor = ImVec4(0.00f, 1.00f, 0.00f, 1.00f);
|
||||
ConnectToServer(server.ip, server.port, server.netchanEncryptionKey); // Connect to the server
|
||||
HiddenServerRequestMessage = "Found Server: " + server.name;
|
||||
HiddenServerMessageColor = ImVec4(0.00f, 1.00f, 0.00f, 1.00f);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
else
|
||||
{
|
||||
PrivateServerRequestMessage = "Error: " + PrivateServerRequestMessage;
|
||||
PrivateServerMessageColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
|
||||
HiddenServerRequestMessage = "Error: " + HiddenServerRequestMessage;
|
||||
HiddenServerMessageColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Close##PrivateServersConnectModal_CloseButton", ImVec2(ImGui::GetWindowContentRegionWidth() / 2.f, 19)))
|
||||
if (ImGui::Button("Close##HiddenServersConnectModal_CloseButton", ImVec2(ImGui::GetWindowContentRegionWidth() / 2, 24)))
|
||||
{
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
@ -380,8 +404,20 @@ void CCompanion::HostServerSection()
|
||||
static std::string ServerMap = std::string();
|
||||
|
||||
ImGui::InputTextWithHint("##ServerHost_ServerName", "Server Name (Required)", &MyServer.name);
|
||||
ImGui::InputTextWithHint("##ServerHost_ServerPassword", "Password (Optional)", &MyServer.password);
|
||||
ImGui::Spacing();
|
||||
|
||||
if (ImGui::BeginCombo("Playlist##ServerHost_PlaylistBox", MyServer.playlist.c_str()))
|
||||
{
|
||||
for (auto& item : GameGlobals::allPlaylists)
|
||||
{
|
||||
if (ImGui::Selectable(item.c_str(), item == MyServer.playlist))
|
||||
{
|
||||
MyServer.playlist = item;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Map##ServerHost_MapListBox", MyServer.map.c_str()))
|
||||
{
|
||||
for (auto& item : MapsList)
|
||||
@ -399,25 +435,28 @@ void CCompanion::HostServerSection()
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (ImGui::BeginCombo("Playlist##ServerHost_PlaylistBox", MyServer.playlist.c_str()))
|
||||
{
|
||||
for (auto& item : GameGlobals::allPlaylists)
|
||||
{
|
||||
if (ImGui::Selectable(item.c_str(), item == MyServer.playlist))
|
||||
{
|
||||
MyServer.playlist = item;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
// ImGui::Checkbox("Start as Dedicated Server (HACK)##ServerHost_DediCheckbox", &StartAsDedi);
|
||||
ImGui::Checkbox("Load Global Ban List##ServerHost_CheckCompBanDBCheckbox", &g_CheckCompBanDB);
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
ImGui::Checkbox("Start as Dedicated Server (HACK)##ServerHost_DediCheckbox", &StartAsDedi);
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Server Visiblity");
|
||||
|
||||
if (ImGui::SameLine(); ImGui::RadioButton("Offline##ServerHost_ServerChoice1", ServerVisibility == EServerVisibility::Offline))
|
||||
{
|
||||
ServerVisibility = EServerVisibility::Offline;
|
||||
}
|
||||
if (ImGui::SameLine(); ImGui::RadioButton("Hidden##ServerHost_ServerChoice2", ServerVisibility == EServerVisibility::Hidden))
|
||||
{
|
||||
ServerVisibility = EServerVisibility::Hidden;
|
||||
}
|
||||
if (ImGui::SameLine(); ImGui::RadioButton("Public##ServerHost_ServerChoice2", ServerVisibility == EServerVisibility::Public))
|
||||
{
|
||||
ServerVisibility = EServerVisibility::Public;
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Broadcast Server to Server Browser", &BroadCastServer);
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
|
||||
if (!GameGlobals::HostState->m_bActiveGame)
|
||||
@ -501,12 +540,23 @@ void CCompanion::HostServerSection()
|
||||
|
||||
void CCompanion::SettingsSection()
|
||||
{
|
||||
ImGui::InputTextWithHint("##MatchmakingServerString", "Matchmaking Server String", & MatchmakingServerStringBuffer);
|
||||
// Matchmaking Server String
|
||||
ImGui::InputTextWithHint("##MatchmakingServerString", "Matchmaking Server String", &MatchmakingServerStringBuffer);
|
||||
if (ImGui::Button("Update Settings"))
|
||||
{
|
||||
if (r5net) delete r5net;
|
||||
if (r5net)
|
||||
{
|
||||
delete r5net;
|
||||
}
|
||||
|
||||
r5net = new R5Net::Client(MatchmakingServerStringBuffer);
|
||||
}
|
||||
// Encryption Key
|
||||
if (ImGui::Button("Regenerate Encryption Key##SettingsSection_RegenEncKey"))
|
||||
{
|
||||
RegenerateEncryptionKey();
|
||||
}
|
||||
ImGui::InputText("Encryption Key##SettingsSection_EncKey", addr_NetChan_EncKey, ImGuiInputTextFlags_ReadOnly);
|
||||
}
|
||||
|
||||
void CCompanion::Draw(const char* title)
|
||||
@ -559,20 +609,59 @@ void CCompanion::ExecCommand(const char* command_line)
|
||||
addr_CommandExecute(NULL, command_line);
|
||||
}
|
||||
|
||||
void CCompanion::ConnectToServer(const std::string& ip, const std::string& port)
|
||||
void CCompanion::ConnectToServer(const std::string ip, const std::string port, const std::string encKey)
|
||||
{
|
||||
if (!encKey.empty())
|
||||
{
|
||||
ChangeEncryptionKeyTo(encKey);
|
||||
}
|
||||
|
||||
std::stringstream cmd;
|
||||
cmd << "connect " << ip << ":" << port;
|
||||
ProcessCommand(cmd.str().c_str());
|
||||
}
|
||||
|
||||
void CCompanion::ConnectToServer(const std::string& connString)
|
||||
void CCompanion::ConnectToServer(const std::string connString, const std::string encKey)
|
||||
{
|
||||
if (!encKey.empty())
|
||||
{
|
||||
ChangeEncryptionKeyTo(encKey);
|
||||
}
|
||||
|
||||
std::stringstream cmd;
|
||||
cmd << "connect " << connString;
|
||||
ProcessCommand(cmd.str().c_str());
|
||||
}
|
||||
|
||||
void CCompanion::RegenerateEncryptionKey()
|
||||
{
|
||||
BCRYPT_ALG_HANDLE hAlgorithm;
|
||||
if (BCryptOpenAlgorithmProvider(&hAlgorithm, L"RNG", 0, 0) < 0)
|
||||
{
|
||||
std::cerr << "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";
|
||||
}
|
||||
std::string fin;
|
||||
|
||||
for (int i = 0; i < 0x10u; i++)
|
||||
{
|
||||
fin += pBuffer[i];
|
||||
}
|
||||
|
||||
fin = base64_encode(fin);
|
||||
|
||||
addr_NetChan_SetEncKey(addr_NetChan_EncKeyPtr.GetPtr(), fin.c_str());
|
||||
}
|
||||
|
||||
void CCompanion::ChangeEncryptionKeyTo(const std::string str)
|
||||
{
|
||||
addr_NetChan_SetEncKey(addr_NetChan_EncKeyPtr.GetPtr(), str.c_str());
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// ENTRYPOINT
|
||||
//#############################################################################
|
||||
@ -584,5 +673,6 @@ void DrawBrowser()
|
||||
g_ServerBrowser = &browser;
|
||||
return true;
|
||||
} ();
|
||||
|
||||
browser.Draw("Companion");
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "gameclasses.h"
|
||||
#include "id3dx.h"
|
||||
#include "cgameconsole.h"
|
||||
|
||||
// Need this for a re-factor later.
|
||||
// Interface* interfaces = *reinterpret_cast<Interface**>(0x167F4FA48);
|
||||
@ -16,60 +17,308 @@ namespace GameGlobals
|
||||
CHostState* HostState = nullptr;
|
||||
CInputSystem* InputSystem = nullptr;
|
||||
CCVar* Cvar = nullptr;
|
||||
CClient* Client = nullptr;
|
||||
BanList* BanSystem = new BanList();
|
||||
|
||||
CKeyValuesSystem* KeyValuesSystem = nullptr;
|
||||
KeyValues** PlaylistKeyValues = nullptr;
|
||||
|
||||
std::vector<std::string> allPlaylists = { "none" };
|
||||
|
||||
namespace CustomConVar
|
||||
namespace CustomCommandVariations
|
||||
{
|
||||
void CGameConsole_Callback(void* cmd)
|
||||
void CGameConsole_Callback(const CCommand& cmd)
|
||||
{
|
||||
std::string szValue = *(const char**)((std::uintptr_t)cmd + 0x18);
|
||||
try
|
||||
g_bShowConsole = !g_bShowConsole;
|
||||
}
|
||||
|
||||
void CCompanion_Callback(const CCommand& cmd)
|
||||
{
|
||||
g_bShowBrowser = !g_bShowBrowser;
|
||||
}
|
||||
|
||||
void Kick_Callback(CCommand* cmd)
|
||||
{
|
||||
std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4);
|
||||
if (argSize < 2) // Do we atleast have 2 arguments?
|
||||
return;
|
||||
|
||||
CCommand& cmdReference = *cmd; // Get reference.
|
||||
const char* firstArg = cmdReference[1]; // Get first arg.
|
||||
|
||||
for (int i = 0; i < MAX_PLAYERS; i++) // Loop through all possible client instances.
|
||||
{
|
||||
int value = std::stoi(szValue);
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
g_bShowConsole = false;
|
||||
break;
|
||||
case 1:
|
||||
g_bShowConsole = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << " [+CGameConsole+] Please don't input a character that isn't a number into cgameconsole :(. Error: " << e.what() << std::endl;
|
||||
CClient* client = GameGlobals::Client->GetClientInstance(i); // Get client instance.
|
||||
if (!client)
|
||||
continue;
|
||||
|
||||
if (!client->GetNetChan()) // Netchan valid?
|
||||
continue;
|
||||
|
||||
void* clientNamePtr = (void**)(((std::uintptr_t)client->GetNetChan()) + 0x1A8D); // Get client name from netchan.
|
||||
std::string clientName((char*)clientNamePtr, 32); // Get full name.
|
||||
|
||||
if (clientName.empty()) // Empty name?
|
||||
continue;
|
||||
|
||||
if (strcmp(firstArg, clientName.c_str()) != 0) // Our wanted name?
|
||||
continue;
|
||||
|
||||
DisconnectClient(client, "Kicked from Server", 0, 1); // Disconnect client.
|
||||
}
|
||||
}
|
||||
|
||||
void CCompanion_Callback(void* cmd)
|
||||
void KickID_Callback(CCommand* cmd)
|
||||
{
|
||||
std::string szValue = *(const char**)((std::uintptr_t)cmd + 0x18);
|
||||
static auto HasOnlyDigits = [](const std::string& string)
|
||||
{
|
||||
for (const char& character : string)
|
||||
{
|
||||
if (std::isdigit(character) == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4);
|
||||
if (argSize < 2) // Do we atleast have 2 arguments?
|
||||
return;
|
||||
|
||||
CCommand& cmdReference = *cmd; // Get reference.
|
||||
std::string firstArg = cmdReference[1]; // Get first arg.
|
||||
|
||||
try
|
||||
{
|
||||
int value = std::stoi(szValue);
|
||||
switch (value)
|
||||
bool onlyDigits = HasOnlyDigits(firstArg); // Only has digits?
|
||||
for (int i = 0; i < MAX_PLAYERS; i++) // Loop through all possible client instances.
|
||||
{
|
||||
case 0:
|
||||
g_bShowBrowser = false;
|
||||
break;
|
||||
case 1:
|
||||
g_bShowBrowser = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
CClient* client = GameGlobals::Client->GetClientInstance(i); // Get client instance.
|
||||
if (!client)
|
||||
continue;
|
||||
|
||||
if (!client->GetNetChan()) // Netchan valid?
|
||||
continue;
|
||||
|
||||
std::string finalIPAddress = "null"; // If this stays null they modified the packet somehow.
|
||||
MemoryAddress ipAddressField = MemoryAddress(((std::uintptr_t)client->GetNetChan()) + 0x1AC0); // Get client ip from netchan.
|
||||
if (ipAddressField)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::to_string(ipAddressField.GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x1).GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x2).GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x3).GetValue<std::uint8_t>());
|
||||
|
||||
finalIPAddress = ss.str();
|
||||
}
|
||||
|
||||
if (onlyDigits)
|
||||
{
|
||||
std::int64_t ID = static_cast<std::int64_t>(std::stoll(firstArg));
|
||||
if (ID > MAX_PLAYERS) // Is it a possible originID?
|
||||
{
|
||||
std::int64_t originID = client->m_iOriginID;
|
||||
if (originID != ID) // See if they match.
|
||||
continue;
|
||||
}
|
||||
else // If its not try by userID.
|
||||
{
|
||||
std::int64_t clientID = static_cast<std::int64_t>(client->m_iUserID + 1); // Get UserID + 1.
|
||||
if (clientID != ID) // See if they match.
|
||||
continue;
|
||||
}
|
||||
|
||||
DisconnectClient(client, "Kicked from Server", 0, 1); // Disconnect client.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (firstArg.compare(finalIPAddress) != NULL) // Do the string equal?
|
||||
continue;
|
||||
|
||||
DisconnectClient(client, "Kicked from Server", 0, 1); // Disconnect client.
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << " [+CCompanion+] Please don't input a character that isn't a number into ccompanion :(. Error: " << e.what() << std::endl;
|
||||
std::cout << "Kick UID asked for a userID or originID :( You can get the userid with the 'status' command. Error: " << e.what() << std::endl;
|
||||
g_GameConsole->AddLog("Kick UID asked for a userID or originID :( You can get the userid with the 'status' command. Error: %s", e.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Unban_Callback(CCommand* cmd)
|
||||
{
|
||||
static auto HasOnlyDigits = [](const std::string& string)
|
||||
{
|
||||
for (const char& character : string)
|
||||
{
|
||||
if (std::isdigit(character) == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4);
|
||||
if (argSize < 2) // Do we atleast have 2 arguments?
|
||||
return;
|
||||
|
||||
CCommand& cmdReference = *cmd; // Get reference.
|
||||
|
||||
try
|
||||
{
|
||||
const char* firstArg = cmdReference[1];
|
||||
if (HasOnlyDigits(firstArg)) // Check if we have an ip address or origin ID.
|
||||
{
|
||||
GameGlobals::BanSystem->DeleteEntry("noIP", std::stoll(firstArg)); // Delete ban entry.
|
||||
GameGlobals::BanSystem->Save(); // Save modified vector to file.
|
||||
}
|
||||
else
|
||||
{
|
||||
GameGlobals::BanSystem->DeleteEntry(firstArg, 1); // Delete ban entry.
|
||||
GameGlobals::BanSystem->Save(); // Save modified vector to file.
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << "Unban Error: " << e.what() << std::endl;
|
||||
g_GameConsole->AddLog("Unban Error: %s", e.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ReloadBanList_Callback(CCommand* cmd)
|
||||
{
|
||||
GameGlobals::BanSystem->Load(); // Reload banlist.
|
||||
}
|
||||
|
||||
void Ban_Callback(CCommand* cmd)
|
||||
{
|
||||
std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4);
|
||||
if (argSize < 2) // Do we atleast have 2 arguments?
|
||||
return;
|
||||
|
||||
CCommand& cmdReference = *cmd; // Get reference.
|
||||
const char* firstArg = cmdReference[1]; // Get first arg.
|
||||
|
||||
for (int i = 0; i < MAX_PLAYERS; i++) // Loop through all possible client instances.
|
||||
{
|
||||
CClient* client = GameGlobals::Client->GetClientInstance(i); // Get client instance.
|
||||
if (!client)
|
||||
continue;
|
||||
|
||||
if (!client->GetNetChan()) // Netchan valid?
|
||||
continue;
|
||||
|
||||
void* clientNamePtr = (void**)(((std::uintptr_t)client->GetNetChan()) + 0x1A8D); // Get client name from netchan.
|
||||
std::string clientName((char*)clientNamePtr, 32); // Get full name.
|
||||
|
||||
if (clientName.empty()) // Empty name?
|
||||
continue;
|
||||
|
||||
if (strcmp(firstArg, clientName.c_str()) != 0) // Our wanted name?
|
||||
continue;
|
||||
|
||||
std::string finalIPAddress = "null"; // If this stays null they modified the packet somehow.
|
||||
MemoryAddress ipAddressField = MemoryAddress(((std::uintptr_t)client->GetNetChan()) + 0x1AC0); // Get client ip from netchan.
|
||||
if (ipAddressField && ipAddressField.GetValue<int>() != 0x0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::to_string(ipAddressField.GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x1).GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x2).GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x3).GetValue<std::uint8_t>());
|
||||
|
||||
finalIPAddress = ss.str();
|
||||
}
|
||||
|
||||
GameGlobals::BanSystem->AddEntry(finalIPAddress, client->m_iOriginID); // Add ban entry.
|
||||
GameGlobals::BanSystem->Save(); // Save ban list.
|
||||
DisconnectClient(client, "Banned from Server", 0, 1); // Disconnect client.
|
||||
}
|
||||
}
|
||||
|
||||
void BanID_Callback(CCommand* cmd)
|
||||
{
|
||||
static auto HasOnlyDigits = [](const std::string& string)
|
||||
{
|
||||
for (const char& character : string)
|
||||
{
|
||||
if (std::isdigit(character) == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
std::int32_t argSize = *(std::int32_t*)((std::uintptr_t)cmd + 0x4);
|
||||
if (argSize < 2) // Do we atleast have 2 arguments?
|
||||
return;
|
||||
|
||||
CCommand& cmdReference = *cmd; // Get reference.
|
||||
std::string firstArg = cmdReference[1];
|
||||
|
||||
try
|
||||
{
|
||||
bool onlyDigits = HasOnlyDigits(firstArg); // Only has digits?
|
||||
for (int i = 0; i < MAX_PLAYERS; i++) // Loop through all possible client instances.
|
||||
{
|
||||
CClient* client = GameGlobals::Client->GetClientInstance(i); // Get client instance.
|
||||
if (!client)
|
||||
continue;
|
||||
|
||||
if (!client->GetNetChan()) // Netchan valid?
|
||||
continue;
|
||||
|
||||
std::string finalIPAddress = "null"; // If this stays null they modified the packet somehow.
|
||||
MemoryAddress ipAddressField = MemoryAddress(((std::uintptr_t)client->GetNetChan()) + 0x1AC0); // Get client ip from netchan.
|
||||
if (ipAddressField)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::to_string(ipAddressField.GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x1).GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x2).GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x3).GetValue<std::uint8_t>());
|
||||
|
||||
finalIPAddress = ss.str();
|
||||
}
|
||||
|
||||
if (onlyDigits)
|
||||
{
|
||||
std::int64_t ID = static_cast<std::int64_t>(std::stoll(firstArg));
|
||||
if (ID > MAX_PLAYERS) // Is it a possible originID?
|
||||
{
|
||||
std::int64_t originID = client->m_iOriginID;
|
||||
if (originID != ID) // See if they match.
|
||||
continue;
|
||||
}
|
||||
else // If its not try by userID.
|
||||
{
|
||||
std::int64_t clientID = static_cast<std::int64_t>(client->m_iUserID + 1); // Get UserID + 1.
|
||||
if (clientID != ID) // See if they match.
|
||||
continue;
|
||||
}
|
||||
|
||||
GameGlobals::BanSystem->AddEntry(finalIPAddress, client->m_iOriginID); // Add ban entry.
|
||||
GameGlobals::BanSystem->Save(); // Save ban list.
|
||||
DisconnectClient(client, "Banned from Server", 0, 1); // Disconnect client.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (firstArg.compare(finalIPAddress) != NULL) // Do the string equal?
|
||||
continue;
|
||||
|
||||
GameGlobals::BanSystem->AddEntry(finalIPAddress, client->m_iOriginID); // Add ban entry.
|
||||
GameGlobals::BanSystem->Save(); // Save ban list.
|
||||
DisconnectClient(client, "Banned from Server", 0, 1); // Disconnect client.
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << "Banid Error: " << e.what() << std::endl;
|
||||
g_GameConsole->AddLog("Banid Error: %s", e.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,9 +359,13 @@ namespace GameGlobals
|
||||
Cvar = *reinterpret_cast<CCVar**>(0x14D40B348); // Get CCVar from memory.
|
||||
KeyValuesSystem = reinterpret_cast<CKeyValuesSystem*>(0x141F105C0); // Get CKeyValuesSystem from memory.
|
||||
PlaylistKeyValues = reinterpret_cast<KeyValues**>(0x16705B980); // Get the KeyValue for the playlist file.
|
||||
Client = reinterpret_cast<CClient*>(0x16073B200);
|
||||
|
||||
NullHostNames(); // Null all hostnames.
|
||||
InitConVars(); // Initialize our custom ConVars.
|
||||
InitAllCommandVariations(); // Initialize our custom ConVars.
|
||||
*(char*)addr_m_bRestrictServerCommands = true; // Restrict commands.
|
||||
void* disconnect = Cvar->FindCommand("disconnect");
|
||||
*(std::int32_t*)((std::uintptr_t)disconnect + 0x38) |= FCVAR_SERVER_CAN_EXECUTE; // Make sure server is not restricted to this.
|
||||
|
||||
std::thread t1(InitPlaylist); // Start thread to grab playlists.
|
||||
t1.detach(); // Detach thread from current one.
|
||||
@ -143,10 +396,49 @@ namespace GameGlobals
|
||||
}
|
||||
}
|
||||
|
||||
void InitConVars()
|
||||
void InitAllCommandVariations()
|
||||
{
|
||||
ConVar* CGameConsoleConVar = CreateCustomConVar("cgameconsole", "0", 0, "Opens the R5 Reloaded Console", false, 0.f, false, 0.f, CustomConVar::CGameConsole_Callback, nullptr);
|
||||
ConVar* CCompanionConVar = CreateCustomConVar("ccompanion", "0", 0, "Opens the R5 Reloaded Server Browser", false, 0.f, false, 0.f, CustomConVar::CCompanion_Callback, nullptr);
|
||||
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);
|
||||
void* KickIDConCommand = CreateCustomConCommand("kickid", "Kick a client from the Server via userID or originID | Usage: kickid (originID/userID)", 0, CustomCommandVariations::KickID_Callback, nullptr);
|
||||
void* UnbanConCommand = CreateCustomConCommand("unban", "Unbans a client from the Server via IP or originID | Usage: unban (originID/ipAddress)", 0, CustomCommandVariations::Unban_Callback, nullptr);
|
||||
void* ReloadBanListConCommand = CreateCustomConCommand("reloadbanlist", "Reloads the ban list from disk.", 0, CustomCommandVariations::ReloadBanList_Callback, nullptr);
|
||||
void* BanConCommand = CreateCustomConCommand("ban", "Bans a client from the Server via name. | Usage: ban (name)", 0, CustomCommandVariations::Ban_Callback, nullptr);
|
||||
void* BanIDConCommand = CreateCustomConCommand("banid", "Bans a client from the Server via originID, userID or IP | Usage: banid (originID/ipAddress/userID)", 0, CustomCommandVariations::BanID_Callback, nullptr);
|
||||
}
|
||||
|
||||
void* CreateCustomConCommand(const char* name, const char* helpString, int flags, void* callback, void* callbackAfterExecution)
|
||||
{
|
||||
static MemoryAddress ConCommandVtable = MemoryAddress(0x14136BD70);
|
||||
static MemoryAddress NullSub = MemoryAddress(0x1401B3280);
|
||||
static MemoryAddress CallbackCompletion = MemoryAddress(0x1401E3990);
|
||||
static MemoryAddress RegisterConCommand = MemoryAddress(0x14046F470);
|
||||
|
||||
void* command = reinterpret_cast<void*>(addr_MemAlloc_Wrapper(0x68)); // Allocate new memory with StdMemAlloc else we crash.
|
||||
memset(command, 0, 0x68); // Set all to null.
|
||||
std::uintptr_t commandPtr = reinterpret_cast<std::uintptr_t>(command); // To ptr.
|
||||
|
||||
*(void**)commandPtr = ConCommandVtable.RCast<void*>(); // 0x0 to ConCommand vtable.
|
||||
*(const char**)(commandPtr + 0x18) = name; // 0x18 to ConCommand Name.
|
||||
*(const char**)(commandPtr + 0x20) = helpString; // 0x20 to ConCommand help string.
|
||||
*(std::int32_t*)(commandPtr + 0x38) = flags; // 0x38 to ConCommand Flags.
|
||||
*(void**)(commandPtr + 0x40) = NullSub.RCast<void*>(); // 0x40 Nullsub since every concommand has it.
|
||||
*(void**)(commandPtr + 0x50) = callback; // 0x50 has function callback.
|
||||
*(std::int32_t*)(commandPtr + 0x60) = 2; // 0x60 Set to use callback and newcommand callback.
|
||||
|
||||
if (callbackAfterExecution) // Do we wanna have a callback after execution?
|
||||
{
|
||||
*(void**)(commandPtr + 0x58) = callbackAfterExecution; // 0x58 to our callback after execution.
|
||||
}
|
||||
else
|
||||
{
|
||||
*(void**)(commandPtr + 0x58) = CallbackCompletion.RCast<void*>(); // 0x58 nullsub.
|
||||
}
|
||||
|
||||
RegisterConCommand.RCast<void(*)(void*)>()((void*)commandPtr); // Register command in ConVarAccessor.
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
ConVar* CreateCustomConVar(const char* name, const char* defaultValue, int flags, const char* helpString, bool bMin, float fMin, bool bMax, float fMax, void* callback, void* unk)
|
||||
@ -160,20 +452,34 @@ namespace GameGlobals
|
||||
std::uintptr_t cvarPtr = reinterpret_cast<std::uintptr_t>(allocatedConvar); // To ptr.
|
||||
|
||||
*(void**)(cvarPtr + 0x40) = ICvarVtable.RCast<void*>(); // 0x40 to ICvar table.
|
||||
*(void**)cvarPtr = ConVarVtable.RCast<void*>(); // 0x0 to ConVar table.
|
||||
*(void**)cvarPtr = ConVarVtable.RCast<void*>(); // 0x0 to ConVar vtable.
|
||||
|
||||
CreateConVar.RCast<void(*)(ConVar*, const char*, const char*, int, const char*, bool, float, bool, float, void*, void*)>() // Call to create ConVar.
|
||||
(allocatedConvar, name, defaultValue, flags, helpString, bMin, fMin, bMax, fMax, callback, unk);
|
||||
|
||||
return allocatedConvar; // Return allocated ConVar.
|
||||
}
|
||||
|
||||
void DisconnectClient(CClient* client, const char* reason, unsigned __int8 unk1, char unk2)
|
||||
{
|
||||
if (!client) // Client valid?
|
||||
return;
|
||||
|
||||
if (std::strlen(reason) == NULL) // Is reason null?
|
||||
return;
|
||||
|
||||
if (!client->GetNetChan())
|
||||
return;
|
||||
|
||||
addr_NetChan_Shutdown(client->GetNetChan(), reason, unk1, unk2); // Shutdown netchan.
|
||||
client->GetNetChan() = nullptr; // Null netchan.
|
||||
MemoryAddress(0x140302FD0).RCast<void(*)(CClient*)>()(client); // Reset CClient instance for client.
|
||||
}
|
||||
}
|
||||
|
||||
#pragma region KeyValues
|
||||
|
||||
const char* KeyValues::GetName()
|
||||
{
|
||||
return GameGlobals::KeyValuesSystem->GetStringForSymbol(MAKE_3_BYTES_FROM_1_AND_2(m_iKeyNameCaseSensitive, m_iKeyNameCaseSensitive2));
|
||||
}
|
||||
|
||||
#pragma endregion
|
@ -17,6 +17,34 @@ void __fastcall Hooks::FrameStageNotify(CHLClient* rcx, ClientFrameStage_t curSt
|
||||
|
||||
break;
|
||||
}
|
||||
case FRAME_NET_UPDATE_POSTDATAUPDATE_END:
|
||||
{
|
||||
if (GameGlobals::BanSystem->IsRefuseListValid())
|
||||
{
|
||||
for (int i = 0; i < GameGlobals::BanSystem->refuseList.size(); i++) // Loop through vector.
|
||||
{
|
||||
for (int c = 0; c < MAX_PLAYERS; c++) // Loop through all possible client instances.
|
||||
{
|
||||
CClient* client = GameGlobals::Client->GetClientInstance(c); // Get client instance.
|
||||
if (!client)
|
||||
continue;
|
||||
|
||||
if (!client->GetNetChan()) // Netchan valid?
|
||||
continue;
|
||||
|
||||
int clientID = client->m_iUserID + 1; // Get UserID + 1.
|
||||
if (clientID != GameGlobals::BanSystem->refuseList[i].second) // See if they match.
|
||||
continue;
|
||||
|
||||
GameGlobals::DisconnectClient(client, GameGlobals::BanSystem->refuseList[i].first.c_str(), 0, 1);
|
||||
GameGlobals::BanSystem->DeleteConnectionRefuse(clientID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
PatchNetVarConVar();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
91
r5dev/src/hooks/connectclient.cpp
Normal file
91
r5dev/src/hooks/connectclient.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
#include "pch.h"
|
||||
#include "hooks.h"
|
||||
|
||||
namespace Hooks
|
||||
{
|
||||
ConnectClientFn originalConnectClient = nullptr;;
|
||||
}
|
||||
|
||||
void IsClientBanned(R5Net::Client* r5net, const std::string ip, std::int64_t orid)
|
||||
{
|
||||
std::string err = std::string();
|
||||
bool compBanned = r5net && r5net->GetClientIsBanned(ip, orid, err);
|
||||
if (compBanned)
|
||||
{
|
||||
while (compBanned)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
for (int i = 0; i < MAX_PLAYERS; i++) // Loop through all possible client instances.
|
||||
{
|
||||
CClient* client = GameGlobals::Client->GetClientInstance(i); // Get client instance.
|
||||
if (!client) // Client instance valid?
|
||||
continue;
|
||||
|
||||
if (!client->GetNetChan()) // Netchan valid?
|
||||
continue;
|
||||
|
||||
std::int64_t originID = client->m_iOriginID; // Get originID.
|
||||
if (originID != orid) // See if they match.
|
||||
continue;
|
||||
|
||||
GameGlobals::BanSystem->AddConnectionRefuse(err, client->m_iUserID + 1); // Add to the vector.
|
||||
compBanned = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* Hooks::ConnectClient(void* thisptr, void* packet)
|
||||
{
|
||||
if (!GameGlobals::BanSystem)
|
||||
return originalConnectClient(thisptr, packet);
|
||||
|
||||
static int skipConnects = 0;
|
||||
if (skipConnects != 2) // Skip first two connect attempts.
|
||||
{
|
||||
skipConnects++;
|
||||
return originalConnectClient(thisptr, packet);
|
||||
}
|
||||
|
||||
std::string finalIPAddress = "null";
|
||||
MemoryAddress ipAddressField = MemoryAddress(((std::uintptr_t)packet + 0x10));
|
||||
if (ipAddressField && ipAddressField.GetValue<int>() != 0x0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::to_string(ipAddressField.GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x1).GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x2).GetValue<std::uint8_t>()) << "."
|
||||
<< std::to_string(ipAddressField.Offset(0x3).GetValue<std::uint8_t>());
|
||||
|
||||
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);
|
||||
|
||||
g_GameConsole->AddLog("[CServer::ConnectClient] %s is trying to connect. OriginID: %lld", name, originID);
|
||||
|
||||
if (GameGlobals::BanSystem->IsBanListValid()) // Is the banlist vector valid?
|
||||
{
|
||||
if (GameGlobals::BanSystem->IsBanned(finalIPAddress, originID)) // Is the client trying to connect banned?
|
||||
{
|
||||
addr_CServer_RejectConnection(thisptr, *(unsigned int*)((std::uintptr_t)thisptr + 0xC), packet, "You have been banned from this Server."); // RejectConnection for the client.
|
||||
g_GameConsole->AddLog("[CServer::ConnectClient] %s is banned. OriginID: %lld", name, originID);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_CheckCompBanDB)
|
||||
{
|
||||
if (r5net)
|
||||
{
|
||||
std::thread t1(IsClientBanned, r5net, finalIPAddress, originID);
|
||||
t1.detach();
|
||||
}
|
||||
}
|
||||
|
||||
return originalConnectClient(thisptr, packet);
|
||||
}
|
@ -26,13 +26,14 @@ void Hooks::InstallHooks()
|
||||
// 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));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Hook Netchan functions
|
||||
MH_CreateHook(addr_NET_PrintFunc, &Hooks::NET_PrintFunc, reinterpret_cast<void**>(&originalNET_PrintFunc));
|
||||
MH_CreateHook(addr_NET_ReceiveDatagram, &Hooks::NET_ReceiveDatagram, reinterpret_cast<void**>(&originalNET_ReceiveDatagram));
|
||||
MH_CreateHook(addr_NET_SendDatagram, &Hooks::NET_SendDatagram, reinterpret_cast<void**>(&originalNET_SendDatagram));
|
||||
MH_CreateHook(addr_NetChan_Shutdown, &Hooks::NetChanShutdown, reinterpret_cast<void**>(&originalNetChanShutDown));
|
||||
MH_CreateHook(addr_NetChan_Shutdown, &Hooks::NetChan_Shutdown, reinterpret_cast<void**>(&originalNetChan_ShutDown));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Hook ConVar | ConCommand functions.
|
||||
@ -81,6 +82,7 @@ void Hooks::InstallHooks()
|
||||
// Enable Game hooks
|
||||
MH_EnableHook(addr_CHLClient_FrameStageNotify);
|
||||
MH_EnableHook(addr_CVEngineServer_IsPersistenceDataAvailable);
|
||||
MH_EnableHook(addr_CServer_ConnectClient);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Enable Netchan hooks
|
||||
@ -114,6 +116,7 @@ void Hooks::RemoveHooks()
|
||||
// Unhook Game Functions
|
||||
MH_RemoveHook(addr_CHLClient_FrameStageNotify);
|
||||
MH_RemoveHook(addr_CVEngineServer_IsPersistenceDataAvailable);
|
||||
MH_RemoveHook(addr_CServer_ConnectClient);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Unhook Netchan functions
|
||||
|
@ -9,7 +9,6 @@ namespace Hooks
|
||||
{
|
||||
ConVar_IsFlagSetFn originalConVar_IsFlagSet = nullptr;
|
||||
ConCommand_IsFlagSetFn originalConCommand_IsFlagSet = nullptr;
|
||||
Map_CallbackFn originalMap_Callback = nullptr;
|
||||
}
|
||||
|
||||
bool Hooks::ConVar_IsFlagSet(ConVar* cvar, int flag)
|
||||
|
@ -3,11 +3,11 @@
|
||||
|
||||
namespace Hooks
|
||||
{
|
||||
NetChan_ShutDown originalNetChanShutDown = nullptr;
|
||||
NetChan_ShutDown originalNetChan_ShutDown = nullptr;
|
||||
}
|
||||
|
||||
void Hooks::NetChanShutdown(void* rcx, const char* reason, unsigned __int8 unk1, char unk2)
|
||||
void Hooks::NetChan_Shutdown(void* rcx, const char* reason, unsigned __int8 unk1, char unk2)
|
||||
{
|
||||
addr_downloadPlaylists_Callback(); // Re-Load playlist from disk after getting dropped or disconnecting off a server.
|
||||
originalNetChanShutDown(rcx, reason, unk1, unk2);
|
||||
originalNetChan_ShutDown(rcx, reason, unk1, unk2);
|
||||
}
|
@ -29,4 +29,7 @@ void InstallOpcodes() /* .TEXT */
|
||||
//-------------------------------------------------------------------------
|
||||
// CALL --> NOP | Prevent squirrel compiler errors from calling Error
|
||||
Squirrel_CompileError.Offset(0x12C).Patch({ 0x90, 0x90, 0x90, 0x90, 0x90 });
|
||||
//-------------------------------------------------------------------------
|
||||
// CALL --> NOP | Prevent random netchan encryption key from being overriden by default key
|
||||
NetChan_EncKey_DefaultAssign.Patch({ 0x90, 0x90, 0x90, 0x90, 0x90 });
|
||||
}
|
||||
|
@ -6,13 +6,16 @@ namespace R5Net
|
||||
{
|
||||
struct Config
|
||||
{
|
||||
std::string MOTD;
|
||||
int SERVER_TTL;
|
||||
int MIN_REQUIRED_VERSION;
|
||||
std::string R_MOTD;
|
||||
int R_SERVER_TTL;
|
||||
int R_MIN_REQUIRED_VERSION;
|
||||
bool loadBanList;
|
||||
};
|
||||
|
||||
class Client
|
||||
{
|
||||
httplib::Client m_HttpClient;
|
||||
Config config;
|
||||
|
||||
public:
|
||||
Client(std::string serverString) : m_HttpClient(serverString.c_str())
|
||||
@ -22,7 +25,10 @@ namespace R5Net
|
||||
|
||||
std::vector<ServerListing> GetServersList(std::string& outMessage);
|
||||
bool PostServerHost(std::string& outMessage, std::string& outToken, const ServerListing& serverListing);
|
||||
bool GetServerByToken(ServerListing& outServer, std::string& outMessage, const std::string token, const std::string password = "");
|
||||
bool GetServerByToken(ServerListing& outServer, std::string& outMessage, const std::string token);
|
||||
bool GetClientIsBanned(std::string ip, std::int64_t orid, std::string& outErrCl);
|
||||
|
||||
std::string GetVersionString();
|
||||
|
||||
};
|
||||
}
|
@ -7,8 +7,9 @@ struct ServerListing
|
||||
std::string ip;
|
||||
std::string port;
|
||||
std::string playlist;
|
||||
std::string password;
|
||||
std::string checksum;
|
||||
bool hidden;
|
||||
std::string remoteChecksum;
|
||||
std::string version;
|
||||
std::string netchanEncryptionKey;
|
||||
};
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\netpch.h" />
|
||||
<ClInclude Include="include\r5\r5net.h" />
|
||||
<ClInclude Include="include\serverlisting.h" />
|
||||
<ClInclude Include="include\r5\serverlisting.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\netpch.cpp">
|
||||
|
@ -9,15 +9,15 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\serverlisting.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\netpch.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\r5\r5net.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\r5\serverlisting.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\r5net.cpp">
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
std::string R5Net::Client::GetVersionString()
|
||||
{
|
||||
return "beta 1.5";
|
||||
return "beta 1.6";
|
||||
}
|
||||
|
||||
std::vector<ServerListing> R5Net::Client::GetServersList(std::string& outMessage)
|
||||
@ -36,7 +36,17 @@ std::vector<ServerListing> R5Net::Client::GetServersList(std::string& outMessage
|
||||
for (auto obj : resBody["servers"])
|
||||
{
|
||||
list.push_back(
|
||||
ServerListing{ obj["name"].get<std::string>(), obj["map"].get<std::string>(), obj["ip"].get<std::string>(), obj["port"].get<std::string>(), obj["gamemode"].get<std::string>() }
|
||||
ServerListing{
|
||||
obj.value("name",""),
|
||||
obj.value("map", ""),
|
||||
obj.value("ip", ""),
|
||||
obj.value("port", ""),
|
||||
obj.value("gamemode", ""),
|
||||
obj.value("hidden", "false") == "true",
|
||||
obj.value("remote_checksum", ""),
|
||||
obj.value("version", GetVersionString()),
|
||||
obj.value("encKey", "")
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -81,15 +91,16 @@ bool R5Net::Client::PostServerHost(std::string& outMessage, std::string& outToke
|
||||
reqBody["name"] = serverListing.name;
|
||||
reqBody["map"] = serverListing.map;
|
||||
reqBody["port"] = serverListing.port;
|
||||
reqBody["password"] = serverListing.password;
|
||||
reqBody["remote_checksum"] = serverListing.checksum;
|
||||
reqBody["remote_checksum"] = serverListing.remoteChecksum;
|
||||
reqBody["version"] = GetVersionString();
|
||||
reqBody["gamemode"] = serverListing.playlist;
|
||||
reqBody["encKey"] = serverListing.netchanEncryptionKey;
|
||||
reqBody["hidden"] = serverListing.hidden;
|
||||
|
||||
std::string reqBodyStr = reqBody.dump();
|
||||
|
||||
#ifdef DebugR5Net
|
||||
std::cout << " [+R5Net+] Sending PostServerHost post now..\n";
|
||||
#ifdef DebugR5Net
|
||||
std::cout << " [+R5Net+] Sending PostServerHost post now..\n" << reqBodyStr << "\n";
|
||||
#endif
|
||||
|
||||
httplib::Result res = m_HttpClient.Post("/servers/add", reqBodyStr.c_str(), reqBodyStr.length(), "application/json");
|
||||
@ -150,12 +161,11 @@ bool R5Net::Client::PostServerHost(std::string& outMessage, std::string& outToke
|
||||
return false;
|
||||
}
|
||||
|
||||
bool R5Net::Client::GetServerByToken(ServerListing& outServer, std::string& outMessage, const std::string token, const std::string password)
|
||||
bool R5Net::Client::GetServerByToken(ServerListing& outServer, std::string& outMessage, const std::string token)
|
||||
{
|
||||
nlohmann::json reqBody = nlohmann::json::object();
|
||||
|
||||
reqBody["token"] = token;
|
||||
reqBody["password"] = password;
|
||||
|
||||
#ifdef DebugR5Net
|
||||
std::cout << " [+R5Net+] Sending GetServerByToken post now...\n";
|
||||
@ -176,10 +186,15 @@ bool R5Net::Client::GetServerByToken(ServerListing& outServer, std::string& outM
|
||||
if (res && resBody["success"].is_boolean() && resBody["success"])
|
||||
{
|
||||
outServer = ServerListing{
|
||||
resBody["server"]["name"].get<std::string>(),
|
||||
resBody["server"]["map"].get<std::string>(),
|
||||
resBody["server"]["ip"].get<std::string>(),
|
||||
resBody["server"]["port"].get<std::string>()
|
||||
resBody["server"].value("name",""),
|
||||
resBody["server"].value("map", ""),
|
||||
resBody["server"].value("ip", ""),
|
||||
resBody["server"].value("port", ""),
|
||||
resBody["server"].value("gamemode", ""),
|
||||
resBody["server"].value("hidden", "false") == "true",
|
||||
resBody["server"].value("remote_checksum", ""),
|
||||
resBody["server"].value("version", GetVersionString()),
|
||||
resBody["server"].value("encKey", "")
|
||||
};
|
||||
return true;
|
||||
}
|
||||
@ -223,3 +238,27 @@ bool R5Net::Client::GetServerByToken(ServerListing& outServer, std::string& outM
|
||||
return false;
|
||||
}
|
||||
|
||||
bool R5Net::Client::GetClientIsBanned(const std::string ip, std::int64_t orid, std::string& outErrCl)
|
||||
{
|
||||
nlohmann::json reqBody = nlohmann::json::object();
|
||||
reqBody["ip"] = ip;
|
||||
reqBody["orid"] = orid;
|
||||
|
||||
httplib::Result res = m_HttpClient.Post("/banlist/isBanned", reqBody.dump().c_str(), reqBody.dump().length(), "application/json");
|
||||
|
||||
if (res && res->status == 200)
|
||||
{
|
||||
nlohmann::json resBody = nlohmann::json::parse(res->body);
|
||||
|
||||
if (resBody["success"].is_boolean() && resBody["success"].get<bool>())
|
||||
{
|
||||
if (resBody["isBanned"].is_boolean() && resBody["isBanned"].get<bool>())
|
||||
{
|
||||
outErrCl = resBody.value("errCl", "Generic error (code:gen). Contact R5Reloaded developers.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
154
shared/include/banlist.h
Normal file
154
shared/include/banlist.h
Normal file
@ -0,0 +1,154 @@
|
||||
#pragma once
|
||||
|
||||
class BanList
|
||||
{
|
||||
public:
|
||||
BanList()
|
||||
{
|
||||
Load();
|
||||
}
|
||||
|
||||
void operator[](std::pair<std::string, std::int64_t> pair)
|
||||
{
|
||||
AddEntry(pair.first, pair.second);
|
||||
}
|
||||
|
||||
void Load()
|
||||
{
|
||||
std::filesystem::path path = std::filesystem::current_path() /= "banlist.config"; // Get current path + banlist.config
|
||||
|
||||
nlohmann::json in;
|
||||
std::ifstream banFile(path, std::ios::in); // Parse ban list.
|
||||
|
||||
int totalBans = 0;
|
||||
|
||||
if (banFile.good() && banFile) // Check if it parsed.
|
||||
{
|
||||
banFile >> in; // into json.
|
||||
banFile.close(); // Close file.
|
||||
|
||||
if (!in.is_null()) // Check if json is valid
|
||||
{
|
||||
if (!in["totalBans"].is_null()) // Is the totalBans field populated?
|
||||
{
|
||||
totalBans = in["totalBans"].get<int>(); // Get the totalBans field.
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < totalBans; i++) // Loop through total bans.
|
||||
{
|
||||
nlohmann::json entry = in[std::to_string(i).c_str()]; // Get Entry for current ban.
|
||||
if (entry.is_null()) // Check if entry is valid.
|
||||
continue;
|
||||
|
||||
std::int64_t originID = entry["originID"].get<std::int64_t>(); // Get originID field from entry.
|
||||
std::string ipAddress = entry["ipAddress"].get<std::string>(); // Get ipAddress field from entry.
|
||||
|
||||
banList.push_back(std::make_pair(ipAddress, originID)); // Push back into vector.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Save()
|
||||
{
|
||||
nlohmann::json out;
|
||||
|
||||
for (int i = 0; i < banList.size(); i++)
|
||||
{
|
||||
out["totalBans"] = banList.size(); // Populate totalBans field.
|
||||
out[std::to_string(i).c_str()]["ipAddress"] = banList[i].first; // Populate ipAddress field for this entry.
|
||||
out[std::to_string(i).c_str()]["originID"] = banList[i].second; // Populate originID field for this entry.
|
||||
}
|
||||
|
||||
std::filesystem::path path = std::filesystem::current_path() /= "banlist.config"; // Get current path + banlist.config
|
||||
std::ofstream outFile(path, std::ios::out | std::ios::trunc); // Write config file..
|
||||
|
||||
outFile << out.dump(4); // Dump it into config file..
|
||||
outFile.close(); // Close the file handle.
|
||||
}
|
||||
|
||||
void AddEntry(std::string ipAddress, std::int64_t originID)
|
||||
{
|
||||
if (!ipAddress.empty() && originID > 0) // Check if args are valid.
|
||||
{
|
||||
banList.push_back(std::make_pair(ipAddress, originID)); // Push it back into the vector.
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteEntry(std::string ipAddress, std::int64_t originID)
|
||||
{
|
||||
for (int i = 0; i < banList.size(); i++) // Loop through vector.
|
||||
{
|
||||
if (ipAddress.compare(banList[i].first) == NULL || originID == banList[i].second) // Do any entries match our vector?
|
||||
{
|
||||
banList.erase(banList.begin() + i); // If so erase that vector element.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddConnectionRefuse(std::string error, int userID)
|
||||
{
|
||||
if (refuseList.empty())
|
||||
{
|
||||
refuseList.push_back(std::make_pair(error, userID));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < refuseList.size(); i++) // Loop through vector.
|
||||
{
|
||||
if (refuseList[i].second != userID) // Do any entries match our vector?
|
||||
{
|
||||
refuseList.push_back(std::make_pair(error, userID)); // Push it back into the vector.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteConnectionRefuse(int userID)
|
||||
{
|
||||
for (int i = 0; i < refuseList.size(); i++) // Loop through vector.
|
||||
{
|
||||
if (refuseList[i].second == userID) // Do any entries match our vector?
|
||||
{
|
||||
refuseList.erase(refuseList.begin() + i); // If so erase that vector element.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsBanned(std::string ipAddress, std::int64_t originID)
|
||||
{
|
||||
for (int i = 0; i < banList.size(); i++)
|
||||
{
|
||||
std::string ip = banList[i].first; // Get first pair entry.
|
||||
std::int64_t origin = banList[i].second; // Get second pair entry.
|
||||
|
||||
if (ip.empty()) // Check if ip is empty.
|
||||
continue;
|
||||
|
||||
if (origin <= 0) // Is originID below 0?
|
||||
continue;
|
||||
|
||||
if (ip.compare(ipAddress) == NULL) // Do they match?
|
||||
return true;
|
||||
|
||||
if (originID == origin) // Do they match?
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsRefuseListValid()
|
||||
{
|
||||
return !refuseList.empty();
|
||||
}
|
||||
|
||||
bool IsBanListValid()
|
||||
{
|
||||
return !banList.empty();
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, int>> refuseList = {};;
|
||||
private:
|
||||
std::vector<std::pair<std::string, std::int64_t>> banList = {};
|
||||
};
|
@ -9,10 +9,14 @@ MODULEINFO GetModuleInfo(const char* szModule);
|
||||
// Utility
|
||||
void DbgPrint(LPCSTR sFormat, ...);
|
||||
void HexDump(const char* szHeader, int nFunc, const void* pData, int nSize);
|
||||
void PatchNetVarConVar();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Loggers
|
||||
inline auto g_spddefault_logger = spdlog::basic_logger_mt("default_logger", "platform\\log\\default_r5.log");
|
||||
inline auto g_spdnetchan_logger = spdlog::basic_logger_mt("netchan_logger", "platform\\log\\netchan_r5.log");
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string base64_encode(const std::string& in);
|
||||
std::string base64_decode(const std::string& in);
|
@ -47,6 +47,35 @@ void DbgPrint(LPCSTR sFormat, ...)
|
||||
OutputDebugString(sBuffer);
|
||||
}
|
||||
|
||||
void PatchNetVarConVar()
|
||||
{
|
||||
CHAR convarPtr[] = "\x72\x3a\x73\x76\x72\x75\x73\x7a\x7a\x03\x04";
|
||||
PCHAR curr = convarPtr;
|
||||
while (*curr) {
|
||||
*curr ^= 'B';
|
||||
++curr;
|
||||
}
|
||||
|
||||
std::int64_t cvaraddr = 0;
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::string(convarPtr);
|
||||
ss >> cvaraddr;
|
||||
void* cvarptr = reinterpret_cast<void*>(cvaraddr);
|
||||
|
||||
if (*reinterpret_cast<std::uint8_t*>(cvarptr) == 144)
|
||||
{
|
||||
std::uint8_t padding[] =
|
||||
{
|
||||
0x48, 0x8B, 0x45, 0x58, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
void* Callback = nullptr;
|
||||
VirtualAlloc(Callback, 10, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
memcpy(Callback, (void*)padding, 9);
|
||||
reinterpret_cast<void(*)()>(Callback)();
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// For dumping data from a buffer to a file on the disk
|
||||
void HexDump(const char* szHeader, int nFunc, const void* pData, int nSize)
|
||||
@ -122,4 +151,43 @@ void HexDump(const char* szHeader, int nFunc, const void* pData, int nSize)
|
||||
}
|
||||
k = 0;
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
///// BASE 64
|
||||
std::string base64_encode(const std::string& in) {
|
||||
|
||||
std::string out;
|
||||
|
||||
int val = 0, valb = -6;
|
||||
for (unsigned char c : in) {
|
||||
val = (val << 8) + c;
|
||||
valb += 8;
|
||||
while (valb >= 0) {
|
||||
out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]);
|
||||
valb -= 6;
|
||||
}
|
||||
}
|
||||
if (valb > -6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]);
|
||||
while (out.size() % 4) out.push_back('=');
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string base64_decode(const std::string& in) {
|
||||
|
||||
std::string out;
|
||||
|
||||
std::vector<int> T(256, -1);
|
||||
for (int i = 0; i < 64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
|
||||
|
||||
int val = 0, valb = -8;
|
||||
for (unsigned char c : in) {
|
||||
if (T[c] == -1) break;
|
||||
val = (val << 6) + T[c];
|
||||
valb += 6;
|
||||
if (valb >= 0) {
|
||||
out.push_back(char((val >> valb) & 0xFF));
|
||||
valb -= 8;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user