本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
集成 亚马逊 GameLift 服务器 放入虚幻引擎项目
了解如何将适用于 Unreal Engine 的 Amazon GameLift Servers SDK 集成到您的游戏项目中,以访问完整的服务器 SDK 功能集。
提示
为实现更快速的部署,请尝试使用适用于 Unreal Engine 的 Amazon GameLift Servers 独立插件。它提供了引导式 UI 工作流程,可通过最少的设置快速部署游戏服务器,助您即时测试游戏组件的运行效果。请参阅亚马逊 GameLift 服务器 虚幻引擎插件。
其他资源
安装适用于 Unreal 的服务器 SDK
从这里获取虚幻引擎的开源 Amazon GameLift Servers SDK GitHub
设置生成包目标和模块规则
修改您的游戏项目文件,以正确生成可与 Amazon GameLift Servers 搭配使用的生成包组件。
要添加客户端和服务器生成包目标,请执行以下操作:
-
打开游戏项目的代码文件并找到
.../Games/文件。示例:[your application name]Source/[your application name]Target.cs.../Source/GameLiftUnrealAppTarget.cs。(如果您使用 Visual Studio,请打开项目的.sln文件。) -
复制此文件,以在
Source/目录中创建两个新的目标文件。客户端目标:将新文件重命名为
。编辑内容以更新类名称和目标类型值,如以下示例代码所示:[your application name]Client.Target.csusing UnrealBuildTool; using System.Collections.Generic; public class GameLiftUnrealAppClientTarget : TargetRules { public GameLiftUnrealAppClientTarget ( TargetInfo Target ) : base ( Target ) { Type = TargetType.Client; DefaultBuildSettings = BuildSettingsVersion.V2; IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1; ExtraModuleNames.Add( "GameLiftUnrealApp"); } }-
服务器目标:将新文件重命名为
。编辑内容以更新类名称和目标类型值,如以下示例代码所示:[your application name]Server.Target.csusing UnrealBuildTool; using System.Collections.Generic; public class GameLiftUnrealAppServerTarget : TargetRules { public GameLiftUnrealAppServerTarget ( TargetInfo Target ) : base ( Target ) { Type = TargetType.Server; DefaultBuildSettings = BuildSettingsVersion.V2; IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1; ExtraModuleNames.Add( "GameLiftUnrealApp"); } }
-
重新生成您的项目文件。如果您使用 Visual Studio,可以右键单击游戏项目的
.uproject文件,然后选择生成 Visual Studio 项目文件。
要更新游戏项目模块规则,请执行以下操作:
更新游戏项目的模块规则,使其依赖于插件。
-
打开游戏项目的代码文件并找到
.../Games/文件。示例:[your application name]Source/[your application name].Build.cs.../Source/GameLiftUnrealApp.Build.cs。(如果您使用 Visual Studio,请打开项目的.sln文件。) -
找到
ModuleRules类并进行更新,如以下示例代码所示:using UnrealBuildTool; public class GameLiftUnrealApp : ModuleRules { public GameLiftUnrealApp ( ReadOnlyTargetRules Target ) : base ( Target ) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PublicDependencyModuleNames.AddRange( new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "EnhancedInput" }); // Add the following section if (Target.Type == TargetType.Server) { PublicDependencyModuleNames.Add("GameLiftServerSDK"); } else { PublicDefinitions.Add("WITH_GAMELIFT=0"); } bEnableExceptions = true; } } 创建新的目标文件并修改模块规则后,重新构建您的游戏项目。
为您的服务器代码添加游戏托管功能
在完成服务器 SDK 的安装和配置后,下一步是将游戏托管功能集成到服务器代码中。服务器 SDK 使您的游戏服务器能够与 Amazon GameLift Servers 服务通信,接收游戏会话指令,报告状态和运行状况,并执行其他操作。
本主题提供示例代码,用于添加使用 Amazon GameLift Servers 托管游戏所需的最低功能。
步骤 1:更新 GameMode 标头文件
-
打开游戏项目的代码文件并找到
文件。示例:Your-application-nameGameMode.hGameLiftUnrealAppGameMode.h。如果您使用 Visual Studio,请打开游戏项目的.sln文件。 -
更改标头文件以包含以下示例代码。请务必将 “GameLiftUnrealApp” 替换为您自己的应用程序名称。
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 #pragma once #include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "GameLiftUnrealAppGameMode.generated.h" struct FProcessParameters; DECLARE_LOG_CATEGORY_EXTERN(GameServerLog, Log, All); UCLASS(minimalapi) class AGameLiftUnrealAppGameMode : public AGameModeBase { GENERATED_BODY() public: AGameLiftUnrealAppGameMode(); protected: virtual void BeginPlay() override; private: void InitGameLift(); private: TSharedPtr<FProcessParameters> ProcessParameters; };
步骤 2:将所需的服务器 SDK 调用添加到游戏服务器代码中
使用本节中的示例代码,将您的游戏服务器代码集成到 Amazon GameLift Servers 服务器中。有关代码功能的详细信息,请参阅初始化服务器进程和C++(虚幻)服务器 SDK 5.x 适用于 亚马逊 GameLift 服务器 --动作。
注意
WITH_GAMELIFT 预处理器标志有两个用途:
将 Amazon GameLift Servers 后端 API 调用限制为仅限 Unreal 服务器生成包
确保不同 Unreal 生成包目标之间的兼容性
-
打开相关的源文件
文件。在本示例中:Your-application-nameGameMode.cppGameLiftUnrealAppGameMode.cpp。 更改代码以使其与以下示例代码保持一致。请务必使用您自己的应用程序名称替换 GameLiftUnrealApp “” 的任意实例。
提供的代码示例显示了如何添加与 Amazon GameLift Servers 集成所需的元素。这些方法包括:
-
初始化 Amazon GameLift Servers API 客户端。
-
实现回调函数以响应 Amazon GameLift Servers 服务的请求,包括
OnStartGameSession、OnProcessTerminate和onHealthCheck。 -
准备好托管游戏会话时,请调用
ProcessReady()以通知 Amazon GameLift Servers 服务。
-
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 #include "GameLiftUnrealAppGameMode.h" #include "UObject/ConstructorHelpers.h" #include "Kismet/GameplayStatics.h" #if WITH_GAMELIFT #include "GameLiftServerSDK.h" #include "GameLiftServerSDKModels.h" #endif #include "GenericPlatform/GenericPlatformOutputDevices.h" DEFINE_LOG_CATEGORY(GameServerLog); AGameLiftUnrealAppGameMode::AGameLiftUnrealAppGameMode() : ProcessParameters(nullptr) { // Set default pawn class to our Blueprinted character static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter")); if (PlayerPawnBPClass.Class != NULL) { DefaultPawnClass = PlayerPawnBPClass.Class; } UE_LOG(GameServerLog, Log, TEXT("Initializing AGameLiftUnrealAppGameMode...")); } void AGameLiftUnrealAppGameMode::BeginPlay() { Super::BeginPlay(); #if WITH_GAMELIFT InitGameLift(); #endif } void AGameLiftUnrealAppGameMode::InitGameLift() { #if WITH_GAMELIFT UE_LOG(GameServerLog, Log, TEXT("Calling InitGameLift...")); // Getting the module first. FGameLiftServerSDKModule* GameLiftSdkModule = &FModuleManager::LoadModuleChecked<FGameLiftServerSDKModule>(FName("GameLiftServerSDK")); //Define the server parameters for a GameLift Anywhere fleet. These are not needed for a GameLift managed EC2 fleet. FServerParameters ServerParametersForAnywhere; bool bIsAnywhereActive = false; if (FParse::Param(FCommandLine::Get(), TEXT("glAnywhere"))) { bIsAnywhereActive = true; } if (bIsAnywhereActive) { UE_LOG(GameServerLog, Log, TEXT("Configuring server parameters for Anywhere...")); // If GameLift Anywhere is enabled, parse command line arguments and pass them in the ServerParameters object. FString glAnywhereWebSocketUrl = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereWebSocketUrl="), glAnywhereWebSocketUrl)) { ServerParametersForAnywhere.m_webSocketUrl = TCHAR_TO_UTF8(*glAnywhereWebSocketUrl); } FString glAnywhereFleetId = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereFleetId="), glAnywhereFleetId)) { ServerParametersForAnywhere.m_fleetId = TCHAR_TO_UTF8(*glAnywhereFleetId); } FString glAnywhereProcessId = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereProcessId="), glAnywhereProcessId)) { ServerParametersForAnywhere.m_processId = TCHAR_TO_UTF8(*glAnywhereProcessId); } else { // If no ProcessId is passed as a command line argument, generate a randomized unique string. FString TimeString = FString::FromInt(std::time(nullptr)); FString ProcessId = "ProcessId_" + TimeString; ServerParametersForAnywhere.m_processId = TCHAR_TO_UTF8(*ProcessId); } FString glAnywhereHostId = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereHostId="), glAnywhereHostId)) { ServerParametersForAnywhere.m_hostId = TCHAR_TO_UTF8(*glAnywhereHostId); } FString glAnywhereAuthToken = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereAuthToken="), glAnywhereAuthToken)) { ServerParametersForAnywhere.m_authToken = TCHAR_TO_UTF8(*glAnywhereAuthToken); } FString glAnywhereAwsRegion = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereAwsRegion="), glAnywhereAwsRegion)) { ServerParametersForAnywhere.m_awsRegion = TCHAR_TO_UTF8(*glAnywhereAwsRegion); } FString glAnywhereAccessKey = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereAccessKey="), glAnywhereAccessKey)) { ServerParametersForAnywhere.m_accessKey = TCHAR_TO_UTF8(*glAnywhereAccessKey); } FString glAnywhereSecretKey = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereSecretKey="), glAnywhereSecretKey)) { ServerParametersForAnywhere.m_secretKey = TCHAR_TO_UTF8(*glAnywhereSecretKey); } FString glAnywhereSessionToken = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereSessionToken="), glAnywhereSessionToken)) { ServerParametersForAnywhere.m_sessionToken = TCHAR_TO_UTF8(*glAnywhereSessionToken); } UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_YELLOW); UE_LOG(GameServerLog, Log, TEXT(">>>> WebSocket URL: %s"), *ServerParametersForAnywhere.m_webSocketUrl); UE_LOG(GameServerLog, Log, TEXT(">>>> Fleet ID: %s"), *ServerParametersForAnywhere.m_fleetId); UE_LOG(GameServerLog, Log, TEXT(">>>> Process ID: %s"), *ServerParametersForAnywhere.m_processId); UE_LOG(GameServerLog, Log, TEXT(">>>> Host ID (Compute Name): %s"), *ServerParametersForAnywhere.m_hostId); UE_LOG(GameServerLog, Log, TEXT(">>>> Auth Token: %s"), *ServerParametersForAnywhere.m_authToken); UE_LOG(GameServerLog, Log, TEXT(">>>> Aws Region: %s"), *ServerParametersForAnywhere.m_awsRegion); UE_LOG(GameServerLog, Log, TEXT(">>>> Access Key: %s"), *ServerParametersForAnywhere.m_accessKey); UE_LOG(GameServerLog, Log, TEXT(">>>> Secret Key: %s"), *ServerParametersForAnywhere.m_secretKey); UE_LOG(GameServerLog, Log, TEXT(">>>> Session Token: %s"), *ServerParametersForAnywhere.m_sessionToken); UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_NONE); } UE_LOG(GameServerLog, Log, TEXT("Initializing the GameLift Server...")); //InitSDK will establish a local connection with GameLift's agent to enable further communication. FGameLiftGenericOutcome InitSdkOutcome = GameLiftSdkModule->InitSDK(ServerParametersForAnywhere); if (InitSdkOutcome.IsSuccess()) { UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_GREEN); UE_LOG(GameServerLog, Log, TEXT("GameLift InitSDK succeeded!")); UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_NONE); } else { UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_RED); UE_LOG(GameServerLog, Log, TEXT("ERROR: InitSDK failed : (")); FGameLiftError GameLiftError = InitSdkOutcome.GetError(); UE_LOG(GameServerLog, Log, TEXT("ERROR: %s"), *GameLiftError.m_errorMessage); UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_NONE); return; } ProcessParameters = MakeShared<FProcessParameters>(); //When a game session is created, Amazon GameLift Servers sends an activation request to the game server and passes along the game session object containing game properties and other settings. //Here is where a game server should take action based on the game session object. //Once the game server is ready to receive incoming player connections, it should invoke GameLiftServerAPI.ActivateGameSession() ProcessParameters->OnStartGameSession.BindLambda([=](Aws::GameLift::Server::Model::GameSession InGameSession) { FString GameSessionId = FString(InGameSession.GetGameSessionId()); UE_LOG(GameServerLog, Log, TEXT("GameSession Initializing: %s"), *GameSessionId); GameLiftSdkModule->ActivateGameSession(); }); //OnProcessTerminate callback. Amazon GameLift Servers will invoke this callback before shutting down an instance hosting this game server. //It gives this game server a chance to save its state, communicate with services, etc., before being shut down. //In this case, we simply tell Amazon GameLift Servers we are indeed going to shut down. ProcessParameters->OnTerminate.BindLambda([=]() { UE_LOG(GameServerLog, Log, TEXT("Game Server Process is terminating")); // First call ProcessEnding() FGameLiftGenericOutcome processEndingOutcome = GameLiftSdkModule->ProcessEnding(); // Then call Destroy() to free the SDK from memory FGameLiftGenericOutcome destroyOutcome = GameLiftSdkModule->Destroy(); // Exit the process with success or failure if (processEndingOutcome.IsSuccess() && destroyOutcome.IsSuccess()) { UE_LOG(GameServerLog, Log, TEXT("Server process ending successfully")); } else { if (!processEndingOutcome.IsSuccess()) { const FGameLiftError& error = processEndingOutcome.GetError(); UE_LOG(GameServerLog, Error, TEXT("ProcessEnding() failed. Error: %s"), error.m_errorMessage.IsEmpty() ? TEXT("Unknown error") : *error.m_errorMessage); } if (!destroyOutcome.IsSuccess()) { const FGameLiftError& error = destroyOutcome.GetError(); UE_LOG(GameServerLog, Error, TEXT("Destroy() failed. Error: %s"), error.m_errorMessage.IsEmpty() ? TEXT("Unknown error") : *error.m_errorMessage); } } }); //This is the HealthCheck callback. //Amazon GameLift Servers will invoke this callback every 60 seconds or so. //Here, a game server might want to check the health of dependencies and such. //Simply return true if healthy, false otherwise. //The game server has 60 seconds to respond with its health status. Amazon GameLift Servers will default to 'false' if the game server doesn't respond in time. //In this case, we're always healthy! ProcessParameters->OnHealthCheck.BindLambda([]() { UE_LOG(GameServerLog, Log, TEXT("Performing Health Check")); return true; }); //GameServer.exe -port=7777 LOG=server.mylog ProcessParameters->port = FURL::UrlConfig.DefaultPort; TArray<FString> CommandLineTokens; TArray<FString> CommandLineSwitches; FCommandLine::Parse(FCommandLine::Get(), CommandLineTokens, CommandLineSwitches); for (FString SwitchStr : CommandLineSwitches) { FString Key; FString Value; if (SwitchStr.Split("=", &Key, &Value)) { if (Key.Equals("port")) { ProcessParameters->port = FCString::Atoi(*Value); } } } //Here, the game server tells Amazon GameLift Servers where to find game session log files. //At the end of a game session, Amazon GameLift Servers uploads everything in the specified //location and stores it in the cloud for access later. TArray<FString> Logfiles; Logfiles.Add(TEXT("GameLiftUnrealApp/Saved/Logs/server.log")); ProcessParameters->logParameters = Logfiles; //The game server calls ProcessReady() to tell Amazon GameLift Servers it's ready to host game sessions. UE_LOG(GameServerLog, Log, TEXT("Calling Process Ready...")); FGameLiftGenericOutcome ProcessReadyOutcome = GameLiftSdkModule->ProcessReady(*ProcessParameters); if (ProcessReadyOutcome.IsSuccess()) { UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_GREEN); UE_LOG(GameServerLog, Log, TEXT("Process Ready!")); UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_NONE); } else { UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_RED); UE_LOG(GameServerLog, Log, TEXT("ERROR: Process Ready Failed!")); FGameLiftError ProcessReadyError = ProcessReadyOutcome.GetError(); UE_LOG(GameServerLog, Log, TEXT("ERROR: %s"), *ProcessReadyError.m_errorMessage); UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_NONE); } UE_LOG(GameServerLog, Log, TEXT("InitGameLift completed!")); #endif }
步骤 3:重建游戏项目
-
为以下两种目标类型构建游戏项目:开发编辑器和开发服务器。
注意
您不需要重新构建解决方案。只需在应用程序的
/Games/文件夹下构建项目即可。否则,Visual Studio 将重建整个 UE5 项目,这可能需要长达一个小时的时间。
添加 亚马逊 GameLift 服务器 服务器代码到你的虚幻项目(服务器 SDK 4.x)
服务器 SDK 现已准备就绪,但您还没有编写代码来使用它。首先,请使用 Unreal Engine 示例项目中包含的现有GameMode文件。以下代码示例包括修改过的GameMode.h和GameMode.cpp文件。
GameMode.h
// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "GameLift426TestGameMode.generated.h" DECLARE_LOG_CATEGORY_EXTERN(GameServerLog, Log, All); UCLASS(minimalapi) class AGameLift426TestGameMode : public AGameModeBase { GENERATED_BODY() public: AGameLift426TestGameMode(); protected: virtual void BeginPlay() override; private: void InitGameLift(); };
GameMode.cpp
// Copyright Epic Games, Inc. All Rights Reserved. #include "GameLift426TestGameMode.h" #include "GameLift426TestCharacter.h" #include "UObject/ConstructorHelpers.h" #include "GameLiftServerSDK.h" DEFINE_LOG_CATEGORY(GameServerLog); AGameLift426TestGameMode::AGameLift426TestGameMode() { UE_LOG(LogInit, Log, TEXT("Game Mode Constructor")); // set default pawn class to our Blueprinted character static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter")); if (PlayerPawnBPClass.Class != NULL) { DefaultPawnClass = PlayerPawnBPClass.Class; } } void AGameLift426TestGameMode::BeginPlay() { #if WITH_GAMELIFT InitGameLift(); #endif } void AGameLift426TestGameMode::InitGameLift() { UE_LOG(GameServerLog, Log, TEXT("Initializing the GameLift Server")); //Getting the module first. FGameLiftServerSDKModule* GameLiftSdkModule = &FModuleManager::LoadModuleChecked<FGameLiftServerSDKModule>(FName("GameLiftServerSDK")); //Define the server parameters FServerParameters serverParameters; //AuthToken returned from the "aws gamelift get-compute-auth-token" API. Note this will expire and require a new call to the API after 15 minutes. if (FParse::Value(FCommandLine::Get(), TEXT("-authtoken="), serverParameters.m_authToken)) { UE_LOG(GameServerLog, Log, TEXT("AUTH_TOKEN: %s"), *serverParameters.m_authToken) } //The Host/Compute ID of the GameLift Anywhere instance. if (FParse::Value(FCommandLine::Get(), TEXT("-hostid="), serverParameters.m_hostId)) { UE_LOG(GameServerLog, Log, TEXT("HOST_ID: %s"), *serverParameters.m_hostId) } //The EC2 or Anywhere Fleet ID. if (FParse::Value(FCommandLine::Get(), TEXT("-fleetid="), serverParameters.m_fleetId)) { UE_LOG(GameServerLog, Log, TEXT("FLEET_ID: %s"), *serverParameters.m_fleetId) } //The WebSocket URL (GameLiftServiceSdkEndpoint). if (FParse::Value(FCommandLine::Get(), TEXT("-websocketurl="), serverParameters.m_webSocketUrl)) { UE_LOG(GameServerLog, Log, TEXT("WEBSOCKET_URL: %s"), *serverParameters.m_webSocketUrl) } //The PID of the running process serverParameters.m_processId = FString::Printf(TEXT("%d"), GetCurrentProcessId()); UE_LOG(GameServerLog, Log, TEXT("PID: %s"), *serverParameters.m_processId); //InitSDK will establish a local connection with GameLift's agent to enable further communication. GameLiftSdkModule->InitSDK(serverParameters); //When a game session is created, GameLift sends an activation request to the game server and passes along the game session object containing game properties and other settings. //Here is where a game server should take action based on the game session object. //Once the game server is ready to receive incoming player connections, it should invoke GameLiftServerAPI.ActivateGameSession() auto onGameSession = [=](Aws::GameLift::Server::Model::GameSession gameSession) { FString gameSessionId = FString(gameSession.GetGameSessionId()); UE_LOG(GameServerLog, Log, TEXT("GameSession Initializing: %s"), *gameSessionId); GameLiftSdkModule->ActivateGameSession(); }; FProcessParameters params; params.OnStartGameSession.BindLambda(onGameSession); //OnProcessTerminate callback. GameLift will invoke this callback before shutting down an instance hosting this game server. //It gives this game server a chance to save its state, communicate with services, etc., before being shut down. //In this case, we simply tell GameLift we are indeed going to shut down. params.OnTerminate.BindLambda([=]() { UE_LOG(GameServerLog, Log, TEXT("Game Server Process is terminating")); GameLiftSdkModule->ProcessEnding(); }); //This is the HealthCheck callback. //GameLift will invoke this callback every 60 seconds or so. //Here, a game server might want to check the health of dependencies and such. //Simply return true if healthy, false otherwise. //The game server has 60 seconds to respond with its health status. GameLift will default to 'false' if the game server doesn't respond in time. //In this case, we're always healthy! params.OnHealthCheck.BindLambda([]() { UE_LOG(GameServerLog, Log, TEXT("Performing Health Check")); return true; }); //This game server tells GameLift that it will listen on port 7777 for incoming player connections. params.port = 7777; //Here, the game server tells GameLift what set of files to upload when the game session ends. //GameLift will upload everything specified here for the developers to fetch later. TArray<FString> logfiles; logfiles.Add(TEXT("GameLift426Test/Saved/Logs/GameLift426Test.log")); params.logParameters = logfiles; //Calling ProcessReady tells GameLift this game server is ready to receive incoming game sessions! UE_LOG(GameServerLog, Log, TEXT("Calling Process Ready")); GameLiftSdkModule->ProcessReady(params); }
搭建您的游戏服务器
当您完成向项目中添加服务器 SDK 代码后,请按照以下步骤创建游戏服务器生成包,并将其上传到 Amazon GameLift Servers 进行托管。
-
为以下两种目标类型构建游戏项目:开发编辑器和开发服务器。
注意
您不需要重新构建解决方案。相反,只在与您的应用程序名称相匹配的
Games文件夹下构建项目。否则,Visual Studio 会重建整个 UE5 项目,这可能需要长达一个小时的时间。 -
两个构建都完成后,关闭Visual Studio并打开项目的
.uproject文件以在虚幻编辑器中将其打开。 -
在虚幻编辑器中,打包游戏的服务器版本。要选择目标,请前往 “平台” 、“Windows” 并选择
Your-application-nameServer。 -
要开始构建服务器应用程序的过程,请转到平台、Windows,然后选择Package Project。构建完成后,您就有了可执行文件,例如
GameLiftUnrealAppServer.exe。 -
在虚幻编辑器中构建服务器应用程序会生成两个可执行文件。一个位于游戏构建文件夹的根目录中,用作实际服务器可执行文件的封装器。
使用服务器生成包创建 Amazon GameLift Servers 实例集时,我们建议您传入实际的服务器可执行文件作为运行时配置启动路径。例如,在您的游戏版本文件夹中,您的根目录可能有一个
GameLiftFPS.exe文件,另一个位于根目录\GameLiftFPS\Binaries\Win64\GameLiftFPSServer.exe。创建队列时,我们建议您使用C:\GameLiftFPS\Binaries\Win64\GameLiftFPSServer.exe作为运行时配置的启动路径。 -
确保在 Amazon GameLift Servers 实例集上打开必要的 UDP 端口,以便游戏服务器可以与游戏客户端通信。默认情况下, Unreal Engine 使用端口
7777。有关更多信息,请参阅UpdateFleetPortSettings的服务 API 参考指南Amazon GameLift Servers。 -
在 Windows 上:为您的游戏生成包创建
文件。每当将游戏版本部署到Amazon GameLift Servers舰队时,此安装脚本就会运行。下面给出了一个示例install.batinstall.bat文件:VC_redist.x64.exe /q UE5PrereqSetup_x64.exe /q -
现在,您可以将游戏生成包打包并上传到 Amazon GameLift Servers。
您用于构建的 OpenSSL 版本需要与游戏服务器使用的版本相匹配。确保在游戏服务器版本中打包正确的 OpenSSL 版本。对于 Windows 操作系统,OpenSSL 格式为。
.dll注意
将 OpenSSL DLL/SO 文件打包到游戏服务器版本中。请务必使用与构建游戏服务器时使用的版本相同的版本。 DLL/SOs
-
libssl-3-x64.dll(Windows)或libssl.so.1.1(Linux) -
libcrypto-3-x64.dll(Windows)或libcrypto.so.1.1(Linux)
将依赖项与游戏服务器可执行文件一起打包到 zip 文件的根目录中。例如,在 Windows 上,
openssl-libDLL 应与.exe文件位于同一目录中。 -
打包游戏服务器以便托管
现在,您的游戏服务器代码已集成所需的最低服务器 SDK 功能,您已准备好使用 Unreal 编辑器打包游戏服务器生成包。
打包游戏服务器生成包
-
在 Unreal 编辑器中打开游戏项目。
-
按照 Unreal 编辑器的步骤来打包您的游戏服务器:
-
选择目标平台(Windows 或 Linux)。
-
选择服务器构建目标 (
。[your application name]Server
打包过程会生成您的游戏服务器可执行文件:
。[your application name]Server.exe -
-
准备好您的游戏服务器生成包,以便部署到托管资源。生成包应包含以下文件:
-
游戏服务器可执行文件
-
如果您使用的是 Unreal Engine 版本 5.5 或更早版本,请为 Windows 生成包包含以下文件。您可在源代码构建版本的 Unreal Engine 中找到这些文件:
-
VC_redist.x64.exe(UnrealEngine\Engine\Source\Programs\PrereqInstaller\Resources\VCRedist\) -
UEPrereqSetup_x64.exe or UE5PrereqSetup_x64.exe(UnrealEngine\Engine\Extras\Redist\en-us\)
-
-
游戏服务器所需的所有其他依赖项。
-
如果需要,可以使用 OpenSSL 库。如果您的游戏服务器与 Amazon GameLift Servers 服务器 SDK 5.3 版本或更高版本集成,可以跳过此步骤。最新的服务器 SDK 版本可在此处获取。
-
您必须包含与在 Unreal 中打包游戏服务器时相同的 OpenSSL 库版本。这些库位于您的游戏引擎源代码中。具体位置因开发环境而异:
在 Windows 上:
-
[ENGINE_ROOT_DIR]\Engine\Extras\ThirdPartyNotUE\libimobiledevice\x64\libssl-1_1-x64.dll -
[ENGINE_ROOT_DIR]\Engine\Extras\ThirdPartyNotUE\libimobiledevice\x64\libcrypto-1_1-x64.dll
在 Linux 上:
-
Engine/Source/Thirdparty/OpenSSL/1.1.1n/include/libssl.so.1.1 -
Engine/Source/Thirdparty/OpenSSL/1.1.1n/include/libcrypto.so.1.1
将 OpenSSL 库复制到游戏生成包中,使其与游戏服务器可执行文件位于同一目录下。
后续步骤
既然您已准备好具备在 Amazon GameLift Servers 上托管所需最低功能的游戏服务器生成包,请考虑以下潜在后续步骤:
部署您的集成游戏服务器以进行测试和开发。借助 Anywhere 实例集,您可以将本地计算机设置为托管资源,并用其测试游戏服务器与游戏客户端连接。对于基于云的托管,请将游戏服务器部署到托管式 EC2 实例集或托管式容器实例集。请参阅以下主题获取指导:
通过添加可选功能,自定义游戏服务器集成。例如,您可能需要添加具有唯一玩家 ID 的玩家会话、设置配对回填或管理游戏服务器对其他 Amazon 资源(例如数据库或内容存储服务)的访问权限。请参阅以下主题获取指导:
自定义您的游戏客户端组件,以请求游戏会话、接收连接信息并直接连接到游戏服务器进行游戏。请参阅以下主题获取指导: