void C4Network2Players::HandlePlayerInfo(const class C4ClientPlayerInfos &rInfoPacket) { // network only assert(::Network.isEnabled()); // 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 // make sure resources are loaded for those players rInfoList.LoadResources(); // get associated client - note that pClientInfo might be NULL for empty packets that got discarded if (pClientInfo) { const C4Client *pClient = Game.Clients.getClientByID(pClientInfo->GetClientID()); // host, game running and client active already? if (::Network.isHost() && ::Network.isRunning() && pClient && pClient->isActivated()) { // then join the players immediately JoinUnjoinedPlayersInControlQueue(pClientInfo); } } // adding the player may have invalidated other players (through team settings). Send them. SendUpdatedPlayers(); // lobby: update players C4GameLobby::MainDlg *pLobby = ::Network.GetLobby(); if (pLobby) pLobby->OnPlayersChange(); // invalidate reference ::Network.InvalidateReference(); }
void C4Network2Players::HandlePlayerInfoUpdRequest(const class C4ClientPlayerInfos *pInfoPacket, bool fByHost) { // network host only assert(::Network.isEnabled()); assert(::Network.isHost()); // 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()) { C4ClientPlayerInfos *pExistingClientInfo = rInfoList.GetInfoByClientID(OwnInfoPacket.GetClientID()); if (pExistingClientInfo) { int iCnt=OwnInfoPacket.GetPlayerCount(); C4PlayerInfo *pPlrInfo; C4Network2Res *pRes; while (iCnt--) if ((pPlrInfo=OwnInfoPacket.GetPlayerInfo(iCnt))) if (!pPlrInfo->GetID()) if ((pRes = pPlrInfo->GetRes())) if (pExistingClientInfo->GetPlayerInfoByRes(pRes->getResID())) { // double join: simply deny without message #ifdef _DEBUG Log("Network: Duplicate player join rejected!"); #endif OwnInfoPacket.RemoveIndexedInfo(iCnt); } } if (!OwnInfoPacket.GetPlayerCount()) { // player join request without players: probably all removed because doubled #ifdef _DEBUG Log("Network: Empty player join request ignored!"); #endif return; } } // assign player IDs if (!rInfoList.AssignPlayerIDs(&OwnInfoPacket) && OwnInfoPacket.IsAddPacket()) { // no players could be joined in an add request: probably because the maximum player limit has been reached return; } // 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(); if (Game.Parameters.isLeague()) { // lobby only if (!::Network.isLobbyActive()) return; // check league authentication for new players for (int i = 0; i < OwnInfoPacket.GetPlayerCount(); i++) if (!rInfoList.GetPlayerInfoByID(OwnInfoPacket.GetPlayerInfo(i)->GetID())) { C4PlayerInfo *pInfo = OwnInfoPacket.GetPlayerInfo(i); // remove player infos without authentication if (!::Network.LeaguePlrAuthCheck(pInfo)) { OwnInfoPacket.RemoveIndexedInfo(i); i--; } else // always reset authentication ID after check - it's not needed anymore pInfo->SetAuthID(""); } } // 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); // notify lobby of updates C4GameLobby::MainDlg *pLobby = ::Network.GetLobby(); if (pLobby) pLobby->OnPlayersChange(); }