/// <summary> /// Applies parameters saved in the serialized Material to a Unity Material /// </summary> /// <param name="injector"></param> /// <param name="component"></param> /// <returns></returns> public override bool Apply(Injector injector, UnityEngine.Object resource) { Material material = (Material)resource; // Find Texture2D resource in Store ResourceNode node = null; if (this.t != "null" && !injector.resourceStore.TryGet(this.t, typeof(Texture2D), out node)) { // If Texture2D resource that belongs to this Material is not found, then Unity component cannot be created return(false); } // Apply Material color if (material.HasProperty("_Color")) { material.color = this.c; } // Apply texture if (this.t != "null") { material.mainTextureOffset = this.o; material.mainTextureScale = this.s; material.mainTexture = (Texture2D)node.resource; } // Apply shader values Shader shader = Shader.Find(this.n); if (shader != null) { material.shader = shader; material.shaderKeywords = this.k; } return(true); }
/// <summary> /// Tries to find a Resource of correct name and type by priority /// 1) A matching tracked Resource from the store. /// 2) A matching Resource of the correct type from the Resources folder (if using existing resources is enabled). /// </summary> /// <param name="resourceName"></param> /// <param name="type"></param> /// <param name="node"></param> /// <returns>Returns true if a matching Resource was found.</returns> internal bool TryGet(string resourceName, Type type, out ResourceNode node) { // Check if ResourceStore contains Resource with name if (this.Contains(resourceName)) { // Get ResourceNode for resource with name ResourceNode resource = (ResourceNode)this[resourceName]; // Check if ResourceNode is of the correct type if (resource.resource != null && resource.resource.GetType() == type) { node = resource; return(true); } } // Should existing resources be preferred if (this.injector.configuration.EXISTINGRESOURCES) { // Try to load exsting resource UnityEngine.Object resource = Resources.Load("NetworkModel/" + resourceName, type); // Check if loading of resource failed if (resource != null) { // Create a new ResourceNode node = new ResourceNode(this.injector, resource, resourceName); Add(resourceName, node); return(true); } } // No ResourceNode found node = null; return(false); }
/// <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); } }