private Dictionary <int, RealtimeView> CreateChildViewMap()
        {
            Dictionary <int, RealtimeView> childViewMap = new Dictionary <int, RealtimeView>();

            // Loop through all child views, ignore invalid ones.
            foreach (RealtimeViewChildIDViewPair pair in _childViews)
            {
                int          viewID = pair.viewID;
                RealtimeView view   = pair.view;

                // Check for valid view ID (greater than zero)
                // TODO: We need to verify the upper bound limit on viewIDs too
                if (viewID <= 0)
                {
                    Debug.LogError("RealtimeView child views must have an ID of 1 or greater. Skipping view: (" + viewID + ":" + view + ")", view);
                    continue;
                }

                // Check for duplicate
                if (childViewMap.Remove(viewID))
                {
                    Debug.LogError("Found duplicate child view ID (" + viewID + "). Skipping both views to avoid data corruption.", view);
                    continue;
                }

                childViewMap.Add(viewID, view);
            }

            return(childViewMap);
        }
        private void CreateComponentsModelAndChildViewsModelIfNeeded(string prefabName)
        {
            // Load the prefab
            GameObject prefab = Resources.Load <GameObject>(prefabName);

            if (prefab == null)
            {
                Debug.LogError("Attempting to instantiate prefab from datastore. Failed to find prefab \"" + prefabName + "\". Make sure it's in a Resources folder. Bailing.");
                return;
            }

            // Get the RealtimeView script at the root
            RealtimeView prefabRealtimeView = prefab.GetComponent <RealtimeView>();

            if (prefabRealtimeView == null)
            {
                Debug.LogError("Attempting to instantiate prefab from datastore. Failed to find RealtimeView component on prefab \"" + prefabName + "\". Make sure the prefab has a RealtimeView script at the root level. Bailing.");
                return;
            }

            if (_componentsModel == null)
            {
                _componentsModel = prefabRealtimeView._CreateComponentsModel();
            }
            if (_childViewsModel == null)
            {
                _childViewsModel = prefabRealtimeView._CreateChildViewsModel();
            }
        }
        private RealtimeViewComponentsModel CreateChildViewsModel(Dictionary <int, RealtimeView> childViewMap)
        {
            // Create models for all views
            Dictionary <int, IModel> childViewModelMap = new Dictionary <int, IModel>();

            foreach (KeyValuePair <int, RealtimeView> pair in childViewMap)
            {
                int          viewID = pair.Key;
                RealtimeView view   = pair.Value;

                if (view == null)
                {
                    // Note: Deprecated view IDs will have a null view property. This is normal and they can be safely ignored.
                    continue;
                }

                // Create model
                RealtimeViewModel viewModel = view._CreateChildViewModel();
                if (viewModel == null)
                {
                    Debug.LogError("Model supplied by child RealtimeView is null. Skipping view: (" + viewID + ":" + view + ")", view);
                    continue;
                }

                // Set model
                childViewModelMap[viewID] = viewModel;
            }

            // Create RealtimeViewComponentsModel
            RealtimeViewComponentsModel childViewsModel = new RealtimeViewComponentsModel(childViewModelMap);

            return(childViewsModel);
        }
        private static void RemoveChildViewFromParentViewList(RealtimeView parentView, RealtimeView childView)
        {
            // Remove from parent view's childViews list.
            SerializedObject parentViewSerializedObject = new SerializedObject(parentView);

            parentViewSerializedObject.Update();
            SerializedProperty childViewsProperty = parentViewSerializedObject.FindProperty("_childViews");
            int numberOfChildViews = childViewsProperty.arraySize;

            // Check for child view in the list
            for (int i = 0; i < numberOfChildViews; i++)
            {
                SerializedProperty childViewProperty     = childViewsProperty.GetArrayElementAtIndex(i);
                SerializedProperty childViewViewProperty = childViewProperty.FindPropertyRelative("view");
                SerializedProperty childViewViewToUseIfMovedBackProperty = childViewProperty.FindPropertyRelative("viewToUseIfMovedBack");
                RealtimeView       view = childViewViewProperty.objectReferenceValue as RealtimeView;

                // If the view exists, clear it out.
                if (view == childView)
                {
                    // Clear view property
                    childViewViewProperty.objectReferenceValue = null;

                    // Store a reference so if the view is moved back, it gets assigned to the same View ID
                    childViewViewToUseIfMovedBackProperty.objectReferenceValue = childView;
                }
            }
            parentViewSerializedObject.ApplyModifiedPropertiesWithoutUndo();
        }
        public static void _ConfigureRealtimeView(RealtimeView realtimeView)
        {
            GameObject[] sceneRootGameObjects = SceneManager.GetActiveScene().GetRootGameObjects();
            Realtime[]   realtimeInstances    = sceneRootGameObjects.SelectMany(i => i.GetComponentsInChildren <Realtime>()).ToArray();
            bool         didWarnAboutRealtimeInstancesBeingTooFewOrTooMany = false;

            ConfigureRealtimeView(realtimeView, realtimeInstances, ref didWarnAboutRealtimeInstancesBeingTooFewOrTooMany);
        }
