> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 使用 Azure Functions 的 PlayFab CloudScript 快速入门指南

> 使用 Visual Studio Code 和 Unity 通过 Azure Functions 编写 C# 版 PlayFab CloudScript,然后将函数链接到规则、计划任务或客户端调用。

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

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

## 先决条件

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

* 访问 Visual Studio Code 的[快速入门:使用 Visual Studio Code 创建 Azure Functions 项目](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-csharp?pivots=programming-language-csharp),完成设置后返回此处。该快速入门指南中涵盖以下先决条件:
  * 一个 [Azure 帐户](https://azure.microsoft.com/free)。注册 Azure 帐户是免费的。
  * 一个 [Azure 订阅](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/create-subscription)
  * 在 Azure 门户中配置的 Functions 应用资源
    * 为最大限度减少 CloudScript 使用 Azure Functions 时的延迟,请将它们放置在 *US-West*、*US-West 2* 或 *US-West 3* Azure 区域中。
    * **安全说明:** 从安全的角度来看,你应确保给定的函数密钥仅与 PlayFab 一起使用,而不要用于从任何其他源调用相同的函数。
    * **安全说明:** 对于队列函数,你应为队列触发器使用的队列设置一个独立的存储帐户。
* 一个 [PlayFab](https://developer.playfab.com/) 帐户。

<Note>
  PlayFab Azure Functions 可以使用 Azure Functions V2 或更高版本的运行时,以及 .NET Core 2 或更高版本。我们建议你使用最新版本(当前为 Azure Functions V4 和 .NET 6)。
</Note>

## 创建 Azure Function

1. 创建一个基本的 “HelloWorld” 示例函数。你可以通过遵循[使用 Visual Studio Code 创建你的第一个函数指南](https://learn.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-vs-code)了解如何执行此操作。有关使用 PlayFab 变量的代码示例,请参阅 [PlayFab 函数上下文、变量和使用服务器 SDK](#playfabfunctioncontext) 部分。

<Info>
  “使用 Visual Studio Code 创建你的第一个函数”指南指示你将 Azure Function 的授权级别设置为 `Anonymous`。这样做是为了简化测试。在生产环境中,大多数情况下,你不应使用 Anonymous 授权,因为它允许任何人调用你的函数终结点。若要在 PlayFab 环境中正确保护你的函数,我们建议你使用 `Function` 级别的授权。
</Info>

2. 创建并部署函数后,请转到 **Automation** > **Cloud Script**,然后选择页面右上角的 **Register Function** 按钮。

   <img src="https://mintcdn.com/microsoft-4404708b/dqv53299jA1M-fNi/images/playfab/live-service-management/service-gateway/automation/cloudscript-af/register_cs_function.png?fit=max&auto=format&n=dqv53299jA1M-fNi&q=85&s=4bfc5e2c33a1ad384fa01a0698d4cd5d" alt="注册 CloudScript 函数" width="542" height="549" data-path="images/playfab/live-service-management/service-gateway/automation/cloudscript-af/register_cs_function.png" />

3. 对于 **Name**,输入函数的一个便于识别的名称。对于 **Function URL**,输入该函数的 HTTP 触发器 URL。该 URL 可在 Azure 函数资源的上下文菜单中找到,如[快速入门:使用 Visual Studio Code 在 Azure 中创建函数](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-csharp?pivots=programming-language-csharp#run-the-function-in-azure)的 “Run the function in Azure” 部分所示。如果你的 Azure Function 使用 `Function` 级别的授权,则该 URL 包含授权密钥。

有关部署 Azure Functions 的更多信息,请参阅[使用 Visual Studio Code 部署 Azure Functions](https://learn.microsoft.com/azure/azure-functions/functions-develop-vs-code)。

## 从 PlayFab 游戏中使用和调用 CloudScript 使用 Azure Functions

本指南中的示例代码使用 Unity C# 和 Azure Function C# 代码编写。

现在你的函数已注册,你可以在 PlayFab API 中调用该函数。

### 从 Visual Studio Code 使用 HTTP 请求调用你的函数

使用 [REST Client 扩展](https://marketplace.visualstudio.com/items?itemName=humao.rest-client),你可以在 Visual Studio 中调用该函数。

```http theme={null}
@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"]
}

```

将此代码粘贴到 Visual Studio Code 中扩展名为 .http 的文件中之后,你应该能够在 *LoginWithCustomID* 函数下选择 *Send request* 来获取玩家的实体令牌,然后在 *LoginWithCustomID* 下调用你的函数。调用 *GetObjects* 应会显示 Azure 函数附加给该玩家的对象。

### 从 Unity 调用你的函数

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

```c# theme={null}
//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 <a name="playfabfunctioncontext" />

使用 Azure Functions 的 CloudScript 的一大优势是,PlayStream 事件和玩家配置文件上下文会自动传递给 Azure Function。在调用 CloudScript 时,你会根据该函数的调用场景收到相应的上下文。例如,由 PlayStream 操作触发与直接从客户端调用,上下文会有所不同。这包括调用 CloudScript 时所代表的实体配置文件,以及可能用于调用 CloudScript 的 PlayStream 事件等信息。

1. 你需要通过 Package Manager 安装 PlayFab SDK。为此,请在 Visual Studio Code 中打开 Terminal 或 CMD 控制台并输入:`dotnet add package PlayFabAllSDK`
2. 你需要包含实现 `PlayFab.Samples` 的 [CS2AFHelperClasses.cs](https://github.com/PlayFab/PlayFab-Samples/blob/master/Samples/CSharp/AzureFunctions/CS2AFHelperClasses.cs) 文件
3. 脚本的执行可以通过多种方法进行(API、计划任务、PlayStream 事件、分段进入和退出方法)。执行的上下文对于实现你的 CloudScript 很重要。有关如何使用脚本上下文的详细信息,请参阅[使用 CloudScript 上下文模型教程](/services/playfab/live-service-management/service-gateway/automation/cloudscript-af/CloudScript-af-context)。

你可以将 HelloWorld 示例作为你的第一个 Azure Function。它会调用一个实体 API,并向已通过身份验证的玩家返回问候语。可以以类似方式调用传统的服务器 API;不过,这需要指定游戏密钥才能进行调用。密钥可以存储在[应用程序设置](https://learn.microsoft.com/en-us/azure/azure-functions/functions-how-to-use-azure-function-app-settings?tabs=portal#settings)中,并使用 `Environment.GetEnvironmentVariable()` 方法进行检索。

```c# theme={null}
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` 字段中传入的参数可在 *args* 中获取。但是,与[使用 Visual Studio Code 创建你的第一个函数指南](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-csharp)中的 Hello World 示例不同,参数是在 POST 正文中传递,而不是在查询字符串中。

要从 PlayFab SDK 调用 HelloWorld Azure Function,请使用 `ExecuteFunction`。

## 自动化规则中的 Azure Functions

也可以通过创建规则和计划任务来调用 Azure Functions。其工作方式与我们的标准 CloudScript 相同。要创建规则或计划任务,请转到 **Automation** > **Rules** 或 **Automation** > **Scheduled Tasks**。

* 选择 **New Rule**
* 输入规则名称
* 选择此规则触发的事件类型
* 添加一个操作
* 从操作下拉列表中,选择 **Execute Azure Function**

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

<img src="https://mintcdn.com/microsoft-4404708b/dqv53299jA1M-fNi/images/playfab/live-service-management/service-gateway/automation/cloudscript-af/azure_function_rules.png?fit=max&auto=format&n=dqv53299jA1M-fNi&q=85&s=f48a4376587a492bd3dcbf1efa86c666" alt="为 Azure Functions 配置规则" width="800" height="966" data-path="images/playfab/live-service-management/service-gateway/automation/cloudscript-af/azure_function_rules.png" />

## 调试你的 Azure Function

使用 Azure Functions,你现在可以选择在本地或在 Azure 门户中调试你的 CloudScript。若要了解有关门户调试的更多信息,请参阅[在 Azure 门户中使用 Azure Functions 调试 CloudScript](/services/playfab/live-service-management/service-gateway/automation/cloudscript-af/debugging-with-CloudScript-AF-Azure)。若要了解如何设置本地调试,请参阅[使用 Azure Functions 的 Cloudscript 本地调试](/services/playfab/live-service-management/service-gateway/automation/cloudscript-af/local-debugging-for-cloudscript-using-azure-functions)。

## 执行限制

对 Azure Functions 的 CloudScript 调用有超时限制。如果你的 webhook 执行时间过长,PlayFab 中的请求就会超时。请确保你的代码执行足够快,以保持在超时限制之内。

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