diff --git a/Editor/AddressableImportRule.cs b/Editor/AddressableImportRule.cs index 09f4c59..513cb6b 100644 --- a/Editor/AddressableImportRule.cs +++ b/Editor/AddressableImportRule.cs @@ -56,14 +56,6 @@ public class AddressableImportRule [Tooltip("The group name in which the Addressable will be added. Leave blank for the default group.")] public string groupName = string.Empty; - /// - /// Cleaned group name. - /// - string CleanedGroupName { - get { - return groupName.Trim().Replace('/', '-').Replace('\\', '-'); - } - } /// /// Defines if labels will be added or replaced. @@ -73,9 +65,12 @@ string CleanedGroupName { /// /// Label reference list. /// - [Tooltip("The list of labels to be added to the Addressable Asset")] + [Tooltip("The list of addressable labels (already existing in your project) to be added to the Addressable Asset")] public List labelRefs; + [Tooltip("The list of dynamic labels to be added to the Addressable Asset. If an addressable label doesn't exist, then it will be create in your unity project")] + public List dynamicLabels; + /// /// Group template to use. Default Group settings will be used if empty. /// @@ -102,7 +97,7 @@ string CleanedGroupName { [ConditionalField("matchType", AddressableImportRuleMatchType.Regex, "simplified", false)] public string addressReplacement = string.Empty; - public bool HasLabel + public bool HasLabelRefs { get { @@ -140,12 +135,30 @@ public bool Match(string assetPath) /// public string ParseGroupReplacement(string assetPath) { - if (string.IsNullOrWhiteSpace(path) || string.IsNullOrWhiteSpace(groupName)) + return ParseReplacement(assetPath, groupName); + + } + + /// + /// Parse assetPath and replace all elements that match this.path regex + /// with the + /// Returns null if this.path or is empty. + /// + /// + /// + /// + public string ParseReplacement(string assetPath, string name) + { + if (string.IsNullOrWhiteSpace(path) || string.IsNullOrWhiteSpace(name)) return null; + + var cleanedName = name.Trim().Replace('/', '-').Replace('\\', '-'); + // Parse path elements. - var replacement = AddressableImportRegex.ParsePath(assetPath, CleanedGroupName); + var replacement = AddressableImportRegex.ParsePath(assetPath, cleanedName); // Parse this.path regex. - if (matchType == AddressableImportRuleMatchType.Regex) { + if (matchType == AddressableImportRuleMatchType.Regex) + { string pathRegex = path; replacement = Regex.Replace(assetPath, pathRegex, replacement); } @@ -172,21 +185,21 @@ public string ParseAddressReplacement(string assetPath) // If the match type is Wildcard, the pattern will match and capture the entire path string. string pathRegex = simplified - ? @"(?.*[/\\])+(?.+?)(?\.[^.]*$|$)" - : (matchType == AddressableImportRuleMatchType.Wildcard - ? @"(.*)" - : path); + ? @"(?.*[/\\])+(?.+?)(?\.[^.]*$|$)" + : (matchType == AddressableImportRuleMatchType.Wildcard + ? @"(.*)" + : path); replacement = simplified - ? @"${filename}" - : (matchType == AddressableImportRuleMatchType.Wildcard - ? @"$1" - : replacement); + ? @"${filename}" + : (matchType == AddressableImportRuleMatchType.Wildcard + ? @"$1" + : replacement); replacement = Regex.Replace(assetPath, pathRegex, replacement); return replacement; } - public IEnumerable labels + public IEnumerable labelsRefsEnum { get { @@ -264,4 +277,4 @@ static public string ParsePath(string assetPath, string replacement) return finalPath; } } -} +} \ No newline at end of file diff --git a/Editor/AddressableImporter.cs b/Editor/AddressableImporter.cs index 6508b0f..ff2a3eb 100644 --- a/Editor/AddressableImporter.cs +++ b/Editor/AddressableImporter.cs @@ -19,7 +19,8 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse var isConfigurationPass = (importedAssets.Length > 0 && importedAssets.All(x => x.StartsWith("Assets/AddressableAssetsData"))) && (deletedAssets.Length > 0 && deletedAssets.All(x => x.StartsWith("Assets/AddressableAssetsData"))); - if (isConfigurationPass) { + if (isConfigurationPass) + { return; } var settings = AddressableAssetSettingsDefaultObject.Settings; @@ -32,7 +33,8 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse return; } var importSettings = AddressableImportSettings.Instance; - if (importSettings == null) { + if (importSettings == null) + { Debug.LogWarningFormat("[AddressableImporter] import settings file not found.\nPlease go to Assets/AddressableAssetsData folder, right click in the project window and choose 'Create > Addressable Assets > Import Settings'."); return; } @@ -64,7 +66,8 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse foreach (var deletedAsset in deletedAssets) { - if (TryGetMatchedRule(deletedAsset, importSettings, out var matchedRule)) { + if (TryGetMatchedRule(deletedAsset, importSettings, out var matchedRule)) + { var guid = AssetDatabase.AssetPathToGUID(deletedAsset); if (!string.IsNullOrEmpty(guid) && settings.RemoveAssetEntry(guid)) { @@ -74,7 +77,8 @@ static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAsse } } - if (dirty) { + if (dirty) + { AssetDatabase.SaveAssets(); } } @@ -97,7 +101,7 @@ static bool ApplyImportRule( var entry = CreateOrUpdateAddressableAssetEntry(settings, importSettings, matchedRule, assetPath); if (entry != null) { - if (matchedRule.HasLabel) + if (matchedRule.HasLabelRefs) Debug.LogFormat("[AddressableImporter] Entry created/updated for {0} with address {1} and labels {2}", assetPath, entry.address, string.Join(", ", entry.labels)); else Debug.LogFormat("[AddressableImporter] Entry created/updated for {0} with address {1}", assetPath, entry.address); @@ -171,10 +175,18 @@ static AddressableAssetEntry CreateOrUpdateAddressableAssetEntry( // Add labels if (rule.LabelMode == LabelWriteMode.Replace) entry.labels.Clear(); - foreach (var label in rule.labels) + foreach (var label in rule.labelsRefsEnum) { entry.labels.Add(label); } + + foreach (var dynamicLabel in rule.dynamicLabels) + { + var label = rule.ParseReplacement(assetPath, dynamicLabel); + settings.AddLabel(label); + entry.labels.Add(label); + } + } return entry; } @@ -308,4 +320,4 @@ private static bool ValidateCheckFoldersFromSelection() } -} +} \ No newline at end of file diff --git a/Editor/Attributes/ButtonMethodAttribute.cs b/Editor/Attributes/ButtonMethodAttribute.cs index b1e1214..11561cc 100644 --- a/Editor/Attributes/ButtonMethodAttribute.cs +++ b/Editor/Attributes/ButtonMethodAttribute.cs @@ -11,5 +11,4 @@ namespace UnityAddressableImporter.Helper public class ButtonMethodAttribute : PropertyAttribute { } -} - +} \ No newline at end of file diff --git a/Editor/Helper/AddressableImportSettingsEditor.cs b/Editor/Helper/AddressableImportSettingsEditor.cs index 313f2c1..63f6f51 100644 --- a/Editor/Helper/AddressableImportSettingsEditor.cs +++ b/Editor/Helper/AddressableImportSettingsEditor.cs @@ -6,58 +6,58 @@ namespace UnityAddressableImporter.Helper.Internal { - using System; - using System.Collections.Generic; - using System.Reflection; - using Editor.Helper; - using UnityEditor; - - - [CustomEditor(typeof(AddressableImportSettings), true), CanEditMultipleObjects] - public class AddressableImportSettingsEditor : Editor - { - private List _methods; - private AddressableImportSettings _target; - private AddressableImporterOdinHandler _drawer; - - - private void OnEnable() - { - _target = target as AddressableImportSettings; - _drawer = _drawer ?? new AddressableImporterOdinHandler(); - if (_target == null) return; - - _drawer.Initialize(_target); - _methods = AddressableImporterMethodHandler.CollectValidMembers(_target.GetType()); - - } - - private void OnDisable() - { - _drawer.Dispose(); - } - - public override void OnInspectorGUI() - { - DrawBaseEditor(); + using System; + using System.Collections.Generic; + using System.Reflection; + using Editor.Helper; + using UnityEditor; + + + [CustomEditor(typeof(AddressableImportSettings), true), CanEditMultipleObjects] + public class AddressableImportSettingsEditor : Editor + { + private List _methods; + private AddressableImportSettings _target; + private AddressableImporterOdinHandler _drawer; + + + private void OnEnable() + { + _target = target as AddressableImportSettings; + _drawer = _drawer ?? new AddressableImporterOdinHandler(); + if (_target == null) return; + + _drawer.Initialize(_target); + _methods = AddressableImporterMethodHandler.CollectValidMembers(_target.GetType()); + + } + + private void OnDisable() + { + _drawer.Dispose(); + } + + public override void OnInspectorGUI() + { + DrawBaseEditor(); #if !ODIN_INSPECTOR - if (_methods == null) return; + if (_methods == null) return; - AddressableImporterMethodHandler.OnInspectorGUI(_target, _methods); + AddressableImporterMethodHandler.OnInspectorGUI(_target, _methods); #endif - serializedObject.ApplyModifiedProperties(); + serializedObject.ApplyModifiedProperties(); - } + } - private void DrawBaseEditor() - { + private void DrawBaseEditor() + { #if ODIN_INSPECTOR _drawer.Draw(); #else - base.OnInspectorGUI(); + base.OnInspectorGUI(); #endif - } - } + } + } } \ No newline at end of file diff --git a/Editor/Helper/AddressableImporterMethodHandler.cs b/Editor/Helper/AddressableImporterMethodHandler.cs index 9ab8514..5d67958 100644 --- a/Editor/Helper/AddressableImporterMethodHandler.cs +++ b/Editor/Helper/AddressableImporterMethodHandler.cs @@ -86,7 +86,7 @@ private static string SplitCamelCase(string camelCaseString) { if (string.IsNullOrEmpty(camelCaseString)) return camelCaseString; - string camelCase = Regex.Replace(Regex.Replace(camelCaseString, @"(\P{Ll})(\P{Ll}\p{Ll})", "$1 $2"), @"(\p{Ll})(\P{Ll})", "$1 $2"); + string camelCase = Regex.Replace(Regex.Replace(camelCaseString, @"(\P{Ll})(\P{Ll}\p{Ll})", "$1 $2"), @"(\p{Ll})(\P{Ll})", "$1 $2"); string firstLetter = camelCase.Substring(0, 1).ToUpper(); if (camelCaseString.Length > 1) diff --git a/Editor/Helper/ConditionalFieldAttribute.cs b/Editor/Helper/ConditionalFieldAttribute.cs index 4b784b9..2d4d0f3 100644 --- a/Editor/Helper/ConditionalFieldAttribute.cs +++ b/Editor/Helper/ConditionalFieldAttribute.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using UnityEngine; - #if UNITY_EDITOR using UnityEditor; #endif @@ -24,143 +23,143 @@ public ConditionalFieldAttribute(params object[] conditions) } #if UNITY_EDITOR - public bool CheckBehaviourPropertyVisible(MonoBehaviour behaviour, string propertyName) - { - if (conditions == null || conditions.Length == 0) - return true; - var so = new SerializedObject(behaviour); - var property = so.FindProperty(propertyName); - return CheckPropertyVisible(property); - } - - - public bool CheckPropertyVisible(SerializedProperty property) - { - if (conditions == null || conditions.Length == 0) - return true; - for (int i = 0; i < conditions.Length / 2; i++) - { - string _fieldToCheck = conditions[i*2] as string; - object _compareValue = conditions[i*2+1]; - var conditionProperty = FindRelativeProperty(property, _fieldToCheck); - if (conditionProperty == null) - continue; - string asString = AsStringValue(conditionProperty).ToUpper(); - if (_compareValue != null) - { - bool compareValueMatch = _compareValue.ToString().ToUpper() == asString; - if (!compareValueMatch) - return false; - } - } - return true; - } - - private SerializedProperty FindRelativeProperty(SerializedProperty property, string toGet) - { - if (property.depth == 0) - return property.serializedObject.FindProperty(toGet); - var path = property.propertyPath.Replace(".Array.data[", "["); - var elements = path.Split('.'); - var nestedProperty = NestedPropertyOrigin(property, elements); - // if nested property is null = we hit an array property - if (nestedProperty == null) - { - var cleanPath = path.Substring(0, path.IndexOf('[')); - var arrayProp = property.serializedObject.FindProperty(cleanPath); - if (_warningsPool.Contains(arrayProp.exposedReferenceValue)) return null; - var target = arrayProp.serializedObject.targetObject; - var who = string.Format("Property {0} in object {1} caused: ", arrayProp.name, - target.name); - Debug.LogWarning(who + "Array fields is not supported by [ConditionalFieldAttribute]", target); - _warningsPool.Add(arrayProp.exposedReferenceValue); - return null; - } - return nestedProperty.FindPropertyRelative(toGet); - } - - // For [Serialized] types with [Conditional] fields - private SerializedProperty NestedPropertyOrigin(SerializedProperty property, string[] elements) - { - SerializedProperty parent = null; - for (int i = 0; i < elements.Length - 1; i++) - { - var element = elements[i]; - int index = -1; - if (element.Contains("[")) - { - index = Convert.ToInt32(element.Substring(element.IndexOf("[", StringComparison.Ordinal)) - .Replace("[", "").Replace("]", "")); - element = element.Substring(0, element.IndexOf("[", StringComparison.Ordinal)); - } - - parent = i == 0 - ? property.serializedObject.FindProperty(element) - : parent.FindPropertyRelative(element); - - if (index >= 0) parent = parent.GetArrayElementAtIndex(index); - } - return parent; - } - - - private string AsStringValue(SerializedProperty prop) - { - switch (prop.propertyType) - { - case SerializedPropertyType.String: - return prop.stringValue; - - case SerializedPropertyType.Character: - case SerializedPropertyType.Integer: - if (prop.type == "char") return Convert.ToChar(prop.intValue).ToString(); - return prop.intValue.ToString(); - - case SerializedPropertyType.ObjectReference: - return prop.objectReferenceValue != null ? prop.objectReferenceValue.ToString() : "null"; - - case SerializedPropertyType.Boolean: - return prop.boolValue.ToString(); - - case SerializedPropertyType.Enum: - return prop.enumNames[prop.enumValueIndex]; - - default: - return string.Empty; - } - } - - //This pool is used to prevent spamming with warning messages - //One message per property - readonly HashSet _warningsPool = new HashSet(); + public bool CheckBehaviourPropertyVisible(MonoBehaviour behaviour, string propertyName) + { + if (conditions == null || conditions.Length == 0) + return true; + var so = new SerializedObject(behaviour); + var property = so.FindProperty(propertyName); + return CheckPropertyVisible(property); + } + + + public bool CheckPropertyVisible(SerializedProperty property) + { + if (conditions == null || conditions.Length == 0) + return true; + for (int i = 0; i < conditions.Length/2; i++) + { + string _fieldToCheck = conditions[i*2] as string; + object _compareValue = conditions[i*2 + 1]; + var conditionProperty = FindRelativeProperty(property, _fieldToCheck); + if (conditionProperty == null) + continue; + string asString = AsStringValue(conditionProperty).ToUpper(); + if (_compareValue != null) + { + bool compareValueMatch = _compareValue.ToString().ToUpper() == asString; + if (!compareValueMatch) + return false; + } + } + return true; + } + + private SerializedProperty FindRelativeProperty(SerializedProperty property, string toGet) + { + if (property.depth == 0) + return property.serializedObject.FindProperty(toGet); + var path = property.propertyPath.Replace(".Array.data[", "["); + var elements = path.Split('.'); + var nestedProperty = NestedPropertyOrigin(property, elements); + // if nested property is null = we hit an array property + if (nestedProperty == null) + { + var cleanPath = path.Substring(0, path.IndexOf('[')); + var arrayProp = property.serializedObject.FindProperty(cleanPath); + if (_warningsPool.Contains(arrayProp.exposedReferenceValue)) return null; + var target = arrayProp.serializedObject.targetObject; + var who = string.Format("Property {0} in object {1} caused: ", arrayProp.name, + target.name); + Debug.LogWarning(who + "Array fields is not supported by [ConditionalFieldAttribute]", target); + _warningsPool.Add(arrayProp.exposedReferenceValue); + return null; + } + return nestedProperty.FindPropertyRelative(toGet); + } + + // For [Serialized] types with [Conditional] fields + private SerializedProperty NestedPropertyOrigin(SerializedProperty property, string[] elements) + { + SerializedProperty parent = null; + for (int i = 0; i < elements.Length - 1; i++) + { + var element = elements[i]; + int index = -1; + if (element.Contains("[")) + { + index = Convert.ToInt32(element.Substring(element.IndexOf("[", StringComparison.Ordinal)) + .Replace("[", "").Replace("]", "")); + element = element.Substring(0, element.IndexOf("[", StringComparison.Ordinal)); + } + + parent = i == 0 + ? property.serializedObject.FindProperty(element) + : parent.FindPropertyRelative(element); + + if (index >= 0) parent = parent.GetArrayElementAtIndex(index); + } + return parent; + } + + + private string AsStringValue(SerializedProperty prop) + { + switch (prop.propertyType) + { + case SerializedPropertyType.String: + return prop.stringValue; + + case SerializedPropertyType.Character: + case SerializedPropertyType.Integer: + if (prop.type == "char") return Convert.ToChar(prop.intValue).ToString(); + return prop.intValue.ToString(); + + case SerializedPropertyType.ObjectReference: + return prop.objectReferenceValue != null ? prop.objectReferenceValue.ToString() : "null"; + + case SerializedPropertyType.Boolean: + return prop.boolValue.ToString(); + + case SerializedPropertyType.Enum: + return prop.enumNames[prop.enumValueIndex]; + + default: + return string.Empty; + } + } + + //This pool is used to prevent spamming with warning messages + //One message per property + readonly HashSet _warningsPool = new HashSet(); #endif } } #if UNITY_EDITOR namespace UnityAddressableImporter.Helper.Internal { - [CustomPropertyDrawer(typeof(ConditionalFieldAttribute))] - public class ConditionalFieldAttributeDrawer : PropertyDrawer - { - private ConditionalFieldAttribute Attribute - { - get { return _attribute ?? (_attribute = attribute as ConditionalFieldAttribute); } - } - - private ConditionalFieldAttribute _attribute; - - private bool _toShow = true; - - public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - { - _toShow = Attribute.CheckPropertyVisible(property); - return _toShow ? EditorGUI.GetPropertyHeight(property) : 0; - } - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - if (_toShow) EditorGUI.PropertyField(position, property, label, true); - } - } + [CustomPropertyDrawer(typeof(ConditionalFieldAttribute))] + public class ConditionalFieldAttributeDrawer : PropertyDrawer + { + private ConditionalFieldAttribute Attribute + { + get { return _attribute ?? (_attribute = attribute as ConditionalFieldAttribute); } + } + + private ConditionalFieldAttribute _attribute; + + private bool _toShow = true; + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + _toShow = Attribute.CheckPropertyVisible(property); + return _toShow ? EditorGUI.GetPropertyHeight(property) : 0; + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + if (_toShow) EditorGUI.PropertyField(position, property, label, true); + } + } } #endif \ No newline at end of file diff --git a/Editor/Helper/LabelAttribute.cs b/Editor/Helper/LabelAttribute.cs index 9f23bab..f834b40 100644 --- a/Editor/Helper/LabelAttribute.cs +++ b/Editor/Helper/LabelAttribute.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using UnityEngine; - #if UNITY_EDITOR using UnityEditor; #endif @@ -27,21 +26,21 @@ public LabelAttribute(string label) #if UNITY_EDITOR namespace UnityAddressableImporter.Helper.Internal { - [CustomPropertyDrawer(typeof(LabelAttribute))] - public class LabelAttributeDrawer : PropertyDrawer - { - private LabelAttribute Attribute - { - get { return _attribute ?? (_attribute = attribute as LabelAttribute); } - } + [CustomPropertyDrawer(typeof(LabelAttribute))] + public class LabelAttributeDrawer : PropertyDrawer + { + private LabelAttribute Attribute + { + get { return _attribute ?? (_attribute = attribute as LabelAttribute); } + } - private LabelAttribute _attribute; + private LabelAttribute _attribute; - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { var guiContent = new GUIContent(Attribute.Label); - EditorGUI.PropertyField(position, property, guiContent, true); - } - } + EditorGUI.PropertyField(position, property, guiContent, true); + } + } } #endif \ No newline at end of file diff --git a/Editor/OdinSupport/AddressableImporterFilterOdinHandler.cs b/Editor/OdinSupport/AddressableImporterFilterOdinHandler.cs index 70bcd11..b568df8 100644 --- a/Editor/OdinSupport/AddressableImporterFilterOdinHandler.cs +++ b/Editor/OdinSupport/AddressableImporterFilterOdinHandler.cs @@ -49,7 +49,8 @@ public void Initialize(AddressableImportSettings importSettings) _filters = new List>() { ValidateAddressableGroupName, ValidateRulePath, - ValidateLabelsPath, + ValidateLabelRefsPath, + ValidateDynamicLabelsPath }; _drawerTree.OnPropertyValueChanged += (property, index) => EditorUtility.SetDirty(_importSettings); @@ -93,11 +94,14 @@ private bool ValidateRulePath(AddressableImportRule rule, string filter) return rule.path.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0; } - private bool ValidateLabelsPath(AddressableImportRule rule, string filter) + private bool ValidateLabelRefsPath(AddressableImportRule rule, string filter) { - return rule.labels.Any(x => x.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0); + return rule.labelsRefsEnum.Any(x => x.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0); } + private bool ValidateDynamicLabelsPath(AddressableImportRule rule, string filter) { + return rule.dynamicLabels.Any(x => x.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0); + } private void FilterRules(string filter) { rules = new List(); diff --git a/Editor/OdinSupport/AddressableImporterOdinHandler.cs b/Editor/OdinSupport/AddressableImporterOdinHandler.cs index ab0c9a2..e5a8ea9 100644 --- a/Editor/OdinSupport/AddressableImporterOdinHandler.cs +++ b/Editor/OdinSupport/AddressableImporterOdinHandler.cs @@ -62,4 +62,4 @@ public void Dispose() { } } #endif -} +} \ No newline at end of file diff --git a/Tests/Editor/AddressableImportRuleTests.cs b/Tests/Editor/AddressableImportRuleTests.cs index 1662aeb..11660de 100644 --- a/Tests/Editor/AddressableImportRuleTests.cs +++ b/Tests/Editor/AddressableImportRuleTests.cs @@ -1,5 +1,4 @@ - -using UnityEngine; +using UnityEngine; using UnityEditor; using UnityEngine.AddressableAssets; using System.Collections.Generic;