diff --git a/Assets/SmartAddresser/Editor/Core/Models/Services/ApplyLayoutRuleService.cs b/Assets/SmartAddresser/Editor/Core/Models/Services/ApplyLayoutRuleService.cs index 1d3353f..3eb3c51 100644 --- a/Assets/SmartAddresser/Editor/Core/Models/Services/ApplyLayoutRuleService.cs +++ b/Assets/SmartAddresser/Editor/Core/Models/Services/ApplyLayoutRuleService.cs @@ -15,10 +15,12 @@ public sealed class ApplyLayoutRuleService private readonly LayoutRule _layoutRule; private readonly IVersionExpressionParser _versionExpressionParser; - public ApplyLayoutRuleService(LayoutRule layoutRule, + public ApplyLayoutRuleService( + LayoutRule layoutRule, IVersionExpressionParser versionExpressionParser, IAddressableAssetSettingsAdapter addressableSettingsAdapter, - IAssetDatabaseAdapter assetDatabaseAdapter) + IAssetDatabaseAdapter assetDatabaseAdapter + ) { _layoutRule = layoutRule; _addressableSettingsAdapter = addressableSettingsAdapter; @@ -42,7 +44,7 @@ public void Setup() /// /// Apply the layout rule to the addressable settings for all assets. /// - public void UpdateAllEntries() + public void ApplyAll() { Setup(); @@ -56,14 +58,43 @@ public void UpdateAllEntries() if (!result) removeTargetAssetGuids.Add(guid); } - - // Remove all entries that are not under control of this layout rule (if the entry is exists). + + // If the address is not assigned by the LayoutRule and the entry belongs to the AddressableGroup under Control, remove the entry. + var controlGroupNames = _layoutRule + .AddressRules + .Where(x => x.Control.Value) + .Select(x => x.AddressableGroup.Name) + .ToArray(); foreach (var guid in removeTargetAssetGuids) - _addressableSettingsAdapter.RemoveEntry(guid, false); - + { + var entryAdapter = _addressableSettingsAdapter.FindAssetEntry(guid); + if (entryAdapter == null) + continue; + + if (controlGroupNames.Contains(entryAdapter.GroupName)) + _addressableSettingsAdapter.RemoveEntry(guid, false); + } + _addressableSettingsAdapter.InvokeBatchModificationEvent(); } + public void Apply(string assetGuid, bool doSetup, bool invokeModificationEvent, string versionExpression = null) + { + var result = TryAddEntry(assetGuid, doSetup, invokeModificationEvent, versionExpression); + + // If the address is not assigned by the LayoutRule and the entry belongs to the AddressableGroup under Control, remove the entry. + var controlGroupNames = _layoutRule + .AddressRules + .Where(x => x.Control.Value) + .Select(x => x.AddressableGroup.Name); + if (!result) + { + var entryAdapter = _addressableSettingsAdapter.FindAssetEntry(assetGuid); + if (entryAdapter != null && controlGroupNames.Contains(entryAdapter.GroupName)) + _addressableSettingsAdapter.RemoveEntry(assetGuid, invokeModificationEvent); + } + } + /// /// Apply the layout rule to the addressable settings. /// @@ -82,16 +113,24 @@ public void UpdateAllEntries() /// If the layout rule was applied to the addressable asset system, return true. /// Returns false if no suitable layout rule was found. /// - public bool TryAddEntry(string assetGuid, bool doSetup, bool invokeModificationEvent, string versionExpression = null) + private bool TryAddEntry( + string assetGuid, + bool doSetup, + bool invokeModificationEvent, + string versionExpression = null + ) { var assetPath = _assetDatabaseAdapter.GUIDToAssetPath(assetGuid); var assetType = _assetDatabaseAdapter.GetMainAssetTypeAtPath(assetPath); var isFolder = _assetDatabaseAdapter.IsValidFolder(assetPath); // If the layout rule was not found, return false. - if (!_layoutRule.TryProvideAddressAndAddressableGroup(assetPath, assetType, isFolder, doSetup, - out var address, - out var addressableGroup)) + if (!_layoutRule.TryProvideAddressAndAddressableGroup(assetPath, + assetType, + isFolder, + doSetup, + out var address, + out var addressableGroup)) return false; // If the layout rule is found but the addressable asset group has already been destroyed, return false. @@ -117,7 +156,8 @@ public bool TryAddEntry(string assetGuid, bool doSetup, bool invokeModificationE } // Set group and address. - var entryAdapter = _addressableSettingsAdapter.CreateOrMoveEntry(addressableGroupName, assetGuid, invokeModificationEvent); + var entryAdapter = + _addressableSettingsAdapter.CreateOrMoveEntry(addressableGroupName, assetGuid, invokeModificationEvent); entryAdapter.SetAddress(address); // Add labels to addressable settings if not exists. @@ -138,7 +178,7 @@ public bool TryAddEntry(string assetGuid, bool doSetup, bool invokeModificationE return true; } - + public void InvokeBatchModificationEvent() { _addressableSettingsAdapter.InvokeBatchModificationEvent(); diff --git a/Assets/SmartAddresser/Editor/Core/Tools/Addresser/LayoutRuleEditor/LayoutRuleEditorPresenter.cs b/Assets/SmartAddresser/Editor/Core/Tools/Addresser/LayoutRuleEditor/LayoutRuleEditorPresenter.cs index 21ab967..48cacc3 100644 --- a/Assets/SmartAddresser/Editor/Core/Tools/Addresser/LayoutRuleEditor/LayoutRuleEditorPresenter.cs +++ b/Assets/SmartAddresser/Editor/Core/Tools/Addresser/LayoutRuleEditor/LayoutRuleEditorPresenter.cs @@ -276,7 +276,7 @@ void Apply() var addressableSettingsAdapter = new AddressableAssetSettingsAdapter(addressableSettings); var applyService = new ApplyLayoutRuleService(layoutRule, versionExpressionParser, addressableSettingsAdapter, assetDatabaseAdapter); - applyService.UpdateAllEntries(); + applyService.ApplyAll(); } }); diff --git a/Assets/SmartAddresser/Editor/Core/Tools/Addresser/LayoutRuleEditor/LayoutRuleEditorWindow.cs b/Assets/SmartAddresser/Editor/Core/Tools/Addresser/LayoutRuleEditor/LayoutRuleEditorWindow.cs index 72b1290..bcb5e8f 100644 --- a/Assets/SmartAddresser/Editor/Core/Tools/Addresser/LayoutRuleEditor/LayoutRuleEditorWindow.cs +++ b/Assets/SmartAddresser/Editor/Core/Tools/Addresser/LayoutRuleEditor/LayoutRuleEditorWindow.cs @@ -81,7 +81,7 @@ private void OnLostFocus() var addressableSettingsAdapter = new AddressableAssetSettingsAdapter(addressableSettings); var applyService = new ApplyLayoutRuleService(layoutRule, versionExpressionParser, addressableSettingsAdapter, assetDatabaseAdapter); - applyService.UpdateAllEntries(); + applyService.ApplyAll(); } _hasAnyDataChanged = false; diff --git a/Assets/SmartAddresser/Editor/Core/Tools/CLI/SmartAddresserCLI.cs b/Assets/SmartAddresser/Editor/Core/Tools/CLI/SmartAddresserCLI.cs index 8576776..9b93bd6 100644 --- a/Assets/SmartAddresser/Editor/Core/Tools/CLI/SmartAddresserCLI.cs +++ b/Assets/SmartAddresser/Editor/Core/Tools/CLI/SmartAddresserCLI.cs @@ -80,7 +80,7 @@ public static void ApplyRules() // Apply the layout rules to the addressable asset system. var applyService = new ApplyLayoutRuleService(layoutRule, versionExpressionParser, addressableSettingsAdapter, assetDatabaseAdapter); - applyService.UpdateAllEntries(); + applyService.ApplyAll(); EditorApplication.Exit(ErrorLevelNone); } diff --git a/Assets/SmartAddresser/Editor/Core/Tools/Importer/SmartAddresserAssetPostProcessor.cs b/Assets/SmartAddresser/Editor/Core/Tools/Importer/SmartAddresserAssetPostProcessor.cs index 0044463..74ee3b1 100644 --- a/Assets/SmartAddresser/Editor/Core/Tools/Importer/SmartAddresserAssetPostProcessor.cs +++ b/Assets/SmartAddresser/Editor/Core/Tools/Importer/SmartAddresserAssetPostProcessor.cs @@ -36,13 +36,13 @@ private static void OnPostprocessAllAssets(string[] importedAssetPaths, string[] foreach (var importedAssetPath in importedAssetPaths) { var guid = AssetDatabase.AssetPathToGUID(importedAssetPath); - applyService.TryAddEntry(guid, false, false, versionExpression); + applyService.Apply(guid, false, true, versionExpression); } foreach (var movedAssetPath in movedAssetPaths) { var guid = AssetDatabase.AssetPathToGUID(movedAssetPath); - applyService.TryAddEntry(guid, false, false, versionExpression); + applyService.Apply(guid, false, true, versionExpression); } applyService.InvokeBatchModificationEvent(); diff --git a/Assets/SmartAddresser/Editor/Core/Tools/Shared/SmartAddresserProjectSettingsProvider.cs b/Assets/SmartAddresser/Editor/Core/Tools/Shared/SmartAddresserProjectSettingsProvider.cs index fe313bb..08fec1c 100644 --- a/Assets/SmartAddresser/Editor/Core/Tools/Shared/SmartAddresserProjectSettingsProvider.cs +++ b/Assets/SmartAddresser/Editor/Core/Tools/Shared/SmartAddresserProjectSettingsProvider.cs @@ -53,7 +53,7 @@ public override void OnGUI(string searchContext) var addressableSettingsAdapter = new AddressableAssetSettingsAdapter(addressableSettings); var applyService = new ApplyLayoutRuleService(layoutRule, versionExpressionParser, addressableSettingsAdapter, assetDatabaseAdapter); - applyService.UpdateAllEntries(); + applyService.ApplyAll(); } else { diff --git a/Assets/SmartAddresser/Tests/Editor/Core/Models/Services/ApplyLayoutRuleServiceTest.cs b/Assets/SmartAddresser/Tests/Editor/Core/Models/Services/ApplyLayoutRuleServiceTest.cs index 6599310..f5b3999 100644 --- a/Assets/SmartAddresser/Tests/Editor/Core/Models/Services/ApplyLayoutRuleServiceTest.cs +++ b/Assets/SmartAddresser/Tests/Editor/Core/Models/Services/ApplyLayoutRuleServiceTest.cs @@ -35,12 +35,13 @@ public void CreateEntry() var assetDatabaseAdapter = CreateSingleEntryAssetDatabaseAdapter(assetGuid, TestAssetPath, assetType, isFolder); var addressableSettingsAdapter = new FakeAddressableAssetSettingsAdapter(); - var service = new ApplyLayoutRuleService(layoutRule, new UnityVersionExpressionParser(), - addressableSettingsAdapter, assetDatabaseAdapter); + var service = new ApplyLayoutRuleService(layoutRule, + new UnityVersionExpressionParser(), + addressableSettingsAdapter, + assetDatabaseAdapter); - var result = service.TryAddEntry(assetGuid, true, false); + service.Apply(assetGuid, true, false); var assetEntry = addressableSettingsAdapter.FindAssetEntry(assetGuid); - Assert.That(result, Is.True); Assert.That(assetEntry, Is.Not.Null); Assert.That(assetEntry.GroupName, Is.EqualTo(TestAddressableGroupName)); Assert.That(assetEntry.Address, Is.EqualTo(TestAssetName)); @@ -57,39 +58,106 @@ public void PreSetup() var assetDatabaseAdapter = CreateSingleEntryAssetDatabaseAdapter(assetGuid, TestAssetPath, assetType, isFolder); var addressableSettingsAdapter = new FakeAddressableAssetSettingsAdapter(); - var service = new ApplyLayoutRuleService(layoutRule, new UnityVersionExpressionParser(), - addressableSettingsAdapter, assetDatabaseAdapter); + var service = new ApplyLayoutRuleService(layoutRule, + new UnityVersionExpressionParser(), + addressableSettingsAdapter, + assetDatabaseAdapter); service.Setup(); - var result = service.TryAddEntry(assetGuid, false, false); + service.Apply(assetGuid, false, false); var assetEntry = addressableSettingsAdapter.FindAssetEntry(assetGuid); - Assert.That(result, Is.True); Assert.That(assetEntry, Is.Not.Null); Assert.That(assetEntry.GroupName, Is.EqualTo(TestAddressableGroupName)); Assert.That(assetEntry.Address, Is.EqualTo(TestAssetName)); } [Test] - public void MatchedLayoutRuleNotExists_ReturnFalse() + public void AddressIsNotAssignedAndBelongingToControlGroup_Removed() { var assetGuid = GUID.Generate().ToString(); var assetType = typeof(ScriptableObject); const bool isFolder = false; - var layoutRule = CreateLayoutRule(TestAddressableGroupName, "Assets/NotMatchedAssetPath.asset", + var layoutRule = CreateLayoutRule(TestAddressableGroupName, TestAssetPath, PartialAssetPathType.FileName); + var assetDatabaseAdapter = + CreateSingleEntryAssetDatabaseAdapter(assetGuid, TestAssetPath, assetType, isFolder); + var addressableSettingsAdapter = new FakeAddressableAssetSettingsAdapter(); + var service = new ApplyLayoutRuleService(layoutRule, + new UnityVersionExpressionParser(), + addressableSettingsAdapter, + assetDatabaseAdapter); + + service.Apply(assetGuid, true, false); + var assetEntry = addressableSettingsAdapter.FindAssetEntry(assetGuid); + Assert.That(assetEntry, Is.Not.Null); + + // Clear the asset groups + foreach (var addressRule in layoutRule.AddressRules) + addressRule.AssetGroups.Clear(); + // Apply again + service.Setup(); + service.Apply(assetGuid, true, false); + // The entry should be removed. + assetEntry = addressableSettingsAdapter.FindAssetEntry(assetGuid); + Assert.That(assetEntry, Is.Null); + } + + [Test] + public void AddressIsNotAssignedAndBelongingToNotControlGroup_NotRemoved() + { + var assetGuid = GUID.Generate().ToString(); + var assetType = typeof(ScriptableObject); + const bool isFolder = false; + + var layoutRule = CreateLayoutRule(TestAddressableGroupName, TestAssetPath, PartialAssetPathType.FileName); + var assetDatabaseAdapter = + CreateSingleEntryAssetDatabaseAdapter(assetGuid, TestAssetPath, assetType, isFolder); + var addressableSettingsAdapter = new FakeAddressableAssetSettingsAdapter(); + var service = new ApplyLayoutRuleService(layoutRule, + new UnityVersionExpressionParser(), + addressableSettingsAdapter, + assetDatabaseAdapter); + + service.Apply(assetGuid, true, false); + var assetEntry = addressableSettingsAdapter.FindAssetEntry(assetGuid); + Assert.That(assetEntry, Is.Not.Null); + + // Clear the asset groups + foreach (var addressRule in layoutRule.AddressRules) + addressRule.Control.Value = false; + // Apply again + service.Setup(); + service.Apply(assetGuid, true, false); + // The entry should not be removed. + assetEntry = addressableSettingsAdapter.FindAssetEntry(assetGuid); + Assert.That(assetEntry, Is.Not.Null); + } + + [Test] + public void MatchedLayoutRuleNotExists_EntryIsNull() + { + var assetGuid = GUID.Generate().ToString(); + var assetType = typeof(ScriptableObject); + const bool isFolder = false; + + var layoutRule = CreateLayoutRule(TestAddressableGroupName, + "Assets/NotMatchedAssetPath.asset", PartialAssetPathType.FileName); var assetDatabaseAdapter = CreateSingleEntryAssetDatabaseAdapter(assetGuid, TestAssetPath, assetType, isFolder); var addressableSettingsAdapter = new FakeAddressableAssetSettingsAdapter(); - var service = new ApplyLayoutRuleService(layoutRule, new UnityVersionExpressionParser(), - addressableSettingsAdapter, assetDatabaseAdapter); + var service = new ApplyLayoutRuleService(layoutRule, + new UnityVersionExpressionParser(), + addressableSettingsAdapter, + assetDatabaseAdapter); - var result = service.TryAddEntry(assetGuid, true, false); - Assert.That(result, Is.False); + service.Apply(assetGuid, true, false); + var assetEntry = addressableSettingsAdapter.FindAssetEntry(assetGuid); + Assert.That(assetEntry, Is.Null); } [Test] - public void GroupIsNull_ReturnFalse() + public void GroupIsNull_EntryIsNull() { var assetGuid = GUID.Generate().ToString(); var assetType = typeof(ScriptableObject); @@ -100,11 +168,14 @@ public void GroupIsNull_ReturnFalse() var assetDatabaseAdapter = CreateSingleEntryAssetDatabaseAdapter(assetGuid, TestAssetPath, assetType, isFolder); var addressableSettingsAdapter = new FakeAddressableAssetSettingsAdapter(); - var service = new ApplyLayoutRuleService(layoutRule, new UnityVersionExpressionParser(), - addressableSettingsAdapter, assetDatabaseAdapter); + var service = new ApplyLayoutRuleService(layoutRule, + new UnityVersionExpressionParser(), + addressableSettingsAdapter, + assetDatabaseAdapter); - var result = service.TryAddEntry(assetGuid, true, false); - Assert.That(result, Is.False); + service.Apply(assetGuid, true, false); + var assetEntry = addressableSettingsAdapter.FindAssetEntry(assetGuid); + Assert.That(assetEntry, Is.Null); } [Test] @@ -114,39 +185,47 @@ public void VersionIsSatisfied() var assetType = typeof(ScriptableObject); const bool isFolder = false; - var layoutRule = CreateLayoutRule(TestAddressableGroupName, TestAssetPath, PartialAssetPathType.FileName, + var layoutRule = CreateLayoutRule(TestAddressableGroupName, + TestAssetPath, + PartialAssetPathType.FileName, version: "1.2.3"); var assetDatabaseAdapter = CreateSingleEntryAssetDatabaseAdapter(assetGuid, TestAssetPath, assetType, isFolder); var addressableSettingsAdapter = new FakeAddressableAssetSettingsAdapter(); - var service = new ApplyLayoutRuleService(layoutRule, new UnityVersionExpressionParser(), - addressableSettingsAdapter, assetDatabaseAdapter); + var service = new ApplyLayoutRuleService(layoutRule, + new UnityVersionExpressionParser(), + addressableSettingsAdapter, + assetDatabaseAdapter); - var result = service.TryAddEntry(assetGuid, true, false, "[1.2.3,1.2.4)"); + service.Apply(assetGuid, true, false, "[1.2.3,1.2.4)"); var assetEntry = addressableSettingsAdapter.FindAssetEntry(assetGuid); - Assert.That(result, Is.True); Assert.That(assetEntry, Is.Not.Null); Assert.That(assetEntry.GroupName, Is.EqualTo(TestAddressableGroupName)); Assert.That(assetEntry.Address, Is.EqualTo(TestAssetName)); } [Test] - public void VersionIsNotSatisfied_ReturnFalse() + public void VersionIsNotSatisfied_EntryIsNull() { var assetGuid = GUID.Generate().ToString(); var assetType = typeof(ScriptableObject); const bool isFolder = false; - var layoutRule = CreateLayoutRule(TestAddressableGroupName, TestAssetPath, PartialAssetPathType.FileName, + var layoutRule = CreateLayoutRule(TestAddressableGroupName, + TestAssetPath, + PartialAssetPathType.FileName, version: "1.2.3"); var assetDatabaseAdapter = CreateSingleEntryAssetDatabaseAdapter(assetGuid, TestAssetPath, assetType, isFolder); var addressableSettingsAdapter = new FakeAddressableAssetSettingsAdapter(); - var service = new ApplyLayoutRuleService(layoutRule, new UnityVersionExpressionParser(), - addressableSettingsAdapter, assetDatabaseAdapter); + var service = new ApplyLayoutRuleService(layoutRule, + new UnityVersionExpressionParser(), + addressableSettingsAdapter, + assetDatabaseAdapter); - var result = service.TryAddEntry(assetGuid, true, false, "(1.2.3,1.3)"); - Assert.That(result, Is.False); + service.Apply(assetGuid, true, false, "(1.2.3,1.3)"); + var assetEntry = addressableSettingsAdapter.FindAssetEntry(assetGuid); + Assert.That(assetEntry, Is.Null); } [Test] @@ -156,15 +235,19 @@ public void InvalidVersionExpression_Exception() var assetType = typeof(ScriptableObject); const bool isFolder = false; - var layoutRule = CreateLayoutRule(TestAddressableGroupName, TestAssetPath, PartialAssetPathType.FileName, + var layoutRule = CreateLayoutRule(TestAddressableGroupName, + TestAssetPath, + PartialAssetPathType.FileName, version: "1.2.3"); var assetDatabaseAdapter = CreateSingleEntryAssetDatabaseAdapter(assetGuid, TestAssetPath, assetType, isFolder); var addressableSettingsAdapter = new FakeAddressableAssetSettingsAdapter(); - var service = new ApplyLayoutRuleService(layoutRule, new UnityVersionExpressionParser(), - addressableSettingsAdapter, assetDatabaseAdapter); + var service = new ApplyLayoutRuleService(layoutRule, + new UnityVersionExpressionParser(), + addressableSettingsAdapter, + assetDatabaseAdapter); - Assert.That(() => service.TryAddEntry(assetGuid, true, false, "(1.2.3, 1.3)"), Throws.InstanceOf()); + Assert.That(() => service.Apply(assetGuid, true, false, "(1.2.3, 1.3)"), Throws.InstanceOf()); } [Test] @@ -175,24 +258,31 @@ public void SetLabel() const bool isFolder = false; const string LabelName = "TestLabel"; - var layoutRule = CreateLayoutRule(TestAddressableGroupName, TestAssetPath, PartialAssetPathType.FileName, + var layoutRule = CreateLayoutRule(TestAddressableGroupName, + TestAssetPath, + PartialAssetPathType.FileName, LabelName); var assetDatabaseAdapter = CreateSingleEntryAssetDatabaseAdapter(assetGuid, TestAssetPath, assetType, isFolder); var addressableSettingsAdapter = new FakeAddressableAssetSettingsAdapter(); - var service = new ApplyLayoutRuleService(layoutRule, new UnityVersionExpressionParser(), - addressableSettingsAdapter, assetDatabaseAdapter); + var service = new ApplyLayoutRuleService(layoutRule, + new UnityVersionExpressionParser(), + addressableSettingsAdapter, + assetDatabaseAdapter); - var result = service.TryAddEntry(assetGuid, true, false); + service.Apply(assetGuid, true, false); var assetEntry = addressableSettingsAdapter.FindAssetEntry(assetGuid); - Assert.That(result, Is.True); Assert.That(assetEntry, Is.Not.Null); Assert.That(assetEntry.Labels.Count, Is.EqualTo(1)); Assert.That(assetEntry.Labels.First(), Is.EqualTo(LabelName)); } - private static FakeAssetDatabaseAdapter CreateSingleEntryAssetDatabaseAdapter(string guid, string assetPath, - Type assetType, bool isValidFolder) + private static FakeAssetDatabaseAdapter CreateSingleEntryAssetDatabaseAdapter( + string guid, + string assetPath, + Type assetType, + bool isValidFolder + ) { var assetDatabaseAdapter = new FakeAssetDatabaseAdapter(); var entry = new FakeAssetDatabaseAdapter.Entry(guid, assetPath, assetType, isValidFolder); @@ -200,16 +290,26 @@ private static FakeAssetDatabaseAdapter CreateSingleEntryAssetDatabaseAdapter(st return assetDatabaseAdapter; } - private static LayoutRule CreateLayoutRule(string addressableGroupName, string regexAssetPathFilter, - PartialAssetPathType addressProvideMode, string label = null, string version = null) + private static LayoutRule CreateLayoutRule( + string addressableGroupName, + string regexAssetPathFilter, + PartialAssetPathType addressProvideMode, + string label = null, + string version = null + ) { var addressableGroup = ScriptableObject.CreateInstance(); addressableGroup.Name = addressableGroupName; return CreateLayoutRule(addressableGroup, regexAssetPathFilter, addressProvideMode, label, version); } - private static LayoutRule CreateLayoutRule(AddressableAssetGroup addressableGroup, string regexAssetPathFilter, - PartialAssetPathType addressProvideMode, string label = null, string version = null) + private static LayoutRule CreateLayoutRule( + AddressableAssetGroup addressableGroup, + string regexAssetPathFilter, + PartialAssetPathType addressProvideMode, + string label = null, + string version = null + ) { var assetFilter = new RegexBasedAssetFilter {