亚马逊AWS官方博客

UnrealEngine 5 结合 AmazonGameLift 在 Graviton3 上的实践

方案总览

虚幻引擎 5 提供了一个名为 Lyra 的免费示例游戏项目,支持在线多人游戏,我们将通过这个项目来构建专用服务器。在本教程中,我们将 Amazon GameLift 插件集成到 Lyra 中,并描述如何使用 Amazon GameLift Anywhere 来测试和迭代您的游戏服务器,最后将其部署到 GameLift Managed Fleet 上。GameLift 目前已经 Graviton3 的机型,用户在使用 Graviton 的机型后,可以帮助客户大大节省成本,本文会大家逐步完成实践。因在本文发布时,GameLift Server SDK 支持的 UE 最高的版本是 5.3,所以下面内容均是在 5.3.2 这个版本上进行构建。

环境信息

  1. AWS CLI
  2. Visual Studio 2022 可以参考配置:Epic 官方
  3. Github Account
  4. EpicGames Account
  5. Epic Games Store
  6. Cross-Compile Toolchain
  7. Nvidia Driver
  8. OpenSSL 安装完全版本,不要安装 Light 版本,并添加环境变量

源码编译 UE5

下载 UE5 代码

注册 Epic Game 账户后,参考链接 https://www.unrealengine.com/en-US/ue-on-github 关联 Github Org 下载源码

然后 Github 邀请加入到 EpicGames Organization

然后就可以访问 https://github.com/EpicGames/UnrealEngine 下载源码进行后续编译了

源码构建,参考:文档

将代码存放在 C 盘根目录下防止因为目录太长导致报错,本文中将文件解压存放地址 C:\UnrealEngine-5.3.2

然后执行执行命令 C:\UnrealEngine-5.3.2\Setup.bat

生成 UE5.sln

执行 C:\UnrealEngine-5.3.2\GenerateProjectFiles.bat,这一步会生成 VS2022 要用到的 .sln 文件: UE5.sln

如果报错找不到包,如下所示,考虑增加在线源

C:\UnrealEngine-5.3.2\Engine\Source\Programs\Shared\EpicGames.UBA\EpicGames.UBA.csproj : error NU1301: 未能从远程源“https://a
pi.nuget.org/v3-flatcontainer/microsoft.csharp/index.json”检索有关“Microsoft.CSharp”的信息。 [C:\UnrealEngine-5.3.2\Engine\Sour
ce\Programs\UnrealBuildTool\UnrealBuildTool.csproj]
C:\UnrealEngine-5.3.2\Engine\Source\Programs\Shared\EpicGames.UHT\EpicGames.UHT.csproj : error NU1301: 未能从远程源“https://a
pi.nuget.org/v3-flatcontainer/microsoft.csharp/index.json”检索有关“Microsoft.CSharp”的信息。 [C:\UnrealEngine-5.3.2\Engine\Sour
ce\Programs\UnrealBuildTool\UnrealBuildTool.csproj]

整个 Build 过程可能需要的时间比较久,当大家看到类似下面信息后则 Build 成功

12>Total time in Parallel executor: 1650.13 seconds
12>Total execution time: 1851.52 seconds
========== Build: 12 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 4:31 AM and took 31:07.296 minutes ==========

下载安装 Sample Game:Lyra Starter Game

打开 Epic Games Store,找到 Lyra Starter Game 点击创建项目

等待几分钟,项目便会生成在指定目录下。

构建 Lyra Game

1. 在我们指定的下载目录下找到 Lyra Game 文件,在 LyraStarterGame 右键 Generate Visual Studio project files,生成 LyraStarterGame.sln 项目文件

2. 双击 LyraStarterGame.uproject 文件,在 Unreal Editor 中打开 Lyra Game。下面可以参考博客(从调整工程参数开始),UE 官网中配置 Lyra 构建,出包并分别出服务端,客户端打包测试工作

3. 在此过程中,如果在 Visual Studio 2022 中 Build Solution 报错,信息如下:

CS8604 Possible null reference argument for parameter 'other' in 'void HashSet<string>.UnionWith(IEnumerable<string> other)'.BuildGraph.Automation
CA2200 Re-throwing caught exception changes stack information

