diff --git a/r5dev/include/CCompanion.h b/r5dev/include/CCompanion.h
index 5a7ef11c..166ee791 100644
--- a/r5dev/include/CCompanion.h
+++ b/r5dev/include/CCompanion.h
@@ -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;
\ No newline at end of file
+extern CCompanion* g_ServerBrowser;
+
+extern bool g_CheckCompBanDB;
\ No newline at end of file
diff --git a/r5dev/include/enums.h b/r5dev/include/enums.h
index 6a4d4ff7..f3ff58b5 100644
--- a/r5dev/include/enums.h
+++ b/r5dev/include/enums.h
@@ -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.
diff --git a/r5dev/include/gameclasses.h b/r5dev/include/gameclasses.h
index 1197cee3..bd096e01 100644
--- a/r5dev/include/gameclasses.h
+++ b/r5dev/include/gameclasses.h
@@ -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);
 }
\ No newline at end of file
diff --git a/r5dev/include/gui_utility.h b/r5dev/include/gui_utility.h
index 052314ab..e502bdc3 100644
--- a/r5dev/include/gui_utility.h
+++ b/r5dev/include/gui_utility.h
@@ -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.
     };
 };
 
diff --git a/r5dev/include/hooks.h b/r5dev/include/hooks.h
index bad42cf2..fec365eb 100644
--- a/r5dev/include/hooks.h
+++ b/r5dev/include/hooks.h
@@ -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
diff --git a/r5dev/include/opcptc.h b/r5dev/include/opcptc.h
index 697374a5..fc0715e2 100644
--- a/r5dev/include/opcptc.h
+++ b/r5dev/include/opcptc.h
@@ -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;
diff --git a/r5dev/include/patterns.h b/r5dev/include/patterns.h
index 4ca2776e..9d6534f0 100644
--- a/r5dev/include/patterns.h
+++ b/r5dev/include/patterns.h
@@ -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);
diff --git a/r5dev/r5dev.vcxproj b/r5dev/r5dev.vcxproj
index bc2148f4..84db9479 100644
--- a/r5dev/r5dev.vcxproj
+++ b/r5dev/r5dev.vcxproj
@@ -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" />
diff --git a/r5dev/r5dev.vcxproj.filters b/r5dev/r5dev.vcxproj.filters
index fe05a640..aafd9c56 100644
--- a/r5dev/r5dev.vcxproj.filters
+++ b/r5dev/r5dev.vcxproj.filters
@@ -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">
diff --git a/r5dev/src/CCompanion.cpp b/r5dev/src/CCompanion.cpp
index 2898a518..0ba5c913 100644
--- a/r5dev/src/CCompanion.cpp
+++ b/r5dev/src/CCompanion.cpp
@@ -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");
 }
diff --git a/r5dev/src/gameclasses.cpp b/r5dev/src/gameclasses.cpp
index c62c0c29..3d0b7919 100644
--- a/r5dev/src/gameclasses.cpp
+++ b/r5dev/src/gameclasses.cpp
@@ -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
\ No newline at end of file
diff --git a/r5dev/src/hooks/chlclient.cpp b/r5dev/src/hooks/chlclient.cpp
index 32b67fb9..63a83f4b 100644
--- a/r5dev/src/hooks/chlclient.cpp
+++ b/r5dev/src/hooks/chlclient.cpp
@@ -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;
 	}
diff --git a/r5dev/src/hooks/connectclient.cpp b/r5dev/src/hooks/connectclient.cpp
new file mode 100644
index 00000000..ef6f5902
--- /dev/null
+++ b/r5dev/src/hooks/connectclient.cpp
@@ -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);
+}
\ No newline at end of file
diff --git a/r5dev/src/hooks/hooks.cpp b/r5dev/src/hooks/hooks.cpp
index aa0c2102..6d8e9a59 100644
--- a/r5dev/src/hooks/hooks.cpp
+++ b/r5dev/src/hooks/hooks.cpp
@@ -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
diff --git a/r5dev/src/hooks/iconvar.cpp b/r5dev/src/hooks/iconvar.cpp
index 780a9d72..ef384a0f 100644
--- a/r5dev/src/hooks/iconvar.cpp
+++ b/r5dev/src/hooks/iconvar.cpp
@@ -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)
diff --git a/r5dev/src/hooks/netchannel.cpp b/r5dev/src/hooks/netchannel.cpp
index 3b09e286..6ad9ffa3 100644
--- a/r5dev/src/hooks/netchannel.cpp
+++ b/r5dev/src/hooks/netchannel.cpp
@@ -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);
 }
\ No newline at end of file
diff --git a/r5dev/src/opcptc.cpp b/r5dev/src/opcptc.cpp
index 40f944aa..a6fbbbf4 100644
--- a/r5dev/src/opcptc.cpp
+++ b/r5dev/src/opcptc.cpp
@@ -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 });
 }
diff --git a/r5net/include/r5/r5net.h b/r5net/include/r5/r5net.h
index 1293c5f1..c3005b65 100644
--- a/r5net/include/r5/r5net.h
+++ b/r5net/include/r5/r5net.h
@@ -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();
+
 	};
 }
\ No newline at end of file
diff --git a/r5net/include/r5/serverlisting.h b/r5net/include/r5/serverlisting.h
index 0b317eb6..1e895fbd 100644
--- a/r5net/include/r5/serverlisting.h
+++ b/r5net/include/r5/serverlisting.h
@@ -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;
 };
 
diff --git a/r5net/r5net.vcxproj b/r5net/r5net.vcxproj
index 577d5ed0..cc893185 100644
--- a/r5net/r5net.vcxproj
+++ b/r5net/r5net.vcxproj
@@ -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">
diff --git a/r5net/r5net.vcxproj.filters b/r5net/r5net.vcxproj.filters
index f50c168f..91f23065 100644
--- a/r5net/r5net.vcxproj.filters
+++ b/r5net/r5net.vcxproj.filters
@@ -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">
diff --git a/r5net/src/r5net.cpp b/r5net/src/r5net.cpp
index 1ef0e78e..3c007778 100644
--- a/r5net/src/r5net.cpp
+++ b/r5net/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;
+}
+
diff --git a/shared/include/banlist.h b/shared/include/banlist.h
new file mode 100644
index 00000000..71889965
--- /dev/null
+++ b/shared/include/banlist.h
@@ -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 = {};
+};
diff --git a/shared/include/utility.h b/shared/include/utility.h
index c2075066..2f4704db 100644
--- a/shared/include/utility.h
+++ b/shared/include/utility.h
@@ -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");
 
-/////////////////////////////////////////////////////////////////////////////
\ No newline at end of file
+/////////////////////////////////////////////////////////////////////////////
+
+std::string base64_encode(const std::string& in);
+std::string base64_decode(const std::string& in);
\ No newline at end of file
diff --git a/shared/utility.cpp b/shared/utility.cpp
index 58e32408..3d6e1f30 100644
--- a/shared/utility.cpp
+++ b/shared/utility.cpp
@@ -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;
 }
\ No newline at end of file