Exemple #6
0
    void Start()
    {
        _rt = GetComponentInParent <Normal.Realtime.RealtimeTransform>();
        _rv = GetComponentInParent <Normal.Realtime.RealtimeView>();
        //_rv.RequestOwnership();

        //Debug.Log("realtime.clientID is " + _rt.ownerID);
        objMats = this.gameObject.GetComponent <Renderer>().materials;

        if (_rt != null)
        {
            //set the player number to the matching material number
            if (_rt.ownerID < avatarMats.Length && _rt.ownerID >= -1)
            {
                //Debug.Log(_rt.ownerID + 1);
                objMats[matSlot] = avatarMats[_rt.ownerID + 1];
            }
            //but if we have more players than materials, than cycle back around
            else
            {
                objMats[matSlot] = avatarMats[_rt.ownerID % avatarMats.Length];
            }
            //don't forget to tell this object to now use our new materials
            this.gameObject.GetComponent <Renderer>().materials = objMats;

            //Debug.Log("clientID is " + _rv.realtime.clientID);
        }
        if (_rt == null && _rv != null)
        {
            //set the player number to the matching material number
            if (_rv.ownerID < avatarMats.Length && _rv.ownerID >= -1)
            {
                //Debug.Log(_rt.ownerID + 1);
                objMats[matSlot] = avatarMats[_rv.ownerID + 1];
            }
            //but if we have more players than materials, than cycle back around
            else
            {
                objMats[matSlot] = avatarMats[_rv.ownerID % avatarMats.Length];
            }
            //don't forget to tell this object to now use our new materials
            this.gameObject.GetComponent <Renderer>().materials = objMats;

            //Debug.Log("clientID is " + _rv.realtime.clientID);
        }

        /*
         * if (_rt == null && _rv == null)
         * {
         *
         * } */
    }
        static RealtimeView AddRealtimeViewComponentIfNeeded(GameObject gameObject)
        {
            RealtimeView realtimeView = gameObject.GetComponent <RealtimeView>();

            if (realtimeView == null)
            {
                realtimeView = gameObject.AddComponent <RealtimeView>();

                // Collapse inspector
                SetComponentInspectorExpanded(realtimeView, false);
            }
            return(realtimeView);
        }
        private static RealtimeView FindParentRealtimeViewForTransform(Transform realtimeViewTransform)
        {
            Transform parent = realtimeViewTransform.parent;

            if (parent == null)
            {
                return(null);
            }
            RealtimeView realtimeView = parent.GetComponent <RealtimeView>();

            if (realtimeView != null)
            {
                return(realtimeView);
            }
            return(FindParentRealtimeViewForTransform(parent));
        }
        private static void AddComponentToViewListIfNeeded(RealtimeView view, RealtimeComponent componentToAdd)
        {
            // Add to view's components list.
            SerializedObject viewSerializedObject = new SerializedObject(view);

            viewSerializedObject.Update();
            SerializedProperty componentsProperty = viewSerializedObject.FindProperty("_components");
            int numberOfComponents = componentsProperty.arraySize;

            // Check for component in the list
            int largestComponentID = 0;

            for (int i = 0; i < numberOfComponents; i++)
            {
                SerializedProperty componentProperty            = componentsProperty.GetArrayElementAtIndex(i);
                SerializedProperty componentComponentIDProperty = componentProperty.FindPropertyRelative("componentID");
                SerializedProperty componentComponentProperty   = componentProperty.FindPropertyRelative("component");
                MonoBehaviour      component = componentComponentProperty.objectReferenceValue as MonoBehaviour;

                // If the component exists, we're done.
                if (component == componentToAdd)
                {
                    return;
                }

                int componentID = componentComponentIDProperty.intValue;
                if (componentID > largestComponentID)
                {
                    largestComponentID = componentID;
                }
            }

            // Not found. Add to list.
            int componentIndex           = numberOfComponents;
            int nextAvailableComponentID = largestComponentID + 1;

            componentsProperty.InsertArrayElementAtIndex(componentIndex);
            SerializedProperty newComponentProperty = componentsProperty.GetArrayElementAtIndex(componentIndex);

            newComponentProperty.FindPropertyRelative("componentID").intValue             = nextAvailableComponentID;
            newComponentProperty.FindPropertyRelative("component").objectReferenceValue   = componentToAdd;
            newComponentProperty.FindPropertyRelative("componentIDHasBeenUsed").boolValue = true;

            viewSerializedObject.ApplyModifiedPropertiesWithoutUndo();
        }
        static void AddComponentToRealtimeViewIfNeeded(RealtimeView realtimeView, Component component)
        {
            SerializedObject realtimeViewSerializedObject = new SerializedObject(realtimeView);

            realtimeViewSerializedObject.Update();

            SerializedProperty realtimeViewComponentsProperty = realtimeViewSerializedObject.FindProperty("_components");

            // Check if the component already exists on the RealtimeView
            int numberOfProperties    = realtimeViewComponentsProperty.arraySize;
            int largestPropertyIDSeen = 0;

            for (int i = 0; i < numberOfProperties; i++)
            {
                SerializedProperty realtimeViewComponentProperty            = realtimeViewComponentsProperty.GetArrayElementAtIndex(i);
                SerializedProperty realtimeViewComponentComponentIDProperty = realtimeViewComponentProperty.FindPropertyRelative("componentID");
                SerializedProperty realtimeViewComponentComponentProperty   = realtimeViewComponentProperty.FindPropertyRelative("component");

                // Record the property ID
                largestPropertyIDSeen = realtimeViewComponentComponentIDProperty.intValue;

                // We found the component. We're done.
                if (realtimeViewComponentComponentProperty.objectReferenceValue == component)
                {
                    return;
                }
            }

            // Component not found, add it.
            int newPropertyIndex = realtimeViewComponentsProperty.arraySize;

            realtimeViewComponentsProperty.InsertArrayElementAtIndex(newPropertyIndex);
            SerializedProperty realtimeViewNewComponentProperty            = realtimeViewComponentsProperty.GetArrayElementAtIndex(newPropertyIndex);
            SerializedProperty realtimeViewNewComponentComponentIDProperty = realtimeViewNewComponentProperty.FindPropertyRelative("componentID");
            SerializedProperty realtimeViewNewComponentComponentProperty   = realtimeViewNewComponentProperty.FindPropertyRelative("component");

            realtimeViewNewComponentComponentIDProperty.intValue           = largestPropertyIDSeen + 1;
            realtimeViewNewComponentComponentProperty.objectReferenceValue = component;

            realtimeViewSerializedObject.ApplyModifiedProperties();
        }
        void CreateAvatarPrefab()
        {
            GameObject gameObject = realtimeAvatar.gameObject;

            //// Root
            // RealtimeView
            RealtimeView rootRealtimeView = AddRealtimeViewComponentIfNeeded(gameObject);

            // RealtimeAvatar
            AddComponentToRealtimeViewIfNeeded(rootRealtimeView, realtimeAvatar);

            // RealtimeTransform
            RealtimeTransform rootRealtimeTransform = AddRealtimeTransformComponentIfNeeded(gameObject, true);

            AddComponentToRealtimeViewIfNeeded(rootRealtimeView, rootRealtimeTransform);


            //// Head
            Transform head = CreateGameObjectForPropertyIfNeeded(headProperty, gameObject.transform, "Head", new Type[] { typeof(Examples.VoiceScale) });

            // RealtimeView
            RealtimeView headRealtimeView = AddRealtimeViewComponentIfNeeded(head.gameObject);

            // RealtimeTransform
            RealtimeTransform headRealtimeTransform = AddRealtimeTransformComponentIfNeeded(head.gameObject, false);

            AddComponentToRealtimeViewIfNeeded(headRealtimeView, headRealtimeTransform);

            // RealtimeAvatarVoice
            RealtimeAvatarVoice headRealtimeAvatarVoice = head.gameObject.GetComponent <RealtimeAvatarVoice>();

            if (headRealtimeAvatarVoice == null)
            {
                headRealtimeAvatarVoice = head.gameObject.AddComponent <RealtimeAvatarVoice>();

                // Collapse inspector
                SetComponentInspectorExpanded(headRealtimeAvatarVoice, false);
            }
            AddComponentToRealtimeViewIfNeeded(headRealtimeView, headRealtimeAvatarVoice);


            //// Left Hand
            Transform leftHand = CreateGameObjectForPropertyIfNeeded(leftHandProperty, gameObject.transform, "Left Hand");

            // RealtimeView
            RealtimeView leftHandRealtimeView = AddRealtimeViewComponentIfNeeded(leftHand.gameObject);

            // RealtimeTransform
            RealtimeTransform leftHandRealtimeTransform = AddRealtimeTransformComponentIfNeeded(leftHand.gameObject, false);

            AddComponentToRealtimeViewIfNeeded(leftHandRealtimeView, leftHandRealtimeTransform);


            //// Right Hand
            Transform rightHand = CreateGameObjectForPropertyIfNeeded(rightHandProperty, gameObject.transform, "Right Hand");

            // RealtimeView
            RealtimeView rightHandRealtimeView = AddRealtimeViewComponentIfNeeded(rightHand.gameObject);

            // RealtimeTransform
            RealtimeTransform rightHandRealtimeTransform = AddRealtimeTransformComponentIfNeeded(rightHand.gameObject, false);

            AddComponentToRealtimeViewIfNeeded(rightHandRealtimeView, rightHandRealtimeTransform);
        }
        private void SetModel(RealtimeViewModel model)
        {
            if (model == _model)
            {
                return;
            }

            if (_model != null)
            {
                _model._SetRealtimeView(null);
            }

            _model = model;

            if (_model != null)
            {
                _model._SetRealtimeView(this);

                Dictionary <int, Tuple <Component, MethodInfo, PropertyInfo, PropertyInfo> > componentMap = CreateComponentMap();

                // Create components model if needed (can happen if RealtimeViewModel existed in the datastore but hasn't been linked to a RealtimeView yet)
                RealtimeViewComponentsModel componentsModel = _model.componentsModel;
                if (_model.componentsModel == null)
                {
                    componentsModel = CreateComponentsModel(componentMap);
                    _model.SetComponentsModelAndDeserializeCachedModelsIfNeeded(componentsModel);
                }

                // Loop through components and assign models
                foreach (KeyValuePair <int, Tuple <Component, MethodInfo, PropertyInfo, PropertyInfo> > pair in componentMap)
                {
                    int          componentID          = pair.Key;
                    Component    component            = pair.Value.First;
                    MethodInfo   createModelMethod    = pair.Value.Second;
                    PropertyInfo modelProperty        = pair.Value.Third;
                    PropertyInfo realtimeViewProperty = pair.Value.Fourth;

                    IModel componentModel = componentsModel[componentID];
                    if (componentModel == null)
                    {
                        Debug.LogError("RealtimeView is attempting to connect a component to its model, but cannot find model for component: (" + componentID + ":" + component + "). This is a bug!", component);
                        continue;
                    }

                    // Set realtime view reference on object if it supports it
                    if (realtimeViewProperty != null)
                    {
                        realtimeViewProperty.SetValue(component, this, null);
                    }

                    // Set model on component
                    modelProperty.SetValue(component, componentModel, null);
                }

                Dictionary <int, RealtimeView> childViewMap = CreateChildViewMap();

                // Create child views model if needed (can happen if RealtimeViewModel existed in the datastore but hasn't been linked to a RealtimeView yet)
                RealtimeViewComponentsModel childViewsModel = _model.childViewsModel;
                if (childViewsModel == null)
                {
                    childViewsModel = CreateChildViewsModel(childViewMap);
                    _model.SetChildViewsModelAndDeserializeCachedModelsIfNeeded(childViewsModel);
                }

                // Loop through child views and assign models
                foreach (KeyValuePair <int, RealtimeView> pair in childViewMap)
                {
                    int          viewID = pair.Key;
                    RealtimeView view   = pair.Value;

                    RealtimeViewModel viewModel = childViewsModel[viewID] as RealtimeViewModel;
                    if (viewModel == null)
                    {
                        Debug.LogError("RealtimeView attempting to connect child view to its models, but cannot find model for view: (" + viewID + ":" + view + "). This is a bug!", view);
                        continue;
                    }

                    // Set realtime instance and model
                    view._SetRealtime(_realtime);
                    view.model = viewModel;
                }
            }
        }
 public void _SetRealtimeView(RealtimeView realtimeView)
 {
     _realtimeView = realtimeView;
 }
        private static bool AddChildViewToParentViewIfNeeded(RealtimeView childView, SerializedObject childViewSerializedObject)
        {
            if (childView == null)
            {
                Debug.LogError("Attempting to add null child view to parent view. This is a bug! Bailing...");
                return(false);
            }

            // Recursively trace up to the parent
            RealtimeView parentView = FindParentRealtimeViewForTransform(childView.transform);

            // Remove from previous parentView and update _parentView property.
            SerializedProperty parentViewSerializedProperty = childViewSerializedObject.FindProperty("_parentView");
            RealtimeView       oldParentView = parentViewSerializedProperty.objectReferenceValue as RealtimeView;

            if (parentView != oldParentView)
            {
                // We're going to change the parent below. Remove the child view from the old parent view's child view list.
                if (oldParentView != null)
                {
                    RemoveChildViewFromParentViewList(oldParentView, childView);
                }

                // Set parent property on child view
                parentViewSerializedProperty.objectReferenceValue = parentView;
            }

            // No parent found, this is a root view.
            if (parentView == null)
            {
                return(true);
            }

            // Add to parent view's childViews list.
            SerializedObject parentViewSerializedObject = new SerializedObject(parentView);

            parentViewSerializedObject.Update();
            SerializedProperty childViewsProperty = parentViewSerializedObject.FindProperty("_childViews");
            int numberOfChildViews = childViewsProperty.arraySize;

            // Check for child view in the list
            int largestViewID = 0;

            for (int i = 0; i < numberOfChildViews; i++)
            {
                SerializedProperty childViewProperty       = childViewsProperty.GetArrayElementAtIndex(i);
                SerializedProperty childViewViewIDProperty = childViewProperty.FindPropertyRelative("viewID");
                SerializedProperty childViewViewProperty   = childViewProperty.FindPropertyRelative("view");
                SerializedProperty childViewViewToUseIfMovedBackProperty = childViewProperty.FindPropertyRelative("viewToUseIfMovedBack");
                RealtimeView       view = childViewViewProperty.objectReferenceValue as RealtimeView;
                RealtimeView       viewToUseIfMovedBack = childViewViewToUseIfMovedBackProperty.objectReferenceValue as RealtimeView;

                // If the view exists, we're done.
                if (view == childView)
                {
                    return(false);
                }

                // If the view has been assigned to this property before, re-assign it and we're done.
                if (viewToUseIfMovedBack == childView)
                {
                    childViewViewProperty.objectReferenceValue        = childView;
                    parentViewSerializedProperty.objectReferenceValue = parentView;
                    parentViewSerializedObject.ApplyModifiedPropertiesWithoutUndo();
                    return(false);
                }

                int viewID = childViewViewIDProperty.intValue;
                if (viewID > largestViewID)
                {
                    largestViewID = viewID;
                }
            }

            // Not found. Add to list.
            int viewIndex           = numberOfChildViews;
            int nextAvailableViewID = largestViewID + 1;

            childViewsProperty.InsertArrayElementAtIndex(viewIndex);
            SerializedProperty newChildViewProperty = childViewsProperty.GetArrayElementAtIndex(viewIndex);

            newChildViewProperty.FindPropertyRelative("viewID").intValue           = nextAvailableViewID;
            newChildViewProperty.FindPropertyRelative("view").objectReferenceValue = childView;
            newChildViewProperty.FindPropertyRelative("viewToUseIfMovedBack").objectReferenceValue = childView;
            newChildViewProperty.FindPropertyRelative("viewIDHasBeenUsed").boolValue = true;
            parentViewSerializedObject.ApplyModifiedPropertiesWithoutUndo();

            return(false);
        }
 public static void _UpdateRealtimeViewSceneViewUUID(RealtimeView realtimeView, byte[] sceneViewUUID)
 {
     _rootSceneViewUUIDMap[realtimeView] = sceneViewUUID;
 }
        private static void ConfigureRealtimeView(RealtimeView realtimeView, Realtime[] realtimeInstances, ref bool didWarnAboutRealtimeInstancesBeingTooFewOrTooMany)
        {
            SerializedObject realtimeViewSerializedObject = new SerializedObject(realtimeView);

            realtimeViewSerializedObject.Update();
            SerializedProperty realtimeProperty         = realtimeViewSerializedObject.FindProperty("_realtime");
            SerializedProperty sceneViewUUIDProperty    = realtimeViewSerializedObject.FindProperty("_sceneViewUUID");
            SerializedProperty isRootPrefabViewProperty = realtimeViewSerializedObject.FindProperty("_isRootPrefabView");

            // Realtime Instance
            Realtime realtime = realtimeProperty.objectReferenceValue as Realtime;
            bool     prefab   = EditorUtility.IsPersistent(realtimeView.gameObject);

            if (prefab)
            {
                if (realtime != null)
                {
                    realtimeProperty.objectReferenceValue = null;
                }
            }
            else
            {
                if (realtime == null)
                {
                    if (realtimeInstances.Length == 1)
                    {
                        realtimeProperty.objectReferenceValue = realtimeInstances[0];
                    }
                    else if (!didWarnAboutRealtimeInstancesBeingTooFewOrTooMany)
                    {
                        if (realtimeInstances.Length == 0)
                        {
                            Debug.LogWarning("RealtimeView: No instances of Realtime exist in the scene. Make sure to create an instance of Realtime otherwise this scene view will not work!");
                        }
                        else if (realtimeInstances.Length > 1)
                        {
                            Debug.LogWarning("RealtimeView: There are multiple instances of Realtime in the scene. If you plan to use this as a scene view, wire up a reference to Realtime manually under the Advanced Settings panel on the RealtimeView.");
                        }
                        didWarnAboutRealtimeInstancesBeingTooFewOrTooMany = true;
                    }
                }
            }

            // Add realtime components
            RealtimeComponent[] components = realtimeView.GetComponents <RealtimeComponent>();
            foreach (RealtimeComponent component in components)
            {
                AddComponentToViewListIfNeeded(realtimeView, component);
            }

            // Add to parent RealtimeView if this is a child view
            bool isRoot = AddChildViewToParentViewIfNeeded(realtimeView, realtimeViewSerializedObject);

            byte[] sceneViewUUID = GetSceneViewUUIDAsByteArray(sceneViewUUIDProperty);

            if (isRoot && !prefab)
            {
                // Root scene view

                // Make sure this root scene view exists in our map. If it does, verify the UUID is set properly.
                byte[] previouslyAssignedUUID;
                if (_rootSceneViewUUIDMap.TryGetValue(realtimeView, out previouslyAssignedUUID))
                {
                    // If previously assigned UUID doesn't match, reset it. This can happen when clicking Apply on a prefab.
                    // This is because the UUID gets stored on the prefab and cleared on the scene view because it inherits the value from the prefab.
                    // Then this script comes in and clears the UUID on the prefab, which then means the scene view will have no UUID because it's inheriting
                    // from the prefab. We'll detect that here and set it back on the scene view.
                    if (!previouslyAssignedUUID.SequenceEqual(sceneViewUUID))
                    {
                        // Reset scene view UUID
                        sceneViewUUID = SetSceneViewUUIDUsingByteArray(sceneViewUUIDProperty, previouslyAssignedUUID);
                    }
                }
                else
                {
                    // Set scene UUID if needed
                    if (sceneViewUUID == null || sceneViewUUID.Length == 0)
                    {
                        sceneViewUUID = SetSceneViewUUIDUsingByteArray(sceneViewUUIDProperty, Guid.NewGuid().ToByteArray());
                    }
                    else
                    {
                        // If this view doesn't exist in the UUID map, but it has a scene view UUID, it's possible it's been copy & pasted. Check the map to see if another scene view has the same UUID. If it does, reset it and log a warning.
                        foreach (KeyValuePair <RealtimeView, byte[]> viewUUIDPair in _rootSceneViewUUIDMap)
                        {
                            RealtimeView view     = viewUUIDPair.Key;
                            byte[]       viewUUID = viewUUIDPair.Value;
                            if (sceneViewUUID.SequenceEqual(viewUUID) && realtimeView != view && realtimeView.gameObject.scene == view.gameObject.scene)
                            {
                                // If we enter this block, it means there's already a realtime view with this UUID loaded, /and/ it exists in the same scene.
                                // As far as I know, the only way for that to happen is to copy & paste a root scene realtime view. In that case, I think it's ok to reset
                                // the UUID on the copy. And since the original is going to be the one that already exists in the map, that means this one is the copy.
                                // For root scene views that have the same UUID as a view in another scene, we'll log an error below. That can happen when a scene is saved
                                // as a copy, and the copy is additively loaded. In that case, we don't know which view the developer will want to keep so we log the error.
                                Debug.LogWarning("Realtime: Found a RealtimeView in scene with a duplicate UUID. Resetting the UUID on the copy.");
                                sceneViewUUID = SetSceneViewUUIDUsingByteArray(sceneViewUUIDProperty, Guid.NewGuid().ToByteArray());
                                break;
                            }
                        }
                    }

                    // Add to the map
                    _rootSceneViewUUIDMap[realtimeView] = sceneViewUUID;
                }
            }
            else
            {
                // Not root scene view

                // Clear scene UUID
                if (sceneViewUUID == null || sceneViewUUID.Length != 0)
                {
                    // Clear the UUID
                    sceneViewUUID = SetSceneViewUUIDUsingByteArray(sceneViewUUIDProperty, new byte[0]);

                    // Remove from map
                    _rootSceneViewUUIDMap.Remove(realtimeView);
                }
            }

            if (isRoot && prefab)
            {
                // Root prefab view

                // Set isRootPrefabView property
                if (!isRootPrefabViewProperty.boolValue)
                {
                    isRootPrefabViewProperty.boolValue = true;
                }
            }
            else
            {
                // Not root prefab view

                // Clear isRootPrefabView property
                if (isRootPrefabViewProperty.boolValue)
                {
                    isRootPrefabViewProperty.boolValue = false;
                }
            }

            realtimeViewSerializedObject.ApplyModifiedPropertiesWithoutUndo();
        }