可以参考 https://github.com/EpicGames/UnrealEngine/pull/11110/files 这个 PR 来进行修改后,重新 Build Solution。

构建 Amazon GameLift Plugin

Amazon GameLift plugin 支持在 Windows 以及 Linux 服务器进行构建,但是我们需要将 GameLift Server SDK 进行重新编译并将其放到 UE project 的 plugin 里。

C++ Server SDK下载地址

编译 Game Lift Managed Servers C++ SDK For Windows

前提条件:需要安装 Git.

1. 打开 Visual Studio 2022 Developer Command Prompt

2. 修改目录至 C++ SDK 文件目录

3. 使用以下命令编译 Windows 版本插件

mkdir out 
cd out 
cmake -G "Visual Studio 17 2022" -DBUILD_FOR_UNREAL=1 .. 
msbuild ALL_BUILD.vcxproj /p:Configuration=Release

4. 上面命令会产生两个文件至 out\gamelift-server-sdk\Release 目录

aws-cpp-sdk-gamelift-server.lib、aws-cpp-sdk-gamelift-server.dll

编译 Game Lift Managed Servers C++ SDK For Linux2023

1. 创建测试使用 EC2

2. 通过 SSH 登陆到 EC2 上,安装 git 并 clone amazon-gamelift-toolkit

sudo yum install git docker
sudo systemctl enable docker
sudo systemctl start docker
git clone https://github.com/aws/amazon-gamelift-toolkit.git
cd amazon-gamelift-toolkit/building-gamelift-server-sdk-for-unreal-engine-and-amazon-linux

在这里我们需要确认当前的 UE 支持的 Openssl 的版本,通常我们可以通过 package 的 output log 来看到如下的日志信息:

LogInit:  - supports SSL with OpenSSL/1.1.1t

所以通过上面的内容,我们目前测试使用的 UE5.3 匹配的 OpenSSL 的版本为 1.1.1t,所以我们需要修改以下内容来编译 GameLift Server SDK

首先需要修改 Docker File,如下所示:

FROM public.ecr.aws/amazonlinux/amazonlinux:latest as build-server
# Install dependencies
RUN yum install -y gcc-c++ gdb cmake3 git wget openssl openssl-devel tar perl sudo

# Install correct OpenSSL version. NOTE: You might need to change this based on your Unreal Engine 5 version and the OpenSSL version it utilizes
RUN wget https://github.com/openssl/openssl/archive/refs/tags/OpenSSL_1_1_1t.tar.gz && \
tar -xzvf OpenSSL_1_1_1t.tar.gz && \
cd openssl-OpenSSL_1_1_1t/ && \
./config && \
sudo make install && \
mkdir lib && \
cp libssl.so.1.1 /lib && \
cp libcrypto.so.1.1 /lib

RUN export LD_LIBRARY_PATH=/usr/local/lib:/usr/local/lib64 && \
openssl version && \
cd ..

# Copy the Open SSL files to binaries folder
RUN mkdir /binaries && \
cp ./openssl-OpenSSL_1_1_1t/libssl.so.1.1 /binaries/ && \
cp ./openssl-OpenSSL_1_1_1t/libcrypto.so.1.1 /binaries/

