From 0d8a0d3b1d158bc24ac5925c39445eafe28c4907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 12 Nov 2023 15:21:47 +0100 Subject: [PATCH] Dynamically connect/disconnect debug dummies, cleanup Call expected server callback functions to simulate clients dynamically connecting and disconnecting when changing the `dbg_dummies` variable. This makes the debug dummies more useful for debugging. Previously, the debug dummies were considered invalid clients, whereas they are now considered to be ingame, so they should behave mostly like real clients being connected to the server. The debug dummies also have correct client names now, e.g. "Debug dummy 42". The game server code is cleaned up by moving all special handling for debug dummies to the engine server function `CServer::UpdateDebugDummies`. The left/right direction inputs for debug dummies are now properly added to the client input array, so their input handling should be consistent with normal clients, which fixes some inconsistent prediction with debug dummies. --- src/engine/server/server.cpp | 45 ++++++++++++++++++++++++++++++ src/engine/server/server.h | 5 ++++ src/game/server/gamecontext.cpp | 33 ---------------------- src/game/server/gamecontroller.cpp | 7 ----- src/game/server/player.cpp | 23 ++++----------- src/game/variables.h | 4 +-- 6 files changed, 57 insertions(+), 60 deletions(-) diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 4ba4a5807..0773ed7a1 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -2615,6 +2615,44 @@ int CServer::LoadMap(const char *pMapName) return 1; } +#ifdef CONF_DEBUG +void CServer::UpdateDebugDummies(bool ForceDisconnect) +{ + if(m_PreviousDebugDummies == g_Config.m_DbgDummies && !ForceDisconnect) + return; + + for(int DummyIndex = 0; DummyIndex < maximum(m_PreviousDebugDummies, g_Config.m_DbgDummies); ++DummyIndex) + { + const bool AddDummy = !ForceDisconnect && DummyIndex < g_Config.m_DbgDummies; + const int ClientID = MAX_CLIENTS - DummyIndex - 1; + if(AddDummy && m_aClients[ClientID].m_State == CClient::STATE_EMPTY) + { + NewClientCallback(ClientID, this, false); + GameServer()->OnClientConnected(ClientID, nullptr); + m_aClients[ClientID].m_State = CClient::STATE_INGAME; + str_format(m_aClients[ClientID].m_aName, sizeof(m_aClients[ClientID].m_aName), "Debug dummy %d", DummyIndex + 1); + GameServer()->OnClientEnter(ClientID); + } + else if(!AddDummy && m_aClients[ClientID].m_State == CClient::STATE_INGAME) + { + DelClientCallback(ClientID, "Dropping debug dummy", this); + } + + if(AddDummy && m_aClients[ClientID].m_State == CClient::STATE_INGAME) + { + CNetObj_PlayerInput Input = {0}; + Input.m_Direction = (ClientID & 1) ? -1 : 1; + m_aClients[ClientID].m_aInputs[0].m_GameTick = Tick() + 1; + mem_copy(m_aClients[ClientID].m_aInputs[0].m_aData, &Input, minimum(sizeof(Input), sizeof(m_aClients[ClientID].m_aInputs[0].m_aData))); + m_aClients[ClientID].m_LatestInput = m_aClients[ClientID].m_aInputs[0]; + m_aClients[ClientID].m_CurrentInput = 0; + } + } + + m_PreviousDebugDummies = ForceDisconnect ? 0 : g_Config.m_DbgDummies; +} +#endif + int CServer::Run() { if(m_RunServer == UNINITIALIZED) @@ -2762,6 +2800,9 @@ int CServer::Run() } } +#ifdef CONF_DEBUG + UpdateDebugDummies(true); +#endif GameServer()->OnShutdown(m_pPersistentData); for(int ClientID = 0; ClientID < MAX_CLIENTS; ClientID++) @@ -2851,6 +2892,10 @@ int CServer::Run() { GameServer()->OnPreTickTeehistorian(); +#ifdef CONF_DEBUG + UpdateDebugDummies(false); +#endif + for(int c = 0; c < MAX_CLIENTS; c++) { if(m_aClients[c].m_State != CClient::STATE_INGAME) diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 888834555..16d442721 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -122,6 +122,11 @@ class CServer : public IServer class CDbConnectionPool *m_pConnectionPool; +#ifdef CONF_DEBUG + int m_PreviousDebugDummies = 0; + void UpdateDebugDummies(bool ForceDisconnect); +#endif + public: class IGameServer *GameServer() { return m_pGameServer; } class CConfig *Config() { return m_pConfig; } diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 8b4b5e5de..154d12c90 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -1195,21 +1195,6 @@ void CGameContext::OnTick() m_SqlRandomMapResult = nullptr; } -#ifdef CONF_DEBUG - if(g_Config.m_DbgDummies) - { - for(int i = 0; i < g_Config.m_DbgDummies; i++) - { - if(m_apPlayers[MAX_CLIENTS - i - 1]) - { - CNetObj_PlayerInput Input = {0}; - Input.m_Direction = (i & 1) ? -1 : 1; - m_apPlayers[MAX_CLIENTS - i - 1]->OnPredictedInput(&Input); - } - } - } -#endif - // Record player position at the end of the tick if(m_TeeHistorianActive) { @@ -1615,14 +1600,6 @@ void CGameContext::OnClientConnected(int ClientID, void *pData) m_apPlayers[ClientID]->SetInitialAfk(Afk); NextUniqueClientID += 1; -#ifdef CONF_DEBUG - if(g_Config.m_DbgDummies) - { - if(ClientID >= MAX_CLIENTS - g_Config.m_DbgDummies) - return; - } -#endif - SendMotd(ClientID); SendSettings(ClientID); @@ -3702,16 +3679,6 @@ void CGameContext::OnInit(const void *pPersistentData) Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "git-revision", GIT_SHORTREV_HASH); m_pAntibot->RoundStart(this); - -#ifdef CONF_DEBUG - if(g_Config.m_DbgDummies) - { - for(int i = 0; i < g_Config.m_DbgDummies; i++) - { - OnClientConnected(MAX_CLIENTS - i - 1, 0); - } - } -#endif } void CGameContext::CreateAllEntities(bool Initial) diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp index 10badd466..93638f9cf 100644 --- a/src/game/server/gamecontroller.cpp +++ b/src/game/server/gamecontroller.cpp @@ -53,13 +53,6 @@ void IGameController::DoActivityCheck() for(int i = 0; i < MAX_CLIENTS; ++i) { -#ifdef CONF_DEBUG - if(g_Config.m_DbgDummies) - { - if(i >= MAX_CLIENTS - g_Config.m_DbgDummies) - break; - } -#endif if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS && Server()->GetAuthedState(i) == AUTHED_NO) { if(Server()->Tick() > GameServer()->m_apPlayers[i]->m_LastActionTick + g_Config.m_SvInactiveKickTime * Server()->TickSpeed() * 60) diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 25c72aa0e..4007ff3af 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -169,14 +169,7 @@ void CPlayer::Tick() m_ScoreFinishResult = nullptr; } - bool ClientIngame = Server()->ClientIngame(m_ClientID); -#ifdef CONF_DEBUG - if(g_Config.m_DbgDummies && m_ClientID >= MAX_CLIENTS - g_Config.m_DbgDummies) - { - ClientIngame = true; - } -#endif - if(!ClientIngame) + if(!Server()->ClientIngame(m_ClientID)) return; if(m_ChatScore > 0) @@ -302,11 +295,8 @@ void CPlayer::PostTick() void CPlayer::PostPostTick() { -#ifdef CONF_DEBUG - if(!g_Config.m_DbgDummies || m_ClientID < MAX_CLIENTS - g_Config.m_DbgDummies) -#endif - if(!Server()->ClientIngame(m_ClientID)) - return; + if(!Server()->ClientIngame(m_ClientID)) + return; if(!GameServer()->m_World.m_Paused && !m_pCharacter && m_Spawning && m_WeakHookSpawn) TryRespawn(); @@ -314,11 +304,8 @@ void CPlayer::PostPostTick() void CPlayer::Snap(int SnappingClient) { -#ifdef CONF_DEBUG - if(!g_Config.m_DbgDummies || m_ClientID < MAX_CLIENTS - g_Config.m_DbgDummies) -#endif - if(!Server()->ClientIngame(m_ClientID)) - return; + if(!Server()->ClientIngame(m_ClientID)) + return; int id = m_ClientID; if(!Server()->Translate(id, SnappingClient)) diff --git a/src/game/variables.h b/src/game/variables.h index 93320fbad..30bd7b8ea 100644 --- a/src/game/variables.h +++ b/src/game/variables.h @@ -221,8 +221,8 @@ MACRO_CONFIG_INT(ClVideoX264Crf, cl_video_crf, 18, 0, 51, CFGFLAG_CLIENT | CFGFL MACRO_CONFIG_INT(ClVideoX264Preset, cl_video_preset, 5, 0, 9, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Set preset when encode video with libx264, default is 5 (medium), 0 is ultrafast, 9 is placebo (the slowest, not recommend)") // debug -#ifdef CONF_DEBUG // this one can crash the server if not used correctly -MACRO_CONFIG_INT(DbgDummies, dbg_dummies, 0, 0, MAX_CLIENTS, CFGFLAG_SERVER, "(Debug build only)") +#ifdef CONF_DEBUG +MACRO_CONFIG_INT(DbgDummies, dbg_dummies, 0, 0, MAX_CLIENTS, CFGFLAG_SERVER, "Add debug dummies to server (Debug build only)") #endif MACRO_CONFIG_INT(DbgTuning, dbg_tuning, 0, 0, 2, CFGFLAG_CLIENT, "Display information about the tuning parameters that affect the own player (0 = off, 1 = show changed, 2 = show all)")