RealtimeStyleTransferRuntime/Source/LyraGame/GameModes/LyraBotCreationComponent.cpp

166 lines
5.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "LyraBotCreationComponent.h"
#include "LyraGameMode.h"
#include "Engine/World.h"
#include "GameFramework/PlayerState.h"
#include "GameModes/LyraExperienceDefinition.h"
#include "GameModes/LyraExperienceManagerComponent.h"
#include "Development/LyraDeveloperSettings.h"
#include "Player/LyraPlayerState.h"
#include "GameFramework/PlayerController.h"
#include "Character/LyraPawnExtensionComponent.h"
#include "AIController.h"
#include "Kismet/GameplayStatics.h"
#include "Character/LyraHealthComponent.h"
ULyraBotCreationComponent::ULyraBotCreationComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void ULyraBotCreationComponent::BeginPlay()
{
Super::BeginPlay();
// Listen for the experience load to complete
AGameStateBase* GameState = GetGameStateChecked<AGameStateBase>();
ULyraExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass<ULyraExperienceManagerComponent>();
check(ExperienceComponent);
ExperienceComponent->CallOrRegister_OnExperienceLoaded_LowPriority(FOnLyraExperienceLoaded::FDelegate::CreateUObject(this, &ThisClass::OnExperienceLoaded));
}
void ULyraBotCreationComponent::OnExperienceLoaded(const ULyraExperienceDefinition* Experience)
{
#if WITH_SERVER_CODE
if (HasAuthority())
{
ServerCreateBots();
}
#endif
}
#if WITH_SERVER_CODE
void ULyraBotCreationComponent::ServerCreateBots()
{
if (BotControllerClass == nullptr)
{
return;
}
RemainingBotNames = RandomBotNames;
// Determine how many bots to spawn
int32 EffectiveBotCount = NumBotsToCreate;
// Give the developer settings a chance to override it
if (GIsEditor)
{
const ULyraDeveloperSettings* DeveloperSettings = GetDefault<ULyraDeveloperSettings>();
if (DeveloperSettings->bOverrideBotCount)
{
EffectiveBotCount = DeveloperSettings->OverrideNumPlayerBotsToSpawn;
}
}
// Give the URL a chance to override it
if (AGameModeBase* GameModeBase = GetGameMode<AGameModeBase>())
{
EffectiveBotCount = UGameplayStatics::GetIntOption(GameModeBase->OptionsString, TEXT("NumBots"), EffectiveBotCount);
}
// Create them
for (int32 Count = 0; Count < EffectiveBotCount; ++Count)
{
SpawnOneBot();
}
}
FString ULyraBotCreationComponent::CreateBotName(int32 PlayerIndex)
{
FString Result;
if (RemainingBotNames.Num() > 0)
{
const int32 NameIndex = FMath::RandRange(0, RemainingBotNames.Num() - 1);
Result = RemainingBotNames[NameIndex];
RemainingBotNames.RemoveAtSwap(NameIndex);
}
else
{
//@TODO: PlayerId is only being initialized for players right now
PlayerIndex = FMath::RandRange(260, 260+100);
Result = FString::Printf(TEXT("Tinplate %d"), PlayerIndex);
}
return Result;
}
void ULyraBotCreationComponent::SpawnOneBot()
{
FActorSpawnParameters SpawnInfo;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
SpawnInfo.OverrideLevel = GetComponentLevel();
SpawnInfo.ObjectFlags |= RF_Transient;
AAIController* NewController = GetWorld()->SpawnActor<AAIController>(BotControllerClass, FVector::ZeroVector, FRotator::ZeroRotator, SpawnInfo);
if (NewController != nullptr)
{
ALyraGameMode* GameMode = GetGameMode<ALyraGameMode>();
check(GameMode);
if (NewController->PlayerState != nullptr)
{
NewController->PlayerState->SetPlayerName(CreateBotName(NewController->PlayerState->GetPlayerId()));
}
GameMode->DispatchPostLogin(NewController);
GameMode->RestartPlayer(NewController);
if (NewController->GetPawn() != nullptr)
{
if (ULyraPawnExtensionComponent* PawnExtComponent = NewController->GetPawn()->FindComponentByClass<ULyraPawnExtensionComponent>())
{
PawnExtComponent->CheckDefaultInitialization();
}
}
SpawnedBotList.Add(NewController);
}
}
void ULyraBotCreationComponent::RemoveOneBot()
{
if (SpawnedBotList.Num() > 0)
{
// Right now this removes a random bot as they're all the same; could prefer to remove one
// that's high skill or low skill or etc... depending on why you are removing one
const int32 BotToRemoveIndex = FMath::RandRange(0, SpawnedBotList.Num() - 1);
AAIController* BotToRemove = SpawnedBotList[BotToRemoveIndex];
SpawnedBotList.RemoveAtSwap(BotToRemoveIndex);
if (BotToRemove)
{
// If we can find a health component, self-destruct it, otherwise just destroy the actor
if (APawn* ControlledPawn = BotToRemove->GetPawn())
{
if (ULyraHealthComponent* HealthComponent = ULyraHealthComponent::FindHealthComponent(ControlledPawn))
{
// Note, right now this doesn't work quite as desired: as soon as the player state goes away when
// the controller is destroyed, the abilities like the death animation will be interrupted immediately
HealthComponent->DamageSelfDestruct();
}
else
{
ControlledPawn->Destroy();
}
}
// Destroy the controller (will cause it to Logout, etc...)
BotToRemove->Destroy();
}
}
}
#endif