跳到主要内容

战斗会话

1. 什么是战斗会话

战斗会话用于协助游戏 DS 管理游戏战斗和战斗中的玩家。当通过匹配或房间创建战斗时,会同时生成一个战斗会话。

NOTE

PGOS 允许玩家同时加入多个战斗会话。游戏客户端可以使用 DescribeBattleSessions API 查询玩家参与的战斗会话。

2. 架构图

游戏客户端通过 PGOS Client SDK 访问战斗会话服务。

  • 点击此处了解如何通过匹配发起战斗会话。
  • 点击此处了解如何通过房间发起战斗会话。

游戏 DS 通过 PGOS Server SDK 访问战斗会话服务。

  • 点击此处了解如何管理战斗会话的生命周期以及战斗会话中的玩家。

1631516746552

3. 查询战斗会话

3.1 从战斗会话日志中查询战斗会话

打开网页门户,选择"战斗"菜单下的"战斗会话"子菜单。您可以使用以下参数搜索战斗会话:

  • Fleet。战斗会话所在的 DS fleet。
  • 配置。生成战斗会话的匹配/房间配置。
  • ID。指定战斗会话 ID。战斗会话 ID 可以从客户端的匹配结果或 DS 端的 FDelegateOnStartBattleSession 事件中获取。
  • 状态。战斗会话的状态。
  • 创建时间。战斗会话的创建时间。

image-20220607194347829

导出搜索结果:您可以将搜索结果导出为CSV文件,PGOS支持最多导出5,000条数据。如果数据超过5,000条,则只会导出前5,000条数据。

查看战斗会话详情:点击战斗会话搜索结果中的战斗会话ID可查看详细信息。

3.2 查询指定Fleet的战斗会话

查询指定Fleet下的战斗会话的另一种方法是:打开web门户,选择DS & Builds菜单下的Fleets子菜单,然后选择Battle Sessions标签页。

1631517935782

在战斗会话搜索结果中点击战斗会话ID以查看详细信息。

4. 战斗会话详情

点击战斗会话搜索结果中的战斗会话 ID可查看详细信息。每个战斗会话包含以下信息:

  • 战斗会话 ID
  • 对局配置名称。 生成战斗会话的对局配置。
  • Fleet ID
  • 状态。 战斗会话状态。点击此处了解如何通过 PGOS Server SDK 激活战斗会话。
  • 等待中 – 战斗会话已放置,等待运行
  • 运行中 – 战斗会话已被 DS 激活,可接收玩家
  • 已超时 – 如果战斗会话未在指定时间内激活,将会超时。战斗会话的超时时间由托管它的 Fleet 配置决定。点击此处了解更多信息
  • 已终止 – 战斗会话已被 DS 结束或从控制台终止
  • 失败 – 战斗会话放置失败
  • IP:端口。 为战斗会话指定的 IP 地址和用于连接战斗会话的端口号。
  • 玩家。 已连接到战斗会话的玩家数量以及战斗会话支持的最大玩家数。
  • 运行时间。 战斗会话运行的总时长。
  • 创建时间。 战斗会话创建的日期和时间戳。

当战斗会话状态为运行中时,您可以点击终止按钮手动取消该战斗会话。这是一个异步操作,将在 1 分钟内生效。

image-20210422113604379

当战斗会话终止后,您可以点击"下载日志"来下载战斗会话日志。

image-20210422113317134

4.1 玩家战斗会话

战斗会话为每个被分配到战斗中的玩家维护一个玩家战斗会话。当战斗会话被游戏 DS 激活时,这些玩家战斗会话会立即初始化。 注意: 我们为每个玩家的战斗会话维护一组数据,以帮助您追踪战斗中的玩家。您可以在战斗会话的详情页面查看这些信息。

