1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2004-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // permanent player information management
17 //
18 // A separate list of all local and remote player infos is held here,
19 // independantely of the global C4PlayerList.
20 // This list is used for:
21 // -player information to be known before actual join
22 //  (player count for landscape width, team, color, etc.)
23 // -player file resource association (network mode)
24 // -league information to be stored for each player; even after elimination
25 // *-startup loader screen information; e.g. for replays
26 //
27 // * = 2do
28 //
29 // Please note that any fields added to C4PlayerInfo will be transferred to the masterserver and back.
30 // C4RoundResults is responsible for collecting information after player elimination.
31 
32 #ifndef INC_C4PlayerInfo
33 #define INC_C4PlayerInfo
34 
35 #include "config/C4Constants.h"
36 #include "lib/C4InputValidation.h"
37 #include "network/C4PacketBase.h"
38 #include "network/C4Network2Res.h"
39 #include "object/C4Id.h"
40 
41 // information about one player at a client
42 class C4PlayerInfo
43 {
44 public:
45 	// player flags
46 	enum Flags
47 	{
48 		PIF_Joined = 1 << 0,   // player has joined the game
49 		PIF_Removed = 1 << 2,   // player has been removed
50 		PIF_HasRes = 1 << 3,   // pRes is set
51 		PIF_JoinIssued = 1 << 4,   // flag for host to mark a player for which the join is issued
52 		PIF_TempFile = 1 << 5,   // player file is temporary and to be deleted after join recreation
53 		PIF_InScenarioFile = 1 << 6,   // player file is present within the scenario; res is not to be used
54 		PIF_JoinedForSavegameOnly = 1 << 7, // player file has been specified to take over a savegame player; do not join as normal player if association fails
55 		PIF_Disconnected = 1 << 8,   // the player was removed because his client disconnected
56 		PIF_Won = 1 << 9,   // player survived until game end (for game evaluation only)
57 		PIF_VotedOut = 1 << 10,  // player was removed from the round after a successful voting
58 		PIF_AttributesFixed = 1 << 11, // player color and name aren't changed on collision
59 		PIF_NoScenarioInit = 1 << 12, // do not call ScenariInit for this player
60 		PIF_NoEliminationCheck = 1 << 13, // do not eliminate player if crew is empty
61 		PIF_Invisible = 1 << 14,  // do not show in lobby and menus
62 		PIF_NoScenarioSave = 1 << 15,  // not saved in SavePlayerInfos.txt if "save as scenario" is performed
63 
64 		// flags to be synchronized via network and saved into player info
65 		PIF_SyncFlags = PIF_Joined | PIF_Removed | PIF_HasRes | PIF_InScenarioFile | PIF_JoinedForSavegameOnly | PIF_Disconnected | PIF_Won | PIF_VotedOut | PIF_AttributesFixed | PIF_NoScenarioInit | PIF_NoEliminationCheck | PIF_Invisible | PIF_NoScenarioSave,
66 
67 		// flags to be copied from savegame-player for takeover
68 		PIF_SavegameTakeoverFlags = PIF_Joined | PIF_Removed | PIF_JoinIssued | PIF_AttributesFixed | PIF_NoScenarioInit | PIF_NoEliminationCheck | PIF_Invisible | PIF_NoScenarioSave,
69 	};
70 
71 	// player attributes used in attribute conflict resolver
72 	enum Attribute { PLRATT_Color=0, PLRATT_Name=1, PLRATT_Last=2 };
73 	enum AttributeLevel { PLRAL_Current, PLRAL_Original, PLRAL_Alternate };
74 private:
75 	uint32_t dwFlags{0}; // DWORD-mask of C4PlayerInfoFlags-constants
76 	C4PlayerType eType{C4PT_User};         // user or script player
77 
78 	ValidatedStdCopyStrBuf<C4InVal::VAL_NameNoEmpty> sName;     // player name
79 	ValidatedStdCopyStrBuf<C4InVal::VAL_NameAllowEmpty> sForcedName; // player name if a new name is forced e.g. because the current name appeared twice
80 	int32_t iID{0};          // unique ID set by host
81 	C4Network2Res::Ref pRes;    // player resource to load from
82 	C4Network2ResCore ResCore;  // core of resource to load from
83 	StdCopyStrBuf szFilename;   // source filename for local players
84 	uint32_t dwColor{0xffffffff};           // player color
85 	uint32_t dwOriginalColor{0}, dwAlternateColor{0}; // original player color wish
86 	int32_t idSavegamePlayer{0};   // ID of associated savegame player
87 	int32_t idTeam{0};             // team ID
88 	StdCopyStrBuf szAuthID;     // authentication ID (for league server, will be cleared on successful join)
89 	int32_t iInGameNumber{-1}, iInGameJoinFrame{-1}, iInGamePartFrame{-1}; // information about player in game
90 	C4ID idExtraData;           // extra data for script players
91 
92 	ValidatedStdCopyStrBuf<C4InVal::VAL_NameAllowEmpty> sLeagueAccount; // account name on league server
93 	int32_t iLeagueScore{0};       // score on league server at join time
94 	int32_t iLeagueRank{0};        // rank on league server at join time
95 	int32_t iLeagueRankSymbol{0};  // symbolization of the player's rank
96 	int32_t iLeagueScoreProjected;// score on league server in case of win
97 	int32_t iLeagueProjectedGain{-1}; // projected league score increase if game is won - -1 for unknown; valid values always positive
98 	ValidatedStdCopyStrBuf<C4InVal::VAL_NameAllowEmpty> sClanTag; // clan ("team") tag
99 	int32_t iLeaguePerformance{0}; // script-set league performance value, only set temporarily for masterserver end reference
100 	StdCopyStrBuf sLeagueProgressData; // level progress data as reported by league
101 
102 public:
C4PlayerInfo()103 	C4PlayerInfo()                           // construct empty
104 			: pRes(nullptr), szFilename(), idExtraData(C4ID::None), sLeagueAccount("") { }
105 
106 	void Clear();                            // clear fields
107 
108 	bool LoadFromLocalFile(const char *szFilename); // load data from local file
109 	bool SetAsScriptPlayer(const char *szName, uint32_t dwColor, uint32_t dwFlags, C4ID idExtra); // set as a script (AI) player
110 
111 	void SetJoined(int32_t iNumber); // mark as joined in current game frame
SetJoinIssued()112 	void SetJoinIssued() { dwFlags |= PIF_JoinIssued; }        // mark as joined
113 	void SetRemoved();              // mark as removed in current game frame - always marks as previously joined, too
SetID(int32_t iToID)114 	void SetID(int32_t iToID) { iID = iToID; }              // set player info ID
SetColor(DWORD dwUseClr)115 	void SetColor(DWORD dwUseClr) { dwColor = dwUseClr; } // set color to be used
SetOriginalColor(DWORD dwUseClr)116 	void SetOriginalColor(DWORD dwUseClr) { dwOriginalColor = dwUseClr; } // set color the player wishes to have
117 	void SetFilename(const char *szToFilename);           // set new player filename
118 	void SetToScenarioFilename(const char *szScenFilename); // set to file within scenario; discard resource
SetTempFile()119 	void SetTempFile() { assert(!!szFilename); dwFlags |= PIF_TempFile; } // mark filename as temp, so it is deleted in dtor or after join
SetTeam(int32_t idToTeam)120 	void SetTeam(int32_t idToTeam) { idTeam = idToTeam; }
121 	void DeleteTempFile();                                // delete filename if temp
122 	void LoadResource();                                  // network: Load resource if present and not being loaded yet
123 	void DiscardResource();                               // delete any source resource for network player infos
SetAssociatedSavegamePlayer(int32_t aidSavegamePlayer)124 	void SetAssociatedSavegamePlayer(int32_t aidSavegamePlayer)   // link with savegame player from restore list
125 	{ idSavegamePlayer=aidSavegamePlayer; }
GetAssociatedSavegamePlayerID()126 	int32_t GetAssociatedSavegamePlayerID() const
127 	{ return idSavegamePlayer; }
SetJoinForSavegameOnly()128 	void SetJoinForSavegameOnly()                          // flag to be deleted if savegame association fails
129 	{ dwFlags |= PIF_JoinedForSavegameOnly; }
IsJoinForSavegameOnly()130 	bool IsJoinForSavegameOnly()                           // flag to be deleted if savegame association fails
131 	{ return !!(dwFlags & PIF_JoinedForSavegameOnly); }
132 	bool SetSavegameResume(C4PlayerInfo *pSavegameInfo);   // take over savegame player data to do resume
SetAuthID(const char * sznAuthID)133 	void SetAuthID(const char *sznAuthID)
134 	{ szAuthID = sznAuthID; }
SetLeagueData(const char * szAccount,const char * szNewClanTag,int32_t iScore,int32_t iRank,int32_t iRankSymbol,const char * szProgressData)135 	void SetLeagueData(const char *szAccount, const char *szNewClanTag, int32_t iScore, int32_t iRank, int32_t iRankSymbol, const char *szProgressData)
136 	{ sLeagueAccount.CopyValidated(szAccount); sClanTag.CopyValidated(szNewClanTag); iLeagueScore = iScore; iLeagueRank = iRank; iLeagueRankSymbol = iRankSymbol; sLeagueProgressData.Copy(szProgressData); }
SetLeaguePerformance(int32_t iNewPerf)137 	void SetLeaguePerformance(int32_t iNewPerf)
138 		{ iLeaguePerformance = iNewPerf; }
SetLeagueProgressData(const char * szNewProgressData)139 	void SetLeagueProgressData(const char *szNewProgressData)
140 		{ if (szNewProgressData) sLeagueProgressData.Copy(szNewProgressData); else sLeagueProgressData.Clear(); }
SetVotedOut()141 	void SetVotedOut()
142 	{ dwFlags |= PIF_VotedOut; }
SetLeagueProjectedGain(int32_t iProjectedGain)143 	void SetLeagueProjectedGain(int32_t iProjectedGain)
144 	{ assert(iProjectedGain>=0); iLeagueProjectedGain = iProjectedGain; }
ResetLeagueProjectedGain()145 	void ResetLeagueProjectedGain()
146 	{ iLeagueProjectedGain = -1; }
SetForcedName(const char * szNewName)147 	void SetForcedName(const char *szNewName)
148 	{ if (szNewName) sForcedName.CopyValidated(szNewName); else sForcedName.Clear(); }
149 
150 	void CompileFunc(StdCompiler *pComp);
151 
GetType()152 	C4PlayerType GetType() const { return eType; }
GetColor()153 	uint32_t GetColor() const { return dwColor; }     // get player color
154 	uint32_t GetLobbyColor() const;
GetOriginalColor()155 	uint32_t GetOriginalColor() const { return dwOriginalColor; }     // get original player color
GetAlternateColor()156 	uint32_t GetAlternateColor() const { return dwAlternateColor; }     // get secondary original player color
GetName()157 	const char *GetName() const { return sLeagueAccount.getLength() ? sLeagueAccount.getData() : sForcedName.getLength() ? sForcedName.getData() : sName.getData(); } // get player name
GetOriginalName()158 	const char *GetOriginalName() const { return sName.getData(); }
GetForcedName()159 	const char *GetForcedName() const { return sForcedName.getData(); }
160 	StdStrBuf GetLobbyName() const; // return player name including clan/team tag if known; fallback to regular player name
GetFilename()161 	const char *GetFilename() const { return szFilename.getData(); } // get filename for local games
162 	const char *GetLocalJoinFilename() const;              // get name of file to join the player from
GetRes()163 	C4Network2Res *GetRes() const { return pRes; }         // get player resource for network games
IsRemoved()164 	bool IsRemoved() const { return !!(dwFlags & PIF_Removed); }
HasJoined()165 	bool HasJoined() const { return !!(dwFlags & PIF_Joined); }    // return whether player has joined
IsJoined()166 	bool IsJoined() const { return HasJoined() && !(dwFlags & PIF_Removed); } // return whether player is currently in the game
HasJoinIssued()167 	bool HasJoinIssued() const { return !!(dwFlags & (PIF_Joined | PIF_JoinIssued)); } // return whether player join is in the queue already (or performed long ago, even)
HasJoinPending()168 	bool HasJoinPending() const { return !(dwFlags & (PIF_Joined | PIF_Removed)); } // return whether player join should be done but has not been performed yet
IsUsingColor()169 	bool IsUsingColor() const { return !IsRemoved() && !idSavegamePlayer; } //return whether the player is actually using the player color
IsUsingName()170 	bool IsUsingName() const { return !IsRemoved() && !sLeagueAccount.getLength(); } //return whether the player is actually using the player name (e.g. not if league name is used)
IsUsingAttribute(Attribute eAttr)171 	bool IsUsingAttribute(Attribute eAttr) const { if (eAttr == PLRATT_Color) return IsUsingColor(); else return IsUsingName(); }
IsUsingPlayerFile()172 	bool IsUsingPlayerFile() const { return !IsRemoved(); } //return whether the player is using the file (i.e., isn't dead yet)
IsUsingTeam()173 	bool IsUsingTeam() const { return !IsRemoved(); }       // whether player should be in the team list
IsAttributesFixed()174 	bool IsAttributesFixed() const { return !!(dwFlags & PIF_AttributesFixed); }
IsInvisible()175 	bool IsInvisible() const { return !!(dwFlags & PIF_Invisible); }
IsScenarioInitDesired()176 	bool IsScenarioInitDesired() const { return !(dwFlags & PIF_NoScenarioInit); }
IsScenarioSaveDesired()177 	bool IsScenarioSaveDesired() const { return !(dwFlags & PIF_NoScenarioSave); }
GetScriptPlayerExtraID()178 	C4ID GetScriptPlayerExtraID() const { return idExtraData; }
IsNoEliminationCheck()179 	bool IsNoEliminationCheck() const { return !!(dwFlags & PIF_NoEliminationCheck); }
HasAutoGeneratedColor()180 	bool HasAutoGeneratedColor() { return dwColor != dwOriginalColor; } // whether the player got a new color assigned due to color conflict
HasWon()181 	bool HasWon() const { return !!(dwFlags & PIF_Won); }
182 	bool HasTeamWon() const;
getAuthID()183 	const char *getAuthID() const { return szAuthID.getData(); } // returns authentication ID for this player [league]
getLeagueAccount()184 	const char *getLeagueAccount() const { return sLeagueAccount.getData(); } // returns account name on league server
getLeagueScore()185 	int32_t getLeagueScore() const { return iLeagueScore; } // returns score number on league server (0 for not assigned)
getLeagueRank()186 	int32_t getLeagueRank() const { return iLeagueRank; } // returns rank on league server (0 for not assigned)
getLeagueRankSymbol()187 	int32_t getLeagueRankSymbol() const { return iLeagueRankSymbol; } // returns rank symbol on league server (0 for not assigned)
getLeagueScoreProjected()188 	int32_t getLeagueScoreProjected() const { return iLeagueScoreProjected; } // returns score on league server in case of win (0 for not assigned)
GetInGameNumber()189 	int32_t GetInGameNumber() const { return iInGameNumber; } // returns player number the player had in the game
IsLeagueProjectedGainValid()190 	bool IsLeagueProjectedGainValid() const { return iLeagueProjectedGain>=0; }
GetLeagueProjectedGain()191 	int32_t GetLeagueProjectedGain() const { return iLeagueProjectedGain; } // get score gain in primary league if this player's team wins
GetLeagueProgressData()192 	const char *GetLeagueProgressData() const { return sLeagueProgressData.getData(); }
193 
GetID()194 	int32_t GetID() const { return iID; }                    // get unique ID, if assigned
GetTeam()195 	int32_t GetTeam() const { return idTeam; }
IsTempFile()196 	bool IsTempFile() const { return !!(dwFlags & PIF_TempFile); } // return whether filename points to temp folder
197 
GetFlags()198 	DWORD GetFlags() { return dwFlags; } // for dbg print only
199 
SetDisconnected()200 	void SetDisconnected() { dwFlags |= PIF_Disconnected; }
SetWinner()201 	void SetWinner() { dwFlags |= PIF_Won; }
202 
203 	bool LoadBigIcon(C4FacetSurface &fctTarget); // load BigIcon.png of player into target facet; return false if no bigicon present or player file not yet loaded
204 };
205 
206 // player infos for one client
207 // merely a list of player infos
208 class C4ClientPlayerInfos
209 {
210 private:
211 	// std::vector...
212 	int32_t iPlayerCount{0};               // number of clients registered into the list
213 	int32_t iPlayerCapacity{0};            // size of pClients-array
214 	C4PlayerInfo **ppPlayers{nullptr};       // array of registered client information
215 	void GrowList(size_t iByVal); // increase list capacity
216 
217 	int32_t iClientID{-1};          // ID of client described by this packet
218 
219 	// flags for this packet
220 	enum Flags
221 	{
222 		CIF_AddPlayers  = 1<<0, // if set, the players are to be added to the current list (otherwise overwrite)
223 		CIF_Updated     = 1<<1, // set temporarily if changed and not transmissioned to clients (valid for host only)
224 		CIF_Initial     = 1<<2, // set for first-time player info packets
225 		CIF_Developer   = 1<<3, // set for developer hosts (by regkey); client side check only!
226 		CIF_Removed     = 1<<4 // client was removed
227 	};
228 	uint32_t dwFlags{0}; // bit mask of the above flags
229 
230 public:
231 	C4ClientPlayerInfos(const char *szJoinFilenames=nullptr, bool fAdd=false, C4PlayerInfo *pAddInfo=nullptr); // ctor; sets local data (or makes an add-player-packet if filename is given) if par is true
232 	C4ClientPlayerInfos(const C4ClientPlayerInfos &rCopy); // copy ctor
~C4ClientPlayerInfos()233 	~C4ClientPlayerInfos() { Clear(); }                   // dtor
234 
235 	C4ClientPlayerInfos &operator = (const C4ClientPlayerInfos &rCopy);
236 
237 	void Clear();                                     // del all players
238 	void GrabMergeFrom(C4ClientPlayerInfos &rFrom);   // merge existing player info packed into this one - empties pFrom!
239 	void AddInfo(C4PlayerInfo *pAddInfo);             // add info to list
240 	void RemoveIndexedInfo(int32_t iAtIndex);             // remove info from list (delete it)
241 	void RemoveInfo(int32_t idPlr);                       // remove info from list (delete it)
242 
243 	// update-flag
SetUpdated()244 	void SetUpdated() { dwFlags |= CIF_Updated; }
IsUpdated()245 	bool IsUpdated() { return !!(dwFlags & CIF_Updated); }
ResetUpdated()246 	void ResetUpdated() { dwFlags &= ~CIF_Updated; }
SetAdd()247 	void SetAdd() { dwFlags |= CIF_AddPlayers; }
ResetAdd()248 	void ResetAdd() { dwFlags &= ~CIF_AddPlayers; }
249 
250 	// query functions
GetPlayerCount()251 	int32_t GetPlayerCount() const { return iPlayerCount; } // get number of player infos available
252 	int32_t GetFlaggedPlayerCount(DWORD dwFlag) const;      // get number of player infos with any of the given flags set
253 	C4PlayerInfo *GetPlayerInfo(int32_t iIndex) const;      // get indexed player info
254 	C4PlayerInfo *GetPlayerInfo(int32_t iIndex, C4PlayerType eType) const;      // get indexed player info of given type
255 	C4PlayerInfo *GetPlayerInfoByID(int32_t id) const;      // get player info by unique player ID
256 	C4PlayerInfo *GetPlayerInfoByRes(int32_t idResID) const; // get player info by resource ID
GetClientID()257 	int32_t GetClientID() const { return iClientID; }       // get target client ID
258 	bool HasUnjoinedPlayers() const;                          // check all players and return whether one of them didn't join
259 	int32_t GetJoinedPlayerCount() const;                   // return number of players that are IsJoined()
IsAddPacket()260 	bool IsAddPacket() const { return !!(dwFlags & CIF_AddPlayers); }  // return whether players are to be added to the current list (otherwise overwrite)
IsInitialPacket()261 	bool IsInitialPacket() const { return !!(dwFlags & CIF_Initial); } // returns whether this packet was sent as the first local-join packet
IsDeveloperPacket()262 	bool IsDeveloperPacket() const { return !!(dwFlags & CIF_Developer); } // returns whether packet was created by a developer host - client side check only!
263 
264 	// network: Load all resources connected with the players that are not being loaded yet
265 	void LoadResources();
266 
267 	// pack/unpack functions
268 	void CompileFunc(StdCompiler *pComp);
269 };
270 
271 // * PID_PlayerInfoUpdRequest
272 // packet containing information about one or more joined players at a client
273 // or about lobby player-info updates
274 class C4PacketPlayerInfoUpdRequest : public C4PacketBase
275 {
276 public:
277 	C4ClientPlayerInfos Info; // info for clients to be joined
278 
C4PacketPlayerInfoUpdRequest()279 	C4PacketPlayerInfoUpdRequest() : Info() { } // std ctor
C4PacketPlayerInfoUpdRequest(const char * szFilenames,bool fAdd)280 	C4PacketPlayerInfoUpdRequest(const char *szFilenames, bool fAdd) // ctor
281 			: Info(szFilenames, fAdd) { };
282 
C4PacketPlayerInfoUpdRequest(const C4ClientPlayerInfos & rInfo)283 	C4PacketPlayerInfoUpdRequest(const C4ClientPlayerInfos &rInfo) : Info(rInfo) {} // ctor
284 
285 	void CompileFunc(StdCompiler *pComp) override;
286 };
287 
288 // * PID_PlayerInfoUpd
289 // packet containing information about one or more (updated) players at a client
290 class C4PacketPlayerInfo : public C4PacketBase
291 {
292 public:
293 	C4ClientPlayerInfos Info; // info for clients to be updated
294 	bool fIsRecreationInfo{false};   // if set, this info packet describes savegame recreation players
295 
C4PacketPlayerInfo()296 	C4PacketPlayerInfo() : Info() { } // std ctor
C4PacketPlayerInfo(const C4ClientPlayerInfos & rCopyInfos,bool fRecreationPlayers)297 	C4PacketPlayerInfo(const C4ClientPlayerInfos &rCopyInfos, bool fRecreationPlayers) // ctor
298 			: Info(rCopyInfos), fIsRecreationInfo(fRecreationPlayers) { };
299 
300 	void CompileFunc(StdCompiler *pComp) override;
301 };
302 
303 // player info list
304 // contains player info packets for all known clients and self
305 class C4PlayerInfoList
306 {
307 private:
308 	// std::vector...
309 	int32_t iClientCount{0};               // number of clients registered into the list
310 	int32_t iClientCapacity{0};            // size of pClients-array
311 	C4ClientPlayerInfos **ppClients{nullptr}; // array of registered client information
312 	void GrowList(size_t iByVal); // increase list capacity
313 
314 	int32_t iLastPlayerID{0};              // last ID given to a player
315 
316 	enum MatchingLevel { PML_PlrFileName=0, PML_PlrName, PML_PrefColor, PML_Any };
317 
318 public:
319 	C4PlayerInfoList();               // ctor
320 	C4PlayerInfoList(const C4PlayerInfoList &rCpy);
~C4PlayerInfoList()321 	~C4PlayerInfoList() { Clear(); }  // dtor
322 	C4PlayerInfoList &operator = (const C4PlayerInfoList &rCpy);
323 	void Clear();                     // clear list
324 
325 	// forwards player info update request to the appropriate handler
326 	bool DoPlayerInfoUpdate(C4ClientPlayerInfos *pUpdate);
327 
328 	// performs a local player join for the given player file(s)
329 	bool DoLocalNonNetworkPlayerJoin(const char *szPlayerFile);
330 	bool DoLocalNonNetworkPlayerInfoUpdate(C4ClientPlayerInfos *pUpdate);
331 
332 	// sets any unset IDs (host/standalone only); also removes players that would exceed the maximum player limit
333 	// returns whether any players remain
334 	bool AssignPlayerIDs(C4ClientPlayerInfos *pNewClientInfo);
335 
336 	// assign any unset teams (host/standalone only) - fByHost determines whether packet was sent by host
337 	void AssignTeams(C4ClientPlayerInfos *pNewClientInfo, bool fByHost);
338 
339 	// generate teams used by the player info list if they do not exist and auto generated teams are enabled
340 	// used for replays
341 	void RecheckAutoGeneratedTeams();
342 
343 	// add info for client; overwriting or appending to existing info if necessary
344 	// this takes over the pNewClientInfo ptr, and may invalidate (delete) it!
345 	// the pointer to the info structure as it is valid in the list is returned
346 	// when infos are added, unset IDs will automatically be assigned (should happen for host only!)
347 	C4ClientPlayerInfos *AddInfo(C4ClientPlayerInfos *pNewClientInfo);
348 
349 	// resolve any color conflicts in self AND given (optional) packet. Sets Updated-flags.
350 	void ResolvePlayerAttributeConflicts(C4ClientPlayerInfos *pSecPacket);
351 
352 	// do color updates: Savegame color assignment; team colors; duplicate attribute check
353 	void UpdatePlayerAttributes(C4ClientPlayerInfos *pForInfo, bool fResolveConflicts);
354 	void UpdatePlayerAttributes();
355 
356 	// query functions
GetInfoCount()357 	int32_t GetInfoCount() const { return iClientCount; }    // get number of registered client infos
GetIndexedInfo(int32_t iIndex)358 	C4ClientPlayerInfos *GetIndexedInfo(int32_t iIndex) const // get client player infos by indexed
359 	{ return (ppClients && Inside<int32_t>(iIndex, 0, iClientCount-1)) ? ppClients[iIndex] : nullptr; }
360 	C4ClientPlayerInfos **GetInfoPtrByClientID(int32_t iClientID) const; // get info for a specific client ID
GetInfoByClientID(int32_t iClientID)361 	C4ClientPlayerInfos *GetInfoByClientID(int32_t iClientID) const
362 	{ C4ClientPlayerInfos **ppNfo = GetInfoPtrByClientID(iClientID); return ppNfo ? *ppNfo : nullptr; }
363 	C4PlayerInfo *GetPlayerInfoByIndex(int32_t index) const;  // get player info by index (for running through all players regardless of clients or ids)
364 	C4PlayerInfo *GetPlayerInfoByID(int32_t id) const;        // get player info by unique player ID
365 	C4PlayerInfo *GetPlayerInfoByID(int32_t id, int32_t *pidClient) const;  // get player info by unique player ID, and assign associated client
366 	C4ClientPlayerInfos *GetClientInfoByPlayerID(int32_t id) const; // get client info that contains a specific player
367 	C4PlayerInfo *GetPlayerInfoBySavegameID(int32_t id) const;// get player info by savegame association ID
368 	C4PlayerInfo *GetNextPlayerInfoByID(int32_t id) const;    // get player info with smallest ID > given id
369 	C4PlayerInfo *GetActivePlayerInfoByName(const char *szName);    // find info by name (case insensitive)
370 	int32_t GetPlayerCount() const;                           // get number of players on all clients
371 	int32_t GetJoinIssuedPlayerCount() const;                 // get number of players with PIF_JoinIssued-flag set
372 	int32_t GetJoinPendingPlayerCount() const;                 // get number of players with PIF_JoinIssued-flag but not joined or removed flag set
373 	int32_t GetActivePlayerCount(bool fCountInvisible) const;                     // get number of players that have not been removed
374 	StdStrBuf GetActivePlayerNames(bool fCountInvisible, int32_t iAtClientID=-1) const;                   // get a comma-separated list of players that have not been removed yet
375 	int32_t GetActiveScriptPlayerCount(bool fCountSavegameResumes, bool fCountInvisible) const;               // get number of script players that have not been removed
GetPrimaryInfoByClientID(int32_t iClientID)376 	C4PlayerInfo *GetPrimaryInfoByClientID(int32_t iClientID) const
377 	{
378 		C4ClientPlayerInfos *pInfoPkt = GetInfoByClientID(iClientID);
379 		if (!pInfoPkt) return nullptr;
380 		return pInfoPkt->GetPlayerInfo(0);
381 	}
382 	C4PlayerInfo *FindSavegameResumePlayerInfo(const C4PlayerInfo *pMatchInfo, MatchingLevel mlMatchStart, MatchingLevel mlMatchEnd) const; // automatic savegame player association: Associate by name (or prefcolor, if none matches)
383 	bool HasSameTeamPlayers(int32_t iClient1, int32_t iClient2) const; // check all active players; return true if two of them on different clients are in the same team
384 	C4PlayerInfo *FindUnassociatedRestoreInfo(const C4PlayerInfoList &rRestoreInfoList); // find a player in the given list that has not been associated by a player in this list
385 
RemoveInfo(C4ClientPlayerInfos ** ppRemoveInfo)386 	void RemoveInfo(C4ClientPlayerInfos **ppRemoveInfo) // remove client info given by direct ptr into list
387 	{ *ppRemoveInfo = ppClients[--iClientCount]; /* maybe redundant self-assignment; no vector shrink */ }
388 
389 public:
390 	bool Load(C4Group &hGroup, const char *szFromFile, class C4LangStringTable *pLang=nullptr); // clear self and load from group file
391 	bool Save(C4Group &hGroup, const char *szToFile); // save to group file
392 
393 	// external ID counter manipulation used by C4Game
SetIDCounter(int32_t idNewCounter)394 	void SetIDCounter(int32_t idNewCounter) { iLastPlayerID = idNewCounter; }
GetIDCounter()395 	int32_t GetIDCounter() { return iLastPlayerID; }
396 	void FixIDCounter(); // make sure ID counter is same as largest info
397 
398 	// game interaction
399 	bool InitLocal();                       // put locally joining players into list (non-network)
400 	bool LocalJoinUnjoinedPlayersInQueue(); // join all unjoined players to local input queue
401 	int32_t GetStartupCount();              // get number of players already joined and to be joined
402 	void CreateRestoreInfosForJoinedScriptPlayers(C4PlayerInfoList &rSavegamePlayers); // create matching script player joins for all script playeers in restore info
403 	bool RecreatePlayers(C4ValueNumbers *); // directly join all players whose join-flag is set
404 	bool RecreatePlayerFiles();             // update player source files
405 	bool RestoreSavegameInfos(C4PlayerInfoList &rSavegamePlayers); // recreate this list from rSavegamePlayers for host/single games; just merge associated infos
406 	bool SetAsRestoreInfos(C4PlayerInfoList &rFromPlayers, bool fSaveUserPlrs, bool fSaveScriptPlrs, bool fSetUserPlrRefToLocalGroup, bool fSetScriptPlrRefToLocalGroup); // copy all joined players from player list
407 	void RemoveUnassociatedPlayers(C4PlayerInfoList &rSavegamePlayers); // remove all savegame players that are not associated to this list from the game
408 	int32_t GetFreePlayerSlotCount();       // get number of players that may still join
409 	void ResetLeagueProjectedGain(bool fSetUpdated); // reset known projected gains for all players (to be updated by league again)
410 
411 	// network: Load all resources connected with the players that are not being loaded yet
412 	void LoadResources();
413 
414 	// compiler
415 	void CompileFunc(StdCompiler *pComp);
416 };
417 
418 #endif // INC_C4PlayerInfo
419