SkillAgentSearch skills...

UnityHack

A secret recipe to extend Unity Editor.

Install / Use

/learn @pjc0247/UnityHack
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

UnityHack

A set of snippets to extend Unity Editor.

Before you start

All of snippets from this repository only work inside Unity Editor.<br> You must place your code inside Editor directory to avoid build errors.

Bootstrap your plugin

It all begins with bootstrapping code. This step is pretty easy because Unity already has API for this.

[InitializeOnLoadMethod]
public static void Initialize() {
    /* ... Your code goes here ... */
}

Input

Because of Input class does not work on Unity Editor, you have to write special code to handle it.

Handling global editor input

System.Reflection.FieldInfo info = typeof(EditorApplication).GetField("globalEventHandler", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
EditorApplication.CallbackFunction value = (EditorApplication.CallbackFunction)info.GetValue(null);
value += HandleUnityEvent;
info.SetValue(null, value);
static void HandleUnityEvent()
{
    var e = Event.current;

    if (e.type == EventType.KeyDown && e.keyCode == KeyCode.LeftControl)
    {
        /* Do your stuffs here */
    }
}

Handling scene window input<br> If you want to execute your code ONLY inside the scene view, try this instead of globalEventHandler. It also seems less scary.

SceneView.duringSceneGui += HandleSceneEvent;
static void HandleSceneEvent() {
    var e = Event.current;
                
    if (e == null) return;
    if (e.type == EventType.KeyDown && e.keyCode == KeyCode.LeftControl)
    {
        /* Do your stuffs here */
    }
}

Property change detection

There's no official API to get notification when your changed the property. However, this can be done with Undo.postprocessModifications since every changes will be recorded to Undo.

Undo.postprocessModifications += OnPostProcessModifications;
private static UndoPropertyModification[] OnPostProcessModifications(UndoPropertyModification[] propertyModifications)
{
    foreach (var m in propertyModifications)
    {
        if (m.currentValue.target is Text textTarget) {
            if (m.currentValue.propertyPath == "m_FontData.m_FontSize") {
                /* User has changed `FontSize` from `Text` Component. */
            }
        }
    }
}

Rendering inside SceneView

OnDrawGizmo is a traditional way to draw something inside SceneView. However, you must have a GameObject to receive OnDrawGizmo callback from Unity.<br> You can also use SceneView.duringSceneGui to draw your stuffs without active GameObject.

SceneView.duringSceneGui += OnDrawSceneGUI;
static void OnDrawSceneGUI()
{
    /* Do your stuffs! */
}

Render Texts<br> There are APIs for drawing Rect, Line, Polygon and even Texture. But they don't have an API to render texts.<br> You can render texts by below script:

public static void DrawString(string text, Vector3 position, Color? color = null, bool showTexture = true, int offsetY = 0)
{
    Handles.BeginGUI();

    var restoreColor = GUI.color;
    var viewSize = SceneView.currentDrawingSceneView.position;
    if (color.HasValue) GUI.color = color.Value;
    var view = SceneView.currentDrawingSceneView;
    Vector3 screenPos = view.camera.WorldToScreenPoint(
        position + view.camera.transform.forward);
    if (screenPos.y < 0 || screenPos.y > Screen.height || screenPos.x < 0 || screenPos.x > Screen.width || screenPos.z < 0)
    {
        GUI.color = restoreColor;
        Handles.EndGUI();
        return;
    }
    var style = new GUIStyle(GUI.skin.label);
    style.alignment = TextAnchor.MiddleCenter;
    style.fontSize = 30;
    Vector2 size = style.CalcSize(new GUIContent(text));
    GUI.Label(new Rect(screenPos.x - size.x/2, viewSize.height - screenPos.y - offsetY - size.y/2, size.x, size.y), text, style);
    GUI.color = restoreColor;

    Handles.EndGUI();
}

Detecting object creation

Detect GameObject creation

EditorApplication.hierarchyChanged += OnHierarchyChanged;
private static GameObject lastChangedGO;

private static void OnHierarchyChanged()
{
    if (Selection.objects.Length == 0)
        return;
    var go = Selection.objects[0] as GameObject;
    if (go == null)
        return;

    if (go == lastChangedGO)
        return;

    lastChangedGO = go;

    /* Do your stuff! */ 
}

Detect Component creation

private static GameObject lastChangedGO;
private static int lastGOComponentCount;

private static void OnHierarchyChanged()
{
    if (Selection.objects.Length == 0)
        return;
    var go = Selection.objects[0] as GameObject;
    if (go == null)
        return;

    if (go != lastChangedGO)
        return;
    lastChangedGO = go;

    var comps = go.GetComponents<Component>();
    if (comps.Length == lastGOComponentCount)
        return;
    lastGOComponentCount = comps.Length;

    var addedComponent = comps.Last();
    /* Do your stuff! */ 
}

Drag and Drop

Asset drag detection<br> You can watch BeginDrag for your assets with below code:

EditorApplication.update += OnUpdate;
static void OnUpdate()
{
    if (DragAndDrop.paths.Length > 0 &&
        !(Selection.activeObject is GameObject))
    {
        // DragAndDrop.objectReferences;
    }
}

Object Picking

You can retrive gameObjects with a XY position using HandleUtility.PickGameObject. This is slightly better than Physics.Raycast since it does not require Collider on the GameObject.

SceneView.duringSceneGui += HandleSceneEvents;
static void HandleSceneEvents() {
    if (e == null) return;
    if (e.type == EventType.MouseDown) {
        var picked = HandleUtility.PickGameObject(
            Event.current.mousePosition, false);
        Debug.Log(picked);
    }
}

Pick ALL objects with current mouse position

var ignoreList = new List<GameObject>();
while (true)
{
    var picked = HandleUtility.PickGameObject(
        Event.current.mousePosition, false,
        ignoreList.ToArray());

    if (picked == null)
        break;

    Debug.Log(picked);

    ignoreList.Add(picked);
}
View on GitHub
GitHub Stars27
CategoryDevelopment
Updated1y ago
Forks3

Security Score

75/100

Audited on Aug 25, 2024

No findings