Files
test/Assets/PerfectWorld/Scripts/Utils/Editor/AddressableTools.cs
T
2026-05-26 16:11:24 +07:00

546 lines
15 KiB
C#

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<string, List<AddressableAssetEntry>>();
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<AddressableAssetEntry>();
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");
}
/// <summary>
/// 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
/// </summary>
[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");
}
/// <summary>
/// Prints the address and GUID for all addressable assets - useful for debugging
/// </summary>
[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<string>();
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.");
}
}
}