Photon

本部分提供有关将 PlayFab 与 Photon 多人游戏服务(如 Photon RealTime 和 Photon Unity 网络 (PUN))一起使用的信息。

目前,我们提供以下 Photon 集成:

  • 使用 PlayFab 对 Photon 玩家进行身份验证。
  • 使用 PlayFab CloudScript 回调侦听房间事件。

Photon 快速入门

本快速入门介绍如何设置 Photon 多人游戏以使用 PlayFab。 当前,PlayFab 提供以下 Photon 集成:

  • 使用 PlayFab 对 Photon 玩家进行身份验证。
  • 使用 PlayFab CloudScript 回调侦听房间事件。

在此快速入门中,我们会使用最新的 Photon Unity 示例项目说明这两个功能如何工作。

注意

有关 Unity 上完全支持的 PlayFab 多人游戏和聊天体验,请参阅 PlayFab Party Unity 插件了解详细信息。

先决条件

  1. 一个 Unity 项目,其中导入了 PlayFab SDK 并具有已配置的游戏。
  2. 已注册 PlayFab 游戏。

注意

本指南省略了聊天应用程序设置。 若要集成聊天应用程序,请创建新的 Photon 聊天应用程序,然后在 Unity 和 PlayFab Game Manager - Photon 加载项页面对应的框中输入应用 ID。

设置 Photon 应用程序

  1. 注册并登录到 Photon 仪表板后,请选择“创建新应用”。

创建新 Photon 应用程序

  1. 选择 Photon 类型
  2. 选择 Name
  3. 创建 Description
  4. 通过选择 Create 进行提交。

新应用程序表单

设置身份验证

  1. 在列表中查找新创建的应用程序,然后选择“管理”。

管理测试应用程序

  1. 在“应用程序”仪表板中,查找并保存位于“游戏”页面下的“应用 ID”。

保存应用 ID

  1. 找到 Authentication 部分。
  2. 选择“自定义服务器”。

自定义服务器身份验证

下一个页面可用于为 Photon 配置身份验证 URL。

https://{PlayFabTitleId}.playfabapi.com/photon/authenticate

PlayFabTitleId 占位符替换为您自己的游戏 ID。

{PlayFabTitleId}
  1. 输入 URL
  2. 通过选择“创建”按钮进行提交。

输入身份验证 URL

为 Photon 设置 PlayFab 游戏

导航到游戏的 Game Manager 页面,然后:

  1. 导航到 Add-ons 选项卡。
  2. 附加内容列表中,找到并选择 Photon

游戏管理器加载项选项卡

  1. 在“Photon 加载项”页面中,通过指定 Photon 实时应用程序 ID 可以安装 Photon。
    • 可以选择指定 Chat App ID
    • 安装加载项 (3) 后,会生成 Photon 密钥(2)
    • 保存它以便在以后配置 Webhook 时使用。

注意

请注意将 Photon 密钥保存在安全且易于访问的位置。 配置 Webhook 时会十分方便。

复制实时应用 ID

设置 Photon Webhook

作为可选集成,Photon 可以将特定事件传输给 PlayFab CloudScript。 以下操作是使用 Webhook 完成的:

  • 指定基 URL。
  • 然后为每个可用事件指定路径。
  • 路径实际上是在 CloudScript 中实现的处理程序名称。

基本 URL 具有以下格式:

https://{PlayFabTitleId}.playfablogic.com/webhook/1/prod/{PhotonSecretKey}

确保将 Title Id 占位符替换为您自己的游戏 ID。

{PlayFabTitleId}

确保将 PhotonSecretKey 令牌替换为 Photon Add-on 页面上生成的密钥。

{PhotonSecretKey}
  1. 填写基 URL
  2. 为每个可用事件 分配 CloudScript 处理程序名称
  3. 移除任何 CustomHttpHeaders
  4. 通过选择 Save 按钮提交此信息。

分配 CloudScript 事件处理程序

设置 Unity 项目

本指南假设已导入、设置了 PlayFab SDK,并配置了游戏设置。

导入 Photon Unity

