306 lines
9.3 KiB
C#
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
|