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(); }