Photon(PUN 2)で任意データの同期処理を書く（自動でオーナー変更！）

# はじめに

*こんにちは、のんびりエンジニアのたっつーです。*
*[ブログ](https://www.fast-system.jp/)を運営しています、今回は[この記事](https://www.fast-system.jp/unity-photon-text-sync-data/)の転載になります。*


Unityのネットワークライブラリの Photon を使う場合に、自分で定義したデータを同期したい場合がありますよね。
そこで今回は自分で同期処理を書いてみます。

# Photon とは？

[PUN 2 – FREE](https://assetstore.unity.com/packages/tools/network/pun-2-free-119922?aid=1101l7pnr) （無料版）
[Photon PUN 2+](https://assetstore.unity.com/packages/tools/network/photon-pun-2-120838?aid=1101l7pnr) （有料版）

Photon とは***マルチプレイヤーゲーム***を作る場合にネットワーク部分を担当してくれる***ネットワークライブラリ***になります。

例えば、モンストなどのゲームを作る場合には同時プレイしている***４人の画面の情報を同期***しないといけないですよね？そんな時に Photon を使うとネットワーク部分のめんどくさい部分を一括して担当してくれます。

# 使い方

まずは、Photon は同期するオブジェクトに PhotonView のスクリプトをアタッチします。
この ***PhotonView ではそのオブジェクトがどのクライアントの持ち主（オーナー）かを管理***しています。

データを同期する際には、***オーナー側がデータを送信して、オーナー以外がデータを受信***する動きをします。
オーナー以外がデータを送信する側になりたい場合、***一度オーナー権限を取得してからデータを送信する処理***を書きましょう。

## ソースコード

今回はサンプルとして、***文字列（テキスト）を同期するスクリプト***を書いてみます。

１つ目ポイントとなるのは、***OnPhotonSerializeView メソッドでオーナー側、オーナー以外側の処理を同時***に記載しています。

２つ目のポイントは、Textプロパティを変更すると、オーナーのリクエストを発行して非オーナーでもデータの変更（同期）が可能となっています。
※ ***Text変更毎にオーナーがどんどん変わっていきます***。

```C#:PhotonTextView.cs
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhotonTextView : MonoBehaviour, IPunObservable
{
    private PhotonView photonView;

    public string _text;

    public string Text
    {
        get { return _text; }
        set { _text = value; RequestOwner(); }
    }

    void Awake()
    {
        this.photonView = GetComponent<PhotonView>();
    }

    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        // オーナーの場合
        if (stream.IsWriting)
        {
            stream.SendNext(this._text);
        }
        // オーナー以外の場合
        else
        {
            this._text = (string)stream.ReceiveNext();
        }
    }

    private void RequestOwner()
    {
        if (this.photonView.IsMine == false)
        {
            if (this.photonView.OwnershipTransfer != OwnershipOption.Request)
                Debug.LogError("OwnershipTransferをRequestに変更してください。");
            else
                this.photonView.RequestOwnership();
        }
    }
}
```

## 同期可能なデータ種類

[Photonでサポートされている型](https://doc.photonengine.com/ja-jp/pun/current/reference/serialization-in-photon) をみると基本的な部分は使えそうですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/c01cb7f1-56ee-22fa-b805-ced582fb6e05.png)

## 使い方

い方は、下の３ステップになります。
※ すでに PhotonView が追加されている場合は、Observed Componetnsのプラスボタンで複数追加できるようになるので増やして使ってください。

１．PhotonView を追加してください。
２．PhotonTextView （今回作成したスクリプト） を追加してください。
３．PhotonTextView を PhotonView.ObservedComponets に紐づけてください。
４．PhotonViewの Owner＝Request に変更してください。

![image-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/6545b232-06e9-ae2e-8ca5-987f43803977.png)


## 実行結果

それでは実行してみましょう、以下のようなクライアントになります。
　左側が、オーナー側で送信側
　右側が、非オーナー側で受信側

![photonsync.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/ef2e94a4-15dd-0e9a-ba21-2ee8e0389c94.gif)


# 終わりに

*よければ ブログ「[Unity+AssetStoreおすすめ情報](https://www.fast-system.jp/)」の方にも色々記載しているのでぜひご参照いただければと思います。*