Beispiel #1
0
        /// <summary>
        /// Explicitly delete Component from Gameobject and remove it from tracked store.
        /// </summary>
        /// <param name="name">Name of containing gameobject</param>
        /// <param name="type">Type of component to remove</param>
        private void DeleteComponents(Request request)
        {
            ObjectNode node;

            if (this.injector.objectStore.TryGetValue(request.name, out node))
            {
                foreach (Type t in request.componentTypes)
                {
                    Type type = this.injector.serializer.ToCommonType(t);
                    if (type != null)
                    {
                        // If component is not allowed to receive update, then drop request
                        if (!RuleUtility.FindComponentRule(this.injector, node.gameObject, type, UpdateType.RECEIVE))
                        {
                            continue;
                        }

                        // Remove component
                        Component component = node.gameObject.GetComponent(type);
                        node.RemoveComponent(this.injector.serializer.ToCommonType(type));
                        Destroy(component);
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Update components in GameObject, creating them if necessary.
        /// </summary>
        /// <param name="request"></param>
        private void UpdateComponents(Request request)
        {
            // Find a node of the correct gameobject for the request to use, creating it if it doesn't exist yet.
            ObjectNode node = this.injector.objectStore.GetOrCreate(request.name);

            // Update the components
            foreach (AbstractComponent serializedComponent in request.components)
            {
                // Get component type
                Type type = this.injector.serializer.GetCommonType(serializedComponent);

                // Check if type is not null
                if (type != null)
                {
                    // If component is not allowed to receive update, then drop request
                    if (!RuleUtility.FindComponentRule(this.injector, node.gameObject, type, UpdateType.RECEIVE))
                    {
                        continue;
                    }

                    // Get or create the component
                    Component component = node.GetOrCreateComponent(type);

                    // Try to apply updates; if successful, request is fulfilled
                    if (serializedComponent.Apply(this.injector, component))
                    {
                        node.UpdateComponent(type);
                        LogUtility.Log(this.injector, LogType.INFORMATION, "Component " + type + " update sucessful");
                        continue;
                    }

                    // Component creation could not add values in this update

                    // Create Request to try in a later update
                    Request newRequest = Request.UpdateComponents(this.injector, request.name, new List <AbstractComponent>()
                    {
                        serializedComponent
                    });
                    newRequest.channel = request.channel; // Save channel information

                    // If this request was handled less times than allowed, then try in an later update loop
                    if (request.iteration < Model.ATTEMPTS_TO_UPDATE)
                    {
                        // Integrate the iterations of the old request
                        newRequest.iteration = request.iteration + 1;
                        nextRequestQueue.Enqueue(newRequest);
                        LogUtility.Log(this.injector, LogType.INFORMATION, "Component " + type + " update unsucessful because missing references");
                    }
                    // Else, report failed resource update
                    else
                    {
                        LogUtility.Log(this.injector, LogType.WARNING, "Request to update component " + type + " for " + request.name + " dropped");
                    }
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Update content of Resource, creating it if necessary.
        /// </summary>
        /// <param name="request"></param>
        private void UpdateResource(Request request)
        {
            // Get Unity Type of Resource
            Type commonType = this.injector.serializer.ToCommonType(request.resourceType);

            // If resource is not allowed to receive update, then drop request
            if (!RuleUtility.FindResourceRule(this.injector, commonType, UpdateType.RECEIVE))
            {
                return;
            }

            ResourceNode node;

            if (this.injector.resourceStore.TryGet(request.name, commonType, out node))
            {
                // If Resource exists, try to apply updates. If successful, request is fulfilled.
                if (request.resource.Apply(this.injector, node.resource))
                {
                    node.UpdateHash();
                    LogUtility.Log(this.injector, LogType.INFORMATION, "Resource update sucessful");
                    return;
                }
            }
            else
            {
                // If Resource does not exist, create it
                UnityEngine.Object resource = request.resource.Construct();
                resource.name = request.name;

                // Try to apply updates; if successful, request is fulfilled
                if (request.resource.Apply(this.injector, resource))
                {
                    node = this.injector.resourceStore.Add(request.name, resource);
                    node.UpdateHash();
                    LogUtility.Log(this.injector, LogType.INFORMATION, "Resource " + commonType + " update sucessful");
                    return;
                }
            }

            // Resource creation was not successful in this update

            // If this request was handled less times than allowed, then try in an later update loop
            if (request.iteration < Model.ATTEMPTS_TO_UPDATE)
            {
                request.iteration++;
                nextRequestQueue.Enqueue(request);
                LogUtility.Log(this.injector, LogType.INFORMATION, "Resource  " + commonType + " update unsucessful because of missing references");
            }
            // Else, report failed resource update
            else
            {
                LogUtility.Log(this.injector, LogType.WARNING, "Request to update resource " + commonType + " for " + request.name + " dropped");
            }
        }
Beispiel #4
0
        /// <summary>
        /// Compress an array of Vector3
        /// </summary>
        /// <param name="gameObject"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        internal static Vector3[] Compress(GameObject gameObject, Vector3[] value)
        {
            int places = RuleUtility.FindDecimalPlaces(gameObject);

            Vector3[] result = new Vector3[value.Length];

            for (int i = 0; i < value.Length && i < result.Length; i++)
            {
                result[i] = Compress(places, value[i]);
            }

            return(result);
        }
Beispiel #5
0
        /// <summary>
        /// Remove Resource from tracked store. Will only be garbage-collected if no other resource uses it.
        /// </summary>
        /// <param name="request"></param>
        private void DeleteResource(Request request)
        {
            // Get Unity Type of Resource
            Type commonType = this.injector.serializer.ToCommonType(request.resourceType);

            // If resource is not allowed to receive update, then drop request
            if (!RuleUtility.FindResourceRule(this.injector, commonType, UpdateType.RECEIVE))
            {
                return;
            }

            // If ResourceStore contains Resource, then remove it
            if (this.injector.resourceStore.Contains(name))
            {
                this.injector.resourceStore.Remove(name);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Check synchronized part of scene for changes in GameObjects, Components or Resources.
        /// </summary>
        internal void TrackChanges()
        {
            // Create lists of resources and components that have pending requests
            List <NameTypePair> blockedResources  = new List <NameTypePair>();
            List <NameTypePair> blockedComponents = new List <NameTypePair>();

            // Check pending requests for components and resources
            foreach (Request request in requestQueue.ToArray())
            {
                switch (request.messageType)
                {
                // Check if request is pending for resource
                case Request.RESOURCE:
                    if (request.resource != null)
                    {
                        blockedResources.Add(new NameTypePair(request.name, request.resource.commonType));
                    }
                    else if (request.resourceType != null)
                    {
                        blockedResources.Add(new NameTypePair(request.name, request.resourceType));
                    }
                    break;

                // Check if request is pending for component
                case Request.COMPONENT:
                    if (request.components != null)
                    {
                        // Component requests can contain multiple components
                        foreach (AbstractComponent component in request.components)
                        {
                            blockedComponents.Add(new NameTypePair(request.name, component.commonType));
                        }
                    }
                    else if (request.componentTypes != null)
                    {
                        // Component requests can contain multiple components
                        foreach (Type type in request.componentTypes)
                        {
                            blockedComponents.Add(new NameTypePair(request.name, type));
                        }
                    }
                    break;
                }
            }

            // Add untracked GameObjects to ObjectStore as Objects without Components
            foreach (Transform transform in this.gameObject.GetComponentsInChildren <Transform>())
            {
                // Make sure that GameObject with NetworkModel attached does not get synced to Server
                if (transform != this.gameObject.transform)
                {
                    // Get existing reference or create a unique reference for GameObject
                    transform.gameObject.name = this.injector.objectStore.GetReferenceName(transform.gameObject);

                    // Check if GameObject is already in ObjectStore
                    if (!this.injector.objectStore.ContainsKey(transform.gameObject.name))
                    {
                        this.injector.objectStore.Add(transform.gameObject);
                    }
                }
            }

            // List of GameObjects that have been deleted on this client
            List <string> objectsToDelete = new List <string>();

            // Iterate over GameObject Store
            foreach (KeyValuePair <string, ObjectNode> objectEntry in this.injector.objectStore)
            {
                // Never synchronize the root gameobject containing the NetworkModel
                string referenceName = objectEntry.Key;
                if (referenceName == Model.ROOT_NAME)
                {
                    continue;
                }

                // If Element does not exist anymore (or the name was changed), then add it to the list to schedule the deletion
                // (When changing the name of a GameObject, the ObjectNode of that GameOBject gets destroyed and a new ObjectNode is created)
                ObjectNode node = objectEntry.Value;
                if (node.gameObject == null || node.gameObject.name != referenceName)
                {
                    objectsToDelete.Add(referenceName);
                }

                // Else, check for changes in hierarchy and components
                else
                {
                    // Check if parent of gameObject has changed compared to last known state
                    if (node.gameObject.transform.parent.GetInstanceID() != node.parentID)
                    {
                        // Send updated parent information to server
                        this.injector.connection.SendRequest(Request.UpdateObject(this.injector, node.gameObject));
                        node.gameObject.transform.hasChanged = false;
                    }

                    // Update Node with current values from represented GameObject
                    node.Update();

                    // List of Components that have been deleted on this client
                    List <Type> deletedComponents = new List <Type>();
                    // List of Components that have been deleted and inform the server about it
                    List <Type> sendDeletedComponents = new List <Type>();

                    // List of Components that have been changed on this client
                    List <AbstractComponent> updatedComponents = new List <AbstractComponent>();
                    // List of Components that have been changed and inform the server about it
                    List <AbstractComponent> sendUpdatedComponents = new List <AbstractComponent>();

                    // Iterate over tracked components of the node
                    foreach (KeyValuePair <Type, long> hashEntry in node.hashes)
                    {
                        // If component is blocked from tracking changes, then continue with next component
                        if (blockedComponents.Contains(new NameTypePair(node.gameObject.name, hashEntry.Key)))
                        {
                            LogUtility.Log(this.injector, LogType.INFORMATION, "Component " + hashEntry.Key + " update blocked");
                            continue;
                        }

                        // Get the component which is pointed at in this loop
                        Component component = node.gameObject.GetComponent(hashEntry.Key);

                        // If component is allowed to send, then track changes
                        bool send = RuleUtility.FindComponentRule(this.injector, node.gameObject, component.GetType(), UpdateType.SEND);

                        // If Component does not exist anymore, then schedule it for deletion
                        if (component == null)
                        {
                            // Delete references to component on client
                            Type type = this.injector.serializer.ToSerializableType(hashEntry.Key);
                            deletedComponents.Add(type);

                            // Inform the server about the change
                            if (send)
                            {
                                sendDeletedComponents.Add(type);
                            }

                            continue;
                        }

                        // Transform UnityEngine Component to NetworkModel AbstractComponent
                        AbstractComponent serializedComponent = this.injector.serializer.ToSerializableComponent(component);

                        // If Component does not exist as a serializable Component
                        if (serializedComponent == null)
                        {
                            continue;
                        }

                        // Generate hash of component and compare it to the previously stored value; if not equal, then add it to update list
                        if (serializedComponent.GetHash() != hashEntry.Value)
                        {
                            // Update hash stored for component on client
                            updatedComponents.Add(serializedComponent);

                            // Inform the server about the change
                            if (send)
                            {
                                sendUpdatedComponents.Add(serializedComponent);
                            }
                        }
                    }

                    // Components scheduled for Delete
                    foreach (Type type in deletedComponents)
                    {
                        node.RemoveComponent(this.injector.serializer.ToCommonType(type));
                    }

                    // Components scheduled for Update
                    foreach (AbstractComponent component in updatedComponents)
                    {
                        node.UpdateComponent(component.commonType);
                    }

                    // Check if there are deleted components the server needs to be informed about
                    if (sendDeletedComponents.Count > 0)
                    {
                        this.injector.connection.SendRequest(Request.DeleteComponents(this.injector, referenceName, sendDeletedComponents));
                    }

                    // Check if there are updated components the server needs to be informed about
                    if (sendUpdatedComponents.Count > 0)
                    {
                        this.injector.connection.SendRequest(Request.UpdateComponents(this.injector, referenceName, sendUpdatedComponents));
                        node.gameObject.transform.hasChanged = false;
                    }
                }
            }

            // Delete scheduled GameObjects and send Delete Request
            foreach (string referenceName in objectsToDelete)
            {
                this.injector.objectStore.Remove(referenceName);
                this.injector.connection.SendRequest(Request.DeleteObject(this.injector, referenceName));
            }

            // List of Resources that have been deleted on this client
            List <string> resourcesToDelete = new List <string>();

            // Iterate over Resource Store
            for (int i = 0; i < this.injector.resourceStore.Count; i++)
            {
                // Get the resource which is pointed at in this loop
                ResourceNode node         = (ResourceNode)this.injector.resourceStore[i];
                string       resourceName = node.name;

                // If resource name is null, then check next resource
                if (resourceName == "null")
                {
                    continue;
                }

                // If resource is blocked from tracking changes, then continue with next resource
                if (blockedResources.Contains(new NameTypePair(resourceName, node.type)))
                {
                    LogUtility.Log(this.injector, LogType.INFORMATION, "Resource " + node.type + " update blocked");
                    continue;
                }

                // If resource is allowed to send, then track changes
                bool send = RuleUtility.FindResourceRule(this.injector, node.type, UpdateType.SEND);

                // If Element does not exist anymore, then schedule it for deletion
                if (node.resource == null || node.resource.name != resourceName || node.resource.GetType() != node.type)
                {
                    // Delete references to resource on client
                    resourcesToDelete.Add(resourceName);

                    // Inform the server about the change
                    if (send)
                    {
                        this.injector.connection.SendRequest(Request.DeleteResource(this.injector, resourceName));
                    }
                }
                // Else, check for changes
                else
                {
                    // Transform UnityEngine Resource to NetworkModel AbstractResource
                    AbstractResource serializedResource = this.injector.serializer.ToSerializableResource(node.resource);
                    if (serializedResource.GetHash() != node.hash)
                    {
                        // Inform the server about the change
                        if (send)
                        {
                            this.injector.connection.SendRequest(Request.UpdateResource(this.injector, resourceName,
                                                                                        this.injector.serializer.ToSerializableType(node.type), serializedResource));
                        }

                        // Update hash stored for resource on client
                        node.UpdateHash();
                    }
                }
            }

            // Delete resources scheduled for deleting from ResourceStore
            foreach (string resourceName in resourcesToDelete)
            {
                this.injector.resourceStore.Remove(resourceName);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Compress a Vector3
        /// </summary>
        /// <param name="gameObject"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        internal static Vector3 Compress(GameObject gameObject, Vector3 value)
        {
            int places = RuleUtility.FindDecimalPlaces(gameObject);

            return(Compress(places, value));
        }