openclonk/src/network/C4Network2Players.cpp

504 lines
17 KiB
C++
Raw Permalink Normal View History

2009-05-08 13:28:41 +00:00
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2004-2009, RedWolf Design GmbH, http://www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
2009-05-08 13:28:41 +00:00
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
2009-05-08 13:28:41 +00:00
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
2009-05-08 13:28:41 +00:00
*/
// NET2 network player management
// see header for some additional information
// 2do: Handle client joins after game go but before runtime join (Frame 0)?
// Those will not receive a player info list right in time
#include "C4Include.h"
#include "network/C4Network2Players.h"
#include "control/C4Control.h"
#include "control/C4GameControl.h"
#include "control/C4PlayerInfo.h"
#include "control/C4RoundResults.h"
#include "gui/C4GameLobby.h"
#include "network/C4Network2.h"
2009-05-08 13:28:41 +00:00
// *** C4Network2Players
C4Network2Players::C4Network2Players() : rInfoList(Game.Parameters.PlayerInfos)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// ctor - init rInfoList-ref to only
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::Init()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// caution: In this call, only local players are joined
// remote players may have been added already for runtime joins
// not in replay
if (Game.C4S.Head.Replay) return;
// network only
2009-06-05 15:19:46 +00:00
assert(::Network.isEnabled());
2009-05-08 13:28:41 +00:00
// must init before game is running
assert(!Game.IsRunning);
2009-06-05 15:19:46 +00:00
if (::Network.isHost())
{
// host: Rejoin script players from savegame before joining local players so team distribution is done correctly
// But prepare empty host list before recreation
JoinLocalPlayer("", true);
2009-05-08 13:28:41 +00:00
Game.PlayerInfos.CreateRestoreInfosForJoinedScriptPlayers(Game.RestorePlayerInfos);
JoinLocalPlayer(Game.PlayerFilenames, false);
}
else
{
// Client: join the local player(s)
JoinLocalPlayer(Game.PlayerFilenames, true);
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::Clear()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// nothing...
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Network2Players::JoinLocalPlayer(const char *szLocalPlayerFilename, bool initial)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// ignore in replay
// shouldn't even come here though
assert(!Game.C4S.Head.Replay);
if (Game.C4S.Head.Replay) return false;
// if observing: don't try
if (Game.Clients.getLocal()->isObserver()) return false;
2009-05-08 13:28:41 +00:00
// network only
2009-06-05 15:19:46 +00:00
assert(::Network.isEnabled());
2009-05-08 13:28:41 +00:00
// create join info packet
C4ClientPlayerInfos JoinInfo(szLocalPlayerFilename, !initial);
2009-05-08 13:28:41 +00:00
// league game: get authentication for players
if (Game.Parameters.isLeague())
2010-03-28 18:58:01 +00:00
for (int i = 0; i < JoinInfo.GetPlayerCount(); i++)
{
2009-05-08 13:28:41 +00:00
C4PlayerInfo *pInfo = JoinInfo.GetPlayerInfo(i);
2010-03-28 18:58:01 +00:00
if (!::Network.LeaguePlrAuth(pInfo))
{
2009-05-08 13:28:41 +00:00
JoinInfo.RemoveIndexedInfo(i);
i--;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// host or client?
2009-06-05 15:19:46 +00:00
if (::Network.isHost())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// error joining players? Zero players is OK for initial packet; marks host as observer
if (!initial && !JoinInfo.GetPlayerCount()) return false;
2009-05-08 13:28:41 +00:00
// handle it as a direct request
HandlePlayerInfoUpdRequest(&JoinInfo, true);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// clients request initial joins at host only
// create player info for local player joins
C4PacketPlayerInfoUpdRequest JoinRequest(JoinInfo);
// any players to join? Zero players is OK for initial packet; marks client as observer
// it's also necessary to send the empty player info packet, so the host will answer
// with infos of all other clients
if (!initial && !JoinRequest.Info.GetPlayerCount()) return false;
2009-06-05 15:19:46 +00:00
::Network.Clients.SendMsgToHost(MkC4NetIOPacket(PID_PlayerInfoUpdReq, JoinRequest));
// request activation
2010-03-28 18:58:01 +00:00
if (JoinRequest.Info.GetPlayerCount() && !Game.Clients.getLocal()->isActivated())
::Network.RequestActivate();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// done, success
return true;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::RequestPlayerInfoUpdate(const class C4ClientPlayerInfos &rRequest)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// network only
2009-06-05 15:19:46 +00:00
assert(::Network.isEnabled());
2009-05-08 13:28:41 +00:00
// host or client?
2009-06-05 15:19:46 +00:00
if (::Network.isHost())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// host processes directly
HandlePlayerInfoUpdRequest(&rRequest, true);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// client sends request to host
C4PacketPlayerInfoUpdRequest UpdateRequest(rRequest);
2009-06-05 15:19:46 +00:00
::Network.Clients.SendMsgToHost(MkC4NetIOPacket(PID_PlayerInfoUpdReq, UpdateRequest));
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::HandlePlayerInfoUpdRequest(const class C4ClientPlayerInfos *pInfoPacket, bool fByHost)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// network host only
2009-06-05 15:19:46 +00:00
assert(::Network.isEnabled());
assert(::Network.isHost());
2009-05-08 13:28:41 +00:00
// copy client infos (need to be adjusted)
C4ClientPlayerInfos OwnInfoPacket(*pInfoPacket);
// safety: check any duplicate, unjoined players first
// check those with unassigned IDs only, so update packets won't be rejected by this
if (!OwnInfoPacket.IsInitialPacket())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4ClientPlayerInfos *pExistingClientInfo = rInfoList.GetInfoByClientID(OwnInfoPacket.GetClientID());
if (pExistingClientInfo)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int iCnt=OwnInfoPacket.GetPlayerCount(); C4PlayerInfo *pPlrInfo;
C4Network2Res *pRes;
2010-01-25 04:00:59 +00:00
while (iCnt--) if ((pPlrInfo=OwnInfoPacket.GetPlayerInfo(iCnt)))
2010-03-28 18:58:01 +00:00
if (!pPlrInfo->GetID()) if ((pRes = pPlrInfo->GetRes()))
if (pExistingClientInfo->GetPlayerInfoByRes(pRes->getResID()))
{
// double join: simply deny without message
2009-05-08 13:28:41 +00:00
#ifdef _DEBUG
2010-03-28 18:58:01 +00:00
Log("Network: Duplicate player join rejected!");
2009-05-08 13:28:41 +00:00
#endif
2010-03-28 18:58:01 +00:00
OwnInfoPacket.RemoveIndexedInfo(iCnt);
}
}
2009-05-08 13:28:41 +00:00
if (!OwnInfoPacket.GetPlayerCount())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// player join request without players: probably all removed because doubled
#ifdef _DEBUG
Log("Network: Empty player join request ignored!");
#endif
return;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// assign player IDs
if (!rInfoList.AssignPlayerIDs(&OwnInfoPacket) && OwnInfoPacket.IsAddPacket())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// no players could be joined in an add request: probably because the maximum player limit has been reached
return;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// check doubled savegame player usage
UpdateSavegameAssignments(&OwnInfoPacket);
// update teams
rInfoList.AssignTeams(&OwnInfoPacket, fByHost);
// update any other player colors and names
// this may only change colors and names of all unjoined players (which is all players in lobby mode)
// any affected players will get an updated-flag
rInfoList.UpdatePlayerAttributes(&OwnInfoPacket, true);
// league score gains may now be different
rInfoList.ResetLeagueProjectedGain(true);
int32_t iPlrInfo = 0;
C4PlayerInfo *pPlrInfo;
while ((pPlrInfo = OwnInfoPacket.GetPlayerInfo(iPlrInfo++))) pPlrInfo->ResetLeagueProjectedGain();
2009-05-08 13:28:41 +00:00
if (Game.Parameters.isLeague())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check league authentication for new players
2010-03-28 18:58:01 +00:00
for (int i = 0; i < OwnInfoPacket.GetPlayerCount(); i++)
{
2010-03-28 18:58:01 +00:00
if (!rInfoList.GetPlayerInfoByID(OwnInfoPacket.GetPlayerInfo(i)->GetID()))
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
C4PlayerInfo *pInfo = OwnInfoPacket.GetPlayerInfo(i);
// remove normal (non-script) player infos without authentication or when not in the lobby
if (pInfo->GetType() != C4PT_Script && (!::Network.isLobbyActive() || !::Network.LeaguePlrAuthCheck(pInfo)))
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
OwnInfoPacket.RemoveIndexedInfo(i);
i--;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
else
// always reset authentication ID after check - it's not needed anymore
pInfo->SetAuthID("");
2009-05-08 13:28:41 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// send updates to all other clients and reset update flags
SendUpdatedPlayers();
// finally, add new player join as direct input
// this will add the player infos directly on host side (DirectExec as a subcall),
// so future player join request will take the other joined clients into consideration
// when assigning player colors, etc.; it will also start resource loading
// in running mode, this call will also put the actual player joins into the queue
::Control.DoInput(CID_PlrInfo, new C4ControlPlayerInfo(OwnInfoPacket), CDT_Direct);
2009-05-08 13:28:41 +00:00
// notify lobby of updates
2009-06-05 15:19:46 +00:00
C4GameLobby::MainDlg *pLobby = ::Network.GetLobby();
2009-05-08 13:28:41 +00:00
if (pLobby) pLobby->OnPlayersChange();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::HandlePlayerInfo(const class C4ClientPlayerInfos &rInfoPacket)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// network only
2009-06-05 15:19:46 +00:00
assert(::Network.isEnabled());
2009-05-08 13:28:41 +00:00
// copy client player infos out of packet to be used in local list
C4ClientPlayerInfos *pClientInfo = new C4ClientPlayerInfos(rInfoPacket);
// add client info to local player info list - eventually deleting pClientInfo and
// returning a pointer to the new info structure when multiple player infos are merged
// may also replace existing info, if this is an update-call
pClientInfo = rInfoList.AddInfo(pClientInfo);
// make sure team list reflects teams set in player infos
Game.Teams.RecheckPlayers();
Game.Teams.RecheckTeams(); // recheck random teams - if a player left, teams may need to be rebalanced
2009-05-08 13:28:41 +00:00
// make sure resources are loaded for those players
rInfoList.LoadResources();
// get associated client - note that pClientInfo might be nullptr for empty packets that got discarded
2009-05-08 13:28:41 +00:00
if (pClientInfo)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
const C4Client *pClient = Game.Clients.getClientByID(pClientInfo->GetClientID());
// host, game running and client active already?
2009-06-05 15:19:46 +00:00
if (::Network.isHost() && ::Network.isRunning() && pClient && pClient->isActivated())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// then join the players immediately
JoinUnjoinedPlayersInControlQueue(pClientInfo);
}
2010-03-28 18:58:01 +00:00
}
// adding the player may have invalidated other players (through team settings). Send them.
SendUpdatedPlayers();
2009-05-08 13:28:41 +00:00
// lobby: update players
2009-06-05 15:19:46 +00:00
C4GameLobby::MainDlg *pLobby = ::Network.GetLobby();
2009-05-08 13:28:41 +00:00
if (pLobby) pLobby->OnPlayersChange();
// invalidate reference
2009-06-05 15:19:46 +00:00
::Network.InvalidateReference();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::SendUpdatedPlayers()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check all clients for update
C4ClientPlayerInfos *pUpdInfo; int i=0;
2010-01-25 04:00:59 +00:00
while ((pUpdInfo = rInfoList.GetIndexedInfo(i++)))
2009-05-08 13:28:41 +00:00
if (pUpdInfo->IsUpdated())
2010-03-28 18:58:01 +00:00
{
pUpdInfo->ResetUpdated();
2009-05-08 13:28:41 +00:00
C4ControlPlayerInfo *pkSend = new C4ControlPlayerInfo(*pUpdInfo);
// send info to all
2009-06-15 22:06:37 +00:00
::Control.DoInput(CID_PlrInfo, pkSend, CDT_Direct);
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::UpdateSavegameAssignments(C4ClientPlayerInfos *pNewInfo)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
if (!pNewInfo) return;
// check all joins of new info; backwards so they can be deleted
C4PlayerInfo *pInfo, *pInfo2, *pSaveInfo; int i=pNewInfo->GetPlayerCount(), j, id;
2010-01-25 04:00:59 +00:00
while (i--) if ((pInfo = pNewInfo->GetPlayerInfo(i)))
2010-03-28 18:58:01 +00:00
if ((id=pInfo->GetAssociatedSavegamePlayerID()))
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
// check for non-existant savegame players
if (!(pSaveInfo=Game.RestorePlayerInfos.GetPlayerInfoByID(id)))
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
pInfo->SetAssociatedSavegamePlayer(id=0);
pNewInfo->SetUpdated();
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
// check for duplicates (can't really occur...)
if (id)
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
j=i;
while ((pInfo2 = pNewInfo->GetPlayerInfo(++j)))
if (pInfo2->GetAssociatedSavegamePlayerID() == id)
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
// fix it by resetting the savegame info
pInfo->SetAssociatedSavegamePlayer(id=0);
pNewInfo->SetUpdated(); break;
2009-05-08 13:28:41 +00:00
}
}
2010-03-28 18:58:01 +00:00
// check against all infos of other clients
C4ClientPlayerInfos *pkClientInfo; int k=0;
while ((pkClientInfo = rInfoList.GetIndexedInfo(k++)) && id)
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
// if it's not an add packet, don't check own client twice
if (pkClientInfo->GetClientID() == pNewInfo->GetClientID() && !(pNewInfo->IsAddPacket()))
continue;
// check against all players
j=0;
while ((pInfo2 = pkClientInfo->GetPlayerInfo(j++)))
if (pInfo2->GetAssociatedSavegamePlayerID() == id)
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
// fix it by resetting the savegame info
pInfo->SetAssociatedSavegamePlayer(id=0);
pNewInfo->SetUpdated(); break;
2009-05-08 13:28:41 +00:00
}
}
2010-03-28 18:58:01 +00:00
// if the player joined just for the savegame assignment, and that failed, delete it
if (!id && pInfo->IsJoinForSavegameOnly())
pNewInfo->RemoveIndexedInfo(i);
// prev info
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::ResetUpdatedPlayers()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// mark all client packets as up-to-date
C4ClientPlayerInfos *pUpdInfo; int i=0;
2010-01-25 04:00:59 +00:00
while ((pUpdInfo = rInfoList.GetIndexedInfo(i++))) pUpdInfo->ResetUpdated();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::JoinUnjoinedPlayersInControlQueue(C4ClientPlayerInfos *pNewPacket)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// only host may join any players to the queue
2009-06-05 15:19:46 +00:00
assert(::Network.isHost());
2009-05-08 13:28:41 +00:00
// check all players
int i=0; C4PlayerInfo *pInfo;
2010-01-25 04:00:59 +00:00
while ((pInfo = pNewPacket->GetPlayerInfo(i++)))
2009-05-08 13:28:41 +00:00
// not yet joined and no savegame assignment?
if (!pInfo->HasJoinIssued()) if (!pInfo->GetAssociatedSavegamePlayerID())
{
2010-03-28 18:58:01 +00:00
// join will be marked when queue is executed (C4Player::Join)
// but better mark join now already to prevent permanent sending overkill
pInfo->SetJoinIssued();
// do so!
C4Network2Res *pPlrRes = pInfo->GetRes();
C4Network2Client *pClient = ::Network.Clients.GetClientByID(pNewPacket->GetClientID());
if (!pPlrRes || (!pClient && pNewPacket->GetClientID() != ::Control.ClientID()))
if (pInfo->GetType() != C4PT_Script)
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
// failure: Non-script players must have a res to join from!
const char *szPlrName = pInfo->GetName(); if (!szPlrName) szPlrName="???";
LogF("Network: C4Network2Players::JoinUnjoinedPlayersInControlQueue failed to join player %s!", szPlrName);
continue;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
if (pPlrRes)
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
// join with resource
Game.Input.Add(CID_JoinPlr,
new C4ControlJoinPlayer(pPlrRes->getFile(), pNewPacket->GetClientID(), pInfo->GetID(), pPlrRes->getCore()));
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
else
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
// join without resource (script player)
Game.Input.Add(CID_JoinPlr,
new C4ControlJoinPlayer(nullptr, pNewPacket->GetClientID(), pInfo->GetID()));
2009-05-08 13:28:41 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::HandlePacket(char cStatus, const C4PacketBase *pPacket, C4Network2IOConnection *pConn)
2010-03-28 18:58:01 +00:00
{
if (!pConn) return;
2009-05-08 13:28:41 +00:00
// find associated client
2009-06-05 15:19:46 +00:00
C4Network2Client *pClient = ::Network.Clients.GetClient(pConn);
2010-03-28 18:58:01 +00:00
if (!pClient) pClient = ::Network.Clients.GetClientByID(pConn->getClientID());
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
#define GETPKT(type, name) \
assert(pPacket); const type &name = \
static_cast<const type &>(*pPacket);
2009-05-08 13:28:41 +00:00
// player join request?
if (cStatus == PID_PlayerInfoUpdReq)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
GETPKT(C4PacketPlayerInfoUpdRequest, pkPlrInfo);
// this packet is sent to the host only, and thus cannot have been sent from the host
2010-03-28 18:58:01 +00:00
if (!::Network.isHost()) return;
2009-05-08 13:28:41 +00:00
// handle this packet
HandlePlayerInfoUpdRequest(&pkPlrInfo.Info, false);
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if (cStatus == PID_LeagueRoundResults)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
GETPKT(C4PacketLeagueRoundResults, pkLeagueInfo);
// accepted from the host only
if (!pClient || !pClient->isHost()) return;
// process
Game.RoundResults.EvaluateLeague(pkLeagueInfo.sResultsString.getData(), pkLeagueInfo.fSuccess, pkLeagueInfo.Players);
}
2010-03-28 18:58:01 +00:00
#undef GETPKT
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::OnClientPart(C4Client *pPartClient)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// lobby could be notified about the removal - but this would be redundant, because
// client leave notification is already done directly; this will delete any associated players
C4ClientPlayerInfos **ppCltInfo = rInfoList.GetInfoPtrByClientID(pPartClient->getID());
// abort here if no info is registered - client seems to have had a short life only, anyway...
if (!ppCltInfo) return;
// remove all unjoined player infos
2010-03-28 18:58:01 +00:00
for (int32_t i = 0; i < (*ppCltInfo)->GetPlayerCount();)
{
2009-05-08 13:28:41 +00:00
C4PlayerInfo *pInfo = (*ppCltInfo)->GetPlayerInfo(i);
// not joined yet? remove it
2010-03-28 18:58:01 +00:00
if (!pInfo->HasJoined())
2009-05-08 13:28:41 +00:00
(*ppCltInfo)->RemoveIndexedInfo(i);
else
// just ignore, the "removed" flag will be set eventually
i++;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// empty? remove
2010-03-28 18:58:01 +00:00
if (!(*ppCltInfo)->GetPlayerCount())
2009-05-08 13:28:41 +00:00
rInfoList.RemoveInfo(ppCltInfo);
// update team association to left player
Game.Teams.RecheckPlayers();
// host: update player data according to leaver
2009-06-05 15:19:46 +00:00
if (::Network.isHost() && ::Network.isEnabled())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// host: update any player colors and names
rInfoList.UpdatePlayerAttributes();
// team distribution of remaining unjoined players may change
Game.Teams.RecheckTeams();
// league score gains may now be different
Game.PlayerInfos.ResetLeagueProjectedGain(true);
2009-05-08 13:28:41 +00:00
// send changes to all clients and reset update flags
SendUpdatedPlayers();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// invalidate reference
2010-03-28 18:58:01 +00:00
if (::Network.isHost())
2009-06-05 15:19:46 +00:00
::Network.InvalidateReference();
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Network2Players::OnStatusGoReached()
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// host only
2009-06-05 15:19:46 +00:00
if (!::Network.isHost()) return;
2009-05-08 13:28:41 +00:00
// check all player lists
int i=0; C4ClientPlayerInfos *pkInfo;
2010-01-25 04:00:59 +00:00
while ((pkInfo = rInfoList.GetIndexedInfo(i++)))
2009-05-08 13:28:41 +00:00
// any unsent player joins?
if (pkInfo->HasUnjoinedPlayers())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get client core
const C4Client *pClient = Game.Clients.getClientByID(pkInfo->GetClientID());
// don't send if client is unknown or not activated yet
if (!pClient || !pClient->isActivated()) continue;
// send them w/o info packet
// info packets are synced during pause mode
JoinUnjoinedPlayersInControlQueue(pkInfo);
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
C4ClientPlayerInfos *C4Network2Players::GetLocalPlayerInfoPacket() const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get local client ID
int iLocalClientID = Game.Clients.getLocalID();
// check all packets for same client ID as local
int i=0; C4ClientPlayerInfos *pkInfo;
2010-01-25 04:00:59 +00:00
while ((pkInfo = rInfoList.GetIndexedInfo(i++)))
2009-05-08 13:28:41 +00:00
if (pkInfo->GetClientID() == iLocalClientID)
// found
return pkInfo;
// not found
return nullptr;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4ClientPlayerInfos *C4Network2Players::GetIndexedPlayerInfoPacket(int iIndex)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// just get from info list
2010-03-28 18:58:01 +00:00
return rInfoList.GetIndexedInfo(iIndex);
}
2009-05-08 13:28:41 +00:00
DWORD C4Network2Players::GetClientChatColor(int idForClient, bool fLobby) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// return color of first joined player; force to white for unknown
// deactivated always white
const C4Client *pClient = Game.Clients.getClientByID(idForClient);
if (pClient && pClient->isActivated())
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get players for activated
C4ClientPlayerInfos *pInfoPacket = rInfoList.GetInfoByClientID(idForClient);
C4PlayerInfo *pPlrInfo;
if (pInfoPacket && (pPlrInfo = pInfoPacket->GetPlayerInfo(0, C4PT_User)))
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if (fLobby)
return pPlrInfo->GetLobbyColor();
else
return pPlrInfo->GetColor();
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// default color
return 0xffffff;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00