在 Amazon GameLift 服务器上托管永久世界游戏

作者: Juho Jantunen |

多人游戏已经从纯粹的基于会话的传统大型多人在线游戏 (MMO) 演变为结合持续元素和基于会话的元素的新型在线体验。像《命运 2》和《Rust》这样的游戏就是很好的例子。持久的游戏玩法可以是"中心"或"家庭世界",玩家可以在其中漫步并与之互动,然后进入基于会话的体验。这些游戏可以让玩家创建新的持久世界,并随心所欲地登录和退出。支持这一新浪潮的多人游戏体验需要灵活的技术,无论是游戏会话管理还是游戏世界数据持久化。

Amazon GameLift Servers 是一款专门构建的解决方案,用于在全球范围内托管多种类型的多人游戏。该服务支持多种用例,从基于会话的经典游戏到不同类型的持续游戏玩法。为 Amazon GameLift 服务器引入容器支持简化了托管持久世界和基于会话的游戏所面临的挑战。持久世界游戏可以在每个游戏服务器上运行 sidecar 容器进程,以访问数据库获取持久性数据。您还可以将世界状态管理拆分为多个容器进程,这些进程可以通过本地主机进行通信。当您需要访问游戏的其他亚马逊云科技服务时,基于容器的队列的 Amazon Identity and Access Management (IAM) 角色会自动分配给每个容器,从而允许您使用亚马逊云科技开发工具包和亚马逊云科技命令行接口 (亚马逊云科技 CLI)。

在这篇文章中,我们将介绍如何将持续游戏和基于会话的游戏玩法相结合。这包括如何执行以下操作:

  • 管理持久世界的生命周期
  • 管理永久世界的玩家会话
  • 保持游戏世界的状态
  • 从持续体验中开始基于会话的游戏

管理持久世界的生命周期

持久世界鼓励你根据需要创建新世界,并允许玩家加入和离开它们。世界的创建可以由玩家触发,也可以由你的后端集中管理。你还需要将玩家引导到这些世界并管理玩家会话。

第一步是以 zip 文件或容器镜像的形式上传游戏服务器版本,然后创建一个全球舰队以托管在 Amazon GameLift Servers 上。多位置功能允许您在全球范围内托管离玩家很近的游戏世界。容器入门套件是让任何游戏服务器版本在该服务上运行的快捷简便方法。

要在舰队上创建游戏世界实例,请使用带有亚马逊云科技开发工具包的 CreateGameSession API。调用 API 时,您需要传递位置和任何游戏世界特定的元数据,以创建世界并接收世界信息作为响应。要获得更多基于事件的流程,您还可以使用 Amazon GameLift 服务器队列,并通过队列将游戏会话置于舰队上。

CreateGameSession 调用(使用亚马逊云科技 CLI 进行演示目的)的示例请求可能如下所示:

aws gamelift create-game-session \
  --fleet-id my-fleet-id \
  --location us-west-2 \
  --maximum-player-session-count 200 \
  --game-properties "Key=worldName,Value=MyWorld" "Key=mapToLoad,Value=HomeArena"

成功的响应如下所示:

