ZoeAppClass/Assets/Editor/ConfigurarJogosAddressables.cs

306 lines
9.3 KiB
C#

#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.AddressableAssets.Settings.GroupSchemas;
using UnityEngine;
/// <summary>
/// Configura os arquivos de Assets/Jogos como Addressables remotos sem mover nenhum arquivo.
/// Compatível com Unity 2019.3 e Addressables 1.1.x.
/// </summary>
public static class ConfigurarJogosAddressables
{
private const string JogosRoot = "Assets/Jogos";
private const string GroupPrefix = "RemoteJogo_";
private const string LabelPrefix = "jogo_";
[MenuItem("Tools/Zoe/Configurar Assets-Jogos como Addressables")]
public static void Configurar()
{
if (EditorApplication.isPlayingOrWillChangePlaymode)
{
Debug.LogError("Saia do Play Mode antes de configurar os Addressables.");
return;
}
if (!AssetDatabase.IsValidFolder(JogosRoot))
{
Debug.LogError("A pasta não foi encontrada: " + JogosRoot);
return;
}
AddressableAssetSettings settings =
AddressableAssetSettingsDefaultObject.GetSettings(true);
if (settings == null)
{
Debug.LogError("Não foi possível criar ou carregar AddressableAssetSettings.");
return;
}
Dictionary<string, AddressableAssetGroup> groups =
new Dictionary<string, AddressableAssetGroup>();
string[] guids = AssetDatabase.FindAssets(string.Empty, new[] { JogosRoot });
int configured = 0;
int ignored = 0;
int errors = 0;
try
{
AssetDatabase.StartAssetEditing();
for (int i = 0; i < guids.Length; i++)
{
string guid = guids[i];
string path = AssetDatabase.GUIDToAssetPath(guid).Replace('\\', '/');
EditorUtility.DisplayProgressBar(
"Configurando Assets/Jogos",
path,
guids.Length == 0 ? 1f : (float)i / guids.Length
);
if (ShouldIgnore(path))
{
ignored++;
continue;
}
string gameKey = GetTopLevelFolder(path);
string safeGameKey = Sanitize(gameKey);
string groupName = GroupPrefix + safeGameKey;
string labelName = LabelPrefix + safeGameKey.ToLowerInvariant();
AddressableAssetGroup group;
if (!groups.TryGetValue(groupName, out group))
{
group = GetOrCreateRemoteGroup(settings, groupName);
groups.Add(groupName, group);
settings.AddLabel(labelName);
}
try
{
AddressableAssetEntry entry =
settings.CreateOrMoveEntry(guid, group, false, false);
if (entry == null)
{
errors++;
Debug.LogError("Falha ao criar entrada Addressable: " + path);
continue;
}
entry.address = BuildAddress(path);
entry.SetLabel(labelName, true, true);
configured++;
}
catch (Exception ex)
{
errors++;
Debug.LogError("Erro em " + path + ": " + ex.Message);
}
}
}
finally
{
AssetDatabase.StopAssetEditing();
EditorUtility.ClearProgressBar();
}
settings.BuildRemoteCatalog = true;
settings.RemoteCatalogBuildPath.SetVariableByName(
settings,
AddressableAssetSettings.kRemoteBuildPath
);
settings.RemoteCatalogLoadPath.SetVariableByName(
settings,
AddressableAssetSettings.kRemoteLoadPath
);
EditorUtility.SetDirty(settings);
foreach (AddressableAssetGroup group in groups.Values)
EditorUtility.SetDirty(group);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
string result =
"Configuração concluída." +
"\n\nGrupos criados/atualizados: " + groups.Count +
"\nAssets configurados: " + configured +
"\nArquivos ignorados: " + ignored +
"\nErros: " + errors +
"\n\nNenhum arquivo foi movido de Assets/Jogos.";
Debug.Log(result.Replace("\n", " | "));
EditorUtility.DisplayDialog("Addressables - Assets/Jogos", result, "OK");
}
[MenuItem("Tools/Zoe/Validar Assets-Jogos Addressables")]
public static void Validar()
{
AddressableAssetSettings settings =
AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
Debug.LogError("AddressableAssetSettings não encontrado.");
return;
}
int groups = 0;
int entries = 0;
int withoutLabel = 0;
StringBuilder details = new StringBuilder();
foreach (AddressableAssetGroup group in settings.groups)
{
if (group == null || !group.Name.StartsWith(GroupPrefix))
continue;
groups++;
int groupEntries = 0;
foreach (AddressableAssetEntry entry in group.entries)
{
if (entry == null) continue;
entries++;
groupEntries++;
bool hasGameLabel = false;
foreach (string label in entry.labels)
{
if (label.StartsWith(LabelPrefix))
{
hasGameLabel = true;
break;
}
}
if (!hasGameLabel)
withoutLabel++;
}
details.AppendLine(group.Name + ": " + groupEntries + " assets");
}
string message =
"Grupos: " + groups +
"\nEntradas: " + entries +
"\nSem label jogo_: " + withoutLabel +
"\n\n" + details;
Debug.Log(message.Replace("\n", " | "));
EditorUtility.DisplayDialog("Validação Assets/Jogos", message, "OK");
}
private static AddressableAssetGroup GetOrCreateRemoteGroup(
AddressableAssetSettings settings,
string groupName)
{
AddressableAssetGroup group = settings.FindGroup(groupName);
if (group == null)
{
group = settings.CreateGroup(
groupName,
false,
false,
false,
null,
typeof(BundledAssetGroupSchema),
typeof(ContentUpdateGroupSchema)
);
}
BundledAssetGroupSchema bundled =
group.GetSchema<BundledAssetGroupSchema>();
if (bundled == null)
bundled = group.AddSchema<BundledAssetGroupSchema>();
bundled.BuildPath.SetVariableByName(
settings,
AddressableAssetSettings.kRemoteBuildPath
);
bundled.LoadPath.SetVariableByName(
settings,
AddressableAssetSettings.kRemoteLoadPath
);
bundled.BundleMode =
BundledAssetGroupSchema.BundlePackingMode.PackTogether;
ContentUpdateGroupSchema update =
group.GetSchema<ContentUpdateGroupSchema>();
if (update == null)
group.AddSchema<ContentUpdateGroupSchema>();
EditorUtility.SetDirty(bundled);
return group;
}
private static bool ShouldIgnore(string path)
{
if (string.IsNullOrEmpty(path)) return true;
if (AssetDatabase.IsValidFolder(path)) return true;
Type type = AssetDatabase.GetMainAssetTypeAtPath(path);
if (type == typeof(MonoScript)) return true;
string extension = Path.GetExtension(path).ToLowerInvariant();
return extension == ".cs" ||
extension == ".dll" ||
extension == ".asmdef" ||
extension == ".asmref" ||
extension == ".meta";
}
private static string GetTopLevelFolder(string path)
{
string relative = path.Substring(JogosRoot.Length).TrimStart('/');
int slash = relative.IndexOf('/');
if (slash <= 0)
return "Comum";
return relative.Substring(0, slash);
}
private static string BuildAddress(string path)
{
string relative = path.Substring(JogosRoot.Length).TrimStart('/');
string extension = Path.GetExtension(relative);
if (!string.IsNullOrEmpty(extension))
relative = relative.Substring(0, relative.Length - extension.Length);
return "Jogos/" + relative.Replace('\\', '/');
}
private static string Sanitize(string value)
{
if (string.IsNullOrEmpty(value)) return "Comum";
StringBuilder result = new StringBuilder(value.Length);
for (int i = 0; i < value.Length; i++)
{
char c = value[i];
result.Append(char.IsLetterOrDigit(c) || c == '_' || c == '-' ? c : '_');
}
return result.ToString();
}
}
#endif