haxis/Source/UnrealProject/GameState/MenuController.cpp

332 lines
9.2 KiB
C++

// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "DefaultGameInstance.h"
#include "MenuController.h"
#include "SplashScreen.h"
#include "LobbyMenu.h"
#include "CharacterSettings.h"
#include "StartPromptScreen.h"
#include "PlayerStateBase.h"
#include "GameStateBase.h"
#include "SessionManager.h"
#include "TransitionScreen.h"
#include "ScreenOverlay.h"
#include "SkillTreeWidget.h"
#include "DefaultPlayerController.h"
#include "MenuScreen.h"
#include "MenuGameMode.h"
static UClass* menuWidgetClass = nullptr;
static UClass* lobbyWidgetClass = nullptr;
static UClass* splashScreenClass = nullptr;
static UClass* startScreenClass = nullptr;
static UClass* skillTreeClass = nullptr;
static TSubclassOf<UMenuPanel> mainSubMenuClass;
AMenuController::AMenuController(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
menuWidgetClass = ConstructorHelpers::FClassFinder<UMenuScreen>(TEXT("/Game/Assets/GUI/WEEGEE_Menu")).Class;
lobbyWidgetClass = ConstructorHelpers::FClassFinder<ULobbyMenu>(TEXT("/Game/Assets/GUI/WEEGEE_Lobby")).Class;
splashScreenClass = ConstructorHelpers::FClassFinder<USplashScreen>(TEXT("/Game/Assets/GUI/WEEGEE_Splash")).Class;
startScreenClass = ConstructorHelpers::FClassFinder<UStartPromptScreen>(TEXT("/Game/Assets/GUI/WEEGEE_StartPrompt")).Class;
skillTreeClass = ConstructorHelpers::FClassFinder<USkillTreeWidget>(TEXT("/Game/Assets/GUI/WEEGEE_SkillTree")).Class;
mainSubMenuClass = ConstructorHelpers::FClassFinder<UMenuPanel>(TEXT("/Game/Assets/GUI/Menus/WEEGEE_MainSubMenu")).Class;
this->bShowMouseCursor = true;
m_inLobby = false;
PrimaryActorTick.bCanEverTick = true;
}
void AMenuController::BeginPlay()
{
Super::BeginPlay();
if(IsLocalController())
{
// Create skill tree widget
skillTree = CreateWidget<USkillTreeWidget>(GetWorld(), skillTreeClass);
skillTree->AddToViewport(5);
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetGameInstance());
UWorld* world = GetWorld();
bool showSplash = !inst->splashScreenShown;
if(world->WorldType == EWorldType::PIE)
showSplash = false;
if(inst->sessionManager->HasNetConnection())
showSplash = false;
if(showSplash)
{
m_splash = CreateWidget<USplashScreen>(this, splashScreenClass);
m_splash->onDone.AddDynamic(this, &AMenuController::m_OnSplashScreenEnded);
check(m_splash);
m_splash->AddToViewport();
}
else
{
m_OnStartPromptClosed();
}
inst->splashScreenShown = true;
inst->sessionManager->onAcceptInvite.AddUObject(this, &AMenuController::m_OnInviteAccepted);
}
}
void AMenuController::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetGameInstance());
inst->sessionManager->onAcceptInvite.RemoveAll(this);
}
void AMenuController::NotifyLoadedWorld(FName WorldPackageName, bool bFinalDest)
{
Super::NotifyLoadedWorld(WorldPackageName, bFinalDest);
if(bFinalDest)
{
GPRINT("Final level loaded for player controller " + GetName());
if(transitionScreen)
{
// Hide transition screen
transitionScreen->OnHide();
}
}
}
void AMenuController::Destroyed()
{
GPRINT("Menu controller destroyed " + GetName());
Super::Destroyed();
}
void AMenuController::PreClientTravel(const FString& PendingURL, ETravelType TravelType, bool bIsSeamlessTravel)
{
if(bIsSeamlessTravel)
{
// Hide lobby UI
if(lobbyMenu)
lobbyMenu->OnHide();
// Close all the menu
if(m_splash)
m_splash->RemoveFromViewport();
if(m_startScreen)
m_startScreen->RemoveFromViewport();
if(lobbyMenu)
lobbyMenu->RemoveFromViewport();
if(mainMenu)
mainMenu->RemoveFromViewport();
if(skillTree)
skillTree->RemoveFromViewport();
mainMenu = nullptr;
lobbyMenu = nullptr;
skillTree = nullptr;
m_startScreen = nullptr;
m_splash = nullptr;
// Show transition screen
transitionScreen->OnShow();
GPRINT("Seamless travel on player " + GetName() + " to \"" + PendingURL + "\"");
}
else
{
GPRINT("Regular travel on player to " + GetName() + " to \"" + PendingURL + "\"");
}
Super::PreClientTravel(PendingURL, TravelType, bIsSeamlessTravel);
}
void AMenuController::SeamlessTravelFrom(class APlayerController* OldPC)
{
Super::SeamlessTravelFrom(OldPC);
GPRINT("Seamless travel to menu [" + GetName() + "]<-[" + OldPC->GetName() + "]");
}
void AMenuController::SeamlessTravelTo(class APlayerController* NewPC)
{
Super::SeamlessTravelTo(NewPC);
GPRINT("Seamless travel to game level [" + GetName() + "]->[" + NewPC->GetName() + "]");
APlayerStateBase* pcbn = Cast<APlayerStateBase>(NewPC->PlayerState);
APlayerStateBase* pcbo = GetPlayerState<APlayerStateBase>();
check(pcbn && pcbo);
pcbn->Transfer(pcbo);
ADefaultPlayerController* newDPC = Cast<ADefaultPlayerController>(NewPC);
if(newDPC)
{
newDPC->setupState = setupState;
}
}
void AMenuController::OnLearnSkill(class UBaseSkillObject* object)
{
}
void AMenuController::OnUnlearnSkill(class UBaseSkillObject* object)
{
}
void AMenuController::OnEnterLobby()
{
if(m_inLobby)
return;
if(mainMenu && lobbyMenu)
{
mainMenu->OnHide();
lobbyMenu->OnShow();
lobbyMenu->OnLobbyEnter();
m_inLobby = true;
OnRep_PlayerState();
}
else
{
GERROR("wat");
}
// Set Default character slot
/// TODO: Add selector widget
//UCharacterSettings* settings = Cast<UDefaultGameInstance>(GetGameInstance())->GetCharacterSettings();
//if(settings->characterSaves.Num() > 0)
//{
// const FCharacterSave& save = settings->characterSaves[0];
// FPlayerSetupState pss;
// pss.customizations = save.characterCustomization;
// pss.skills = save.skillTreeState;
// pss.characterClass = save.characterClass;
// SetSetupState(pss);
//}
}
/// TODO, validate skill tree / customization here
bool AMenuController::SetSetupState_Validate(const FPlayerSetupState& state)
{
return true;
}
void AMenuController::SetSetupState_Implementation(const FPlayerSetupState& state)
{
setupState = state;
// Resync the lobby
UWorld* const world = GetWorld();
if (IsValid(world))
{
AGameStateBase* const gameState = Cast<AGameStateBase>(GetWorld()->GetGameState());
if (IsValid(gameState))
gameState->OnPlayerStateChange.Broadcast(this);
}
}
void AMenuController::OnRep_PlayerState()
{
// Request a team if we're in a lobby
if(m_inLobby)
{
m_AutoRequestTeam();
}
// Send to the server that we got our player state
m_OnClientInitialized();
}
void AMenuController::SwitchToMenu()
{
mainMenu->OnShow();
lobbyMenu->OnHide();
m_inLobby = false;
}
bool AMenuController::m_OnClientInitialized_Validate()
{
return true;
}
void AMenuController::m_OnClientInitialized_Implementation()
{
AMenuGameMode* gm = Cast<AMenuGameMode>(GetWorld()->GetAuthGameMode());
if(gm)
{
gm->onPlayerJoined.Broadcast(this);
}
}
void AMenuController::m_OnInviteAccepted(bool success, const FOnlineSessionSearchResult& result)
{
if(success)
{
GPRINT("Accepted an invite");
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetGameInstance());
inst->sessionManager->onJoinSessionComplete.AddUObject(this, &AMenuController::m_OnSessionJoined);
inst->sessionManager->JoinSession(result);
}
}
void AMenuController::m_OnSessionJoined(int32 result)
{
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(GetGameInstance());
inst->sessionManager->onJoinSessionComplete.RemoveAll(this);
if(result == EOnJoinSessionCompleteResult::Success)
{
ClientTravel(inst->sessionManager->joinConnectionString, ETravelType::TRAVEL_Absolute);
}
else
{
TArray<FString> options;
options.Add("OK");
overlay->ShowMessageBox("Error", FString("Failed to accept invite (") + FString::FromInt(result) + ")", options);
GERROR("Failed to join session invite");
SwitchToMenu();
}
}
void AMenuController::m_AutoRequestTeam()
{
UWorld* world = GetWorld();
APlayerStateBase* state = GetPlayerState<APlayerStateBase>();
if(state)
{
state->AutoAssignTeam();
if(world->IsPlayInEditor())
state->SetReadyState(true);
//GetWorld()->GetTimerManager().ClearTimer(m_teamRequestTimer);
}
}
void AMenuController::m_OnSplashScreenEnded()
{
m_splash = nullptr;
// Create start prompt
m_startScreen = CreateWidget<UStartPromptScreen>(this, startScreenClass);
check(m_startScreen);
m_startScreen->onClosed.AddUObject(this, &AMenuController::m_OnStartPromptClosed);
m_startScreen->AddToViewport();
}
void AMenuController::m_OnStartPromptClosed()
{
m_startScreen = nullptr;
// Open main menu
lobbyMenu = CreateWidget<ULobbyMenu>(this, lobbyWidgetClass);
lobbyMenu->AddToViewport();
mainMenu = CreateWidget<UMenuScreen>(this, menuWidgetClass);
mainMenu->AddToViewport();
mainMenu->OnShow();
mainMenu->OpenScreenMenu(mainSubMenuClass);
// Enter lobby when initially connected
UWorld* world = GetWorld();
UDefaultGameInstance* inst = Cast<UDefaultGameInstance>(world->GetGameInstance());
if(inst->sessionManager->HasNetConnection())
{
OnEnterLobby();
}
}
bool AMenuController::WorldIsPIE() const
{
UWorld* const world = GetWorld();
if (!IsValid(world)) return false;
return world->WorldType == EWorldType::PIE;
}