Пример #1
0
        // this method corrects the IDs for photonviews in the scene and in prefabs
        // make sure prefabs always use viewID 0
        // make sure instances never use a owner
        // this is a editor class that should only run if not playing
        internal static void HierarchyChange()
        {
            if (Application.isPlaying)
            {
                //Debug.Log("HierarchyChange ignored, while running.");
                CheckSceneForStuckHandlers = true;  // done once AFTER play mode.
                return;
            }

            if (CheckSceneForStuckHandlers)
            {
                CheckSceneForStuckHandlers = false;
                PhotonNetwork.InternalCleanPhotonMonoFromSceneIfStuck();
            }

            HashSet <PhotonView> pvInstances             = new HashSet <PhotonView>();
            HashSet <int>        usedInstanceViewNumbers = new HashSet <int>();
            bool fixedSomeId = false;

            //// the following code would be an option if we only checked scene objects (but we can check all PVs)
            //PhotonView[] pvObjects = GameObject.FindSceneObjectsOfType(typeof(PhotonView)) as PhotonView[];
            //Debug.Log("HierarchyChange. PV Count: " + pvObjects.Length);

            string levelName = SceneManagerHelper.ActiveSceneName;

            #if UNITY_EDITOR
            levelName = SceneManagerHelper.EditorActiveSceneName;
            #endif
            int minViewIdInThisScene = PunSceneSettings.MinViewIdForScene(levelName);
            //Debug.Log("Level '" + Application.loadedLevelName + "' has a minimum ViewId of: " + minViewIdInThisScene);

            PhotonView[] pvObjects = Resources.FindObjectsOfTypeAll(typeof(PhotonView)) as PhotonView[];

            foreach (PhotonView view in pvObjects)
            {
                // first pass: fix prefabs to viewID 0 if they got a view number assigned (cause they should not have one!)
                if (EditorUtility.IsPersistent(view.gameObject))
                {
                    if (view.ViewID != 0 || view.prefixField != -1)
                    {
                        Debug.LogWarning("PhotonView on persistent object being fixed (id and prefix must be 0). Was: " + view);
                        view.ViewID      = 0;
                        view.prefixField = -1;
                        EditorUtility.SetDirty(view);   // even in Unity 5.3+ it's OK to SetDirty() for non-scene objects.
                        fixedSomeId = true;
                    }
                }
                else
                {
                    // keep all scene-instanced PVs for later re-check
                    pvInstances.Add(view);
                }
            }

            Dictionary <GameObject, int> idPerObject = new Dictionary <GameObject, int>();

            // second pass: check all used-in-scene viewIDs for duplicate viewIDs (only checking anything non-prefab)
            // scene-PVs must have user == 0 (scene/room) and a subId != 0
            foreach (PhotonView view in pvInstances)
            {
                if (view.OwnerActorNr > 0)
                {
                    Debug.Log("Re-Setting Owner ID of: " + view);
                }

                view.Prefix = -1;   // TODO: prefix could be settable via inspector per scene?!

                if (view.ViewID != 0)
                {
                    if (view.ViewID < minViewIdInThisScene || usedInstanceViewNumbers.Contains(view.ViewID))
                    {
                        view.ViewID = 0; // avoid duplicates and negative values by assigning 0 as (temporary) number to be fixed in next pass
                    }
                    else
                    {
                        usedInstanceViewNumbers.Add(view.ViewID); // builds a list of currently used viewIDs

                        int instId = 0;
                        if (idPerObject.TryGetValue(view.gameObject, out instId))
                        {
                            view.InstantiationId = instId;
                        }
                        else
                        {
                            view.InstantiationId         = view.ViewID;
                            idPerObject[view.gameObject] = view.InstantiationId;
                        }
                    }
                }
            }

            // third pass: anything that's now 0 must get a new (not yet used) ID (starting at 0)
            int lastUsedId = (minViewIdInThisScene > 0) ? minViewIdInThisScene - 1 : 0;

            foreach (PhotonView view in pvInstances)
            {
                if (view.ViewID == 0)
                {
                    Undo.RecordObject(view, "Automatic viewID change for: " + view.gameObject.name);

                    // Debug.LogWarning("setting scene ID: " + view.gameObject.name + " ID: " + view.subId.ID + " scene ID: " + view.GetSceneID() + " IsPersistent: " + EditorUtility.IsPersistent(view.gameObject) + " IsSceneViewIDFree: " + IsSceneViewIDFree(view.subId.ID, view));
                    int nextViewId = PhotonViewHandler.GetID(lastUsedId, usedInstanceViewNumbers);

                    view.ViewID = nextViewId;

                    int instId = 0;
                    if (idPerObject.TryGetValue(view.gameObject, out instId))
                    {
                        view.InstantiationId = instId;
                    }
                    else
                    {
                        view.InstantiationId         = view.ViewID;
                        idPerObject[view.gameObject] = nextViewId;
                    }

                    lastUsedId  = nextViewId;
                    fixedSomeId = true;
                }
            }


            if (fixedSomeId)
            {
                //Debug.LogWarning("Some subId was adjusted."); // this log is only interesting for Exit Games
            }
        }
        public override void OnInspectorGUI()
        {
            this.m_Target = (PhotonView)target;
            bool isProjectPrefab = EditorUtility.IsPersistent(this.m_Target.gameObject);

            if (this.m_Target.ObservedComponents == null)
            {
                this.m_Target.ObservedComponents = new System.Collections.Generic.List <Component>();
            }

            if (this.m_Target.ObservedComponents.Count == 0)
            {
                this.m_Target.ObservedComponents.Add(null);
            }

            EditorGUILayout.BeginHorizontal();
            // Owner
            if (isProjectPrefab)
            {
                EditorGUILayout.LabelField("Owner:", "Set at runtime");
            }
            else if (!this.m_Target.IsOwnerActive)
            {
                EditorGUILayout.LabelField("Owner", "Scene");
            }
            else
            {
                Player owner     = this.m_Target.Owner;
                string ownerInfo = (owner != null) ? owner.NickName : "<no Player found>";

                if (string.IsNullOrEmpty(ownerInfo))
                {
                    ownerInfo = "<no playername set>";
                }

                EditorGUILayout.LabelField("Owner", "[" + this.m_Target.OwnerActorNr + "] " + ownerInfo);
            }

            // ownership requests
            EditorGUI.BeginDisabledGroup(Application.isPlaying);
            OwnershipOption own = (OwnershipOption)EditorGUILayout.EnumPopup(this.m_Target.OwnershipTransfer, GUILayout.Width(100));

            if (own != this.m_Target.OwnershipTransfer)
            {
                // jf: fixed 5 and up prefab not accepting changes if you quit Unity straight after change.
                // not touching the define nor the rest of the code to avoid bringing more problem than solving.
                EditorUtility.SetDirty(this.m_Target);

                Undo.RecordObject(this.m_Target, "Change PhotonView Ownership Transfer");
                this.m_Target.OwnershipTransfer = own;
            }
            EditorGUI.EndDisabledGroup();

            EditorGUILayout.EndHorizontal();


            // View ID
            if (isProjectPrefab)
            {
                EditorGUILayout.LabelField("View ID", "Set at runtime");
            }
            else if (EditorApplication.isPlaying)
            {
                EditorGUILayout.LabelField("View ID", this.m_Target.ViewID.ToString());
            }
            else
            {
                int idValue = EditorGUILayout.IntField("View ID [1.." + (PhotonNetwork.MAX_VIEW_IDS - 1) + "]", this.m_Target.ViewID);
                if (this.m_Target.ViewID != idValue)
                {
                    Undo.RecordObject(this.m_Target, "Change PhotonView viewID");
                    this.m_Target.ViewID = idValue;
                }
            }

            // Locally Controlled
            if (EditorApplication.isPlaying)
            {
                string masterClientHint = PhotonNetwork.IsMasterClient ? "(master)" : "";
                EditorGUILayout.Toggle("Controlled locally: " + masterClientHint, this.m_Target.IsMine);
            }

            // ViewSynchronization (reliability)
            if (this.m_Target.Synchronization == ViewSynchronization.Off)
            {
                GUI.color = Color.grey;
            }

            EditorGUILayout.PropertyField(serializedObject.FindProperty("Synchronization"), new GUIContent("Observe option:"));

            if (this.m_Target.Synchronization != ViewSynchronization.Off && this.m_Target.ObservedComponents.FindAll(item => item != null).Count == 0)
            {
                GUILayout.BeginVertical(GUI.skin.box);
                GUILayout.Label("Warning", EditorStyles.boldLabel);
                GUILayout.Label("Setting the synchronization option only makes sense if you observe something.");
                GUILayout.EndVertical();
            }

            GUI.color = Color.white;
            DrawObservedComponentsList();

            // Cleanup: save and fix look
            if (GUI.changed)
            {
                PhotonViewHandler.HierarchyChange(); // TODO: check if needed
            }

            GUI.color = Color.white;
        }
        public override void OnInspectorGUI()
        {
            this.m_Target = (PhotonView)this.target;
            bool isProjectPrefab = PhotonEditorUtils.IsPrefab(this.m_Target.gameObject);
            bool multiSelected   = Selection.gameObjects.Length > 1;

            if (this.m_Target.ObservedComponents == null)
            {
                this.m_Target.ObservedComponents = new System.Collections.Generic.List <Component>();
            }

            if (this.m_Target.ObservedComponents.Count == 0)
            {
                this.m_Target.ObservedComponents.Add(null);
            }

            GUILayout.Space(5);

            EditorGUILayout.BeginVertical((GUIStyle)"HelpBox");
            // View ID - Hide if we are multi-selected
            if (!multiSelected)
            {
                if (isProjectPrefab)
                {
                    EditorGUILayout.LabelField("View ID", "<i>Set at runtime</i>", new GUIStyle("Label")
                    {
                        richText = true
                    });
                }
                else if (EditorApplication.isPlaying)
                {
                    EditorGUILayout.LabelField("View ID", this.m_Target.ViewID.ToString());
                }
                else
                {
                    int idValue = EditorGUILayout.IntField("View ID [1.." + (PhotonNetwork.MAX_VIEW_IDS - 1) + "]", this.m_Target.ViewID);
                    if (this.m_Target.ViewID != idValue)
                    {
                        Undo.RecordObject(this.m_Target, "Change PhotonView viewID");
                        this.m_Target.ViewID = idValue;
                    }
                }
            }

            // Locally Controlled
            if (EditorApplication.isPlaying)
            {
                string masterClientHint = PhotonNetwork.IsMasterClient ? " (master)" : "";
                EditorGUILayout.LabelField("IsMine:", this.m_Target.IsMine.ToString() + masterClientHint);
                Room   room    = PhotonNetwork.CurrentRoom;
                int    cretrId = this.m_Target.CreatorActorNr;
                Player cretr   = (room != null) ? room.GetPlayer(cretrId) : null;
                Player owner   = this.m_Target.Owner;
                Player ctrlr   = this.m_Target.Controller;
                EditorGUILayout.LabelField("Controller:", (ctrlr != null ? ("[" + ctrlr.ActorNumber + "] '" + ctrlr.NickName + "' " + (ctrlr.IsMasterClient ? " (master)" : "")) : "[0] <null>"));
                EditorGUILayout.LabelField("Owner:", (owner != null ? ("[" + owner.ActorNumber + "] '" + owner.NickName + "' " + (owner.IsMasterClient ? " (master)" : "")) : "[0] <null>"));
                EditorGUILayout.LabelField("Creator:", (cretr != null ? ("[" + cretrId + "] '" + cretr.NickName + "' " + (cretr.IsMasterClient ? " (master)" : "")) : "[0] <null>"));
            }

            EditorGUILayout.EndVertical();

            EditorGUI.BeginDisabledGroup(Application.isPlaying);

            GUILayout.Space(5);

            // Ownership section

            EditorGUILayout.LabelField("Ownership", (GUIStyle)"BoldLabel");

            OwnershipOption own = (OwnershipOption)EditorGUILayout.EnumPopup(ownerTransferGuiContent, this.m_Target.OwnershipTransfer /*, GUILayout.MaxWidth(68), GUILayout.MinWidth(68)*/);

            if (own != this.m_Target.OwnershipTransfer)
            {
                // jf: fixed 5 and up prefab not accepting changes if you quit Unity straight after change.
                // not touching the define nor the rest of the code to avoid bringing more problem than solving.
                EditorUtility.SetDirty(this.m_Target);

                Undo.RecordObject(this.m_Target, "Change PhotonView Ownership Transfer");
                this.m_Target.OwnershipTransfer = own;
            }


            GUILayout.Space(5);

            // Observables section

            EditorGUILayout.LabelField("Observables", (GUIStyle)"BoldLabel");

            EditorGUILayout.PropertyField(this.serializedObject.FindProperty("Synchronization"), syncronizationGuiContent);

            if (this.m_Target.Synchronization == ViewSynchronization.Off)
            {
                // Show warning if there are any observables. The null check is because the list allows nulls.
                var observed = m_Target.ObservedComponents;
                if (observed.Count > 0)
                {
                    for (int i = 0, cnt = observed.Count; i < cnt; ++i)
                    {
                        if (observed[i] != null)
                        {
                            EditorGUILayout.HelpBox("Syncronization is set to Off. Select a Syncronization setting in order to sync the listed Observables.", MessageType.Warning);
                            break;
                        }
                    }
                }
            }


            PhotonView.ObservableSearch autoFindObservables = (PhotonView.ObservableSearch)EditorGUILayout.EnumPopup(observableSearchGuiContent, m_Target.observableSearch);

            if (m_Target.observableSearch != autoFindObservables)
            {
                Undo.RecordObject(this.m_Target, "Change Auto Find Observables Toggle");
                m_Target.observableSearch = autoFindObservables;
            }

            m_Target.FindObservables();

            if (!multiSelected)
            {
                bool disableList = Application.isPlaying || autoFindObservables != PhotonView.ObservableSearch.Manual;

                if (disableList)
                {
                    EditorGUI.BeginDisabledGroup(true);
                }

                this.DrawObservedComponentsList(disableList);

                if (disableList)
                {
                    EditorGUI.EndDisabledGroup();
                }
            }

            // Cleanup: save and fix look
            if (GUI.changed)
            {
                PhotonViewHandler.OnHierarchyChanged(); // TODO: check if needed
            }

            EditorGUI.EndDisabledGroup();
        }