导入过程完成之后,“PUN 设置”窗口立即打开。

  • 输入在 Photon 应用程序仪表板中对所创建的 Photon 应用找到的实时应用程序 ID (1)
  • 选择 Setup Project (2)
  • 设置完成后,选择 Close (3)

PUN 设置

如果接受了 AppId,则“Photon 服务器设置”对象在“Unity Inspector”窗口中处于选中状态并且可供查看。 手动访问服务器设置对象:

  • 导航到顶部窗口面板。
  • 选择 Window
  • 然后选择 Photon Unity Networking (1)
  • 最后选择 Highlight Server Settings (2)
  • 标准 Unity”项目窗口会显示“PhotonServerSettings (3)”对象。
  • 选择该对象以在 Unity Inspector 窗口中显示其设置。

Photon 服务器设置

注意

作为 PhotonServerSettings 的一部分,可以选择分配聊天应用程序 ID

此时已配置了项目。

实现 PlayFab 到 Photon 的身份验证

在 PlayFab Game Manager 中为游戏启用了 Photon 加载项,并且在 Photon 应用程序仪表板上配置了身份验证后,PlayFab 允许在 Photon 环境中对现有 PlayFab 玩家进行身份验证。

这意味着可以完全避免为 Photon 实现任何用户管理。

  1. Photon Unity Networking Free 程序包 Classic 版本导航到DemoHub-Scene-V2 场景。
    • 此场景是该程序包中所有示例的中心。
    • 因为它是要加载的第一个 场景,因此我们添加了一个小脚本,以便可以使用 Photon 对 PlayFab 进行身份验证。
  2. 创建名为 PlayFabAuthenticator 的空 GameObject
  3. 然后在 Unity Inspector 窗口中,将具有相同名称的组件添加到此 GameObject

添加身份验证组件

选择齿轮图标,然后从下拉菜单中选择要编辑的脚本。 复制并粘贴 PlayFabAuthenticator 组件的代码,然后保存并关闭文件。

using PlayFab;
using PlayFab.ClientModels;
using UnityEngine;

public class PlayFabAuthenticator : MonoBehaviour {

    private string _playFabPlayerIdCache;

    //Run the entire thing on awake
    public void Awake() {
        AuthenticateWithPlayFab();
    }

    /*
     * Step 1
     * We authenticate a current PlayFab user normally.
     * In this case we use the LoginWithCustomID API call for simplicity.
     * You can absolutely use any Login method you want.
     * We use PlayFabSettings.DeviceUniqueIdentifier as our custom ID.
     * We pass RequestPhotonToken as a callback to be our next step, if
     * authentication was successful.
     */
    private void AuthenticateWithPlayFab(){
        LogMessage("PlayFab authenticating using Custom ID...");

        PlayFabClientAPI.LoginWithCustomID(new LoginWithCustomIDRequest()
        {
            CreateAccount = true,
            CustomId = PlayFabSettings.DeviceUniqueIdentifier
        }, RequestPhotonToken, OnPlayFabError);
    }

    /*
    * Step 2
    * We request a Photon authentication token from PlayFab.
    * This is a crucial step, because Photon uses different authentication tokens
    * than PlayFab. Thus, you cannot directly use PlayFab SessionTicket and
    * you need to explicitly request a token. This API call requires you to
    * pass a Photon App ID. The App ID may be hard coded, but in this example,
    * we are accessing it using convenient static field on PhotonNetwork class.
    * We pass in AuthenticateWithPhoton as a callback to be our next step, if
    * we have acquired the token successfully.
    */
    private void RequestPhotonToken(LoginResult obj) {
        LogMessage("PlayFab authenticated. Requesting photon token...");

        //We can player PlayFabId. This will come in handy during next step
        _playFabPlayerIdCache = obj.PlayFabId;

        PlayFabClientAPI.GetPhotonAuthenticationToken(new GetPhotonAuthenticationTokenRequest()
        {
            PhotonApplicationId = PhotonNetwork.PhotonServerSettings.AppSettings.AppIdRealtime
        }, AuthenticateWithPhoton, OnPlayFabError);
    }

