Search Unity

Feedback Getting the current custom EditorTool instance globally

Discussion in 'Scripting' started by Xarbrough, Jun 14, 2019.

  1. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    With the new EditorTools API, isn't there a clean and easy way to retrieve the current custom EditorTool instance?

    I only found EditorTools.activeToolType which gives me the Type of tool. This I can use the find all instances via Resources.FindObjectsOfTypeAll, but this feels slow and more cumbersome than it needs to be. Unity is already managing the current tool instance for me, so it could simply be a static read property.

    Additionally, the callback EditorTools.activeToolChanged doesn't send the previous and current instance. Why not? I'd like to build custom tooling that can make use of this existing context, but therefore it needs to know which was the last tool and which is the current one.

    Overall, I like the new EditorTool API. The ability to insert custom tools that behave very similar to the builtin Unity tools is great, but the API is lacking just these few things to make it more convenient. :)
     
  2. alesimula

    alesimula

    Joined:
    Mar 27, 2019
    Posts:
    7
    Very late answer, but probably still useful for someone

    I've made this little utility containing three getters: a method with a generic parameter, a method with a System.Type parameter (in case you got the tool type through reflection) and a property to get the active tool

    It uses reflection but it's probably way faster than using FindObjectsOfTypeAll

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using UnityEditor.EditorTools;
    4. using System.Linq;
    5.  
    6. namespace Unity.Utils {
    7. public static class EditorToolUtils
    8. {
    9.     private static System.Reflection.BindingFlags bindingFlagsAny = (System.Reflection.BindingFlags)(-1);
    10.     private static System.Reflection.Assembly editorAssembly = System.Reflection.Assembly.Load("UnityEditor");
    11.     private static System.Type editorToolUtilityType = editorAssembly.GetType("UnityEditor.EditorTools.EditorToolUtility");
    12.     private static System.Type editorToolContextType = editorAssembly.GetType("UnityEditor.EditorTools.EditorToolContext");
    13.     private static System.Reflection.MethodInfo attributeGetter = editorToolUtilityType.GetMethods(bindingFlagsAny).Where(method => method.Name == "GetEditorToolAttribute"
    14.         && method.GetParameters().Aggregate(true, (old, param) => old && param.ParameterType.Equals(typeof(System.Type)))).First();
    15.     private static System.Reflection.MethodInfo toolSingletonGetter = editorToolContextType.GetMethods(bindingFlagsAny).Where(method => method.Name == "GetSingleton"
    16.         && method.GetParameters().Length == 1 && method.GetParameters().Aggregate(true, (old, param) => old && param.ParameterType.Equals(typeof(System.Type)))).First();
    17.     private static System.Reflection.MethodInfo toolGetter = editorToolContextType.GetMethod("GetCustomEditorToolOfType", bindingFlagsAny);
    18.  
    19.     public static EditorTool GetEditorTool(System.Type toolType) {
    20.         var attribute = attributeGetter.Invoke(null, new object[] {toolType});
    21.         if (attribute != null && (attribute as EditorToolAttribute)?.targetType != null)
    22.             return toolGetter.Invoke(null, new object[] {toolType, true}) as EditorTool;
    23.         else return toolSingletonGetter.Invoke(null, new object[] {toolType}) as EditorTool;
    24.     }
    25.     public static T GetEditorTool<T>() where T: EditorTool => GetEditorTool(typeof(T)) as T;
    26.     public static EditorTool activeEditorTool => GetEditorTool(EditorTools.activeToolType);
    27. }}
    28.  
     
    Last edited: Jun 8, 2020
  3. Flyclops

    Flyclops

    Joined:
    Apr 19, 2013
    Posts:
    12
    Thanks for this script. I've been using it for a bit, but it's not longer working in Unity 2020.2. toolSingletonGetter is an empty array. I thought maybe the GetSingleton methods were removed.

    So I tried to recreate. The ability to get the instance of the current active editor tool is pretty important to our workflow. After trying to find out what I could via reflection, I found that the source is actually shared by Unity on github here: https://github.com/Unity-Technologies/UnityCsReference

    It looks like there's a private property of EditorToolContext that is exactly what I need, activeTool, line 40 of this class: https://github.com/Unity-Technologi....2/Editor/Mono/GUI/Tools/EditorToolContext.cs

    But... I can't seem to find it via reflection. Here's my code:

    Code (CSharp):
    1. var context = typeof(UnityEditor.EditorTools.EditorToolContext);
    2. var props = context.GetProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance);
    3. foreach (var prop in props)
    4. {
    5.     Debug.Log(prop.Name);
    6. }
    This outputs only name and hideFlags. Similarly most of the other fields, methods and properties in the source do not seem accessible via reflection.

    Anybody know why? Or any other methods that people know of to get the current editor tools active instance?