From 3d36c87b0819cb366fc42efda35e4830ce170c62 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 23 Feb 2024 00:12:06 +0100 Subject: [PATCH] Statically construct all ConCommand Properly implement the ConCommandBase and ConCommand classes so we could statically construct all ConCommand objects in the global scope of each translation unit, this way we don't need to put them in a global file and deal with preprocessor directives to compile then in/out for certain projects. --- src/common/callback.cpp | 729 ------------------------- src/common/callback.h | 31 -- src/common/global.cpp | 80 +-- src/common/global.h | 1 - src/core/dllmain.cpp | 2 - src/engine/client/cl_rcon.cpp | 96 ++++ src/engine/client/clientstate.cpp | 2 +- src/engine/net.cpp | 17 + src/engine/sys_dll.cpp | 10 - src/game/client/vscript_client.cpp | 37 ++ src/game/server/ai_utility.cpp | 29 + src/game/server/player.cpp | 48 +- src/game/server/vscript_server.cpp | 18 + src/gameui/IBrowser.cpp | 13 +- src/gameui/IBrowser.h | 4 + src/gameui/IConsole.cpp | 79 ++- src/gameui/IConsole.h | 8 + src/materialsystem/cmaterialsystem.cpp | 2 +- src/networksystem/bansystem.cpp | 79 +++ src/public/coordsize.h | 2 +- src/public/iconcommand.h | 34 +- src/public/tier1/convar.h | 88 ++- src/public/tier1/cvar.h | 15 +- src/rtech/pak/pakparse.cpp | 8 - src/rtech/pak/pakparse.h | 50 +- src/rtech/pak/pakstate.cpp | 256 +++++++++ src/rtech/pak/pakstate.h | 47 +- src/rtech/playlists/playlists.cpp | 13 + src/rtech/playlists/playlists.h | 3 + src/tier0/commandline.cpp | 2 +- src/tier1/convar.cpp | 395 ++++++++++++-- src/tier1/cvar.cpp | 60 +- 32 files changed, 1248 insertions(+), 1010 deletions(-) diff --git a/src/common/callback.cpp b/src/common/callback.cpp index efb08a01..d353307f 100644 --- a/src/common/callback.cpp +++ b/src/common/callback.cpp @@ -94,154 +94,7 @@ void MP_HostName_Changed_f(IConVar* pConVar, const char* pOldString, float flOld #endif // !DEDICATED } -#ifndef DEDICATED -/* -===================== -ToggleConsole_f -===================== -*/ -void ToggleConsole_f(const CCommand& args) -{ - g_Console.m_bActivate ^= true; - ResetInput(); // Disable input to game when console is drawn. -} - -/* -===================== -ToggleBrowser_f -===================== -*/ -void ToggleBrowser_f(const CCommand& args) -{ - g_Browser.m_bActivate ^= true; - ResetInput(); // Disable input to game when browser is drawn. -} -#endif // !DEDICATED #ifndef CLIENT_DLL -/* -===================== -Host_Kick_f - - helper function for - bansystem -===================== -*/ -void _Author_Client_f(const CCommand& args, EKickType type) -{ - if (args.ArgC() < 2) - { - return; - } - - const char* szReason = args.ArgC() > 2 ? args.Arg(2) : nullptr; - - switch(type) - { - case KICK_NAME: - { - g_BanSystem.KickPlayerByName(args.Arg(1), szReason); - break; - } - case KICK_ID: - { - g_BanSystem.KickPlayerById(args.Arg(1), szReason); - break; - } - case BAN_NAME: - { - g_BanSystem.BanPlayerByName(args.Arg(1), szReason); - break; - } - case BAN_ID: - { - g_BanSystem.BanPlayerById(args.Arg(1), szReason); - break; - } - default: - { - // Code bug. - Assert(0); - } - } -} - - -/* -===================== -Host_Kick_f -===================== -*/ -void Host_Kick_f(const CCommand& args) -{ - _Author_Client_f(args, EKickType::KICK_NAME); -} - -/* -===================== -Host_KickID_f -===================== -*/ -void Host_KickID_f(const CCommand& args) -{ - _Author_Client_f(args, EKickType::KICK_ID); -} - -/* -===================== -Host_Ban_f -===================== -*/ -void Host_Ban_f(const CCommand& args) -{ - _Author_Client_f(args, EKickType::BAN_NAME); -} - -/* -===================== -Host_BanID_f -===================== -*/ -void Host_BanID_f(const CCommand& args) -{ - _Author_Client_f(args, EKickType::BAN_ID); -} - -/* -===================== -Host_Unban_f -===================== -*/ -void Host_Unban_f(const CCommand& args) -{ - if (args.ArgC() < 2) - { - return; - } - - g_BanSystem.UnbanPlayer(args.Arg(1)); -} - -/* -===================== -Host_ReloadBanList_f -===================== -*/ -void Host_ReloadBanList_f(const CCommand& args) -{ - g_BanSystem.LoadList(); // Reload banned list. -} - -/* -===================== -Host_ReloadPlaylists_f -===================== -*/ -void Host_ReloadPlaylists_f(const CCommand& args) -{ - v__DownloadPlaylists_f(); - Playlists_SDKInit(); // Re-Init playlist. -} - /* ===================== Host_Changelevel_f @@ -265,267 +118,7 @@ void Host_Changelevel_f(const CCommand& args) v_HostState_ChangeLevelMP(levelName, landMarkName); } } - -/* -===================== -Detour_HotSwap_f - - Hot swaps the NavMesh - while the game is running -===================== -*/ -void Detour_HotSwap_f(const CCommand& args) -{ - if (!g_pServer->IsActive()) - return; // Only execute if server is initialized and active. - - Msg(eDLL_T::SERVER, "Executing NavMesh hot swap for level '%s'\n", - g_ServerGlobalVariables->m_pszMapName); - - CFastTimer timer; - - timer.Start(); - Detour_HotSwap(); - - timer.End(); - Msg(eDLL_T::SERVER, "Hot swap took '%lf' seconds\n", timer.GetDuration().GetSeconds()); -} #endif // !CLIENT_DLL -/* -===================== -Pak_ListPaks_f -===================== -*/ -void Pak_ListPaks_f(const CCommand& args) -{ - Msg(eDLL_T::RTECH, "| id | name | status | asset count |\n"); - Msg(eDLL_T::RTECH, "|------|----------------------------------------------------|--------------------------------------|-------------|\n"); - - uint32_t nTotalLoaded = 0; - - for (int16_t i = 0, n = g_pakGlobals->loadedPakCount; i < n; ++i) - { - const PakLoadedInfo_t& info = g_pakGlobals->loadedPaks[i]; - - if (info.status == EPakStatus::PAK_STATUS_FREED) - continue; - - const char* szRpakStatus = Pak_StatusToString(info.status); - - // todo: make status into a string from an array/vector - Msg(eDLL_T::RTECH, "| %04i | %-50s | %-36s | %11i |\n", info.handle, info.fileName, szRpakStatus, info.assetCount); - nTotalLoaded++; - } - Msg(eDLL_T::RTECH, "|------|----------------------------------------------------|--------------------------------------|-------------|\n"); - Msg(eDLL_T::RTECH, "| %18i loaded paks. |\n", nTotalLoaded); - Msg(eDLL_T::RTECH, "|------|----------------------------------------------------|--------------------------------------|-------------|\n"); -} - -/* -===================== -Pak_ListTypes_f -===================== -*/ -void Pak_ListTypes_f(const CCommand& args) -{ - Msg(eDLL_T::RTECH, "| ext | description | version | header size | native size |\n"); - Msg(eDLL_T::RTECH, "|------|---------------------------|---------|-------------|-------------|\n"); - - uint32_t nRegistered = 0; - - for (int8_t i = 0; i < PAK_MAX_TYPES; ++i) - { - PakAssetBinding_t* type = &g_pakGlobals->assetBindings[i]; - - if (!type->description) - continue; - - FourCCString_t assetExtension; - FourCCToString(assetExtension, type->extension); - - Msg(eDLL_T::RTECH, "| %-4s | %-25s | %7i | %11i | %11i |\n", assetExtension, type->description, type->version, type->headerSize, type->nativeClassSize); - nRegistered++; - } - Msg(eDLL_T::RTECH, "|------|---------------------------|---------|-------------|-------------|\n"); - Msg(eDLL_T::RTECH, "| %18i registered types. |\n", nRegistered); - Msg(eDLL_T::RTECH, "|------|---------------------------|---------|-------------|-------------|\n"); -} - -/* -===================== -Pak_RequestUnload_f -===================== -*/ -void Pak_RequestUnload_f(const CCommand& args) -{ - if (args.ArgC() < 2) - { - return; - } - - if (args.HasOnlyDigits(1)) - { - const PakHandle_t pakHandle = atoi(args.Arg(1)); - const PakLoadedInfo_t* const pakInfo = Pak_GetPakInfo(pakHandle); - - if (!pakInfo) - { - Warning(eDLL_T::RTECH, "Found no pak entry for specified handle.\n"); - return; - } - - Msg(eDLL_T::RTECH, "Requested pak unload for handle '%d'\n", pakHandle); - g_pakLoadApi->UnloadAsync(pakHandle); - } - else - { - const PakLoadedInfo_t* const pakInfo = Pak_GetPakInfo(args.Arg(1)); - if (!pakInfo) - { - Warning(eDLL_T::RTECH, "Found no pak entry for specified name.\n"); - return; - } - - Msg(eDLL_T::RTECH, "Requested pak unload for file '%s'\n", args.Arg(1)); - g_pakLoadApi->UnloadAsync(pakInfo->handle); - } -} - -/* -===================== -Pak_RequestLoad_f -===================== -*/ -void Pak_RequestLoad_f(const CCommand& args) -{ - g_pakLoadApi->LoadAsync(args.Arg(1), AlignedMemAlloc(), NULL, 0); -} - - -/* -===================== -Pak_Swap_f -===================== -*/ -void Pak_Swap_f(const CCommand& args) -{ - if (args.ArgC() < 2) - { - return; - } - - const char* pakName = nullptr; - - PakHandle_t pakHandle = INVALID_PAK_HANDLE; - const PakLoadedInfo_t* pakInfo = nullptr; - - if (args.HasOnlyDigits(1)) - { - pakHandle = atoi(args.Arg(1)); - pakInfo = Pak_GetPakInfo(pakHandle); - - if (!pakInfo) - { - Warning(eDLL_T::RTECH, "Found no pak entry for specified handle.\n"); - return; - } - - pakName = pakInfo->fileName; - } - else - { - pakName = args.Arg(1); - pakInfo = Pak_GetPakInfo(pakName); - - if (!pakInfo) - { - Warning(eDLL_T::RTECH, "Found no pak entry for specified name.\n"); - return; - } - - pakHandle = pakInfo->handle; - } - - Msg(eDLL_T::RTECH, "Requested pak swap for handle '%d'\n", pakHandle); - g_pakLoadApi->UnloadAsync(pakHandle); - - while (pakInfo->status != EPakStatus::PAK_STATUS_FREED) // Wait till this slot gets free'd. - std::this_thread::sleep_for(std::chrono::seconds(1)); - - g_pakLoadApi->LoadAsync(pakName, AlignedMemAlloc(), NULL, 0); -} - -/* -===================== -RTech_StringToGUID_f -===================== -*/ -void Pak_StringToGUID_f(const CCommand& args) -{ - if (args.ArgC() < 2) - { - return; - } - - unsigned long long guid = Pak_StringToGuid(args.Arg(1)); - - Msg(eDLL_T::RTECH, "______________________________________________________________\n"); - Msg(eDLL_T::RTECH, "] RTECH_HASH ]------------------------------------------------\n"); - Msg(eDLL_T::RTECH, "] GUID: '0x%llX'\n", guid); -} - -/* -===================== -RTech_Decompress_f - - Decompresses input RPak file and - dumps results to override path -===================== -*/ -void Pak_Decompress_f(const CCommand& args) -{ - if (args.ArgC() < 2) - { - return; - } - - CFmtStr1024 inPakFile(PLATFORM_PAK_PATH "%s", args.Arg(1)); - CFmtStr1024 outPakFile(PLATFORM_PAK_OVERRIDE_PATH "%s", args.Arg(1)); - - if (!Pak_DecodePakFile(inPakFile.String(), outPakFile.String())) - { - Error(eDLL_T::RTECH, NO_ERROR, "%s - decompression failed for '%s'!\n", - __FUNCTION__, inPakFile.String()); - } -} - -/* -===================== -RTech_Compress_f - - Compresses input RPak file and - dumps results to base path -===================== -*/ -void Pak_Compress_f(const CCommand& args) -{ - if (args.ArgC() < 2) - { - return; - } - - CFmtStr1024 inPakFile(PLATFORM_PAK_OVERRIDE_PATH "%s", args.Arg(1)); - CFmtStr1024 outPakFile(PLATFORM_PAK_PATH "%s", args.Arg(1)); - - // NULL means default compress level - const int compressLevel = args.ArgC() > 2 ? atoi(args.Arg(2)) : NULL; - - if (!Pak_EncodePakFile(inPakFile.String(), outPakFile.String(), compressLevel)) - { - Error(eDLL_T::RTECH, NO_ERROR, "%s - compression failed for '%s'!\n", - __FUNCTION__, inPakFile.String()); - } -} /* ===================== @@ -641,35 +234,6 @@ void VPK_Unmount_f(const CCommand& args) FileSystem()->UnmountVPKFile(args.Arg(1)); } -/* -===================== -NET_SetKey_f - - Sets the input netchannel encryption key -===================== -*/ -void NET_SetKey_f(const CCommand& args) -{ - if (args.ArgC() < 2) - { - return; - } - - NET_SetKey(args.Arg(1)); -} - -/* -===================== -NET_GenerateKey_f - - Sets a random netchannel encryption key -===================== -*/ -void NET_GenerateKey_f(const CCommand& args) -{ - NET_GenerateKey(); -} - /* ===================== NET_UseRandomKeyChanged_f @@ -719,206 +283,7 @@ void NET_UseSocketsForLoopbackChanged_f(IConVar* pConVar, const char* pOldString } } -/* -===================== -SIG_GetAdr_f - - Logs the sigscan - results to the console. -===================== -*/ -void SIG_GetAdr_f(const CCommand& args) -{ - if (!IsCert() && !IsRetail()) - DetourAddress(); -} - -/* -===================== -CON_Help_f - - Shows the colors and - description of each - context. -===================== -*/ -void CON_Help_f(const CCommand& args) -{ - Msg(eDLL_T::COMMON, "Contexts:\n"); - SQVM_PrintFunc(reinterpret_cast(SQCONTEXT::SERVER), (SQChar*)(" = Server DLL (Script)\n")); - SQVM_PrintFunc(reinterpret_cast(SQCONTEXT::CLIENT), (SQChar*)(" = Client DLL (Script)\n")); - SQVM_PrintFunc(reinterpret_cast(SQCONTEXT::UI), (SQChar*)(" = UI DLL (Script)\n")); - - Msg(eDLL_T::SERVER, " = Server DLL (Code)\n"); - Msg(eDLL_T::CLIENT, " = Client DLL (Code)\n"); - Msg(eDLL_T::UI, " = UI DLL (Code)\n"); - Msg(eDLL_T::ENGINE, " = Engine DLL (Code)\n"); - Msg(eDLL_T::FS, " = FileSystem (Code)\n"); - Msg(eDLL_T::RTECH, " = PakLoad API (Code)\n"); - Msg(eDLL_T::MS, " = MaterialSystem (Code)\n"); - Msg(eDLL_T::AUDIO, " = Audio DLL (Code)\n"); - Msg(eDLL_T::VIDEO, " = Video DLL (Code)\n"); - Msg(eDLL_T::NETCON, " = NetConsole (Code)\n"); -} - #ifndef DEDICATED -/* -===================== -CON_LogHistory_f - - Shows the game console - submission history. -===================== -*/ -void CON_LogHistory_f(const CCommand& args) -{ - const vector vHistory = g_Console.GetHistory(); - for (size_t i = 0, nh = vHistory.size(); i < nh; i++) - { - Msg(eDLL_T::COMMON, "%3d: %s\n", i, vHistory[i].c_str()); - } -} - -/* -===================== -CON_RemoveLine_f - - Removes a range of lines - from the console. -===================== -*/ -void CON_RemoveLine_f(const CCommand& args) -{ - if (args.ArgC() < 3) - { - Msg(eDLL_T::CLIENT, "Usage 'con_removeline': start(int) end(int)\n"); - return; - } - - int start = atoi(args[1]); - int end = atoi(args[2]); - - g_Console.RemoveLog(start, end); -} - -/* -===================== -CON_ClearLines_f - - Clears all lines from - the developer console. -===================== -*/ -void CON_ClearLines_f(const CCommand& args) -{ - g_Console.ClearLog(); -} - -/* -===================== -CON_ClearHistory_f - - Clears all submissions from the - developer console history. -===================== -*/ -void CON_ClearHistory_f(const CCommand& args) -{ - g_Console.ClearHistory(); -} - -/* -===================== -RCON_CmdQuery_f - - Issues an RCON command to the - RCON server. -===================== -*/ -void RCON_CmdQuery_f(const CCommand& args) -{ - const int64_t argCount = args.ArgC(); - - if (argCount < 2) - { - const char* pszAddress = rcon_address->GetString(); - - if (RCONClient()->IsInitialized() - && !RCONClient()->IsConnected() - && pszAddress[0]) - { - RCONClient()->Connect(pszAddress); - } - } - else - { - if (!RCONClient()->IsInitialized()) - { - Warning(eDLL_T::CLIENT, "Failed to issue command to RCON server: %s\n", "uninitialized"); - return; - } - else if (RCONClient()->IsConnected()) - { - vector vecMsg; - bool bSuccess = false; - const SocketHandle_t hSocket = RCONClient()->GetSocket(); - - if (strcmp(args.Arg(1), "PASS") == 0) // Auth with RCON server using rcon_password ConVar value. - { - if (argCount > 2) - { - bSuccess = RCONClient()->Serialize(vecMsg, args.Arg(2), "", cl_rcon::request_t::SERVERDATA_REQUEST_AUTH); - } - else // Use 'rcon_password' ConVar as password. - { - bSuccess = RCONClient()->Serialize(vecMsg, rcon_password->GetString(), "", cl_rcon::request_t::SERVERDATA_REQUEST_AUTH); - } - - if (bSuccess) - { - RCONClient()->Send(hSocket, vecMsg.data(), int(vecMsg.size())); - } - - return; - } - else if (strcmp(args.Arg(1), "disconnect") == 0) // Disconnect from RCON server. - { - RCONClient()->Disconnect("issued by user"); - return; - } - - bSuccess = RCONClient()->Serialize(vecMsg, args.Arg(1), args.ArgS(), cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND); - if (bSuccess) - { - RCONClient()->Send(hSocket, vecMsg.data(), int(vecMsg.size())); - } - return; - } - else - { - Warning(eDLL_T::CLIENT, "Failed to issue command to RCON server: %s\n", "unconnected"); - return; - } - } -} - -/* -===================== -RCON_Disconnect_f - - Disconnect from RCON server -===================== -*/ -void RCON_Disconnect_f(const CCommand& args) -{ - const bool bIsConnected = RCONClient()->IsConnected(); - RCONClient()->Disconnect("issued by user"); - - if (bIsConnected) // Log if client was indeed connected. - { - Msg(eDLL_T::CLIENT, "User closed RCON connection\n"); - } -} /* ===================== @@ -1065,55 +430,7 @@ void RCON_ConnectionCountChanged_f(IConVar* pConVar, const char* pOldString, flo } #endif // !CLIENT_DLL -/* -===================== -SQVM_ServerScript_f - - Executes input on the - VM in SERVER context. -===================== -*/ -void SQVM_ServerScript_f(const CCommand& args) -{ - if (args.ArgC() >= 2) - { - Script_Execute(args.ArgS(), SQCONTEXT::SERVER); - } -} - #ifndef DEDICATED -/* -===================== -SQVM_ClientScript_f - - Executes input on the - VM in CLIENT context. -===================== -*/ -void SQVM_ClientScript_f(const CCommand& args) -{ - if (args.ArgC() >= 2) - { - Script_Execute(args.ArgS(), SQCONTEXT::CLIENT); - } -} - -/* -===================== -SQVM_UIScript_f - - Executes input on the - VM in UI context. -===================== -*/ -void SQVM_UIScript_f(const CCommand& args) -{ - if (args.ArgC() >= 2) - { - Script_Execute(args.ArgS(), SQCONTEXT::UI); - } -} - /* ===================== Mat_CrossHair_f @@ -1369,52 +686,6 @@ void CVFlag_f(const CCommand& args) cv->CvarFindFlags_f(args); } -/* -===================== -CC_CreateFakePlayer_f - - Creates a fake player - on the server -===================== -*/ -#ifndef CLIENT_DLL -void CC_CreateFakePlayer_f(const CCommand& args) -{ - if (!g_pServer->IsActive()) - return; - - if (args.ArgC() < 3) - { - Msg(eDLL_T::SERVER, "usage 'sv_addbot': name(string) teamid(int)\n"); - return; - } - - const int numPlayers = g_pServer->GetNumClients(); - - // Already at max, don't create. - if (numPlayers >= g_ServerGlobalVariables->m_nMaxClients) - return; - - const char* playerName = args.Arg(1); - - int teamNum = atoi(args.Arg(2)); - const int maxTeams = int(g_pServer->GetMaxTeams()) + 1; - - // Clamp team count, going above the limit will - // cause a crash. Going below 0 means that the - // engine will assign the bot to the last team. - if (teamNum > maxTeams) - teamNum = maxTeams; - - g_pEngineServer->LockNetworkStringTables(true); - - const edict_t nHandle = g_pEngineServer->CreateFakeClient(playerName, teamNum); - g_pServerGameClients->ClientFullyConnect(nHandle, false); - - g_pEngineServer->LockNetworkStringTables(false); -} -#endif // !CLIENT_DLL - #ifndef DEDICATED static double s_flScriptExecTimeBase = 0.0f; static int s_nScriptExecCount = 0; diff --git a/src/common/callback.h b/src/common/callback.h index eb4493e9..9f57a51c 100644 --- a/src/common/callback.h +++ b/src/common/callback.h @@ -3,35 +3,14 @@ inline bool(*v_SetupGamemode)(const char* pszPlayList); /* ==== CONCOMMANDCALLBACK ============================================================================================================================================== */ -inline void(*v__DownloadPlaylists_f)(void); inline void(*v__Cmd_Exec_f)(const CCommand& args); /////////////////////////////////////////////////////////////////////////////// void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue); void MP_HostName_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue); -#ifndef DEDICATED -void ToggleConsole_f(const CCommand& args); -void ToggleBrowser_f(const CCommand& args); -#endif // !DEDICATED #ifndef CLIENT_DLL -void Host_Kick_f(const CCommand& args); -void Host_KickID_f(const CCommand& args); -void Host_Ban_f(const CCommand& args); -void Host_BanID_f(const CCommand& args); -void Host_Unban_f(const CCommand& args); -void Host_ReloadBanList_f(const CCommand& args); -void Host_ReloadPlaylists_f(const CCommand& args); void Host_Changelevel_f(const CCommand& args); -void Detour_HotSwap_f(const CCommand& args); #endif // !CLIENT_DLL -void Pak_ListPaks_f(const CCommand& args); -void Pak_ListTypes_f(const CCommand& args); -void Pak_RequestUnload_f(const CCommand& args); -void Pak_RequestLoad_f(const CCommand& args); -void Pak_Swap_f(const CCommand& args); -void Pak_StringToGUID_f(const CCommand& args); -void Pak_Decompress_f(const CCommand& args); -void Pak_Compress_f(const CCommand& args); void VPK_Pack_f(const CCommand& args); void VPK_Unpack_f(const CCommand& args); void VPK_Mount_f(const CCommand& args); @@ -40,16 +19,8 @@ void NET_SetKey_f(const CCommand& args); void NET_GenerateKey_f(const CCommand& args); void NET_UseRandomKeyChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue); void NET_UseSocketsForLoopbackChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue); -void SIG_GetAdr_f(const CCommand& args); -void CON_Help_f(const CCommand& args); #ifndef DEDICATED -void CON_LogHistory_f(const CCommand& args); -void CON_RemoveLine_f(const CCommand& args); -void CON_ClearLines_f(const CCommand& args); -void CON_ClearHistory_f(const CCommand& args); -void RCON_CmdQuery_f(const CCommand& args); -void RCON_Disconnect_f(const CCommand& args); void RCON_InputOnlyChanged_f(IConVar* pConVar, const char* pOldString, float flOldValue); void GFX_NVN_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue); @@ -84,13 +55,11 @@ class VCallback : public IDetour virtual void GetAdr(void) const { LogFunAdr("SetupGamemode", v_SetupGamemode); - LogFunAdr("DownloadPlaylist_f", v__DownloadPlaylists_f); LogFunAdr("Cmd_Exec_f", v__Cmd_Exec_f); } virtual void GetFun(void) const { g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 48 8B D9 48 C7 C0 ?? ?? ?? ??").GetPtr(v_SetupGamemode); - g_GameDll.FindPatternSIMD("33 C9 C6 05 ?? ?? ?? ?? ?? E9 ?? ?? ?? ??").GetPtr(v__DownloadPlaylists_f); g_GameDll.FindPatternSIMD("40 55 53 48 8D AC 24 ?? ?? ?? ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B D9").GetPtr(v__Cmd_Exec_f); } virtual void GetVar(void) const { } diff --git a/src/common/global.cpp b/src/common/global.cpp index 28fcb7bb..831a8869 100644 --- a/src/common/global.cpp +++ b/src/common/global.cpp @@ -719,79 +719,19 @@ void ConVar_PurgeHostNames(void) } } -//----------------------------------------------------------------------------- -// Purpose: ConCommand registration -//----------------------------------------------------------------------------- -void ConCommand_StaticInit(void) -{ - //------------------------------------------------------------------------- - // ENGINE DLL | - ConCommand::StaticCreate("bhit", "Bullet-hit trajectory debug.", nullptr, FCVAR_DEVELOPMENTONLY | FCVAR_GAMEDLL, BHit_f, nullptr); +static ConCommand bhit("bhit", BHit_f, "Bullet-hit trajectory debug", FCVAR_DEVELOPMENTONLY | FCVAR_GAMEDLL); + #ifndef DEDICATED - ConCommand::StaticCreate("line", "Draw a debug line.", nullptr, FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT, Line_f, nullptr); - ConCommand::StaticCreate("sphere", "Draw a debug sphere.", nullptr, FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT, Sphere_f, nullptr); - ConCommand::StaticCreate("capsule", "Draw a debug capsule.", nullptr, FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT, Capsule_f, nullptr); +static ConCommand line("line", Line_f, "Draw a debug line", FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT); +static ConCommand sphere("sphere", Sphere_f, "Draw a debug sphere", FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT); +static ConCommand capsule("capsule", Capsule_f, "Draw a debug capsule", FCVAR_DEVELOPMENTONLY | FCVAR_CHEAT); #endif //!DEDICATED - ConCommand::StaticCreate("con_help", "Shows the colors and description of each context.", nullptr, FCVAR_RELEASE, CON_Help_f, nullptr); -#ifndef CLIENT_DLL - ConCommand::StaticCreate("reload_playlists", "Reloads the playlists file.", nullptr, FCVAR_RELEASE, Host_ReloadPlaylists_f, nullptr); -#endif // !CLIENT_DLL - //------------------------------------------------------------------------- - // SERVER DLL | -#ifndef CLIENT_DLL - ConCommand::StaticCreate("script", "Run input code as SERVER script on the VM.", nullptr, FCVAR_DEVELOPMENTONLY | FCVAR_GAMEDLL | FCVAR_CHEAT, SQVM_ServerScript_f, nullptr); - ConCommand::StaticCreate("kick", "Kick a client from the server by user name.", "kick \"\"", FCVAR_RELEASE, Host_Kick_f, nullptr); - ConCommand::StaticCreate("kickid", "Kick a client from the server by handle, nucleus id or ip address.", "kickid \"\"/\"/\"", FCVAR_RELEASE, Host_KickID_f, nullptr); - ConCommand::StaticCreate("ban", "Bans a client from the server by user name.", "ban ", FCVAR_RELEASE, Host_Ban_f, nullptr); - ConCommand::StaticCreate("banid", "Bans a client from the server by handle, nucleus id or ip address.", "banid \"\"/\"/\"", FCVAR_RELEASE, Host_BanID_f, nullptr); - ConCommand::StaticCreate("unban", "Unbans a client from the server by nucleus id or ip address.", "unban \"\"/\"\"", FCVAR_RELEASE, Host_Unban_f, nullptr); - ConCommand::StaticCreate("sv_reloadbanlist", "Reloads the banned list.", nullptr, FCVAR_RELEASE, Host_ReloadBanList_f, nullptr); - ConCommand::StaticCreate("sv_addbot", "Creates a bot on the server.", nullptr, FCVAR_RELEASE, CC_CreateFakePlayer_f, nullptr); - ConCommand::StaticCreate("navmesh_hotswap", "Hot swap the NavMesh for all hulls.", nullptr, FCVAR_DEVELOPMENTONLY, Detour_HotSwap_f, nullptr); -#endif // !CLIENT_DLL -#ifndef DEDICATED - //------------------------------------------------------------------------- - // CLIENT DLL | - ConCommand::StaticCreate("script_client", "Run input code as CLIENT script on the VM.", nullptr, FCVAR_DEVELOPMENTONLY| FCVAR_CLIENTDLL | FCVAR_CHEAT, SQVM_ClientScript_f, nullptr); - ConCommand::StaticCreate("rcon", "Forward RCON query to remote server.", "rcon \"\"", FCVAR_CLIENTDLL | FCVAR_RELEASE, RCON_CmdQuery_f, nullptr); - ConCommand::StaticCreate("rcon_disconnect", "Disconnect from RCON server.", nullptr, FCVAR_CLIENTDLL | FCVAR_RELEASE, RCON_Disconnect_f, nullptr); - ConCommand::StaticCreate("con_history", "Shows the developer console submission history.", nullptr, FCVAR_CLIENTDLL | FCVAR_RELEASE, CON_LogHistory_f, nullptr); - ConCommand::StaticCreate("con_removeline", "Removes a range of lines from the developer console.", nullptr, FCVAR_CLIENTDLL | FCVAR_RELEASE, CON_RemoveLine_f, nullptr); - ConCommand::StaticCreate("con_clearlines", "Clears all lines from the developer console.", nullptr, FCVAR_CLIENTDLL | FCVAR_RELEASE, CON_ClearLines_f, nullptr); - ConCommand::StaticCreate("con_clearhistory", "Clears all submissions from the developer console history.", nullptr, FCVAR_CLIENTDLL | FCVAR_RELEASE, CON_ClearHistory_f, nullptr); - - ConCommand::StaticCreate("toggleconsole", "Show/hide the developer console.", nullptr, FCVAR_CLIENTDLL | FCVAR_RELEASE, ToggleConsole_f, nullptr); - ConCommand::StaticCreate("togglebrowser", "Show/hide the server browser.", nullptr, FCVAR_CLIENTDLL | FCVAR_RELEASE, ToggleBrowser_f, nullptr); - //------------------------------------------------------------------------- - // UI DLL | - ConCommand::StaticCreate("script_ui", "Run input code as UI script on the VM.", nullptr, FCVAR_DEVELOPMENTONLY | FCVAR_CLIENTDLL | FCVAR_CHEAT, SQVM_UIScript_f, nullptr); -#endif // !DEDICATED - //------------------------------------------------------------------------- - // FILESYSTEM API | - ConCommand::StaticCreate("fs_vpk_mount", "Mount a VPK file for FileSystem usage.", nullptr, FCVAR_DEVELOPMENTONLY, VPK_Mount_f, nullptr); - ConCommand::StaticCreate("fs_vpk_unmount", "Unmount a VPK file and clear its cache.", nullptr, FCVAR_DEVELOPMENTONLY, VPK_Unmount_f, nullptr); - ConCommand::StaticCreate("fs_vpk_pack", "Pack a VPK file from current workspace.", nullptr, FCVAR_DEVELOPMENTONLY, VPK_Pack_f, nullptr); - ConCommand::StaticCreate("fs_vpk_unpack", "Unpack all files from a VPK file.", nullptr, FCVAR_DEVELOPMENTONLY, VPK_Unpack_f, nullptr); - //------------------------------------------------------------------------- - // RTECH API | - ConCommand::StaticCreate("pak_strtoguid", "Calculates the GUID from input data.", nullptr, FCVAR_DEVELOPMENTONLY, Pak_StringToGUID_f, nullptr); - ConCommand::StaticCreate("pak_compress", "Compresses specified RPAK file.", nullptr, FCVAR_DEVELOPMENTONLY, Pak_Compress_f, RTech_PakCompress_f_CompletionFunc); - ConCommand::StaticCreate("pak_decompress", "Decompresses specified RPAK file.", nullptr, FCVAR_DEVELOPMENTONLY, Pak_Decompress_f, RTech_PakDecompress_f_CompletionFunc); - ConCommand::StaticCreate("pak_requestload", "Requests asynchronous load for specified RPAK file.", nullptr, FCVAR_DEVELOPMENTONLY, Pak_RequestLoad_f, RTech_PakLoad_f_CompletionFunc); - ConCommand::StaticCreate("pak_requestunload", "Requests unload for specified RPAK file or ID.", nullptr, FCVAR_DEVELOPMENTONLY, Pak_RequestUnload_f, RTech_PakUnload_f_CompletionFunc); - ConCommand::StaticCreate("pak_swap", "Requests swap for specified RPAK file or ID", nullptr, FCVAR_DEVELOPMENTONLY, Pak_Swap_f, nullptr); - ConCommand::StaticCreate("pak_listpaks", "Display a list of the loaded Pak files.", nullptr, FCVAR_RELEASE, Pak_ListPaks_f, nullptr); - ConCommand::StaticCreate("pak_listtypes", "Display a list of the registered asset types.", nullptr, FCVAR_RELEASE, Pak_ListTypes_f, nullptr); - //------------------------------------------------------------------------- - // NETCHANNEL | - ConCommand::StaticCreate("net_setkey", "Sets user specified base64 net key.", nullptr, FCVAR_RELEASE, NET_SetKey_f, nullptr); - ConCommand::StaticCreate("net_generatekey", "Generates and sets a random base64 net key.", nullptr, FCVAR_RELEASE, NET_GenerateKey_f, nullptr); - //------------------------------------------------------------------------- - // TIER0 | - if (!IsCert() && !IsRetail()) - ConCommand::StaticCreate("sig_getadr", "Logs the sigscan results to the console.", nullptr, FCVAR_DEVELOPMENTONLY | FCVAR_HIDDEN, SIG_GetAdr_f, nullptr); -} +// TODO: move VPK building code to separate file and place this in 'packedstore.cpp' +static ConCommand fs_vpk_mount("fs_vpk_mount", VPK_Mount_f, "Mount a VPK file for FileSystem usage", FCVAR_DEVELOPMENTONLY); +static ConCommand fs_vpk_unmount("fs_vpk_unmount", VPK_Unmount_f, "Unmount a VPK file and clear its cache", FCVAR_DEVELOPMENTONLY); +static ConCommand fs_vpk_pack("fs_vpk_pack", VPK_Pack_f, "Pack a VPK file from current workspace", FCVAR_DEVELOPMENTONLY); +static ConCommand fs_vpk_unpack("fs_vpk_unpack", VPK_Unpack_f, "Unpack all files from a VPK file", FCVAR_DEVELOPMENTONLY); //----------------------------------------------------------------------------- // Purpose: shipped ConCommand initialization diff --git a/src/common/global.h b/src/common/global.h index 118e241d..ee0b3da0 100644 --- a/src/common/global.h +++ b/src/common/global.h @@ -299,7 +299,6 @@ void ConVar_StaticInit(void); void ConVar_InitShipped(void); void ConVar_PurgeShipped(void); void ConVar_PurgeHostNames(void); -void ConCommand_StaticInit(void); void ConCommand_InitShipped(void); void ConCommand_PurgeShipped(void); diff --git a/src/core/dllmain.cpp b/src/core/dllmain.cpp index 75d4ebb0..b4a772e8 100644 --- a/src/core/dllmain.cpp +++ b/src/core/dllmain.cpp @@ -62,8 +62,6 @@ void Tier0_Init() g_RadAudioDecoderDll.InitFromName("binkawin64.dll"); g_RadAudioSystemDll.InitFromName("mileswin64.dll"); #endif // !DEDICATED - - g_pCmdLine = g_GameDll.GetExportedSymbol("g_pCmdLine").RCast(); g_CoreMsgVCallback = &EngineLoggerSink; // Setup logger callback sink. g_pCmdLine->CreateCmdLine(GetCommandLineA()); diff --git a/src/engine/client/cl_rcon.cpp b/src/engine/client/cl_rcon.cpp index f1f2873d..218fb598 100644 --- a/src/engine/client/cl_rcon.cpp +++ b/src/engine/client/cl_rcon.cpp @@ -229,3 +229,99 @@ CRConClient* RCONClient() // Singleton RCON Client. { return &s_RCONClient; } + +/* +===================== +RCON_CmdQuery_f + + Issues an RCON command to the + RCON server. +===================== +*/ +static void RCON_CmdQuery_f(const CCommand& args) +{ + const int64_t argCount = args.ArgC(); + + if (argCount < 2) + { + const char* pszAddress = rcon_address->GetString(); + + if (RCONClient()->IsInitialized() + && !RCONClient()->IsConnected() + && pszAddress[0]) + { + RCONClient()->Connect(pszAddress); + } + } + else + { + if (!RCONClient()->IsInitialized()) + { + Warning(eDLL_T::CLIENT, "Failed to issue command to RCON server: %s\n", "uninitialized"); + return; + } + else if (RCONClient()->IsConnected()) + { + vector vecMsg; + bool bSuccess = false; + const SocketHandle_t hSocket = RCONClient()->GetSocket(); + + if (strcmp(args.Arg(1), "PASS") == 0) // Auth with RCON server using rcon_password ConVar value. + { + if (argCount > 2) + { + bSuccess = RCONClient()->Serialize(vecMsg, args.Arg(2), "", cl_rcon::request_t::SERVERDATA_REQUEST_AUTH); + } + else // Use 'rcon_password' ConVar as password. + { + bSuccess = RCONClient()->Serialize(vecMsg, rcon_password->GetString(), "", cl_rcon::request_t::SERVERDATA_REQUEST_AUTH); + } + + if (bSuccess) + { + RCONClient()->Send(hSocket, vecMsg.data(), int(vecMsg.size())); + } + + return; + } + else if (strcmp(args.Arg(1), "disconnect") == 0) // Disconnect from RCON server. + { + RCONClient()->Disconnect("issued by user"); + return; + } + + bSuccess = RCONClient()->Serialize(vecMsg, args.Arg(1), args.ArgS(), cl_rcon::request_t::SERVERDATA_REQUEST_EXECCOMMAND); + if (bSuccess) + { + RCONClient()->Send(hSocket, vecMsg.data(), int(vecMsg.size())); + } + return; + } + else + { + Warning(eDLL_T::CLIENT, "Failed to issue command to RCON server: %s\n", "unconnected"); + return; + } + } +} + +/* +===================== +RCON_Disconnect_f + + Disconnect from RCON server +===================== +*/ +static void RCON_Disconnect_f() +{ + const bool bIsConnected = RCONClient()->IsConnected(); + RCONClient()->Disconnect("issued by user"); + + if (bIsConnected) // Log if client was indeed connected. + { + Msg(eDLL_T::CLIENT, "User closed RCON connection\n"); + } +} + +static ConCommand rcon("rcon", RCON_CmdQuery_f, "Forward RCON query to remote server", FCVAR_CLIENTDLL | FCVAR_RELEASE, nullptr, "rcon \"\""); +static ConCommand rcon_disconnect("rcon_disconnect", RCON_Disconnect_f, "Disconnect from RCON server", FCVAR_CLIENTDLL | FCVAR_RELEASE); diff --git a/src/engine/client/clientstate.cpp b/src/engine/client/clientstate.cpp index b3a2c644..00041fd2 100644 --- a/src/engine/client/clientstate.cpp +++ b/src/engine/client/clientstate.cpp @@ -139,7 +139,7 @@ void CClientState::VConnectionClosing(CClientState* thisptr, const char* szReaso { // Reload the local playlist to override the cached // one from the server we got disconnected from. - v__DownloadPlaylists_f(); + v_Playlists_Download_f(); Playlists_SDKInit(); }, 0); } diff --git a/src/engine/net.cpp b/src/engine/net.cpp index 0bce7f2e..6496fb2b 100644 --- a/src/engine/net.cpp +++ b/src/engine/net.cpp @@ -18,6 +18,23 @@ #endif // !_TOOLS #ifndef _TOOLS +static void NET_SetKey_f(const CCommand& args) +{ + if (args.ArgC() < 2) + { + return; + } + + NET_SetKey(args.Arg(1)); +} +static void NET_GenerateKey_f() +{ + NET_GenerateKey(); +} + +static ConCommand net_setkey("net_setkey", NET_SetKey_f, "Sets user specified base64 net key", FCVAR_RELEASE); +static ConCommand net_generatekey("net_generatekey", NET_GenerateKey_f, "Generates and sets a random base64 net key", FCVAR_RELEASE); + //----------------------------------------------------------------------------- // Purpose: hook and log the receive datagram // Input : iSocket - diff --git a/src/engine/sys_dll.cpp b/src/engine/sys_dll.cpp index 70f1635e..4365946b 100644 --- a/src/engine/sys_dll.cpp +++ b/src/engine/sys_dll.cpp @@ -40,19 +40,9 @@ //----------------------------------------------------------------------------- bool CSourceAppSystemGroup::StaticPreInit(CSourceAppSystemGroup* pSourceAppSystemGroup) { - if (pSourceAppSystemGroup->GetCurrentStage() == CSourceAppSystemGroup::CREATION) - { - ConVar_InitShipped(); - ConVar_PurgeShipped(); - ConCommand_StaticInit(); - ConCommand_InitShipped(); - ConCommand_PurgeShipped(); - } - return CSourceAppSystemGroup__PreInit(pSourceAppSystemGroup); } - //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/src/game/client/vscript_client.cpp b/src/game/client/vscript_client.cpp index fe6db959..edffbc3d 100644 --- a/src/game/client/vscript_client.cpp +++ b/src/game/client/vscript_client.cpp @@ -16,10 +16,47 @@ #include "networksystem/pylon.h" #include "networksystem/listmanager.h" #include "game/shared/vscript_shared.h" + +#include "vscript/vscript.h" #include "vscript/languages/squirrel_re/include/sqvm.h" #include "vscript_client.h" +/* +===================== +SQVM_ClientScript_f + + Executes input on the + VM in CLIENT context. +===================== +*/ +static void SQVM_ClientScript_f(const CCommand& args) +{ + if (args.ArgC() >= 2) + { + Script_Execute(args.ArgS(), SQCONTEXT::CLIENT); + } +} + +/* +===================== +SQVM_UIScript_f + + Executes input on the + VM in UI context. +===================== +*/ +static void SQVM_UIScript_f(const CCommand& args) +{ + if (args.ArgC() >= 2) + { + Script_Execute(args.ArgS(), SQCONTEXT::UI); + } +} + +static ConCommand script_client("script_client", SQVM_ClientScript_f, "Run input code as CLIENT script on the VM", FCVAR_DEVELOPMENTONLY | FCVAR_CLIENTDLL | FCVAR_CHEAT); +static ConCommand script_ui("script_ui", SQVM_UIScript_f, "Run input code as UI script on the VM", FCVAR_DEVELOPMENTONLY | FCVAR_CLIENTDLL | FCVAR_CHEAT); + //----------------------------------------------------------------------------- // Purpose: checks if the server index is valid, raises an error if not //----------------------------------------------------------------------------- diff --git a/src/game/server/ai_utility.cpp b/src/game/server/ai_utility.cpp index 7cfdd427..ea2fe0ad 100644 --- a/src/game/server/ai_utility.cpp +++ b/src/game/server/ai_utility.cpp @@ -5,7 +5,9 @@ //=============================================================================// #include "core/stdafx.h" +#include "tier0/fasttimer.h" #include "tier1/cvar.h" +#include "engine/server/server.h" #include "public/edict.h" #include "game/server/detour_impl.h" #include "game/server/ai_networkmanager.h" @@ -132,6 +134,33 @@ void Detour_HotSwap() Error(eDLL_T::SERVER, NOERROR, "%s - Failed to hot swap NavMesh\n", __FUNCTION__); } +/* +===================== +Detour_HotSwap_f + + Hot swaps the NavMesh + while the game is running +===================== +*/ +static void Detour_HotSwap_f() +{ + if (!g_pServer->IsActive()) + return; // Only execute if server is initialized and active. + + Msg(eDLL_T::SERVER, "Executing NavMesh hot swap for level '%s'\n", + g_ServerGlobalVariables->m_pszMapName); + + CFastTimer timer; + + timer.Start(); + Detour_HotSwap(); + + timer.End(); + Msg(eDLL_T::SERVER, "Hot swap took '%lf' seconds\n", timer.GetDuration().GetSeconds()); +} + +static ConCommand navmesh_hotswap("navmesh_hotswap", Detour_HotSwap_f, "Hot swap the NavMesh for all hulls", FCVAR_DEVELOPMENTONLY); + /////////////////////////////////////////////////////////////////////////////// void VRecast::Detour(const bool bAttach) const { diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index c7365536..2a90ab76 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -234,4 +234,50 @@ void CPlayer::PlayerRunCommand(CUserCmd* pUserCmd, IMoveHelper* pMover) void CPlayer::SetLastUserCommand(CUserCmd* pUserCmd) { m_LastCmd.Copy(pUserCmd); -} \ No newline at end of file +} + +/* +===================== +CC_CreateFakePlayer_f + + Creates a fake player + on the server +===================== +*/ +static void CC_CreateFakePlayer_f(const CCommand& args) +{ + if (!g_pServer->IsActive()) + return; + + if (args.ArgC() < 3) + { + Msg(eDLL_T::SERVER, "usage 'sv_addbot': name(string) teamid(int)\n"); + return; + } + + const int numPlayers = g_pServer->GetNumClients(); + + // Already at max, don't create. + if (numPlayers >= g_ServerGlobalVariables->m_nMaxClients) + return; + + const char* playerName = args.Arg(1); + + int teamNum = atoi(args.Arg(2)); + const int maxTeams = int(g_pServer->GetMaxTeams()) + 1; + + // Clamp team count, going above the limit will + // cause a crash. Going below 0 means that the + // engine will assign the bot to the last team. + if (teamNum > maxTeams) + teamNum = maxTeams; + + g_pEngineServer->LockNetworkStringTables(true); + + const edict_t nHandle = g_pEngineServer->CreateFakeClient(playerName, teamNum); + g_pServerGameClients->ClientFullyConnect(nHandle, false); + + g_pEngineServer->LockNetworkStringTables(false); +} + +static ConCommand sv_addbot("sv_addbot", CC_CreateFakePlayer_f, "Creates a bot on the server", FCVAR_RELEASE); diff --git a/src/game/server/vscript_server.cpp b/src/game/server/vscript_server.cpp index c6fc6fc0..e82d815b 100644 --- a/src/game/server/vscript_server.cpp +++ b/src/game/server/vscript_server.cpp @@ -11,12 +11,30 @@ #include "core/stdafx.h" #include "engine/server/server.h" #include "game/shared/vscript_shared.h" +#include "vscript/vscript.h" #include "vscript/languages/squirrel_re/include/sqvm.h" #include "vscript_server.h" #include #include +/* +===================== +SQVM_ServerScript_f + + Executes input on the + VM in SERVER context. +===================== +*/ +static void SQVM_ServerScript_f(const CCommand& args) +{ + if (args.ArgC() >= 2) + { + Script_Execute(args.ArgS(), SQCONTEXT::SERVER); + } +} +static ConCommand script("script", SQVM_ServerScript_f, "Run input code as SERVER script on the VM", FCVAR_DEVELOPMENTONLY | FCVAR_GAMEDLL | FCVAR_CHEAT); + namespace VScriptCode { namespace Server diff --git a/src/gameui/IBrowser.cpp b/src/gameui/IBrowser.cpp index 4ed71f5a..a622854f 100644 --- a/src/gameui/IBrowser.cpp +++ b/src/gameui/IBrowser.cpp @@ -37,6 +37,8 @@ History: #include "public/edict.h" #include "game/shared/vscript_shared.h" +static ConCommand togglebrowser("togglebrowser", CBrowser::ToggleBrowser_f, "Show/hide the server browser", FCVAR_CLIENTDLL | FCVAR_RELEASE); + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -602,7 +604,7 @@ void CBrowser::HostPanel(void) { g_TaskScheduler->Dispatch([]() { - v__DownloadPlaylists_f(); + v_Playlists_Download_f(); Playlists_SDKInit(); // Re-Init playlist. }, 0); } @@ -869,4 +871,13 @@ void CBrowser::SetStyleVar(void) ImGui::SetWindowPos(ImVec2(-500.f, 50.f), ImGuiCond_FirstUseEver); } +//----------------------------------------------------------------------------- +// Purpose: toggles the server browser +//----------------------------------------------------------------------------- +void CBrowser::ToggleBrowser_f() +{ + g_Browser.m_bActivate ^= true; + ResetInput(); // Disable input to game when browser is drawn. +} + CBrowser g_Browser; \ No newline at end of file diff --git a/src/gameui/IBrowser.h b/src/gameui/IBrowser.h index b01eb17d..2a9d40f0 100644 --- a/src/gameui/IBrowser.h +++ b/src/gameui/IBrowser.h @@ -38,6 +38,10 @@ public: inline bool IsVisible() { return m_flFadeAlpha > 0.0f; } +public: + // Command callbacks + static void ToggleBrowser_f(); + const char* m_pszBrowserLabel; bool m_bActivate; diff --git a/src/gameui/IConsole.cpp b/src/gameui/IConsole.cpp index 7d5f9b12..052bd0e7 100644 --- a/src/gameui/IConsole.cpp +++ b/src/gameui/IConsole.cpp @@ -23,6 +23,13 @@ History: #include "engine/cmd.h" #include "gameui/IConsole.h" +static ConCommand toggleconsole("toggleconsole", CConsole::ToggleConsole_f, "Show/hide the developer console.", FCVAR_CLIENTDLL | FCVAR_RELEASE); + +static ConCommand con_history("con_history", CConsole::LogHistory_f, "Shows the developer console submission history", FCVAR_CLIENTDLL | FCVAR_RELEASE); +static ConCommand con_removeline("con_removeline", CConsole::RemoveLine_f, "Removes a range of lines from the developer console", FCVAR_CLIENTDLL | FCVAR_RELEASE); +static ConCommand con_clearlines("con_clearlines", CConsole::ClearLines_f, "Clears all lines from the developer console", FCVAR_CLIENTDLL | FCVAR_RELEASE); +static ConCommand con_clearhistory("con_clearhistory", CConsole::ClearHistory_f, "Clears all submissions from the developer console history", FCVAR_CLIENTDLL | FCVAR_RELEASE); + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -524,18 +531,24 @@ bool CConsole::AutoComplete(void) else if (m_bCanAutoComplete) // Command completion callback. { ResetAutoComplete(); - string svCommand; - for (size_t i = 0; i < sizeof(m_szInputBuf); i++) + char szCommand[sizeof(m_szInputBuf)]; + size_t i = 0; + + // Truncate everything past (and including) the space to get the + // command string. + for (; i < sizeof(m_szInputBuf); i++) { if (isspace(m_szInputBuf[i])) { break; } - svCommand += m_szInputBuf[i]; + + szCommand[i] = m_szInputBuf[i]; } - ConCommand* pCommand = g_pCVar->FindCommand(svCommand.c_str()); + szCommand[i] = '\0'; + ConCommand* pCommand = g_pCVar->FindCommand(szCommand); if (pCommand && pCommand->CanAutoComplete()) { @@ -547,9 +560,9 @@ bool CConsole::AutoComplete(void) return false; } - for (int i = 0; i < iret; ++i) + for (int j = 0; j < iret; ++j) { - m_vSuggest.push_back(CSuggest(commands[i].String(), COMMAND_COMPLETION_MARKER)); + m_vSuggest.push_back(CSuggest(commands[j].String(), COMMAND_COMPLETION_MARKER)); } } else @@ -1152,4 +1165,58 @@ void CConsole::SetStyleVar(void) ImGui::SetWindowPos(ImVec2(-1000, 50), ImGuiCond_FirstUseEver); } +//----------------------------------------------------------------------------- +// Purpose: toggles the console +//----------------------------------------------------------------------------- +void CConsole::ToggleConsole_f() +{ + g_Console.m_bActivate ^= true; + ResetInput(); // Disable input to game when console is drawn. +} + +//----------------------------------------------------------------------------- +// Purpose: shows the game console submission history. +//----------------------------------------------------------------------------- +void CConsole::LogHistory_f() +{ + const vector vHistory = g_Console.GetHistory(); + for (size_t i = 0, nh = vHistory.size(); i < nh; i++) + { + Msg(eDLL_T::COMMON, "%3d: %s\n", i, vHistory[i].c_str()); + } +} + +//----------------------------------------------------------------------------- +// Purpose: removes a range of lines from the console. +//----------------------------------------------------------------------------- +void CConsole::RemoveLine_f(const CCommand& args) +{ + if (args.ArgC() < 3) + { + Msg(eDLL_T::CLIENT, "Usage 'con_removeline': start(int) end(int)\n"); + return; + } + + int start = atoi(args[1]); + int end = atoi(args[2]); + + g_Console.RemoveLog(start, end); +} + +//----------------------------------------------------------------------------- +// Purpose: clears all lines from the developer console. +//----------------------------------------------------------------------------- +void CConsole::ClearLines_f() +{ + g_Console.ClearLog(); +} + +//----------------------------------------------------------------------------- +// Purpose: clears all submissions from the developer console history. +//----------------------------------------------------------------------------- +void CConsole::ClearHistory_f() +{ + g_Console.ClearHistory(); +} + CConsole g_Console; diff --git a/src/gameui/IConsole.h b/src/gameui/IConsole.h index ac100fc6..bb974da9 100644 --- a/src/gameui/IConsole.h +++ b/src/gameui/IConsole.h @@ -62,6 +62,14 @@ public: inline bool IsVisible() { return m_flFadeAlpha > 0.0f; } +public: + // Console command callbacks + static void ToggleConsole_f(); + static void LogHistory_f(); + static void RemoveLine_f(const CCommand& args); + static void ClearLines_f(); + static void ClearHistory_f(); + private: // Internal only. void AddLog(const ImVec4& color, const char* fmt, ...) /*IM_FMTARGS(2)*/; diff --git a/src/materialsystem/cmaterialsystem.cpp b/src/materialsystem/cmaterialsystem.cpp index 138fc051..edb9c694 100644 --- a/src/materialsystem/cmaterialsystem.cpp +++ b/src/materialsystem/cmaterialsystem.cpp @@ -8,7 +8,7 @@ #include "tier0/commandline.h" #include "tier1/cvar.h" #include "tier1/keyvalues.h" -#include "rtech/pak/pakparse.h" +#include "rtech/pak/pakstate.h" #include "engine/cmodel_bsp.h" #include "engine/sys_engine.h" #include "geforce/reflex.h" diff --git a/src/networksystem/bansystem.cpp b/src/networksystem/bansystem.cpp index d6dbf24a..2714dd77 100644 --- a/src/networksystem/bansystem.cpp +++ b/src/networksystem/bansystem.cpp @@ -412,5 +412,84 @@ void CBanSystem::AuthorPlayerById(const char* playerHandle, const bool shouldBan } } +/////////////////////////////////////////////////////////////////////////////// +// Console command handlers +/////////////////////////////////////////////////////////////////////////////// + +static void _Author_Client_f(const CCommand& args, EKickType type) +{ + if (args.ArgC() < 2) + { + return; + } + + const char* szReason = args.ArgC() > 2 ? args.Arg(2) : nullptr; + + switch (type) + { + case KICK_NAME: + { + g_BanSystem.KickPlayerByName(args.Arg(1), szReason); + break; + } + case KICK_ID: + { + g_BanSystem.KickPlayerById(args.Arg(1), szReason); + break; + } + case BAN_NAME: + { + g_BanSystem.BanPlayerByName(args.Arg(1), szReason); + break; + } + case BAN_ID: + { + g_BanSystem.BanPlayerById(args.Arg(1), szReason); + break; + } + default: + { + // Code bug. + Assert(0); + } + } +} +static void Host_Kick_f(const CCommand& args) +{ + _Author_Client_f(args, EKickType::KICK_NAME); +} +static void Host_KickID_f(const CCommand& args) +{ + _Author_Client_f(args, EKickType::KICK_ID); +} +static void Host_Ban_f(const CCommand& args) +{ + _Author_Client_f(args, EKickType::BAN_NAME); +} +static void Host_BanID_f(const CCommand& args) +{ + _Author_Client_f(args, EKickType::BAN_ID); +} +static void Host_Unban_f(const CCommand& args) +{ + if (args.ArgC() < 2) + { + return; + } + + g_BanSystem.UnbanPlayer(args.Arg(1)); +} +static void Host_ReloadBanList_f() +{ + g_BanSystem.LoadList(); // Reload banned list. +} + +static ConCommand kick("kick", Host_Kick_f, "Kick a client from the server by user name", FCVAR_RELEASE, nullptr, "kick \"\""); +static ConCommand kickid("kickid", Host_KickID_f, "Kick a client from the server by handle, nucleus id or ip address", FCVAR_RELEASE, nullptr, "kickid \"\"/\"/\""); +static ConCommand ban("ban", Host_Ban_f, "Bans a client from the server by user name", FCVAR_RELEASE, nullptr, "ban "); +static ConCommand banid("banid", Host_BanID_f, "Bans a client from the server by handle, nucleus id or ip address", FCVAR_RELEASE, nullptr, "banid \"\"/\"/\""); +static ConCommand unban("unban", Host_Unban_f, "Unbans a client from the server by nucleus id or ip address", FCVAR_RELEASE, nullptr, "unban \"\"/\"\""); +static ConCommand reload_banlist("banlist_reload", Host_ReloadBanList_f, "Reloads the banned list", FCVAR_RELEASE); + /////////////////////////////////////////////////////////////////////////////// CBanSystem g_BanSystem; diff --git a/src/public/coordsize.h b/src/public/coordsize.h index 8666768f..b21d9eee 100644 --- a/src/public/coordsize.h +++ b/src/public/coordsize.h @@ -29,7 +29,7 @@ #define NORMAL_RESOLUTION (1.0f/(NORMAL_DENOMINATOR)) // this is limited by the network fractional bits used for coords -// because net coords will be only be accurate to 5 bits fractional +// because net coords will only be accurate to 5 bits fractional // Standard collision test epsilon // 1/32nd inch collision epsilon #define DIST_EPSILON (0.03125) diff --git a/src/public/iconcommand.h b/src/public/iconcommand.h index af3bcb78..03805d4a 100644 --- a/src/public/iconcommand.h +++ b/src/public/iconcommand.h @@ -17,37 +17,7 @@ abstract_class IConCommandBaseAccessor public: // Flags is a combination of FCVAR flags in cvar.h. // hOut is filled in with a handle to the variable. - virtual bool RegisterConCommandBase(ConCommandBase* pVar) = 0; + virtual bool RegisterConCommandBase(ConCommandBase* const pVar) = 0; }; -//----------------------------------------------------------------------------- -// Abstract interface for ConVars -//----------------------------------------------------------------------------- -abstract_class IConCommandBase -{ -public: - virtual ~IConCommandBase(void) = 0; - - virtual bool IsCommand(void) const = 0; - - virtual bool IsFlagSet(int flag) const = 0; // Check flag - virtual void AddFlags(int flags) = 0; // Set flag - virtual void RemoveFlags(int flags) = 0; // Clear flag - virtual int GetFlags() const = 0; // Get flag - - virtual const char* GetName(void) const = 0; // Return name of cvar - virtual const char* GetHelpText(void) const = 0; // Return help text for cvar - virtual const char* GetUsageText(void) const = 0; // Return usage text for cvar - virtual void SetAccessor(char* bAccessors) const = 0; - - virtual bool IsRegistered(void) const = 0; - virtual CVarDLLIdentifier_t GetDLLIdentifier() const = 0; // Returns the DLL identifier - -protected: - virtual void Create(const char* pName, const char* pHelpString = 0, - int flags = 0) = 0; - virtual void Init() = 0; // Used internally by OneTimeInit to initialize/shutdown -}; - - -#endif // ICONCOMMAND_H \ No newline at end of file +#endif // ICONCOMMAND_H diff --git a/src/public/tier1/convar.h b/src/public/tier1/convar.h index adc4ad91..df145af2 100644 --- a/src/public/tier1/convar.h +++ b/src/public/tier1/convar.h @@ -26,38 +26,57 @@ class ConCommandBase public: virtual ~ConCommandBase(void) { }; - virtual bool IsCommand(void) const = 0; - virtual bool IsFlagSet(int nFlags) const = 0; + virtual bool IsCommand(void) const; + virtual bool IsFlagSet(const int nFlags) const; - virtual void AddFlags(int nFlags) = 0; - virtual void RemoveFlags(int nFlags) = 0; + virtual void AddFlags(const int nFlags); + virtual void RemoveFlags(const int nFlags); - virtual int GetFlags(void) const = 0; - virtual const char* GetName(void) const = 0; - virtual const char* GetHelpText(void) const = 0; - virtual const char* GetUsageText(void) const = 0; + virtual int GetFlags(void) const; + virtual const char* GetName(void) const; + virtual const char* GetHelpText(void) const; + virtual const char* GetUsageText(void) const; - virtual void SetAccessor(IConCommandBaseAccessor* pAccessor) = 0; - virtual bool IsRegistered(void) const = 0; + virtual void SetAccessor(IConCommandBaseAccessor* const pAccessor); + virtual bool IsRegistered(void) const; - virtual int GetDLLIdentifier() const = 0; + virtual int GetDLLIdentifier() const; virtual ConCommandBase* Create(const char* szName, const char* szHelpString, - int nFlags, const char* pszUsageString) = 0; + int nFlags, const char* pszUsageString); - virtual void Init() = 0; - - bool HasFlags(int nFlags) const; + virtual void Init(); + void Shutdown(); ConCommandBase* GetNext(void) const; char* CopyString(const char* szFrom) const; +//private: + // Next ConVar in chain + // Prior to register, it points to the next convar in the DLL. + // Once registered, though, m_pNext is reset to point to the next + // convar in the global list ConCommandBase* m_pNext; //0x0008 + + // Has the cvar been added to the global list? bool m_bRegistered; //0x0010 + + // Static data. const char* m_pszName; //0x0018 const char* m_pszHelpString; //0x0020 const char* m_pszUsageString; //0x0028 - IConCommandBaseAccessor* s_pAccessor; //0x0030 <-- unused since executable is monolithic. + + IConCommandBaseAccessor* m_pAccessor; //0x0030 <-- unused since executable is monolithic. + + // ConVar flags int m_nFlags; //0x0038 + + // ConVars add themselves to this list for the executable. + // Then ConVar_Register runs through all the console variables + // and registers them into a global list stored in vstdlib.dll + static ConCommandBase* s_pConCommandBases; + + // ConVars in this executable use this 'global' to access values. + static IConCommandBaseAccessor* s_pAccessor; }; static_assert(sizeof(ConCommandBase) == 0x40); @@ -70,16 +89,37 @@ class ConCommand : public ConCommandBase { friend class CCvar; public: - ConCommand(void); + typedef ConCommandBase BaseClass; - static ConCommand* StaticCreate(const char* szName, const char* szHelpString, const char* pszUsageString, - int nFlags, FnCommandCallback_t pCallback, FnCommandCompletionCallback pCommandCompletionCallback); + ConCommand(const char* pName, FnCommandCallbackV1_t callback, + const char* pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0, const char* pszUsageString = 0); + ConCommand(const char* pName, FnCommandCallback_t callback, + const char* pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0, const char* pszUsageString = 0); + ConCommand(const char* pName, ICommandCallback* pCallback, + const char* pHelpString = 0, int flags = 0, ICommandCompletionCallback* pCommandCompletionCallback = 0, const char* pszUsageString = 0); - virtual int AutoCompleteSuggest(const char* partial, CUtlVector< CUtlString >& commands) = 0; - virtual bool CanAutoComplete(void) const = 0; + virtual ~ConCommand(void); + virtual bool IsCommand(void) const; + + virtual int AutoCompleteSuggest(const char* partial, CUtlVector< CUtlString >& commands); + virtual bool CanAutoComplete(void) const; + + // Invoke the function + virtual void Dispatch(const CCommand& command); + +//private: void* m_nNullCallBack; //0x0040 void* m_pSubCallback; //0x0048 + + // NOTE: To maintain backward compatibility, we have to be very careful: + // All public virtual methods must appear in the same order always + // since engine code will be calling into this code, which *does not match* + // in the mod code; it's using slightly different, but compatible versions + // of this class. Also: Be very careful about adding new fields to this class. + // Those fields will not exist in the version of this class that is instanced + // in mod code. + // Call this function when executing the command union { @@ -233,6 +273,12 @@ FORCEINLINE const char* ConVar::GetString(void) const return str ? str : ""; } +//----------------------------------------------------------------------------- +// Called by the framework to register ConCommands with the ICVar +//----------------------------------------------------------------------------- +void ConVar_Register(int nCVarFlag = 0, IConCommandBaseAccessor* pAccessor = NULL); +void ConVar_Unregister(); + /* ==== CONVAR ========================================================================================================================================================== */ inline void*(*ConVar__Register)(ConVar* thisptr, const char* szName, const char* szDefaultValue, int nFlags, const char* szHelpString, bool bMin, float fMin, bool bMax, float fMax, FnChangeCallback_t pCallback, const char* pszUsageString); inline void(*ConVar__Unregister)(ConVar* thisptr); diff --git a/src/public/tier1/cvar.h b/src/public/tier1/cvar.h index af1f37c4..d422470e 100644 --- a/src/public/tier1/cvar.h +++ b/src/public/tier1/cvar.h @@ -162,6 +162,9 @@ extern ConVarFlags g_ConVarFlags; bool ConVar_ParseFlagString(const char* pszFlags, int& nFlags, const char* pszConVarName = "<>"); void ConVar_PrintDescription(ConCommandBase* pVar); +inline bool (*CCvar__Connect)(CCvar* thisptr, CreateInterfaceFn factory); +inline void (*CCvar__Disconnect)(CCvar* thisptr); + inline void (*v_ConVar_PrintDescription)(ConCommandBase* pVar); /////////////////////////////////////////////////////////////////////////////// @@ -169,18 +172,20 @@ class VCVar : public IDetour { virtual void GetAdr(void) const { + LogFunAdr("CCvar::Connect", CCvar__Connect); + LogFunAdr("CCvar::Disconnect", CCvar__Disconnect); LogFunAdr("ConVar_PrintDescription", v_ConVar_PrintDescription); LogVarAdr("g_pCVar", g_pCVar); } virtual void GetFun(void) const { + g_GameDll.FindPatternSIMD("48 83 EC 28 48 8B 05 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? 48 85 C0 48 0F 45 C8 FF 05 ?? ?? ?? ?? 48 89 0D ?? ?? ?? ??").GetPtr(CCvar__Connect); + g_GameDll.FindPatternSIMD("48 83 EC 28 48 8B 0D ?? ?? ?? ?? 48 85 C9 74 26 80 3D ?? ?? ?? ?? ?? 74 1D 48 8B 01 8B 15 ?? " + "?? ?? ?? FF 50 58 C7 05 ?? ?? ?? ?? ?? ?? ?? ?? C6 05 ?? ?? ?? ?? ?? 48 C7 05 ?? ?? ?? ?? ?? ?? ?? ??").GetPtr(CCvar__Disconnect); + g_GameDll.FindPatternSIMD("B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B 01 48 89 9C 24 ?? ?? ?? ??").GetPtr(v_ConVar_PrintDescription); } - virtual void GetVar(void) const - { - g_GameDll.FindPatternSIMD("48 83 EC 28 48 8B 05 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? 48 85 C0 48 0F 45 C8 FF 05 ?? ?? ?? ?? 48 89 0D ?? ?? ?? ??") - .FindPatternSelf("48 8D 0D").ResolveRelativeAddressSelf(3, 7).GetPtr(g_pCVar); - } + virtual void GetVar(void) const { } virtual void GetCon(void) const { } virtual void Detour(const bool bAttach) const; }; diff --git a/src/rtech/pak/pakparse.cpp b/src/rtech/pak/pakparse.cpp index 2aadcdd7..acd1a66e 100644 --- a/src/rtech/pak/pakparse.cpp +++ b/src/rtech/pak/pakparse.cpp @@ -332,7 +332,6 @@ bool Pak_ProcessPakFile(PakFile_t* const pak) fileStream->bytesStreamed, (memoryData->processedPatchedDataSize + PAK_DECODE_OUT_RING_BUFFER_SIZE), v22->compressionMode); qword1D0 = pak->pakDecoder.outBufBytePos; - pak->inputBytePos = pak->pakDecoder.inBufBytePos; if (didDecode) @@ -353,10 +352,6 @@ bool Pak_ProcessPakFile(PakFile_t* const pak) size_t numBytesToProcess = qword1D0 - memoryData->processedPatchedDataSize; - // DEBUG: REMOVE - if ((long long)pak->memoryData.patchFunc == 0x14043E2A0) - pak->memoryData.patchFunc = g_pakPatchApi[0]; - while (memoryData->patchSrcSize + memoryData->field_2A8) { // if there are no bytes left to process in this patch operation @@ -1310,6 +1305,3 @@ void V_PakParse::Detour(const bool bAttach) const DetourSetup(&v_Pak_RunAssetLoadingJobs, &Pak_RunAssetLoadingJobs, bAttach); } - -// Symbols taken from R2 dll's. -PakLoadFuncs_t* g_pakLoadApi = nullptr; diff --git a/src/rtech/pak/pakparse.h b/src/rtech/pak/pakparse.h index 22d62df3..30a176fe 100644 --- a/src/rtech/pak/pakparse.h +++ b/src/rtech/pak/pakparse.h @@ -28,49 +28,6 @@ inline int (*Pak_TrackAsset)(PakFile_t* const a1, PakAsset_t* a2); // TODO: name these! inline void (*sub_14043D870)(PakLoadedInfo_t* a1, int a2); -typedef struct PakLoadFuncs_s -{ - void* Initialize; // Returns the pak handle of the patch master RPak once initialized. - void* RegisterAsset; - char unknown0[8]; - PakHandle_t(*LoadAsync)(const char* pakFileName, CAlignedMemAlloc* allocator, int nIdx, bool bUnk); - void* LoadAsyncAndWait; - void (*UnloadAsync)(PakHandle_t handle); - void* UnloadAsyncAndWait; - char unknown2[16]; - void* Func7; - void* Func8; - EPakStatus(*WaitAsync)(PakHandle_t handle, void* finishCallback); - void* Func10; - void* Func11; - void* FindByGUID; - void* FindByName; - char unknown3[8]; - void* Func14; - void* Func15; - void* Func16; - void* Func17; - void* Func18; - void* IncrementStreamingAssetCount; - void* DecrementStreamingAssetCount; - void* IsFullStreamingInstall; - char unknown4[48]; - int (*OpenAsyncFile)(const char* const fileName, int logLevel, size_t* const outFileSize); - void (*CloseAsyncFile)(short fileHandle); - void* Func24; - void* Func25; - void* ReadAsyncFile; - void* ReadAsyncFileWithUserData; - uint8_t (*CheckAsyncRequest)(int idx, size_t* const bytesProcessed, const char** const statusMsg); - uint8_t (*WaitAndCheckAsyncRequest)(int idx, size_t* const bytesProcessed, const char** const statusMsg); - void* WaitForAsyncFileRead; - void* Func31; - void* Func32; - void* Func33; -} PakLoadFuncs_t; - -extern PakLoadFuncs_t* g_pakLoadApi; - /////////////////////////////////////////////////////////////////////////////// class V_PakParse : public IDetour { @@ -89,8 +46,6 @@ class V_PakParse : public IDetour LogFunAdr("Pak_ProcessPakFile", v_Pak_ProcessPakFile); LogFunAdr("Pak_ProcessAssets", v_Pak_ProcessAssets); LogFunAdr("Pak_ResolveAssetRelations", v_Pak_ResolveAssetRelations); - - LogVarAdr("g_pakLoadApi", g_pakLoadApi); } virtual void GetFun(void) const { @@ -111,10 +66,7 @@ class V_PakParse : public IDetour g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? EB 14 48 8D 0D ?? ?? ?? ??").FollowNearCallSelf().GetPtr(sub_14043D870); } - virtual void GetVar(void) const - { - g_pakLoadApi = CMemory(v_LauncherMain).Offset(0x820).FindPatternSelf("48 89").ResolveRelativeAddressSelf(0x3, 0x7).RCast(); - } + virtual void GetVar(void) const { } virtual void GetCon(void) const { } virtual void Detour(const bool bAttach) const; }; diff --git a/src/rtech/pak/pakstate.cpp b/src/rtech/pak/pakstate.cpp index a12979bf..496d855d 100644 --- a/src/rtech/pak/pakstate.cpp +++ b/src/rtech/pak/pakstate.cpp @@ -3,6 +3,262 @@ // Purpose: pak runtime memory and management // //=============================================================================// +#include "tier1/fmtstr.h" +#include "common/completion.h" #include "rtech/ipakfile.h" +#include "pakencode.h" +#include "pakdecode.h" +#include "paktools.h" #include "pakstate.h" +/* +===================== +Pak_ListPaks_f +===================== +*/ +static void Pak_ListPaks_f() +{ + Msg(eDLL_T::RTECH, "| id | name | status | asset count |\n"); + Msg(eDLL_T::RTECH, "|------|----------------------------------------------------|--------------------------------------|-------------|\n"); + uint32_t nTotalLoaded = 0; + + for (int16_t i = 0, n = g_pakGlobals->loadedPakCount; i < n; ++i) + { + const PakLoadedInfo_t& info = g_pakGlobals->loadedPaks[i]; + + if (info.status == EPakStatus::PAK_STATUS_FREED) + continue; + + const char* szRpakStatus = Pak_StatusToString(info.status); + + // todo: make status into a string from an array/vector + Msg(eDLL_T::RTECH, "| %04i | %-50s | %-36s | %11i |\n", info.handle, info.fileName, szRpakStatus, info.assetCount); + nTotalLoaded++; + } + Msg(eDLL_T::RTECH, "|------|----------------------------------------------------|--------------------------------------|-------------|\n"); + Msg(eDLL_T::RTECH, "| %18i loaded paks. |\n", nTotalLoaded); + Msg(eDLL_T::RTECH, "|------|----------------------------------------------------|--------------------------------------|-------------|\n"); +} + +/* +===================== +Pak_ListTypes_f +===================== +*/ +static void Pak_ListTypes_f() +{ + Msg(eDLL_T::RTECH, "| ext | description | version | header size | native size |\n"); + Msg(eDLL_T::RTECH, "|------|---------------------------|---------|-------------|-------------|\n"); + + uint32_t nRegistered = 0; + + for (int8_t i = 0; i < PAK_MAX_TYPES; ++i) + { + PakAssetBinding_t* type = &g_pakGlobals->assetBindings[i]; + + if (!type->description) + continue; + + FourCCString_t assetExtension; + FourCCToString(assetExtension, type->extension); + + Msg(eDLL_T::RTECH, "| %-4s | %-25s | %7i | %11i | %11i |\n", assetExtension, type->description, type->version, type->headerSize, type->nativeClassSize); + nRegistered++; + } + Msg(eDLL_T::RTECH, "|------|---------------------------|---------|-------------|-------------|\n"); + Msg(eDLL_T::RTECH, "| %18i registered types. |\n", nRegistered); + Msg(eDLL_T::RTECH, "|------|---------------------------|---------|-------------|-------------|\n"); +} + +/* +===================== +Pak_RequestUnload_f +===================== +*/ +static void Pak_RequestUnload_f(const CCommand& args) +{ + if (args.ArgC() < 2) + { + return; + } + + if (args.HasOnlyDigits(1)) + { + const PakHandle_t pakHandle = atoi(args.Arg(1)); + const PakLoadedInfo_t* const pakInfo = Pak_GetPakInfo(pakHandle); + + if (!pakInfo) + { + Warning(eDLL_T::RTECH, "Found no pak entry for specified handle.\n"); + return; + } + + Msg(eDLL_T::RTECH, "Requested pak unload for handle '%d'\n", pakHandle); + g_pakLoadApi->UnloadAsync(pakHandle); + } + else + { + const PakLoadedInfo_t* const pakInfo = Pak_GetPakInfo(args.Arg(1)); + if (!pakInfo) + { + Warning(eDLL_T::RTECH, "Found no pak entry for specified name.\n"); + return; + } + + Msg(eDLL_T::RTECH, "Requested pak unload for file '%s'\n", args.Arg(1)); + g_pakLoadApi->UnloadAsync(pakInfo->handle); + } +} + +/* +===================== +Pak_RequestLoad_f +===================== +*/ +static void Pak_RequestLoad_f(const CCommand& args) +{ + g_pakLoadApi->LoadAsync(args.Arg(1), AlignedMemAlloc(), NULL, 0); +} + + +/* +===================== +Pak_Swap_f +===================== +*/ +static void Pak_Swap_f(const CCommand& args) +{ + if (args.ArgC() < 2) + { + return; + } + + const char* pakName = nullptr; + + PakHandle_t pakHandle = INVALID_PAK_HANDLE; + const PakLoadedInfo_t* pakInfo = nullptr; + + if (args.HasOnlyDigits(1)) + { + pakHandle = atoi(args.Arg(1)); + pakInfo = Pak_GetPakInfo(pakHandle); + + if (!pakInfo) + { + Warning(eDLL_T::RTECH, "Found no pak entry for specified handle.\n"); + return; + } + + pakName = pakInfo->fileName; + } + else + { + pakName = args.Arg(1); + pakInfo = Pak_GetPakInfo(pakName); + + if (!pakInfo) + { + Warning(eDLL_T::RTECH, "Found no pak entry for specified name.\n"); + return; + } + + pakHandle = pakInfo->handle; + } + + Msg(eDLL_T::RTECH, "Requested pak swap for handle '%d'\n", pakHandle); + g_pakLoadApi->UnloadAsync(pakHandle); + + while (pakInfo->status != EPakStatus::PAK_STATUS_FREED) // Wait till this slot gets free'd. + std::this_thread::sleep_for(std::chrono::seconds(1)); + + g_pakLoadApi->LoadAsync(pakName, AlignedMemAlloc(), NULL, 0); +} + +/* +===================== +RTech_StringToGUID_f +===================== +*/ +static void Pak_StringToGUID_f(const CCommand& args) +{ + if (args.ArgC() < 2) + { + return; + } + + unsigned long long guid = Pak_StringToGuid(args.Arg(1)); + + Msg(eDLL_T::RTECH, "______________________________________________________________\n"); + Msg(eDLL_T::RTECH, "] RTECH_HASH ]------------------------------------------------\n"); + Msg(eDLL_T::RTECH, "] GUID: '0x%llX'\n", guid); +} + +/* +===================== +RTech_Decompress_f + + Decompresses input RPak file and + dumps results to override path +===================== +*/ +static void Pak_Decompress_f(const CCommand& args) +{ + if (args.ArgC() < 2) + { + return; + } + + CFmtStr1024 inPakFile(PLATFORM_PAK_PATH "%s", args.Arg(1)); + CFmtStr1024 outPakFile(PLATFORM_PAK_OVERRIDE_PATH "%s", args.Arg(1)); + + if (!Pak_DecodePakFile(inPakFile.String(), outPakFile.String())) + { + Error(eDLL_T::RTECH, NO_ERROR, "%s - decompression failed for '%s'!\n", + __FUNCTION__, inPakFile.String()); + } +} + +/* +===================== +RTech_Compress_f + + Compresses input RPak file and + dumps results to base path +===================== +*/ +static void Pak_Compress_f(const CCommand& args) +{ + if (args.ArgC() < 2) + { + return; + } + + CFmtStr1024 inPakFile(PLATFORM_PAK_OVERRIDE_PATH "%s", args.Arg(1)); + CFmtStr1024 outPakFile(PLATFORM_PAK_PATH "%s", args.Arg(1)); + + // NULL means default compress level + const int compressLevel = args.ArgC() > 2 ? atoi(args.Arg(2)) : NULL; + + if (!Pak_EncodePakFile(inPakFile.String(), outPakFile.String(), compressLevel)) + { + Error(eDLL_T::RTECH, NO_ERROR, "%s - compression failed for '%s'!\n", + __FUNCTION__, inPakFile.String()); + } +} + +static ConCommand pak_strtoguid("pak_strtoguid", Pak_StringToGUID_f, "Calculates the GUID from input data", FCVAR_DEVELOPMENTONLY); + +static ConCommand pak_compress("pak_compress", Pak_Compress_f, "Compresses specified RPAK file", FCVAR_DEVELOPMENTONLY, RTech_PakCompress_f_CompletionFunc); +static ConCommand pak_decompress("pak_decompress", Pak_Decompress_f, "Decompresses specified RPAK file", FCVAR_DEVELOPMENTONLY, RTech_PakDecompress_f_CompletionFunc); + +static ConCommand pak_requestload("pak_requestload", Pak_RequestLoad_f, "Requests asynchronous load for specified RPAK file", FCVAR_DEVELOPMENTONLY, RTech_PakLoad_f_CompletionFunc); +static ConCommand pak_requestunload("pak_requestunload", Pak_RequestUnload_f, "Requests unload for specified RPAK file or ID", FCVAR_DEVELOPMENTONLY, RTech_PakUnload_f_CompletionFunc); + +static ConCommand pak_swap("pak_swap", Pak_Swap_f, "Requests swap for specified RPAK file or ID", FCVAR_DEVELOPMENTONLY); + +static ConCommand pak_listpaks("pak_listpaks", Pak_ListPaks_f, "Display a list of the loaded Pak files", FCVAR_RELEASE); +static ConCommand pak_listtypes("pak_listtypes", Pak_ListTypes_f, "Display a list of the registered asset types", FCVAR_RELEASE); + + +// Symbols taken from R2 dll's. +PakLoadFuncs_s* g_pakLoadApi = nullptr; diff --git a/src/rtech/pak/pakstate.h b/src/rtech/pak/pakstate.h index f3efb868..c2c08f28 100644 --- a/src/rtech/pak/pakstate.h +++ b/src/rtech/pak/pakstate.h @@ -6,7 +6,50 @@ #include "rtech/ipakfile.h" +struct PakLoadFuncs_s +{ + void* Initialize; // Returns the pak handle of the patch master RPak once initialized. + void* RegisterAsset; + char unknown0[8]; + PakHandle_t(*LoadAsync)(const char* pakFileName, CAlignedMemAlloc* allocator, int nIdx, bool bUnk); + void* LoadAsyncAndWait; + void (*UnloadAsync)(PakHandle_t handle); + void* UnloadAsyncAndWait; + char unknown2[16]; + void* Func7; + void* Func8; + EPakStatus(*WaitAsync)(PakHandle_t handle, void* finishCallback); + void* Func10; + void* Func11; + void* FindByGUID; + void* FindByName; + char unknown3[8]; + void* Func14; + void* Func15; + void* Func16; + void* Func17; + void* Func18; + void* IncrementStreamingAssetCount; + void* DecrementStreamingAssetCount; + void* IsFullStreamingInstall; + char unknown4[48]; + int (*OpenAsyncFile)(const char* const fileName, int logLevel, size_t* const outFileSize); + void (*CloseAsyncFile)(short fileHandle); + void* Func24; + void* Func25; + void* ReadAsyncFile; + void* ReadAsyncFileWithUserData; + uint8_t(*CheckAsyncRequest)(int idx, size_t* const bytesProcessed, const char** const statusMsg); + uint8_t(*WaitAndCheckAsyncRequest)(int idx, size_t* const bytesProcessed, const char** const statusMsg); + void* WaitForAsyncFileRead; + void* Func31; + void* Func32; + void* Func33; +}; + inline PakGlobals_s* g_pakGlobals; +extern PakLoadFuncs_s* g_pakLoadApi; + inline JobHelpCallback_t g_pPakFifoLockWrapper; // Pointer to functor that takes the global pak fifolock as argument. // TODO: rename to 'g_bPakFifoLockAcquiredInMainThread' @@ -21,6 +64,7 @@ class V_PakState : public IDetour virtual void GetAdr(void) const { LogVarAdr("g_pakGlobals", g_pakGlobals); + LogVarAdr("g_pakLoadApi", g_pakLoadApi); LogVarAdr("g_pakFifoLockWrapper", g_pPakFifoLockWrapper); LogVarAdr("g_pakFifoLockAcquired", g_bPakFifoLockAcquired); @@ -28,7 +72,8 @@ class V_PakState : public IDetour virtual void GetFun(void) const { } virtual void GetVar(void) const { - g_pakGlobals = g_GameDll.FindPatternSIMD("48 8D 1D ?? ?? ?? ?? 45 8D 5A 0E").ResolveRelativeAddressSelf(0x3, 0x7).RCast(); /*48 8D 1D ? ? ? ? 45 8D 5A 0E*/ + g_pakGlobals = g_GameDll.FindPatternSIMD("48 8D 1D ?? ?? ?? ?? 45 8D 5A 0E").ResolveRelativeAddressSelf(0x3, 0x7).RCast(); + g_pakLoadApi = CMemory(v_LauncherMain).Offset(0x820).FindPatternSelf("48 89").ResolveRelativeAddressSelf(0x3, 0x7).RCast(); const CMemory jtBase(JT_HelpWithAnything); diff --git a/src/rtech/playlists/playlists.cpp b/src/rtech/playlists/playlists.cpp index 50039276..059bbe59 100644 --- a/src/rtech/playlists/playlists.cpp +++ b/src/rtech/playlists/playlists.cpp @@ -11,6 +11,19 @@ KeyValues** g_pPlaylistKeyValues = nullptr; // Get the KeyValue for the playlist vector g_vAllPlaylists = { "<>" }; std::mutex g_PlaylistsVecMutex; +/* +===================== +Host_ReloadPlaylists_f +===================== +*/ +static void Host_ReloadPlaylists_f() +{ + v_Playlists_Download_f(); + Playlists_SDKInit(); // Re-Init playlist. +} + +static ConCommand playlist_reload("playlist_reload", Host_ReloadPlaylists_f, "Reloads the playlists file", FCVAR_RELEASE); + //----------------------------------------------------------------------------- // Purpose: Initializes the playlist globals //----------------------------------------------------------------------------- diff --git a/src/rtech/playlists/playlists.h b/src/rtech/playlists/playlists.h index 735a134e..32b4f0cd 100644 --- a/src/rtech/playlists/playlists.h +++ b/src/rtech/playlists/playlists.h @@ -11,6 +11,7 @@ bool Playlists_Parse(const char* pszPlaylist); inline bool(*v_Playlists_Load)(const char* pszPlaylist); inline bool(*v_Playlists_Parse)(const char* pszPlaylist); inline const char* (*v_Playlists_GetCurrent)(void); +inline void(*v_Playlists_Download_f)(void); extern KeyValues** g_pPlaylistKeyValues; @@ -25,6 +26,7 @@ class VPlaylists : public IDetour LogFunAdr("Playlists_Load", v_Playlists_Load); LogFunAdr("Playlists_Parse", v_Playlists_Parse); LogFunAdr("Playlists_GetCurrent", v_Playlists_GetCurrent); + LogFunAdr("Playlists_Download_f", v_Playlists_Download_f); LogVarAdr("g_pPlaylistKeyValues", g_pPlaylistKeyValues); } virtual void GetFun(void) const @@ -32,6 +34,7 @@ class VPlaylists : public IDetour g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 56 48 83 EC 40 48 8B F1").GetPtr(v_Playlists_Load); g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 80 3D ?? ?? ?? ?? ?? 74 0C").FollowNearCallSelf().GetPtr(v_Playlists_Parse); g_GameDll.FindPatternSIMD("48 8B 05 ?? ?? ?? ?? 48 85 C0 75 08 48 8D 05 ?? ?? ?? ?? C3 0F B7 50 2A").GetPtr(v_Playlists_GetCurrent); + g_GameDll.FindPatternSIMD("33 C9 C6 05 ?? ?? ?? ?? ?? E9 ?? ?? ?? ??").GetPtr(v_Playlists_Download_f); } virtual void GetVar(void) const { diff --git a/src/tier0/commandline.cpp b/src/tier0/commandline.cpp index 38526d69..8cb9dd18 100644 --- a/src/tier0/commandline.cpp +++ b/src/tier0/commandline.cpp @@ -86,7 +86,7 @@ void CCommandLine::AppendParametersFromFile(const char* const pszConfig) } /////////////////////////////////////////////////////////////////////////////// -CCommandLine* g_pCmdLine = nullptr; +CCommandLine* g_pCmdLine = CModule::GetExportedSymbol(CModule::GetProcessEnvironmentBlock()->ImageBaseAddress, "g_pCmdLine").RCast(); void VCommandLine::Detour(const bool bAttach) const diff --git a/src/tier1/convar.cpp b/src/tier1/convar.cpp index 10317c80..9dd0c692 100644 --- a/src/tier1/convar.cpp +++ b/src/tier1/convar.cpp @@ -7,13 +7,238 @@ #include "tier1/convar.h" //----------------------------------------------------------------------------- -// Purpose: Checks if ConCommand has requested flags. -// Input : nFlags - -// Output : True if ConCommand has nFlags. +// Statically constructed list of ConCommandBases, +// used for registering them with the ICVar interface //----------------------------------------------------------------------------- -bool ConCommandBase::HasFlags(int nFlags) const +ConCommandBase* ConCommandBase::s_pConCommandBases = NULL; +IConCommandBaseAccessor* ConCommandBase::s_pAccessor = NULL; + +static int s_nCVarFlag = 0; + +// An unique identifier indicating which DLL this convar came from +static int s_nDLLIdentifier = -1; +static bool s_bRegistered = false; + +class CDefaultAccessor : public IConCommandBaseAccessor { - return m_nFlags & nFlags; +public: + virtual bool RegisterConCommandBase(ConCommandBase* const pVar) + { + // Link to engine's list instead + g_pCVar->RegisterConCommand(pVar); + return true; + } +}; + +static CDefaultAccessor s_DefaultAccessor; + +//----------------------------------------------------------------------------- +// Called by the framework to register ConCommandBases with the ICVar +//----------------------------------------------------------------------------- +void ConVar_Register(int nCVarFlag, IConCommandBaseAccessor* pAccessor) +{ + if (!g_pCVar || s_bRegistered) + return; + + Assert(s_nDLLIdentifier < 0); + s_bRegistered = true; + s_nCVarFlag = nCVarFlag; + s_nDLLIdentifier = g_pCVar->AllocateDLLIdentifier(); + + ConCommandBase* pCur, * pNext; + + ConCommandBase::s_pAccessor = pAccessor ? pAccessor : &s_DefaultAccessor; + pCur = ConCommandBase::s_pConCommandBases; + + while (pCur) + { + pNext = pCur->m_pNext; + pCur->AddFlags(s_nCVarFlag); + pCur->Init(); + pCur = pNext; + } + + g_pCVar->ProcessQueuedMaterialThreadConVarSets(); + + ConCommandBase::s_pConCommandBases = NULL; +} + +void ConVar_Unregister() +{ + if (!g_pCVar || !s_bRegistered) + return; + + Assert(s_nDLLIdentifier >= 0); + + // Do this after unregister!!! + g_pCVar->UnregisterConCommands(s_nDLLIdentifier); + s_nDLLIdentifier = -1; + s_bRegistered = false; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if this is a command +//----------------------------------------------------------------------------- +bool ConCommandBase::IsCommand(void) const +{ + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Checks if ConCommand has requested flags. +// Input : flag - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool ConCommandBase::IsFlagSet(const int flag) const +{ + return (flag & m_nFlags) ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flags - +//----------------------------------------------------------------------------- +void ConCommandBase::AddFlags(const int flags) +{ + m_nFlags |= flags; +} + +//----------------------------------------------------------------------------- +// Purpose: removes specified flags +//----------------------------------------------------------------------------- +void ConCommandBase::RemoveFlags(const int flags) +{ + m_nFlags &= ~flags; +} + +//----------------------------------------------------------------------------- +// Purpose: returns current flags +//----------------------------------------------------------------------------- +int ConCommandBase::GetFlags() const +{ + return m_nFlags; +} + +//----------------------------------------------------------------------------- +// Purpose: Return name of the command/var +// Output : const char +//----------------------------------------------------------------------------- +const char* ConCommandBase::GetName(void) const +{ + return m_pszName; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const char +//----------------------------------------------------------------------------- +const char* ConCommandBase::GetHelpText(void) const +{ + return m_pszHelpString; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const char +//----------------------------------------------------------------------------- +const char* ConCommandBase::GetUsageText(void) const +{ + return m_pszUsageString; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ConCommandBase::SetAccessor(IConCommandBaseAccessor* const pAccessor) +{ + m_pAccessor = pAccessor; +} + +//----------------------------------------------------------------------------- +// Purpose: Has this cvar been registered +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool ConCommandBase::IsRegistered(void) const +{ + return m_bRegistered; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the DLL identifier +//----------------------------------------------------------------------------- +int ConCommandBase::GetDLLIdentifier(void) const +{ + return s_nDLLIdentifier; +} + +//----------------------------------------------------------------------------- +// Purpose: Used internally by OneTimeInit to initialize. +//----------------------------------------------------------------------------- +void ConCommandBase::Init() +{ + if (s_pAccessor) + { + s_pAccessor->RegisterConCommandBase(this); + } +} + +void ConCommandBase::Shutdown() +{ + if (g_pCVar) + { + g_pCVar->UnregisterConCommand(this); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pName - +// callback - +// *pHelpString - +// flags - +//----------------------------------------------------------------------------- +ConCommandBase* ConCommandBase::Create(const char* pName, const char* pHelpString, int flags, const char* pszUsageString) +{ + m_bRegistered = false; + + // Name should be static data + Assert(pName); + m_pszName = pName; + + m_pszHelpString = pHelpString ? pHelpString : ""; + m_pszUsageString = pszUsageString ? pszUsageString : ""; + + m_pAccessor = nullptr; + + m_nFlags = flags; + + const int releaseMask = FCVAR_ARCHIVE|FCVAR_USERINFO|FCVAR_CHEAT| + FCVAR_RELEASE|FCVAR_ARCHIVE_PLAYERPROFILE|FCVAR_CLIENTCMD_CAN_EXECUTE; + + if (!(m_nFlags & releaseMask)) + { + m_nFlags |= FCVAR_DEVELOPMENTONLY; + } + + if (!(m_nFlags & FCVAR_UNREGISTERED)) + { + m_pNext = s_pConCommandBases; + s_pConCommandBases = this; + } + else + { + // It's unregistered + m_pNext = NULL; + } + + // If s_pAccessor is already set (this ConVar is not a global variable), + // register it. + if (s_pAccessor) + { + Init(); + } + + return m_pNext; } //----------------------------------------------------------------------------- @@ -65,50 +290,144 @@ int DefaultCompletionFunc(const char* partial, char commands[COMMAND_COMPLETION_ return 0; } -//----------------------------------------------------------------------------- -// Purpose: create -//----------------------------------------------------------------------------- -ConCommand* ConCommand::StaticCreate(const char* pszName, const char* pszHelpString, const char* pszUsageString, - int nFlags, FnCommandCallback_t pCallback, FnCommandCompletionCallback pCompletionFunc) +ConCommand::ConCommand(const char* pName, FnCommandCallbackV1_t callback, const char* pHelpString /*= 0*/, + int flags /*= 0*/, FnCommandCompletionCallback completionFunc /*= 0*/, const char* pszUsageString /*= 0*/) { - ConCommand* pCommand = (ConCommand*)malloc(sizeof(ConCommand)); - *(ConCommand**)pCommand = g_pConCommandVFTable; + m_nNullCallBack = DefaultNullSub; + m_pSubCallback = nullptr; - pCommand->m_pNext = nullptr; - pCommand->m_bRegistered = false; + // Set the callback + m_fnCommandCallbackV1 = callback; + m_bUsingNewCommandCallback = false; + m_bUsingCommandCallbackInterface = false; + m_fnCompletionCallback = completionFunc ? completionFunc : DefaultCompletionFunc; + m_bHasCompletionCallback = completionFunc != 0 ? true : false; - pCommand->m_pszName = pszName; - pCommand->m_pszHelpString = pszHelpString; - pCommand->m_pszUsageString = pszUsageString; - pCommand->s_pAccessor = nullptr; - pCommand->m_nFlags = nFlags; + // Setup the rest + BaseClass::Create(pName, pHelpString, flags, pszUsageString); +} - pCommand->m_nNullCallBack = DefaultNullSub; - pCommand->m_pSubCallback = nullptr; - pCommand->m_fnCommandCallback = pCallback; - pCommand->m_bHasCompletionCallback = pCompletionFunc != nullptr ? true : false; - pCommand->m_bUsingNewCommandCallback = true; - pCommand->m_bUsingCommandCallbackInterface = false; - pCommand->m_fnCompletionCallback = pCompletionFunc ? pCompletionFunc : DefaultCompletionFunc; +ConCommand::ConCommand(const char* pName, FnCommandCallback_t callback, const char* pHelpString /*= 0*/, + int flags /*= 0*/, FnCommandCompletionCallback completionFunc /*= 0*/, const char* pszUsageString /*= 0*/) +{ + m_nNullCallBack = DefaultNullSub; + m_pSubCallback = nullptr; - g_pCVar->RegisterConCommand(pCommand); - return pCommand; + // Set the callback + m_fnCommandCallback = callback; + m_bUsingNewCommandCallback = true; + m_fnCompletionCallback = completionFunc ? completionFunc : DefaultCompletionFunc; + m_bHasCompletionCallback = completionFunc != 0 ? true : false; + m_bUsingCommandCallbackInterface = false; + + // Setup the rest + BaseClass::Create(pName, pHelpString, flags, pszUsageString); +} + +ConCommand::ConCommand(const char* pName, ICommandCallback* pCallback, const char* pHelpString /*= 0*/, + int flags /*= 0*/, ICommandCompletionCallback* pCompletionCallback /*= 0*/, const char* pszUsageString /*= 0*/) +{ + m_nNullCallBack = DefaultNullSub; + m_pSubCallback = nullptr; + + // Set the callback + m_pCommandCallback = pCallback; + m_bUsingNewCommandCallback = false; + m_pCommandCompletionCallback = pCompletionCallback; + m_bHasCompletionCallback = (pCompletionCallback != 0); + m_bUsingCommandCallbackInterface = true; + + // Setup the rest + BaseClass::Create(pName, pHelpString, flags, pszUsageString); } //----------------------------------------------------------------------------- -// Purpose: construct/allocate +// Purpose: destructor //----------------------------------------------------------------------------- -ConCommand::ConCommand() - : m_nNullCallBack(nullptr) - , m_pSubCallback(nullptr) - , m_fnCommandCallbackV1(nullptr) - , m_fnCompletionCallback(nullptr) - , m_bHasCompletionCallback(false) - , m_bUsingNewCommandCallback(false) - , m_bUsingCommandCallbackInterface(false) +ConCommand::~ConCommand() { } +//----------------------------------------------------------------------------- +// Purpose: Returns true if this is a command +//----------------------------------------------------------------------------- +bool ConCommand::IsCommand(void) const +{ + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: calls the autocompletion method to get autocompletion suggestions +//----------------------------------------------------------------------------- +int ConCommand::AutoCompleteSuggest(const char* partial, CUtlVector< CUtlString >& commands) +{ + if (m_bUsingCommandCallbackInterface) + { + if (!m_pCommandCompletionCallback) + return 0; + + return m_pCommandCompletionCallback->CommandCompletionCallback(partial, commands); + } + + Assert(m_fnCompletionCallback); + + if (!m_fnCompletionCallback) + return 0; + + char rgpchCommands[COMMAND_COMPLETION_MAXITEMS][COMMAND_COMPLETION_ITEM_LENGTH]; + const int iret = (m_fnCompletionCallback)(partial, rgpchCommands); + + for (int i = 0; i < iret; ++i) + { + const CUtlString str = rgpchCommands[i]; + commands.AddToTail(str); + } + + return iret; +} + +//----------------------------------------------------------------------------- +// Returns true if the console command can autocomplete +//----------------------------------------------------------------------------- +bool ConCommand::CanAutoComplete(void) const +{ + return m_bHasCompletionCallback; +} + +//----------------------------------------------------------------------------- +// Purpose: invoke the function if there is one +//----------------------------------------------------------------------------- +void ConCommand::Dispatch(const CCommand& command) +{ + if (m_bUsingNewCommandCallback) + { + if (m_fnCommandCallback) + { + (*m_fnCommandCallback)(command); + return; + } + } + else if (m_bUsingCommandCallbackInterface) + { + if (m_pCommandCallback) + { + m_pCommandCallback->CommandCallback(command); + return; + } + } + else + { + if (m_fnCommandCallbackV1) + { + (*m_fnCommandCallbackV1)(); + return; + } + } + + // Command without callback!!! + AssertMsg(0, "Encountered ConCommand '%s' without a callback!\n", GetName()); +} + //----------------------------------------------------------------------------- // Purpose: create //----------------------------------------------------------------------------- @@ -126,7 +445,7 @@ ConVar* ConVar::StaticCreate(const char* pszName, const char* pszDefaultValue, pNewConVar->m_pszName = nullptr; pNewConVar->m_pszHelpString = nullptr; pNewConVar->m_pszUsageString = nullptr; - pNewConVar->s_pAccessor = nullptr; + pNewConVar->m_pAccessor = nullptr; pNewConVar->m_nFlags = FCVAR_NONE; pNewConVar->m_pNext = nullptr; diff --git a/src/tier1/cvar.cpp b/src/tier1/cvar.cpp index 83f07a89..81c2addd 100644 --- a/src/tier1/cvar.cpp +++ b/src/tier1/cvar.cpp @@ -675,11 +675,69 @@ int CCvarUtilities::CvarFindFlagsCompletionCallback(const char* partial, return values; } +/* +===================== +CON_Help_f + + Shows the colors and + description of each + context. +===================== +*/ +static void CON_Help_f() +{ + Msg(eDLL_T::COMMON, "Contexts:\n"); + + Msg(eDLL_T::SCRIPT_SERVER, " = Server DLL (Script)\n"); + Msg(eDLL_T::SCRIPT_CLIENT, " = Client DLL (Script)\n"); + Msg(eDLL_T::SCRIPT_UI, " = UI DLL (Script)\n"); + + Msg(eDLL_T::SERVER, " = Server DLL (Code)\n"); + Msg(eDLL_T::CLIENT, " = Client DLL (Code)\n"); + Msg(eDLL_T::UI, " = UI DLL (Code)\n"); + + Msg(eDLL_T::ENGINE, " = Engine DLL (Code)\n"); + Msg(eDLL_T::FS, " = FileSystem (Code)\n"); + Msg(eDLL_T::RTECH, " = PakLoad API (Code)\n"); + Msg(eDLL_T::MS, " = MaterialSystem (Code)\n"); + + Msg(eDLL_T::AUDIO, " = Audio DLL (Code)\n"); + Msg(eDLL_T::VIDEO, " = Video DLL (Code)\n"); + Msg(eDLL_T::NETCON, " = NetConsole (Code)\n"); +} + +static ConCommand con_help("con_help", CON_Help_f, "Shows the colors and description of each context", FCVAR_RELEASE); + /////////////////////////////////////////////////////////////////////////////// -CCvar* g_pCVar = nullptr; +CCvar* g_pCVar = CModule::GetExportedSymbol(CModule::GetProcessEnvironmentBlock()->ImageBaseAddress, "g_pCVar").RCast(); + + +static bool CVar_Connect(CCvar* thisptr, CreateInterfaceFn factory) +{ + CCvar__Connect(thisptr, factory); + + ConVar_InitShipped(); + ConVar_PurgeShipped(); + ConCommand_InitShipped(); + ConCommand_PurgeShipped(); + + ConVar_Register(); + + // CCvar::Connect() always returns true in the implementation of the engine + return true; +} + +static void CVar_Disconnect(CCvar* thisptr) +{ + ConVar_Unregister(); + CCvar__Disconnect(thisptr); +} /////////////////////////////////////////////////////////////////////////////// void VCVar::Detour(const bool bAttach) const { + DetourSetup(&CCvar__Connect, &CVar_Connect, bAttach); + DetourSetup(&CCvar__Disconnect, &CVar_Disconnect, bAttach); + DetourSetup(&v_ConVar_PrintDescription, &ConVar_PrintDescription, bAttach); }