1631519416863

  • Player Battle Session ID(玩家战斗会话ID): 分配给玩家战斗会话的标识符。
  • Player(玩家): 显示玩家的名称。点击可查看玩家的详细信息。
  • Status(状态): 玩家战斗会话状态。点击此处了解如何在游戏DS上管理玩家战斗会话
  • Reserved(已预留):玩家战斗会话已被预留,但玩家尚未连接。
  • Active(活跃):表示玩家已连接到游戏DS。
  • Completed(已完成): 玩家战斗会话已结束。这表示玩家不再连接。
  • Disconnected(已断开):表示玩家已从游戏DS断开连接。
  • Uptime(运行时间): 玩家在战斗会话中保持活跃状态的总时长。
  • Connect Time(连接时间): 玩家连接到游戏服务器的日期。
  • erminate Time(终止时间): 玩家从游戏服务器断开连接的日期。

4.2 状态转换

4.2.1 战斗会话的状态转换

1631797728221

  • (1) PendingActive
    • DS 可以通过调用接口 ActivateBattleSession 触发此状态转换
  • (2) PendingTimeout
    • 如果 DS 未在限定时间内调用 ActivateBattleSession,将触发此状态转换
  • (3) ActiveTerminated
    • DS 可以通过调用接口 ProcessEnding 触发此状态转换

4.2.2 玩家战斗会话的状态转换

1631797156846

  • (1) DummyReserved
    • 当战斗会话被 DS 激活时,所有玩家战斗会话转变为 Reserved 状态
  • (2) ReservedActive
    • 仅 DS 可以通过调用接口 AcceptPlayerBattleSession 触发此状态转换
  • (3) ReservedCompleted
    • DS 可以通过调用接口 RemovePlayerBattleSession 触发此状态转换
    • 客户端可以通过调用接口 TerminatedPlayerBattleSession 触发此状态转换
  • (4) ActiveDisconnected
    • DS 可以通过调用接口 DisconnectPlayerBattleSession 触发此状态转换
  • (5) ActiveCompleted
    • DS 可以通过调用接口 RemovePlayerBattleSession 触发此状态转换
    • 客户端可以通过调用接口 TerminatedPlayerBattleSession 触发此状态转换
  • (6) DisconnectedCompleted
    • DS 可以通过调用接口 RemovePlayerBattleSession 触发此状态转换
    • 客户端可以通过调用接口 TerminatedPlayerBattleSession 触发此状态转换
  • (6) DisconnectedActive
    • DS 可以通过调用接口 AcceptPlayerBattleSession 触发此状态转换

4.3 管理游戏 DS 上的战斗会话和玩家战斗会话

请参考相关文档

4.4 在游戏客户端访问玩家对战会话

4.4.1 API列表

API描述
DescribePlayerBattleSession【已弃用!!!】已声明为弃用,建议改用 DescribeBattleSessions。
DescribeBattleSessions获取玩家正在参与的对战会话列表。
TerminatePlayerBattleSession尝试终止玩家的战斗会话。调用成功后,玩家将无法再进入此战斗会话,请谨慎使用

4.4.2 API 使用说明

UPgosBattleAPI::DescribeBattleSessions 此接口返回当前玩家已激活的对战会话信息,同时返回游戏 DS 的访问信息。如果您的客户端意外关闭并希望重新连接到之前的对战时,可以调用此接口获取必要的访问信息。

接口原型:

  /**
* Get the player's battle session info.
*
* @param PlayerId The player id
*/
void DescribeBattleSessions(
TFunction<void(const FPgosResult& Ret, const FClientPlayerBattleSessionInfo * Data)> Callback) const;

