事件管道

事件管道是 PlayFab Services SDK 的一项功能,主要目的是允许游戏开发人员发送存储在 PlayFab Insights 中的事件。 它允许开发人员指定正确遥测解决方案的批大小、发送频率和其他方面。

它有助于减轻游戏开发人员的负担,并代表他们处理所有这些方面。 支持可配置的事件管道。 游戏可以包含其中一个或多个管道,并且每个管道都可以使用其自己的属性进行配置。

让我们来了解一下管道的一些基本概念。

管道类型

管道类型与管道发出的事件类型直接相关。 开发人员可以实例化两种不同类型的管道:

  • 遥测事件管道:只能发出遥测事件并使用 写入遥测事件 REST API。

  • PlayStream 事件管道:只能发出 PlayStream 事件并使用 写入事件 REST API。

可以有多个具有不同类型和配置的管道,但值得一提的是,管道类型在创建后 无法 更改,需要重新实例化管道。

身份验证类型

管道创建的另一个重要部分是身份验证类型。 PlayFab 事件有两种受支持的身份验证机制 - 实体身份验证和遥测密钥身份验证。

当游戏开发人员想要将其事件与特定实体链接以进行进一步的聚合或分析时,将使用实体身份验证。 例如,游戏开发人员可以记录与玩家操作相关的事件,以便对允许分段的游戏玩家进行进一步的行为分析。

当游戏开发人员想要记录不需要链接到实体的事件时,将使用遥测密钥身份验证。 例如,在登录玩家之前,游戏可以开始发送与要收集的性能或特定指标相关的事件以供进一步分析。 无需执行常规实体身份验证过程即可完成此操作。

支持的身份验证类型/事件类型组合

实体身份验证 遥测密钥身份验证
遥测事件 有效 有效
PlayStream 事件 有效 无效

实体身份验证

此身份验证类型是正常且最常见的 PlayFab 身份验证方法。 它与特定实体密切相关,需要调用相应的 PlayFab 登录 API,以便获取要在任何后续调用中使用的实体令牌。 以下列表表示可与实体身份验证一起使用的不同类型的实体。

  • 命名空间:命名空间实体是指摄影棚内全部游戏的 所有 全局信息。
  • 游戏:游戏实体是该游戏的所有全局信息。
  • master_player_account:master_player_account 是由工作室中的所有游戏共享的玩家实体。
  • title_player_account:对于大多数开发人员来说,title_player_account 以最传统的方式表示玩家。
  • 字符:字符实体是 title_player_account 的子实体。
  • :组实体是其他实体的容器。 其当前仅限于玩家和角色。

有关不同实体类型的详细信息,请参阅 内置实体类型

此外,管道实体可以在管道创建后通过提供有效的 PFEntityHandle 进行更新。 因此,游戏开发人员可以添加实体以开始将其事件链接到实体(请参阅“切换到实体身份验证或更新实体 ”部分),甚至可以将其删除,以便记录与实体无关的内容(请参阅“切换到遥测密钥身份验证”部分)。

如果管道上存在实体,则它始终优先于遥测密钥身份验证。

遥测密钥身份验证

遥测密钥身份验证不需要实体令牌,因此它不与任何特定实体相关联。

如果使用遥测密钥身份验证,则在创建管道期间需要 PFEventPipelineTelemetryKeyConfig 结构。 此结构有两个主要部分:

  1. 遥测密钥,包含通过 PlayFab Game Manager 创建和管理的字符串。

  2. 一个 PFServiceConfigHandle,它让 SDK 知道哪个服务配置适合用于上传事件。 服务配置句柄是在 SDK 初始化期间通过调用 PFServiceConfigCreateHandle 创建的。

如果开发人员想要使用遥测密钥,请务必在管道创建时提供遥测密钥,因为在管道实例化后无法添加遥测密钥。

值得一提的是,遥测密钥身份验证仅适用于遥测事件; 它不支持 PlayStream 事件。

事件管道配置

如前所述,事件管道具有一些可配置的属性,可在通过 PFEventPipelineConfig 结构参数创建管道后提供这些属性。

可配置的属性为:

  • maxEventsPerBatch:将事件写入 PlayFab 之前批处理的最大事件数。
  • maxWaitTimeInSeconds:管道在发送不完整的批处理之前等待的最长时间。
  • pollDelayInMs:管道在清空后将从事件缓冲区再次读取的等待时间。
  • compressionLevel:定义用于压缩算法的压缩级别。 有关压缩的更多详细信息,请参阅 GZIP 压缩
  • retryOnDisconnect: 事件管道将重试发送因连接丢失而失败的事件。 仅适用于遥测事件管道。
  • bufferSize: 管道缓冲区中事件数的限制。

