快速入门:使用 Azure Functions 编写 PlayFab CloudScript

在本快速入门中,你将使用包含 Visual Studio Code、Azure Functions 和 Unity 的Azure Functions编写 C# C# CloudScript。 完成本指南后,你将能够将新的 CloudScript 链接到规则、计划任务,甚至可以从客户端代码调用它。

先决条件

开始使用 PlayFab C# CloudScript 需要几个步骤。

  • 请访问 Visual Studio Code 快速入门:使用 Visual Studio Code 创建Azure Functions 项目,并在设置后返回此处。 快速入门指南介绍了以下先决条件:
    • Azure 帐户。 注册 Azure 帐户是免费的
    • Azure 订阅
    • 在 Azure 门户 中配置的 Functions 应用资源
      • 若要使用 Azure Functions 将 CloudScript 的延迟降到最低,请将其放置在 US-WestUS-West 2US-West 3 Azure 区域。
      • 安全说明: 从安全角度来看,应确保仅对 PlayFab 使用给定的函数机密,而不要将其用于从任何其他源调用同一函数。
      • 安全说明: 对于排队的函数,应为用于队列触发器的队列设置不同的存储帐户。
  • PlayFab 帐户。

注意

PlayFab Azure Functions可以使用 Azure Functions V2 运行时或更高版本,以及 .NET Core 2 或更高版本。 建议使用最新版本(当前 Azure Functions V4 和 .NET 6)。

创建 Azure 函数

  1. 创建基本的"HelloWorld"示例函数。 你可以按照 使用Visual Studio Code指南创建第一个函数来了解如何执行此操作。 有关使用 PlayFab 变量的代码示例,请参阅以下部分 PlayFab 函数上下文、变量和使用服务器 SDK

    重要

    "使用 Visual Studio Code 创建第一个函数"指南指示将 Azure 函数的授权级别设置为 Anonymous。 这样做是为了简化测试。

    在生产环境中,在大多数情况下,不应使用匿名授权,因为它允许任何人调用函数终结点。 若要在 PlayFab 环境中正确保护函数,建议使用 Function 级授权。

  2. 创建和部署函数后,转到“自动化”>“云脚本”,然后选择页面右上角的“注册函数”按钮。

    注册 CloudScript 函数

  3. 对于 名称,请输入函数的友好名称。 对于 函数 URL,请输入函数的 HTTP 触发器 URL。 可以在 Azure 函数资源的上下文菜单中找到 URL,如 快速入门的“在 Azure 中运行函数”部分所示:使用 Visual Studio Code 在 Azure 中创建函数。 如果 Azure 函数使用 Function 级别授权,则 URL 包含授权密钥。

有关部署 Azure Functions 的详细信息,请参阅 从 Visual Studio Code部署Azure Functions

使用 PlayFab 游戏中的Azure Functions使用和调用 CloudScript

本指南中的示例代码以 Unity C# 和 Azure 函数 C# 代码编写。

注册函数后,可以使用 PlayFab API 从内部调用该函数。

使用来自 Visual Studio Code 的 HTTP 请求调用函数

使用 REST 客户端扩展,可以从Visual Studio中调用该函数。

@titleId =  ????? # Enter your title ID here
@baseUrl = https://{{titleId}}.playfabapi.com

###
# @name LoginWithCustomID
POST {{baseUrl}}/Client/LoginWithCustomID
Accept-Encoding: gzip
Content-Type: application/json

{
  "CustomId": "demo",
  "CreateAccount": true,
  "TitleId": "{{titleId}}"
}

@entityToken = {{LoginWithCustomID.response.body.$.data.EntityToken.EntityToken}}
@entity = {{LoginWithCustomID.response.body.$.data.EntityToken.Entity}}

###
# @name ExecuteFunction
POST {{baseUrl}}/CloudScript/ExecuteFunction
Accept-Encoding: gzip
Content-Type: application/json
X-EntityToken: {{entityToken}}

{
  "FunctionName": "HelloWorld"
}

###
# @name GetObjects
POST {{baseUrl}}/Object/GetObjects
Accept-Encoding: gzip
Content-Type: application/json
X-EntityToken: {{entityToken}}

{
  "Entity": {{entity}},
  "Objects": ["obj1"]
}

将此代码粘贴到具有 .http 扩展名的 Visual Studio Code 中的文件中后,应能够在 LoginWithCustomID 函数下选择 发送请求 ,以获取玩家的实体令牌,然后在 LoginWithCustomID 下调用函数。 调用 GetObjects 应显示 Azure 函数附加玩家的对象。

从 Unity 调用函数

可以在 Unity 中使用此代码来调用函数。

//This snippet assumes that your game client is already logged into PlayFab.

using PlayFab;
using PlayFab.CloudScriptModels;

private void CallCSharpExecuteFunction()
{
    PlayFabCloudScriptAPI.ExecuteFunction(new ExecuteFunctionRequest()
    {
        Entity = new PlayFab.CloudScriptModels.EntityKey()
        {
            Id = PlayFabSettings.staticPlayer.EntityId, //Get this from when you logged in,
            Type = PlayFabSettings.staticPlayer.EntityType, //Get this from when you logged in
        },
        FunctionName = "HelloWorld", //This should be the name of your Azure Function that you created.
        FunctionParameter = new Dictionary<string, object>() { { "inputValue", "Test" } }, //This is the data that you would want to pass into your function.
        GeneratePlayStreamEvent = false //Set this to true if you would like this call to show up in PlayStream
    }, (ExecuteFunctionResult result) =>
    {
        if (result.FunctionResultTooLarge ?? false)
        {
            Debug.Log("This can happen if you exceed the limit that can be returned from an Azure Function, See PlayFab Limits Page for details.");
            return;
        }
        Debug.Log($"The {result.FunctionName} function took {result.ExecutionTimeMilliseconds} to complete");
        Debug.Log($"Result: {result.FunctionResult.ToString()}");
    }, (PlayFabError error) =>
    {
        Debug.Log($"Opps Something went wrong: {error.GenerateErrorReport()}");
    });
}

