/* ┌──────────────────────────────────────────────────────────────────┐ │ Author: Ivan Murzak (https://github.com/IvanMurzak) │ │ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │ │ Copyright (c) 2025 Ivan Murzak │ │ Licensed under the Apache License, Version 2.0. │ │ See the LICENSE file in the project root for more information. │ └──────────────────────────────────────────────────────────────────┘ */ #nullable enable using System; using com.IvanMurzak.Unity.MCP.Runtime.Extensions; using UnityEditor; using UnityEngine; namespace com.IvanMurzak.Unity.MCP.Editor.Utils { /// /// Caches built-in Unity Editor assets to avoid repeated expensive LoadAllAssetsAtPath calls. /// Built-in assets don't change during an editor session, so caching is safe. /// public static class BuiltInAssetCache { private static UnityEngine.Object[]? _cachedAssets; private static readonly object _lock = new object(); /// /// Gets all built-in assets, loading and caching them on first access. /// public static UnityEngine.Object[] GetAllAssets() { if (_cachedAssets != null) return _cachedAssets; lock (_lock) { if (_cachedAssets != null) return _cachedAssets; _cachedAssets = AssetDatabase.LoadAllAssetsAtPath(ExtensionsRuntimeObject.UnityEditorBuiltInResourcesPath); } return _cachedAssets; } /// /// Finds a built-in asset by name and optional type. /// /// The name of the asset to find. /// Optional type to filter by. If null, returns the first asset with matching name. /// The found asset, or null if not found. public static UnityEngine.Object? FindAsset(string name, Type? type = null) { var assets = GetAllAssets(); foreach (var obj in assets) { if (obj == null || obj.name != name) continue; if (type == null) return obj; if (type.IsAssignableFrom(obj.GetType())) return obj; } return null; } /// /// Finds a built-in asset by name and file extension (used to disambiguate types). /// /// The name of the asset to find. /// File extension like ".mat", ".shader", etc. /// The found asset, or null if not found. public static UnityEngine.Object? FindAssetByExtension(string name, string? extension) { var assets = GetAllAssets(); foreach (var obj in assets) { if (obj == null || obj.name != name) continue; if (string.IsNullOrEmpty(extension)) return obj; if (MatchesExtension(obj, extension!)) return obj; } return null; } /// /// Checks if a Unity object matches the expected type for a given file extension. /// /// The Unity object to check. /// File extension like ".mat", ".shader", etc. /// True if the object type matches the extension, false otherwise. public static bool MatchesExtension(UnityEngine.Object obj, string extension) { // Normalize extension to lowercase for case-insensitive matching var ext = extension.ToLowerInvariant(); return ext switch { // Materials ".mat" => obj is Material, // Shaders ".shader" => obj is Shader, ".compute" => obj is ComputeShader, // Textures & Sprites (same source formats can be either) ".png" or ".jpg" or ".jpeg" or ".tga" or ".psd" or ".tif" or ".tiff" or ".gif" or ".bmp" => obj is Texture2D or Sprite, ".hdr" or ".exr" => obj is Texture2D or Cubemap, // Audio ".wav" or ".mp3" or ".ogg" or ".aif" or ".aiff" => obj is AudioClip, // Animation ".anim" => obj is AnimationClip, // Fonts ".ttf" or ".otf" or ".fontsettings" => obj is Font, // Meshes (built-in primitives) ".fbx" or ".obj" or ".dae" or ".3ds" or ".blend" => obj is Mesh, // GUI ".guiskin" => obj is GUISkin, // Flare ".flare" => obj is Flare, // Unknown extension - accept any type _ => true }; } /// /// Gets the file extension for a built-in asset based on its type. /// Only returns extensions for types with unambiguous mappings. /// Types like Sprite, Texture2D, AudioClip, Mesh, Font can have multiple /// possible extensions, so they return empty string. /// /// The Unity object to get the extension for. /// File extension like ".mat", ".shader", etc., or empty string for ambiguous/unknown types. public static string GetExtensionForAsset(UnityEngine.Object obj) { // Only return extensions for types with unique/unambiguous mappings return obj switch { Material => ".mat", Shader => ".shader", ComputeShader => ".compute", AnimationClip => ".anim", GUISkin => ".guiskin", Flare => ".flare", // Types with multiple possible extensions (Sprite, Texture2D, Cubemap, // AudioClip, Mesh, Font) - cannot determine without file system access _ => string.Empty }; } /// /// Clears the cache. Useful if you need to force a reload (rarely needed). /// public static void ClearCache() { lock (_lock) { _cachedAssets = null; } } } }