// Copyright Epic Games, Inc. All Rights Reserved. #include "GameLaunchDaemonMessageHandler.h" #include "HAL/PlatformProcess.h" #include "IMessageContext.h" #include "IOSMessageProtocol.h" #include "MessageEndpoint.h" #include "MessageEndpointBuilder.h" #include #import void FGameLaunchDaemonMessageHandler::Init() { FModuleManager::Get().LoadModuleChecked(TEXT("LaunchDaemonMessages")); MessageEndpoint = FMessageEndpoint::Builder("FGameLaunchDaemonMessageHandler") .Handling(this, &FGameLaunchDaemonMessageHandler::HandlePingMessage) .Handling(this, &FGameLaunchDaemonMessageHandler::HandleLaunchRequest); if (MessageEndpoint.IsValid()) { MessageEndpoint->Subscribe(); } } void FGameLaunchDaemonMessageHandler::Shutdown() { if (MessageEndpoint.IsValid()) { MessageEndpoint.Reset(); } } void FGameLaunchDaemonMessageHandler::HandlePingMessage(const FIOSLaunchDaemonPing& Message, const TSharedRef& Context) { if (MessageEndpoint.IsValid()) { FMessageAddress MessageSender = Context->GetSender(); MessageEndpoint->Send(FMessageEndpoint::MakeMessage(FString(FPlatformProperties::PlatformName()) + (TARGET_IPHONE_SIMULATOR ? FString(TEXT("Simulator:")) : FString(TEXT("@"))) + FString(FPlatformProcess::ComputerName()) , FString(TEXT("udid")) , FPlatformProcess::ComputerName() , "Game_Running" , [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone? "Phone" : "Tablet" , FString(TEXT("local")) , false , false , false , true ), MessageSender); } } void FGameLaunchDaemonMessageHandler::HandleLaunchRequest(const FIOSLaunchDaemonLaunchApp& Message, const TSharedRef& Context) { FString Error; // We're in the game. We need to launch ULD instead, with launch arguments that tell it to immediately relaunch. FString NewURL = TEXT("UnrealLaunchDaemon:// -directlaunch "); NSLog(@"Launching ULD\n"); // Leaving in extra variable in case text debugging needs to be injected. FString LaunchURL = NewURL + FString(Message.AppID + TEXT("://") + Message.Parameters); FPlatformProcess::LaunchURL(*LaunchURL, NULL, &Error); // Exiting the process prevents a sockets conflict with the game. // Here's the supported sequence of events: // 1) Launch ULD manually to kick things off // 2) UFE wants to launch the game and sends the LaunchRequest. // 3a) If ULD is running, it launches the game and shuts down // 3b) If the game is running, it launches ULD with special arguments and shuts down. // ULD detects that it needs to do an immediate launch, and after a few second delay to let the game shut down, // it relaunches the game. // 4) rinse and repeat. // // It's worth mentioning that exit(0) is not considered an appropriate way for shutting down a consumer app. But in this case, it works fine. exit(0); }