using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEditor; using UnityEditor.AddressableAssets; using UnityEditor.AddressableAssets.Settings; using UnityEngine; namespace BrewMonster { public static class AddressableTools { public static string _modelPathPrefixToRemove = "Assets/ModelRenderer/Art/Models"; public static string _gfxPathPrefixToRemove = "Assets/ModelRenderer/Art/Gfx"; public static string _sfxPathPrefixToRemove = "Assets/ModelRenderer/Art/sfx"; private const string _terrainPathPrefix = "Assets/ModelRenderer/Art/Terrain"; [MenuItem("Tools/Addressable/Get All Asset Name")] public static void GetAllAssetName() { AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings; if (settings == null) { Debug.LogWarning("Addressable settings not found."); return; } var groupNameToEntries = new Dictionary>(); foreach (var group in settings.groups) { if (group == null) continue; var entries = group.entries; // available in most Addressables versions if (entries == null) continue; string groupName = group.Name; if (!groupNameToEntries.TryGetValue(groupName, out var list)) { list = new List(); groupNameToEntries[groupName] = list; } foreach (var entry in entries) { if (entry == null) continue; list.Add(entry); } } var sb = new StringBuilder(); int totalCount = 0; foreach (var kvp in groupNameToEntries.OrderBy(k => k.Key)) { sb.AppendLine($"[Group] {kvp.Key} ({kvp.Value.Count})"); foreach (var e in kvp.Value.OrderBy(e => e.address)) { sb.AppendLine($"- {e.address}"); } sb.AppendLine(); totalCount += kvp.Value.Count; } if (totalCount == 0) { sb.Append("No addressable assets found."); } Debug.Log(sb.ToString()); EditorUtility.DisplayDialog("Get All Asset Name", $"Printed {totalCount} addressable assets to Console.", "OK"); } [MenuItem("Tools/Addressable/Update Addressable Path For Models")] public static void RemovePrefixFromAddresses() { UpdateAddressableAddressesPath("models", _modelPathPrefixToRemove, ".ecm"); } [MenuItem("Tools/Addressable/Update Addressable Path For Gfx")] public static void UpdateAddressablePathForGfx() { UpdateAddressableAddressesPath("gfx", _gfxPathPrefixToRemove, ".gfx"); } [MenuItem("Tools/Addressable/Update Addressable Path For Sfx")] public static void UpdateAddressablePathForSfx() { UpdateAddressableAddressesPath("sfx", _sfxPathPrefixToRemove, ""); } [MenuItem("Tools/Addressable/Update Addressable Path For a61")] public static void UpdateAddressablePathFora61() { UpdateAddressableAddressesPath("a61", _modelPathPrefixToRemove, ""); } [MenuItem("Tools/Addressable/Update Addressable Path For a61 Terrain")] public static void UpdateAddressablePathFora61Terrain() { UpdateAddressableAddressesPath("a61-terrain", _terrainPathPrefix, ".prefab"); } [MenuItem("Tools/Addressable/Update Addressable Path For world Terrain")] public static void UpdateAddressablePathForWorldTerrain() { UpdateAddressableAddressesPath("world-terrain", _terrainPathPrefix, ".prefab"); } [MenuItem("Tools/Addressable/Update Addressable Path For World")] public static void UpdateAddressablePathForWorld() { UpdateAddressableAddressesPath("world", _modelPathPrefixToRemove, ""); } [MenuItem("Tools/Addressable/Setup Addressable For All Selected Object On Scene (Group: models)")] public static async void SetupAddressableForAllSelectedObjectOnScene() { SetupAddressableForAllSelectedObjectOnScene("models"); } public static async void UpdateAddressableAddressesPath(string groupName, string prefixToRemove, string subfix) { AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings; if (settings == null) { Debug.LogWarning("Addressable settings not found."); return; } int updatedCount = 0; int count = 0; foreach (var group in settings.groups) { if (group == null) continue; if (group.Name != groupName) continue; var entries = group.entries; if (entries == null) continue; foreach (var entry in entries) { count++; // show editor progress bar EditorUtility.DisplayProgressBar("Update Addressable Addresses Path", $"Updating {groupName} -- {count} / {entries.Count}", count / entries.Count); if (entry == null) continue; var address = entry.address; if (string.IsNullOrEmpty(address)) continue; string newAddress = address; // Remove prefix if present if (newAddress.StartsWith(prefixToRemove)) { newAddress = newAddress.Substring(prefixToRemove.Length); if (newAddress.StartsWith("/")) newAddress = newAddress.Substring(1); } // remove the current subfix if present int subfixIndex = newAddress.LastIndexOf('.'); if (subfixIndex != -1) { newAddress = newAddress.Substring(0, subfixIndex); } // apply the new subfix newAddress = newAddress + subfix; // Change suffix from .prefab to .ecm if applicable // if (newAddress.EndsWith(".prefab")) // { // newAddress = newAddress.Substring(0, newAddress.Length - ".prefab".Length) + subfix; // } if (newAddress != address) { entry.SetAddress(newAddress); updatedCount++; } await Task.Delay(1); } } EditorUtility.ClearProgressBar(); if (updatedCount > 0) { EditorUtility.SetDirty(settings); AssetDatabase.SaveAssets(); } Debug.Log($"Update Addressable Addresses Path: Updated {updatedCount} entries."); EditorUtility.DisplayDialog("Update Addressable Addresses Path", $"Updated {updatedCount} entries.", "OK"); } /// /// Sets the address of all addressable assets to match their asset path (relative to Assets folder) /// This allows you to load assets using their file path as the key /// [MenuItem("Tools/Addressable/Set Address To Asset Path")] public static void SetAddressToAssetPath() { AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings; if (settings == null) { Debug.LogWarning("Addressable settings not found."); return; } int updatedCount = 0; var sb = new StringBuilder(); sb.AppendLine("Setting addresses to asset paths:"); sb.AppendLine(); foreach (var group in settings.groups) { if (group == null) continue; var entries = group.entries; if (entries == null) continue; foreach (var entry in entries) { if (entry == null) continue; // Get the asset path (e.g., "Assets/ModelRenderer/Art/Models/...") string assetPath = entry.AssetPath; if (string.IsNullOrEmpty(assetPath)) continue; // Remove "Assets/" prefix to get a cleaner path string newAddress = assetPath; if (newAddress.StartsWith("Assets/")) { newAddress = newAddress.Substring("Assets/".Length); } // Only update if the address is different if (newAddress != entry.address) { string oldAddress = entry.address; entry.SetAddress(newAddress); sb.AppendLine($"[{group.Name}] {oldAddress} �� {newAddress}"); updatedCount++; } } } if (updatedCount > 0) { settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryModified, null, true); AssetDatabase.SaveAssets(); } sb.AppendLine(); sb.AppendLine($"Updated {updatedCount} entries."); Debug.Log(sb.ToString()); EditorUtility.DisplayDialog("Set Address To Asset Path", $"Updated {updatedCount} entries to use their asset paths.", "OK"); } /// /// Prints the address and GUID for all addressable assets - useful for debugging /// [MenuItem("Tools/Addressable/Print Address and GUID")] public static void PrintAddressAndGUID() { AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings; if (settings == null) { Debug.LogWarning("Addressable settings not found."); return; } var sb = new StringBuilder(); sb.AppendLine("Addressable Assets (Address �� GUID �� Path):"); sb.AppendLine(); int totalCount = 0; foreach (var group in settings.groups) { if (group == null) continue; var entries = group.entries; if (entries == null) continue; sb.AppendLine($"[Group: {group.Name}]"); foreach (var entry in entries) { if (entry == null) continue; sb.AppendLine($" Address: {entry.address}"); sb.AppendLine($" GUID: {entry.guid}"); sb.AppendLine($" Path: {entry.AssetPath}"); sb.AppendLine(); totalCount++; } } sb.AppendLine($"Total: {totalCount} addressable assets"); Debug.Log(sb.ToString()); EditorUtility.DisplayDialog("Print Address and GUID", $"Printed {totalCount} addressable assets to Console.", "OK"); } [MenuItem("Tools/Addressable/Set Addressable For Lit Mode In Folder")] public static async void SetAddressableForLitModeInFolder() { Object selected = Selection.activeObject; if (selected == null) { Debug.LogError("Please select a folder."); return; } string folderPath = AssetDatabase.GetAssetPath(selected); if (!AssetDatabase.IsValidFolder(folderPath)) { Debug.LogError("Selected object is not a folder."); return; } // ========================= // Config // ========================= // Prefix path to remove from address string prefixPath = "Assets/ModelRenderer/Art/Models/"; // Addressable group name string groupName = "world"; // ========================= // Addressable Settings // ========================= AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings; if (settings == null) { Debug.LogError("Addressable Settings not found."); return; } AddressableAssetGroup group = settings.FindGroup(groupName); if (group == null) { Debug.LogError($"Addressable group not found: {groupName}"); return; } // ========================= // Search prefabs // ========================= string[] guids = AssetDatabase.FindAssets( "t:Prefab litmodel_", new[] { folderPath } ); Debug.Log($"Found {guids.Length} prefabs"); int addedCount = 0; foreach (string guid in guids) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); // Remove prefix path string address = assetPath; if (address.StartsWith(prefixPath)) { address = address.Substring(prefixPath.Length); } // Remove .prefab extension if (address.EndsWith(".prefab")) { address = address.Substring( 0, address.Length - ".prefab".Length ); } // Create or move entry into group AddressableAssetEntry entry = settings.CreateOrMoveEntry(guid, group); // Set address entry.address = address; addedCount++; // show progress bar EditorUtility.DisplayProgressBar("Set Addressable For Lit Mode In Folder", $"Processing {addedCount} prefabs", addedCount / guids.Length); Debug.Log( $"Added Addressable\n" + $"Path: {assetPath}\n" + $"Address: {address}\n" + $"Group: {groupName}" ); await Task.Delay(1); } EditorUtility.ClearProgressBar(); AssetDatabase.SaveAssets(); Debug.Log($"Finished. Added {addedCount} prefabs to Addressables."); } public static async void SetupAddressableForAllSelectedObjectOnScene(string groupName) { if (string.IsNullOrEmpty(groupName)) { Debug.LogError("Addressable group name is empty."); return; } GameObject[] selectedObjects = Selection.gameObjects; if (selectedObjects == null || selectedObjects.Length == 0) { Debug.LogError("Please select prefab GameObjects in the scene."); return; } // ========================= // Config // ========================= // Prefix path to remove from address string prefixPath = "Assets/ModelRenderer/Art/Models/"; // ========================= // Addressable Settings // ========================= AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings; if (settings == null) { Debug.LogError("Addressable Settings not found."); return; } AddressableAssetGroup group = settings.FindGroup(groupName); if (group == null) { Debug.LogError($"Addressable group not found: {groupName}"); return; } var prefabGuids = new HashSet(); foreach (GameObject selectedObject in selectedObjects) { GameObject prefabInstanceRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(selectedObject); if (prefabInstanceRoot == null) { Debug.LogError($"Selected GameObject is not a prefab instance: {selectedObject.name}"); return; } GameObject sourcePrefab = PrefabUtility.GetCorrespondingObjectFromOriginalSource(prefabInstanceRoot); string assetPath = AssetDatabase.GetAssetPath(sourcePrefab); if (string.IsNullOrEmpty(assetPath) || !assetPath.EndsWith(".prefab")) { Debug.LogError($"Cannot find prefab asset for selected GameObject: {selectedObject.name}"); return; } string guid = AssetDatabase.AssetPathToGUID(assetPath); if (string.IsNullOrEmpty(guid)) { Debug.LogError($"Cannot find GUID for prefab asset: {assetPath}"); return; } prefabGuids.Add(guid); } Debug.Log($"Found {prefabGuids.Count} prefabs"); int addedCount = 0; foreach (string guid in prefabGuids) { string assetPath = AssetDatabase.GUIDToAssetPath(guid); // Remove prefix path string address = assetPath; if (address.StartsWith(prefixPath)) { address = address.Substring(prefixPath.Length); } // Remove .prefab extension if (address.EndsWith(".prefab")) { address = address.Substring( 0, address.Length - ".prefab".Length ); // add .ecm extension address = address + ".ecm"; } // Create or move entry into group AddressableAssetEntry entry = settings.CreateOrMoveEntry(guid, group); // Set address entry.address = address; addedCount++; // show progress bar EditorUtility.DisplayProgressBar( "Setup Addressable For All Selected Object On Scene", $"Processing {addedCount} prefabs", (float)addedCount / prefabGuids.Count ); Debug.Log( $"Added Addressable\n" + $"Path: {assetPath}\n" + $"Address: {address}\n" + $"Group: {groupName}" ); await Task.Delay(1); } EditorUtility.ClearProgressBar(); AssetDatabase.SaveAssets(); Debug.Log($"Finished. Added {addedCount} prefabs to Addressables."); } } }