// 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 mainSubMenuClass; AMenuController::AMenuController(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { menuWidgetClass = ConstructorHelpers::FClassFinder(TEXT("/Game/Assets/GUI/WEEGEE_Menu")).Class; lobbyWidgetClass = ConstructorHelpers::FClassFinder(TEXT("/Game/Assets/GUI/WEEGEE_Lobby")).Class; splashScreenClass = ConstructorHelpers::FClassFinder(TEXT("/Game/Assets/GUI/WEEGEE_Splash")).Class; startScreenClass = ConstructorHelpers::FClassFinder(TEXT("/Game/Assets/GUI/WEEGEE_StartPrompt")).Class; skillTreeClass = ConstructorHelpers::FClassFinder(TEXT("/Game/Assets/GUI/WEEGEE_SkillTree")).Class; mainSubMenuClass = ConstructorHelpers::FClassFinder(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(GetWorld(), skillTreeClass); skillTree->AddToViewport(5); UDefaultGameInstance* inst = Cast(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(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(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(NewPC->PlayerState); APlayerStateBase* pcbo = GetPlayerState(); check(pcbn && pcbo); pcbn->Transfer(pcbo); ADefaultPlayerController* newDPC = Cast(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(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(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(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(GetGameInstance()); inst->sessionManager->onJoinSessionComplete.AddUObject(this, &AMenuController::m_OnSessionJoined); inst->sessionManager->JoinSession(result); } } void AMenuController::m_OnSessionJoined(int32 result) { UDefaultGameInstance* inst = Cast(GetGameInstance()); inst->sessionManager->onJoinSessionComplete.RemoveAll(this); if(result == EOnJoinSessionCompleteResult::Success) { ClientTravel(inst->sessionManager->joinConnectionString, ETravelType::TRAVEL_Absolute); } else { TArray 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(); 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(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(this, lobbyWidgetClass); lobbyMenu->AddToViewport(); mainMenu = CreateWidget(this, menuWidgetClass); mainMenu->AddToViewport(); mainMenu->OnShow(); mainMenu->OpenScreenMenu(mainSubMenuClass); // Enter lobby when initially connected UWorld* world = GetWorld(); UDefaultGameInstance* inst = Cast(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; }