Unity/PUN2 による RequestOwnership() で OnOwnershipRequest コールバックが呼ばれない!?ときにチェックすること

悩んでいたこと

タイトルの通り。
Unity/PUN2(Photon)によるリアルタイム通信を実装していて、ネットワークオブジェクトの所有権の操作をしていました。

PUN2で始めるオンラインゲーム開発入門【その5】
https://connect.unity.com/p/pun2deshi-meruonraingemukai-fa-ru-men-sono5

PhotonView.RequestOwnership()すればいいよ、ということはわかったのですが、どうしてもコールバックの OnOwnershipRequest() が呼ばれずに悩んでいました。

何が原因だったか

これを書いていませんでした。。。
PhotonNetwork.AddCallbackTarget(this);
IPunOwnershipCallbacks を実装したオブジェクトをコールバックに登録するコードを書く必要がありました。。。

これ、API リファレンス以外のところに書かれてなくない!?
(公式のチュートリアルにすら書いてない)

このフォーラムの投稿から見つけました。。。

PUN v2 Ownership Callbacks
https://forum.photonengine.com/discussion/13494/pun-v2-ownership-callbacks

同じことで悩んでいる人が1分でも早く解決にたどり着けるよう、記事にしておこうと思い立った次第です。

まとめ – OnOwnershipRequest コールバックを使いたい場合のネットワークオブジェクトの所有権移譲の実装方法

  1. 権限移譲の対象にしたいネットワークオブジェクトの PhotonView の所有権オプションを Request にする。
  2. IPunOwnershipCallbacks インターフェースを実装したスクリプトを作り、OnOwnershipRequest, OnOwnershipTransfer コールバックを実装する
  3. そのオブジェクトを Photon のコールバックに登録するため、PhotonNetwork.AddCallbackTarget(this)する。そのスクリプトが MonoBehaviour を継承しているなら、OnEnable() でやるのが吉。(this は IPunOwnershipCallbacks を実装したオブジェクト)
  4. そのスクリプトをゲームオブジェクトにアタッチする。(使いたいシーンで)
  5. 所有権を要求したいタイミングで、そのオブジェクトのPhotonView.RequestOwnership() を呼ぶ。

ちなみに、コールバック登録を解除したい場合はPhotonNetwork.RemoveCallbackTarget(this)です。MonoBehaviour なら OnDisable() で。

参考

こういうスクリプトを書いてゲームオブジェクトにアタッチしておくと動きます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;

public class PunCallback : MonoBehaviour, IPunOwnershipCallbacks
{
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }

    void OnEnable() {
        PhotonNetwork.AddCallbackTarget(this);
    }

    void OnDisable() {
        PhotonNetwork.RemoveCallbackTarget(this);
    }

    // 所有権のリクエストが行われた時に呼ばれるコールバック
    void IPunOwnershipCallbacks.OnOwnershipRequest(PhotonView targetView, Player requestingPlayer)
    {
        // 自身が所有権を持つインスタンスで所有権のリクエストが行われたら、常に許可して所有権を移譲する
        if (targetView.IsMine)
        {
            bool acceptsRequest = true;
            if (acceptsRequest)
            {
                targetView.TransferOwnership(requestingPlayer);
            }
            else
            {
                // リクエストを拒否する場合は、何もしない
            }
        }
    }

    // 所有権の移譲が行われた時に呼ばれるコールバック
    void IPunOwnershipCallbacks.OnOwnershipTransfered(PhotonView targetView, Player previousOwner)
    {
        string id = targetView.ViewID.ToString();
        string p1 = previousOwner.NickName;
        string p2 = targetView.Owner.NickName;
        Debug.Log($"ViewID {id} の所有権が {p1} から {p2} に移譲されました");
    }
}

元記事はこちら

Unity/PUN2 による RequestOwnership() で OnOwnershipRequest コールバックが呼ばれない!?ときにチェックすること