如果 PFEventPipelineConfig 仅指定了某些属性,则将覆盖为空的属性并使用默认值。

有关如何为事件管道更新这些属性的示例,请参阅更新管道配置

GZIP 压缩

事件管道提供使用 GZIP 压缩标准压缩正文有效负载的选项。

可以在 PFEventPipelineUpdateConfiguration API 参数的 PFEventPipelineConfig 结构中指定所需的压缩级别。

压缩级别越低,压缩程度越低,但速度最高,而压缩级别越高,压缩率越高,但压缩速度最慢。 压缩率的差异全部取决于要发送的数据类型。 根据数据的大小和随机性,压缩率即使在不同的级别上也可能相同。

权衡:

由于增加了运行压缩算法的复杂性,使用压缩会增加 CPU 时间,但另一方面,网络主体有效负载会显著减少。 因此,根据游戏需求和资源,是否应使用压缩由游戏开发人员决定。

根据内部验证,CPU 时间平均增加 20%,有效负载正文大小平均减少 91%。 这些百分比可能在很大程度上取决于被压缩的数据的有效负载大小和复杂程度。

事件处理程序

作为管道创建的一部分,游戏开发人员可以提供两个可选的事件处理程序,这些处理程序会在上传事件时调用。

但是,如果游戏开发人员想要“触发并忘记”体验,则可以省略提供事件处理程序。

可提供的事件处理程序如下所示:

  • PFEventPipelineBatchUploadSucceededEventHandler:顾名思义,它会接收成功上传到 PlayFab 的所有事件。

  • PFEventPipelineBatchUploadFailedEventHandler:在完成管道重试逻辑后,它将接收所有失败的事件。

管道创建示例

下面提供了有关如何基于前面讨论的主题实例化事件管道的不同示例。

  1. 使用实体身份验证创建遥测事件管道

    如果开发人员想要发送遥测事件,但不需要使用遥测密钥身份验证,可使用 PFEventPipelineCreateTelemetryPipelineHandleWithEntity API 实现此目的,如以下示例所示:

    void EventPipelineCreation(PFEntityHandle entityHandle, XTaskQueueHandle taskQueueHandle)
    {
        PFEventPipelineHandle handle;
    
        HRESULT hr = PFEventPipelineCreateTelemetryPipelineHandleWithEntity(
            entityHandle,                       // entityHandle
            taskQueueHandle,                    // queue
            nullptr,                            // eventPipelineBatchUploadedEventHandler
            nullptr,                            // eventPipelineBatchFailedEventHandler
            nullptr,                            // handlerContext
            &handle                             // eventPipelineHandle
        );
    
        if (FAILED(hr))
        {
            printf("Failed creating event pipeline: 0x%x\r\n", hr);
            return;
        }
    }
    

    此示例演示如何创建使用实体身份验证且没有处理程序的遥测事件管道。 这意味着管道会触发事件并忘记结果。

  2. 使用遥测密钥身份验证创建遥测事件管道

    如果开发人员想要发送遥测事件,并且需要使用遥测密钥身份验证,可使用 PFEventPipelineCreateTelemetryPipelineHandleWithKey API 实现此目的,如以下示例所示:

    void EventPipelineCreation(PFServiceConfigHandle serviceConfigHandle, XTaskQueueHandle taskQueueHandle)
    {
        PFEventPipelineHandle handle;
    
        PFEventPipelineTelemetryKeyConfig telemetryKeyConfig
        {
            "myTelemetryKey",                   // telemetryKey
            serviceConfigHandle,                // serviceConfigHandle
        };
    
        HRESULT hr = PFEventPipelineCreateTelemetryPipelineHandleWithKey(
            &telemetryKeyConfig,                // eventPipelineTelemetryKeyConfig
            taskQueueHandle,                    // queue
            nullptr,                            // eventPipelineBatchUploadedEventHandler
            nullptr,                            // eventPipelineBatchFailedEventHandler
            nullptr,                            // handlerContext
            &handle                             // eventPipelineHandle
        );
    
        if (FAILED(hr))
        {
            printf("Failed creating event pipeline: 0x%x\r\n", hr);
            return;
        }
    }
    

    此示例演示如何创建不使用实体身份验证的遥测事件管道。

    事件管道开始使用遥测密钥上传事件,以后可能会添加实体。 请参阅 切换到实体身份验证或更新实体

  3. PlayStream 事件管道创建

    如果开发人员想要发送 PlayStream 事件,则 PFEventPipelineCreatePlayStreamPipelineHandle API 将提供此目的,如以下示例所示:

    void EventPipelineCreation(PFEntityHandle entityHandle, XTaskQueueHandle taskQueueHandle)
    {
        PFEventPipelineHandle handle;
    
        HRESULT hr = PFEventPipelineCreatePlayStreamPipelineHandle(
            entityHandle,                       // entityHandle
            taskQueueHandle,                    // queue
            nullptr,                            // eventPipelineBatchUploadedEventHandler
            nullptr,                            // eventPipelineBatchFailedEventHandler
            nullptr,                            // handlerContext
            &handle                             // eventPipelineHandle
        );
    
        if (FAILED(hr))
        {
            printf("Failed creating event pipeline: 0x%x\r\n", hr);
            return;
        }
    }
    

    此示例演示如何创建使用实体身份验证且没有处理程序的 PlayStream 事件管道。 这意味着管道会触发事件并忘记结果。

  4. 使用事件处理程序的事件管道

    此示例演示如何将事件处理程序提供给管道创建 API。

    void CALLBACK OnBatchUploadedHandler(void* context, PFUploadedEvent const* const* events, size_t eventsCount)
    {
        // Handle response
    }
    
    void CALLBACK OnBatchUploadFailedHandler(void* context, HRESULT hr, const char* errorMessage, PFEvent const* const* events, size_t eventsCount)
    {
        // Handle response
    }
    
    void EventPipelineCreation(PFEntityHandle entityHandle, XTaskQueueHandle taskQueueHandle)
    {
        PFEventPipelineHandle handle;
    
        HRESULT hr = PFEventPipelineCreateTelemetryPipelineHandleWithEntity(
            entityHandle,                       // entityHandle
            taskQueueHandle,                    // queue
            OnBatchUploadedHandler,             // eventPipelineBatchUploadedEventHandler
            OnBatchUploadFailedHandler,         // eventPipelineBatchFailedEventHandler
            nullptr,                            // handlerContext
            &handle                             // eventPipelineHandle
        );
    
        if (FAILED(hr))
        {
            printf("Failed creating event pipeline: 0x%x\r\n", hr);
            return;
        }
    }
    

