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