Exemplo n.º 1
0
        /// <summary>
        /// After the response is received from the server, unpacks serialized parameters into human-readable parameters
        /// </summary>
        public void OnAfterDeserialize()
        {
            this.messageType = this.type.Substring(0, 1);
            this.updateType  = this.type.Substring(1, 1);
            switch (type)
            {
            case Request.RESOURCE + Request.UPDATE:
                this.resourceType = Type.GetType(this.DecodeClass(string1[0]));
                this.resource     = (AbstractResource)JsonUtility.FromJson(this.string2[0], this.resourceType);
                break;

            case Request.OBJECT + Request.UPDATE:
                this.parent = this.string1[0];
                break;

            case Request.COMPONENT + Request.UPDATE:
                this.components = new List <AbstractComponent>();
                for (int i = 0; i < this.string1.Count && i < this.string2.Count; i++)
                {
                    Type type = Type.GetType(this.DecodeClass(this.string1[i]));
                    this.components.Add((AbstractComponent)JsonUtility.FromJson(this.string2[i], type));
                }
                break;

            case Request.COMPONENT + Request.DELETE:
                this.componentTypes = new List <Type>();
                foreach (string typeName in string1)
                {
                    this.componentTypes.Add(Type.GetType(this.DecodeClass(typeName)));
                }
                break;
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Create Request to update a specific Resource
        /// </summary>
        /// <param name="injector"></param>
        /// <param name="name"></param>
        /// <param name="resourceType"></param>
        /// <param name="resource"></param>
        /// <returns>Request</returns>
        internal static Request UpdateResource(Injector injector, string name, Type resourceType, AbstractResource resource)
        {
            Request request = new Request(injector, Request.RESOURCE, Request.UPDATE, name);

            request.resource     = resource;
            request.resourceType = resourceType;
            return(request);
        }
Exemplo n.º 3
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);
            }
        }