PhotonView broken inside Unity prefab

I have 1 PhotonView. Using RPCs. When I instantiate it from a prefab, RPCs are broken it's trying to message View Id 0. Intermittent, but mostly broken with exceptions about View id 0 not found.

When I just put it in the scene instead of instantiating from prefab, the RPC calls work fine.

Btw that's cool that you support byte arrays for RPC . thank you :)_

Comments

  • What version of PUN are you using? See PhotonNetwork.versionPUN.

    I assume you are using UNity 3.4 (and not 3.5).
    Then this might possibly fix it:

    PhotonViewInspector line +- 75
    if (sceneProp.isInstantiatedPrefab && !sceneProp.prefabOverride)
            {
                //Fix the assignment
    #if !UNITY_3_5
                sceneProp.prefabOverride = true;
    #endif
    

    After applying this patch, make sure to inspect the prefab before using it in your scene.
  • Hi sorry I didn't say I'm using: Unity 3.5.0f1
  • I see, I'm trying to repro & fix this right now.
  • I believe I've fixed it, please try this for PhotonView.cs.
    This works for me on PUN 1.8, but I'm not sure if this'll work out oft he box on 1.7 too.

    // ----------------------------------------------------------------------------
    // <copyright file="PhotonView.cs" company="Exit Games GmbH">
    //   PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH
    // </copyright>
    // <summary>
    //   
    // </summary>
    // <author>developer@exitgames.com</author>
    // ----------------------------------------------------------------------------
    using UnityEngine;
    using System.Collections;
    
    public enum ViewSynchronization { Off, ReliableDeltaCompressed, Unreliable }
    public enum OnSerializeTransform { OnlyPosition, OnlyRotation, OnlyScale, PositionAndRotation, All }
    public enum OnSerializeRigidBody { OnlyVelocity, OnlyAngularVelocity, All }
    
    
    [AddComponentMenu("Miscellaneous/Photon View")]
    public class PhotonView : Photon.MonoBehaviour
    {
        //Save scene ID in serializable INT (only changable via Editor)
        [SerializeField]
        private int sceneViewID = 0;
    
        [SerializeField]
        private PhotonViewID ID = new PhotonViewID(0, null);
        
        public Component observed;
        public ViewSynchronization synchronization;
        public int group = 0;
        public int prefix = -1;
        public object[] instantiationData = null;
        public Hashtable lastOnSerializeDataSent = null;
        public OnSerializeTransform onSerializeTransformOption = OnSerializeTransform.PositionAndRotation;
        public OnSerializeRigidBody onSerializeRigidBodyOption = OnSerializeRigidBody.All;
        private bool registeredPhotonView = false;
    
        public PhotonViewID viewID
        {
            get
            {
                if (!ranSetup) Setup();
                if (ID.ID < 1 && sceneViewID > 0)
                {   //Load the correct scene ID
                    ID = new PhotonViewID(sceneViewID, null);
                }
                return ID;
            }
            set
            {
                if (!ranSetup) Setup();
                if (registeredPhotonView && PhotonNetwork.networkingPeer != null) PhotonNetwork.networkingPeer.RemovePhotonView(this, true);
                ID = value;
                if (PhotonNetwork.networkingPeer != null)
                {
                    PhotonNetwork.networkingPeer.RegisterPhotonView(this);
                    registeredPhotonView = true;
                }
            }
        }
    
        public override string ToString()
        {
            return string.Format("View {0} on {1} {2}", this.ID.ID, this.gameObject.name, (this.isSceneView)? "(scene)" : "");
        }
    
        public bool isSceneView
        {
            get
            {
                return sceneViewID > 0;
            }
        }
    
        public PhotonPlayer owner
        {
            get
            {
                if (!ranSetup) Setup();
                return viewID.owner;
            }
        }
    
        public bool isMine
        {
            get
            {
                if (!ranSetup) Setup();
                return (owner == PhotonNetwork.player) || (isSceneView && PhotonNetwork.isMasterClient);
            }
        }
    
    #if UNITY_EDITOR
    
        public void SetSceneID(int newID)
        {
            sceneViewID = newID;
        }
    
        public int GetSceneID()
        {
            return sceneViewID;
        }
    
    #endif
    
        void Awake()
        {
            Setup();
        }
    
        private bool ranSetup = false;
        private void Setup()
        {
            if (!Application.isPlaying) return;
            if (ranSetup) return;
    
            ranSetup = true;
            
            if (isSceneView)
            {
                bool result = PhotonNetwork.networkingPeer.PhotonViewSetup_FindMatchingRoot(gameObject);
                if (result)
                {
                    // This instantiated prefab needs to be corrected as it's incorrectly reported as a sceneview.
                    // It is wrongly reported as isSceneView because a scene-prefab changes have been applied to the project prefab
                    // The scene's prefab viewID is therefore saved to the project prefab. This workaround fixes all problems
                    sceneViewID = 0;                          
                }
                else
                {
                    if (sceneViewID < 1) Debug.LogError("SceneView " + sceneViewID);
                    ID = new PhotonViewID(sceneViewID, null);
                    registeredPhotonView = true;
                    PhotonNetwork.networkingPeer.RegisterPhotonView(this);
                }
            }
            else
            {
                bool res = PhotonNetwork.networkingPeer.PhotonViewSetup_FindMatchingRoot(gameObject);
                if (!res)
                {
                    Debug.LogError("Error: Did not find the root of a PhotonNetwork.Instantiated PhotonView! This can cause problems with the viewID.");
                }
            }
            
        }
    
        void OnDestroy()
        {
            PhotonNetwork.networkingPeer.RemovePhotonView(this, true);
        }
    
        public void RPC(string methodName, PhotonTargets target, params object[] parameters)
        {
            PhotonNetwork.RPC(this, methodName, target, parameters);
        }
    
        public void RPC(string methodName, PhotonPlayer targetPlayer, params object[] parameters)
        {
            PhotonNetwork.RPC(this, methodName, targetPlayer, parameters);
        }
    
        public static PhotonView Get(Component component)
        {
            return component.GetComponent<PhotonView>();
        }
    
        public static PhotonView Get(GameObject gameObj)
        {
            return gameObj.GetComponent<PhotonView>();
        }
    
        public static PhotonView Find(int viewID)
        {
            return PhotonNetwork.networkingPeer.GetPhotonView(viewID);
        }
    }
    


    If the above doesn't work for 1.7, try replacing only SETUP():
    private void Setup()
        {
            if (!Application.isPlaying) return;
            if (ranSetup) return;
    
            ranSetup = true;
            
            if (isSceneView)
            {
                bool result = PhotonNetwork.networkingPeer.PhotonViewSetup_FindMatchingRoot(gameObject);
                if (result)
                {
                    // This instantiated prefab needs to be corrected as it's incorrectly reported as a sceneview.
                    // It is wrongly reported as isSceneView because a scene-prefab changes have been applied to the project prefab
                    // The scene's prefab viewID is therefore saved to the project prefab. This workaround fixes all problems
                    sceneViewID = 0;                          
                }
                else
                {
                    if (sceneViewID < 1) Debug.LogError("SceneView " + sceneViewID);
                    ID = new PhotonViewID(sceneViewID, null);
                    registeredPhotonView = true;
                    PhotonNetwork.networkingPeer.RegisterPhotonView(this);
                }
            }
            else
            {
                bool res = PhotonNetwork.networkingPeer.PhotonViewSetup_FindMatchingRoot(gameObject);
                if (!res)
                {
                    Debug.LogError("Error: Did not find the root of a PhotonNetwork.Instantiated PhotonView! This can cause problems with the viewID.");
                }
            }
        }
    
  • Thanks Leepo, I'm getting errors with both of the fixes, so I guess I'l wait for 1.8 and try prefabs again.
  • So in 1.8 I'm not getting the view id = 0 error message, but instead
    error: Did not find the root of a PhotonNetwork.Instantiated PhotonView! This can cause problems with the viewID.
    I should clarify: I am using Instantiate() not PhotonNetwork.Instantiate().
    I just want to have my multiplayer controller code in a prefab, and not load it unless the user picks multiplayer game. But it's not a big deal to just have it in the scene if PhotonView doesn't like launching from a Prefab.
  • Ahhh, ok now that error does make sense since the PhotonView expects to be either a Scene prefab OR instantiated via PhotonNetwork.Instantiate.
    If you want to use Instantiate at runtime you'll have to allocate PhotonViewID's yourself using PhotonNetwork.AllocateViewID and use that viewID(s) for the new PhotonView(s).

    if you can simply leave the prefab in the scene I'd go for that easy route.
  • Leepo wrote:
    if you can simply leave the prefab in the scene I'd go for that easy route.
    Was this improved at all in 1.9 or is it still advised to always leave the PhotonView in the Scene and not put it in a prefab? I didn't see anything about it in the ChangeLog but thought I would ask.
  • This has not changed in 1.9
    I should clarify: I am using Instantiate() not PhotonNetwork.Instantiate().
    I just want to have my multiplayer controller code in a prefab, and not load it unless the user picks multiplayer game. But it's not a big deal to just have it in the scene if PhotonView doesn't like launching from a Prefab.
    You can use Unity's normal Instantiate() to instantiate such a prefab, but the problem is that this will be a user-owned PhotonView (after allocating it a PhotonViewID) and you have no way to send the PhotonViewID to other clients...so communication over this view will not work. You do really need at least 1 scene photonview.
    There should be next to no overhead to have a PhotonView in a scene for a non-multiplayer game.