    /*
     * Step 3
     * This is the final and the simplest step. We create a new AuthenticationValues instance.
     * This class describes how to authenticate a player inside the Photon environment.
     */
    private void AuthenticateWithPhoton(GetPhotonAuthenticationTokenResult obj) {
        LogMessage("Photon token acquired: " + obj.PhotonCustomAuthenticationToken + "  Authentication complete.");

        //We set AuthType to custom, meaning we bring our own, PlayFab authentication procedure.
        var customAuth = new Photon.Realtime.AuthenticationValues { AuthType = CustomAuthenticationType.Custom };

        //We add "username" parameter. Do not let it confuse you: PlayFab is expecting this parameter to contain player PlayFab ID (!) and not username.
        customAuth.AddAuthParameter("username", _playFabPlayerIdCache);    // expected by PlayFab custom auth service

        //We add "token" parameter. PlayFab expects it to contain Photon Authentication Token issues to your during previous step.
        customAuth.AddAuthParameter("token", obj.PhotonCustomAuthenticationToken);

        //We finally tell Photon to use this authentication parameters throughout the entire application.
        PhotonNetwork.AuthValues = customAuth;
    }

    private void OnPlayFabError(PlayFabError obj) {
        LogMessage(obj.GenerateErrorReport());
    }

    public void LogMessage(string message) {
        Debug.Log("PlayFab + Photon Example: " + message);
    }
}

测试 PlayFab 到 Photon 的身份验证

  1. 启动场景。
  2. 检查控制台消息流。 控制:
  3. 对 PlayFab 本身进行的身份验证是否成功。
  4. 是否获取了 Photon 令牌。

下图说明正确的流程。

启动场景

获取了 Photon 令牌,并且身份验证完成后,便可以签出 Photon 演示。

例如,启动名为 Demo Boxes 的演示。

  1. 为确保 PlayFab 身份验证完成,请选择 Demo Boxes
  2. 然后选择 Load Dem,如下图所示。

加载演示

Photon 开始输出调试消息。 通过监视控制台,可以轻松查明是否遇到任何身份验证问题。

Photon 调试控制台

确保控制台中不存在 Authentication Denied 错误。 此时已设置了最低程度的 PlayFab 与 Photon 集成。

Photon 房间事件 + CloudScript

Photon 匹配系统具有房间 的概念。 如果不熟悉此概念,请参阅 Photon 匹配指南

PlayFab 允许截获各种房间事件。 以下房间事件只需 CloudScript 即可截获:

  • RoomCreated
  • RoomJoined
  • RoomLeft
  • RoomClosed

以下事件需要对 Unity 代码进行额外控制才能进行截获(本文档后面部分提供了详细信息):

  • RoomPropertyUpdated
  • RoomEventRaised

注意

引入房间事件的处理程序后,它成为事件处理流的必要组成部分。 因此,在运行 CloudScript 时产生的错误可能会导致整个 系统出现问题。 例如,如果 RoomCreated 处理程序引发错误,则客户端也会引发错误,并且无法正确连接。

我们通过为每种事件类型分别定义处理程序,来构造一个 PlayFab CloudScript。

创建房间处理程序

每当创建 Photon 房间时,都会调用 RoomCreated 处理程序。 以下 CloudScript 处理程序会截获这类事件。

// Triggered automatically when a Photon room is first created
handlers.RoomCreated = function (args) {
    return { ResultCode : 0, Message: 'Success' };
};

注意

使用“args”参数可以获取有关事件的更多数据。

{
  "ActorNr": 1,
  "AppVersion": "1.2_1.85",
  "AppId": "bfd5f98b-c6a4-4763-80d9-824d20db842b",
  // Options with which the room was created.
  "CreateOptions": {
    "MaxPlayers": 4,
    "LobbyId": null,
    "LobbyType": 0,
    "CustomProperties": {

    },
    "EmptyRoomTTL": 0,
    "PlayerTTL": 0,
    "CheckUserOnJoin": false,
    "DeleteCacheOnLeave": true,
    "SuppressRoomEvents": false,
    "PublishUserId": false,
    "ExpectedUsers": null
  },
  // Unique game identifier
  "GameId": "8b8322de-096d-4481-a2b2-8db8bb45cfef",
  "Region": "EU",
  "Type": "Create",
  // User that caused the room to be created
  "UserId": "834D5AA5BAB1DFB6",
  "Username": ""
}

