/// <summary> /// Finds a list of memberinfo objects that form a property path. Returns null if no matching path could be found. /// </summary> public static MemberInfo[] FindPropertyPath(Type startingPoint, string propertyPath) { string key = startingPoint.FullName + ":" + propertyPath; if (propertyPathCache.ContainsKey(key)) { return(propertyPathCache [key]); } string[] propertyNames = propertyPath.Split('.'); var referenceType = startingPoint; MemberInfo[] result = new MemberInfo[propertyNames.Length]; int index = 0; foreach (var propertyName in propertyNames) { var matches = referenceType.GetMember(propertyName, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance); if (matches.Length == 1) { result[index] = matches[0]; referenceType = UTInternalCall.GetMemberType(matches[0]); } else { result = null; break; } index++; } propertyPathCache.Add(key, result); return(result); }
/// <summary> /// Finds the components annotated with the given annotations. Components are instanciated and returned as keys /// of the result dictionary. The values of the result dictionary contain the respective annotations which identified /// the components. /// </summary> /// <returns> /// The components annotated with the given annotation type. /// </returns> /// <typeparam name='ExpectedType'> /// The expected type of the components. /// </typeparam> /// <typeparam name='AnnotationType'> /// The annotation identifying the components. /// </typeparam> public static Dictionary <ExpectedType, AnnotationType> FindComponentsAnnotatedWith <ExpectedType, AnnotationType> () { Dictionary <ExpectedType, AnnotationType> result = new Dictionary <ExpectedType, AnnotationType> (); var referencedAssemblies = (Assembly[])UTInternalCall.GetStatic("UnityEditor.EditorAssemblies", "loadedAssemblies"); foreach (var referencedAssembly in referencedAssemblies) { var allTypes = referencedAssembly.GetTypes(); foreach (var theType in allTypes) { var attrs = theType.GetCustomAttributes(typeof(AnnotationType), false); if (attrs.Length == 1) { if (!theType.IsSubclassOf(typeof(ExpectedType)) && theType.GetInterface(typeof(ExpectedType).Name) == null) { Debug.LogWarning("Class " + theType.FullName + " is not a subclass/implementation of " + typeof(ExpectedType).FullName + ". Ignoring it."); continue; } ExpectedType theInstance = (ExpectedType)Activator.CreateInstance(theType); result.Add(theInstance, (AnnotationType)attrs [0]); } } } return(result); }
/// <summary> /// Finds all visible assets of the given type. /// </summary> public static List <T> AllVisibleAssetsOfType <T> () where T : ScriptableObject { List <T> result = new List <T> (); object filteredHierarchy = CreateFilteredHierarchy(); #if UNITY_3_5 UTInternalCall.Set(filteredHierarchy, "filter", typeof(T).Name); UTInternalCall.Set(filteredHierarchy, "searchMode", UTInternalCall.EnumValue("UnityEditor.FilteredHierarchy+SearchMode", "Type")); #else var searchFilter = UTInternalCall.InvokeStatic("UnityEditor.SearchableEditorWindow", "CreateFilter", typeof(T).Name, UTInternalCall.EnumValue("UnityEditor.SearchableEditorWindow+SearchMode", "Type")); UTInternalCall.Set(filteredHierarchy, "searchFilter", searchFilter); #endif var hierarchyProperty = UTInternalCall.InvokeStatic("UnityEditor.FilteredHierarchyProperty", "CreateHierarchyPropertyForFilter", filteredHierarchy); var emptyIntArray = new int[0]; while ((bool)UTInternalCall.Invoke(hierarchyProperty, "Next", emptyIntArray)) { var instanceId = (int)UTInternalCall.Get(hierarchyProperty, "instanceID"); var path = AssetDatabase.GetAssetPath(instanceId); T t = AssetDatabase.LoadAssetAtPath(path, typeof(T)) as T; if (t != null) { result.Add(t); } } return(result); }
private void BuildMenu(GenericMenu menu, Type type, string itemVisiblePath, string itemInternalPath, bool addSelf, int depth, GenericMenu.MenuFunction2 function) { if (addSelf) { menu.AddItem(new GUIContent(itemVisiblePath + "/" + type.Name), false, function, itemInternalPath); } var members = UTComponentScanner.FindPublicWritableMembersOf(type); foreach (var memberInfo in members.MemberInfos) { var newInternalPath = string.IsNullOrEmpty(itemInternalPath) ? memberInfo.Name : itemInternalPath + "." + memberInfo.Name; var newVisiblePath = string.IsNullOrEmpty(itemVisiblePath) ? memberInfo.Name : itemVisiblePath + "/" + memberInfo.Name; if (memberInfo.DeclaringType != typeof(Component)) { var memberInfoType = UTInternalCall.GetMemberType(memberInfo); if (UTInternalCall.HasMembers(memberInfoType) && depth < 2) { BuildMenu(menu, memberInfoType, newVisiblePath, newInternalPath, UTInternalCall.IsWritable(memberInfo), depth + 1, function); } else { menu.AddItem(new GUIContent(newVisiblePath), false, function, newInternalPath); } } } }
public void Render(UTFieldWrapper fieldWrapper) { Type baseType = fieldWrapper.InspectorHint.baseType; var compatibleTypes = UTComponentScanner.FindCompatibleTypes(baseType); var val = (UTMemberInfo)fieldWrapper.Value; int currentIndex = -1; if (val != null) { currentIndex = Array.IndexOf(compatibleTypes.TypeNames, val.TypeName); } EditorGUILayout.BeginVertical(); int newIndex = -1; if (fieldWrapper.Label != null) { newIndex = EditorGUILayout.Popup(fieldWrapper.Label, currentIndex, compatibleTypes.NicifiedTypeNames); } else { newIndex = EditorGUILayout.Popup(currentIndex, compatibleTypes.NicifiedTypeNames); } if (currentIndex != newIndex) { if (newIndex == -1) { fieldWrapper.Value = null; val = null; } else { var type = UTInternalCall.GetType(compatibleTypes.TypeNames [newIndex]); var writableMembers = UTComponentScanner.FindPublicWritableMembersOf(type); string propertyPath = null; if (writableMembers.MemberInfos.Length > 0) { propertyPath = writableMembers.MemberInfos[0].Name; } val = new UTMemberInfo(type.FullName, propertyPath); fieldWrapper.Value = val; } } GUI.enabled = val != null && !string.IsNullOrEmpty(val.TypeName); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); if (GUILayout.Button(val.FieldPath, EditorStyles.popup)) { var genericMenu = BuildMenu(val.Type, val.SetFieldPath); genericMenu.ShowAsContext(); } EditorGUILayout.EndHorizontal(); GUI.enabled = true; EditorGUILayout.EndVertical(); }
private static object CreateFilteredHierarchy() { if (filteredHierarchy == null) { filteredHierarchy = UTInternalCall.CreateInstance("UnityEditor.FilteredHierarchy", HierarchyType.Assets); } UTInternalCall.Invoke(filteredHierarchy, "ResultsChanged"); return(filteredHierarchy); }
/// <summary> /// Evaluate the specified input and replaces all known placeholders. Placeholders can be written as /// $foo.bar or optionally $(foo.bar) in case the first notation is ambiguous. /// /// You can write arbitrary JavaScript expressions like: /// /// 2 + 2 (yields 4) /// '2' + '2' (yields '22') /// '2' == '2' (yields true) /// etc.. /// /// Please note that properties can have different types and casting/transformation is not performed /// automatically. E.g. If the property "foo" has the value "2" (as a string) $foo * 2 will yield "22" /// because it is a string. If you want to have the numeric value use parseInt($foo) * 2 (will yield 4). /// /// </summary> /// <param name='input'> /// The input string. /// </param> public object Evaluate(string input) { var replaced = Regex.Replace(input, PlaceholderRegexp, "context['$1']"); try { // we call this via reflection because we cannot reference unityscript stuff directly return(UTInternalCall.InvokeStatic("UTEval", "Evaluate", replaced, this)); } catch (Exception e) { throw new UTFailBuildException("Unparseable expression: '" + input + "' " + e.Message, null); // no experiments. } }
public static void Init() { var window = EditorWindow.GetWindow <UTMainWindow> ( #if UTOMATE_DEMO "uTomate Demo", #else "uTomate", #endif UTInternalCall.GetType("UnityEditor.InspectorWindow")); window.minSize = new Vector2(400, 250); }
public static UTMemberListResult FindPublicWritableMembersOf(Type type) { if (memberListCache.ContainsKey(type)) { return(memberListCache [type]); } var allMembers = UTInternalCall.PublicMembersOf(type); UTMemberListResult result = new UTMemberListResult(Array.FindAll(allMembers, item => UTInternalCall.IsWritable(item))); memberListCache.Add(type, result); return(result); }
public override IEnumerator Execute(UTContext context) { UDebug.LogWarning("This action is experimental and might break.", this); bool connError = (bool)UTInternalCall.InvokeStatic("UnityEditor.AssetServer", "HasConnectionError"); if (connError) { throw new UTFailBuildException("Currently unable to connect to the asset server.", this); } UDebug.Log("Not working properly..."); throw new UTFailBuildException("Not implemented.", this); /* * UDebug.Log("Starting update..."); * Process process = new Process(); * process.StartInfo.FileName = GetEditorExecutable(); * process.StartInfo.Arguments = "-batchMode -assetServerUpdate " + string.Join(" ", new string[] {assetServerLocation, projectOnAssetServer, username, password}); * process.StartInfo.RedirectStandardOutput = true; * process.StartInfo.UseShellExecute = false; * process.OutputDataReceived += (sender, args) => UDebug.Log("[Unity]"+ args.Data); * try { * process.Start(); * process.BeginOutputReadLine(); * process.WaitForExit(); * if (process.ExitCode != 0) { * UDebug.LogError("Update failed."); * return false; * } * * } * catch(Win32Exception e) { * UDebug.LogError("Couldn't start process: " + e.Message); * return false; * } * return true;*/ }
public override UTVisibilityDecision IsVisible(System.Reflection.FieldInfo fieldInfo) { if (fieldInfo.Name == "gameObject" || fieldInfo.Name == "property") { return(base.IsVisible(fieldInfo)); } // only expression field if the type is not clear var self = (UTSetComponentPropertyAction)target; if (self.property.UseExpression || !self.property.Value.FullyDefined) { if (fieldInfo.Name == "objectPropertyValue") { return(UTVisibilityDecision.Visible); } return(UTVisibilityDecision.Invisible); } // only expression field if the property is not valid anymore var propertyPath = UTComponentScanner.FindPropertyPath(self.property.Value.Type, self.property.Value.FieldPath); if (propertyPath == null) { if (fieldInfo.Name == "objectPropertyValue") { return(UTVisibilityDecision.Visible); } return(UTVisibilityDecision.Invisible); } Type propertyType = UTInternalCall.GetMemberType(propertyPath[propertyPath.Length - 1]); string expectedPropertyFieldName = "objectPropertyValue"; if (typeof(string).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "stringPropertyValue"; } else if (typeof(bool).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "boolPropertyValue"; } else if (typeof(int).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "intPropertyValue"; } else if (typeof(float).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "floatPropertyValue"; } else if (typeof(Texture).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "texturePropertyValue"; } else if (typeof(Vector3).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "vector3PropertyValue"; } else if (typeof(Vector2).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "vector2PropertyValue"; } else if (typeof(Rect).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "rectPropertyValue"; } else if (typeof(Quaternion).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "quaternionPropertyValue"; } else if (typeof(Material).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "materialPropertyValue"; } else if (typeof(Color).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "colorPropertyValue"; } else if (typeof(GameObject).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "gameObjectPropertyValue"; } else if (typeof(UObject).IsAssignableFrom(propertyType)) { expectedPropertyFieldName = "unityObjectPropertyValue"; } if (fieldInfo.Name == expectedPropertyFieldName) { return(UTVisibilityDecision.Visible); } return(UTVisibilityDecision.Invisible); }
public override IEnumerator Execute(UTContext context) { var theGameObject = gameObject.EvaluateIn(context); if (theGameObject == null) { throw new UTFailBuildException("You must specify the game object htat holds the component.", this); } var theProperty = property.EvaluateIn(context); if (theProperty == null || !theProperty.FullyDefined) { throw new UTFailBuildException("You must specify the component type and its property you want to change.", this); } var propertyPath = UTComponentScanner.FindPropertyPath(theProperty.Type, theProperty.FieldPath); if (propertyPath == null) { throw new UTFailBuildException("The component type or the property path is no longer valid.", this); } var theComponent = theGameObject.GetComponent(theProperty.Type); if (theComponent == null) { // nothing to do if (UTPreferences.DebugMode) { Debug.Log("Component " + theProperty.Type.Name + " not found at game object " + theGameObject, this); } } else { Type propertyType = UTInternalCall.GetMemberType(propertyPath[propertyPath.Length - 1]); object propertyValue; if (typeof(string).IsAssignableFrom(propertyType)) { propertyValue = stringPropertyValue.EvaluateIn(context); } else if (typeof(bool).IsAssignableFrom(propertyType)) { propertyValue = boolPropertyValue.EvaluateIn(context); } else if (typeof(int).IsAssignableFrom(propertyType)) { propertyValue = intPropertyValue.EvaluateIn(context); } else if (typeof(float).IsAssignableFrom(propertyType)) { propertyValue = floatPropertyValue.EvaluateIn(context); } else if (typeof(Texture).IsAssignableFrom(propertyType)) { propertyValue = texturePropertyValue.EvaluateIn(context); } else if (typeof(Vector3).IsAssignableFrom(propertyType)) { propertyValue = vector3PropertyValue.EvaluateIn(context); } else if (typeof(Vector2).IsAssignableFrom(propertyType)) { propertyValue = vector2PropertyValue.EvaluateIn(context); } else if (typeof(Rect).IsAssignableFrom(propertyType)) { propertyValue = rectPropertyValue.EvaluateIn(context); } else if (typeof(Quaternion).IsAssignableFrom(propertyType)) { propertyValue = quaternionPropertyValue.EvaluateIn(context); } else if (typeof(Material).IsAssignableFrom(propertyType)) { propertyValue = materialPropertyValue.EvaluateIn(context); } else if (typeof(Color).IsAssignableFrom(propertyType)) { propertyValue = colorPropertyValue.EvaluateIn(context); } else if (typeof(GameObject).IsAssignableFrom(propertyType)) { propertyValue = gameObjectPropertyValue.EvaluateIn(context); } else if (typeof(UObject).IsAssignableFrom(propertyType)) { propertyValue = unityObjectPropertyValue.EvaluateIn(context); } else { propertyValue = objectPropertyValue.EvaluateIn(context); } // TODO: we need a lot more validation here. // e.g. is the value assignable? // Tested with Vector3 -> BoxCollider:center // and float -> BoxCollider:center.y UTInternalCall.SetMemberValue(theComponent, propertyPath, propertyValue); } yield return(""); }
/// <summary> /// Hides the async progress bar. /// </summary> public static void ClearAsyncProgressBar() { UTInternalCall.InvokeStatic("UnityEditor.AsyncProgressBar", "Clear"); }
/// <summary> /// Shows an async progress bar in the lower right corner of Unity's window (like the one shown when /// rendering lightmaps). /// </summary> /// <param name='text'> /// Text to show. /// </param> /// <param name='progress'> /// Progress to show (anything between 0f and 1f) /// </param> public static void ShowAsyncProgressBar(string text, float progress) { UTInternalCall.InvokeStatic("UnityEditor.AsyncProgressBar", "Display", text, progress); }
/// <summary> /// Clears Unity's console. /// </summary> public static void ClearConsole() { UTInternalCall.InvokeStatic("UnityEditorInternal.LogEntries", "Clear"); }
/// <summary> /// Checks if the build pipeline supports the given build target. /// </summary> public static bool IsBuildTargetSupported(BuildTarget target) { return((bool)UTInternalCall.InvokeStatic("UnityEditor.BuildPipeline", "IsBuildTargetSupported", target)); }