# Download and build the GameLift Server SDK (NOTE: You might need to change this to download a different SDK version)
RUN echo "Download and unzip GameLift Server SDK 5.1.2" && \
mkdir SDK && cd SDK && \
wget https://gamelift-server-sdk-release.s3.us-west-2.amazonaws.com/cpp/GameLift-Cpp-ServerSDK-5.1.2.zip && \
unzip GameLift-Cpp-ServerSDK-5.1.2.zip && \
echo "Build the GameLift server SDK" && \
mkdir cmake-build && \
export OPENSSL_ROOT_DIR=/openssl-OpenSSL_1_1_1t/ && \
export OPENSSL_LIBRARIES=/openssl-OpenSSL_1_1_1t/lib/ && \
cmake -G "Unix Makefiles" -DBUILD_FOR_UNREAL=1 -DCMAKE_BUILD_TYPE=Release -S . -B ./cmake-build && \
cmake —build cmake-build —target all && \
cd ./cmake-build/prefix/ && \
echo "Copying files over to binaries folder" && \
cp -r ./lib/* /binaries/ && \
echo "copying over headers (these are already provided by the GameLift Unreal Plugin so you don't need them with that)" && \
mkdir /binaries/include && \
cp -r ./include/* /binaries/include/

# Copy the binaries only to a clean setup for copying to local system after build
FROM scratch AS server
COPY —from=build-server /binaries/ /
ENTRYPOINT [ "/GameLiftSampleServer" ]

此处我们需要修改 buildbinaries.sh 修改 docker build 中的 platform 值为 arm64

#!/bin/bash
echo "Building the Unreal GameLift Server SDK binaries for Amazon Linux 2023..."
docker buildx build --platform=linux/arm64 --output=./ --target=server . # 此处需要修改platform的值为arm64,因为我们需要将DS运行在Graviton机器上
echo "Done, now zipping the content.."
zip -r AL2023GameliftUE5sdk.zip lib*
echo "Done! Select Actions -> Download File and type AL2023GameliftUE5sdk.zip to download the binaries."

3. 执行命令,获取编译包

sudo ./buildbinaries.sh

执行完毕后,下载 AL2023GameliftUE5sdk.zip 至 Windows 机器上

配置 Amazon GameLift Unreal Plugin

下载安装 Plugin

1. 在亚马逊云科技官网下对应 UE 版本的插件,解压文件,并拷贝插件至 Lyra 项目中,目录结构如下

2. 在 UE Project 中添加 GameLiftServerSDK Plugin,在 LyraStarterGame.uproject 文件中添加如下记录

{
    "Name": "GameLiftServerSDK",
    "Enabled": true
}

3. /Source/LyraGame/LyraGame.Build.cs 文件中添加 GameLiftServerSDK 到公共依赖列表中


PublicDependencyModuleNames.AddRange(
    new string[] {
        "Core",
        ...
        "GameLiftServerSDK" # 添加这一行至此
    }
);

4. 解压 AL2023GameliftUE5sdk.zip 并将其中的 libaws-cpp-sdk-gamelift-server.so 文件拷贝至 LyraStarterGame\Plugins\GameLiftServerSDK\ThirdParty\GameLiftServerSDK\Linux\x86_64-unknown-linux-gnu 目录下

5. 拷贝上面 Windows 下编译的两个文件 aws-cpp-sdk-gamelift-server.lib、aws-cpp-sdk-gamelift-server.dll 到目录 LyraStarterGame\Plugins\GameLiftServerSDK\ThirdParty\GameLiftServerSDK\Win64

6. 打开 LyraStarterGame.uprojet,会提示如下信息,点击 Yes 重新 rebuild,可能需要等个几分钟

7. 重新 Build 完毕,插件引入完毕

代码集成 GameLift

本文我们会集成 GameLift Anywhere Fleet 和 GameLift Managed Fleet 两种方式,当我们在 Anywhere 模式调用 InitSDK() 来初始化 Amazon GameLift 服务器 SDK 时,您需要提供一个 FServerParameters 对象,其中包含了 SDK 应该如何初始化的值。而对于托管的 Amazon EC2 实例,这些服务器参数值可以留空。

我们需要在代码中实现:

  • 通过 InitSDK 操作初始化 Amazon GameLift 服务器 SDK,如果提供了命令行参数,则使用这些参数。
  • 通过 ProcessReady 操作通知 Amazon GameLift 服务,我们的进程已准备好托管玩家,实现回调函数来处理来自 Amazon GameLift 服务的请求,以检查进程健康状况、激活新的游戏会话和终止运行中的游戏会话。

1. 打开 Source\LyraGame\GameModes\LyraGameMode.h 添加代码如下

private:
void InitGameLift();
protected:
virtual void BeginPlay() override;

2. 打开 Source\LyraGame\GameModes\LyraGameMode.h 添加 include header 代码如下

#include “GameLiftServerSDK.h”

3. 在文件 LyraGameMode.cpp 末尾处添加 GameLift 集成相关代码

void ALyraGameMode::BeginPlay()
{
    // Code enclosed with the WITH_GAMELIFT=1 flag is only processed if the following are true:
    // The plugin found the Amazon GameLift server SDK binary files.
    // The build is a game server : Target.Type == TargetRules.TargetType.Server

#if WITH_GAMELIFT
    InitGameLift();
#else
    UE_LOG(LogTemp, Warning, TEXT("WITH_GAMELIFT is false. InitGameLift() not called."));
#endif
}

void ALyraGameMode::InitGameLift()
{
    FString AuthToken;
    FString HostId;
    FString FleetId;
    FString WSSUrl;

    FServerParameters serverParameters;
    FGameLiftGenericOutcome initSdkOutcome;

    UE_LOG(LogLyra, Log, TEXT("Running on port %d"), GetWorld()->URL.Port);

    bool bIsAnywhereActive = false;
    if (FParse::Param(FCommandLine::Get(), TEXT("glanywhere")))
    {
        bIsAnywhereActive = true;
    }
    else
    {
        UE_LOG(LogLyra, Log, TEXT("The -glanywhere parameter is not active."));
    }

    //Getting the module first.
    FGameLiftServerSDKModule* gameLiftSdkModule = &FModuleManager::
        LoadModuleChecked<FGameLiftServerSDKModule>(FName("GameLiftServerSDK"));

    if (bIsAnywhereActive)
    {
        UE_LOG(LogLyra, Log, TEXT("Configuring server parameters for Anywhere..."));

        FParse::Value(FCommandLine::Get(), TEXT("-authtoken="), serverParameters.m_authToken);

        if (FParse::Value(FCommandLine::Get(), TEXT("-hostid="), serverParameters.m_hostId))
        {
            UE_LOG(LogLyra, Log, TEXT("HOST_ID: %s"), *serverParameters.m_hostId)
        }

        if (FParse::Value(FCommandLine::Get(), TEXT("-fleetid="), serverParameters.m_fleetId))
        {
            UE_LOG(LogLyra, Log, TEXT("FLEET_ID: %s"), *serverParameters.m_fleetId)
        }

        if (FParse::Value(FCommandLine::Get(), TEXT("-websocketurl="), serverParameters.m_webSocketUrl))
        {
            UE_LOG(LogLyra, Log, TEXT("WEBSOCKET_URL: %s"), *serverParameters.m_webSocketUrl)
        }

#ifndef __linux__
        serverParameters.m_processId = FString::Printf(TEXT("%d"), GetCurrentProcessId());
#else
        serverParameters.m_processId = FString::Printf(TEXT("%d"), getpid());
#endif

        UE_LOG(LogLyra, Log, TEXT("PID: %s"), *serverParameters.m_processId);

        UE_LOG(LogLyra, Log, TEXT("Initializing the GameLift Server"));

        //InitSDK will establish a local connection with GameLift's agent to enable further communication.
        initSdkOutcome = gameLiftSdkModule->InitSDK(serverParameters);
    }
    else 
    {
        UE_LOG(LogLyra, Log, TEXT("Configuring server parameters for Managed Fleet"));
        initSdkOutcome = gameLiftSdkModule->InitSDK();
    }

    if (initSdkOutcome.IsSuccess())
    {
        UE_LOG(LogLyra, Log, TEXT("GameLift InitSDK succeeded"));
    }
    else
    {
        UE_LOG(LogLyra, Log, TEXT("ERROR: InitSDK failed"));
        FGameLiftError gameLiftError = initSdkOutcome.GetError();
        UE_LOG(LogLyra, Log, TEXT("ERROR: %s"), *gameLiftError.m_errorMessage);
        return;
    }

    //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(LogLyra, Log, TEXT("GameSession Initializing: %s"), *gameSessionId);
            gameLiftSdkModule->ActivateGameSession();
        };
    FProcessParameters* params = new FProcessParameters();
    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 shutdown.
    params->OnTerminate.BindLambda([=]() {
        UE_LOG(LogLyra, 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(LogLyra, Log, TEXT("Performing Health Check"));
        return true;
        });

    //The game server takes the port from the Unreal world.
    params->port = GetWorld()->URL.Port;

    //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("LyraStarterGame/Saved/Logs/LyraStarterGame"));
    params->logParameters = logfiles;
    //Calling ProcessReady tells GameLift this game server is ready to receive incoming game sessions!
    UE_LOG(LogLyra, Log, TEXT("Calling Process Ready"));
    FGameLiftGenericOutcome processReadyOutcome = gameLiftSdkModule->ProcessReady(*params);
    if (processReadyOutcome.IsSuccess())
    {
        UE_LOG(LogLyra, Log, TEXT("Process Ready Succeded"));
    }
    else
    {
        UE_LOG(LogLyra, Log, TEXT("ERROR: Process Ready Failed"));
        FGameLiftError processReadyError = processReadyOutcome.GetError();
        UE_LOG(LogLyra, Log, TEXT("ERROR: %s"), *processReadyError.m_errorMessage);
    }
    UE_LOG(LogLyra, Log, TEXT("Init GameLift complete"));
}

4. 在 Visual Studio 2022 中重新 Build Development Server Solution Configuration

配置 Amazon GameLift Anywhere fleet on Windows

我们首先在 GameLift Anywhere 上测试当前集成是否符合预期。

1. 创建一个自定义位置并指定一个位置名称。自定义位置名称必须以”custom-“开头,并且长度至少为 8 个字符

aws gamelift create-location --location-name custom-arm-test

2. 使用新创建的位置创建一个 Fleet,并将计算类型指定为 ANYWHERE

aws gamelift create-fleet --name arm-test-fleet-win --compute-type ANYWHERE --locations "Location=custom-arm-test"

3. 上面命令的返回后,我们需要记录一下 FleetId 的值,下面我们将测试服务器注册到 Fleet 上去

aws gamelift register-compute --compute-name win-server2 --fleet-id <fleet-id> --ip-address <ip address> --location custom-arm-test

4. 系统会返回一个 JSON 对象,请记录下 GameLiftServiceSdkEndpoint – 我们需要将其传递给我们的游戏服务器

5. 获取 Windows Server 的计算授权令牌

aws gamelift get-compute-auth-token --fleet-id <FleetId> --compute-name win-server1

系统会返回一个 JSON 对象,其中包含一个 AuthToken,在初始化 Amazon GameLift Server SDK 时,需要使用该令牌来对 Amazon GameLift 进行服务器授权。

需要注意 AuthToken 过期时间为 15 分钟, 一旦过期需要重新通过上面命令重新获取 Token。

6. 下面我们通过上面获取到的 AuthTokenGameLiftServiceSdkEndpointFleetIdComputeName 值启动 Lyra Server

LyraServer.exe -log -glanywhere -fleetid=<FleetId> -hostid=<ComputeName> -websocketurl=<GameLiftServiceSdkEndpoint> -authtoken=<AuthToken>

7. 启动日志有如下输出时,则说明集成成功

如果启动时,报错 ERROR: InitSDK failed 需要注意反复确认上面参数是否正确。

8. 在该 Fleet Server 上创建 Game Session,在生产环境我们建议使用 game session queuesgame session placement events 来管理 Game Session,因本文主要是测试,所以我们直接使用 create-game-session 来进行创建 Game Session,执行命令如下:

aws gamelift create-game-session --fleet-id <FleetId> --maximum-player-session-count 2 --location <LocationName>

命令执行完毕后,可以在 Game Server 的日志上可以看到:

[2024.09.17-05.14.44:408][756]LogLyra: GameSession Initializing: arn:aws:gamelift:us-east-1::gamesession/fleet-940a5d35-xxxxxx-883b-37e93b80fa33/custom-arm-test/gsess-067949f2-7c39-4371-a139-xxxxx

至此在 Windows 服务器上的测试完毕。

配置 Amazon GameLift Anywhere fleet on Linux Arm64

1. 首先我们需要打开 Game Lift Server SDK 中代码文件 GameLiftServerSDK.Build.cs,修改其中代码,大概在 45 行

# 在下面的判断地方需要添加: || Target.Platform == UnrealTargetPlatform.LinuxArm64,示例代码如下:
if (Target.Platform == UnrealTargetPlatform.Linux || Target.Platform == UnrealTargetPlatform.LinuxArm64)
{
    SDKDirectory = System.IO.Path.Combine(SDKDirectory, "x86_64-unknown-linux-gnu");
    string SDKLib = System.IO.Path.Combine(SDKDirectory, "libaws-cpp-sdk-gamelift-server.so");
                
    PublicAdditionalLibraries.Add(SDKLib);
    RuntimeDependencies.Add(SDKLib);
}

2. 在 Plugin 文件下创建 LinuxArm64 的文件夹

3. 拷贝上面打包好的依赖包放到如下目录下

4. 然后打开 Visual Studio 2022 下选择 Development Server 平台选择 LinuxArm64 重新 Build Solution

5. 通过交叉编译来打包 Lyra Server,我们首先 Cook Content,然后再 Package Project

等待几分钟后,将 Linux Arm64 下的游戏包打包完毕,此时我们需要将 libssl.so.1.1libcrypto.so.1.1 放到如下图的目录内

然后我们上传游戏包至 Linux Arm based Server 上

6. 注册 Linux Server 至 Fleet

aws gamelift register-compute --fleet-id <fleet-id> --compute-name linux-server1 --ip-address <ipaddrees> --location custom-arm-test

7. 获取 Linux  Server 的计算授权令牌

aws gamelift get-compute-auth-token --fleet-id <FleetId> --compute-name win-server1

8. 使用如下命令启动服务,并看到如下日志则表示启动成功

./LyraServer -log -glanywhere -fleetid=<fleet-id> -hostid=linux-server1 -websocketurl=wss://us-east-1.api.amazongamelift.com -authtoken=<上面获取到的token>

9. 创建 Game Session 进行测试

返回信息如下:

aws gamelift create-game-session —fleet-id <fleet-id> —maximum-player-session-count 2 —location custom-arm-test

10. 通过 Windows Lyra Client 连接进行测试

{
    "GameSession": {
        "GameSessionId": "arn:aws:gamelift:us-east-1::gamesession/fleet-xxxx-c956-4f6f-883b-37e93b80fa33/custom-arm-test/gsess-a1649483-3d82-4865-9845-fe2196fcaf9c",
        "FleetId": "fleet-940a5d35-c956-4f6f-883b-xxxx",
        "FleetArn": "arn:aws:gamelift:us-east-1:xxxx:fleet/fleet-xxxx-c956-4f6f-883b-37e93b80fa33",
        "CreationTime": "2024-09-19T08:14:15.909000+00:00",
        "CurrentPlayerSessionCount": 0,
        "MaximumPlayerSessionCount": 2,
        "Status": "ACTIVATING",
        "GameProperties": [],
        "IpAddress": "54.xxxx",
        "Port": 7777,
        "PlayerSessionCreationPolicy": "ACCEPT_ALL",
        "Location": "custom-arm-test"
    }
}

11. 通过 Lyra Client 来进行测试,命令参考如下:

./LyraClient.exe <IP>:7777 -WINDOWED -ResX=800 -ResY=450

此处需要注意记得开启 EC2 上 UDP 7777 的端口

至此,通过 GameLift Anywhere 在 Linux 上部署 Dedicated Server 的测试就完成了。

配置 GameLift Managed Fleet

1. 首先我们需要基于 Package 内容,创建 Build,上传完毕后,请记录下对应的 Build ID

aws gamelift upload-build \
--operating-system AMAZON_LINUX_2023 \
--server-sdk-version "5.1.2" \
--build-root /home/ec2-user/linuxarm64/ \
--name "arm-test" \
--build-version "v1" \
--region us-east-1

2. 基于上面的 Build 创建 GameLift Managed Fleet,创建完毕后,我们需要记录 Fleet ID

aws gamelift create-fleet \
--name ArmTestFleet1 \
--description "A arm test fleet" \
--region us-east-1 \
--ec2-instance-type c7g.2xlarge \
--fleet-type SPOT \
--build-id <build-id> \
--runtime-configuration "ServerProcesses=[{LaunchPath=/local/game/LyraServer-Arm64.sh, ConcurrentExecutions=1}]" \
--ec2-inbound-permissions "FromPort=7777,ToPort=7777,IpRange=0.0.0.0/0,Protocol=UDP"

3. Fleet 创建完毕后,等待它的状态变为 Active 状态,我们来创建 Game Session

aws gamelift create-game-session —fleet-id <fleet-id> —maximum-player-session-count 2

上面的命令,同样会返回类似如下内容:

4. 通过上面的 IP 和 Port,我们在 Windows 上进行测试一下

LyraClient.exe <IP>:7777 -WINDOWED -ResX=800 -ResY=450

至此我们通过 UE5 结合 GameLift Graviton 实例的实践就成功了。

总结

本文我们带大家逐步实现了将 UE5 的游戏部署到 Graviton3 的 GameLift Fleet 上,通过使用 GameLift 来托管游戏服,可以大大降低运维成本,再结合 Graviton 提供的性价比,可以让用户把更多的资源放到游戏研发上。亚马逊云科技每一年都会有新一代的 Graviton 机型的推出,同时带来更好的性价比。

常见问题

1. OpenSSL 问题,在 Linux 服务启动时如下错误时

[2024.09.19-07.06.05:937][ 0]LogCore: === Critical error: ===
Unhandled Exception: SIGSEGV: invalid attempt to access memory at address 0x0000ffff88fd24f0
[2024.09.19-07.06.05:937][ 0]LogCore: Fatal error!
0x0000ffff88fd24f0 libcrypto.so.3!UnknownFunction(0x3d24f0)
[2024.09.19-07.06.05:948][ 0]LogExit: Executing StaticShutdownAfterError
Malloc Size=131160 LargeMemoryPoolOffset=393352
Malloc Size=131160 LargeMemoryPoolOffset=524536
Malloc Size=100199 LargeMemoryPoolOffset=624759
[2024.09.19-07.06.05:960][ 0]LogHAL: Error: FUnixPlatformProcess::CreateProc: File does not exist (/home/ec2-user/linuxarm64/Engine/Binaries/LinuxArm64/CrashReportClient)

请使用 LDD 命令确保 Server SDK 文件的信息如下,则为正确打包信息,不然即会报如上错误

[ec2-user@ip-172-31-23-111 lib]$ ldd libaws-cpp-sdk-gamelift-server.so 
linux-vdso.so.1 (0x0000ffff83d9f000)
libssl.so.1.1 => /usr/local/lib/libssl.so.1.1 (0x0000ffff83bac000)
libcrypto.so.1.1 => /usr/local/lib/libcrypto.so.1.1 (0x0000ffff83800000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x0000ffff83400000)
libm.so.6 => /lib64/libm.so.6 (0x0000ffff83afb000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000ffff837bf000)
libc.so.6 => /lib64/libc.so.6 (0x0000ffff83232000)
/lib/ld-linux-aarch64.so.1 (0x0000ffff83d52000)

2. 如果在打开 LyraStarterGame.uproject 文件时,报插件需要重新构建,此时可以打开 LyraStarterGame.sln,然后在 Visual Studio 里重新 Build 一下即可,如下图所示

3. 安装 .Net 3.5 Framework 报错

执行时可能会报错 .Net 3.5 Framework 无法安装,可以通过服务器管理器来进行安装,如下图所示

参考资料

https://thinkwithwp.com/blogs/gametech/unreal-engine-5-dedicated-server-development-with-amazon-gamelift-anywhere/

https://thinkwithwp.com/cn/blogs/china/unreal-engine-5-dedicated-server-running-on-amazon-graviton-4/

本篇作者

边学明

英雄互娱极光工作室后端主程,十余年游戏行业开发设计经验,擅长游戏后端架构设计及基于云原生的大型 FPS、MMO 游戏架构设计。

吕书顺

英雄互娱资深 C++ 开发工程师,主要负责数据库、网络及其它核心模块的底层设计及关键组件封装工作,拥有多年的游戏开发经验。

郭俊龙

亚马逊云科技解决方案架构师,主要负责游戏行业客户解决方案设计,比较擅长云原生微服务以及大数据方案设计和实践。