如示例中所示,OnBatchUploadedHandlerOnBatchUploadFailedHandler声明为创建事件管道时传递的两个不同的回调函数。 与事件关联的每个结果都基于这两个函数之一返回,具体取决于结果是成功还是失败。 这取决于游戏开发人员如何处理结果。

发出事件

创建事件管道后,发出事件是一项简单的操作。 游戏开发人员应调用 PFEventPipelineEmitEvent API,以接收现有的事件管道句柄和要发送的事件。

void EmitEvent(PFEventPipelineHandle handle)
{
    PFEvent myEvent
    {
        nullptr,
        "custom.playfab.events.PlayFab.Test.TelemetryEventPipelineTests",
        "TelemetryEvent",
        nullptr,
        "{}"
    };

    HRESULT hr = PFEventPipelineEmitEvent(
        handle,
        &myEvent
    );

    if (FAILED(hr))
    {
        printf("Failed emitting event: 0x%x\r\n", hr);
        return;
    }
}

请务必注意,使用遥测密钥身份验证时,作为 PFEntityKey 一部分的 entityType 的唯一有效值是“外部”。 将拒绝任何其他实体类型,并且不会上传事件。

使用遥测密钥身份验证时有效的 PFEntityKey 示例:

void EmitEvent(PFEventPipelineHandle handle)
{
    PFEntityKey pfEntityKey{ "my-unique-ID", "external" };  // Note the "external" value

    PFEvent myEvent
    {
        &pfEntityKey,
        "custom.playfab.events.PlayFab.Test.EventsWithTelemetryKey",
        "TelemetryEvent",
        nullptr,
        "{}"
    };

    HRESULT hr = PFEventPipelineEmitEvent(
        handle,
        &myEvent
    );

    if (FAILED(hr))
    {
        printf("Failed emitting event: 0x%x\r\n", hr);
        return;
    }
}

如果在发出事件时超出缓冲区大小限制,你将遇到来自 SDK 的错误,如下所示:

  • E_PF_API_CLIENT_REQUEST_RATE_LIMIT_EXCEEDED (0x892354dd)

确保根据需要设置足够的缓冲区大小。

切换到实体身份验证或更新实体

