using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEngine; using UnityEngine.Assertions; namespace SuperTiled2Unity.Editor { public static class GameObjectExtensions { public static float GetSuperPropertyValueFloat(this GameObject go, string propName, float defaultValue) { CustomProperty property; if (go.TryGetCustomPropertySafe(propName, out property)) { return property.GetValueAsFloat(); } return defaultValue; } public static int GetSuperPropertyValueInt(this GameObject go, string propName, int defaultValue) { CustomProperty property; if (go.TryGetCustomPropertySafe(propName, out property)) { return property.GetValueAsInt(); } return defaultValue; } public static bool GetSuperPropertyValueBool(this GameObject go, string propName, bool defaultValue) { CustomProperty property; if (go.TryGetCustomPropertySafe(propName, out property)) { return property.GetValueAsBool(); } return defaultValue; } public static Color GetSuperPropertyValueColor(this GameObject go, string propName, Color defaultValue) { CustomProperty property; if (go.TryGetCustomPropertySafe(propName, out property)) { return property.GetValueAsColor(); } return defaultValue; } public static T GetSuperPropertyValueEnum(this GameObject go, string propName, T defaultValue) { CustomProperty property; if (go.TryGetCustomPropertySafe(propName, out property)) { return property.GetValueAsEnum(); } return defaultValue; } public static string GetSuperPropertyValueString(this GameObject go, string propName, string defaultValue) { CustomProperty property; if (go.TryGetCustomPropertySafe(propName, out property)) { return property.GetValueAsString(); } return defaultValue; } public static void AddChildWithUniqueName(this GameObject go, GameObject child) { if (go == null) { return; } // Make sure the child name is unqiue string name = child.name; int count = 0; while (go.transform.Find(name) != null) { name = string.Format("{0} ({1})", child.name, ++count); } child.name = name; child.transform.SetParent(go.transform, false); } // Creates a new object, attached to the parent, with a specialized layer component public static T AddSuperLayerGameObject(this GameObject goParent, SuperLayerLoader loader, SuperImportContext importContext) where T : SuperLayer { GameObject goLayer = new GameObject(); // Read in the fields common across our Tiled layer types var layerComponent = loader.CreateLayer(goLayer) as T; Assert.IsNotNull(layerComponent); // Add the object to the parent goLayer.name = layerComponent.m_TiledName; goParent.AddChildWithUniqueName(goLayer); return layerComponent; } // Assing the layers on all children to our layer public static void AssignChildLayers(this GameObject goParent) { foreach (Transform child in goParent.transform) { child.ChangeLayersRecursively(goParent.layer); } } private static void ChangeLayersRecursively(this Transform trans, int layer) { trans.gameObject.layer = layer; foreach (Transform child in trans) { child.ChangeLayersRecursively(layer); } } public static void BroadcastProperty(this GameObject go, CustomProperty property, Dictionary objectsById) { object objValue; if (property.m_Type == "bool") { objValue = property.GetValueAsBool(); } else if (property.m_Type == "color") { objValue = property.GetValueAsColor(); } else if (property.m_Type == "float") { objValue = property.GetValueAsFloat(); } else if (property.m_Type == "int") { objValue = property.GetValueAsInt(); } else if (property.m_Type == "object") { var objectId = property.GetValueAsInt(); GameObject gameObject; if (!objectsById.TryGetValue(objectId, out gameObject)) { Debug.LogErrorFormat("Object property refers to invalid ID {0}", objectId); return; } else { objValue = gameObject; } } else { objValue = property.GetValueAsString(); } // Use properties on all types in hierary that inherit from MonoBehaviour var components = go.GetComponentsInChildren(); foreach (var comp in components) { // Look for methods first var method = FindMethodBySignature(comp, property.m_Name, objValue.GetType()); if (method != null) { method.Invoke(comp, new object[1] { objValue }); continue; } // Then properties var csprop = FindPropertyBySignature(comp, property.m_Name, objValue.GetType()); if (csprop != null) { csprop.SetValue(comp, objValue, null); continue; } // Finally, look for public fields var csfield = FindFieldBySignature(comp, property.m_Name, objValue.GetType()); if (csfield != null) { csfield.SetValue(comp, objValue); continue; } } } private static MethodInfo FindMethodBySignature(MonoBehaviour component, string name, Type paramType) { return component.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(info => { // Name must match if (info.Name != name) { return false; } // Return type must be void if (info.ReturnType != typeof(void)) { return false; } // Must have one parameter that matches param type var parameters = info.GetParameters(); if (parameters.Length != 1) { return false; } // Parameter type must match if (parameters[0].ParameterType != paramType) { return false; } return true; }).FirstOrDefault(); } private static PropertyInfo FindPropertyBySignature(MonoBehaviour component, string name, Type valueType) { // Property must be public and instanced and writable return component.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where( info => info.CanWrite && info.Name == name && info.PropertyType == valueType ).FirstOrDefault(); } private static FieldInfo FindFieldBySignature(MonoBehaviour component, string name, Type valueType) { return component.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public).Where( info => !info.IsInitOnly && info.Name == name && info.FieldType == valueType ).FirstOrDefault(); } } }