加入房间处理程序

每当玩家加入房间时,都会调用 RoomJoined 处理程序。 以下 CloudScript 处理程序会截获这类事件。

// Triggered automatically when a player joins a Photon room
handlers.RoomJoined = function (args) {
    return { ResultCode : 0, Message: 'Success' };
};

对于进入房间的第一个用户,不调用此回调。 使用 RoomCreated 可截获加入的第一个玩家。 使用“args”参数可以获取有关事件的更多数据。

{
  "ActorNr": 2,
  "AppVersion": "1.2_1.85",
  "AppId": "bfd5f98b-c6a4-4763-80d9-824d20db842b",
  // Unique Game Identifier
  "GameId": "b0f55a2e-431d-402a-9809-b0240443267e",
  "Region": "EU",
  "Type": "Join",
  // Id of the player that has joined
  "UserId": "AAC7634BF46289DF",
  "Username": ""
}

离开房间

每当玩家离开房间时,都会调用 RoomLeft 处理程序。 以下 CloudScript 处理程序会截获这类事件。

// Triggered automatically when a player leaves a Photon room
handlers.RoomLeft = function (args) {
    return { ResultCode : 0, Message: 'Success' };
};

使用“args”参数可以获取有关事件的更多数据。

{
  "ActorNr": 2,
  "AppVersion": "1.2_1.85",
  "AppId": "bfd5f98b-c6a4-4763-80d9-824d20db842b",
  // Unique Game Identifier
  "GameId": "b0f55a2e-431d-402a-9809-b0240443267e",
  "IsInactive": false,
  "Reason": "0",
  "Region": "EU",
  "Type": "ClientDisconnect",
  // Id of the user that has left the room
  "UserId": "AAC7634BF46289DF",
  "Username": ""
}

关闭房间处理程序

每当最后一个玩家离开房间,房间中没有任何玩家留下时,都会调用 RoomClosed 处理程序。 以下 CloudScript 处理程序会截获这类事件。

// Triggered automatically when a Photon room closes
// Note: currentPlayerId is undefined in this function
handlers.RoomClosed = function (args) {
    return { ResultCode : 0, Message: 'Success' };
};

使用“args”参数可以获取有关事件的更多数据。

  "ActorCount": 0,
  "ActorNr": 1,
  "AppVersion": "1.2_1.85",
  "AppId": "bfd5f98b-c6a4-4763-80d9-824d20db842b",
  // Unique game identifier
  "GameId": "b0f55a2e-431d-402a-9809-b0240443267e",
  "Region": "EU",
  "State2": {
    "ActorList": [

    ]
  },
  "Type": "Close"
}

更新房间属性

每当房间属性更改时,都会调用 RoomPropertyUpdated 处理程序。 以下 CloudScript 处理程序会截获这类事件。

// Triggered automatically when a Photon room game property is updated.
// Note: currentPlayerId is undefined in this function
handlers.RoomPropertyUpdated = function (args) {
    return { ResultCode : 0, Message: 'Success' };
};

注意

currentPlayerId 未在此处理程序中定义。 如果从客户端更改了房间属性,则可以使用“args”参数,并引用 UserId 以获取负责的玩家。

使用“args”参数可以获取有关事件的更多数据。

