#if UNITY_EDITOR using System; using System.IO; using System.Linq; using DTT.Utils.Exceptions; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace DTT.Utils.EditorUtilities { /// /// Provides an API and menu items to modify compile ability of a script asset using /// pre processing defines. /// public static class AssetUtility { /// /// The unity editor preprocessing define. /// public const string UNITY_EDITOR_PREPROCESS_NAME = "UNITY_EDITOR"; /// /// The unity ios preprocessing define. /// public const string IOS_PREPROCESS_NAME = "UNITY_IOS"; /// /// The unity android preprocessing define. /// public const string ANDROID_PREPROCESS_NAME = "UNITY_ANDROID"; /// /// The base menu item name using when right-clicking an asset. /// private const string SCRIPT_PREPROCESS_MENU_ITEM_NAME = "Assets/PreProcess Selected/"; /// /// The menu item name for adding a scene asset to build settings. /// private const string SCENE_BUILD_SETTINGS_MENU_ITEM_NAME = "Assets/Add to build settings"; /// /// The preprocessing if statement. /// private const string PRE_PROCESS_IF = "#if "; /// /// The preprocessing end of an if statement. /// private const string PRE_PROCESS_END_IF = "#endif"; /// /// Called when the unity editor preprocessing menu item is clicked, /// it will apply unity editor preprocessing on selected assets. /// [MenuItem(SCRIPT_PREPROCESS_MENU_ITEM_NAME + UNITY_EDITOR_PREPROCESS_NAME)] private static void OnUnityEditorAssetPreProcess() { string[] assetGuids = Selection.assetGUIDs; for (int i = 0; i < assetGuids.Length; i++) ApplyPreProcessingOnAsset(assetGuids[i], UNITY_EDITOR_PREPROCESS_NAME); } /// /// Called when the unity ios preprocessing menu item is clicked, /// it will apply unity ios preprocessing on selected assets. /// [MenuItem(SCRIPT_PREPROCESS_MENU_ITEM_NAME + IOS_PREPROCESS_NAME)] private static void OnIOSAssetPreProcess() { string[] assetGuids = Selection.assetGUIDs; for (int i = 0; i < assetGuids.Length; i++) ApplyPreProcessingOnAsset(assetGuids[i], IOS_PREPROCESS_NAME); } /// /// Called when the unity android preprocessing menu item is clicked, /// it will apply unity android preprocessing on selected assets. /// [MenuItem(SCRIPT_PREPROCESS_MENU_ITEM_NAME + ANDROID_PREPROCESS_NAME)] private static void OnAndroidAssetPreProcess() { string[] assetGuids = Selection.assetGUIDs; for (int i = 0; i < assetGuids.Length; i++) ApplyPreProcessingOnAsset(assetGuids[i], ANDROID_PREPROCESS_NAME); } /// /// Adds selected scene assets to build settings. /// [MenuItem(SCENE_BUILD_SETTINGS_MENU_ITEM_NAME)] private static void OnAddSceneAssetToBuildSettings() { string[] assetGuids = Selection.assetGUIDs; if (assetGuids.Length != 0) AddScenesToBuildSettings(assetGuids.Select(guid => AssetDatabase.GUIDToAssetPath(guid)).ToArray()); } /// /// Adds a scene asset at given path to the build settings. /// /// The scene asset's path. public static void AddSceneToBuildSettings(string sceneAssetPath) { if (sceneAssetPath == null) throw new ArgumentNullException(nameof(sceneAssetPath)); AddScenesToBuildSettings(new string[]{ sceneAssetPath }); } /// /// Returns whether a given scene asset path corresponds with a scene in the build settings. /// /// The scene asset path to check. /// Whether the given scene asset path corresponds with a scene in the build settings. public static bool IsScenePartOfBuildSettings(string sceneAssetPath) { if (sceneAssetPath == null) throw new ArgumentNullException(nameof(sceneAssetPath)); EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes; for(int i = 0; i < scenes.Length; i++) if (scenes[i].path == sceneAssetPath) return true; return false; } /// /// Adds scene asset's at given paths to the build settings. /// /// The scene asset's paths. public static void AddScenesToBuildSettings(string[] sceneAssetPaths) { if (sceneAssetPaths == null) throw new ArgumentNullException(nameof(sceneAssetPaths)); EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes; EditorBuildSettingsScene[] updated = new EditorBuildSettingsScene[scenes.Length + sceneAssetPaths.Length]; Array.Copy(scenes, updated, scenes.Length); for (int i = 0, j = scenes.Length; i < sceneAssetPaths.Length; i++, j++) updated[j] = new EditorBuildSettingsScene(sceneAssetPaths[i], true); EditorBuildSettings.scenes = updated; string[] newSceneNames = sceneAssetPaths.Select(path => Path.GetFileNameWithoutExtension(path)).ToArray(); Debug.Log($"Successfully added scenes to build settings: {string.Join(", ", newSceneNames)}"); } /// /// Will apply preprocessing on an asset at a given path. /// /// The asset path. /// The preprocess name. (e.g. UNITY_EDITOR) public static void ApplyPreProcessingOnAssetAtPath(string assetPath, string preprocessName) { if (string.IsNullOrEmpty(assetPath)) throw new NullOrEmptyException(nameof(assetPath)); if (string.IsNullOrEmpty(preprocessName)) throw new NullOrEmptyException(nameof(preprocessName)); MonoScript script = AssetDatabase.LoadAssetAtPath(assetPath); if (script == null) { Debug.LogWarning($"Failed applying pre processing on asset at path {assetPath} as it is not a script asset."); return; } if (string.IsNullOrEmpty(script.text)) { Debug.Log("Can't apply pre processing if script file text is null or empty."); return; } using (StringReader reader = new StringReader(script.text)) { string firstLine = reader.ReadLine(); if (firstLine.Contains(preprocessName)) { Debug.LogWarning($"Asset at {assetPath} already has preprocessing statement {preprocessName}."); return; } string text; if (firstLine.Contains(PRE_PROCESS_IF)) { text = script.text.Replace(firstLine, firstLine + $" && {preprocessName}"); } else { text = script.text.Insert(0, string.Format("{0}{1}\n\n", PRE_PROCESS_IF, preprocessName)) + string.Format("\n{0}", PRE_PROCESS_END_IF); } File.WriteAllText(assetPath, text); AssetDatabase.ImportAsset(assetPath); } } /// /// Will apply preprocessing on an asset with a given guid. /// /// The asset guid. /// The preprocess name. (e.g. UNITY_EDITOR) public static void ApplyPreProcessingOnAsset(string assetGuid, string preprocessName) => ApplyPreProcessingOnAssetAtPath(AssetDatabase.GUIDToAssetPath(assetGuid), preprocessName); /// /// Returns the editor icon for a unity object. /// /// The unity object to get the editor icon for. /// The editor icon. public static Texture GetEditorIcon(this Object unityObject) { if (unityObject == null) throw new ArgumentNullException(nameof(unityObject)); if (unityObject is ScriptableObject) return EditorGUIUtility.IconContent("ScriptableObject Icon").image; if (unityObject is Component || unityObject is MonoScript) return EditorGUIUtility.IconContent("cs Script Icon").image; return EditorGUIUtility.IconContent($"{unityObject.GetType().Name} Icon").image; } /// /// Returns the editor icon for an object type. /// /// The object type to get the editor icon for. /// The editor icon. public static Texture GetEditorIcon(this Type objectType) { if (objectType == null) throw new ArgumentNullException(nameof(objectType)); if(!objectType.IsSubclassOf(typeof(Object))) return EditorGUIUtility.IconContent("cs Script Icon").image; if (objectType.IsSubclassOf(typeof(ScriptableObject))) return EditorGUIUtility.IconContent("ScriptableObject Icon").image; if (objectType.IsSubclassOf(typeof(Component)) || objectType == typeof(MonoScript)) return EditorGUIUtility.IconContent("cs Script Icon").image; return EditorGUIUtility.IconContent($"{objectType.Name} Icon").image; } } } #endif