From ee2f625754ca9f01be6732550f16098c5afa704a Mon Sep 17 00:00:00 2001 From: oy Date: Thu, 10 Mar 2011 10:08:14 +0100 Subject: added extended spectator mode. Closes #28 --- src/game/server/entities/character.cpp | 2 +- src/game/server/gamecontext.cpp | 56 ++++++++++++++++++++++++---------- src/game/server/player.cpp | 39 ++++++++++++++++++----- src/game/server/player.h | 41 ++++++++++++++----------- 4 files changed, 95 insertions(+), 43 deletions(-) (limited to 'src/game/server') diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index ddd416d1..32a9523e 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -822,7 +822,7 @@ void CCharacter::Snap(int SnappingClient) pCharacter->m_Direction = m_Input.m_Direction; - if(m_pPlayer->GetCID() == SnappingClient) + if(m_pPlayer->GetCID() == SnappingClient || SnappingClient == -1 || m_pPlayer->GetCID() == GameServer()->m_apPlayers[SnappingClient]->m_SpectatorID) { pCharacter->m_Health = m_Health; pCharacter->m_Armor = m_Armor; diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 44d9b6fc..7f8a075f 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -389,7 +389,10 @@ void CGameContext::OnTick() for(int i = 0; i < MAX_CLIENTS; i++) { if(m_apPlayers[i]) + { m_apPlayers[i]->Tick(); + m_apPlayers[i]->PostTick(); + } } // update voting @@ -454,7 +457,7 @@ void CGameContext::OnTick() SendChat(-1, CGameContext::CHAT_ALL, "Vote passed"); if(m_apPlayers[m_VoteCreator]) - m_apPlayers[m_VoteCreator]->m_Last_VoteCall = 0; + m_apPlayers[m_VoteCreator]->m_LastVoteCall = 0; } else if(m_VoteEnforce == VOTE_ENFORCE_NO || time_get() > m_VoteCloseTime) { @@ -548,6 +551,13 @@ void CGameContext::OnClientDrop(int ClientID) (void)m_pController->CheckTeamBalance(); m_VoteUpdate = true; + + // update spectator modes + for(int i = 0; i < MAX_CLIENTS; ++i) + { + if(m_apPlayers[i] && m_apPlayers[i]->m_SpectatorID == ClientID) + m_apPlayers[i]->m_SpectatorID = SPEC_FREEVIEW; + } } void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) @@ -572,10 +582,10 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) else Team = CGameContext::CHAT_ALL; - if(g_Config.m_SvSpamprotection && pPlayer->m_Last_Chat && pPlayer->m_Last_Chat+Server()->TickSpeed() > Server()->Tick()) + if(g_Config.m_SvSpamprotection && pPlayer->m_LastChat && pPlayer->m_LastChat+Server()->TickSpeed() > Server()->Tick()) return; - pPlayer->m_Last_Chat = Server()->Tick(); + pPlayer->m_LastChat = Server()->Tick(); // check for invalid chars unsigned char *pMessage = (unsigned char *)pMsg->m_pMessage; @@ -590,11 +600,11 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) } else if(MsgID == NETMSGTYPE_CL_CALLVOTE) { - if(g_Config.m_SvSpamprotection && pPlayer->m_Last_VoteTry && pPlayer->m_Last_VoteTry+Server()->TickSpeed()*3 > Server()->Tick()) + if(g_Config.m_SvSpamprotection && pPlayer->m_LastVoteTry && pPlayer->m_LastVoteTry+Server()->TickSpeed()*3 > Server()->Tick()) return; int64 Now = Server()->Tick(); - pPlayer->m_Last_VoteTry = Now; + pPlayer->m_LastVoteTry = Now; if(pPlayer->GetTeam() == TEAM_SPECTATORS) { SendChatTarget(ClientID, "Spectators aren't allowed to start a vote."); @@ -607,8 +617,8 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) return; } - int Timeleft = pPlayer->m_Last_VoteCall + Server()->TickSpeed()*60 - Now; - if(pPlayer->m_Last_VoteCall && Timeleft > 0) + int Timeleft = pPlayer->m_LastVoteCall + Server()->TickSpeed()*60 - Now; + if(pPlayer->m_LastVoteCall && Timeleft > 0) { char aChatmsg[512] = {0}; str_format(aChatmsg, sizeof(aChatmsg), "You must wait %d seconds before making another vote", (Timeleft/Server()->TickSpeed())+1); @@ -715,7 +725,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) pPlayer->m_Vote = 1; pPlayer->m_VotePos = m_VotePos = 1; m_VoteCreator = ClientID; - pPlayer->m_Last_VoteCall = Now; + pPlayer->m_LastVoteCall = Now; } } else if(MsgID == NETMSGTYPE_CL_VOTE) @@ -738,7 +748,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) { CNetMsg_Cl_SetTeam *pMsg = (CNetMsg_Cl_SetTeam *)pRawMsg; - if(pPlayer->GetTeam() == pMsg->m_Team || (g_Config.m_SvSpamprotection && pPlayer->m_Last_SetTeam && pPlayer->m_Last_SetTeam+Server()->TickSpeed()*3 > Server()->Tick())) + if(pPlayer->GetTeam() == pMsg->m_Team || (g_Config.m_SvSpamprotection && pPlayer->m_LastSetTeam && pPlayer->m_LastSetTeam+Server()->TickSpeed()*3 > Server()->Tick())) return; // Switch team on given client and kill/respawn him @@ -746,7 +756,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) { if(m_pController->CanChangeTeam(pPlayer, pMsg->m_Team)) { - pPlayer->m_Last_SetTeam = Server()->Tick(); + pPlayer->m_LastSetTeam = Server()->Tick(); if(pPlayer->GetTeam() == TEAM_SPECTATORS || pMsg->m_Team == TEAM_SPECTATORS) m_VoteUpdate = true; pPlayer->SetTeam(pMsg->m_Team); @@ -762,14 +772,28 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) SendBroadcast(aBuf, ClientID); } } + else if (MsgID == NETMSGTYPE_CL_SETSPECTATORMODE && !m_World.m_Paused) + { + CNetMsg_Cl_SetSpectatorMode *pMsg = (CNetMsg_Cl_SetSpectatorMode *)pRawMsg; + + if(pPlayer->GetTeam() != TEAM_SPECTATORS || pPlayer->m_SpectatorID == pMsg->m_SpectatorID || ClientID == pMsg->m_SpectatorID || + (g_Config.m_SvSpamprotection && pPlayer->m_LastSetSpectatorMode && pPlayer->m_LastSetSpectatorMode+Server()->TickSpeed()*3 > Server()->Tick())) + return; + + pPlayer->m_LastSetSpectatorMode = Server()->Tick(); + if(pMsg->m_SpectatorID != SPEC_FREEVIEW && !m_apPlayers[pMsg->m_SpectatorID]) + SendChatTarget(ClientID, "Invalid spectator id used"); + else + pPlayer->m_SpectatorID = pMsg->m_SpectatorID; + } else if (MsgID == NETMSGTYPE_CL_CHANGEINFO || MsgID == NETMSGTYPE_CL_STARTINFO) { CNetMsg_Cl_ChangeInfo *pMsg = (CNetMsg_Cl_ChangeInfo *)pRawMsg; - if(g_Config.m_SvSpamprotection && pPlayer->m_Last_ChangeInfo && pPlayer->m_Last_ChangeInfo+Server()->TickSpeed()*5 > Server()->Tick()) + if(g_Config.m_SvSpamprotection && pPlayer->m_LastChangeInfo && pPlayer->m_LastChangeInfo+Server()->TickSpeed()*5 > Server()->Tick()) return; - pPlayer->m_Last_ChangeInfo = Server()->Tick(); + pPlayer->m_LastChangeInfo = Server()->Tick(); pPlayer->m_TeeInfos.m_UseCustomColor = pMsg->m_UseCustomColor; pPlayer->m_TeeInfos.m_ColorBody = pMsg->m_ColorBody; @@ -818,19 +842,19 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) { CNetMsg_Cl_Emoticon *pMsg = (CNetMsg_Cl_Emoticon *)pRawMsg; - if(g_Config.m_SvSpamprotection && pPlayer->m_Last_Emote && pPlayer->m_Last_Emote+Server()->TickSpeed()*3 > Server()->Tick()) + if(g_Config.m_SvSpamprotection && pPlayer->m_LastEmote && pPlayer->m_LastEmote+Server()->TickSpeed()*3 > Server()->Tick()) return; - pPlayer->m_Last_Emote = Server()->Tick(); + pPlayer->m_LastEmote = Server()->Tick(); SendEmoticon(ClientID, pMsg->m_Emoticon); } else if (MsgID == NETMSGTYPE_CL_KILL && !m_World.m_Paused) { - if(pPlayer->m_Last_Kill && pPlayer->m_Last_Kill+Server()->TickSpeed()*3 > Server()->Tick()) + if(pPlayer->m_LastKill && pPlayer->m_LastKill+Server()->TickSpeed()*3 > Server()->Tick()) return; - pPlayer->m_Last_Kill = Server()->Tick(); + pPlayer->m_LastKill = Server()->Tick(); pPlayer->KillCharacter(WEAPON_SELF); pPlayer->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()*3; } diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 573d996d..7d2f4ad9 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -18,6 +18,7 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team) Character = 0; this->m_ClientID = ClientID; m_Team = GameServer()->m_pController->ClampTeam(Team); + m_SpectatorID = SPEC_FREEVIEW; m_LastActionTick = Server()->Tick(); } @@ -77,6 +78,23 @@ void CPlayer::Tick() TryRespawn(); } +void CPlayer::PostTick() +{ + // update latency value + if(m_PlayerFlags&PLAYERFLAG_SCOREBOARD) + { + for(int i = 0; i < MAX_CLIENTS; ++i) + { + if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS) + m_aActLatency[i] = GameServer()->m_apPlayers[i]->m_Latency.m_Min; + } + } + + // update view pos for spectators + if(m_Team == TEAM_SPECTATORS && m_SpectatorID != SPEC_FREEVIEW && GameServer()->m_apPlayers[m_SpectatorID]) + m_ViewPos = GameServer()->m_apPlayers[m_SpectatorID]->m_ViewPos; +} + void CPlayer::Snap(int SnappingClient) { #ifdef CONF_DEBUG @@ -99,12 +117,6 @@ void CPlayer::Snap(int SnappingClient) if(!pPlayerInfo) return; - // update latency value - if(SnappingClient != -1 && m_Team != -1 && GameServer()->m_apPlayers[SnappingClient]->m_PlayerFlags&PLAYERFLAG_SCOREBOARD) - { - GameServer()->m_apPlayers[SnappingClient]->m_aActLatency[m_ClientID] = m_Latency.m_Min; - } - pPlayerInfo->m_Latency = SnappingClient == -1 ? m_Latency.m_Min : GameServer()->m_apPlayers[SnappingClient]->m_aActLatency[m_ClientID]; pPlayerInfo->m_Local = 0; pPlayerInfo->m_ClientID = m_ClientID; @@ -112,7 +124,18 @@ void CPlayer::Snap(int SnappingClient) pPlayerInfo->m_Team = m_Team; if(m_ClientID == SnappingClient) - pPlayerInfo->m_Local = 1; + pPlayerInfo->m_Local = 1; + + if(m_ClientID == SnappingClient && m_Team == TEAM_SPECTATORS && m_SpectatorID != SPEC_FREEVIEW) + { + CNetObj_SpectatorInfo *pSpectatorInfo = static_cast(Server()->SnapNewItem(NETOBJTYPE_SPECTATORINFO, m_ClientID, sizeof(CNetObj_SpectatorInfo))); + if(!pSpectatorInfo) + return; + + pSpectatorInfo->m_SpectatorID = m_SpectatorID; + pSpectatorInfo->m_X = m_ViewPos.x; + pSpectatorInfo->m_Y = m_ViewPos.y; + } } void CPlayer::OnDisconnect() @@ -146,7 +169,7 @@ void CPlayer::OnDirectInput(CNetObj_PlayerInput *NewInput) if(!Character && m_Team != TEAM_SPECTATORS && (NewInput->m_Fire&1)) m_Spawning = true; - if(!Character && m_Team == TEAM_SPECTATORS) + if(!Character && m_Team == TEAM_SPECTATORS && m_SpectatorID == SPEC_FREEVIEW) m_ViewPos = vec2(NewInput->m_TargetX, NewInput->m_TargetY); // check for activity diff --git a/src/game/server/player.h b/src/game/server/player.h index f4d82d24..c638fae8 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -25,6 +25,7 @@ public: int GetCID() const { return m_ClientID; }; void Tick(); + void PostTick(); void Snap(int SnappingClient); void OnDirectInput(CNetObj_PlayerInput *NewInput); @@ -43,18 +44,22 @@ public: // used for snapping to just update latency if the scoreboard is active int m_aActLatency[MAX_CLIENTS]; + + // used for spectator mode + int m_SpectatorID; // int m_Vote; int m_VotePos; // - int m_Last_VoteCall; - int m_Last_VoteTry; - int m_Last_Chat; - int m_Last_SetTeam; - int m_Last_ChangeInfo; - int m_Last_Emote; - int m_Last_Kill; + int m_LastVoteCall; + int m_LastVoteTry; + int m_LastChat; + int m_LastSetTeam; + int m_LastSetSpectatorMode; + int m_LastChangeInfo; + int m_LastEmote; + int m_LastKill; // TODO: clean this up struct @@ -76,6 +81,17 @@ public: int m_TargetX; int m_TargetY; } m_LatestActivity; + + // network latency calculations + struct + { + int m_Accum; + int m_AccumMin; + int m_AccumMax; + int m_Avg; + int m_Min; + int m_Max; + } m_Latency; private: CCharacter *Character; @@ -88,17 +104,6 @@ private: bool m_Spawning; int m_ClientID; int m_Team; - - // network latency calculations - struct - { - int m_Accum; - int m_AccumMin; - int m_AccumMax; - int m_Avg; - int m_Min; - int m_Max; - } m_Latency; }; #endif -- cgit 1.4.1