Skip to content

Instantly share code, notes, and snippets.

@CSaratakij
Last active September 30, 2024 07:15
Show Gist options
  • Select an option

  • Save CSaratakij/bf6e7eb0108e963c59c833ad5a9f7a0a to your computer and use it in GitHub Desktop.

Select an option

Save CSaratakij/bf6e7eb0108e963c59c833ad5a9f7a0a to your computer and use it in GitHub Desktop.

Revisions

  1. CSaratakij revised this gist Sep 30, 2024. 2 changed files with 2 additions and 2 deletions.
    2 changes: 1 addition & 1 deletion BuildTypeEditorWindowTitleStatus.cs
    Original file line number Diff line number Diff line change
    @@ -13,7 +13,7 @@
    using System.Reflection;
    using UnityEditor;

    namespace EditorUtility
    namespace Game.EditorUtility
    {
    internal static class BuildTypeEditorWindowTitleStatus
    {
    2 changes: 1 addition & 1 deletion QuickChangeBuildTypeMenu.cs
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    using System;
    using UnityEditor;

    namespace EditorUtility
    namespace Game.EditorUtility
    {
    public enum BuildType
    {
  2. CSaratakij revised this gist Sep 29, 2024. 2 changed files with 307 additions and 54 deletions.
    233 changes: 233 additions & 0 deletions BuildTypeEditorWindowTitleStatus.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,233 @@
    /*
    Note : adhocs for unity 2022.3.31
    TODO : Need to Support Unity 6 with the new callback : https://docs.unity3d.com/6000.0/Documentation/ScriptReference/EditorApplication.UpdateMainWindowTitle.html
    and the new force update window title method : https://docs.unity3d.com/6000.0/Documentation/ScriptReference/EditorApplication.UpdateMainWindowTitle.html
    */

    #if UNITY_2022_3_31
    #define EDITOR_ALLOW_BUILDTYPE_STATUS
    #endif

    #if UNITY_EDITOR && UNITY_EDITOR_WIN && EDITOR_ALLOW_BUILDTYPE_STATUS
    using System;
    using System.Reflection;
    using UnityEditor;

    namespace EditorUtility
    {
    internal static class BuildTypeEditorWindowTitleStatus
    {
    internal static event Action<string> OnInternalEditorUpdateMainWindowTitle;
    internal static event Action<bool> OnEditorApplicationFocusChanged;

    private static bool isPreviousFocus = false;
    private static bool isCurrentFocus = false;

    internal static string CurrentCustomEditorWindowTitle = "";
    private static string CurrentInternalEditorWindowTitle = "";
    private static object CurrentInternalApplicationTitleDescriptor = null;
    private static Delegate updateMainWindowTitleEventHandler = null;

    internal static bool IsInternalApplicationTitleDescriptorDirty => (CurrentInternalApplicationTitleDescriptor == null);

    [InitializeOnLoadMethod]
    private static void Initialize()
    {
    Reset();

    try
    {
    EventInfo eventInfo = GetUpdateMainWindowTitleEvent(out var bindingFlags);

    if (eventInfo != null)
    {
    MethodInfo callbackMethodInfo = typeof(BuildTypeEditorWindowTitleStatus).GetMethod(nameof(OnUpdateMainWindowTitleHandler), BindingFlags.Static | BindingFlags.NonPublic);
    updateMainWindowTitleEventHandler = Delegate.CreateDelegate(eventInfo.EventHandlerType, callbackMethodInfo, throwOnBindFailure: true);

    MethodInfo addEventHandlerMethodInfo = eventInfo.GetAddMethod(nonPublic: true);
    addEventHandlerMethodInfo.Invoke(null, new object[] { updateMainWindowTitleEventHandler });
    }
    else
    {
    throw new Exception($"{nameof(BuildTypeEditorWindowTitleStatus)}: target event 'updateMainWindowTitle' not found in this unity version");
    }

    isPreviousFocus = isCurrentFocus;
    isCurrentFocus = EditorApplication.isFocused;

    EditorApplication.focusChanged += OnEditorApplicationFocusChangedHandler;
    EditorApplication.playModeStateChanged += OnPlayModeStateChange;
    QuickChangeBuildTypeMenu.OnBuildTypeChanged += OnBuildTypeChanged;
    }
    catch (Exception e)
    {
    UnityEngine.Debug.LogError(e);
    }

    void Reset()
    {
    isPreviousFocus = false;
    isCurrentFocus = false;
    CurrentInternalApplicationTitleDescriptor = null;
    }
    }

    private static void OnEditorApplicationFocusChangedHandler(bool isFocused)
    {
    isPreviousFocus = isCurrentFocus;
    isCurrentFocus = isFocused;

    bool isFocusDirty = (isPreviousFocus != isCurrentFocus);

    if (isFocusDirty)
    {
    isPreviousFocus = isCurrentFocus;
    ForceBuildInternalMainWindowTitle();
    }

    OnEditorApplicationFocusChanged?.Invoke(isFocused);
    }

    private static void OnPlayModeStateChange(PlayModeStateChange state)
    {
    if (state == PlayModeStateChange.EnteredEditMode)
    {
    ForceBuildInternalMainWindowTitle();
    }
    }

    private static void OnBuildTypeChanged()
    {
    ForceBuildInternalMainWindowTitle();
    }

    // Note : can only update window title in the exact reference of application title descriptor in this callback only
    private static void OnUpdateMainWindowTitleHandler(object descriptor)
    {
    BuildType? buildType = GetCurrentBuildType();

    if (buildType != null)
    {
    UpdateWindowTitle(descriptor, buildType.Value);
    }
    }

    private static void UpdateWindowTitle(object descriptor, BuildType buildType)
    {
    try
    {
    if (descriptor == null)
    {
    return;
    }

    FieldInfo editorWindowTitleFieldInfo = descriptor.GetType()?.GetField("title");

    if (editorWindowTitleFieldInfo == null)
    {
    return;
    }

    string internalWindowTitle = (editorWindowTitleFieldInfo.GetValue(descriptor) as string);
    string customWindowTitle = $"{internalWindowTitle} <{buildType}>";

    CurrentInternalApplicationTitleDescriptor = descriptor;
    CurrentInternalEditorWindowTitle = internalWindowTitle;
    CurrentCustomEditorWindowTitle = customWindowTitle;

    editorWindowTitleFieldInfo.SetValue(descriptor, customWindowTitle);
    OnInternalEditorUpdateMainWindowTitle?.Invoke(customWindowTitle);
    }
    catch (Exception e)
    {
    UnityEngine.Debug.LogError(e);
    }
    }

    private static bool ForceBuildInternalMainWindowTitle()
    {
    try
    {
    MethodInfo methodInfo_BuildMainWindowTitle = typeof(EditorApplication).GetMethod("BuildMainWindowTitle", BindingFlags.Static | BindingFlags.NonPublic);
    MethodInfo methodInfo_UpdateMainWindowTitle = typeof(EditorApplication).GetMethod("UpdateMainWindowTitle", BindingFlags.Static | BindingFlags.NonPublic);

    bool isValid = (methodInfo_BuildMainWindowTitle != null) && (methodInfo_UpdateMainWindowTitle != null);

    if (!isValid)
    {
    return false;
    }

    // Hacks : force build internal main window title to get the lastest application title descriptor
    if (IsInternalApplicationTitleDescriptorDirty)
    {
    methodInfo_BuildMainWindowTitle?.Invoke(null, null);
    }

    // Hacks : make sure window title gui update from application title descriptor
    methodInfo_UpdateMainWindowTitle?.Invoke(null, null);
    return true;
    }
    catch (Exception e)
    {
    UnityEngine.Debug.LogError(e);
    return false;
    }
    }

    internal static void ForceUpdateMainWindowTitle(object reflection_ApplicationTitleDescriptor)
    {
    try
    {
    EventInfo eventInfo = GetUpdateMainWindowTitleEvent(out var bindingFlags);

    if (eventInfo == null)
    {
    return;
    }

    FieldInfo fieldInfo = typeof(EditorApplication).GetField(eventInfo.Name, bindingFlags);

    if (fieldInfo != null)
    {
    var eventDelegate = (fieldInfo.GetValue(null) as Delegate);
    eventDelegate?.DynamicInvoke(new object[] { reflection_ApplicationTitleDescriptor });
    }
    }
    catch (Exception e)
    {
    UnityEngine.Debug.LogError(e);
    }
    }

    private static EventInfo GetUpdateMainWindowTitleEvent(out BindingFlags bindingFlags)
    {
    bindingFlags = BindingFlags.Static | BindingFlags.NonPublic;

    try
    {
    EventInfo targetEvent = typeof(EditorApplication).GetEvent("updateMainWindowTitle", bindingFlags);
    return targetEvent;
    }
    catch (Exception e)
    {
    UnityEngine.Debug.LogError(e);
    return null;
    }
    }

    private static BuildType? GetCurrentBuildType()
    {
    BuildTargetGroup currentBuildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
    ScriptingImplementation currentScriptingImplementation = PlayerSettings.GetScriptingBackend(currentBuildTargetGroup);

    return currentScriptingImplementation switch
    {
    ScriptingImplementation.Mono2x => BuildType.Mono,
    ScriptingImplementation.IL2CPP => BuildType.IL2CPP,
    _ => null
    };
    }
    }
    }
    #endif
    128 changes: 74 additions & 54 deletions QuickChangeBuildTypeMenu.cs
    Original file line number Diff line number Diff line change
    @@ -1,79 +1,99 @@
    using System;
    using UnityEditor;

    public static class QuickChangeBuildTypeMenu
    namespace EditorUtility
    {
    private const int MENU_ITEM_PRIORITY = -1;
    private const string PATH_MENU_MONO = "Help/Quick change build type/Mono";
    private const string PATH_MENU_IL2CPP = "Help/Quick change build type/IL2CPP";

    private enum BuildType
    public enum BuildType
    {
    Mono,
    IL2CPP
    }

    [MenuItem(PATH_MENU_MONO, true)]
    private static bool ValidateChangeToMonoBuildMenu()
    public static class QuickChangeBuildTypeMenu
    {
    bool shouldCheckedMenu = IsUseCurrentBuildType(BuildType.Mono);
    Menu.SetChecked(PATH_MENU_MONO, isChecked: shouldCheckedMenu);
    return true;
    }
    public static event Action OnBuildTypeChanged;

    [MenuItem(PATH_MENU_IL2CPP, true)]
    private static bool ValidateChangeToIL2CPPBuildMenu()
    {
    bool shouldCheckedMenu = IsUseCurrentBuildType(BuildType.IL2CPP);
    Menu.SetChecked(PATH_MENU_IL2CPP, isChecked: shouldCheckedMenu);
    return true;
    }
    private const int MENU_ITEM_PRIORITY = -1;
    private const string PATH_MENU_MONO = "Help/Quick change build type/Mono";
    private const string PATH_MENU_IL2CPP = "Help/Quick change build type/IL2CPP";

    [MenuItem(PATH_MENU_MONO, false, MENU_ITEM_PRIORITY)]
    private static void ChangeToMonoBuildMenu()
    {
    ChangeBuildType(BuildType.Mono);
    }
    [MenuItem(PATH_MENU_MONO, true)]
    private static bool ValidateChangeToMonoBuildMenu()
    {
    if (EditorApplication.isPlaying)
    {
    return false;
    }

    [MenuItem(PATH_MENU_IL2CPP, false, MENU_ITEM_PRIORITY)]
    private static void ChangeToIL2CPPBuildMenu()
    {
    ChangeBuildType(BuildType.IL2CPP);
    }
    bool shouldCheckedMenu = IsUseCurrentBuildType(BuildType.Mono);
    Menu.SetChecked(PATH_MENU_MONO, isChecked: shouldCheckedMenu);

    private static void ChangeBuildType(BuildType buildType)
    {
    BuildTargetGroup currentBuildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
    return true;
    }

    switch (buildType)
    [MenuItem(PATH_MENU_IL2CPP, true)]
    private static bool ValidateChangeToIL2CPPBuildMenu()
    {
    case BuildType.Mono:
    if (EditorApplication.isPlaying)
    {
    PlayerSettings.SetScriptingBackend(currentBuildTargetGroup, ScriptingImplementation.Mono2x);
    PlayerSettings.SetManagedStrippingLevel(currentBuildTargetGroup, ManagedStrippingLevel.Disabled);
    AssetDatabase.SaveAssets();
    return false;
    }
    break;

    case BuildType.IL2CPP:
    bool shouldCheckedMenu = IsUseCurrentBuildType(BuildType.IL2CPP);
    Menu.SetChecked(PATH_MENU_IL2CPP, isChecked: shouldCheckedMenu);

    return true;
    }

    [MenuItem(PATH_MENU_MONO, false, MENU_ITEM_PRIORITY)]
    private static void ChangeToMonoBuildMenu()
    {
    ChangeBuildType(BuildType.Mono);
    }

    [MenuItem(PATH_MENU_IL2CPP, false, MENU_ITEM_PRIORITY)]
    private static void ChangeToIL2CPPBuildMenu()
    {
    ChangeBuildType(BuildType.IL2CPP);
    }

    private static void ChangeBuildType(BuildType buildType)
    {
    BuildTargetGroup currentBuildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;

    switch (buildType)
    {
    PlayerSettings.SetScriptingBackend(currentBuildTargetGroup, ScriptingImplementation.IL2CPP);
    PlayerSettings.SetManagedStrippingLevel(currentBuildTargetGroup, ManagedStrippingLevel.Minimal);
    AssetDatabase.SaveAssets();
    case BuildType.Mono:
    {
    PlayerSettings.SetScriptingBackend(currentBuildTargetGroup, ScriptingImplementation.Mono2x);
    PlayerSettings.SetManagedStrippingLevel(currentBuildTargetGroup, ManagedStrippingLevel.Disabled);
    AssetDatabase.SaveAssets();
    }
    break;

    case BuildType.IL2CPP:
    {
    PlayerSettings.SetScriptingBackend(currentBuildTargetGroup, ScriptingImplementation.IL2CPP);
    PlayerSettings.SetManagedStrippingLevel(currentBuildTargetGroup, ManagedStrippingLevel.Minimal);
    AssetDatabase.SaveAssets();
    }
    break;
    }
    break;
    }
    }

    private static bool IsUseCurrentBuildType(BuildType buildType)
    {
    BuildTargetGroup currentBuildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
    ScriptingImplementation currentScriptingImplementation = PlayerSettings.GetScriptingBackend(currentBuildTargetGroup);
    OnBuildTypeChanged?.Invoke();
    }

    return buildType switch
    private static bool IsUseCurrentBuildType(BuildType buildType)
    {
    BuildType.Mono => (currentScriptingImplementation == ScriptingImplementation.Mono2x),
    BuildType.IL2CPP => (currentScriptingImplementation == ScriptingImplementation.IL2CPP),
    _ => false
    };
    BuildTargetGroup currentBuildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
    ScriptingImplementation currentScriptingImplementation = PlayerSettings.GetScriptingBackend(currentBuildTargetGroup);

    return buildType switch
    {
    BuildType.Mono => (currentScriptingImplementation == ScriptingImplementation.Mono2x),
    BuildType.IL2CPP => (currentScriptingImplementation == ScriptingImplementation.IL2CPP),
    _ => false
    };
    }
    }
    }
  3. CSaratakij created this gist Apr 24, 2024.
    79 changes: 79 additions & 0 deletions QuickChangeBuildTypeMenu.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,79 @@
    using UnityEditor;

    public static class QuickChangeBuildTypeMenu
    {
    private const int MENU_ITEM_PRIORITY = -1;
    private const string PATH_MENU_MONO = "Help/Quick change build type/Mono";
    private const string PATH_MENU_IL2CPP = "Help/Quick change build type/IL2CPP";

    private enum BuildType
    {
    Mono,
    IL2CPP
    }

    [MenuItem(PATH_MENU_MONO, true)]
    private static bool ValidateChangeToMonoBuildMenu()
    {
    bool shouldCheckedMenu = IsUseCurrentBuildType(BuildType.Mono);
    Menu.SetChecked(PATH_MENU_MONO, isChecked: shouldCheckedMenu);
    return true;
    }

    [MenuItem(PATH_MENU_IL2CPP, true)]
    private static bool ValidateChangeToIL2CPPBuildMenu()
    {
    bool shouldCheckedMenu = IsUseCurrentBuildType(BuildType.IL2CPP);
    Menu.SetChecked(PATH_MENU_IL2CPP, isChecked: shouldCheckedMenu);
    return true;
    }

    [MenuItem(PATH_MENU_MONO, false, MENU_ITEM_PRIORITY)]
    private static void ChangeToMonoBuildMenu()
    {
    ChangeBuildType(BuildType.Mono);
    }

    [MenuItem(PATH_MENU_IL2CPP, false, MENU_ITEM_PRIORITY)]
    private static void ChangeToIL2CPPBuildMenu()
    {
    ChangeBuildType(BuildType.IL2CPP);
    }

    private static void ChangeBuildType(BuildType buildType)
    {
    BuildTargetGroup currentBuildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;

    switch (buildType)
    {
    case BuildType.Mono:
    {
    PlayerSettings.SetScriptingBackend(currentBuildTargetGroup, ScriptingImplementation.Mono2x);
    PlayerSettings.SetManagedStrippingLevel(currentBuildTargetGroup, ManagedStrippingLevel.Disabled);
    AssetDatabase.SaveAssets();
    }
    break;

    case BuildType.IL2CPP:
    {
    PlayerSettings.SetScriptingBackend(currentBuildTargetGroup, ScriptingImplementation.IL2CPP);
    PlayerSettings.SetManagedStrippingLevel(currentBuildTargetGroup, ManagedStrippingLevel.Minimal);
    AssetDatabase.SaveAssets();
    }
    break;
    }
    }

    private static bool IsUseCurrentBuildType(BuildType buildType)
    {
    BuildTargetGroup currentBuildTargetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
    ScriptingImplementation currentScriptingImplementation = PlayerSettings.GetScriptingBackend(currentBuildTargetGroup);

    return buildType switch
    {
    BuildType.Mono => (currentScriptingImplementation == ScriptingImplementation.Mono2x),
    BuildType.IL2CPP => (currentScriptingImplementation == ScriptingImplementation.IL2CPP),
    _ => false
    };
    }
    }