bool UAmethystGameInstance::Tick(float DeltaSeconds) { // Dedicated server doesn't need to worry about game state if (IsRunningDedicatedServer() == true) { return true; } MaybeChangeState(); UAmethystGameViewportClient * AmethystViewport = Cast<UAmethystGameViewportClient>(GetGameViewportClient()); if (CurrentState != AmethystGameInstanceState::WelcomeScreen) { // If at any point we aren't licensed (but we are after welcome screen) bounce them back to the welcome screen if (!bIsLicensed && CurrentState != AmethystGameInstanceState::None && !AmethystViewport->IsShowingDialog()) { const FText ReturnReason = NSLOCTEXT("ProfileMessages", "NeedLicense", "The signed in users do not have a license for this game. Please purchase AmethystGame from the Xbox Marketplace or sign in a user with a valid license."); const FText OKButton = NSLOCTEXT("DialogButtons", "OKAY", "OK"); ShowMessageThenGotoState(ReturnReason, OKButton, FText::GetEmpty(), AmethystGameInstanceState::WelcomeScreen); } // Show controller disconnected dialog if any local players have an invalid controller if (AmethystViewport != NULL && !AmethystViewport->IsShowingDialog()) { for (int i = 0; i < LocalPlayers.Num(); ++i) { if (LocalPlayers[i] && LocalPlayers[i]->GetControllerId() == -1) { AmethystViewport->ShowDialog( LocalPlayers[i], EAmethystDialogType::ControllerDisconnected, FText::Format(NSLOCTEXT("ProfileMessages", "PlayerReconnectControllerFmt", "Player {0}, please reconnect your controller."), FText::AsNumber(i + 1)), #ifdef PLATFORM_PS4 NSLOCTEXT("DialogButtons", "PS4_CrossButtonContinue", "Cross Button - Continue"), #else NSLOCTEXT("DialogButtons", "AButtonContinue", "A - Continue"), #endif FText::GetEmpty(), FOnClicked::CreateUObject(this, &UAmethystGameInstance::OnControllerReconnectConfirm), FOnClicked() ); } } } } return true; }
bool UGameInstance::RemoveLocalPlayer(ULocalPlayer* ExistingPlayer) { // FIXME: Notify server we want to leave the game if this is an online game if (ExistingPlayer->PlayerController != NULL) { // FIXME: Do this all inside PlayerRemoved? ExistingPlayer->PlayerController->CleanupGameViewport(); // Destroy the player's actors. if ( ExistingPlayer->PlayerController->Role == ROLE_Authority ) { ExistingPlayer->PlayerController->Destroy(); } } // Remove the player from the context list const int32 OldIndex = LocalPlayers.Find(ExistingPlayer); if (ensure(OldIndex != INDEX_NONE)) { ExistingPlayer->PlayerRemoved(); LocalPlayers.RemoveAt(OldIndex); // Notify the viewport so the viewport can do the fixups, resize, etc if (GetGameViewportClient() != NULL) { GetGameViewportClient()->NotifyPlayerRemoved(OldIndex, ExistingPlayer); } } // Disassociate this viewport client from the player. // Do this after notifications, as some of them require the ViewportClient. ExistingPlayer->ViewportClient = NULL; UE_LOG(LogPlayerManagement, Log, TEXT("UGameInstance::RemovePlayer: Removed player %s with ControllerId %i at index %i (%i remaining players)"), *ExistingPlayer->GetName(), ExistingPlayer->GetControllerId(), OldIndex, LocalPlayers.Num()); return true; }
int32 UGameInstance::AddLocalPlayer(ULocalPlayer* NewLocalPlayer, int32 ControllerId) { if (NewLocalPlayer == NULL) { return INDEX_NONE; } const int32 InsertIndex = LocalPlayers.Num(); // Add to list LocalPlayers.AddUnique(NewLocalPlayer); // Notify the player he/she was added NewLocalPlayer->PlayerAdded(GetGameViewportClient(), ControllerId); // Notify the viewport that we added a player (so it can update splitscreen settings, etc) if ( GetGameViewportClient() != NULL ) { GetGameViewportClient()->NotifyPlayerAdded(InsertIndex, NewLocalPlayer); } return InsertIndex; }
ULocalPlayer* UGameInstance::CreateLocalPlayer(int32 ControllerId, FString& OutError, bool bSpawnActor) { checkf(GetEngine()->LocalPlayerClass != NULL); ULocalPlayer* NewPlayer = NULL; int32 InsertIndex = INDEX_NONE; const int32 MaxSplitscreenPlayers = (GetGameViewportClient() != NULL) ? GetGameViewportClient()->MaxSplitscreenPlayers : 1; if (FindLocalPlayerFromControllerId( ControllerId ) != NULL) { OutError = FString::Printf(TEXT("A local player already exists for controller ID %d,"), ControllerId); } else if (LocalPlayers.Num() < MaxSplitscreenPlayers) { // If the controller ID is not specified then find the first available if (ControllerId < 0) { for (ControllerId = 0; ControllerId < MaxSplitscreenPlayers; ++ControllerId) { if (FindLocalPlayerFromControllerId( ControllerId ) == NULL) { break; } } check(ControllerId < MaxSplitscreenPlayers); } else if (ControllerId >= MaxSplitscreenPlayers) { UE_LOG(LogPlayerManagement, Warning, TEXT("Controller ID (%d) is unlikely to map to any physical device, so this player will not receive input"), ControllerId); } NewPlayer = NewObject<ULocalPlayer>(GetEngine(), GetEngine()->LocalPlayerClass); InsertIndex = AddLocalPlayer(NewPlayer, ControllerId); if (bSpawnActor && InsertIndex != INDEX_NONE && GetWorld() != NULL) { if (GetWorld()->GetNetMode() != NM_Client) { // server; spawn a new PlayerController immediately if (!NewPlayer->SpawnPlayActor("", OutError, GetWorld())) { RemoveLocalPlayer(NewPlayer); NewPlayer = NULL; } } else { // client; ask the server to let the new player join NewPlayer->SendSplitJoin(); } } } else { OutError = FString::Printf(TEXT( "Maximum number of players (%d) already created. Unable to create more."), MaxSplitscreenPlayers); } if (OutError != TEXT("")) { UE_LOG(LogPlayerManagement, Log, TEXT("UPlayer* creation failed with error: %s"), *OutError); } return NewPlayer; }
bool UGameInstance::StartPIEGameInstance(ULocalPlayer* LocalPlayer, bool bInSimulateInEditor, bool bAnyBlueprintErrors, bool bStartInSpectatorMode) { UEditorEngine* const EditorEngine = CastChecked<UEditorEngine>(GetEngine()); ULevelEditorPlaySettings const* PlayInSettings = GetDefault<ULevelEditorPlaySettings>(); const EPlayNetMode PlayNetMode = [&PlayInSettings]{ EPlayNetMode NetMode(PIE_Standalone); return (PlayInSettings->GetPlayNetMode(NetMode) ? NetMode : PIE_Standalone); }(); // for clients, just connect to the server if (PlayNetMode == PIE_Client) { FString Error; FURL BaseURL = WorldContext->LastURL; if (EditorEngine->Browse(*WorldContext, FURL(&BaseURL, TEXT("127.0.0.1"), (ETravelType)TRAVEL_Absolute), Error) == EBrowseReturnVal::Pending) { EditorEngine->TransitionType = TT_WaitingToConnect; } else { FMessageDialog::Open(EAppMsgType::Ok, FText::Format(NSLOCTEXT("UnrealEd", "Error_CouldntLaunchPIEClient", "Couldn't Launch PIE Client: {0}"), FText::FromString(Error))); return false; } } else { // we're going to be playing in the current world, get it ready for play UWorld* const PlayWorld = GetWorld(); // make a URL FURL URL; // If the user wants to start in spectator mode, do not use the custom play world for now if (EditorEngine->UserEditedPlayWorldURL.Len() > 0 && !bStartInSpectatorMode) { // If the user edited the play world url. Verify that the map name is the same as the currently loaded map. URL = FURL(NULL, *EditorEngine->UserEditedPlayWorldURL, TRAVEL_Absolute); if (URL.Map != PIEMapName) { // Ensure the URL map name is the same as the generated play world map name. URL.Map = PIEMapName; } } else { // The user did not edit the url, just build one from scratch. URL = FURL(NULL, *EditorEngine->BuildPlayWorldURL(*PIEMapName, bStartInSpectatorMode), TRAVEL_Absolute); } // If a start location is specified, spawn a temporary PlayerStartPIE actor at the start location and use it as the portal. AActor* PlayerStart = NULL; if (EditorEngine->SpawnPlayFromHereStart(PlayWorld, PlayerStart, EditorEngine->PlayWorldLocation, EditorEngine->PlayWorldRotation) == false) { // failed to create "play from here" playerstart FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Error_FailedCreatePlayFromHerePlayerStart", "Failed to create PlayerStart at desired starting location.")); return false; } if (!PlayWorld->SetGameMode(URL)) { // Setting the game mode failed so bail FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Error_FailedCreateEditorPreviewWorld", "Failed to create editor preview world.")); return false; } // Make sure "always loaded" sub-levels are fully loaded PlayWorld->FlushLevelStreaming(EFlushLevelStreamingType::Visibility); UNavigationSystem::InitializeForWorld(PlayWorld, LocalPlayers.Num() > 0 ? FNavigationSystem::PIEMode : FNavigationSystem::SimulationMode); PlayWorld->CreateAISystem(); PlayWorld->InitializeActorsForPlay(URL); // @todo, just use WorldContext.GamePlayer[0]? if (LocalPlayer) { FString Error; if (!LocalPlayer->SpawnPlayActor(URL.ToString(1), Error, PlayWorld)) { FMessageDialog::Open(EAppMsgType::Ok, FText::Format(NSLOCTEXT("UnrealEd", "Error_CouldntSpawnPlayer", "Couldn't spawn player: {0}"), FText::FromString(Error))); return false; } } UGameViewportClient* const GameViewport = GetGameViewportClient(); if (GameViewport != NULL && GameViewport->Viewport != NULL) { // Stream any levels now that need to be loaded before the game starts GEngine->BlockTillLevelStreamingCompleted(PlayWorld); } if (PlayNetMode == PIE_ListenServer) { // start listen server with the built URL PlayWorld->Listen(URL); } PlayWorld->BeginPlay(); } return true; }
void UAmethystGameInstance::HandleControllerPairingChanged(int GameUserIndex, const FUniqueNetId& PreviousUser, const FUniqueNetId& NewUser) { if (CurrentState == AmethystGameInstanceState::WelcomeScreen) { // Don't care about pairing changes at welcome screen return; } #if Amethyst_CONSOLE_UI && PLATFORM_XBOXONE if (IgnorePairingChangeForControllerId != -1 && GameUserIndex == IgnorePairingChangeForControllerId) { // We were told to ignores IgnorePairingChangeForControllerId = -1; // Reset now so there there is no chance this remains in a bad state return; } if (PreviousUser.IsValid() && !NewUser.IsValid()) { // Treat this as a disconnect or signout, which is handled somewhere else return; } if (!PreviousUser.IsValid() && NewUser.IsValid()) { // Treat this as a signin ULocalPlayer * ControlledLocalPlayer = FindLocalPlayerFromControllerId(GameUserIndex); if (ControlledLocalPlayer != NULL && !ControlledLocalPlayer->GetCachedUniqueNetId().IsValid()) { // If a player that previously selected "continue without saving" signs into this controller, move them back to welcome screen HandleSignInChangeMessaging(); } return; } // Find the local player currently being controlled by this controller ULocalPlayer * ControlledLocalPlayer = FindLocalPlayerFromControllerId(GameUserIndex); // See if the newly assigned profile is in our local player list ULocalPlayer * NewLocalPlayer = FindLocalPlayerFromUniqueNetId(NewUser); // If the local player being controlled is not the target of the pairing change, then give them a chance // to continue controlling the old player with this controller if (ControlledLocalPlayer != nullptr && ControlledLocalPlayer != NewLocalPlayer) { UAmethystGameViewportClient * AmethystViewport = Cast<UAmethystGameViewportClient>(GetGameViewportClient()); if (AmethystViewport != nullptr) { AmethystViewport->ShowDialog( nullptr, EAmethystDialogType::Generic, NSLOCTEXT("ProfileMessages", "PairingChanged", "Your controller has been paired to another profile, would you like to switch to this new profile now? Selecting YES will sign out of the previous profile."), NSLOCTEXT("DialogButtons", "YES", "A - YES"), NSLOCTEXT("DialogButtons", "NO", "B - NO"), FOnClicked::CreateUObject(this, &UAmethystGameInstance::OnPairingUseNewProfile), FOnClicked::CreateUObject(this, &UAmethystGameInstance::OnPairingUsePreviousProfile) ); } } #endif }