示例代码:

  #include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::SomeFunction()
{
auto Battle = IPgosSDKCpp::Get().GetClientBattleAPI();
if (Battle)
{
FString PlayerId;
Battle->DescribeBattleSessions([](const FPgosResult& Ret, const DescribeBattleSessionsResult * Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("DescribeBattleSessions Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("DescribeBattleSessions Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

UPgosBattleAPI::TerminatePlayerBattleSession 此接口将强制将玩家战斗会话的状态更改为已完成。调用此接口将触发PGOS服务器SDK的回调:UPgosHostingAPI::OnPlayerBattleSessionsTermianted,以通知游戏DS这些已离开战斗会话的玩家。

接口原型:

  /**
* Try to terminate the player's battle session.
* After the calling is successful, players will no longer be able to enter this battle session, please use with caution
*
* @param BattleSessionId The battle session id
* @param PlayerBattleSessionId The player battle session id
*/
void TerminatePlayerBattleSession(
const FString& BattleSessionId,
const FString& PlayerBattleSessionId,
TFunction<void(const FPgosResult& Ret)> Callback) const;

示例代码:

  #include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::SomeFunction()
{
auto Battle = IPgosSDKCpp::Get().GetClientBattleAPI();
if (Battle)
{

FString BattleSessionId;
FString PlayerBattleSessionId;
Battle->TerminatePlayerBattleSession(BattleSessionId, PlayerBattleSessionId, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("TerminatePlayerBattleSession Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("TerminatePlayerBattleSession Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

4.5 战斗会话中玩家管理建议

本章列举了几个典型场景,说明玩家如何离开战斗会话。旨在帮助您了解玩家战斗会话的管理。开发时请遵循游戏机制。

PGOS 严格限制每个玩家同一时间只能有一个活跃的战斗会话,因此了解战斗会话中的玩家战斗会话管理,有助于您为玩家提供符合预期的在线游戏体验。

4.5.14.5.1 完全由 DS 管理

即玩家战斗会话的状态完全由游戏 DS 管理。这意味着在游戏 DS 调用RemovePlayerBattleSession接口之前,玩家无法进入任何其他战斗会话。 这种解决方案适用于希望严格限制玩家退出正在进行的战斗会话的游戏,但也会对玩家体验产生负面影响:玩家似乎在某种程度上失去了一些自由。 使用此解决方案的一般游戏流程如下:

  • 玩家与游戏 DS 断开连接后立即从战斗会话中移除
sequenceDiagram participant DS2 participant Client participant DS participant PGOS ServerSDK Note left of Client: Player join a battle session Client->>DS: Connect DS->>PGOS ServerSDK: AcceptPlayerBattleSession Note left of Client: Player disconnect DS-->>Client: Disconnect DS->>PGOS ServerSDK: RemovePlayerBattleSession Note left of Client:Player could join a new battle session Client->>DS2: Connect
  • 保持玩家的战斗会话直到战斗会话结束。

    sequenceDiagram participant Client participant DS participant PGOS ServerSDK Note left of Client: Player join a battle session Client->>DS: Connect DS->>PGOS ServerSDK: AcceptPlayerBattleSession Note left of Client: Player disconnect DS-->>Client: Disconnect DS->>PGOS ServerSDK: DisconnectPlayerBattleSession Note left of Client:Player reconnect to the DS Client->>DS: Connect DS->>PGOS ServerSDK: AcceptPlayerBattleSession Note left of DS: Battle ending DS->>PGOS ServerSDK: Remove all players by calling RemovePlayerBattleSession

4.5.2 允许客户端退出战斗会话

在此解决方案中,玩家可以通过在客户端调用TerminatePlayerBattleSession接口来退出正在进行的战斗会话。无论客户端当时是否已登录游戏DS。

将退出正在进行的战斗会话的权限交给玩家,可以防止玩家被不良战斗所困扰,但这会对战斗中的其他玩家产生负面影响。开发者需要权衡其利弊。

使用此解决方案的一般游戏流程如下:

sequenceDiagram participant DS2 participant Client participant DS participant PGOS ServerSDK Note left of Client: Player join a battle session Client->>DS: Connect DS->>PGOS ServerSDK: AcceptPlayerBattleSession Note left of Client: Player disconnect DS-->>Client: Disconnect DS->>PGOS ServerSDK: DisconnectPlayerBattleSession Note left of Client:Player could leave the battle Client->>Client: TermaintePlayerBattleSession(player_id_x) PGOS ServerSDK->>DS:OnPlayerBattleSessionTerminated[player_id_x] Note left of Client:Player could join a new battle session Client->>DS2: Connect

4.5.3 检查玩家的进行中战斗会话

我们强烈建议您在游戏客户端启动后调用DescribePlayerBattleSession接口,以确认玩家是否有正在进行的战斗会话信息。因为如果存在进行中的战斗会话且玩家的战斗会话状态不是Completed,玩家将无法进入其他战斗。在这种情况下,玩家大致有两个选择:

  • 通过调用TerminatePlayerBattleSession接口离开战斗会话,然后探索更多乐趣。
sequenceDiagram participant PGOS ClientSDK participant Client participant DS Client->>PGOS ClientSDK: Client launched Client->>PGOS ClientSDK: DescribePlayerBattleSession Note left of Client:Leave current battle Client->>PGOS ClientSDK: TerminatePlayerBattleSession
  • 重新连接到 DS 以继续正在进行的战斗。

    sequenceDiagram participant PGOS ClientSDK participant Client participant DS participant PGOS ServerSDK Client->>PGOS ClientSDK: Client launched Client->>PGOS ClientSDK: DescribePlayerBattleSession Note left of Client:Continue current battle Client->>DS: Connect DS->>PGOS ServerSDK: AcceptPlayerBattleSession

5. 战斗数据

战斗数据旨在构建可从游戏客户端访问的战斗历史信息。游戏可以使用战斗数据来自定义其战斗历史功能。 相关文档:战斗数据的典型用例请参见此处.

5.1 集成步骤

游戏可以通过 PGOS Server SDK 和 PGOS Client SDK 访问战斗数据服务。 通过 PGOS Server SDK,游戏可以:

  • 以 key-value 格式为指定的战斗会话构建战斗数据。
  • 为战斗数据设置字符串格式的标签。

通过 PGOS Client SDK,游戏可以:

  • 查询指定玩家的战斗数据列表,并通过标签和键进行筛选。
  • 查询指定战斗会话 ID 的战斗数据,并通过键进行筛选。

1605606131176

5.2 概念

  • 战斗数据。 一组与战斗会话ID绑定的key-value键值对持久化数据,通常用于记录战斗属性信息、玩家信息、战斗统计信息等数据。
  • 战斗记录。 PGOS保存了玩家参与过的所有战斗会话ID。即使游戏没有写入任何战斗数据,仍然可以通过PGOS提供的接口获取玩家的战斗会话信息。
  • 简要信息和详细信息。 我们使用'brief'和'detail'作为保留键来存储战斗的简要信息和详细信息。系统提供了一组封装接口来访问这些键。当然,这些接口是可选的,游戏可以构建自己的战斗数据来处理复杂场景。

在封装接口中,我们抽象了以下两个概念:

  • 简要信息。'brief' key对应的字符串值。通常,我们建议游戏使用简要信息来存储简短且高度精炼的信息,如获胜队伍、开始时间、击杀/死亡率等。
  • 详细信息。键'detail'对应的字符串值。通常,我们建议游戏使用详细信息来存储较长且复杂的信息,如每个玩家的统计数据。如果简要信息已足够满足游戏需求,则详细信息不是必需的

概念图示:

1646121114802

注意事项

战斗数据的key或Value不支持二进制字符串

5.3 构建基于 Key-Value 的战斗数据

备注

仅限 PGOS Server SDK。

通过战斗数据服务为战斗会话构建战斗数据。

  1. 通过调用 UpdateBattleData 向战斗的战斗数据中添加 key-value 键值对信息
  • BattleSessionID。战斗会话 ID。
  • RecordData。自定义键值对。

按如下方式从 Battle 模块调用 UpdateBattleData

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::UpdateBattleData()
{
auto battle = IPgosSDKCpp::Get().GetServerBattleAPI();
if (battle)
{
FString BattleSessionID;
TMap<FString, FString> RecordData;

battle->UpdateBattleData(BattleSessionID, RecordData, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("UpdateBattleDataSuccess"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("UpdateBattleDataFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
  1. 通过调用 DeleteBattleData 从战斗数据中删除键值

    • BattleSessionID:战斗会话ID。
    • Keys:需要删除的战斗数据键值。 按照以下方式从 Battle 模块调用 DeleteBattleData
    #include "PgosSDKCpp.h"
    #include "Core/PgosErrorCode.h"

    void SomeUObjectClass::DeleteBattleData()
    {
    auto battle = IPgosSDKCpp::Get().GetServerBattleAPI();
    if (battle)
    {
    FString BattleSessionID;
    TArray<FString> Keys;

    battle->DeleteBattleData(BattleSessionID, Keys, [](const FPgosResult& Ret, const FServerDelBattleDataResult* Data) {
    if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
    {
    UE_LOG(LogTemp, Log, TEXT("DeleteBattleDataSuccess"));
    }
    else
    {
    UE_LOG(LogTemp, Log, TEXT("DeleteBattleDataFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
    }
    });
    }
    }

5.4 设置战斗标签

备注

仅限 PGOS Server SDK。

通过调用来设置战斗会话的标签。

  • BattleSessionID。用于构建战斗历史数据的战斗会话 ID。
  • Tags。战斗历史记录的标签。主要用于从游戏客户端查询战斗历史记录时过滤项目。

Battle 模块调用 UpdateBattleRecord 如下:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::UpdateBattleRecord()
{
auto battle = IPgosSDKCpp::Get().GetServerBattleAPI();
if (battle)
{
FString BattleSessionID;
TArray<FString> PlayerIDs;
TArray<FString> Tags;

battle->UpdateBattleRecord(BattleSessionID, PlayerIDs, Tags, [](const FPgosResult& Ret) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("UpdateBattleRecordSuccess"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("UpdateBattleRecordFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
提示

从v0.15.0版本开始,api UpdateBattleRecord 中的 player_ids 已弃用

5.5 查询对战记录

备注

仅限 PGOS Client SDK。

调用 GetBattleRecordList 可批量获取玩家的对战记录。您将获得每条对战记录的所有 key-value 键值对,这些键值对是由游戏服务器通过 UpdateBattleData 设置的。

  • PlayerID. 要查询的玩家 ID。
  • Tags. 获取特定标签的列表,如果标签为空,则不会进行标签过滤。- Keys. 获取特定键的列表,如果键为空,则不会进行键过滤。
  • Offset. 列表的起始位置。
  • Count. 列表的数量。

Battle 模块调用 GetBattleRecordList 的方式如下:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::GetBattleRecordList()
{
auto battle = IPgosSDKCpp::Get().GetClientBattleAPI();
if (battle)
{
FString PlayerID;
TArray<FString> Tags;
TArray<FString> Keys;
int32 Offset;
int32 Count;

battle->GetBattleRecordList(PlayerID, Tags, Keys, Offset, Count, [](const FPgosResult& Ret, const FClientBattleListInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetBattleRecordListSuccess"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetBattleRecordListFailed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

5.6 查询战斗数据

备注

仅限 PGOS Client SDK。

调用 GetBattleData 可以批量获取特定战斗会话的战斗数据。您将获得每个战斗数据的指定 key-value 对,这些数据是由游戏服务器通过 UpdateBattleData 设置的。

  • BattleSessionID. 要查询的 ID。
  • Keys. 获取特定键的列表,如果键为空,则不会进行过滤。

Battle 模块调用 GetBattleData 的方式如下:

#include "PgosSDKCpp.h"
#include "Core/PgosErrorCode.h"

void SomeUObjectClass::GetBattleData()
{
auto battle = IPgosSDKCpp::Get().GetClientBattleAPI();
if (battle)
{
FString BattleSessionID;
TArray<FString> Keys;

battle->GetBattleData(BattleSessionID, Keys, [](const FPgosResult& Ret, const FClientBattleDataInfo* Data) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetBattleDataSuccess"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetBattleDataSuccess: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}

6. 关键错误处理

Error Code相关 APIHandling Suggestion
kBackendNeedRetryActivateBattleSession
HeartbeatBattleSession
TerminateBattleSession
AcceptPlayerBattleSession
RemovePlayerBattleSession
DisconnectPlayerBattleSession
这表示对战会话的操作失败。分布式锁机制保证了并发安全性。建议在有限次数内重试直至成功。