{
  "ActorNr": 1,
  "AppVersion": "1.2_1.85",
  "AppId": "bfd5f98b-c6a4-4763-80d9-824d20db842b",
  // Custom Room Properties
  "Properties": {
    "CustomProperty": "It's Value"
  },
  "GameId": "8b8322de-096d-4481-a2b2-8db8bb45cfef",
  "Region": "EU",
  "State": {
    "ActorCounter": 1,
    "ActorList": [
      {
        "ActorNr": 1,
        "UserId": "834D5AA5BAB1DFB6",
        "Username": "",
        "IsActive": true,
        "Binary": "RGIAAAEBRAAAAAFi\/3MAAA==",
        "DEBUG_BINARY": {
          "1": {
            "255": ""
          }
        }
      }
    ],
    "Binary": {
      "18": "RAAAAANi+nkAAHNzAA1QbGF5ZXJJbmRleGVzRGlpAAEAAAABAAAAAHMADkN1c3RvbVByb3BlcnR5cwAKSXQncyBWYWx1ZQ=="
    },
    "CheckUserOnJoin": false,
    "CustomProperties": {

    },
    "DeleteCacheOnLeave": true,
    "EmptyRoomTTL": 0,
    "IsOpen": true,
    "IsVisible": true,
    "LobbyType": 0,
    "LobbyProperties": [

    ],
    "MaxPlayers": 4,
    "PlayerTTL": 0,
    "SuppressRoomEvents": false,
    "Slice": 0,
    "DebugInfo": {
      "DEBUG_PROPERTIES_18": {
        "250": [

        ],
        "PlayerIndexes": {
          "1": 0
        },
        "CustomProperty": "It's Value"
      }
    },
    "ExcludedActors": [

    ],
    "PublishUserId": false,
    "ExpectedUsers": [

    ]
  },
  "Type": "Game",
  "UserId": "834D5AA5BAB1DFB6",
  "Username": ""
}

使用 Unity Photon 客户端更改自定义房间属性时,请务必标记调用,以便它将事件传递给 Webhook(在此例中为 PlayFab)。

// Properties updates ( this hashtable contains the properties to be changed. Properties not mentioned here will stay as is
var properties = new ExitGames.Client.Photon.Hashtable() { { "CustomProperty" , "It's Value" } };

// Control set. Empty in this case, because our property has not existed before.
// Otherwise you would include previous value of the property.
var expectedProperties = new ExitGames.Client.Photon.Hashtable();

// Set Custom Properties call. Notice the last argument set to "true"
// This tells Photon to forward event to the webhook.
PhotonNetwork.room.SetCustomProperties(properties, expectedProperties, true);

引发房间事件

每当引发自定义房间事件时,会调用 RoomEventRaised。 以下 CloudScript 处理程序会截获这类事件。

// Triggered by calling "OpRaiseEvent" on the Photon client. The "args.Data" property is
// set to the value of the "customEventContent" HashTable parameter, so you can use
// it to pass in arbitrary data.
handlers.RoomEventRaised= function (args) {
    return { ResultCode : 0, Message: 'Success' };
};

使用“args”参数可以获取有关事件的更多数据。

{
  "ActorNr": 1,
  "AppVersion": "1.2_1.85",
  "AppId": "bfd5f98b-c6a4-4763-80d9-824d20db842b",
  // Custom event data
  "Data": {
    "Hello": "World"
  },
  "GameId": "8b8322de-096d-4481-a2b2-8db8bb45cfef",
  "Region": "EU",
  "State": {
    "ActorCounter": 1,
    "ActorList": [
      {
        "ActorNr": 1,
        "UserId": "834D5AA5BAB1DFB6",
        "Username": "",
        "IsActive": true,
        "Binary": "RGIAAAEBRAAAAAFi\/3MAAA==",
        "DEBUG_BINARY": {
          "1": {
            "255": ""
          }
        }
      }
    ],
    "Binary": {
      "18": "RAAAAAJi+nkAAHNzAA1QbGF5ZXJJbmRleGVzRGlpAAEAAAABAAAAAA=="
    },
    "CheckUserOnJoin": false,
    "CustomProperties": {

    },
    "DeleteCacheOnLeave": true,
    "EmptyRoomTTL": 0,
    "IsOpen": true,
    "IsVisible": true,
    "LobbyType": 0,
    "LobbyProperties": [

    ],
    "MaxPlayers": 4,
    "PlayerTTL": 0,
    "SuppressRoomEvents": false,
    "Slice": 0,
    "DebugInfo": {
      "DEBUG_PROPERTIES_18": {
        "250": [

        ],
        "PlayerIndexes": {
          "1": 0
        }
      }
    },
    "ExcludedActors": [

    ],
    "PublishUserId": false,
    "ExpectedUsers": [

    ]
  },
  "Type": "Event",
  // PlayFab User Id if he/she was the source of the event
  "UserId": "834D5AA5BAB1DFB6",
  "Username": "",
  // Event code
  "EvCode": 15
}

