

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# Amazon GameLift Servers虚幻引擎插件
<a name="unreal-plugin"></a>

此插件将 Amazon GameLift Servers C\$1\$1 服务器 SDK 和工具添加到 UE 编辑器中。使用引导式 UI 工作流程将服务器 SDK 功能集成到您的游戏项目中，并为您的游戏服务器部署 Amazon GameLift Servers 托管解决方案。

利用插件，您可以构建一个基本的托管解决方案，然后根据需要进行优化和自定义。设置以本地工作站为主机的 Amazon GameLift Servers Anywhere 实例集。对于使用托管式 EC2 或托管式容器实例集的云托管，请使用完整的解决方案部署游戏服务器，以便管理游戏会话请求和客户端连接。

**Topics**
+ [为 Unreal 游戏项目安装插件](#unreal-plugin-install)
+ [后续步骤：自定义游戏托管解决方案](#unreal-plugin-next-steps)
+ [虚幻引擎插件：设置 AWS 用户个人资料](unreal-plugin-profiles.md)
+ [适用于 Unreal 的插件：集成游戏代码](unreal-plugin-integrate.md)
+ [适用于 Unreal 的插件：使用 Amazon GameLift Servers Anywhere 在本地托管游戏](unreal-plugin-anywhere.md)
+ [适用于 Unreal 的插件：将游戏部署到托管式 EC2 实例集](unreal-plugin-ec2.md)
+ [适用于 Unreal 的插件：将游戏部署到托管式容器实例集](unreal-plugin-container.md)

## 为 Unreal 游戏项目安装插件
<a name="unreal-plugin-install"></a>

**[从以下地址获取虚幻引擎Amazon GameLift Servers插件 GitHub](https://github.com/amazon-gamelift/amazon-gamelift-plugin-unreal)**

有关如何在虚幻编辑器中为游戏项目安装插件的信息，请参阅 GitHub 存储库自述文件。

该插件包括以下组件：
+ UE 编辑器的插件模块。安装插件后，新的主菜单按钮可让您访问 Amazon GameLift Servers 的功能。
+ 适用于 Amazon GameLift Servers 服务 API 的 C\$1\$1 库。在客户端后端服务中使用 API 功能来帮助游戏客户端请求游戏会话和 send/retrieve 游戏会话信息。
+ 适用于 Amazon GameLift Servers 服务器 SDK（版本 5）的 Unreal 库。在游戏服务器代码中使用服务器 SDK 来管理托管游戏服务器进程与 Amazon GameLift Servers 服务之间的通信。
+ 测试内容，包括启动游戏地图和两张测试地图，其中包含用于测试服务器集成的基本蓝图和用户界面元素。
+ 插件在部署游戏服务器进行托管时使用的 CloudFormation 模板形式的可编辑配置。

此插件使用 AWS CloudFormation 模板为常见游戏场景部署托管解决方案。您可以使用提供的这些解决方案，也可以根据游戏需要对其进行自定义。

## 后续步骤：自定义游戏托管解决方案
<a name="unreal-plugin-next-steps"></a>

使用该插件的指导式工作流程可以很好地快速启动并运行 Amazon GameLift Servers 托管解决方案。借助该插件，您可以为解决方案的每个组件设置基本版本。

准备就绪后，您可以通过自定义每个组件，在此基本解决方案的基础上进行构建，并可以在为游戏发布做准备时对解决方案进行微调。考虑以下选项：
+ 修改实例集和实例集配置。请参阅[托管资源自定义](fleets-design.md)。
+ 自定义游戏会话队列配置。请参阅[自定义游戏会话队列](queues-design.md)。
+ 向游戏服务器和游戏客户端添加功能。请参阅[将游戏服务器与 Amazon GameLift Servers 集成](gamelift-sdk-server.md)和[集成 Amazon GameLift Servers 游戏客户端功能](gamelift-sdk-client-api.md)。
+ 自定义后端服务。请参阅[为 Amazon GameLift Servers 构建后端服务](gamelift_quickstart_customservers_designbackend.md)。
+ 设置自动容量扩展以满足预期的玩家需求。请参阅[利用 Amazon GameLift Servers 扩展游戏托管容量](fleets-manage-capacity.md)。
+ 设置托管可观测性工具，包括分析和日志记录。请参阅[监控 Amazon GameLift Servers](monitoring-overview.md)。
+ 使用[基础设施即代码（IaC）](https://docs.aws.amazon.com/whitepapers/latest/introduction-devops-aws/infrastructure-as-code.html)自动执行部署。该插件针对托管解决方案的指导式工作流程使用 AWS CloudFormation 模板。您可以根据需要对模板进行自定义。请参阅[使用管理Amazon GameLift Servers托管资源 CloudFormation](resources-cloudformation.md)。

**Topics**
+ [为 Unreal 游戏项目安装插件](#unreal-plugin-install)
+ [后续步骤：自定义游戏托管解决方案](#unreal-plugin-next-steps)
+ [虚幻引擎插件：设置 AWS 用户个人资料](unreal-plugin-profiles.md)
+ [适用于 Unreal 的插件：集成游戏代码](unreal-plugin-integrate.md)
+ [适用于 Unreal 的插件：使用 Amazon GameLift Servers Anywhere 在本地托管游戏](unreal-plugin-anywhere.md)
+ [适用于 Unreal 的插件：将游戏部署到托管式 EC2 实例集](unreal-plugin-ec2.md)
+ [适用于 Unreal 的插件：将游戏部署到托管式容器实例集](unreal-plugin-container.md)

# 虚幻引擎插件：设置 AWS 用户个人资料
<a name="unreal-plugin-profiles"></a>

安装插件后，使用有效的 AWS 帐户设置用户个人资料。您可以在插件中维护多个配置文件，但一次只能选择一个配置文件。每当使用插件时，请选择要使用的配置文件。每个工作流程页面都会显示当前选择的配置文件。

维护多个配置文件使您能够在不同的托管部署之间切换。例如，您可以设置使用相同 AWS 账户但部署到不同 AWS 区域的配置文件。或者，您可以使用不同的 AWS 帐户、用户和权限集来设置配置文件。

**注意**  
如果您已在工作站上安装了 AWS CLI 并且已经配置了配置文件，则该Amazon GameLift Servers插件将对其进行检测并将其列为现有配置文件。该插件会自动选择任何名为 `[default]` 的配置文件。您可以使用现有配置文件或创建新的配置文件。

必须启动所有配置文件才能在您的账户用户下设置一些必需的 AWS 资源。

**管理您的 AWS 个人资料**

1. 在 Unreal 编辑器主工具栏中，选择 Amazon GameLift Servers 菜单，然后选择 **AWS 访问凭证**。此操作会打开 Amazon GameLift Servers 插件并转到**设置您的用户配置文件**页面。

1. 使用按钮创建新 AWS 帐户或为已有的 AWS 帐户设置用户个人资料。

1. 如果您还没有用户配置文件，系统会提示您输入配置文件详细信息并创建新的配置文件。提供以下信息：
   + 一个 AWS 账户。如果您创建了一个新 AWS 帐户，请使用链接 AWS 管理控制台 并按照提示进行操作。有关更多详细信息，请参阅[创建 AWS 账户](https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-creating.html)。
   + 有权使用Amazon GameLift Servers和其他必需 AWS 服务的 AWS 用户。有关设置具有Amazon GameLift Servers权限的 AWS Identity and Access Management (IAM) 用户以及使用长期证书进行编程访问的说明，请参阅[设置 AWS 用户账户](setting-up-aws-login.md)。
   + 您的 AWS 用户的凭证。这些证书由 AWS 访问密钥 ID 和 AWS 密钥组成。有关更多详细信息，请参阅[获取访问密钥](https://docs.aws.amazon.com/cli/latest/userguide/cli-authentication-user.html#cli-authentication-user-get)。
   + AWS 区域。这是您要在其中创建托管 AWS 资源的地理位置。在开发过程中，我们建议使用靠近您的实际位置的区域。从[支持的区域列表中选择一个 AWS 区域](https://docs.aws.amazon.com/general/latest/gr/gamelift.html)。

1. 如果插件检测到现有配置文件，则会显示可用配置文件列表。从列表中选择现有配置文件，或选择**添加其他配置文件**以创建新的配置文件。

## 引导用户配置文件
<a name="unreal-plugin-profiles-bootstrap"></a>

所有配置文件必须进行引导才能与 Amazon GameLift Servers 插件搭配使用。引导会创建特定于该配置文件的 Amazon S3 存储桶。它用于存储项目配置、构建构件和其他依赖项。存储桶不会在其他配置文件之间共享。

Bootstrapp涉及创建新 AWS 资源，并且可能会产生成本。

**要引导您的配置文件，请执行以下操作：**

1. 在 **AWS 访问凭证**页面上，检查要使用的用户配置文件的引导状态。如果配置文件的引导状态为“非活动”，并且未列出 S3 存储桶，则需要引导配置文件。

1. 选择要使用的配置文件，然后选择**引导配置文件**。

1. 等待引导状态变为“活动”。这可能需要几分钟的时间。

# 适用于 Unreal 的插件：集成游戏代码
<a name="unreal-plugin-integrate"></a>

在将游戏服务器部署到实例集之前，您需要对游戏代码进行一系列更新，并将游戏组件打包以供 Amazon GameLift Servers 服务使用。

本主题将介绍进行最小集成的步骤。要进行服务器集成，请使用提供的代码示例更新项目的游戏模式。
+ [设置生成包目标和模块规则](#unreal-plugin-anywhere-integrate-setup)
+ [更新游戏服务器代码](#unreal-plugin-anywhere-integrate-simple-server)
+ [整合客户端游戏地图](#unreal-plugin-anywhere-integrate-simple-client)
+ [打包游戏组件](#unreal-plugin-anywhere-integrate-build)

## 设置生成包目标和模块规则
<a name="unreal-plugin-anywhere-integrate-setup"></a>

修改您的游戏项目文件，以正确生成可与 Amazon GameLift Servers 搭配使用的生成包组件。

**要添加客户端和服务器生成包目标，请执行以下操作：**

1. 打开游戏项目的代码文件并找到 `.../Games/[your application name]Source/[your application name]Target.cs` 文件。示例：`.../Source/GameLiftUnrealAppTarget.cs`。（如果您使用 Visual Studio，请打开项目的 `.sln` 文件。）

1. 复制此文件，以在 `Source/` 目录中创建两个新的目标文件。
   + 客户端目标：将新文件重命名为 `[your application name]Client.Target.cs`。编辑内容以更新类名称和目标类型值，如以下示例代码所示：

     ```
     using 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.cs`。编辑内容以更新类名称和目标类型值，如以下示例代码所示：

     ```
     using 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");
          }
      }
     ```

1. 重新生成您的项目文件。如果您使用 Visual Studio，可以右键单击游戏项目的 `.uproject` 文件，然后选择**生成 Visual Studio 项目文件**。

**要更新游戏项目模块规则，请执行以下操作：**

更新游戏项目的模块规则，使其依赖于插件。

1. 打开游戏项目的代码文件并找到 `.../Games/[your application name]Source/[your application name].Build.cs` 文件。示例：`.../Source/GameLiftUnrealApp.Build.cs`。（如果您使用 Visual Studio，请打开项目的 `.sln` 文件。）

1. 找到 `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;
        }
    }
   ```

1. 创建新的目标文件并修改模块规则后，重新构建您的游戏项目。

## 更新游戏服务器代码
<a name="unreal-plugin-anywhere-integrate-simple-server"></a>

更新您的游戏服务器代码，以实现游戏服务器进程与 Amazon GameLift Servers 服务之间的通信。您的游戏服务器必须能够响应来自 Amazon GameLift Servers 的请求，例如启动和停止新的游戏会话。

**为 Amazon GameLift Servers 添加服务器代码**

1. 在代码编辑器中，打开游戏项目的解决方案（`.sln`）文件，该文件通常位于项目根文件夹中。例如：`GameLiftUnrealApp.sln`。

1. 打开解决方案后，找到项目游戏模式头文件：`[project-name]GameMode.h` 文件。例如：`GameLiftUnrealAppGameMode.h`。

1. 更改头文件以使其与以下代码保持一致。请务必用您自己的项目名称替换 GameLiftServer “”。这些更新特定于游戏服务器；我们建议您备份原始游戏模式文件副本，以供客户端使用。

### gameMode.h 示例代码
<a name="w2aab9c11b9c19c27c11b7b1"></a>

```
// 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;
};
```
+ 打开相关的源文件 `[project-name]GameMode.cpp` 文件（例如 `GameLiftUnrealAppGameMode.cpp`）。更改代码以使其与以下示例代码保持一致。请务必用您自己的项目名称替换 GameLiftUnrealApp “”。这些更新特定于游戏服务器；我们建议您备份原始文件副本，以供客户端使用。

  以下示例代码展示了如何添加服务器与 Amazon GameLift Servers 集成所需的最少元素：
  + 初始化 Amazon GameLift Servers API 客户端。Amazon GameLift Servers Anywhere 实例集需要使用服务器参数进行 `InitSDK()` 调用。当您连接到 Anywhere 实例集时，插件会将服务器参数存储为控制台参数。示例代码可以在运行时访问这些值。
  + 实现所需的回调函数以响应 Amazon GameLift Servers 服务的请求，包括 `OnStartGameSession`、`OnProcessTerminate` 和 `onHealthCheck`。
  + 准备好托管游戏会话时，请使用指定端口调用 `ProcessReady()` 以通知 Amazon GameLift Servers 服务。

### 游戏服务器示例代码
<a name="w2aab9c11b9c19c27c11c11b1"></a>

```
// 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 shutdown.
    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
}
```

## 整合客户端游戏地图
<a name="unreal-plugin-anywhere-integrate-simple-client"></a>

启动游戏地图包含蓝图逻辑和用户界面元素，这些元素已经包含请求游戏会话和使用连接信息连接到游戏会话的基本代码。您可以按原样使用地图，也可以根据需要对其进行修改。将启动游戏地图与其他游戏资产一起使用，例如 Unreal Engine 提供的第三人称模板项目。这些资产可在内容浏览器中找到。您可以使用它们来测试插件的部署工作流程，或者作为为游戏创建自定义后端服务的指南。

该启动地图具有以下特性：
+ 它包括 Anywhere 实例集和托管 EC2 实例集的逻辑。在运行客户端时，您可以选择连接到任一实例集。
+ 客户端功能包括查找游戏会话（`SearchGameSessions()`）、创建新的游戏会话（`CreateGameSession()`）以及直接加入游戏会话。
+ 它会从项目的 Amazon Cognito 用户群体中获得一个唯一的玩家 ID（这是部署的 Anywhere 解决方案的一部分）。

**要使用启动游戏地图**

1. 在 UE 编辑器中，打开**项目设置、地图和模式**页面，然后展开**默认地图**部分。

1. 对于**编辑器启动地图**，从下拉列表中选择 StartupMap “”。您可能需要搜索位于 `... > Unreal Projects/[project-name]/Plugins/Amazon GameLift Servers Plugin Content/Maps` 中的文件。

1. 对于**游戏默认地图**，请从下拉列表中选择相同的 StartupMap “”。

1. 对于**服务器默认地图**，对于虚幻引擎 5.6 或更高版本，选择 “Lv1\$1ThirdPerson”，对于早期版本，选择 ThirdPersonMap “”。这是您的游戏项目中包含的默认地图。这张地图是为游戏中的两个玩家设计的。

1. 打开服务器默认地图的详细信息面板。将 “**GameMode 覆盖**” 设置为 “无”。

1. 展开**默认模式**部分，将**全局默认服务器游戏模式**设置为您为服务器集成而更新的游戏模式。

对项目进行这些更改后，就可以开始构建游戏组件了。

**注意**  
对于虚幻引擎 5.6 或更高版本，如果在连接到游戏服务器后无法移动角色，请更新 BP\$1 ThirdPersonCharacter 蓝图以添加`IMC_Default`和的输入映射上下文，`IMC_MouseLook`如下所示：  

![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/gameliftservers/latest/developerguide/images/unreal-enhanced-input-blueprint.png)


## 打包游戏组件
<a name="unreal-plugin-anywhere-integrate-build"></a>

**打包游戏服务器和游戏客户端生成包**

1. 在 Unreal Engine 编辑器的源代码构建版本中打开游戏项目。

1. 如果使用虚幻引擎 5.6 或更高版本，请前往**编辑、项目设置、打包**。在**项目内容目录中找到 Cook 所有内容**并将其启用。

1. 使用编辑器打包游戏客户端和服务器生成包。

   1. 选择一个目标。前往**平台、Windows**，然后选择以下选项之一：
      + 服务器：`[your-application-name]Server`
      + 客户：`[your-application-name]Client`

   1. 启动构建。转到**平台、Windows、程序包项目**。

每个打包过程都会生成一个可执行文件：`[your-application-name]Client.exe` 或 `[your-application-name]Server.exe`。

在插件中，在本地工作站上设置客户端和服务器构建可执行文件的路径。

# 适用于 Unreal 的插件：使用 Amazon GameLift Servers Anywhere 在本地托管游戏
<a name="unreal-plugin-anywhere"></a>

使用此工作流程将您的本地工作站设置为使用 Anywhere 实例集的游戏服务器主机。在部署到基于云的托管式实例集之前，您可以使用该流程来测试您的游戏服务器集成。它也可用于在迭代游戏开发期间进行本地测试。

**要启动 Amazon GameLift Servers Anywhere 工作流程，请执行以下操作：**
+ 在 Unreal 编辑器主工具栏中，选择 Amazon GameLift Servers 菜单，然后选择**通过 Anywhere 托管**。此操作将打开插件页面**部署 Anywhere**，其中提供了集成、构建和启动游戏组件的六步流程。

## 步骤 1：设置配置文件
<a name="unreal-plugin-anywhere-profile"></a>

选择您要在遵循此工作流程时使用的配置文件。您选择的配置文件会影响工作流程中的所有步骤。您创建的所有资源都与个人资料的 AWS 账户相关联，并放置在个人资料的默认 AWS 区域中。个人资料用户的权限决定了您对 AWS 资源和操作的访问权限。

**设置用户配置文件**

1. 从可用配置文件的下拉列表中选择一个配置文件。如果您还没有个人资料或想要创建新的个人资料，请前往 **Amazon GameLift** 菜单并选择 “**设置 AWS 用户资料**”。

1. 如果引导状态不是“活动”，请选择**引导配置文件**并等待状态变为“活动”。

## 步骤 2：设置游戏代码
<a name="unreal-plugin-anywhere-integrate"></a>

在此步骤中，准备您的游戏服务器和游戏客户端生成包，使其能够与 Amazon GameLift Servers 搭配使用。如果您尚未集成游戏代码，请参阅[适用于 Unreal 的插件：集成游戏代码](unreal-plugin-integrate.md)。在本地工作站上输入游戏可执行文件的路径。
+ 游戏服务器：将您的游戏服务器与适用于 Amazon GameLift Servers 的服务器 SDK 集成，并打包您的游戏服务器生成包。有关说明，请参阅[适用于 Unreal 的插件：集成游戏代码](unreal-plugin-integrate.md)。游戏服务器必须与服务器 SDK 集成，才能与 Amazon GameLift Servers 服务建立通信，并响应启动新游戏会话和接受游戏客户端连接的提示。
+ 游戏客户端：您至少需要一个可以使用 IP 地址和端口信息连接到您的游戏服务器的游戏客户端。如果您尚未设置游戏客户端组件Amazon GameLift Servers，则可以使用该 AWS CLI 工具手动请求新的游戏会话、获取连接信息，然后使用该信息连接游戏客户端。

  有时，您需要借助后端服务向 Amazon GameLift Servers 服务发送新游戏会话请求，并将连接信息回传给游戏客户端。您可以使用插件附带的测试地图，将客户端 Amazon GameLift Servers 功能添加到您的游戏项目中。有关构建自定义解决方案的帮助，请参阅[集成 Amazon GameLift Servers 游戏客户端功能](gamelift-sdk-client-api.md)。

## 步骤 3：连接到 Anywhere 实例集
<a name="unreal-plugin-anywhere-fleet"></a>

在此步骤中，您将指定要使用的 Anywhere 实例集。Anywhere 实例集定义了一组计算资源，这些资源可以位于任何地方，用于托管游戏服务器。
+ 如果您当前使用的 AWS 账户已有 Anywhere 舰队，请打开舰队名称下拉字段并选择舰队。此下拉列表仅显示当前处于活动状态的用户配置文件 AWS 所在地区的 Anywhere 舰队。
+ 如果目前没有实例集，或者您想创建新实例集，请选择创建新的 Anywhere 实例集并提供实例集名称。

在您为项目选择 Anywhere 实例集后，Amazon GameLift Servers 会验证实例集状态是否处于活动状态并显示实例集 ID。您可以在 Unreal 编辑器的输出日志中跟踪此请求的进度。

## 步骤 4：注册工作站
<a name="unreal-plugin-anywhere-register"></a>

在此步骤中，您将本地工作站注册为新的 Anywhere 实例集中的计算资源。

**将您的工作站注册为 Anywhere 计算**

1. 输入本地计算机的计算名称。如果您在实例集中添加多个计算，则名称必须是唯一的。

1. 为您的本地计算机提供 IP 地址。此字段默认为您计算机的公有 IP 地址。您也可以使用 localhost（127.0.0.1），前提是在同一台计算机上运行游戏客户端和服务器。

1. 选择注册计算。您可以在 Unreal 编辑器的输出日志中跟踪此请求的进度。

作为对这一操作的响应，Amazon GameLift Servers 会验证它是否可以连接到计算并返回有关新注册的计算的信息。它还会创建游戏可执行文件在初始化与 Amazon GameLift Servers 服务的通信时所需的控制台参数。

## 步骤 5：生成身份验证令牌
<a name="unreal-plugin-anywhere-auth"></a>

基于 Anywhere 计算运行的游戏服务器进程需要身份验证令牌才能调用 Amazon GameLift Servers 服务。每当从插件启动游戏服务器时，该插件都会自动生成并存储 Anywhere 实例集的身份验证令牌。身份验证令牌值存储为命令行参数，您的服务器代码可以在运行时检索该参数。

上面提供的代码示例还可让您使用[适用于 API 请求的AWS 签名版本 4（SigV4）](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv.html)。Sigv4 是用于向 API 请求添加身份验证信息的 AWS 签名协议。

您无需在此步骤中执行任何操作。

## 步骤 6：启动游戏
<a name="unreal-plugin-anywhere-launch"></a>

至此，您已经完成了使用 Amazon GameLift Servers 在本地工作站上启动和玩多人游戏所需的所有任务。

**玩托管游戏**

1. 启动游戏服务器。游戏服务器将在准备好托管游戏会话时通知 Amazon GameLift Servers。

1. 启动您的游戏客户端，然后使用新功能启动新的游戏会话。此请求通过新的后端服务发送到 Amazon GameLift Servers。作为回应，Amazon GameLift Servers 会调用在本地计算机上运行的游戏服务器以启动新的游戏会话。当游戏会话准备好接受玩家时，Amazon GameLift Servers 会提供连接信息，供游戏客户端加入游戏会话。

# 适用于 Unreal 的插件：将游戏部署到托管式 EC2 实例集
<a name="unreal-plugin-ec2"></a>

在此工作流程中，部署您的游戏，使其托管在 Amazon GameLift Servers 托管的基于云的计算资源上。将您的集成式游戏服务器生成包上传到 Amazon GameLift Servers 服务进行部署。如果您尚未集成游戏代码，请参阅[适用于 Unreal 的插件：集成游戏代码](unreal-plugin-integrate.md)。此工作流程完成后，您将拥有一个可以连接到云端游戏服务器且正常运行的游戏客户端。

**要启动 Amazon GameLift Servers 托管的 Amazon EC2 工作流程，请执行以下操作：**
+ 在 Unreal 编辑器主工具栏中，选择 Amazon GameLift Servers 菜单，然后选择**通过托管式 EC2 进行托管**。此操作将打开插件页面**部署 Amazon EC2 Fleet**，其中提供了集成、构建、部署和启动游戏组件的六步流程。

## 步骤 1：设置配置文件
<a name="unreal-plugin-ec2-profile"></a>

选择您要在遵循此工作流程时使用的配置文件。您选择的配置文件会影响工作流程中的所有步骤。您创建的所有资源都与个人资料的 AWS 账户相关联，并放置在个人资料的默认 AWS 区域中。个人资料用户的权限决定了您对 AWS 资源和操作的访问权限。

**设置用户配置文件**

1. 从可用配置文件的下拉列表中选择一个配置文件。如果您还没有个人资料或想要创建新的个人资料，请前往 **Amazon GameLift** 菜单并选择 “**设置 AWS 用户资料**”。

1. 如果引导状态不是“活动”，请选择**引导配置文件**并等待状态变为“活动”。

## 步骤 2：设置游戏代码
<a name="unreal-plugin-ec2-integrate"></a>

在此步骤中，准备您的游戏服务器和游戏客户端生成包，使其能够与适用于 Unreal 的 Amazon GameLift Servers C\$1\$1 服务器 SDK 搭配使用。如果您尚未集成游戏代码并构建游戏客户端和服务器可执行文件，请参阅[适用于 Unreal 的插件：集成游戏代码](unreal-plugin-integrate.md)。在本地工作站上输入游戏可执行文件的路径。

在工作流程的这个步骤中，该插件会提供指向说明和源代码的链接，用于设置 Unreal 编辑器的源代码构建版本。在构建客户端和服务器组件时，需要使用源代码构建版本。

构建与服务器 SDK 集的游戏服务器后，请完成以下任务来做好准备，以便将其上传到 Amazon GameLift Servers 进行托管。

### 准备好服务器生成包以进行云部署（Windows）
<a name="w2aab9c11b9c19c35b9b9b1"></a>

在 Unreal 编辑器默认存储服务器生成包文件的 `WindowsServer` 文件夹中，添加以下内容：

1. **将服务器生成包安装脚本复制到 `WindowsServer` 文件夹的根目录中。**安装脚本包含在插件下载内容中。查找文件 `[project-name]/Plugins/Resources/CloudFormation/extra_server_resources/install.bat`。Amazon GameLift Servers 使用此文件在您的托管计算资源上安装服务器生成包。

1. **将 `VC_redist.x64.exe` 文件复制到 `WindowsServer` 文件夹的根目录中。**如果您使用的是 Unreal Engine 5.6 版或更高版本，可以跳过此步骤。此文件包含在您的 Visual Studio 安装中，通常位于 `C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Redist/MSVC/v142`。

1. **将 OpenSSL 库文件添加到游戏服务器生成包中。**如果您的游戏服务器与服务器 SDK 5.3 或更高版本集成，可以跳过此步骤。此版本包含在适用于 Unreal 的 Amazon GameLift Servers 插件 3.0 版或更高版本中。

   手动找到 OpenSSL 库并将其复制到您的游戏生成包目录中，位置为 `<YourGame>/Binaries/Win64`。您**必须**使用与您的 Unreal Engine 5 版本相同的 OpenSSL 版本。使用错误的 OpenSSL 库部署的游戏生成包将无法与 Amazon GameLift Servers 服务通信。

   在您的游戏引擎源代码中查找 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`

### 准备好服务器生成包以进行云部署（Linux）
<a name="w2aab9c11b9c19c35b9c11b1"></a>

有关如何准备专为 Linux 构建的游戏服务器的更多详细说明，请参阅[在 Amazon Linux 上为适用于 Unreal Engine 5 的 Amazon GameLift Servers 构建服务器 SDK](https://github.com/aws/amazon-gamelift-toolkit/tree/main/building-gamelift-server-sdk-for-unreal-engine-and-amazon-linux)。

1. **指定一个工作目录来整理生成包文件。**工作目录的结构按原样部署到每个托管计算资源上。添加您的 Linux 构建的游戏服务器以及所有依赖文件。

1. **在工作目录的根目录中创建服务器生成包安装脚本。**如果需要，请创建一个 `install.sh` 文件，并添加正确安装游戏服务器生成包所需的所有命令。Amazon GameLift Servers 使用此文件将服务器生成包安装到每个 EC2 托管资源上。

1. **将 OpenSSL 库文件添加到游戏服务器生成包中。**如果您的游戏服务器与服务器 SDK 5.3 或更高版本集成，可以跳过此步骤。

   手动查找并复制库。您**必须**使用与您的 Unreal Engine 5 版本相同的 OpenSSL 版本。使用错误的 OpenSSL 库部署的游戏生成包将无法与 Amazon GameLift Servers 服务通信。

   1. 在您的游戏引擎源代码中查找 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`

   1. 找到 OpenSSL 库后，将其复制到您的游戏生成包目录中，位置为 `<YourGame>/Binaries/Linux`。

## 步骤 3：选择部署方案
<a name="unreal-plugin-ec2-scenarios"></a>

在此步骤中，您可以选择此时要部署的游戏托管解决方案。使用任何方案，您都可以对游戏进行多个部署。
+ 单区域队列：将您的游戏服务器部署到活动配置文件默认 AWS 区域中的单个托管资源队列。此方案是测试服务器与 AWS 集成和服务器构建配置的良好起点。它部署了以下资源：
  + 已安装并运行游戏服务器构建的AWS 实例集（按需型）。
  + Amazon Cognito 用户群体和客户端，使玩家能够进行身份验证和开始游戏。
  + 与 APIs用户池关联的 API 网关授权器。
  + Web ACl 用于限制玩家对 API 网关的过多调用。
  + API 网关 \$1 Lambda 函数，供玩家申请游戏位置。如果两者都不可用，则此函数调用 `CreateGameSession()`。
  + API 网关 \$1 Lambda 函数，供玩家获取游戏请求的连接信息。
+ FlexMatch 舰队：将你的游戏服务器部署到一组舰队中，并设置一个带有规则的 FlexMatch 匹配器来创建玩家对战。此方案使用低成本的竞价型托管和一个多实例集、多位置结构，以实现持久可用性。当您准备好开始为托管解决方案设计对战构建器组件时，此方法非常有用。在这种方案下，您将为此解决方案创建基本资源，并可以根据需要后续对其进行自定义。它部署了以下资源：
  + FlexMatch 配对配置和配对规则设置为接受玩家请求和表单匹配。
  + 三个 AWS 实例集，安装了游戏服务器构建，并在多个位置运行。包括两个竞价型实例集和一个按需型实例集作为备份。
  + AWS 游戏会话放置队列，通过寻找尽可能好的托管资源（基于可行性、成本、玩家延迟等）并启动游戏会话来满足对提议对战的请求。
  + Amazon Cognito 用户群体和客户端，使玩家能够进行身份验证和开始游戏。
  + 与 APIs用户池关联的 API 网关授权器。
  + Web ACl 用于限制玩家对 API 网关的过多调用。
  + API 网关 \$1 Lambda 函数，供玩家申请游戏位置。此函数调用 `StartMatchmaking()`。
  + API 网关 \$1 Lambda 函数，供玩家获取游戏请求的连接信息。
  + Amazon DynamoDB 表，用于存储玩家的对战票证和游戏会话信息。
  + SNS 主题 \$1 用于处理事件的 Lambda 函数。 GameSessionQueue 

## 步骤 4：设置游戏参数
<a name="unreal-plugin-ec2-parameters"></a>

在此步骤中，您将描述要上传到的游戏 AWS；
+ 服务器生成包名称：为游戏服务器生成包提供一个有意义的名称。 AWS 使用此名称来指代上传并用于部署的服务器生成包的副本。
+ 服务器构建操作系统：输入构建服务器以在其中运行的操作系统。这将告诉 AWS 使用哪种类型的计算资源来托管您的游戏。
+ 游戏服务器文件夹：确定本地服务器构建文件夹的路径。
+ 游戏服务器构建：确定游戏服务器可执行文件的路径。
+ 游戏客户端路径：确定游戏客户端可执行文件的路径。
+ 客户端配置输出：此字段需要指向您的客户端版本中包含您的 AWS 配置的文件夹。在以下位置寻找：`[client-build]/[project-name]/Content/CloudFormation`。

## 步骤 5：部署方案
<a name="unreal-plugin-ec2-deploy"></a>

在此步骤中，您将根据所选的部署方案将游戏部署到云托管解决方案。在 AWS 验证服务器生成包、预置托管资源、安装游戏服务器、启动服务器进程以及让它们做好托管游戏会话的准备时，此过程可能需要数分钟。

要开始部署，请选择**部署 CloudFormation**。您可以在此处跟踪您的游戏托管状态。要了解更多详细信息，您可以登录 AWS 管理控制台查看 AWS 和查看事件通知。请务必使用与插件中活跃用户个人资料相同的账户、用户和 AWS 地区登录。

部署完成后，您的游戏服务器将安装在 AWS EC2 实例上。至少有一个服务器进程正在运行并准备开始游戏会话。

## 步骤 6：启动客户端
<a name="unreal-plugin-ec2-launch"></a>

至此，您已经完成了启动和玩使用 Amazon GameLift Servers 托管的多人游戏所需的所有任务。要玩游戏，请启动您的游戏客户端实例。

如果您部署了单个实例集方案，则可以用一个玩家打开一个客户端实例，进入服务器地图并四处移动。打开游戏客户端的其他实例，将第二个玩家添加到同一个服务器游戏地图中。

如果您部署了 FlexMatch 场景，则解决方案会等待至少两个客户端排队等候游戏会话放置，然后玩家才能进入服务器地图。

# 适用于 Unreal 的插件：将游戏部署到托管式容器实例集
<a name="unreal-plugin-container"></a>

使用此引导式插件工作流程为您的游戏服务器创建容器映像，并将其部署到基于容器的托管解决方案。如果您尚未集成游戏代码，请参阅[适用于 Unreal 的插件：集成游戏代码](unreal-plugin-integrate.md)。成功完成此工作流程后，您的容器化游戏服务器将在云中运行，您可以使用该插件启动游戏客户端、连接到游戏会话和玩游戏。

## 开始之前
<a name="unreal-plugin-container-prereqs"></a>

此工作流程假定您已完成以下任务。
+ **将游戏服务器代码与 Amazon GameLift Servers 服务器 SDK 集成。**您的托管游戏服务器必须能够与 Amazon GameLift Servers 服务通信，以便能够响应启动新游戏会话和报告游戏会话状态的请求。如果您尚未完成此任务，建议您先按照“通过 Anywhere 托管”插件工作流程进行操作。有关准备游戏服务器代码的指导，请参阅[更新游戏服务器代码](unreal-plugin-integrate.md#unreal-plugin-anywhere-integrate-simple-server)。对于托管式容器实例集，必须将游戏与服务器 SDK 5.2 版或更高版本集成。
**注意**  
如果您使用的是启动游戏地图，则此任务已经为您完成了。
+ **将游戏服务器可执行文件打包，以便在 Linux 上运行。**如果您在 Windows 上开发，并且集成了 C\$1\$1 服务器 SDK 5.2.x 版或更早版本，则需要使用 [Unreal 交叉编译工具包](http://cross-compile toolkit for your UE version)。或者，您可以设置一个单独的 Linux 工作区，或使用适用于 Linux 的 Windows 子系统（WSL）之类的工具。
+ **收集要与游戏服务器生成包一起部署的文件。**在本地计算机上，创建一个工作目录来整理将内置到游戏服务器容器映像中的文件。这些文件可能包括游戏依赖项、启动游戏服务器的脚本以及启动容器时的其他进程等。
+ **为游戏服务器生成包添加 OpenSSL 库文件。**如果您的游戏服务器与服务器 SDK 5.3 或更高版本集成，可以跳过此步骤。

  手动找到 OpenSSL 库并将其复制到您的游戏生成包目录中，位置为 `<YourGame>/Binaries/Win64`。您**必须**使用与您的 Unreal Engine 5 版本相同的 OpenSSL 版本。使用错误的 OpenSSL 库部署的游戏生成包将无法与 Amazon GameLift Servers 服务通信。

  要找到 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`
+ **将游戏客户端代码与 Amazon GameLift Servers 集成。**要完成此任务，其中一种方法是添加已集成的示例资产（包含在插件中）。有关准备游戏客户端代码的指导，请参阅[整合客户端游戏地图](unreal-plugin-integrate.md#unreal-plugin-anywhere-integrate-simple-client)。
+ **在本地计算机上安装 Docker。**如果您希望插件为您创建容器映像并将其推送到 ECR 存储库，则需要安装此工具。或者，您可以手动执行这些任务，并指示插件使用现有的容器映像。有关手动构建映像的更多信息，请参阅[为 Amazon GameLift Servers 构建容器映像](https://docs.aws.amazon.com/gameliftservers/latest/developerguide/containers-prepare-images.html)。

**要启动 Amazon GameLift Servers 托管式容器工作流程，请执行以下操作：**
+ 在 Unreal 编辑器主工具栏中，选择 Amazon GameLift Servers 菜单，然后选择**托管式容器**。此操作将打开插件页面 “**使用托管容器托管**”，该页面显示了使用游戏服务器版本创建容器镜像、将其部署到容器队列以及启动游戏的 step-by-step过程。

## 第 0 步：设置您的个人资料
<a name="unreal-plugin-container-profile"></a>

此部分显示您当前选择的用户配置文件。请确认当前的用户配置文件就是您希望在此工作流程中使用的配置文件。您在此工作流程中创建的所有资源都与个人资料的 AWS 帐户相关联，并放置在配置文件的默认 AWS 区域中。个人资料用户的权限决定了您对 AWS 资源和操作的访问权限。

在以下情况下，您可能需要修改所选的用户配置文件：
+ 当前未选择任何配置文件。
+ 您想要选择其他配置文件或创建新的配置文件。
+ 您需要引导所选的配置文件（如果引导状态为非活动）。

**设置或更改所选用户配置文件**
+ 在Amazon GameLift Servers菜单中，选择**开放 AWS 访问凭证**。

## 第 1 步：评测容器就绪情况
<a name="unreal-plugin-container-assess"></a>

在将游戏服务器部署到容器实例集之前，必须将其打包成容器映像并存储在 Amazon ECR 存储库中。该插件可以为您完成这些任务，或者您也可以手动完成这些任务。在此步骤中，提供有关您的容器映像和 ECR 存储库状态的信息。

使用评测问题告知插件，它需要采取哪些步骤：
+ **创建新的容器映像。**如果您选择此选项，下一步将提示您输入游戏服务器生成包目录和生成包可执行文件的位置。该插件使用 Dockerfile 模板（由 Amazon GameLift Servers 提供），并自动为您的游戏配置该模板。您可以参阅[为 Amazon GameLift Servers 构建容器映像](containers-prepare-images.md)，以查看该模板。选择此选项后，请指明您希望插件存储新映像的位置：
  + 创建一个新的 Amazon ECR 存储库，并将容器映像推送到该存储库。该插件使用您选择的用户个人资料 AWS 区域 中的 AWS 帐户和默认帐户创建私有 ECR 存储库。
  + 将容器映像推送到之前创建的 Amazon ECR 存储库。如果您选择此选项，下一步将提示您从列表中选择现有的 Amazon ECR 存储库。该列表包括该 AWS 账户的所有 Amazon ECR 存储库，并且默认出现在您选择的用户个人资料 AWS 区域 中。您可以选择公有存储库或私有存储库。
+ **使用现有的容器映像。**如果您手动构建了映像，我们建议您使用 Amazon GameLift Servers 提供的 Dockerfile 模板，该模板可在[为 Amazon GameLift Servers 构建容器映像](containers-prepare-images.md)中获取。选择此选项后，请指明映像的位置。
  + 本地存储的 Docker 生成的映像。如果您选择此选项，该插件会创建一个新的 Amazon ECR 私有存储库，并将本地映像文件推送到该存储库。下一步将提示您输入映像 ID，插件会使用该 ID 来找到映像文件。
  + 已存储在 Amazon ECR 存储库中的容器映像。如果您选择此选项，下一步将提示您从列表中选择现有的 Amazon ECR 存储库和映像。该列表包括该 AWS 账户的所有 Amazon ECR 存储库，并且默认出现在您选择的用户个人资料 AWS 区域 中。您可以选择公有存储库或私有存储库。

## 第 2 步：配置映像部署
<a name="unreal-plugin-container-configure"></a>

在此步骤中，提供插件将您的容器映像部署到容器实例集所需的信息。此步骤要求提供以下信息：
+ 您的游戏服务器生成包、容器映像或 Amazon ECR 存储库的位置，具体取决于您在第 1 步中的选择。
+ 用于托管式容器部署的方案。
+ 客户端配置输出路径。在您的客户端版本中选择包含您的 AWS 配置的文件夹。在以下位置寻找：`[client-build]/[project-name]/Content/CloudFormation`。
+ 可选部署设置。此部分包含插件默认使用的配置设置。您可以修改这些设置，也可以保留默认值
  + 默认情况下，游戏名称设置为游戏项目的名称。插件创建的所有 AWS 资源都引用游戏名称值。
  + 端口范围、内存限制和 vCPU 限制是容器实例集的配置设置。有关自定义这些值的更多信息，请参阅[配置网络连接](containers-design-fleet.md#containers-custom-network)以了解连接端口范围，并参阅[设置资源限制](containers-design-fleet.md#containers-design-fleet-limits)以了解资源限制。
  + 容器映像标签用于在 Amazon ECR 中对容器映像进行分类。默认值为 `unreal-gamelift-plugin`。
  + Amazon ECR 存储库的名称。只有在插件为您创建 ECR 存储库时，您才能编辑此字段以建议自定义名称。默认值为 `unreal-game lift-plugin-ecr-repository`。

### 部署方案选项
<a name="unreal-plugin-container-configure-scenarios"></a>

#### 单区域容器实例集
<a name="w2aab9c11b9c19c39c13b7b3b1"></a>

此方案将您的游戏服务器部署到单个容器实例集。它是测试服务器与 AWS 集成和容器配置的良好起点。它部署了以下资源：
+ Amazon GameLift Servers 容器组定义，描述了如何在容器实例集上部署和运行您的容器映像。
+ 已安装并运行您的游戏服务器容器的 Amazon GameLift Servers 容器实例集（按需型），附带别名。
+ Amazon Cognito 用户群体和客户端，使玩家能够进行身份验证和开始游戏。
+ 将用户池与 APIs关联的 API Gateway 授权方。
+ Web 访问控制列表（ACL），用于限制玩家对 API 网关的过多调用。
+ 代表游戏客户端向 Amazon GameLift Servers 服务发出请求的后端服务，例如请求游戏会话和加入游戏：
  + API 网关 \$1 Lambda 函数，供玩家申请游戏会话位置。如果没有可用的空闲位置，则此函数调用 `CreateGameSession()`。
  + API 网关 \$1 Lambda 函数，供玩家获取游戏请求的连接信息。

#### 包含 FlexMatch 的单区域容器实例集
<a name="w2aab9c11b9c19c39c13b7b3b3"></a>

此方案将您的游戏服务器部署到容器实例集、配置游戏会话放置并设置 FlexMatch 对战。当您准备开始为托管解决方案设计自定义配对器时，此方案非常有用。使用此方案时，您将为该解决方案创建基本资源，并可以根据需要后续对其进行自定义。它部署了以下资源：
+ Amazon GameLift Servers 容器组定义，描述了如何在容器实例集上部署和运行您的容器映像。
+ 已安装并运行您的游戏服务器容器的 Amazon GameLift Servers 容器实例集（按需型），附带别名。
+ FlexMatch 对战配置和对战规则设置为接受玩家请求和组成对战。
+ Amazon GameLift Servers 游戏会话队列，通过寻找尽可能好的托管资源（基于可行性、成本、玩家延迟等）并启动游戏会话来满足对提议对战的请求。
+ Amazon Cognito 用户群体和客户端，使玩家能够进行身份验证和开始游戏。
+ 将用户池与 APIs关联的 API Gateway 授权方。
+ Web 访问控制列表（ACL），用于限制玩家对 API 网关的过多调用。
+ 代表游戏客户端向 Amazon GameLift Servers 服务发出请求的后端服务，例如请求游戏会话和加入游戏：
  + API 网关 \$1 Lambda 函数，供玩家申请游戏会话位置。如果没有可用的空闲位置，则此函数调用 `StartMatchmaking()`。
  + API 网关 \$1 Lambda 函数，供玩家获取游戏请求的连接信息。
+ DynamoDB 表，用于存储玩家的对战票证和游戏会话信息。
+ 亚马逊 SNS 主题 \$1 用于处理事件的 Lambda 函数。 GameSessionQueue

## 部署容器实例集
<a name="unreal-plugin-container-deploy"></a>

实例集配置完成后，选择**部署容器实例集**按钮以开始部署。插件将创建容器映像并将其推送到 ECR，为容器实例集预调配托管资源，并为所选托管解决方案场景部署实例集和其他 AWS 资源，整个过程可能需要几分钟。

开始部署时，您可以跟踪每个步骤的进度。根据您的配置，步骤可能包括以下内容：
+ 配置容器映像
+ 创建新的 Amazon ECR 存储库 
+ 构建映像并推送到 Amazon ECR
+ 创建容器组定义
+ 创建容器实例集

有关更详细的部署信息，请选择**在 AWS 管理控制台中查看**。当容器实例集达到活动状态时，即表示实例集正在主动运行容器，其中的服务器进程已准备好托管游戏会话。

部署完成后，您将拥有一个正常运行的容器实例集，随时可以托管游戏会话并接受玩家连接。

您无法停止正在进行的部署。如果部署进入不良状态或失败，您可以使用**重置部署**选项重新开始。

## 启动客户端
<a name="unreal-plugin-container-launch"></a>

至此，您已经完成了启动和玩使用 Amazon GameLift Servers 托管的多人游戏所需的所有任务。要玩游戏，请选择**启动客户端**以启动游戏客户端的本地实例。
+ 如果您部署了单个实例集方案，请打开一个包含一名玩家的游戏客户端实例，然后进入服务器地图并进行移动操作。您可以打开游戏客户端的第二个实例，将第二名玩家添加到同一个服务器游戏地图中。
+ 如果您部署了 FlexMatch 方案，则托管解决方案会等待至少两个游戏客户端发出对战请求。打开至少两个游戏客户端实例，每个实例各包含一名玩家。这两名玩家将进行匹配，并收到加入游戏会话以进行对战的提示。

## 更新容器实例集
<a name="unreal-plugin-container-update"></a>

如果您已成功部署托管式容器托管解决方案，可以使用**更新部署**功能。此选项可让您更新已部署容器实例集的配置设置，而无需创建新的实例集。

更新部署时，您可以部署包含不同游戏服务器生成包的容器映像，更改 Amazon ECR 存储库，选择不同的部署方案，以及自定义可选配置设置。

如果您已准备好部署更改，请选择“更新”。部署更新所需的时间与全面部署所需的时间类似。要了解详细的部署信息，请选择**在 AWS 管理控制台中查看**。

## 清理已部署的资源
<a name="unreal-plugin-container-cleanup"></a>

作为最佳实践，请在不再需要托管容器解决方案时立即清理这些 AWS 资源。如果不删除这些资源，它们可能会继续产生费用。

请删除以下资源：
+ 托管式容器资源堆栈。此堆栈中的资源取决于您选择的部署方案。要删除整个堆栈，请使用 CloudFormation 控制台。从 Amazon GameLift Servers 插件生成的堆栈使用以下命名规范：`GameLiftPluginForUnreal-{GameName}-Containers`。在插件中启动新的托管式容器部署之前，请等待堆栈删除过程完成。有关更多信息，请参阅[从 CloudFormation 控制台删除堆栈](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-delete-stack.html)。
+ Amazon ECR 存储库。如果您使用插件为容器映像创建了存储库，可能需要删除所有不再需要的存储库。在重置托管式容器部署之前，无需删除存储库。如果您更新或重置部署，除非指示使用其他存储库，否则插件将自动使用同一个存储库。有关更多信息，请参阅[在 Amazon ECR 中删除私有存储库](https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-delete.html)。