Lesson 35 - Get Compute Auth Token Working
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
using UnrealBuildTool;
|
||||
using System.IO;
|
||||
|
||||
public class GameLiftClientSDK : ModuleRules
|
||||
{
|
||||
public GameLiftClientSDK(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Engine", "Core", "CoreUObject", "InputCore", "Projects" });
|
||||
PrivateDependencyModuleNames.AddRange(new string[] { });
|
||||
|
||||
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "Public"));
|
||||
PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "Private"));
|
||||
|
||||
// Add dependencies needed by the UI code for testing widgets.
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "WebBrowserWidget", "SlateCore", "HTTP", "Json", "JsonUtilities", "HeadMountedDisplay", "UMG" });
|
||||
|
||||
PublicDefinitions.Add("USE_IMPORT_EXPORT");
|
||||
|
||||
if (Target.Type == TargetRules.TargetType.Editor || Target.Type == TargetRules.TargetType.Client)
|
||||
{
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "AWSSDK", "CoreSDK" });
|
||||
|
||||
PublicDefinitions.Add("WITH_GAMELIFT_CLIENT=1");
|
||||
}
|
||||
else
|
||||
{
|
||||
PublicDefinitions.Add("WITH_GAMELIFT_CLIENT=0");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "GameLiftClientLog.h"
|
||||
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
DEFINE_LOG_CATEGORY(GameLiftClientLog);
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
DECLARE_LOG_CATEGORY_EXTERN(GameLiftClientLog, Log, All);
|
||||
#endif
|
||||
@@ -0,0 +1,208 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "GameLiftClientSDK.h"
|
||||
#include "Core.h"
|
||||
#include "Interfaces/IPluginManager.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include "HAL/UnrealMemory.h"
|
||||
#include "Serializer.h"
|
||||
#include "GameLiftClientLog.h"
|
||||
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/AllowWindowsPlatformTypes.h"
|
||||
#endif
|
||||
|
||||
#include "aws/core/Aws.h"
|
||||
#include "aws/core/utils/logging/LogLevel.h"
|
||||
#include "aws/core/utils/memory/MemorySystemInterface.h"
|
||||
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
#include "aws/gamelift/GameLiftClient.h"
|
||||
#include "aws/gamelift/model/DescribeGameSessionsRequest.h"
|
||||
#include "aws/gamelift/model/CreateGameSessionRequest.h"
|
||||
#include "aws/gamelift/model/CreatePlayerSessionRequest.h"
|
||||
#include "aws/gamelift/model/CreatePlayerSessionsRequest.h"
|
||||
#include "aws/gamelift/model/DescribePlayerSessionsRequest.h"
|
||||
#include "aws/gamelift/core/awsclients/api_initializer.h"
|
||||
#include "aws/gamelift/core/exports.h"
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/HideWindowsPlatformTypes.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FGameLiftClientSDKModule"
|
||||
|
||||
void FGameLiftClientSDKModule::StartupModule()
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
auto LogProxy = [](unsigned int InLevel, const char* InMessage, int InSize)
|
||||
{
|
||||
UE_LOG(GameLiftClientLog, Log, TEXT("********* %s"), UTF8_TO_TCHAR(InMessage));
|
||||
};
|
||||
|
||||
GameLift::AwsApiInitializer::Initialize(LogProxy, this);
|
||||
GameLiftClientHandle = GameLiftClientInstanceCreate();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FGameLiftClientSDKModule::ShutdownModule()
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
GameLiftClientInstanceRelease(GameLiftClientHandle);
|
||||
GameLift::AwsApiInitializer::Shutdown();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FGameLiftClientSDKModule::ConfigureClient(const FString& CredentialsName)
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
std::string StdCredentialsName = AWSSerializer::FSToStdS(CredentialsName);
|
||||
|
||||
if (GameLiftClientHandle)
|
||||
{
|
||||
GameLiftClientInstanceRelease(GameLiftClientHandle);
|
||||
GameLiftClientHandle = nullptr;
|
||||
}
|
||||
|
||||
GameLiftClientHandle = GameLiftClientInstanceCreateWithCredentials(StdCredentialsName.c_str());
|
||||
|
||||
return GameLiftClientHandle != nullptr;
|
||||
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
namespace
|
||||
{
|
||||
FuncErrorCallback ErrorCallback = [](DISPATCH_RECEIVER_HANDLE ErrorReceiver, GAMELIFT_ERROR_INFO* ErrorInfo) -> void
|
||||
{
|
||||
FString* Error = reinterpret_cast<FString*>(ErrorReceiver);
|
||||
*Error = ErrorInfo->errorMessage;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
FGL_GameSession FGameLiftClientSDKModule::CreateGameSession(size_t MaximumPlayerCount, const FString& FleetId, FString& ErrorMsg, const FString& CustomLocation, const FString& EndPoint)
|
||||
{
|
||||
FGL_GameSession Result;
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
|
||||
std::string StdEndPoint = AWSSerializer::FSToStdS(EndPoint);
|
||||
if (!EndPoint.IsEmpty())
|
||||
{
|
||||
GameLiftClientOverrideEndpoint(GameLiftClientHandle, StdEndPoint.c_str());
|
||||
}
|
||||
|
||||
GAMELIFT_GAMESESSION_CREATE_REQUEST CreateSessionRequest;
|
||||
|
||||
std::string StdFleetId = AWSSerializer::FSToStdS(FleetId);
|
||||
CreateSessionRequest.fleetId = StdFleetId.c_str();
|
||||
CreateSessionRequest.maximumPlayerSessionCount = &MaximumPlayerCount;
|
||||
CreateSessionRequest.errorCb = ErrorCallback;
|
||||
CreateSessionRequest.errorReceiver = &ErrorMsg;
|
||||
|
||||
std::string StdCustomLocation = AWSSerializer::FSToStdS(CustomLocation);
|
||||
if (!CustomLocation.IsEmpty())
|
||||
{
|
||||
CreateSessionRequest.location = StdCustomLocation.c_str();
|
||||
}
|
||||
|
||||
auto GameSessionInstance = GameLiftGameSessionCreate(GameLiftClientHandle, &CreateSessionRequest);
|
||||
|
||||
if (GameSessionInstance != nullptr)
|
||||
{
|
||||
Result = GL_Utils::AwsGameSessionToUe(GameSessionInstance);
|
||||
GameLiftGameSessionRelease(GameSessionInstance);
|
||||
}
|
||||
#endif
|
||||
return Result;
|
||||
}
|
||||
|
||||
TArray<FGL_GameSession> FGameLiftClientSDKModule::DescribeGameSessions(const FString& FleetId, const FString& StatusFilter, FString& ErrorMsg, const FString& EndPoint)
|
||||
{
|
||||
TArray<FGL_GameSession> Result;
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
|
||||
std::string StdEndPoint = AWSSerializer::FSToStdS(EndPoint);
|
||||
if (!EndPoint.IsEmpty())
|
||||
{
|
||||
GameLiftClientOverrideEndpoint(GameLiftClientHandle, StdEndPoint.c_str());
|
||||
}
|
||||
|
||||
GAMELIFT_DESCRIBE_GAMESESSIONS_REQUEST DescribeGameSessionsRequest;
|
||||
|
||||
std::string StdString;
|
||||
if(!FleetId.IsEmpty())
|
||||
{
|
||||
StdString = AWSSerializer::FSToStdS(FleetId);
|
||||
DescribeGameSessionsRequest.fleetId = StdString.c_str();
|
||||
}
|
||||
|
||||
std::string StdStatusFilter;
|
||||
if(!StatusFilter.IsEmpty())
|
||||
{
|
||||
StdStatusFilter = AWSSerializer::FSToStdS(StatusFilter);
|
||||
DescribeGameSessionsRequest.statusFilter = StdStatusFilter.c_str();
|
||||
}
|
||||
|
||||
DescribeGameSessionsRequest.errorCb = ErrorCallback;
|
||||
DescribeGameSessionsRequest.errorReceiver = &ErrorMsg;
|
||||
|
||||
FuncGameSessionInfoCallback ResultCallback = [](DISPATCH_RECEIVER_HANDLE DispatchReceiver, GAMELIFT_GAMESESSION_INFO* GameSessionInfo) -> bool
|
||||
{
|
||||
auto Result = reinterpret_cast<TArray<FGL_GameSession>*>(DispatchReceiver);
|
||||
Result->Add(GL_Utils::AwsGameSessionToUe(*GameSessionInfo));
|
||||
return false; // iterate over all sessions, do not filter out any of them
|
||||
};
|
||||
|
||||
DescribeGameSessionsRequest.dispatchReceiver = &Result;
|
||||
DescribeGameSessionsRequest.resultCb = ResultCallback;
|
||||
|
||||
GameLiftDescribeGameSessions(GameLiftClientHandle, &DescribeGameSessionsRequest);
|
||||
|
||||
#endif
|
||||
return Result;
|
||||
}
|
||||
|
||||
FGL_PlayerSession FGameLiftClientSDKModule::CreatePlayerSession(const FString& GameSessionId, const FString& PlayerData, const FString& PlayerId, FString& ErrorMsg, const FString& EndPoint)
|
||||
{
|
||||
FGL_PlayerSession Result;
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
|
||||
std::string StdEndPoint = AWSSerializer::FSToStdS(EndPoint);
|
||||
if (!EndPoint.IsEmpty())
|
||||
{
|
||||
GameLiftClientOverrideEndpoint(GameLiftClientHandle, StdEndPoint.c_str());
|
||||
}
|
||||
|
||||
GAMELIFT_PLAYERSESSION_CREATE_REQUEST CreateSessionRequest;
|
||||
std::string StdGameSessionId = TCHAR_TO_ANSI(*GameSessionId); // Note: AWSSerializer::FSToStdS does not work due to encoding issue. The converted string is not expected.
|
||||
std::string StdPlayerId = AWSSerializer::FSToStdS(PlayerId);
|
||||
std::string StdPlayerData = AWSSerializer::FSToStdS(PlayerData);
|
||||
CreateSessionRequest.gameSessionId = StdGameSessionId.c_str();
|
||||
CreateSessionRequest.playerId = StdPlayerId.c_str();
|
||||
CreateSessionRequest.playerData = StdPlayerData.c_str();
|
||||
CreateSessionRequest.errorCb = ErrorCallback;
|
||||
CreateSessionRequest.errorReceiver = &ErrorMsg;
|
||||
|
||||
auto PlayerSessionInstance = GameLiftPlayerSessionCreate(GameLiftClientHandle, &CreateSessionRequest);
|
||||
|
||||
if (PlayerSessionInstance != nullptr)
|
||||
{
|
||||
Result = GL_Utils::AwsPlayerSessionToUe(PlayerSessionInstance);
|
||||
GameLiftPlayerSessionRelease(PlayerSessionInstance);
|
||||
}
|
||||
#endif
|
||||
return Result;
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FGameLiftClientSDKModule, GameLiftClientSDK)
|
||||
@@ -0,0 +1,229 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameLiftClientSDKModels.h"
|
||||
#include "CoreMinimal.h"
|
||||
#include "Serializer.h"
|
||||
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/AllowWindowsPlatformTypes.h"
|
||||
#endif
|
||||
|
||||
#include "aws/core/Aws.h"
|
||||
#include "aws/core/utils/DateTime.h"
|
||||
#include "aws/gamelift/model/GameSession.h"
|
||||
#include "aws/gamelift/model/PlayerSession.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/HideWindowsPlatformTypes.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
namespace GL_Utils
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
FGL_GameSession AwsGameSessionToUe(const GAMELIFT_GAMESESSION_INFO& GameSessionInfo)
|
||||
{
|
||||
FGL_GameSession Result;
|
||||
|
||||
if (GameSessionInfo.gameSessionId)
|
||||
{
|
||||
Result.GameSessionId = AWSSerializer::ASToFS(GameSessionInfo.gameSessionId);
|
||||
}
|
||||
|
||||
if (GameSessionInfo.fleetId)
|
||||
{
|
||||
Result.FleetId = AWSSerializer::ASToFS(GameSessionInfo.fleetId);
|
||||
}
|
||||
|
||||
if (GameSessionInfo.ipAddress)
|
||||
{
|
||||
Result.IpAddress = AWSSerializer::ASToFS(GameSessionInfo.ipAddress);
|
||||
}
|
||||
|
||||
if (GameSessionInfo.dnsName)
|
||||
{
|
||||
Result.DnsName = AWSSerializer::ASToFS(GameSessionInfo.dnsName);
|
||||
}
|
||||
|
||||
Result.Status = static_cast<EGL_GameSessionStatus>(GameSessionInfo.status);
|
||||
Result.CurrentPlayerSessionCount = GameSessionInfo.currentPlayerSessionCount;
|
||||
Result.MaximumPlayerSessionCount = GameSessionInfo.maximumPlayerSessionCount;
|
||||
Result.Port = GameSessionInfo.port;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
FGL_GameSession AwsGameSessionToUe(GAMELIFT_GAMESESSION_INSTANCE_HANDLE GameSession)
|
||||
{
|
||||
FGL_GameSession Result;
|
||||
GAMELIFT_GAMESESSION_INFO GameSessionInfo;
|
||||
|
||||
GameLiftGameSessionGetInfo(GameSession, &GameSessionInfo);
|
||||
|
||||
return AwsGameSessionToUe(GameSessionInfo);
|
||||
}
|
||||
|
||||
FGL_PlayerSession AwsPlayerSessionToUe(GAMELIFT_PLAYERSESSION_INSTANCE_HANDLE PlayerSession)
|
||||
{
|
||||
FGL_PlayerSession Result;
|
||||
|
||||
GAMELIFT_PLAYERSESSION_INFO PlayerSessionInfo;
|
||||
|
||||
GameLiftPlayerSessionGetInfo(PlayerSession, &PlayerSessionInfo);
|
||||
|
||||
if (PlayerSessionInfo.dnsName)
|
||||
{
|
||||
Result.DnsName = AWSSerializer::ASToFS(PlayerSessionInfo.dnsName);
|
||||
}
|
||||
|
||||
if (PlayerSessionInfo.fleetArn)
|
||||
{
|
||||
Result.FleetArn = AWSSerializer::ASToFS(PlayerSessionInfo.fleetArn);
|
||||
}
|
||||
|
||||
if (PlayerSessionInfo.fleetId)
|
||||
{
|
||||
Result.FleetId = AWSSerializer::ASToFS(PlayerSessionInfo.fleetId);
|
||||
}
|
||||
|
||||
if (PlayerSessionInfo.gameSessionId)
|
||||
{
|
||||
Result.GameSessionId = AWSSerializer::ASToFS(PlayerSessionInfo.gameSessionId);
|
||||
}
|
||||
|
||||
if (PlayerSessionInfo.ipAddress)
|
||||
{
|
||||
Result.IpAddress = AWSSerializer::ASToFS(PlayerSessionInfo.ipAddress);
|
||||
}
|
||||
|
||||
if (PlayerSessionInfo.playerData)
|
||||
{
|
||||
Result.PlayerData = AWSSerializer::ASToFS(PlayerSessionInfo.playerData);
|
||||
}
|
||||
|
||||
if (PlayerSessionInfo.playerId)
|
||||
{
|
||||
Result.PlayerId = AWSSerializer::ASToFS(PlayerSessionInfo.playerId);
|
||||
}
|
||||
|
||||
if (PlayerSessionInfo.playerSessionId)
|
||||
{
|
||||
Result.PlayerSessionId = AWSSerializer::ASToFS(PlayerSessionInfo.playerSessionId);
|
||||
}
|
||||
|
||||
Result.Port = PlayerSessionInfo.port;
|
||||
Result.Status = static_cast<EGL_PlayerSessionStatus>(PlayerSessionInfo.status);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
FGL_GameSession AwsGameSessionToUe(const Aws::GameLift::Model::GameSession& GameSessionIn)
|
||||
{
|
||||
FGL_GameSession Result;
|
||||
if (GameSessionIn.GameSessionIdHasBeenSet())
|
||||
{
|
||||
Result.GameSessionId = AWSSerializer::ASToFS(GameSessionIn.GetGameSessionId().c_str());
|
||||
}
|
||||
|
||||
if (GameSessionIn.FleetIdHasBeenSet())
|
||||
{
|
||||
Result.FleetId = AWSSerializer::ASToFS(GameSessionIn.GetFleetId().c_str());
|
||||
}
|
||||
|
||||
if (GameSessionIn.CurrentPlayerSessionCountHasBeenSet())
|
||||
{
|
||||
Result.CurrentPlayerSessionCount = GameSessionIn.GetCurrentPlayerSessionCount();
|
||||
}
|
||||
|
||||
if (GameSessionIn.MaximumPlayerSessionCountHasBeenSet())
|
||||
{
|
||||
Result.MaximumPlayerSessionCount = GameSessionIn.GetMaximumPlayerSessionCount();
|
||||
}
|
||||
|
||||
if (GameSessionIn.StatusHasBeenSet())
|
||||
{
|
||||
Result.Status = static_cast<EGL_GameSessionStatus>(GameSessionIn.GetStatus());
|
||||
}
|
||||
|
||||
if (GameSessionIn.IpAddressHasBeenSet())
|
||||
{
|
||||
Result.IpAddress = AWSSerializer::ASToFS(GameSessionIn.GetIpAddress().c_str());
|
||||
}
|
||||
|
||||
if (GameSessionIn.DnsNameHasBeenSet())
|
||||
{
|
||||
Result.DnsName = AWSSerializer::ASToFS(GameSessionIn.GetDnsName().c_str());
|
||||
}
|
||||
|
||||
if (GameSessionIn.PortHasBeenSet())
|
||||
{
|
||||
Result.Port = GameSessionIn.GetPort();
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
FGL_PlayerSession AwsPlayerSessionToUe(const Aws::GameLift::Model::PlayerSession& PlayerSessionIn)
|
||||
{
|
||||
FGL_PlayerSession Result;
|
||||
|
||||
if (PlayerSessionIn.DnsNameHasBeenSet())
|
||||
{
|
||||
Result.DnsName = AWSSerializer::ASToFS(PlayerSessionIn.GetDnsName().c_str());
|
||||
}
|
||||
|
||||
if (PlayerSessionIn.FleetArnHasBeenSet())
|
||||
{
|
||||
Result.FleetArn = AWSSerializer::ASToFS(PlayerSessionIn.GetFleetArn().c_str());
|
||||
}
|
||||
|
||||
if (PlayerSessionIn.FleetIdHasBeenSet())
|
||||
{
|
||||
Result.FleetId = AWSSerializer::ASToFS(PlayerSessionIn.GetFleetId().c_str());
|
||||
}
|
||||
|
||||
if (PlayerSessionIn.GameSessionIdHasBeenSet())
|
||||
{
|
||||
Result.GameSessionId = AWSSerializer::ASToFS(PlayerSessionIn.GetGameSessionId().c_str());
|
||||
}
|
||||
|
||||
if (PlayerSessionIn.IpAddressHasBeenSet())
|
||||
{
|
||||
Result.IpAddress = AWSSerializer::ASToFS(PlayerSessionIn.GetIpAddress().c_str());
|
||||
}
|
||||
|
||||
if (PlayerSessionIn.PlayerDataHasBeenSet())
|
||||
{
|
||||
Result.PlayerData = AWSSerializer::ASToFS(PlayerSessionIn.GetPlayerData().c_str());
|
||||
}
|
||||
|
||||
if (PlayerSessionIn.PlayerIdHasBeenSet())
|
||||
{
|
||||
Result.PlayerId = AWSSerializer::ASToFS(PlayerSessionIn.GetPlayerId().c_str());
|
||||
}
|
||||
|
||||
if (PlayerSessionIn.PlayerSessionIdHasBeenSet())
|
||||
{
|
||||
Result.PlayerSessionId = AWSSerializer::ASToFS(PlayerSessionIn.GetPlayerSessionId().c_str());
|
||||
}
|
||||
|
||||
if (PlayerSessionIn.PortHasBeenSet())
|
||||
{
|
||||
Result.Port = PlayerSessionIn.GetPort();
|
||||
}
|
||||
|
||||
if (PlayerSessionIn.StatusHasBeenSet())
|
||||
{
|
||||
Result.Status = static_cast<EGL_PlayerSessionStatus>(PlayerSessionIn.GetStatus());
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "Serializer.h"
|
||||
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
|
||||
namespace AWSSerializer
|
||||
{
|
||||
std::string FSToStdS(const FString& String)
|
||||
{
|
||||
if (String.IsEmpty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto* Chars = StringCast<ANSICHAR>(*String).Get();
|
||||
return std::string(Chars, strlen(Chars));
|
||||
}
|
||||
|
||||
FString ASToFS(const char* String)
|
||||
{
|
||||
return FString(StringCast<TCHAR>(String).Get());
|
||||
}
|
||||
} // namespace AWSSerializer
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,233 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "UI/TestAnywhereMenuWidget.h"
|
||||
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
#include "GameLiftClientSDK.h"
|
||||
#include "GameLiftClientSDKModels.h"
|
||||
#include <Kismet/GameplayStatics.h>
|
||||
#endif
|
||||
|
||||
UTestAnywhereMenuWidget::UTestAnywhereMenuWidget(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
GameLiftSdkModule = &FModuleManager::LoadModuleChecked<FGameLiftClientSDKModule>(FName("GameLiftClientSDK"));
|
||||
check(GameLiftSdkModule);
|
||||
|
||||
TryFetchCommandLineArguments();
|
||||
|
||||
if (!InputCredentialsName.IsEmpty())
|
||||
{
|
||||
GameLiftSdkModule->ConfigureClient(InputCredentialsName);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UTestAnywhereMenuWidget::TryFetchCommandLineArguments()
|
||||
{
|
||||
FString ArgumentFleetId;
|
||||
if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereClientFleetId="), ArgumentFleetId))
|
||||
{
|
||||
InputFleetId = ArgumentFleetId;
|
||||
}
|
||||
|
||||
FString ArgumentCredentialsName;
|
||||
if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereClientCredentialsName="), ArgumentCredentialsName))
|
||||
{
|
||||
InputCredentialsName = ArgumentCredentialsName;
|
||||
}
|
||||
|
||||
FString ArgumentCustomLocation;
|
||||
if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereClientCustomLocation="), ArgumentCustomLocation))
|
||||
{
|
||||
InputCustomLocation = ArgumentCustomLocation;
|
||||
}
|
||||
|
||||
bool bArgumentFetched = !ArgumentCredentialsName.IsEmpty() && !ArgumentFleetId.IsEmpty() && !ArgumentCustomLocation.IsEmpty();
|
||||
|
||||
if (bArgumentFetched)
|
||||
{
|
||||
SetOutputMessage(FString::Printf(TEXT("Successfully loaded launch arguments!\n\nCredentials: %s\nFleet ID: %s\nLocation: %s"),
|
||||
*ArgumentCredentialsName, *ArgumentFleetId, *ArgumentCustomLocation));
|
||||
}
|
||||
else
|
||||
{
|
||||
FString EmptyString(TEXT("<empty>"));
|
||||
|
||||
SetOutputMessage(FString::Printf(TEXT("Failed to load launch arguments!\n\nCredentials: %s\nFleet ID: %s\nLocation: %s"),
|
||||
ArgumentCredentialsName.IsEmpty() ? *EmptyString : *ArgumentCredentialsName,
|
||||
ArgumentFleetId.IsEmpty() ? *EmptyString : *ArgumentFleetId,
|
||||
ArgumentCustomLocation.IsEmpty() ? *EmptyString : *ArgumentCustomLocation), true);
|
||||
}
|
||||
}
|
||||
|
||||
bool UTestAnywhereMenuWidget::ConnectToServer()
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
// Talk to Amazon GameLift to retrieve information to join your game server running on your Anywhere fleet.
|
||||
if (!ConnectToAmazonGameLift())
|
||||
{
|
||||
// If the client cannot create a player session, it will not connect to the running game server.
|
||||
return false;
|
||||
}
|
||||
|
||||
const FString Options = "?PlayerSessionId=" + ServerPlayerSessionId + "?PlayerId=" + ServerPlayerId;
|
||||
|
||||
// This will connect to the server map.
|
||||
FString LevelName = ServerIpAddress + ":" + ServerPort;
|
||||
UGameplayStatics::OpenLevel(GetWorld(), FName(*LevelName), false, Options);
|
||||
|
||||
FString DisplayMessage = FString::Printf(TEXT("Successfully connected to a game session and created a player session!\n\n"));
|
||||
DisplayMessage += FString::Printf(TEXT("Game Session ID: %s\n"), *ServerGameSessionId);
|
||||
DisplayMessage += FString::Printf(TEXT("Player Session ID: %s\n"), *ServerPlayerSessionId);
|
||||
DisplayMessage += FString::Printf(TEXT("Player ID: %s\n"), *ServerPlayerId);
|
||||
DisplayMessage += FString::Printf(TEXT("Host: %s:%s\n\n"), *ServerIpAddress, *ServerPort);
|
||||
DisplayMessage += FString::Printf(TEXT("Opening level: %s (Options: %s)"), *LevelName, *Options);
|
||||
|
||||
SetOutputMessage(DisplayMessage);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UTestAnywhereMenuWidget::ConnectToAmazonGameLift()
|
||||
{
|
||||
// Find or create a new game session on your Anywhere fleet.
|
||||
if (!FindGameSession())
|
||||
{
|
||||
if (!CreateGameSession(kMaximumPlayerSessionCount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A new game session will be in ACTIVATING state for a while. Wait 1 second to connect.
|
||||
FPlatformProcess::Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new player session before joining the game server.
|
||||
if (!CreatePlayerSession())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UTestAnywhereMenuWidget::FindGameSession()
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
check(GameLiftSdkModule);
|
||||
|
||||
if (!ServerGameSessionId.IsEmpty())
|
||||
{
|
||||
SetOutputMessage(FString::Printf(TEXT("Game session already started: %s"), *ServerGameSessionId));
|
||||
return true;
|
||||
}
|
||||
|
||||
FString ErrorMessage;
|
||||
FString StatusFilter = TEXT("ACTIVE");
|
||||
|
||||
const TArray<FGL_GameSession>& GLGameSessionList = GameLiftSdkModule->DescribeGameSessions(InputFleetId, StatusFilter, ErrorMessage);
|
||||
|
||||
if (!ErrorMessage.IsEmpty())
|
||||
{
|
||||
SetOutputMessage(ErrorMessage, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const FGL_GameSession& GLGameSession: GLGameSessionList)
|
||||
{
|
||||
SetOutputMessage(FString::Printf(TEXT("Found game session: %s"), *(GLGameSession.ToString())));
|
||||
|
||||
// Use this game session if it is available.
|
||||
if (GLGameSession.CurrentPlayerSessionCount < GLGameSession.MaximumPlayerSessionCount)
|
||||
{
|
||||
ServerGameSessionId = GLGameSession.GameSessionId;
|
||||
ServerIpAddress = GLGameSession.IpAddress;
|
||||
ServerPort = FString::FromInt(GLGameSession.Port);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UTestAnywhereMenuWidget::CreateGameSession(size_t InMaxPlayerCount)
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
check(GameLiftSdkModule);
|
||||
|
||||
if (!ServerGameSessionId.IsEmpty())
|
||||
{
|
||||
SetOutputMessage(FString::Printf(TEXT("Game session already started: %s"), *ServerGameSessionId));
|
||||
return true;
|
||||
}
|
||||
|
||||
FString ErrorMessage;
|
||||
FGL_GameSession GLGameSession = GameLiftSdkModule->CreateGameSession(InMaxPlayerCount, InputFleetId, ErrorMessage, InputCustomLocation);
|
||||
|
||||
if (!ErrorMessage.IsEmpty())
|
||||
{
|
||||
SetOutputMessage(ErrorMessage, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
SetOutputMessage(FString::Printf(TEXT("Successfully created new game session: %s"), *(GLGameSession.ToString())));
|
||||
|
||||
ServerGameSessionId = GLGameSession.GameSessionId;
|
||||
ServerIpAddress = GLGameSession.IpAddress;
|
||||
ServerPort = FString::FromInt(GLGameSession.Port);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UTestAnywhereMenuWidget::CreatePlayerSession()
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
check(GameLiftSdkModule);
|
||||
|
||||
if (ServerGameSessionId.IsEmpty())
|
||||
{
|
||||
SetOutputMessage("Game session is empty!", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
FString ErorrMessage;
|
||||
const FString PlayerData = TEXT("TestAnywhere_PlayerData");
|
||||
ServerPlayerId = TEXT("TestAnywhere_Player_") + FString::FromInt(FMath::RandRange(0, kMaximumPlayerSessionCount * 100));
|
||||
|
||||
FGL_PlayerSession PlayerSession = GameLiftSdkModule->CreatePlayerSession(ServerGameSessionId, PlayerData, ServerPlayerId, ErorrMessage);
|
||||
|
||||
if (!ErorrMessage.IsEmpty())
|
||||
{
|
||||
SetOutputMessage(ErorrMessage, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
SetOutputMessage(FString::Printf(TEXT("Successfully created player session: %s"), *(PlayerSession.ToString())));
|
||||
|
||||
ServerPlayerSessionId = PlayerSession.PlayerSessionId;
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void UTestAnywhereMenuWidget::SetOutputMessage(const FString& InMessage, bool bIsError)
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
LogOutputText = FText::FromString(!bIsError ? InMessage : FString("[Error]\n" + InMessage));
|
||||
LogOutputColor = !bIsError ? FLinearColor::White : FLinearColor::Red;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,397 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "UI/TestCloudDeploymentMenuWidget.h"
|
||||
|
||||
#include "WebBrowser.h"
|
||||
#include "WebBrowserModule.h"
|
||||
#include "IWebBrowserSingleton.h"
|
||||
#include "IWebBrowserCookieManager.h"
|
||||
#include "Json.h"
|
||||
#include "JsonUtilities.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
#include "aws/gamelift/authentication/exports.h"
|
||||
#include "aws/gamelift/core/errors.h"
|
||||
#endif
|
||||
|
||||
DEFINE_LOG_CATEGORY(TestCloudDeployment);
|
||||
|
||||
static FString sGlobalLoggerError;
|
||||
|
||||
UTestCloudDeploymentMenuWidget::UTestCloudDeploymentMenuWidget(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
Http = &FHttpModule::Get();
|
||||
|
||||
ApiGatewayEndpoint = FString::Printf(TEXT("https://%s.execute-api.%s.amazonaws.com/%s"), TEXT("apigatewayid"), TEXT("region"), TEXT("stage"));
|
||||
GetGameConnectionURI = TEXT("/get_game_connection");
|
||||
GetGameConnectionRetryDelayMs = 3000; // wait for 3 sec before the next attempt to get game connection info when matchmaking is in porgress
|
||||
MatchmakingTimeoutInSecondsParameter = 60; // must match to CFN parameter with the same name
|
||||
MatchmakingIsTimedOut = false;
|
||||
StartSessionURI = TEXT("/start_game");
|
||||
SignupUrl = TEXT("");
|
||||
CallbackUrl = TEXT("https://aws.amazon.com/");
|
||||
ConfigFilePath = TEXT("CloudFormation/awsGameLiftClientConfig.yml");
|
||||
|
||||
MatchmakingInProgress = false;
|
||||
}
|
||||
|
||||
void UTestCloudDeploymentMenuWidget::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
}
|
||||
|
||||
bool UTestCloudDeploymentMenuWidget::OnLoginClicked()
|
||||
{
|
||||
if (!MatchmakingInProgress)
|
||||
{
|
||||
|
||||
int result = AuthAndGetToken();
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
LatestError = TEXT("Authorization failed");
|
||||
UE_LOG(TestCloudDeployment, Error, TEXT("%s for user '%s'"), *LatestError, *Username);
|
||||
return false;
|
||||
}
|
||||
|
||||
EstablishGameConnection();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int UTestCloudDeploymentMenuWidget::OnSignupClicked()
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
auto SessionLogger = [](unsigned int InLevel, const char* InMessage, int InSize)
|
||||
{
|
||||
if (InLevel == GameLift::Logger::Level::Error)
|
||||
{
|
||||
sGlobalLoggerError = InMessage;
|
||||
}
|
||||
UE_LOG(TestCloudDeployment, Log, TEXT("Session manager logger: %s"), UTF8_TO_TCHAR(InMessage));
|
||||
};
|
||||
|
||||
auto configFileFullPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(FPaths::ProjectContentDir(), ConfigFilePath));
|
||||
auto sessionManagerHandle = GameLiftSessionManagerInstanceCreate(StringCast<ANSICHAR>(*configFileFullPath).Get(), SessionLogger);
|
||||
|
||||
auto cb = [](DISPATCH_RECEIVER_HANDLE dispatchReceiver, const char* charPtr)
|
||||
{
|
||||
*(static_cast<FString*>(dispatchReceiver)) = charPtr;
|
||||
};
|
||||
|
||||
const std::string& _Username = StringCast<ANSICHAR>(*Username).Get();
|
||||
const std::string& _Password = StringCast<ANSICHAR>(*Password).Get();
|
||||
|
||||
auto result = GameLiftSignUpByUsernamePassword(sessionManagerHandle, _Username.c_str(), _Password.c_str());
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
LatestError = TEXT("SignUp failed");
|
||||
UE_LOG(TestCloudDeployment, Error, TEXT("%s for user '%s'"), *LatestError, *Username);
|
||||
}
|
||||
|
||||
GameLiftSessionManagerInstanceRelease(sessionManagerHandle);
|
||||
|
||||
return result;
|
||||
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int UTestCloudDeploymentMenuWidget::OnConfirmSignupClicked()
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
auto SessionLogger = [](unsigned int InLevel, const char* InMessage, int InSize)
|
||||
{
|
||||
if (InLevel == GameLift::Logger::Level::Error)
|
||||
{
|
||||
sGlobalLoggerError = InMessage;
|
||||
}
|
||||
UE_LOG(TestCloudDeployment, Log, TEXT("Session manager logger: %s"), UTF8_TO_TCHAR(InMessage));
|
||||
};
|
||||
|
||||
auto ConfigFileFullPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(FPaths::ProjectContentDir(), ConfigFilePath));
|
||||
if (!FPaths::FileExists(ConfigFileFullPath))
|
||||
{
|
||||
LatestError = FString::Printf(TEXT("A config file is not found, make sure to setup it at: %s"), *ConfigFileFullPath);
|
||||
return GameLift::GAMELIFT_ERROR_GENERAL;
|
||||
}
|
||||
|
||||
auto sessionManagerHandle = GameLiftSessionManagerInstanceCreate(StringCast<ANSICHAR>(*ConfigFileFullPath).Get(), SessionLogger);
|
||||
|
||||
auto cb = [](DISPATCH_RECEIVER_HANDLE dispatchReceiver, const char* charPtr)
|
||||
{
|
||||
*(static_cast<FString*>(dispatchReceiver)) = charPtr;
|
||||
};
|
||||
|
||||
const std::string& _Username = StringCast<ANSICHAR>(*Username).Get();
|
||||
const std::string& _VerificationCode = StringCast<ANSICHAR>(*VerificationCode).Get();
|
||||
|
||||
auto result = GameLiftConfirmSignUpByUsernameCode(sessionManagerHandle, _Username.c_str(), _VerificationCode.c_str());
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
LatestError = TEXT("Confirm SignUp failed");
|
||||
UE_LOG(TestCloudDeployment, Error, TEXT("%s for user '%s'"), *LatestError, *Username);
|
||||
}
|
||||
|
||||
GameLiftSessionManagerInstanceRelease(sessionManagerHandle);
|
||||
|
||||
return result;
|
||||
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
FString UTestCloudDeploymentMenuWidget::GetLatestError()
|
||||
{
|
||||
if (!LatestError.IsEmpty())
|
||||
{
|
||||
return FString::Printf(TEXT("Error: %s\n%s"), *LatestError, *sGlobalLoggerError);
|
||||
}
|
||||
|
||||
return FString();
|
||||
}
|
||||
|
||||
int UTestCloudDeploymentMenuWidget::AuthAndGetToken()
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
auto sessionLogger = [](unsigned int InLevel, const char* InMessage, int InSize)
|
||||
{
|
||||
if (InLevel == GameLift::Logger::Level::Error)
|
||||
{
|
||||
sGlobalLoggerError = InMessage;
|
||||
}
|
||||
UE_LOG(TestCloudDeployment, Log, TEXT("Session manager logger: %s"), UTF8_TO_TCHAR(InMessage));
|
||||
};
|
||||
|
||||
auto ConfigFileFullPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(FPaths::ProjectContentDir(), ConfigFilePath));
|
||||
|
||||
if (!FPaths::FileExists(ConfigFileFullPath))
|
||||
{
|
||||
LatestError = FString::Printf(TEXT("A config file is not found, make sure to setup it at: %s"), *ConfigFileFullPath);
|
||||
return GameLift::GAMELIFT_ERROR_GENERAL;
|
||||
}
|
||||
|
||||
auto SessionManagerHandle = GameLiftSessionManagerInstanceCreate(StringCast<ANSICHAR>(*ConfigFileFullPath).Get(), sessionLogger);
|
||||
|
||||
auto CallbackFunc = [](DISPATCH_RECEIVER_HANDLE InDispatchReceiver, const char* InCharPtr)
|
||||
{
|
||||
*(static_cast<FString *>(InDispatchReceiver)) = InCharPtr;
|
||||
};
|
||||
|
||||
const std::string& _Username = StringCast<ANSICHAR>(*Username).Get();
|
||||
const std::string& _Password = StringCast<ANSICHAR>(*Password).Get();
|
||||
|
||||
auto result = GameLiftAuthByUsernamePassword(SessionManagerHandle, _Username.c_str(), _Password.c_str());
|
||||
|
||||
if (result == GameLift::GAMELIFT_SUCCESS)
|
||||
{
|
||||
GameLiftGetTokenId(SessionManagerHandle, &IdToken, CallbackFunc);
|
||||
|
||||
if (GameLiftSessionManagerAreSettingsLoaded(SessionManagerHandle, GameLift::FeatureType::Identity))
|
||||
{
|
||||
result = GameLiftGetIdentityApiGatewayURL(SessionManagerHandle, &ApiGatewayEndpoint, CallbackFunc);
|
||||
}
|
||||
}
|
||||
|
||||
GameLiftSessionManagerInstanceRelease(SessionManagerHandle);
|
||||
|
||||
if (result != GameLift::GAMELIFT_SUCCESS)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (ApiGatewayEndpoint.IsEmpty() || IdToken.IsEmpty())
|
||||
{
|
||||
return GameLift::GAMELIFT_ERROR_NO_ID_TOKEN;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UTestCloudDeploymentMenuWidget::OpenLevel(const FString& IpAddress, const FString& Port, const FString& Options)
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
UE_LOG(TestCloudDeployment, Log, TEXT("OpenLevel: IpAddress '%s', Port '%s', Options '%s'"), *(IpAddress), *(Port), *(Options));
|
||||
|
||||
if (!IpAddress.IsEmpty() && !Port.IsEmpty())
|
||||
{
|
||||
FString LevelName = IpAddress + ":" + Port;
|
||||
UGameplayStatics::OpenLevel(GetWorld(), FName(*LevelName), false, Options);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void UTestCloudDeploymentMenuWidget::EstablishGameConnection()
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
|
||||
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> GameConnectionRequest = Http->CreateRequest();
|
||||
|
||||
GameConnectionRequest->SetVerb("POST");
|
||||
GameConnectionRequest->SetURL(ApiGatewayEndpoint + GetGameConnectionURI);
|
||||
GameConnectionRequest->SetHeader("Content-Type", "application/json");
|
||||
GameConnectionRequest->SetHeader("Auth", IdToken);
|
||||
GameConnectionRequest->OnProcessRequestComplete().BindUObject(this, &UTestCloudDeploymentMenuWidget::OnGetGameConnectionResponse);
|
||||
GameConnectionRequest->ProcessRequest();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void UTestCloudDeploymentMenuWidget::OnGetGameConnectionResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
if (bWasSuccessful)
|
||||
{
|
||||
auto& WorldTimerManager = GetWorld()->GetTimerManager();
|
||||
|
||||
auto PollReset = [this, &WorldTimerManager]()
|
||||
{
|
||||
WorldTimerManager.ClearTimer(PollGameConnectionHandle);
|
||||
WorldTimerManager.ClearTimer(PollGameConnectionEndHandle);
|
||||
MatchmakingInProgress = false;
|
||||
MatchmakingIsTimedOut = false;
|
||||
};
|
||||
|
||||
auto ResponseCode = static_cast<ServerHttpStatusCode>(Response->GetResponseCode());
|
||||
|
||||
if (ResponseCode == ServerHttpStatusCode::GetGameConnection_Ready)
|
||||
{
|
||||
TSharedPtr<FJsonObject> JsonObject;
|
||||
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());
|
||||
|
||||
if (FJsonSerializer::Deserialize(Reader, JsonObject))
|
||||
{
|
||||
FString IpAddress = JsonObject->GetStringField("IpAddress");
|
||||
FString Port = JsonObject->GetStringField("Port");
|
||||
const FString& PlayerSessionId = JsonObject->GetStringField("PlayerSessionId");
|
||||
const FString& PlayerId = JsonObject->GetStringField("PlayerId");
|
||||
const FString& Options = "?PlayerSessionId=" + PlayerSessionId + "?PlayerId=" + PlayerId;
|
||||
|
||||
UE_LOG(TestCloudDeployment, Log, TEXT("Game connection: GameSessionArn '%s', PlayerSessionId '%s', PlayerId '%s'"), *(JsonObject->GetStringField("GameSessionArn")), *PlayerSessionId, *PlayerId);
|
||||
|
||||
if (MatchmakingInProgress)
|
||||
{
|
||||
PollReset();
|
||||
}
|
||||
|
||||
OpenLevel(IpAddress, Port, Options);
|
||||
}
|
||||
}
|
||||
else if (ResponseCode == ServerHttpStatusCode::GetGameConnection_NotFound)
|
||||
{
|
||||
UE_LOG(TestCloudDeployment, Log, TEXT("No game is found, starting new game..."));
|
||||
StartGame(IdToken);
|
||||
}
|
||||
else if (ResponseCode == ServerHttpStatusCode::GetGameConnection_MatchmakingInProgress)
|
||||
{
|
||||
UE_LOG(TestCloudDeployment, Log, TEXT("Wating for the other players to join the game..."));
|
||||
|
||||
if (!MatchmakingInProgress)
|
||||
{
|
||||
MatchmakingInProgress = true;
|
||||
MatchmakingIsTimedOut = false;
|
||||
WorldTimerManager.SetTimer(PollGameConnectionHandle, this, &UTestCloudDeploymentMenuWidget::PollGameConnection, GetGameConnectionRetryDelayMs / 1000.0f, true);
|
||||
WorldTimerManager.SetTimer(PollGameConnectionEndHandle, this, &UTestCloudDeploymentMenuWidget::PollGameConnectionEnd, (float)MatchmakingTimeoutInSecondsParameter, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MatchmakingIsTimedOut)
|
||||
{
|
||||
PollReset();
|
||||
LatestError = TEXT("Game connection is timed out. Try to connect again later");
|
||||
UE_LOG(TestCloudDeployment, Error, TEXT("%s"), *LatestError);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ResponseCode == ServerHttpStatusCode::GetGameConnection_NoServerError)
|
||||
{
|
||||
LatestError = TEXT("Server is not deployed, please use another deployment scenario");
|
||||
UE_LOG(TestCloudDeployment, Error, TEXT("%s. Error code: %d"), *LatestError, ResponseCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
LatestError = TEXT("Failed to get game connection");
|
||||
UE_LOG(TestCloudDeployment, Error, TEXT("%s. Error code: %d"), *LatestError, ResponseCode);
|
||||
|
||||
if (MatchmakingInProgress)
|
||||
{
|
||||
PollReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UTestCloudDeploymentMenuWidget::PollGameConnection()
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
EstablishGameConnection();
|
||||
#endif
|
||||
}
|
||||
|
||||
void UTestCloudDeploymentMenuWidget::PollGameConnectionEnd()
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
MatchmakingIsTimedOut = true;
|
||||
UE_LOG(TestCloudDeployment, Log, TEXT("Game connection timed out is reached"));
|
||||
#endif
|
||||
}
|
||||
|
||||
void UTestCloudDeploymentMenuWidget::StartGame(FString InIdToken)
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
FString UsedToken = ( IdToken.IsEmpty() ? InIdToken : IdToken );
|
||||
|
||||
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> StartSessionHttpRequest = Http->CreateRequest();
|
||||
|
||||
StartSessionHttpRequest->SetVerb("POST");
|
||||
StartSessionHttpRequest->SetURL(ApiGatewayEndpoint + StartSessionURI);
|
||||
StartSessionHttpRequest->SetHeader("Content-Type", "application/json");
|
||||
StartSessionHttpRequest->SetHeader("Auth", UsedToken);
|
||||
StartSessionHttpRequest->OnProcessRequestComplete().BindUObject(this, &UTestCloudDeploymentMenuWidget::OnStartGameResponse);
|
||||
StartSessionHttpRequest->ProcessRequest();
|
||||
#endif
|
||||
}
|
||||
|
||||
void UTestCloudDeploymentMenuWidget::OnStartGameResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
if (bWasSuccessful)
|
||||
{
|
||||
auto responseCode = static_cast<ServerHttpStatusCode>(Response->GetResponseCode());
|
||||
|
||||
if (responseCode == ServerHttpStatusCode::StartGame_Accepted)
|
||||
{
|
||||
UE_LOG(TestCloudDeployment, Log, TEXT("Game was started successfully, establishing game connection..."));
|
||||
EstablishGameConnection();
|
||||
}
|
||||
else if (responseCode == ServerHttpStatusCode::StartGame_Conflict)
|
||||
{
|
||||
LatestError = TEXT("Another game request is being processed now");
|
||||
UE_LOG(TestCloudDeployment, Error, TEXT("%s"), *LatestError);
|
||||
}
|
||||
else
|
||||
{
|
||||
LatestError = TEXT("Starting game request failed");
|
||||
UE_LOG(TestCloudDeployment, Error, TEXT("%s with code '%d'"), *LatestError, responseCode);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Modules/ModuleManager.h"
|
||||
#include "GameLiftClientSDKModels.h"
|
||||
|
||||
class FGameLiftClientSDKModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
|
||||
virtual bool ConfigureClient(const FString& CredentialsName);
|
||||
|
||||
virtual FGL_GameSession CreateGameSession(size_t MaximumPlayerCount, const FString& FleetId, FString& ErrorMsg, const FString& CustomLocation = TEXT(""), const FString& EndPoint = TEXT(""));
|
||||
|
||||
virtual TArray<FGL_GameSession> DescribeGameSessions(const FString& FleetId, const FString& StatusFilter, FString& ErrorMsg, const FString& EndPoint = TEXT(""));
|
||||
|
||||
virtual FGL_PlayerSession CreatePlayerSession(const FString& GameSessionId, const FString& PlayerData, const FString& PlayerId, FString& ErrorMsg, const FString& EndPoint = TEXT(""));
|
||||
|
||||
private:
|
||||
void* GameLiftClientHandle;
|
||||
};
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
#include <aws/gamelift/core/exports.h>
|
||||
#endif
|
||||
|
||||
#include "GameLiftClientSDKModels.generated.h"
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EGL_GameSessionStatus : uint8 {
|
||||
NOT_SET UMETA(DisplayName = "Not Set"),
|
||||
ACTIVE UMETA(DisplayName = "Active"),
|
||||
ACTIVATING UMETA(DisplayName = "Activating"),
|
||||
TERMINATED UMETA(DisplayName = "Terminated"),
|
||||
TERMINATING UMETA(DisplayName = "Terminating"),
|
||||
ERROR_ UMETA(DisplayName = "Error"),
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
|
||||
enum class EGL_PlayerSessionStatus : uint8
|
||||
{
|
||||
NOT_SET UMETA(DisplayName = "Not Set"),
|
||||
RESERVED UMETA(DisplayName = "Reserved"),
|
||||
ACTIVE UMETA(DisplayName = "Active"),
|
||||
COMPLETED UMETA(DisplayName = "Completed"),
|
||||
TIMEDOUT UMETA(DisplayName = "Timedout")
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FGL_GameSession
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString GameSessionId;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString FleetId;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
int CurrentPlayerSessionCount = 0;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
int MaximumPlayerSessionCount = 0;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
EGL_GameSessionStatus Status = EGL_GameSessionStatus::NOT_SET;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString IpAddress;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString DnsName;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
int Port = 0;
|
||||
|
||||
FString ToString() const
|
||||
{
|
||||
return FString::Printf(TEXT("GameSessionId: %s,\nFleetId: %s,\nMaximumPlayerSesssionCount: %s,\nStatus: %s,\nIpAddress: %s,\nDnsName: %s,\nPort: %s\n"),
|
||||
*GameSessionId, *FleetId, *FString::FromInt(MaximumPlayerSessionCount), *StaticEnum<EGL_GameSessionStatus>()->GetValueAsString(Status), *IpAddress, *DnsName, *FString::FromInt(Port));
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FGL_PlayerSession
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString DnsName;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString FleetArn;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString FleetId;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString GameSessionId;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString IpAddress;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString PlayerData;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString PlayerId;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
FString PlayerSessionId;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
int Port = 0;
|
||||
|
||||
UPROPERTY(Category = "GameLiftClient", BlueprintReadOnly)
|
||||
EGL_PlayerSessionStatus Status = EGL_PlayerSessionStatus::NOT_SET;
|
||||
|
||||
FString ToString() const
|
||||
{
|
||||
return FString::Printf(TEXT("DnsName: %s,\nFleetArn: %s,\nFleetId: %s,\nGameSessionId: %s,\nIpAddress: %s,\nPlayerData: %s,\nPlayerId: %s,\nPlayerSesssionId: %s,\nPort: %s,\nPlayerStatus: %s,\n"),
|
||||
*DnsName, *FleetArn, *FleetId, *GameSessionId, *IpAddress, *PlayerData, *PlayerId, *PlayerSessionId, *FString::FromInt(Port), *StaticEnum<EGL_PlayerSessionStatus>()->GetValueAsString(Status));
|
||||
}
|
||||
};
|
||||
|
||||
namespace GL_Utils
|
||||
{
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
FGL_GameSession AwsGameSessionToUe(GAMELIFT_GAMESESSION_INSTANCE_HANDLE GameSession);
|
||||
FGL_GameSession AwsGameSessionToUe(const GAMELIFT_GAMESESSION_INFO& GameSessionInfo);
|
||||
FGL_PlayerSession AwsPlayerSessionToUe(GAMELIFT_PLAYERSESSION_INSTANCE_HANDLE PlayerSession);
|
||||
#endif
|
||||
} // namespace GL_Utils
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#if WITH_GAMELIFT_CLIENT
|
||||
|
||||
#include <string>
|
||||
#include <Containers/StringConv.h>
|
||||
|
||||
namespace AWSSerializer
|
||||
{
|
||||
std::string FSToStdS(const FString& String);
|
||||
FString ASToFS(const char* String);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "Styling/SlateColor.h"
|
||||
#include "TestAnywhereMenuWidget.generated.h"
|
||||
|
||||
class FGameLiftClientSDKModule;
|
||||
|
||||
// This is a sample game mode that you can use the test the GameLift Anywhere workflow in the plugin.
|
||||
// It simulates the process of talking to Amazon GameLift and retrieve info needed to connect to a running game server.
|
||||
UCLASS()
|
||||
class UTestAnywhereMenuWidget : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UTestAnywhereMenuWidget(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool ConnectToServer();
|
||||
|
||||
public:
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
|
||||
FText LogOutputText;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||
FSlateColor LogOutputColor;
|
||||
|
||||
private:
|
||||
// This function will fetch command line arguments which are provided when launching the client build in the plugin's Anywhere page.
|
||||
void TryFetchCommandLineArguments();
|
||||
|
||||
// Communicate with Amazon GameLift for game session (e.g. IP address) and player session information.
|
||||
// Return true if the client can create a player session and ready to connect to the running game server.
|
||||
bool ConnectToAmazonGameLift();
|
||||
|
||||
// These functions simulate the process of finding, creating game session, and creating player session.
|
||||
bool FindGameSession();
|
||||
bool CreateGameSession(size_t InMaxPlayerCount);
|
||||
bool CreatePlayerSession();
|
||||
|
||||
void SetOutputMessage(const FString& InMessage, bool bIsError = false);
|
||||
|
||||
private:
|
||||
FGameLiftClientSDKModule* GameLiftSdkModule = nullptr;
|
||||
|
||||
// Test inputs
|
||||
FString InputFleetId;
|
||||
FString InputCredentialsName;
|
||||
FString InputCustomLocation;
|
||||
|
||||
// Test outputs
|
||||
FString ServerIpAddress;
|
||||
FString ServerPort;
|
||||
FString ServerGameSessionId;
|
||||
FString ServerPlayerId;
|
||||
FString ServerPlayerSessionId;
|
||||
|
||||
const size_t kMaximumPlayerSessionCount = 10;
|
||||
};
|
||||
@@ -0,0 +1,128 @@
|
||||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Http.h"
|
||||
#include "CoreMinimal.h"
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "Engine/EngineTypes.h"
|
||||
#include "TestCloudDeploymentMenuWidget.generated.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(TestCloudDeployment, Log, All);
|
||||
|
||||
enum class ServerHttpStatusCode : int32
|
||||
{
|
||||
// start_game API codes
|
||||
|
||||
// 202 (Accepted) if the matchmaking request is accepted and is now being processed
|
||||
StartGame_Accepted = 202,
|
||||
// 409 (Conflict) if the another matchmaking request is in progress
|
||||
StartGame_Conflict = 409,
|
||||
// 500 (Internal Error) if error occurred when processing the matchmaking request
|
||||
StartGame_InternalError = 500,
|
||||
|
||||
// get_game_connection API codes
|
||||
|
||||
// 200 (OK) if the game connection is ready, along with server info: "IpAddress", "Port", "DnsName", "PlayerSessionId", "PlayerId"
|
||||
GetGameConnection_Ready = 200,
|
||||
// 204 (No Content) if the requested game is still in progress of matchmaking
|
||||
GetGameConnection_MatchmakingInProgress = 204,
|
||||
// 404 (Not Found) if no game has been started by the player, or if all started game were expired
|
||||
GetGameConnection_NotFound = 404,
|
||||
// 500 (Internal Error) if errors occurred during matchmaking or placement
|
||||
GetGameConnection_InternalError = 500,
|
||||
// 501 (No Server Deployed) if no server has been delpoyed
|
||||
GetGameConnection_NoServerError = 501,
|
||||
};
|
||||
|
||||
class UWebBrowser;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UTestCloudDeploymentMenuWidget : public UUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UTestCloudDeploymentMenuWidget(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
bool OnLoginClicked();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
int OnSignupClicked();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
int OnConfirmSignupClicked();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
FString GetLatestError();
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
FString ApiGatewayEndpoint;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
FString GetGameConnectionURI;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
int GetGameConnectionRetryDelayMs;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
uint32 MatchmakingTimeoutInSecondsParameter;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
FString StartSessionURI;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
FString SignupUrl;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
FString CallbackUrl;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
FString Username;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
FString Password;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
FString VerificationCode;
|
||||
|
||||
UPROPERTY(EditAnywhere)
|
||||
FString ConfigFilePath;
|
||||
|
||||
UPROPERTY()
|
||||
UWebBrowser* WebBrowser;
|
||||
|
||||
UPROPERTY()
|
||||
FTimerHandle PollGameConnectionHandle;
|
||||
|
||||
UPROPERTY()
|
||||
FTimerHandle PollGameConnectionEndHandle;
|
||||
|
||||
protected:
|
||||
virtual void NativeConstruct() override;
|
||||
|
||||
private:
|
||||
void PollGameConnection();
|
||||
void PollGameConnectionEnd();
|
||||
|
||||
FHttpModule* Http;
|
||||
|
||||
int AuthAndGetToken();
|
||||
|
||||
void EstablishGameConnection();
|
||||
void OnGetGameConnectionResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
|
||||
void StartGame(FString idt);
|
||||
void OnStartGameResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
|
||||
bool OpenLevel(const FString& IpAddress, const FString& Port, const FString& Options);
|
||||
|
||||
FString IdToken;
|
||||
|
||||
bool MatchmakingInProgress;
|
||||
TAtomic<bool> MatchmakingIsTimedOut;
|
||||
FString LatestError;
|
||||
};
|
||||
Reference in New Issue
Block a user