using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine;
namespace AutoGroupGenerator
{
///
/// Command queue that synchronizes Addressables data with AutoGroupGenerator definitions.
///
internal class AddressableCleanupCommandQueue : CommandQueue
{
#region Static Methods
private static HashSet GetAddressableScenePaths()
{
var paths = new HashSet();
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
return paths;
}
foreach (var entry in AddressableUtil.GetAddressableEntries())
{
if (entry.MainAssetType == typeof(SceneAsset))
{
string assetPath = AssetDatabase.GUIDToAssetPath(entry.guid);
if (!string.IsNullOrEmpty(assetPath))
{
paths.Add(assetPath);
}
}
}
return paths;
}
#endregion
#region Fields
private readonly DataContainer m_DataContainer;
private int m_EmptyGroupRemoved;
private int m_UnnecessaryEntriesRemoved;
HashSet m_AddressableScenes;
List m_RemovedEntriesReport;
List m_RemovedGroupsReport;
#endregion
#region Properties
private AddressableAssetSettings AddressableSettings => AddressableAssetSettingsDefaultObject.Settings;
bool IsReportEnabled => m_DataContainer.Settings.ProcessReport.HasFlag(ProcessStepReport.Cleanup);
#endregion
#region Methods
public AddressableCleanupCommandQueue(DataContainer dataContainer)
{
m_DataContainer = dataContainer;
Title = nameof(AddressableCleanupCommandQueue);
}
public override void PreExecute()
{
ClearQueue();
AddCommand(StartAssetEditing);
AddCommand(RemoveUnusedEntries);
AddCommand(RemoveEmptyAddressableGroups);
AddCommand(RemoveAddressableScenesFromBuildProfile);
AddCommand(SortGroups);
AddCommand(StopAssetEditing);
}
public override void PostExecute()
{
SaveOutputReportToFile();
m_RemovedEntriesReport = null;
m_RemovedGroupsReport = null;
m_AddressableScenes = null;
}
private void StartAssetEditing()
{
AssetDatabase.StartAssetEditing();
m_DataContainer.AssetEditingInProgress = true;
}
private void RemoveUnusedEntries()
{
if (!m_DataContainer.Settings.RemoveUnnecessaryEntries)
{
return;
}
var allNodesInGroupLayouts = new HashSet();
foreach (var groupLayout in m_DataContainer.GroupLayout.Values)
{
foreach (var node in groupLayout.Nodes)
{
allNodesInGroupLayouts.Add(node.Guid.ToString());
}
}
var entriesToRemove = new List();
m_RemovedEntriesReport = new List();
foreach (var entry in AddressableUtil.GetAddressableEntries())
{
var entryGuid = entry.guid;
if(!allNodesInGroupLayouts.Contains(entryGuid))
{
entriesToRemove.Add(entryGuid);
if(IsReportEnabled)
m_RemovedEntriesReport.Add(entry.AssetPath);
}
}
foreach (var guid in entriesToRemove)
{
AddressableSettings.RemoveAssetEntry(guid, false);
m_UnnecessaryEntriesRemoved++;
}
}
private void RemoveEmptyAddressableGroups()
{
if (!m_DataContainer.Settings.RemoveEmptyGroups)
{
return;
}
IEnumerable groupsToRemove = AddressableSettings.groups
.Where(CanRemoveGroup).ToList();
if (IsReportEnabled)
m_RemovedGroupsReport = groupsToRemove.Select(g => g.Name).ToList();
foreach (var group in groupsToRemove)
{
RemoveGroupQuick(group);
m_EmptyGroupRemoved++;
}
}
void RemoveGroupQuick(AddressableAssetGroup group)
{
if (group == null)
return;
group.ClearSchemas(true);
AddressableSettings.groups.Remove(group);
if (group != null)
{
if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(group, out var guidOfGroup, out long localId))
{
var groupPath = AssetDatabase.GUIDToAssetPath(guidOfGroup);
if (!string.IsNullOrEmpty(groupPath))
AssetDatabase.DeleteAsset(groupPath);
}
}
}
private bool CanRemoveGroup(AddressableAssetGroup group)
{
return group != null &&
group.entries.Count == 0 &&
!group.ReadOnly &&
group != AddressableSettings.DefaultGroup;
}
private void RemoveAddressableScenesFromBuildProfile()
{
if (!m_DataContainer.Settings.RemoveAddressableScenesFromBuildProfile)
{
return;
}
m_AddressableScenes = GetAddressableScenePaths();
List originalScenes = EditorBuildSettings.scenes.ToList();
int removedCount = 0;
var updatedScenes = new List();
foreach (EditorBuildSettingsScene scene in originalScenes)
{
if (!m_AddressableScenes.Contains(scene.path))
{
updatedScenes.Add(scene);
}
else
{
removedCount++;
}
}
if (removedCount > 0)
{
EditorBuildSettings.scenes = updatedScenes.ToArray();
}
}
private void SortGroups()
{
if (!m_DataContainer.Settings.SortAddressableGroups)
{
return;
}
AddressableSettings.groups.Sort(ComparisonLogic);
int ComparisonLogic(AddressableAssetGroup a, AddressableAssetGroup b)
{
return string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase);
}
}
private void StopAssetEditing()
{
AssetDatabase.StopAssetEditing();
m_DataContainer.AssetEditingInProgress = false;
AssetDatabase.Refresh();
}
void SaveOutputReportToFile()
{
if (!IsReportEnabled)
return;
var reporter = GetType();
if (m_DataContainer.Settings.RemoveUnnecessaryEntries)
{
var summary = $"Unused Entries Removed ({m_RemovedEntriesReport.Count})";
object data = new List(m_RemovedEntriesReport);
JsonReport.SaveJsonReport(reporter, reporter.Name + "_UnusedEntriesRemoved", summary, data);
}
if (m_DataContainer.Settings.RemoveEmptyGroups)
{
var summary = $"Empty Groups Removed ({m_RemovedGroupsReport.Count})";
object data = new List(m_RemovedGroupsReport);
JsonReport.SaveJsonReport(reporter, reporter.Name + "_EmptyGroupsRemoved", summary, data);
}
if (m_DataContainer.Settings.RemoveAddressableScenesFromBuildProfile)
{
var summary = $"Scenes Removed from Build Profile ({m_AddressableScenes.Count})";
object data = new List(m_AddressableScenes);
JsonReport.SaveJsonReport(reporter, reporter.Name + "_ScenesRemoved", summary, data);
}
}
#endregion
}
}