Make spectators stay specs on map changed

Based on PRs to the upstream:
https://github.com/teeworlds/teeworlds/pull/2065
https://github.com/teeworlds/teeworlds/pull/2066

Co-authored-by: Jordy Ruiz <jordy.ruiz@univ-lille.fr>
Co-authored-by: heinrich5991 <heinrich5991@gmail.com>
This commit is contained in:
Alexander Akulich 2021-02-07 18:03:31 +03:00
parent 2790270abf
commit 6b49bf1388
5 changed files with 80 additions and 8 deletions

View file

@ -267,7 +267,22 @@ public:
virtual void OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) = 0;
virtual void OnClientConnected(int ClientID) = 0;
// Called before map reload, for any data that the game wants to
// persist to the next map.
//
// Has the size of the return value of `PersistentClientDataSize()`.
//
// Returns whether the game should be supplied with the data when the
// client connects for the next map.
virtual bool OnClientDataPersist(int ClientID, void *pData) = 0;
// Called when a client connects.
//
// If it is reconnecting to the game after a map change, the
// `pPersistentData` point is nonnull and contains the data the game
// previously stored.
virtual void OnClientConnected(int ClientID, void *pPersistentData) = 0;
virtual void OnClientEnter(int ClientID) = 0;
virtual void OnClientDrop(int ClientID, const char *pReason) = 0;
virtual void OnClientDirectInput(int ClientID, void *pInput) = 0;
@ -277,6 +292,8 @@ public:
virtual bool IsClientReady(int ClientID) const = 0;
virtual bool IsClientPlayer(int ClientID) const = 0;
virtual int PersistentClientDataSize() const = 0;
virtual CUuid GameUuid() const = 0;
virtual const char *GameType() const = 0;
virtual const char *Version() const = 0;

View file

@ -1465,7 +1465,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
}
else if(Msg == NETMSG_READY)
{
if((pPacket->m_Flags & NET_CHUNKFLAG_VITAL) != 0 && m_aClients[ClientID].m_State == CClient::STATE_CONNECTING)
if((pPacket->m_Flags & NET_CHUNKFLAG_VITAL) != 0 && (m_aClients[ClientID].m_State == CClient::STATE_CONNECTING))
{
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
@ -1473,8 +1473,15 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "player is ready. ClientID=%d addr=<{%s}> secure=%s", ClientID, aAddrStr, m_NetServer.HasSecurityToken(ClientID) ? "yes" : "no");
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf);
void *pPersistentData = 0;
if(m_aClients[ClientID].m_HasPersistentData)
{
pPersistentData = m_aClients[ClientID].m_pPersistentData;
m_aClients[ClientID].m_HasPersistentData = false;
}
m_aClients[ClientID].m_State = CClient::STATE_READY;
GameServer()->OnClientConnected(ClientID);
GameServer()->OnClientConnected(ClientID, pPersistentData);
}
SendConnectionReady(ClientID);
@ -2349,6 +2356,14 @@ int CServer::Run()
m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, SendRconLineAuthed, this);
{
int Size = GameServer()->PersistentClientDataSize();
for(auto &Client : m_aClients)
{
Client.m_pPersistentData = malloc(Size);
}
}
// load map
if(!LoadMap(g_Config.m_SvMap))
{
@ -2458,6 +2473,16 @@ int CServer::Run()
if(LoadMap(g_Config.m_SvMap))
{
// new map loaded
// ask the game to for the data it wants to persist past a map change
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(m_aClients[i].m_State == CClient::STATE_INGAME)
{
m_aClients[i].m_HasPersistentData = GameServer()->OnClientDataPersist(i, m_aClients[i].m_pPersistentData);
}
}
GameServer()->OnShutdown();
for(int ClientID = 0; ClientID < MAX_CLIENTS; ClientID++)
@ -2466,7 +2491,9 @@ int CServer::Run()
continue;
SendMap(ClientID);
bool HasPersistentData = m_aClients[ClientID].m_HasPersistentData;
m_aClients[ClientID].Reset();
m_aClients[ClientID].m_HasPersistentData = HasPersistentData;
m_aClients[ClientID].m_State = CClient::STATE_CONNECTING;
}

View file

@ -178,6 +178,9 @@ public:
const IConsole::CCommandInfo *m_pRconCmdToSend;
bool m_HasPersistentData;
void *m_pPersistentData;
void Reset();
// DDRace

View file

@ -1332,8 +1332,26 @@ void CGameContext::OnClientEnter(int ClientID)
}
}
void CGameContext::OnClientConnected(int ClientID)
bool CGameContext::OnClientDataPersist(int ClientID, void *pData)
{
CPersistentClientData *pPersistent = (CPersistentClientData *)pData;
if(!m_apPlayers[ClientID])
{
return false;
}
pPersistent->m_IsSpectator = m_apPlayers[ClientID]->GetTeam() == TEAM_SPECTATORS;
return true;
}
void CGameContext::OnClientConnected(int ClientID, void *pData)
{
CPersistentClientData *pPersistentData = (CPersistentClientData *)pData;
bool Spec = false;
if(pPersistentData)
{
Spec = pPersistentData->m_IsSpectator;
}
{
bool Empty = true;
for(auto &pPlayer : m_apPlayers)
@ -1351,7 +1369,7 @@ void CGameContext::OnClientConnected(int ClientID)
}
// Check which team the player should be on
const int StartTeam = g_Config.m_SvTournamentMode ? TEAM_SPECTATORS : m_pController->GetAutoTeam(ClientID);
const int StartTeam = (Spec || g_Config.m_SvTournamentMode) ? TEAM_SPECTATORS : m_pController->GetAutoTeam(ClientID);
if(!m_apPlayers[ClientID])
m_apPlayers[ClientID] = new(ClientID) CPlayer(this, ClientID, StartTeam);
@ -3350,7 +3368,7 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/)
{
for(int i = 0; i < g_Config.m_DbgDummies; i++)
{
OnClientConnected(MAX_CLIENTS - i - 1);
OnClientConnected(MAX_CLIENTS - i - 1, 0);
}
}
#endif
@ -3593,7 +3611,7 @@ bool CGameContext::IsClientReady(int ClientID) const
bool CGameContext::IsClientPlayer(int ClientID) const
{
return m_apPlayers[ClientID] && m_apPlayers[ClientID]->GetTeam() == TEAM_SPECTATORS ? false : true;
return m_apPlayers[ClientID] && m_apPlayers[ClientID]->GetTeam() != TEAM_SPECTATORS;
}
CUuid CGameContext::GameUuid() const { return m_GameUuid; }

View file

@ -123,6 +123,11 @@ class CGameContext : public IGameServer
bool m_Resetting;
struct CPersistentClientData
{
bool m_IsSpectator;
};
public:
IServer *Server() const { return m_pServer; }
CConfig *Config() { return m_pConfig; }
@ -246,7 +251,8 @@ public:
void CensorMessage(char *pCensoredMessage, const char *pMessage, int Size);
virtual void OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID);
virtual void OnClientConnected(int ClientID);
virtual bool OnClientDataPersist(int ClientID, void *pData);
virtual void OnClientConnected(int ClientID, void *pData);
virtual void OnClientEnter(int ClientID);
virtual void OnClientDrop(int ClientID, const char *pReason);
virtual void OnClientDirectInput(int ClientID, void *pInput);
@ -258,6 +264,7 @@ public:
virtual bool IsClientReady(int ClientID) const;
virtual bool IsClientPlayer(int ClientID) const;
virtual int PersistentClientDataSize() const { return sizeof(CPersistentClientData); }
virtual CUuid GameUuid() const;
virtual const char *GameType() const;