// Takes a string of the form "{type} {index}" like "UnityEngine.Rigidbody 1" public static Component GetComponentWithIndex(this GameObject obj, string type) { // Try to get an index if we provided one int split = type.IndexOf(' '); int index = 0; if (split != -1) { int.TryParse(type.Substring(split + 1), out index); } // Then get the component with that index Component[] components = obj.GetComponents(TTReferences.GetType(type)); if (components.Length > index) { return(components[index]); } if (components.Length != 0) { return(components[0]); } return(null); }
// TTQMM Ref: JsonToGameObject.CreateGameObject_Internal(JObject json, GameObject GameObjectToPopulate, string Spacing, Component instantiated = null, Type instantiatedType = null) private static GameObject DeserializeIntoGameObject_Internal(JObject jObject, GameObject target) { // Ensure we have a target object if (target == null) { target = new GameObject("Deserialized Object"); } // Then read each JSON property and act accordingly foreach (JProperty jProperty in jObject.Properties()) { string[] split = jProperty.Name.Split('|'); if (split.Length == 1) // "ModuleVision", "UnityEngine.Transform" etc. { Debug.Log($"[Nuterra] Deserializer adding component {split[0]}"); // Format will be "{ComponentType} {Index}" where the index specifies the child index if there are multiple targets string typeNameAndIndex = split[0]; string typeName = typeNameAndIndex.Split(' ')[0]; Type type = TTReferences.GetType(typeName); if (type != null) { Debug.Log($"[Nuterra] Deserializer ready to find or create instance of type {type}"); // See if we have an existing component Component component = target.GetComponentWithIndex(typeNameAndIndex); // A null JSON token means we should delete this object if (jProperty.Value.Type == JTokenType.Null) { if (component != null) { Component.DestroyImmediate(component); } else { Debug.LogError($"[Nuterra] Could not find component of type {typeNameAndIndex} to destroy"); } } else // We have some data, let's process it { // If we couldn't find the component, make a new one if (component == null) { component = target.gameObject.AddComponent(type); } // If we still can't find one, get it. This should like never happen, right? if (component == null) { Debug.LogError($"[Nuterra] Failed to find {typeNameAndIndex}, failed to AddComponent, but trying GetComponent"); component = target.gameObject.GetComponent(type); } // If we still don't have one, exit if (component == null) { Debug.LogError($"[Nuterra] Could not find component {typeNameAndIndex}"); continue; } // Now deserialize the JSON into the new Component DeserializeJSONObject(component, type, jProperty.Value as JObject); } } else { Debug.LogError($"[Nuterra] Could not find type {typeNameAndIndex}"); } } else if (split.Length == 2) // { GameObject childObject = null; string name = split[1]; switch (split[0]) { case "Reference": // Copy a child object or component from another prefab { Debug.Log($"[Nuterra] Deserializing Reference {name}"); if (TTReferences.GetReferenceFromBlockResource(name, out object reference)) { Debug.Log($"[Nuterra] Found reference {reference}"); if (reference is GameObject || reference is Transform) { // If the reference was to a GameObject or a Transform, then we just want to copy that whole object GameObject referenceObject = reference is GameObject ? (GameObject)reference : ((Transform)reference).gameObject; childObject = GameObject.Instantiate(referenceObject); string newName = name.Substring(1 + name.LastIndexOfAny(new char[] { '/', '.' })); int count = 1; while (target.transform.Find(newName)) { newName = $"{name}_{++count}"; } childObject.name = newName; childObject.transform.SetParent(target.transform); childObject.transform.localPosition = referenceObject.transform.localPosition; childObject.transform.localRotation = referenceObject.transform.localRotation; childObject.transform.localScale = referenceObject.transform.localScale; } else if (reference is Component) { // If we referenced a Component, we want to place a copy of that component on our target // However, if we already have a Component of the same type, we most likely want to override its values. // This functionality is as per TTQMM Type type = reference.GetType(); Component existingComponent = target.GetComponent(type); if (existingComponent == null) { existingComponent = target.AddComponent(type); } // Copy the reference and then deserialize our JSON into it ShallowCopy(type, reference, existingComponent, false); DeserializeJSONObject(existingComponent, type, jProperty.Value as JObject); continue; } else { Debug.LogError($"[Nuterra] Unknown object {reference} found as reference"); continue; } } else { Debug.LogError($"[Nuterra] Could not find reference for {name} in deserialization"); continue; } break; } case "Duplicate": // Copy a child object from this prefab { Debug.Log($"[Nuterra] Deserializing Duplicate {name}"); if (name.Contains('/') || name.Contains('.')) { object foundObject = GetCurrentSearchTransform().RecursiveFindWithProperties(name); if (foundObject != null) { if (foundObject is Component foundComponent) { childObject = foundComponent.gameObject; } else if (foundObject is GameObject foundGameObject) { childObject = foundGameObject; } } } if (childObject == null) { childObject = target.transform.Find(name)?.gameObject; } break; } case "GameObject": // Create a new child object case "Instantiate": // Instantiate something default: { Debug.Log($"[Nuterra] Deserializing {split[0]}|{name}"); if (childObject == null) { childObject = target.transform.Find(name)?.gameObject; } break; } } // Fallback, just make an empty object if (childObject == null) { if (jProperty.Value.Type == JTokenType.Null) { Debug.Log($"[Nuterra] Deserializing failed to find {name} to delete"); continue; } else { childObject = new GameObject(name); childObject.transform.parent = target.transform; } } else { // If we've got no JSON data, that means we want to delete this target if (jProperty.Value.Type == JTokenType.Null) { GameObject.DestroyImmediate(childObject); childObject = null; continue; } else if (split[0] == "Duplicate") { childObject = GameObject.Instantiate(childObject); name = name.Substring(1 + name.LastIndexOfAny(new char[] { '/', '.' })); string newName = $"{name}_copy"; int count = 1; while (target.transform.Find(newName)) { newName = $"{name}_copy_{(++count)}"; } childObject.name = newName; childObject.transform.parent = target.transform; childObject.transform.localPosition = Vector3.zero; childObject.transform.localRotation = Quaternion.identity; childObject.transform.localScale = Vector3.one; } } Debug.Log($"[Nuterra] Deserializing jProp {jProperty.Name} --- {jProperty.Value}"); DeserializeIntoGameObject_Internal((JObject)jProperty.Value, childObject); } } return(target); }