如果管道仅使用遥测密钥配置创建,则可以切换到实体身份验证,或者要更新管道以使用其他实体。

通过使用 PFEventPipelineAddUploadingEntity,可以将实体附加到正在运行的管道,而无需重新初始化它。 它还替换现有实体(如果有)。

示例:

在游戏执行开始时使用遥测密钥配置创建遥测事件管道。 这样做的可能原因是还没有玩家标识,或者只是我们不希望仍然记录与玩家相关的任何内容。

void EventPipelineCreation(PFServiceConfigHandle serviceConfigHandle, XTaskQueueHandle taskQueueHandle)
{
    PFEventPipelineHandle handle;

    PFEventPipelineTelemetryKeyConfig telemetryKeyConfig
    {
        "myTelemetryKey",                   // telemetryKey
        serviceConfigHandle,                // serviceConfigHandle
    };

    HRESULT hr = PFEventPipelineCreateTelemetryPipelineHandleWithKey(
        &telemetryKeyConfig,                // eventPipelineTelemetryKeyConfig
        taskQueueHandle,                    // queue
        nullptr,                            // eventPipelineBatchUploadedEventHandler
        nullptr,                            // eventPipelineBatchFailedEventHandler
        nullptr,                            // handlerContext
        &handle                             // eventPipelineHandle
    );

    if (FAILED(hr))
    {
        printf("Failed creating event pipeline: 0x%x\r\n", hr);
        return;
    }
}

然后,玩家已登录,或者我们只想开始发送附加到特定实体的事件,以便我们可以使用现有的事件管道句柄和所需的实体句柄调用 PFEventPipelineAddUploadingEntity ,如下所示:

void EventPipelineUpdateEntity(PFEventPipelineHandle handle)
{
    HRESULT hr = PFEventPipelineAddUploadingEntity(
        handle,                 // eventPipelineHandle
        entityHandle            // entityHandle
    );

    if (FAILED(hr))
    {
        printf("Failed adding uploading entity: 0x%x\r\n", hr);
        return;
    }
}

在此调用后,管道将开始记录链接到该实体的任何后续事件。

切换到遥测密钥身份验证

如果开发人员想要返回到遥测身份验证并从实体中分离事件日志记录,则可以调用 PFEventPipelineRemoveUploadingEntity 并传递事件管道句柄,例如:

void EventPipelineRemoveEntity(PFEventPipelineHandle handle)
{
    HRESULT hr = PFEventPipelineRemoveUploadingEntity(
        handle                  // eventPipelineHandle
    );

    if (FAILED(hr))
    {
        printf("Failed removing uploading entity: 0x%x\r\n", hr);
        return;
    }
}

此调用将删除实体,并有效地切换回所有后续事件的遥测密钥身份验证。

更新管道配置

可以使用 PFEventPipelineUpdateConfiguration API 轻松更新管道,该 API 接收现有事件管道句柄和新的配置结构,如下所示:

void EventPipelineUpdateConfiguration(PFEventPipelineHandle handle)
{
    uint32_t maxEvents = 10;
    uint32_t maxWaitTime = 5;
    uint32_t pollDelay = 50;
    PFHCCompressionLevel compressionLevel = PFHCCompressionLevel::Medium;
    bool retryOnDisconnect = true;
    size_t bufferSize = 2048;

    PFEventPipelineConfig eventPipelineConfig
    {
        &maxEvents,             // maxEventsPerBatch
        &maxWaitTime,           // maxWaitTimeInSeconds
        &pollDelay,             // pollDelayInMs
        &compressionLevel,      // compressionLevel
        &retryOnDisconnect,     // retryOnDisconnect
        &bufferSize,            // bufferSize
    };

    HRESULT hr = PFEventPipelineUpdateConfiguration(
        handle,                 // eventPipelineHandle
        eventPipelineConfig     // eventPipelineConfig
    );

    if (FAILED(hr))
    {
        printf("Failed updating event pipeline configuration: 0x%x\r\n", hr);
        return;
    };
}

提醒:任何空属性或 null 属性都会使用默认值覆盖现有配置值。

无效/已停用的遥测密钥

如果遥测密钥被停用或在管道创建时提供了无效密钥,则使用该遥测密钥运行的任何事件管道在发现密钥无效或已停用后,会立即开始失败。

在客户重新激活密钥的最终情况下,管道不会意识到这一点,并将继续通过失败的事件处理程序发送故障。 值得一提的是,此行为是基于会话的,这意味着,如果游戏重新启动,则会创建一个新的管道,并且能够再次上传事件。

另请参阅