166 lines
5.0 KiB
C++
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 |