#include "UnrealProject.h" #include "GameStateBase.h" #include "PlayerStateBase.h" #include "DefaultPlayerController.h" #include "DefaultGameInstance.h" #include "MapData.h" AGameStateBase::AGameStateBase() { m_mapTeamCount = 4; m_hasWarnedFrank = false; } void AGameStateBase::BeginPlay() { Super::BeginPlay(); mapPath = GetWorld()->GetPathName(); m_LoadActiveMapInfo(); } void AGameStateBase::EndPlay(const EEndPlayReason::Type EndPlayReason) { Super::EndPlay(EndPlayReason); OnPlayerStateChange.Clear(); } void AGameStateBase::RegisterPlayer(APlayerControllerBase* player) { check(Role == ROLE_Authority); check(player); APlayerStateBase* state = Cast(player->PlayerState); check(state); m_playersByController.Add(player, state); m_players.Add(state); // More than 1 player in editor means multiplayer in PIE mode if(m_players.Num() > 1) { EnterLobby(); } OnPlayerStateChange.Broadcast(nullptr); } void AGameStateBase::DeregisterPlayer(APlayerControllerBase* player) { check(Role == ROLE_Authority); m_playersByController.Remove(player); m_players.SetNum(0); for(auto it = m_playersByController.CreateIterator(); it; ++it) { m_players.Add(it->Value); } OnPlayerStateChange.Broadcast(nullptr); } void AGameStateBase::EnterLobby() { check(Role == ROLE_Authority); for(auto it = m_playersByController.CreateIterator(); it; ++it) { it->Key->EnterLobby(); } } void AGameStateBase::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(AGameStateBase, m_players); DOREPLIFETIME(AGameStateBase, m_mapTeamCount); DOREPLIFETIME(AGameStateBase, mapPath); } TArray& AGameStateBase::GetPlayers() { return m_players; } TArray> AGameStateBase::GetPlayersByTeam() { TArray> ret; for(int32 i = 0; i < m_players.Num(); i++) { APlayerStateBase* player = m_players[i]; if(!player) continue; int32 team = player->GetTeam(); if(team >= ret.Num()) { ret.SetNum(team + 1); } TArray& dstArray = ret[team]; dstArray.Add(player); } return ret; } TArray AGameStateBase::GetTeamSizes() { TArray teamSizes; teamSizes.SetNumZeroed(m_mapTeamCount); for(int32 i = 0; i < m_players.Num(); i++) { if(!m_players[i]) continue; int32 team = m_players[i]->GetTeam() - 1; if(team < 0 || team >= m_mapTeamCount) continue; teamSizes[team]++; } return TArray(teamSizes); } int32 AGameStateBase::GetOptimalAutoJoinTeam() { if(GetWorld()->IsPlayInEditor()) { // PIE uses different assignment, default to 2 players per team and then move to the next team TArray teamSize = GetTeamSizes(); int32 optimalTeam = -1; for(int32 i = 0; i < m_mapTeamCount; i++) { if(teamSize[i] < 2) { optimalTeam = i; break; } } return optimalTeam + 1; } else { TArray teamSize = GetTeamSizes(); int32 smallestSize = 2; int32 optimalTeam = -1; for(int32 i = 0; i < m_mapTeamCount; i++) { if(teamSize[i] < smallestSize) { optimalTeam = i; smallestSize = teamSize[i]; } } return optimalTeam + 1; } } int32 AGameStateBase::GetMapTeamCount() const { return m_mapTeamCount; } UMapData* AGameStateBase::GetMapData() const { return m_mapData; } void AGameStateBase::m_OnRep_MapPath() { GPRINT("Map changed to " + mapPath); m_LoadActiveMapInfo(); if(m_mapData) GPRINT("Found attached map data " + m_mapData->GetName()); else GERROR("No attached map data found."); } void AGameStateBase::OnPlayerStateChange_Multi_Implementation() { if (m_playersByController.Num() > 0) OnPlayerStateChange.Broadcast(nullptr); } TMap AGameStateBase::GetPlayersByController() { return m_playersByController; } bool AGameStateBase::m_LoadActiveMapInfo() { UDefaultGameInstance* gameInstance = Cast(GetGameInstance()); if(!gameInstance) return false; m_mapData = gameInstance->GetMapData(mapPath); if(!m_mapData) { if(!m_hasWarnedFrank) { GWERROR(L"Failed to load map info, Create a map info asset with the name formated as I_ + map name in the same folder and add the I_ file to the map list frank!!!"); m_hasWarnedFrank = true; } m_mapTeamCount = 4; } else { m_mapTeamCount = m_mapData->maxTeamCount; } return true; }