RealtimeStyleTransferRuntime/Source/LyraGame/Teams/LyraTeamCreationComponent.cpp

189 lines
5.6 KiB
C++
Raw Normal View History

2022-05-23 18:41:30 +00:00
// Copyright Epic Games, Inc. All Rights Reserved.
#include "LyraTeamCreationComponent.h"
#include "Net/UnrealNetwork.h"
#include "GameModes/LyraExperienceDefinition.h"
#include "GameModes/LyraExperienceManagerComponent.h"
#include "LyraTeamPublicInfo.h"
#include "LyraTeamPrivateInfo.h"
#include "GameFramework/PlayerState.h"
#include "Player/LyraPlayerState.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/GameModeBase.h"
#include "Engine/World.h"
#include "GameModes/LyraGameMode.h"
ULyraTeamCreationComponent::ULyraTeamCreationComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
PublicTeamInfoClass = ALyraTeamPublicInfo::StaticClass();
PrivateTeamInfoClass = ALyraTeamPrivateInfo::StaticClass();
}
#if WITH_EDITOR
EDataValidationResult ULyraTeamCreationComponent::IsDataValid(TArray<FText>& ValidationErrors)
{
EDataValidationResult Result = Super::IsDataValid(ValidationErrors);
//@TODO: TEAMS: Validate that all display assets have the same properties set!
return Result;
}
#endif
void ULyraTeamCreationComponent::BeginPlay()
{
Super::BeginPlay();
// Listen for the experience load to complete
AGameStateBase* GameState = GetGameStateChecked<AGameStateBase>();
ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass<ULyraExperienceManagerComponent>();
check(ExperienceComponent);
ExperienceComponent->CallOrRegister_OnExperienceLoaded_HighPriority(FOnLyraExperienceLoaded::FDelegate::CreateUObject(this, &ThisClass::OnExperienceLoaded));
}
void ULyraTeamCreationComponent::OnExperienceLoaded(const ULyraExperienceDefinition* Experience)
{
#if WITH_SERVER_CODE
if (HasAuthority())
{
ServerCreateTeams();
ServerAssignPlayersToTeams();
}
#endif
}
#if WITH_SERVER_CODE
void ULyraTeamCreationComponent::ServerCreateTeams()
{
for (const auto& KVP : TeamsToCreate)
{
const int32 TeamId = KVP.Key;
ServerCreateTeam(TeamId, KVP.Value);
}
}
void ULyraTeamCreationComponent::ServerAssignPlayersToTeams()
{
// Assign players that already exist to teams
AGameStateBase* GameState = GetGameStateChecked<AGameStateBase>();
for (APlayerState* PS : GameState->PlayerArray)
{
if (ALyraPlayerState* LyraPS = Cast<ALyraPlayerState>(PS))
{
ServerChooseTeamForPlayer(LyraPS);
}
}
// Listen for new players logging in
ALyraGameMode* GameMode = Cast<ALyraGameMode>(GameState->AuthorityGameMode);
check(GameMode);
GameMode->OnGameModeCombinedPostLogin().AddUObject(this, &ThisClass::OnPostLogin);
}
void ULyraTeamCreationComponent::ServerChooseTeamForPlayer(ALyraPlayerState* PS)
{
if (PS->IsOnlyASpectator())
{
PS->SetGenericTeamId(FGenericTeamId::NoTeam);
}
else
{
const FGenericTeamId TeamID = IntegerToGenericTeamId(GetLeastPopulatedTeamID());
PS->SetGenericTeamId(TeamID);
}
}
void ULyraTeamCreationComponent::OnPostLogin(AGameModeBase* GameMode, AController* NewPlayer)
{
check(NewPlayer);
check(NewPlayer->PlayerState);
if (ALyraPlayerState* LyraPS = Cast<ALyraPlayerState>(NewPlayer->PlayerState))
{
ServerChooseTeamForPlayer(LyraPS);
}
}
void ULyraTeamCreationComponent::ServerCreateTeam(int32 TeamId, ULyraTeamDisplayAsset* DisplayAsset)
{
check(HasAuthority());
//@TODO: ensure the team doesn't already exist
UWorld* World = GetWorld();
check(World);
FActorSpawnParameters SpawnInfo;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
ALyraTeamPublicInfo* NewTeamPublicInfo = World->SpawnActor<ALyraTeamPublicInfo>(PublicTeamInfoClass, SpawnInfo);
checkf(NewTeamPublicInfo != nullptr, TEXT("Failed to create public team actor from class %s"), *GetPathNameSafe(*PublicTeamInfoClass));
NewTeamPublicInfo->SetTeamId(TeamId);
NewTeamPublicInfo->SetTeamDisplayAsset(DisplayAsset);
ALyraTeamPrivateInfo* NewTeamPrivateInfo = World->SpawnActor<ALyraTeamPrivateInfo>(PrivateTeamInfoClass, SpawnInfo);
checkf(NewTeamPrivateInfo != nullptr, TEXT("Failed to create private team actor from class %s"), *GetPathNameSafe(*PrivateTeamInfoClass));
NewTeamPrivateInfo->SetTeamId(TeamId);
}
int32 ULyraTeamCreationComponent::GetLeastPopulatedTeamID() const
{
const int32 NumTeams = TeamsToCreate.Num();
if (NumTeams > 0)
{
TMap<int32, uint32> TeamMemberCounts;
TeamMemberCounts.Reserve(NumTeams);
for (const auto& KVP : TeamsToCreate)
{
const int32 TeamId = KVP.Key;
TeamMemberCounts.Add(TeamId, 0);
}
AGameStateBase* GameState = GetGameStateChecked<AGameStateBase>();
for (APlayerState* PS : GameState->PlayerArray)
{
if (ALyraPlayerState* LyraPS = Cast<ALyraPlayerState>(PS))
{
const int32 PlayerTeamID = LyraPS->GetTeamId();
if ((PlayerTeamID != INDEX_NONE) && !LyraPS->IsInactive()) // do not count unassigned or disconnected players
{
check(TeamMemberCounts.Contains(PlayerTeamID))
TeamMemberCounts[PlayerTeamID] += 1;
}
}
}
// sort by lowest team population, then by team ID
int32 BestTeamId = INDEX_NONE;
uint32 BestPlayerCount = TNumericLimits<uint32>::Max();
for (const auto& KVP : TeamMemberCounts)
{
const int32 TestTeamId = KVP.Key;
const uint32 TestTeamPlayerCount = KVP.Value;
if (TestTeamPlayerCount < BestPlayerCount)
{
BestTeamId = TestTeamId;
BestPlayerCount = TestTeamPlayerCount;
}
else if (TestTeamPlayerCount == BestPlayerCount)
{
if ((TestTeamId < BestTeamId) || (BestTeamId == INDEX_NONE))
{
BestTeamId = TestTeamId;
BestPlayerCount = TestTeamPlayerCount;
}
}
}
return BestTeamId;
}
return INDEX_NONE;
}
#endif // WITH_SERVER_CODE