使用 Unity Photon 客户端引发自定义房间事件时,请务必标记调用,以便它将事件传递给 Webhook(在此例中为 PlayFab)。

var data = new Dictionary<string,object>() {
    { "Hello" , "World" }
};

// Raise custom room event
// Replace 15 with any custom event code of your choice [0..299]
PhotonNetwork.RaiseEvent(15, data, true, new RaiseEventOptions() {
    ForwardToWebhook = true, // Mark call to pass event to Webhook (PlayFab in this case)
});

测试房间事件处理程序

此示例扩展上一个示例(PlayFab + Photon 身份验证)。

为游戏上传以下 CloudScript。

handlers.RoomCreated = function (args) {
    server.WriteTitleEvent({
        EventName : "room_created"
    });
    return { ResultCode : 0, Message: 'Success' };
};

handlers.RoomJoined = function (args) {
    server.WriteTitleEvent({
        EventName : "room_joined"
    });
    return { ResultCode : 0, Message: 'Success' };
};

handlers.RoomLeft = function (args) {
    server.WriteTitleEvent({
        EventName : "room_left"
    });
    return { ResultCode : 0, Message: 'Success' };
};

handlers.RoomClosed = function (args) {
    server.WriteTitleEvent({
        EventName : "room_closed"
    });
    return { ResultCode : 0, Message: 'Success' };
};

handlers.RoomPropertyUpdated = function (args) {
    server.WriteTitleEvent({
        EventName : "room_property_changed"
    });
    return { ResultCode : 0, Message: 'Success' };
};

handlers.RoomEventRaised = function (args) {
    server.WriteTitleEvent({
        EventName : "room_event_raised"
    });
    return { ResultCode : 0, Message: 'Success' };
};

该代码仅是在每次调用 Photon 回调时发布新游戏事件。 此示例在生产中没有用处,只是为了让我们清楚了解回调的调用方式。

通过包含会引发自定义事件的新示例代码来扩展 PlayFabAuthenticator 脚本,并设置自定义房间属性。 扩展版本也利用 Awake 方法,不会在场景加载之间销毁对象。

using System.Collections.Generic;
using PlayFab;
using PlayFab.ClientModels;
using UnityEngine;

public class PlayFabAuthenticator : MonoBehaviour {

    private string _playFabPlayerIdCache;


    //Run the entire thing on awake
    public void Awake() {
        AuthenticateWithPlayFab();
        DontDestroyOnLoad(gameObject);
    }


    /*
     * Step 1
     * We authenticate a current PlayFab user normally.
     * In this case we use the LoginWithCustomID API call for simplicity.
     * You can absolutely use any Login method you want.
     * We use PlayFabSettings.DeviceUniqueIdentifier as our custom ID.
     * We pass RequestPhotonToken as a callback to be our next step, if
     * authentication was successful.
     */
    private void AuthenticateWithPlayFab()  {
        LogMessage("PlayFab authenticating using Custom ID...");

        PlayFabClientAPI.LoginWithCustomID(new LoginWithCustomIDRequest()
        {
            CreateAccount = true,
            CustomId = PlayFabSettings.DeviceUniqueIdentifier+"EDITOR"
        }, RequestPhotonToken, OnPlayFabError);
    }

    /*
    * Step 2
    * We request a Photon authentication token from PlayFab.
    * This is a crucial step, because Photon uses different authentication tokens
    * than PlayFab. Thus, you cannot directly use PlayFab SessionTicket and
    * you need to explicitly request a token. This API call requires you to
    * pass a Photon App ID. The App ID may be hard coded, but in this example,
    * we are accessing it using convenient static field on PhotonNetwork class.
    * We pass in AuthenticateWithPhoton as a callback to be our next step, if
    * we have acquired the token successfully.
    */
    private void RequestPhotonToken(LoginResult obj) {
        LogMessage("PlayFab authenticated. Requesting photon token...");

        //We can player PlayFabId. This will come in handy during next step
        _playFabPlayerIdCache = obj.PlayFabId;

        PlayFabClientAPI.GetPhotonAuthenticationToken(new GetPhotonAuthenticationTokenRequest()
        {
            PhotonApplicationId = PhotonNetwork.PhotonServerSettings.AppSettings.AppIdRealtime
        }, AuthenticateWithPhoton, OnPlayFabError);
    }

