PUN2 Example

Description
Below is an example script, which you can attach to your networked object.
Non-owner clients will receive the byte[] from the owner.

In your networked object, we suggested that you should include below script, encoder and decoder.
The encoder should pass the data to FMStreamPUN via Action_SendData().
The decoder should receive the data from FMStreamPUN via OnDataByteReadyEvent

*With PUN2, it can replace these networking system: FMNetworkUDP, FMWebSocket
*There will be a duplicated library error about websocket-sharp.dll, you can remove FMWebSocket folder completely or just websocket-sharp.dll.

Other suggestions from customers
For reducing the PUN2 delay in HoloLens and other mobile devices, below settings are recommended by Byron Boskell.
1) unreliable stream option in PhotonView
2) TCP server option in PUN2 Server Settings

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

public class FMStreamPUN : Photon.Pun.MonoBehaviourPun, IPunObservable {
    private Queue<byte[]> appendQueueSendData = new Queue<byte[]>();
    public int appendQueueSendDataCount { get { return appendQueueSendData.Count; } }

    public UnityEventByteArray OnDataByteReadyEvent = new UnityEventByteArray();

    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) {
        if (stream.IsWriting) {
            //Send the meta data of the byte[] queue length
            stream.SendNext(appendQueueSendDataCount);
            //Sending the queued byte[]
            while(appendQueueSendDataCount > 0) {
                byte[] sentData = appendQueueSendData.Dequeue();
                stream.SendNext(sentData);
            }
        }

        if (stream.IsReading) {
            if (!photonView.IsMine) {
                //Get the queue length
                int streamCount = (int)stream.ReceiveNext();
                for (int i = 0; i < streamCount; i++) {
                    //reading stream one by one
                    byte[] receivedData = (byte[])stream.ReceiveNext();
                    OnDataByteReadyEvent.Invoke(receivedData);
                }
            }
        }
    }

    public void Action_SendData(byte[] inputData) {
        //inputData(byte[]) is the encoded byte[] from your encoder
        //doesn't require any stream, when there is only one player in the room
        if(PhotonNetwork.CurrentRoom.PlayerCount > 1) appendQueueSendData.Enqueue(inputData);
    }
}