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);
        }
        public RealtimeViewModel _CreateRootSceneViewModel()
        {
            if (!isRootSceneView)
            {
                Debug.LogError("RealtimeView: Asked to create root scene view model for view that's not a root scene view. This is a bug!");
            }

            // Create components model
            Dictionary <int, Tuple <Component, MethodInfo, PropertyInfo, PropertyInfo> > componentMap = CreateComponentMap();
            RealtimeViewComponentsModel componentsModel = CreateComponentsModel(componentMap);

            // Create child views model
            Dictionary <int, RealtimeView> childViewsMap   = CreateChildViewMap();
            RealtimeViewComponentsModel    childViewsModel = CreateChildViewsModel(childViewsMap);

            // Ownership / lifetime flags
            int  ownerID       = _sceneViewOwnedByCreatingClient ? _realtime.clientID : -1;
            uint lifetimeFlags = 0;

            if (_sceneViewPreventOwnershipTakeover)
            {
                lifetimeFlags |= (uint)MetaModel.LifetimeFlags.PreventOwnershipTakeover;
            }

            if (_sceneViewDestroyWhenOwnerOrLastClientLeaves)
            {
                lifetimeFlags |= (uint)MetaModel.LifetimeFlags.DestroyWhenOwnerOrLastClientLeaves;
            }

            // Create RealtimeViewModel
            RealtimeViewModel viewModel = new RealtimeViewModel(_sceneViewUUID, ownerID, lifetimeFlags, componentsModel, childViewsModel);

            return(viewModel);
        }
        // Prefab Child Realtime View
        public RealtimeViewModel(RealtimeViewComponentsModel componentsModel, RealtimeViewComponentsModel childViewsModel)
        {
            _metaModel = new MetaModel();

            _componentsModel = componentsModel;
            _childViewsModel = childViewsModel;
        }
        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 CreateComponentsModel(Dictionary <int, Tuple <Component, MethodInfo, PropertyInfo, PropertyInfo> > componentMap)
        {
            // Create models for all components
            Dictionary <int, IModel> componentModelMap = new Dictionary <int, IModel>();

            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;

                // Create model
                object componentModelObject = null;
                if (createModelMethod != null)
                {
                    componentModelObject = createModelMethod.Invoke(null, null);
                    if (componentModelObject == null)
                    {
                        Debug.LogError("Model supplied by MonoBehaviour's CreateModel method is null. Skipping component: (" + componentID + ":" + component + ")", component);
                        continue;
                    }
                }
                else
                {
                    // Create it using the type from the model property.
                    Type modelType = modelProperty.PropertyType;

                    try {
                        componentModelObject = Activator.CreateInstance(modelType);
                    } catch (MissingMethodException) {
                        Debug.LogError("MonoBehaviour doesn't have CreateModel method, and model type (" + modelType + ") doesn't have a public default constructor. Skipping component: (" + componentID + ":" + component + ")", component);
                        continue;
                    } catch (Exception exception) {
                        Debug.LogError("MonoBehaviour doesn't have CreateModel method, and Realtime was unable to create a model instance. Skipping component: (" + componentID + ":" + component + ") (" + exception + ")", component);
                        continue;
                    }
                }

                // Verify model implements IModel
                IModel componentModel = componentModelObject as IModel;
                if (componentModel == null)
                {
                    Debug.LogError("Model created by MonoBehaviour (" + componentModelObject.GetType() + ") doesn't implement IModel interface. Skipping component: (" + componentID + ":" + component + ")", component);
                    continue;
                }

                // Set model
                componentModelMap[componentID] = componentModel;
            }

            // Create RealtimeViewComponentsModel
            RealtimeViewComponentsModel componentsModel = new RealtimeViewComponentsModel(componentModelMap);

            return(componentsModel);
        }
        // Prefab Realtime View
        public RealtimeViewModel(string prefabName, int ownerID, uint lifetimeFlags, RealtimeViewComponentsModel componentsModel, RealtimeViewComponentsModel childViewsModel)
        {
            _prefabName = prefabName;

            _metaModel               = new MetaModel();
            _metaModel.ownerID       = ownerID;
            _metaModel.lifetimeFlags = lifetimeFlags;

            _componentsModel = componentsModel;
            _childViewsModel = childViewsModel;
        }
        // Scene Realtime View
        public RealtimeViewModel(byte[] sceneViewUUID, int ownerID, uint lifetimeFlags, RealtimeViewComponentsModel componentsModel, RealtimeViewComponentsModel childViewsModel)
        {
            _sceneViewUUID = sceneViewUUID;

            _metaModel               = new MetaModel();
            _metaModel.ownerID       = ownerID;
            _metaModel.lifetimeFlags = lifetimeFlags;

            _componentsModel = componentsModel;
            _childViewsModel = childViewsModel;
        }
        public void SetChildViewsModelAndDeserializeCachedModelsIfNeeded(RealtimeViewComponentsModel childViewsModel)
        {
            if (_childViewsModel != null)
            {
                Debug.LogError("Attempting to deserialize cached child views model on RealtimeViewModel that already has a child views model. This is a bug!");
                return;
            }
            _childViewsModel = childViewsModel;

            DeserializeCachedChildViewsModelIfNeeded();
        }
        public RealtimeViewModel _CreateChildViewModel()
        {
            if (!isChildView)
            {
                Debug.LogError("RealtimeView: Asked to create child view model for view that's not a child view. This is a bug!");
            }

            // Create components model
            Dictionary <int, Tuple <Component, MethodInfo, PropertyInfo, PropertyInfo> > componentMap = CreateComponentMap();
            RealtimeViewComponentsModel componentsModel = CreateComponentsModel(componentMap);

            // Create child views model
            Dictionary <int, RealtimeView> childViewsMap   = CreateChildViewMap();
            RealtimeViewComponentsModel    childViewsModel = CreateChildViewsModel(childViewsMap);

            // Create RealtimeViewModel
            RealtimeViewModel viewModel = new RealtimeViewModel(componentsModel, childViewsModel);

            return(viewModel);
        }
        public RealtimeViewModel _CreateRootPrefabViewModel(string prefabName, int ownerID, uint lifetimeFlags)
        {
            if (!isRootPrefabView)
            {
                Debug.LogError("RealtimeView: Asked to create root prefab view model for view that's not on the root of a prefab. This is a bug!");
            }

            // Create components model
            Dictionary <int, Tuple <Component, MethodInfo, PropertyInfo, PropertyInfo> > componentMap = CreateComponentMap();
            RealtimeViewComponentsModel componentsModel = CreateComponentsModel(componentMap);

            // Create child views model
            Dictionary <int, RealtimeView> childViewsMap   = CreateChildViewMap();
            RealtimeViewComponentsModel    childViewsModel = CreateChildViewsModel(childViewsMap);

            // Create RealtimeViewModel
            RealtimeViewModel viewModel = new RealtimeViewModel(prefabName, ownerID, lifetimeFlags, componentsModel, childViewsModel);

            return(viewModel);
        }
        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;
                }
            }
        }