    /*
     * Step 3
     * This is the final and the simplest step. We create a new AuthenticationValues instance.
     * This class describes how to authenticate a player inside the Photon environment.
     */
    private void AuthenticateWithPhoton(GetPhotonAuthenticationTokenResult obj) {
        LogMessage("Photon token acquired: " + obj.PhotonCustomAuthenticationToken + "  Authentication complete.");

        //We set AuthType to custom, meaning we bring our own, PlayFab authentication procedure.
        var customAuth = new Photon.Realtime.AuthenticationValues { AuthType = CustomAuthenticationType.Custom };

        //We add "username" parameter. Do not let it confuse you: PlayFab is expecting this parameter to contain player PlayFab ID (!) and not username.
        customAuth.AddAuthParameter("username", _playFabPlayerIdCache);    // expected by PlayFab custom auth service

        //We add "token" parameter. PlayFab expects it to contain Photon Authentication Token issues to your during previous step.
        customAuth.AddAuthParameter("token", obj.PhotonCustomAuthenticationToken);

        //We finally tell Photon to use this authentication parameters throughout the entire application.
        PhotonNetwork.AuthValues = customAuth;
    }

    private void OnPlayFabError(PlayFabError obj) {
        LogMessage(obj.ErrorMessage);
    }

    public void LogMessage(string message) {
        Debug.Log("PlayFab + Photon Example: " + message);
    }


    // Add small button to launch our example code
    public void OnGUI() {
        if (GUILayout.Button("Execute Example ")) ExecuteExample();
    }


    // Example code which raises custom room event, then sets custom room property
    private void ExecuteExample() {

        // Raise custom room event
        var data = new Dictionary<string, object>() { {"Hello","World"} };
        var result = PhotonNetwork.RaiseEvent(15, data, true, new RaiseEventOptions()
        {
            ForwardToWebhook = true,
        });
        LogMessage("New Room Event Post: "+result);

        // Set custom room property
        var properties = new ExitGames.Client.Photon.Hashtable() { { "CustomProperty", "It's Value" } };
        var expectedProperties = new ExitGames.Client.Photon.Hashtable();
        PhotonNetwork.room.SetCustomProperties(properties, expectedProperties, true);
        LogMessage("New Room Properties Set");
    }

}
  • 运行中心场景并等待 PlayFab 身份验证完成 (1)
  • 然后加载 Boxes Demo 场景 (2)

加载“Demo Boxes”场景

  • 场景加载后,等待对等机连接新创建的房间 (1)
  • 然后选择左上角的 Execute Example(2)
  • 观察控制台输出 (3)
  • 确保未发生错误。

执行示例

请勿忘记阻止 Unity 播放。 这样做是为了确保也收到 RoomLeftRoomClosed 事件。

导航到游戏的 Game Manager 页面,然后观察 PlayStream 面板。 应能够查看由于 CloudScript 代码处理 Photon 事件而生成的事件。

  1. 最初 Photon 实例没有打开的房间。 启动示例后,Photon 为 Boxes Demo 创建了房间。
  2. 要加入的第一个玩家是请求房间的玩家。 因此不记录 RoomJoined 事件。 然后执行我们的示例代码:
    • 首先,引发自定义房间事件
    • 然后,设置自定义房间属性
    • 然后停止 Unity 播放模式。 这会导致我们的客户端离开空间。
  3. 因为我们的断开连接客户端是最后一个,没有任何更多客户端,Photon 会关闭房间。

所有事件都应记录到 PlayStream 事件流中,如下图所示。

PlayStream 事件流

此时已将 Photon 事件支持完全集成到 PlayFab 游戏中。