PlayFab CloudScript 上下文、变量和服务器 SDK

使用 CloudScript Azure Functions的一个优点是 PlayStream 事件和玩家配置文件上下文会自动传递到 Azure 函数。 调用 CloudScript 时,将根据函数的调用方案接收上下文。 例如,上下文因其是由 PlayStream 操作触发还是直接从客户端调用而异。 这包括诸如代表其调用 CloudScripts 的实体配置文件,以及用于调用 CloudScript 的 PlayStream 事件等信息。

  1. 需要通过 程序包管理器 安装 PlayFab SDK。 若要执行此操作,请在Visual Studio Code中打开终端或 CMD 控制台并键入: dotnet add package PlayFabAllSDK
  2. 需要包含 CS2AFHelperClasses.cs 文件,其中包含 PlayFab.Samples 的实现
  3. 可通过多种方法(API、计划任务、PlayStream 事件、段进入和退出方法)执行脚本。 执行上下文对于实现 CloudScript 非常重要。 有关如何使用脚本上下文的详细信息,请参阅 使用 CloudScript 上下文模型教程

可以使用下面的 HelloWorld 示例作为第一个 Azure 函数。 它调用实体 API,并向经过身份验证的播放器返回问候语。 经典服务器 API 的调用方式类似;但是,需要指定游戏密钥才能进行调用。 机密密钥可以存储在 应用程序设置 中,并使用 Environment.GetEnvironmentVariable() 方法进行检索。

using PlayFab;
using PlayFab.Samples;
using PlayFab.DataModels;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace PlayFabCS2AFSample.HelloWorld
{
    public static class HelloWorld
    {
        [FunctionName("HelloWorld")]
        public static async Task<dynamic> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            FunctionExecutionContext<dynamic> context = JsonConvert.DeserializeObject<FunctionExecutionContext<dynamic>>(await req.ReadAsStringAsync());

            dynamic args = context.FunctionArgument;

            var message = $"Hello {context.CallerEntityProfile.Lineage.MasterPlayerAccountId}!";
            log.LogInformation(message);

            dynamic inputValue = null;
            if (args != null && args["inputValue"] != null)
            {
                inputValue = args["inputValue"];
            }

            log.LogDebug($"HelloWorld: {new { input = inputValue} }");

            // The profile of the entity specified in the 'ExecuteEntityCloudScript' request.
            // Defaults to the authenticated entity in the X-EntityToken header.
            var entityProfile = context.CallerEntityProfile;

            var api = new PlayFabDataInstanceAPI(
                new PlayFabApiSettings
                {
                    TitleId = context.TitleAuthenticationContext.Id
                },
                new PlayFabAuthenticationContext
                {
                    EntityToken = context.TitleAuthenticationContext.EntityToken
                }
            );

            var apiResult = await api.SetObjectsAsync(
                new SetObjectsRequest
                {
                    Entity = new EntityKey
                    {
                        Id = entityProfile.Entity.Id,
                        Type = entityProfile.Entity.Type
                    },
                    Objects = new List<SetObject> {
                    new SetObject
                    {
                        ObjectName =  "obj1",
                        DataObject = new
                        {
                            foo = "some server computed value",
                            prop1 = "bar"
                        }
                    }
                }
                });

            return new { messageValue = message };
        }
    }
}

在此示例中,调用方的 CurrentPlayerId 与传统 CloudScript 实现中的相同。 传入 FunctionParameters 字段的参数在 参数中可用。 但是,与 使用Visual Studio Code指南创建第一个函数Hello World示例不同,参数在 POST 正文而不是查询字符串中传递。

若要从 PlayFab SDK 调用 HelloWorld Azure 函数,请使用 ExecuteFunction

自动化规则中的Azure Functions

也可以通过创建规则和计划任务来调用Azure Functions。 其工作方式与标准 CloudScript 相同。 若要创建规则或计划任务,请转到 自动化>规则自动化>计划任务

  • 选择 新规则
  • 输入规则的名称
  • 选择此规则触发的事件类型
  • 添加操作
  • 从操作下拉列表中,选择 执行 Azure Function

已注册的可用Azure Functions列表将在下拉列表中提供。

为Azure Functions配置规则

调试 Azure 函数

使用 Azure Functions,现在可以选择在本地或在Azure 门户中调试 CloudScript。 若要了解有关门户调试的详细信息,请参阅 通过 Azure 门户使用 Azure Functions 调试 CloudScript。 若要了解如何设置本地调试,请参阅使用 Azure Functions 对 Cloudscript 进行本地调试

执行限制

对 Azure Functions 的 CloudScript 调用具有超时限制。 如果 Webhook 执行时间过长,请求将在 PlayFab 中超时。 确保代码的执行速度足够快,以保持在超时限制以下。

操作类型 限制 (秒)
PlayFab API HTTP 请求 10
PlayStream V2 HTTP 请求 10
计划任务 HTTP 请求 4.5
PlayStream V1 HTTP 请求 1
队列函数 队列有效负载 1