using UnityEditor.AddressableAssets; using UnityEditor.AddressableAssets.Settings; using UnityEditor.AddressableAssets.Settings.GroupSchemas; using UnityEngine; using UnityEditor; namespace AppleHills.Editor.Utilities { /// /// Utility methods for working with the Addressables system in editor scripts. /// Contains common operations for creating and managing groups and entries. /// public static class AddressablesUtility { /// /// Get or create the Addressables settings. Returns null if Addressables are not properly set up. /// /// If true, will attempt to create settings if they don't exist /// The AddressableAssetSettings or null if not available public static AddressableAssetSettings GetAddressableSettings(bool createIfMissing = false) { var settings = AddressableAssetSettingsDefaultObject.GetSettings(createIfMissing); if (settings == null && createIfMissing) { Debug.LogError("AddressableAssetSettings could not be found or created. Please ensure Addressables are set up in your project."); } return settings; } /// /// Retrieve or create an Addressables group. /// /// Name of the group /// Whether to include assets in this group when building /// The created or existing group, or null if settings aren't available public static AddressableAssetGroup GetOrCreateGroup(string name, bool includeInBuild = true) { // Use GetSettings(true) to ensure the settings asset is created if missing var settings = GetAddressableSettings(true); if (settings == null) { return null; } var group = settings.FindGroup(name); if (group == null) { group = settings.CreateGroup(name, false, false, true, settings.DefaultGroup.Schemas); // Configure the bundle schema if it exists var bundleSchema = group.GetSchema(); if (bundleSchema != null) { bundleSchema.IncludeInBuild = includeInBuild; } } return group; } /// /// Create or move an asset entry to a specified Addressables group /// /// Path to the asset /// Name of the group to add the asset to /// Optional custom address for the asset /// The created or moved asset entry, or null if failed public static AddressableAssetEntry AddAssetToGroup(string assetPath, string groupName, string address = null) { if (string.IsNullOrEmpty(assetPath)) { Debug.LogError("Cannot add asset to Addressables: Asset path is empty"); return null; } var settings = GetAddressableSettings(false); if (settings == null) { return null; } var group = GetOrCreateGroup(groupName); if (group == null) { return null; } var guid = AssetDatabase.AssetPathToGUID(assetPath); if (string.IsNullOrEmpty(guid)) { Debug.LogError($"Cannot add asset to Addressables: Invalid asset path {assetPath}"); return null; } var entry = settings.CreateOrMoveEntry(guid, group); // Set custom address if provided if (!string.IsNullOrEmpty(address)) { entry.address = address; } settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entry, true); return entry; } /// /// Ensure an asset is in the specified addressable group /// /// Path to the asset /// Target group name /// Whether to mark settings as dirty /// True if the asset is now in the correct group public static bool EnsureAssetInGroup(string assetPath, string groupName, bool markDirty = true) { var settings = GetAddressableSettings(false); if (settings == null) { return false; } var guid = AssetDatabase.AssetPathToGUID(assetPath); if (string.IsNullOrEmpty(guid)) { return false; } var group = GetOrCreateGroup(groupName); if (group == null) { return false; } var entry = settings.FindAssetEntry(guid); // If entry exists but is in wrong group, move it if (entry != null && entry.parentGroup != group) { settings.MoveEntry(entry, group); if (markDirty) { settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryMoved, entry, true); } return true; } // If entry doesn't exist, create it else if (entry == null) { entry = settings.CreateOrMoveEntry(guid, group); if (markDirty) { settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryAdded, entry, true); } return true; } // Entry already exists in correct group return true; } /// /// Save any pending changes to addressable assets /// public static void SaveAddressableAssets() { AssetDatabase.SaveAssets(); } /// /// Add a label to an addressable asset /// /// Path to the asset /// Label to add /// True if the label was successfully added public static bool AddLabelToAsset(string assetPath, string label) { if (string.IsNullOrEmpty(assetPath) || string.IsNullOrEmpty(label)) { return false; } var settings = GetAddressableSettings(false); if (settings == null) { return false; } var guid = AssetDatabase.AssetPathToGUID(assetPath); var entry = settings.FindAssetEntry(guid); if (entry == null) { Debug.LogWarning($"Asset at {assetPath} is not addressable. Add it to a group first before applying labels."); return false; } // Make sure the label exists in the settings if (!settings.GetLabels().Contains(label)) { settings.AddLabel(label); } // Add the label to the entry entry.labels.Add(label); settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryModified, entry, true); return true; } /// /// Ensure an asset is in an addressable group and has the specified label /// /// Path to the asset /// Group to add the asset to /// Label to apply to the asset /// True if the asset was successfully added to the group and labeled public static bool EnsureAssetInGroupWithLabel(string assetPath, string groupName, string label) { bool result = EnsureAssetInGroup(assetPath, groupName); if (result && !string.IsNullOrEmpty(label)) { result = AddLabelToAsset(assetPath, label); } return result; } } }