{
 "GameSession": {
  "GameSessionId": "arn:aws:gamelift:us-west-2::gamesession/id",
  "FleetId": "my-fleet-id",
  "FleetArn": "arn:aws:gamelift:us-west-2:111122223333:my-fleet",
  "CreationTime": "2025-02-18T20:51:01.714000+00:00",
  "CurrentPlayerSessionCount": 0,
  "MaximumPlayerSessionCount": 200,
  "Status": "ACTIVATING",
  "GameProperties": [],
  "IpAddress": "11.222.3.444",
  "DnsName": "ec2-11-222-3-444.us-west-2.compute.amazonaws.com",
  "Port": 4195,
  "PlayerSessionCreationPolicy": "ACCEPT_ALL",
  "Location": "us-west-2",
  "GameProperties": [
            {
                "Key": "worldName",
                "Value": "MyWorld"
            },
            {
                "Key": "mapToLoad",
                "Value": "HomeArena"
            }]
}

然后,你收到的游戏会话信息应存储在数据库中以备将来参考。存储数据的一个选项是 Amazon DynamoDB,它允许您大规模存储键值数据。下图显示了存储游戏世界信息的示例架构。游戏世界的创建可以由玩家请求触发(例如创建一个与朋友一起玩的持久世界),也可以由后端进程(例如根据开发者提供的配置配置持久世界)来触发。

架构展示了玩家如何从后端请求创建世界,然后后端调用 Amazon GameLift 服务器 API 来创建世界并将其存储到 Amazon DynamoDB。还显示了后端进程如何创建世界并将其数据存储到数据库的替代选项。

图 1:游戏会话创建(玩家和后端已启动)。

当游戏世界处于空闲状态或达到固定的生命周期时,基础游戏会话通常由游戏服务器进程本身终止。Amazon GameLift 服务器允许您根据需要托管游戏服务器进程。游戏服务器存储其状态并准备终止后,它调用 Amazon GameLift Server SDK 的 ProcessEnding() 方法来自动删除游戏会话。舰队立即创建了一个新流程,为托管另一个世界做好了准备。也可以使用游戏后端的 TerminateGameSession API 在外部触发游戏会话终止。使用此 API 的优雅终止选项时,游戏服务器会获得回调并可以管理正常终止。

管理永久世界的玩家会话

随着时间的推移,玩家通常可以离开并加入永久世界。您可以选择在后端管理玩家会话,也可以选择使用 Amazon GameLift 服务器的玩家会话功能。玩家会话是使用 CreatePlayerSession API 创建的。

以下是使用亚马逊云科技 CLI 请求玩家会话的示例:

aws gamelift create-player-session \
 --game-session-id arn:aws:gamelift:us-west-2::gamesession/id \
 --player-id 12345

成功响应后,您将收到可以传回游戏客户端的连接信息:

{
 "PlayerSession": {
  "PlayerSessionId": "psess-abcd1234",
  "PlayerId": "12345",
  "GameSessionId": "arn:aws:gamelift:us-west-2::gamesession/id",
  "FleetId": "my-fleet-id",
  "FleetArn": "arn:aws:gamelift:us-west-2:111122223333:my-fleet",
  "CreationTime": "2025-02-18T20:54:54.304000+00:00",
  "Status": "RESERVED",
  "IpAddress": "11.222.3.444",
  "DnsName": "ec2-11-222-3-444.us-west-2.compute.amazonaws.com",
  "Port": 4195
 }
}

然后,游戏客户端可以使用 IP/DnsNamePort 直接连接到会话。该 PlayerSessionId 属性可用于在游戏服务器端验证玩家身份并激活玩家会话。下图显示了玩家如何请求加入特定世界,从 DynamoDB 查询的世界信息,以及为该世界创建的玩家会话以提供连接信息。

架构图显示了玩家如何从后端请求游戏会话,然后后端从 Amazon DynamoDB 获取世界信息,并使用 Amazon GameLift API 创建玩家会话。

图 2:加入游戏世界。

要跟踪世界中当前的玩家会话数,例如已离开的玩家的更新信息,我们建议集中更新数据库中的游戏会话数据。你可以运行一个不断更新数据的后端进程。该 DescribeGameSessions API 可用于迭代所有游戏会话。每个请求最多可检索 100 个游戏会话,您可以使用响应中收到的 NextToken 来迭代所有会话。下图显示了此实现的示例。

架构图显示了后端进程如何使用 Amazon GameLift API 迭代游戏会话并将会话状态更新为 Amazon DynamoDB。

图 3:将游戏世界的当前状态更新到您的数据库。

保持游戏世界的状态

通常,当会话运行时,游戏世界的状态存储在内存中。但是,出于多种原因,我们建议定期将世界状态存储到外部数据存储中。原因之一是在保持空闲世界的状态后清理它们,这样你就可以在玩家重新加入时恢复状态。如果你托管的游戏世界的生命周期为数周甚至几个月,那么你希望能够恢复世界状态,以防游戏服务器进程崩溃,或者定期轮换世界以避免内存泄漏问题。

以下是一些用于存储游戏服务器舰队世界状态的选项:

  • 将世界保存文件直接存储到 Amazon S3
  • 在磁盘上运行本地数据库并将数据库转储/备份同步到 Amazon S3
  • 将世界数据作为键值数据存储在 DynamoDB 中
  • 实现一个安全的 API 层,该层接收世界数据并将其存储在您选择的数据库中

在以下部分中,我们将详细介绍这些选项中的每一个。

将世界保存文件直接存储到 Amazon S3

Amazon GameLift 服务器支持将 IAM 角色附加到您的队列中的亚马逊弹性计算云(Amazon EC2)实例或容器。您可以向该角色授予访问资源(例如 Amazon S3)的权限。可以使用亚马逊云科技开发工具包直接在游戏服务器进程上访问这些资源,也可以运行 sidecar 进程或容器来管理访问权限。

将世界保存文件直接存储到 Amazon S3 时,您可以在游戏服务器上生成保存文件并将其上传到 Amazon S3。如果你需要在稍后阶段在另一个游戏服务器进程上恢复世界状态,那么你可以在启动时加载世界数据。

在磁盘上运行本地数据库并将数据库转储同步到 Amazon S3

另一种方法是托管本地数据库,通常是基于 SQL 的数据库解决方案,游戏服务器会持续向其写入世界更新。然后,您将有一个边车进程或容器,它可以生成数据库转储并按您选择的时间间隔上传到 Amazon S3。

将世界数据作为键值数据存储在 DynamoDB 中

推荐的选择是将世界状态直接存储到数据库中,同样要么使用游戏服务器上的亚马逊云科技 SDK,要么使用游戏服务器与之通信的边车进程或容器。Amazon DynamoDB 是一个很好的高度可扩展的选项。

这种方法的好处是,您可以拥有一个完全托管的高度可扩展的键值数据库,并且所有世界状态变化都将近乎实时地记录。这种方法还提供了世界状态的无缝恢复。如果你的游戏设计要求玩家的每一个动作都必须立即保留,那么这种方法效果很好。亚马逊游戏新世界就是一个使用这种方法的游戏的例子,它每 30 秒处理大约 800,000 次写入来存储游戏状态。DynamoDB 的项目大小限制为 400 kB,因此您经常需要将世界数据拆分为多个项目。

使用 sidecar 进程进行存储和数据库

游戏服务器通常是你的虚幻、Unity 或其他游戏引擎版本的无头版本。直接从游戏服务器访问数据库或存储服务是可行的,但是将此责任分离到边车进程或容器可以带来几个好处:

  • 使用常用于 Python 或 Go 等后端功能的语言的亚马逊云科技开发工具包
  • 无需为游戏服务器项目带来更多依赖关系
  • 独立于游戏服务器开发和维护数据库和存储集成
  • 从游戏服务器进程中卸载 I/O 密集型数据库操作

Amazon GameLift Servers 容器队列允许您定义边车容器,游戏服务器可以访问该容器,例如使用本地主机 HTTPS 端点,如下图所示。

架构图显示了如何将边车进程用于 Amazon GameLift Servers 容器队列上托管的每个游戏会话。sidecar 与 Amazon S3 和 Amazon DynamoDB 通信以存储世界状态。

图 4:使用 sidecar 流程存储世界数据。

从持续体验中开始基于会话的游戏

当我们有了持续的经验后,我们可以回顾游戏中基于会话的元素。根据游戏设计的要求,这可能是玩家聚集在你的中心并前往基于会话的 PvE 冒险或基于配对的 PvP 体验。

无论如何,基于会话的游戏托管都是 Amazon GameLift 服务器的原生版本。首先,你上传游戏服务器版本,并设置你想在世界各地的哪些地点托管游戏。然后,根据体验的不同,你有两个选择:直接为一群玩家创建会话,或者使用配对。

为一群玩家创建会话

当你已经知道你要开始会话的玩家队伍(可能他们在你的中心世界中聚集在一起)时,你可以使用 Amazon GameLift 服务器队列为他们申请会话布局。你可以传递每位玩家在你支持的所有地点的延迟时间,也可以提供主办会话的地点的优先级列表。您还可以在放置请求中定义会话的属性。例如,游戏服务器进程接收这些信息并可以使用它来加载正确的地图。

以下是使用亚马逊云科技 CLI 请求多名玩家放置会话的示例:

aws gamelift start-game-session-placement \
  --game-session-queue-name my-game-session-queue \
  --placement-id "unique-id-1234" \
  --maximum-player-session-count 200 \
  --game-properties "Key=mapName,Value=DungeonRaid" "Key=difficulty,Value=hard" \
  --player-latencies "PlayerId=player1,RegionIdentifier=us-east-1,LatencyInMilliseconds=20" "PlayerId=player2,RegionIdentifier=us-east-1,LatencyInMilliseconds=30" \
  --desired-player-sessions "PlayerId=player1" "PlayerId=player2"

队列会发出放置事件,你的游戏后端可以处理这些事件,将会话信息传递给玩家。

使用配对对玩家进行分组

另一个选择是玩家选择他们想要加入的基于会话的体验,游戏后端为每个玩家创建配对门票,以找到优秀的玩家群体。这种使用 Amazon GameLift Servers FlexMatch 的内置配对可以根据延迟、队伍、技能等级和其他玩家属性制定匹配规则。如果你的牌手已经在持续的体验中创建了派对,那么他们可以配对在一起,确保他们在共享会话中加入同一个队伍。

以下是启动配对票证的示例 API 调用:

  aws gamelift start-matchmaking \
  --configuration-name "MyMatchmakingConfig" \
  --players 'PlayerId=player123,LatencyInMs={us-west-2=45,us-east-1=120},PlayerAttributes={skill={N=29}}'

对于预先组建的玩家队伍,你将在一次通话中传递所有玩家,以确保他们在共享会话中加入同一个队伍:

aws gamelift start-matchmaking \
--configuration-name "MyMatchmakingConfig" \
--players 'PlayerId=player1,LatencyInMs={us-west-2=45,us-east-1=120},PlayerAttributes={skill={N=29}}' \
          'PlayerId=player2,LatencyInMs={us-west-2=50,us-east-1=125},PlayerAttributes={skill={N=39}}'

结论

在这篇文章中,我们介绍了如何使用 Amazon GameLift 服务器在全球范围内托管持久的世界游戏。我们介绍了如何管理持久世界的玩家会话。此外,我们还讨论了保持世界状态的不同方法,并更深入地探讨了如何将基于会话的游戏玩法与持续体验相结合。

现代多人游戏使用多种策略来管理玩家的分组方式,以及如何将他们映射到游戏世界和基于会话的游戏玩法的不同实例。Amazon GameLift 服务器提供的功能和 API 使您能够构建与您的游戏设计完美契合的独特体验。此外,亚马逊云科技上服务广度的强大功能使您能够有效地扩展到管理后端功能和保持世界状态的不同方法。

立即开始使用用于多人游戏服务器托管的 Amazon GameLift 服务器。联系亚马逊云科技代表,了解我们如何帮助加速您的业务。

进一步阅读

  • 在亚马逊云科技上永久托管世界游戏
  • 在 Amazon GameLift 服务器上使用容器进行更快的多人游戏托管
  • Amazon GameLift 每款游戏实现了 1 亿并发连接用户


Juho Jantunen

Juho Jantunen

Juho Jantunen 是亚马逊云科技游戏团队的全球首席解决方案架构师,专注于游戏后端和游戏服务器托管解决方案。他拥有游戏行业和云技术背景,曾在亚马逊云科技上为拥有数百万玩家的多款游戏构建和运营游戏后端。


*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您发展海外业务和/或了解行业前沿技术选择推荐该服务。