From 966984d6717b52b5b68146406605502a7e8c15df Mon Sep 17 00:00:00 2001 From: Unity Technologies <@unity> Date: Sat, 23 Oct 2021 00:00:00 +0000 Subject: [PATCH] com.unity.addressables@1.19.11 ## [1.19.11] - 2021-10-23 - Fixed issue with missing reference exception when using addressables where content has not been built. - Added warning that LZMA compression is not available for WebGL AssetBundles. - Fixed issue were getting a Group Template fails where the project name or parent directory ended in "Assets". - Fixed issue where option to build Addressables when building a Player where displayed for unsupported editor versions. - Fixed issue where hosting services filters ip addresses when entering playmode and no services are in use - Fixed "Editor Hosted" LoadPath, to work with active local Editor hosting service - Fixed error where creating new groups would lead to errors if the default build and load path variables were not present in one's profile settings. - Modified the behavior of AssetReference.editorAsset and AssetReference.SetEditorAsset to be more consistent and intuitive - Fixed issue where upgrading from versions that didn't have ProfileGroupTypes was causing issues during builds. --- CHANGELOG.md | 12 ++ Documentation~/LoadingAddressableAssets.md | 2 +- Editor/Build/AddressablesBuildScriptHooks.cs | 9 +- .../GUI/AddressableAssetSettingsInspector.cs | 6 +- Editor/GUI/ProfileDataSourceDropdownWindow.cs | 23 +- Editor/GUI/ProfileWindow.cs | 9 +- .../HostingServices/HostingServicesManager.cs | 62 +++++- Editor/Settings/AddressableAssetGroup.cs | 2 + .../Settings/AddressableAssetGroupSchema.cs | 8 + .../AddressableAssetProfileSettings.cs | 15 +- Editor/Settings/AddressableAssetSettings.cs | 27 ++- Editor/Settings/AddressableAssetUtility.cs | 18 +- .../GroupSchemas/BundledAssetGroupSchema.cs | 32 ++- Editor/Settings/Preferences.cs | 6 +- Editor/Settings/ProfileDataSourceSettings.cs | 67 ++++-- Editor/Settings/ProfileGroupType.cs | 27 ++- Editor/Settings/ProfileValueReference.cs | 11 + Runtime/AssetReference.cs | 106 ++++++++-- .../Editor/ImportExistingGroup.cs | 16 +- .../AddressableAssetFolderSubfolderTests.cs | 4 +- .../Editor/AddressableAssetReferenceTests.cs | 96 ++++++++- Tests/Editor/ContentUpdateTests.cs | 2 +- Tests/Editor/GroupSchemaTests.cs | 197 ++++++++++++++++++ .../HostingServicesManagerTests.cs | 91 +++++++- .../Editor/ProfileDataSourceSettingsTests.cs | 6 +- Tests/Editor/ProfileGroupTypeTests.cs | 60 +++++- package.json | 6 +- 27 files changed, 814 insertions(+), 106 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3da4612b..1d835038 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this package will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [1.19.11] - 2021-10-23 +- Fixed issue with missing reference exception when using addressables where content has not been built. +- Added warning that LZMA compression is not available for WebGL AssetBundles. +- Fixed issue were getting a Group Template fails where the project name or parent directory ended in "Assets". +- Fixed issue where option to build Addressables when building a Player where displayed for unsupported editor versions. +- Fixed issue where hosting services filters ip addresses when entering playmode and no services are in use +- Fixed "Editor Hosted" LoadPath, to work with active local Editor hosting service +- Fixed error where creating new groups would lead to errors if the default build and load path variables were not present in one's profile settings. +- Modified the behavior of AssetReference.editorAsset and AssetReference.SetEditorAsset to be more consistent and intuitive +- Fixed issue where upgrading from versions that didn't have ProfileGroupTypes was causing issues during builds. + ## [1.19.9] - 2021-09-30 - Fixing a compile error on platforms where the Caching API is stripped. - Updating ScriptableBuildPipeline dependency @@ -55,6 +66,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - UnloadSceneAsync APIs with exposed UnloadSceneOptions parameter - Addressables.CleanBundleCache - New parameter for Addressables.UpdateCatalogs to auto clean the bundle cache + - ProfileGroupType introduces a new workflow of grouping profile variables in the Addressables Profiles window, otherwise known as path pairs. ## [1.18.15] - 2021-07-26 - Improved Addressables inspector for Assets. diff --git a/Documentation~/LoadingAddressableAssets.md b/Documentation~/LoadingAddressableAssets.md index 797e7eab..90d2b3ee 100644 --- a/Documentation~/LoadingAddressableAssets.md +++ b/Documentation~/LoadingAddressableAssets.md @@ -405,7 +405,7 @@ When you call [InstantiateAsync] you have the same options as the [Object.Instan Because the Addressables system uses reference counting to determine whether an asset is in use, you must release every asset that you load or instantiate when you are done with it. See [Memory Management] for more information. -When you unload a Scene, implicit assets in the Scene are not automatically unloaded. You must call [Resources.UnloadUnusedAssets] or [UnloadAsset] to free these assets. Note that the Unity runtime automatically calls `UnloadUnusedAssets` when you load a Scene using the +When you unload a Scene, implicit assets in the Scene are not automatically unloaded. You must call [Resources.UnloadUnusedAssets] or [UnloadAsset] to free these assets. Note that the Unity runtime automatically calls `UnloadUnusedAssets` when you load a Scene using the [LoadSceneMode.Single] mode. ## Using Addressables in a Scene diff --git a/Editor/Build/AddressablesBuildScriptHooks.cs b/Editor/Build/AddressablesBuildScriptHooks.cs index 9a5769c0..483125b5 100644 --- a/Editor/Build/AddressablesBuildScriptHooks.cs +++ b/Editor/Build/AddressablesBuildScriptHooks.cs @@ -24,11 +24,11 @@ static void Init() static void OnEditorPlayModeChanged(PlayModeStateChange state) { + var settings = AddressableAssetSettingsDefaultObject.Settings; + if (settings == null) + return; if (state == PlayModeStateChange.ExitingEditMode) { - var settings = AddressableAssetSettingsDefaultObject.Settings; - if (settings == null) - return; if (settings.ActivePlayModeDataBuilder == null) { var err = "Active play mode build script is null."; @@ -66,8 +66,11 @@ static void OnEditorPlayModeChanged(PlayModeStateChange state) if (BuildScript.buildCompleted != null) BuildScript.buildCompleted(res); settings.DataBuilderCompleted(settings.ActivePlayModeDataBuilder, res); + settings.HostingServicesManager.exitingEditMode = true; } } + else + settings.HostingServicesManager.exitingEditMode = false; } } } diff --git a/Editor/GUI/AddressableAssetSettingsInspector.cs b/Editor/GUI/AddressableAssetSettingsInspector.cs index 9245f27d..431db587 100644 --- a/Editor/GUI/AddressableAssetSettingsInspector.cs +++ b/Editor/GUI/AddressableAssetSettingsInspector.cs @@ -154,9 +154,11 @@ void OnEnable() #if UNITY_2019_4_OR_NEWER GUIContent m_CCDEnabled = new GUIContent("Enable Experimental CCD Features", "If enabled, will unlock experimental CCD features"); #endif +#if UNITY_2021_2_OR_NEWER GUIContent m_BuildAddressablesWithPlayerBuild = new GUIContent("Build Addressables on Player Build", "Determines if a new Addressables build will be built with a Player Build."); - +#endif + public override void OnInspectorGUI() { m_QueuedChanges.Clear(); @@ -276,6 +278,7 @@ public override void OnInspectorGUI() m_BuildFoldout = EditorGUILayout.Foldout(m_BuildFoldout, "Build"); if (m_BuildFoldout) { +#if UNITY_2021_2_OR_NEWER int index = (int) m_AasTarget.BuildAddressablesWithPlayerBuild; int newIndex = EditorGUILayout.Popup(m_BuildAddressablesWithPlayerBuild, index, new[] { @@ -293,6 +296,7 @@ public override void OnInspectorGUI() EditorGUILayout.TextField(" ", enabled ? "Enabled" : "Disabled"); } } +#endif bool ignoreUnsupportedFilesInBuild = EditorGUILayout.Toggle(m_IgnoreUnsupportedFilesInBuild, m_AasTarget.IgnoreUnsupportedFilesInBuild); if (ignoreUnsupportedFilesInBuild != m_AasTarget.IgnoreUnsupportedFilesInBuild) diff --git a/Editor/GUI/ProfileDataSourceDropdownWindow.cs b/Editor/GUI/ProfileDataSourceDropdownWindow.cs index 1a22f4ba..139410fd 100644 --- a/Editor/GUI/ProfileDataSourceDropdownWindow.cs +++ b/Editor/GUI/ProfileDataSourceDropdownWindow.cs @@ -31,11 +31,20 @@ internal enum CCDDropdownState { Bucket, Badge }; internal string m_BucketId; internal string m_BucketName; internal ProfileGroupType m_Bucket; + internal bool m_isRefreshingCCDDataSources; + + private ProfileDataSourceSettings m_ProfileDataSource; internal ProfileDataSourceSettings dataSourceSettings { - get { return ProfileDataSourceSettings.GetSettings(); } + get + { + if (m_ProfileDataSource == null) + m_ProfileDataSource = ProfileDataSourceSettings.GetSettings(); + return m_ProfileDataSource; + } } + static GUIStyle dropdownTitleStyle; static GUIStyle menuOptionStyle; static GUIStyle horizontalBarStyle; @@ -179,10 +188,12 @@ public override void OnGUI(Rect window) if (CloudProjectSettings.projectId != String.Empty) { EditorGUI.LabelField(refreshButtonRect, EditorGUIUtility.IconContent(refreshIcon)); - if (evt.type == EventType.MouseDown && refreshButtonRect.Contains(evt.mousePosition)) + if (evt.type == EventType.MouseDown && refreshButtonRect.Contains(evt.mousePosition) && !m_isRefreshingCCDDataSources) { + m_isRefreshingCCDDataSources = true; await ProfileDataSourceSettings.UpdateCCDDataSourcesAsync(CloudProjectSettings.projectId, true); SyncProfileGroupTypes(); + m_isRefreshingCCDDataSources = false; return; } } @@ -246,8 +257,12 @@ public override void OnGUI(Rect window) m_WindowRect.height = 120; } EditorGUI.LabelField(refreshButtonRect, EditorGUIUtility.IconContent(refreshIcon)); - if (evt.type == EventType.MouseDown && refreshButtonRect.Contains(evt.mousePosition)) + if (evt.type == EventType.MouseDown && refreshButtonRect.Contains(evt.mousePosition) && !m_isRefreshingCCDDataSources) { + m_isRefreshingCCDDataSources = true; + await ProfileDataSourceSettings.UpdateCCDDataSourcesAsync(CloudProjectSettings.projectId, true); + SyncProfileGroupTypes(); + m_isRefreshingCCDDataSources = false; return; } EditorGUILayout.LabelField(String.Format("{0} Badges", m_Bucket.GetVariableBySuffix($"{nameof(CcdBucket)}{nameof(CcdBucket.Name)}").Value), dropdownTitleStyle); @@ -417,7 +432,7 @@ internal EditorHostedOption() OptionName = "Editor Hosted"; state = DropdownState.EditorHosted; BuildPath = AddressableAssetSettings.kRemoteBuildPathValue; - LoadPath = AddressableAssetSettings.kRemoteLoadPathValue; + LoadPath = AddressableAssetSettings.RemoteLoadPathValue; } internal override void Draw(Action action) diff --git a/Editor/GUI/ProfileWindow.cs b/Editor/GUI/ProfileWindow.cs index 9b81f90a..1a204c1a 100644 --- a/Editor/GUI/ProfileWindow.cs +++ b/Editor/GUI/ProfileWindow.cs @@ -36,6 +36,8 @@ internal class ProfileWindow : EditorWindow float m_HorizontalSplitterRatio = k_DefaultHorizontalSplitterRatio; + private ProfileDataSourceSettings m_ProfileDataSource; + internal AddressableAssetSettings settings { get { return AddressableAssetSettingsDefaultObject.Settings; } @@ -43,7 +45,12 @@ internal AddressableAssetSettings settings internal ProfileDataSourceSettings dataSourceSettings { - get { return ProfileDataSourceSettings.GetSettings(); } + get + { + if (m_ProfileDataSource == null) + m_ProfileDataSource = ProfileDataSourceSettings.GetSettings(); + return m_ProfileDataSource; + } } private ProfileTreeView m_ProfileTreeView; diff --git a/Editor/HostingServices/HostingServicesManager.cs b/Editor/HostingServices/HostingServicesManager.cs index 58a13790..d669795d 100644 --- a/Editor/HostingServices/HostingServicesManager.cs +++ b/Editor/HostingServices/HostingServicesManager.cs @@ -4,6 +4,7 @@ using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; +using UnityEditor.AddressableAssets.Build.DataBuilders; using UnityEditor.AddressableAssets.Settings; using UnityEngine; using UnityEngine.Serialization; @@ -51,6 +52,24 @@ internal class HostingServiceInfo ILogger m_Logger; List m_RegisteredServiceTypes; + internal bool exitingEditMode = false; + + [Serializable] + internal class ProfileVariablesInfo + { + [SerializeField] + internal string key; + [SerializeField] + internal string value; + } + [SerializeField] + List m_GlobalProfileVariablesInfos; + + /// + /// Key/Value pairs valid for profile variable substitution + /// + public Dictionary GlobalProfileVariables { get; private set; } + /// /// Direct logging output of all managed services /// @@ -96,11 +115,6 @@ public static void BatchMode() BatchMode(AddressableAssetSettingsDefaultObject.Settings); } - /// - /// Key/Value pairs valid for profile variable substitution - /// - public Dictionary GlobalProfileVariables { get; private set; } - /// /// Indicates whether or not this HostingServiceManager is initialized /// @@ -146,6 +160,7 @@ public int NextInstanceId /// public HostingServicesManager() { + m_GlobalProfileVariablesInfos = new List(); GlobalProfileVariables = new Dictionary(); m_HostingServiceInfos = new List(); m_HostingServiceInfoMap = new Dictionary(); @@ -234,7 +249,8 @@ public IHostingService AddHostingService(Type serviceType, string name) m_Settings.profileSettings.RegisterProfileStringEvaluationFunc(svc.EvaluateProfileString); m_HostingServiceInfoMap.Add(svc, info); - m_Settings.SetDirty(AddressableAssetSettings.ModificationEvent.HostingServicesManagerModified, this, true, true); + m_Settings.SetDirty(AddressableAssetSettings.ModificationEvent.HostingServicesManagerModified, this, true, true); + AddressableAssetUtility.OpenAssetIfUsingVCIntegration(m_Settings); m_NextInstanceId++; return svc; @@ -254,6 +270,7 @@ public void RemoveHostingService(IHostingService svc) m_Settings.profileSettings.UnregisterProfileStringEvaluationFunc(svc.EvaluateProfileString); m_HostingServiceInfoMap.Remove(svc); m_Settings.SetDirty(AddressableAssetSettings.ModificationEvent.HostingServicesManagerModified, this, true, true); + AddressableAssetUtility.OpenAssetIfUsingVCIntegration(m_Settings); } /// @@ -266,14 +283,26 @@ public void OnEnable() m_Settings.OnModification -= OnSettingsModification; m_Settings.OnModification += OnSettingsModification; m_Settings.profileSettings.RegisterProfileStringEvaluationFunc(EvaluateGlobalProfileVariableKey); + + bool hasAnEnabledService = false; foreach (var svc in HostingServices) { svc.Logger = m_Logger; m_Settings.profileSettings.RegisterProfileStringEvaluationFunc(svc.EvaluateProfileString); - (svc as BaseHostingService)?.OnEnable(); + var baseSvc = svc as BaseHostingService; + baseSvc?.OnEnable(); + + if (!hasAnEnabledService) + hasAnEnabledService = svc.IsHostingServiceRunning || baseSvc != null && baseSvc.WasEnabled; } - RefreshGlobalProfileVariables(); + if (!exitingEditMode || exitingEditMode && hasAnEnabledService && IsUsingPackedPlayMode()) + RefreshGlobalProfileVariables(); + } + + bool IsUsingPackedPlayMode() + { + return m_Settings.ActivePlayModeDataBuilder != null && m_Settings.ActivePlayModeDataBuilder.GetType() == typeof(BuildScriptPackedPlayMode); } /// @@ -315,6 +344,15 @@ public void OnBeforeSerialize() m_RegisteredServiceTypeRefs.Clear(); foreach (var type in m_RegisteredServiceTypes) m_RegisteredServiceTypeRefs.Add(TypeToClassRef(type)); + + m_GlobalProfileVariablesInfos.Clear(); + foreach (var profileVar in GlobalProfileVariables) + { + var info = new ProfileVariablesInfo(); + info.key = profileVar.Key; + info.value = profileVar.Value; + m_GlobalProfileVariablesInfos.Add(info); + } } /// Ensure object is ready for serialization, and calls methods @@ -339,6 +377,12 @@ public void OnAfterDeserialize() if (type == null) continue; m_RegisteredServiceTypes.Add(type); } + + GlobalProfileVariables = new Dictionary(); + foreach (var profileVar in m_GlobalProfileVariablesInfos) + { + GlobalProfileVariables.Add(profileVar.key, profileVar.value); + } } /// @@ -365,6 +409,8 @@ public void RefreshGlobalProfileVariables() vars.Add(KPrivateIpAddressKey + "_" + i, ipAddressList[i].ToString()); } } + m_Settings.SetDirty(AddressableAssetSettings.ModificationEvent.HostingServicesManagerModified, this, true, true); + AddressableAssetUtility.OpenAssetIfUsingVCIntegration(m_Settings); } // Internal for unit tests diff --git a/Editor/Settings/AddressableAssetGroup.cs b/Editor/Settings/AddressableAssetGroup.cs index 401e1ab6..3529fd10 100644 --- a/Editor/Settings/AddressableAssetGroup.cs +++ b/Editor/Settings/AddressableAssetGroup.cs @@ -400,6 +400,8 @@ internal void Validate() } if (m_SchemaSet.Schemas[i].Group == null) m_SchemaSet.Schemas[i].Group = this; + + m_SchemaSet.Schemas[i].Validate(); } } diff --git a/Editor/Settings/AddressableAssetGroupSchema.cs b/Editor/Settings/AddressableAssetGroupSchema.cs index 024a3e54..7ea2793c 100644 --- a/Editor/Settings/AddressableAssetGroupSchema.cs +++ b/Editor/Settings/AddressableAssetGroupSchema.cs @@ -25,7 +25,10 @@ internal set { m_Group = value; if (m_Group != null) + { OnSetGroup(m_Group); + Validate(); + } } } @@ -37,6 +40,11 @@ protected virtual void OnSetGroup(AddressableAssetGroup group) { } + internal virtual void Validate() + { + + } + /// /// Used to display the GUI of the schema. /// diff --git a/Editor/Settings/AddressableAssetProfileSettings.cs b/Editor/Settings/AddressableAssetProfileSettings.cs index 60ce5bf0..097d9261 100644 --- a/Editor/Settings/AddressableAssetProfileSettings.cs +++ b/Editor/Settings/AddressableAssetProfileSettings.cs @@ -322,7 +322,7 @@ internal string CreateDefaultProfile() CreateValue(AddressableAssetSettings.kLocalBuildPath, AddressableAssetSettings.kLocalBuildPathValue); CreateValue(AddressableAssetSettings.kLocalLoadPath, AddressableAssetSettings.kLocalLoadPathValue); CreateValue(AddressableAssetSettings.kRemoteBuildPath, AddressableAssetSettings.kRemoteBuildPathValue); - CreateValue(AddressableAssetSettings.kRemoteLoadPath, AddressableAssetSettings.kRemoteLoadPathValue); + CreateValue(AddressableAssetSettings.kRemoteLoadPath, AddressableAssetSettings.RemoteLoadPathValue); } return GetDefaultProfileId(); } @@ -658,6 +658,7 @@ internal string CreateValue(string variableName, string defaultValue, bool inlin pro.values.Add(new BuildProfile.ProfileEntry(id, defaultValue)); } } + SetDirty(AddressableAssetSettings.ModificationEvent.ProfileModified, null, true); return id; } @@ -713,5 +714,17 @@ internal static string GenerateUniqueName(string baseName, IEnumerable e } return newName; } + + internal void CreateDuplicateVariableWithNewName(AddressableAssetSettings addressableAssetSettings, string newVariableName, string variableNameToCopyFrom) + { + var activeProfileId = addressableAssetSettings.activeProfileId; + string newVarId = CreateValue(newVariableName, GetValueByName(activeProfileId, variableNameToCopyFrom)); + string oldVarId = GetVariableId(variableNameToCopyFrom); + foreach (var profile in profiles) + { + profile.SetValueById(newVarId, profile.GetValueById(oldVarId)); + SetDirty(AddressableAssetSettings.ModificationEvent.ProfileModified, profile, true); + } + } } } diff --git a/Editor/Settings/AddressableAssetSettings.cs b/Editor/Settings/AddressableAssetSettings.cs index e35bb2ed..adb60b78 100644 --- a/Editor/Settings/AddressableAssetSettings.cs +++ b/Editor/Settings/AddressableAssetSettings.cs @@ -91,6 +91,9 @@ private static void TryAddAssetPostprocessorOnNextUpdate() /// Default name of remote load path. /// public const string kRemoteLoadPath = "Remote.LoadPath"; + + private const string kLocalGroupTypePrefix = "Built-In"; + internal static string LocalGroupTypePrefix => kLocalGroupTypePrefix; /// /// Default value of local build path. /// @@ -99,6 +102,9 @@ private static void TryAddAssetPostprocessorOnNextUpdate() /// Default value of local load path. /// public const string kLocalLoadPathValue = "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/[BuildTarget]"; + + private const string kEditorHostedGroupTypePrefix = "Editor Hosted"; + internal static string EditorHostedGroupTypePrefix => kEditorHostedGroupTypePrefix; /// /// Default value of remote build path. /// @@ -107,6 +113,16 @@ private static void TryAddAssetPostprocessorOnNextUpdate() /// Default value of remote load path. /// public const string kRemoteLoadPathValue = "http://localhost/[BuildTarget]"; + internal static string RemoteLoadPathValue + { + get + { + // Fix for case ADDR-2314. kRemoteLoadPathValue is incorrect, "http://localhost/[BuildTarget]" does not work with local hosting service + return "http://[PrivateIpAddress]:[HostingServicePort]"; + // kRemoteLoadPathValue will be fixed to the correct path in Addressables 1.20.0 + } + } + #if (ENABLE_CCD && UNITY_2019_4_OR_NEWER) /// /// Default path of build assets that are uploaded to CCD. @@ -641,8 +657,9 @@ public string ContentStateBuildPath [SerializeField] private PlayerBuildOption m_BuildAddressablesWithPlayerBuild = PlayerBuildOption.DoNotBuildWithPlayer; + /// - /// Defines if Addressables content will be built along with a Player build. + /// Defines if Addressables content will be built along with a Player build. (Requires 2021.2 or above) /// /// /// Build with Player, will build Addressables with a Player build, this overrides preferences value. @@ -1302,10 +1319,14 @@ internal bool RemoveAssetEntry(AddressableAssetEntry entry, bool postEvent = tru return true; } - void OnEnable() + void Awake() { profileSettings.OnAfterDeserialize(this); buildSettings.OnAfterDeserialize(this); + } + + void OnEnable() + { HostingServicesManager.OnEnable(); #pragma warning disable 0618 @@ -1423,7 +1444,7 @@ public static AddressableAssetSettings Create(string configFolder, string config // TODO: Uncomment after initial opt-in testing period //aa.ContiguousBundles = true; aa.BuildAddressablesWithPlayerBuild = PlayerBuildOption.PreferencesValue; - + if (isPersisted) { Directory.CreateDirectory(configFolder); diff --git a/Editor/Settings/AddressableAssetUtility.cs b/Editor/Settings/AddressableAssetUtility.cs index a5c3f3d7..bdba37b2 100644 --- a/Editor/Settings/AddressableAssetUtility.cs +++ b/Editor/Settings/AddressableAssetUtility.cs @@ -131,8 +131,7 @@ internal static void ConvertAssetBundlesToAddressables() currCount++; var group = settings.CreateGroup(bundle, false, false, false, null); var schema = group.AddSchema(); - schema.BuildPath.SetVariableByName(settings, AddressableAssetSettings.kLocalBuildPath); - schema.LoadPath.SetVariableByName(settings, AddressableAssetSettings.kLocalLoadPath); + schema.Validate(); schema.BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackTogether; group.AddSchema().StaticContent = true; @@ -350,6 +349,9 @@ internal static bool OpenAssetIfUsingVCIntegration(string path, bool exitGUI = f openedAsset = false; } } + else + openedAsset = false; + if (exitGUI) GUIUtility.ExitGUI(); return openedAsset; @@ -366,22 +368,20 @@ internal static ListRequest RequestPackageListAsync() internal static List GetPackages(ListRequest req) { + var packages = new List(); #if UNITY_2021_1_OR_NEWER - var packagesList = new List(PackageManager.PackageInfo.GetAllRegisteredPackages()); - return packagesList; -#endif + packages.AddRange(PackageManager.PackageInfo.GetAllRegisteredPackages()); +#else while (!req.IsCompleted) - { Thread.Sleep(5); - } - - var packages = new List(); + if (req.Status == StatusCode.Success) { PackageCollection collection = req.Result; foreach (PackageManager.PackageInfo package in collection) packages.Add(package); } +#endif return packages; } diff --git a/Editor/Settings/GroupSchemas/BundledAssetGroupSchema.cs b/Editor/Settings/GroupSchemas/BundledAssetGroupSchema.cs index c54d0822..6978d7c1 100644 --- a/Editor/Settings/GroupSchemas/BundledAssetGroupSchema.cs +++ b/Editor/Settings/GroupSchemas/BundledAssetGroupSchema.cs @@ -536,19 +536,35 @@ internal AddressableAssetSettings settings protected override void OnSetGroup(AddressableAssetGroup group) { //this can happen during the load of the addressables asset - if (group.Settings != null) + } + + internal void SetPathVariable(AddressableAssetSettings addressableAssetSettings, ref ProfileValueReference path, string newPathName, string oldPathName, List variableNames) + { + if (path == null || !path.HasValue(addressableAssetSettings)) { - if (BuildPath == null || string.IsNullOrEmpty(BuildPath.GetValue(group.Settings))) + path = new ProfileValueReference(); + if (variableNames.Contains(newPathName)) { - m_BuildPath = new ProfileValueReference(); - BuildPath.SetVariableByName(group.Settings, AddressableAssetSettings.kLocalBuildPath); + path.SetVariableByName(addressableAssetSettings, newPathName); + SetDirty(true); } - - if (LoadPath == null || string.IsNullOrEmpty(LoadPath.GetValue(group.Settings))) + else if (variableNames.Contains(oldPathName)) { - m_LoadPath = new ProfileValueReference(); - LoadPath.SetVariableByName(group.Settings, AddressableAssetSettings.kLocalLoadPath); + path.SetVariableByName(addressableAssetSettings, oldPathName); + SetDirty(true); } + else + Debug.LogWarning("Default path variable " + newPathName + " not found when initializing BundledAssetGroupSchema. Please manually set the path via the groups window."); + } + } + + internal override void Validate() + { + if (Group != null && Group.Settings != null) + { + List variableNames = Group.Settings.profileSettings.GetVariableNames(); + SetPathVariable(Group.Settings, ref m_BuildPath, AddressableAssetSettings.kLocalBuildPath, "LocalBuildPath", variableNames); + SetPathVariable(Group.Settings, ref m_LoadPath, AddressableAssetSettings.kLocalLoadPath, "LocalLoadPath", variableNames); } if (m_AssetBundleProviderType.Value == null) diff --git a/Editor/Settings/Preferences.cs b/Editor/Settings/Preferences.cs index a9f579d8..c0a29702 100644 --- a/Editor/Settings/Preferences.cs +++ b/Editor/Settings/Preferences.cs @@ -6,7 +6,9 @@ namespace UnityEditor.AddressableAssets { internal static class AddressablesPreferences { - internal const string kBuildAddressablesWithPlayerBuildKey = "Addressables.BuildAddressablesWithPlayerBuild"; +#if UNITY_2021_2_OR_NEWER + internal const string kBuildAddressablesWithPlayerBuildKey = "Addressables.BuildAddressablesWithPlayerBuild"; + #endif private class GUIScope : UnityEngine.GUI.Scope { float m_LabelWidth; @@ -36,8 +38,10 @@ internal class Properties { public static readonly GUIContent buildSettings = EditorGUIUtility.TrTextContent("Build Settings"); public static readonly GUIContent buildLayoutReport = EditorGUIUtility.TrTextContent("Debug Build Layout", $"A debug build layout file will be generated as part of the build process. The file will put written to {BuildLayoutGenerationTask.m_LayoutTextFile}"); +#if UNITY_2021_2_OR_NEWER public static readonly GUIContent playerBuildSettings = EditorGUIUtility.TrTextContent("Player Build Settings"); public static readonly GUIContent enableAddressableBuildPreprocessPlayer = EditorGUIUtility.TrTextContent("Build Addressables on build Player", $"If enabled, will perform a new Addressables build before building a Player. Addressable Asset Settings value can override the user global preferences."); +#endif } static AddressablesPreferences() diff --git a/Editor/Settings/ProfileDataSourceSettings.cs b/Editor/Settings/ProfileDataSourceSettings.cs index ac3a2d1b..f8e3b28f 100644 --- a/Editor/Settings/ProfileDataSourceSettings.cs +++ b/Editor/Settings/ProfileDataSourceSettings.cs @@ -21,7 +21,7 @@ namespace UnityEditor.AddressableAssets.Settings /// /// Scriptable Object that holds data source setting information for the profile data source dropdown window /// - public class ProfileDataSourceSettings : ScriptableObject + public class ProfileDataSourceSettings : ScriptableObject, ISerializationCallbackReceiver { const string DEFAULT_PATH = "Assets/AddressableAssetsData"; const string DEFAULT_NAME = "ProfileDataSourceSettings"; @@ -57,7 +57,7 @@ public static ProfileDataSourceSettings Create(string path = null, string settin aa = CreateInstance(); AssetDatabase.CreateAsset(aa, assetPath); aa = AssetDatabase.LoadAssetAtPath(assetPath); - aa.profileGroupTypes.AddRange(CreateDefaultGroupTypes()); + aa.profileGroupTypes = CreateDefaultGroupTypes(); EditorUtility.SetDirty(aa); } return aa; @@ -81,9 +81,7 @@ public static ProfileDataSourceSettings GetSettings(string path = null, string s aa = AssetDatabase.LoadAssetAtPath(assetPath); if (aa == null) - { return Create(); - } return aa; } @@ -91,21 +89,22 @@ public static ProfileDataSourceSettings GetSettings(string path = null, string s /// Creates a list of default group types that are automatically added on ProfileDataSourceSettings object creation /// /// List of ProfileGroupTypes: Built-In and Editor Hosted - public static List CreateDefaultGroupTypes() + public static List CreateDefaultGroupTypes() => new List{CreateBuiltInGroupType(), CreateEditorHostedGroupType()}; + + static ProfileGroupType CreateBuiltInGroupType() { - List groupTypes = new List(); - ProfileGroupType defaultBuiltIn = new ProfileGroupType("Built-In"); + ProfileGroupType defaultBuiltIn = new ProfileGroupType(AddressableAssetSettings.LocalGroupTypePrefix); defaultBuiltIn.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kBuildPath, AddressableAssetSettings.kLocalBuildPathValue)); defaultBuiltIn.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kLoadPath, AddressableAssetSettings.kLocalLoadPathValue)); + return defaultBuiltIn; + } - ProfileGroupType defaultRemote = new ProfileGroupType("Editor Hosted"); + static ProfileGroupType CreateEditorHostedGroupType() + { + ProfileGroupType defaultRemote = new ProfileGroupType(AddressableAssetSettings.EditorHostedGroupTypePrefix); defaultRemote.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kBuildPath, AddressableAssetSettings.kRemoteBuildPathValue)); - defaultRemote.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kLoadPath, AddressableAssetSettings.kRemoteLoadPathValue)); - - groupTypes.Add(defaultBuiltIn); - groupTypes.Add(defaultRemote); - - return groupTypes; + defaultRemote.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kLoadPath, AddressableAssetSettings.RemoteLoadPathValue)); + return defaultRemote; } /// @@ -157,8 +156,8 @@ public static async Task> UpdateCCDDataSourcesAsync(strin { if (showInfoLog) Addressables.Log("Syncing CCD Buckets and Badges."); var settings = GetSettings(); - settings.profileGroupTypes = new List(); - settings.profileGroupTypes.AddRange(CreateDefaultGroupTypes()); + var profileGroupTypes = new List(); + profileGroupTypes.AddRange(CreateDefaultGroupTypes()); await CCDManagementAPIService.SetConfigurationAuthHeader(CloudProjectSettings.accessToken); var bucketDictionary = await GetAllBucketsAsync(projectId); @@ -166,7 +165,7 @@ public static async Task> UpdateCCDDataSourcesAsync(strin { var bucket = kvp.Value; var badges = await GetAllBadgesAsync(projectId, bucket.Id.ToString()); - if (badges.Count == 0) continue; + if (badges.Count == 0) badges.Add(new CcdBadge(name: "latest")); foreach (var badge in badges) { var groupType = new ProfileGroupType($"CCD{ProfileGroupType.k_PrefixSeparator}{projectId}{ProfileGroupType.k_PrefixSeparator}{bucket.Id}{ProfileGroupType.k_PrefixSeparator}{badge.Name}"); @@ -181,9 +180,10 @@ public static async Task> UpdateCCDDataSourcesAsync(strin string loadPath = $"https://{projectId}.client-api.unity3dusercontent.com/client_api/v1/buckets/{bucket.Id}/release_by_badge/{badge.Name}/entry_by_path/content/?path="; groupType.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kLoadPath, loadPath)); - settings.profileGroupTypes.Add(groupType); + profileGroupTypes.Add(groupType); } } + settings.profileGroupTypes = profileGroupTypes; if (showInfoLog) Addressables.Log("Successfully synced CCD Buckets and Badges."); EditorUtility.SetDirty(settings); AddressableAssetUtility.OpenAssetIfUsingVCIntegration(settings); @@ -236,5 +236,36 @@ private static async Task> GetAllBadgesAsync(string projectId, st return badges; } #endif + void ISerializationCallbackReceiver.OnBeforeSerialize() + { + } + + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + // Ensure static Group types have the correct string + // Local + var types = GetGroupTypesByPrefix(AddressableAssetSettings.LocalGroupTypePrefix); + if (types == null || types.Count == 0) + profileGroupTypes.Add(CreateBuiltInGroupType()); + else + { + types[0].AddOrUpdateVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kBuildPath, + AddressableAssetSettings.kLocalBuildPathValue)); + types[0].AddOrUpdateVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kLoadPath, + AddressableAssetSettings.kLocalLoadPathValue)); + } + + // Editor Hosted + types = GetGroupTypesByPrefix(AddressableAssetSettings.EditorHostedGroupTypePrefix); + if (types.Count == 0) + profileGroupTypes.Add(CreateEditorHostedGroupType()); + else + { + types[0].AddOrUpdateVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kBuildPath, + AddressableAssetSettings.kRemoteBuildPathValue)); + types[0].AddOrUpdateVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kLoadPath, + AddressableAssetSettings.RemoteLoadPathValue)); + } + } } } diff --git a/Editor/Settings/ProfileGroupType.cs b/Editor/Settings/ProfileGroupType.cs index 7fe8c401..bfc7e838 100644 --- a/Editor/Settings/ProfileGroupType.cs +++ b/Editor/Settings/ProfileGroupType.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -105,20 +105,33 @@ internal string GetName(GroupTypeVariable variable) /// Adds a variable in the group /// /// - /// the added variable - internal GroupTypeVariable AddVariable(GroupTypeVariable variable) + /// True if the variable was added, false if the variable already exists + internal bool AddVariable(GroupTypeVariable variable) { GroupTypeVariable exists = m_Variables.Where(ps => ps.Suffix == variable.Suffix).FirstOrDefault(); if (exists != null) { Addressables.LogErrorFormat("{0} already exists.", GetName(variable)); - return null; + return false; } - else + m_Variables.Add(variable); + return true; + } + + + // Adds a variable to the group, or updates the value if already exists + internal void AddOrUpdateVariable(GroupTypeVariable variable) + { + foreach (GroupTypeVariable typeVariable in m_Variables) { - m_Variables.Add(variable); + if (typeVariable.Suffix == variable.Suffix) + { + typeVariable.Value = variable.Value; + return; + } } - return variable; + + m_Variables.Add(variable); } /// diff --git a/Editor/Settings/ProfileValueReference.cs b/Editor/Settings/ProfileValueReference.cs index acec6b01..e2a11d51 100644 --- a/Editor/Settings/ProfileValueReference.cs +++ b/Editor/Settings/ProfileValueReference.cs @@ -83,6 +83,17 @@ public string GetName(AddressableAssetSettings settings) return pid == null ? string.Empty : pid.ProfileName; } + internal bool HasValue(AddressableAssetSettings settings) + { + if (settings == null) + { + Debug.LogWarning("ProfileValueReference: HasValue() - AddressableAssetSettings object is null."); + return false; + } + + return !string.IsNullOrEmpty(settings.profileSettings.GetValueById(settings.activeProfileId, m_Id)); + } + /// /// Set the profile variable id using the id of the variable. /// diff --git a/Runtime/AssetReference.cs b/Runtime/AssetReference.cs index c5f41fd9..56481aec 100644 --- a/Runtime/AssetReference.cs +++ b/Runtime/AssetReference.cs @@ -25,8 +25,12 @@ public class AssetReferenceT : AssetReference where TObject : Object /// Construct a new AssetReference object. /// /// The guid of the asset. - public AssetReferenceT(string guid) : base(guid) + public AssetReferenceT(string guid) + : base(guid) { +#if UNITY_EDITOR + m_DerivedClassType = typeof(TObject); +#endif } /// @@ -83,6 +87,15 @@ public override bool ValidateAsset(string mainAssetPath) return false; #endif } + +#if UNITY_EDITOR + internal TObject FetchAsset() + { + var assetPath = AssetDatabase.GUIDToAssetPath(AssetGUID); + var asset = AssetDatabase.LoadAssetAtPath(assetPath, typeof(TObject)); + return (TObject) asset; + } +#endif #if UNITY_EDITOR /// @@ -93,10 +106,11 @@ public override bool ValidateAsset(string mainAssetPath) { get { - Object baseAsset = base.editorAsset; - TObject asset = baseAsset as TObject; - if (asset == null && baseAsset != null) - Debug.Log("editorAsset cannot cast to " + typeof(TObject)); + if (CachedAsset as TObject != null || string.IsNullOrEmpty(AssetGUID)) + return CachedAsset as TObject; + TObject asset = FetchAsset(); + if (asset == null) + Debug.LogWarning("Assigned editorAsset does not match type " + typeof(TObject) + ". EditorAsset will be null."); return asset; } } @@ -353,6 +367,17 @@ public AssetReference(string guid) EditorApplication.playModeStateChanged += ReleaseHandleWhenPlaymodeStateChanged; #endif } + + //Special constructor only used when constructing in a derived class + internal AssetReference(string guid, Type type) + { + m_AssetGUID = guid; +#if UNITY_EDITOR + m_DerivedClassType = type; + EditorApplication.playModeStateChanged -= ReleaseHandleWhenPlaymodeStateChanged; + EditorApplication.playModeStateChanged += ReleaseHandleWhenPlaymodeStateChanged; +#endif + } #if UNITY_EDITOR void ReleaseHandleWhenPlaymodeStateChanged(PlayModeStateChange state) @@ -629,8 +654,9 @@ public virtual bool ValidateAsset(string path) [SerializeField] #pragma warning disable CS0414 - bool m_EditorAssetChanged; - #pragma warning restore CS0414 + bool m_EditorAssetChanged; + protected internal Type m_DerivedClassType; +#pragma warning restore CS0414 /// /// Used by the editor to represent the main asset referenced. @@ -641,17 +667,32 @@ public virtual Object editorAsset { if (CachedAsset != null || string.IsNullOrEmpty(m_AssetGUID)) return CachedAsset; - var assetPath = AssetDatabase.GUIDToAssetPath(m_AssetGUID); - var mainType = AssetDatabase.GetMainAssetTypeAtPath(assetPath); - return (CachedAsset = AssetDatabase.LoadAssetAtPath(assetPath, mainType)); + + var asset = FetchEditorAsset(); + + if (m_DerivedClassType == null) + return CachedAsset = asset; + + if (asset == null) + Debug.LogWarning("Assigned editorAsset does not match type " + m_DerivedClassType + ". EditorAsset will be null."); + return CachedAsset = asset; } } + + internal Object FetchEditorAsset() + { + var assetPath = AssetDatabase.GUIDToAssetPath(m_AssetGUID); + var asset = AssetDatabase.LoadAssetAtPath(assetPath, m_DerivedClassType ?? AssetDatabase.GetMainAssetTypeAtPath(assetPath)); + return asset; + } + /// /// Sets the main asset on the AssetReference. Only valid in the editor, this sets both the editorAsset attribute, /// and the internal asset GUID, which drives the RuntimeKey attribute. If the reference uses a sub object, /// then it will load the editor asset during edit mode and load the sub object during runtime. For example, if /// the AssetReference is set to a sprite within a sprite atlas, the editorAsset is the atlas (loaded during edit mode) - /// and the sub object is the sprite (loaded during runtime). + /// and the sub object is the sprite (loaded during runtime). If called by AssetReferenceT, will set the editorAsset + /// to the requested object if the object is of type T, and null otherwise. /// Object to reference /// public virtual bool SetEditorAsset(Object value) @@ -682,10 +723,16 @@ public virtual bool SetEditorAsset(Object value) else { m_AssetGUID = AssetDatabase.AssetPathToGUID(path); - var mainAsset = AssetDatabase.LoadMainAssetAtPath(path); + Object mainAsset; + if (m_DerivedClassType != null) + mainAsset = LocateEditorAssetForTypedAssetReference(value, path); + else + { + mainAsset = AssetDatabase.LoadMainAssetAtPath(path); + if (value != mainAsset) + SetEditorSubObject(value); + } CachedAsset = mainAsset; - if (value != mainAsset) - SetEditorSubObject(value); } } @@ -693,6 +740,37 @@ public virtual bool SetEditorAsset(Object value) return true; } + internal Object LocateEditorAssetForTypedAssetReference(Object value, string path) + { + Object mainAsset; + if (value.GetType() != m_DerivedClassType) + { + mainAsset = null; + } + else + { + mainAsset = AssetDatabase.LoadAssetAtPath(path, m_DerivedClassType); + if (mainAsset != value) + { + mainAsset = null; + var subAssets = AssetDatabase.LoadAllAssetRepresentationsAtPath(path); + foreach (var asset in subAssets) + { + if (asset.GetType() == m_DerivedClassType && value == asset) + { + mainAsset = asset; + break; + } + } + } + } + if (mainAsset == null) + Debug.LogWarning( "Assigned editorAsset does not match type " + m_DerivedClassType + ". EditorAsset will be null."); + + return mainAsset; + } + + /// /// Sets the sub object for this asset reference. /// diff --git a/Samples~/ImportExistingGroup/Editor/ImportExistingGroup.cs b/Samples~/ImportExistingGroup/Editor/ImportExistingGroup.cs index 7b22daac..f38bcf9a 100644 --- a/Samples~/ImportExistingGroup/Editor/ImportExistingGroup.cs +++ b/Samples~/ImportExistingGroup/Editor/ImportExistingGroup.cs @@ -1,6 +1,7 @@ #if UNITY_EDITOR using System; using System.Collections; +using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEditor.AddressableAssets; @@ -145,11 +146,22 @@ void ImportSchemasInternal(AddressableAssetSettings settings, string groupName, } if (schema is BundledAssetGroupSchema bundledSchema) { - bundledSchema.BuildPath.SetVariableByName(settings, AddressableAssetSettings.kLocalBuildPath); - bundledSchema.LoadPath.SetVariableByName(settings, AddressableAssetSettings.kLocalLoadPath); + List variableNames = schema.Group.Settings.profileSettings.GetVariableNames(); + SetBundledAssetGroupSchemaPaths(settings, bundledSchema.BuildPath, AddressableAssetSettings.kLocalBuildPath,"LocalBuildPath", variableNames); + SetBundledAssetGroupSchemaPaths(settings, bundledSchema.LoadPath, AddressableAssetSettings.kLocalLoadPath,"LocalLoadPath", variableNames); } group.AddSchema(schema); } } + + internal void SetBundledAssetGroupSchemaPaths(AddressableAssetSettings settings, ProfileValueReference pvr, string newVariableName, string oldVariableName, List variableNames) + { + if (variableNames.Contains(newVariableName)) + pvr.SetVariableByName(settings, newVariableName); + else if (variableNames.Contains(oldVariableName)) + pvr.SetVariableByName(settings, oldVariableName); + else + Debug.LogWarning("Default path variable " + newVariableName + " not found when initializing BundledAssetGroupSchema. Please manually set the path via the groups window."); + } } #endif diff --git a/Tests/Editor/AddressableAssetFolderSubfolderTests.cs b/Tests/Editor/AddressableAssetFolderSubfolderTests.cs index 72582b8c..732ba139 100644 --- a/Tests/Editor/AddressableAssetFolderSubfolderTests.cs +++ b/Tests/Editor/AddressableAssetFolderSubfolderTests.cs @@ -195,11 +195,13 @@ public void WhenFileIsNotInAssetDatabase_EnumerateFiles_DoesNotReturnPath() { string folderPath = m_TestFolderPath + "/TestFolder"; AssetDatabase.CreateFolder(m_TestFolderPath, "TestFolder"); - File.Create(folderPath + "/.hiddenfile"); + string filePath = Path.Combine(folderPath, ".hiddenfile"); + File.Create(filePath).Close(); List assetPaths = EnumerateAddressableFolder(folderPath, Settings, true); Assert.AreEqual(0, assetPaths.Count); + File.Delete(filePath); AssetDatabase.DeleteAsset(folderPath); } diff --git a/Tests/Editor/AddressableAssetReferenceTests.cs b/Tests/Editor/AddressableAssetReferenceTests.cs index 88fe1caa..906c9ae0 100644 --- a/Tests/Editor/AddressableAssetReferenceTests.cs +++ b/Tests/Editor/AddressableAssetReferenceTests.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; @@ -8,7 +7,6 @@ using UnityEditor.AddressableAssets.Settings; using UnityEditor.U2D; using UnityEngine.U2D; - namespace UnityEditor.AddressableAssets.Tests { public class AddressableAssetReferenceTests : AddressableAssetTestBase @@ -16,16 +14,21 @@ public class AddressableAssetReferenceTests : AddressableAssetTestBase private string m_ScriptableObjectPath; private string m_SpriteAtlasPath; private string m_TexturePath; + TestObject mainSO; + TestSubObject subSO; + TestSubObject subSO2; protected override void OnInit() { - var mainSO = ScriptableObject.CreateInstance(); - var subSO = ScriptableObject.CreateInstance(); + mainSO = ScriptableObject.CreateInstance(); + subSO = ScriptableObject.CreateInstance(); + subSO2 = ScriptableObject.CreateInstance(); subSO.name = "sub"; m_ScriptableObjectPath = GetAssetPath("testScriptableObject.asset"); AssetDatabase.CreateAsset(mainSO, m_ScriptableObjectPath); AssetDatabase.AddObjectToAsset(subSO, m_ScriptableObjectPath); + AssetDatabase.AddObjectToAsset(subSO2, m_ScriptableObjectPath); AssetDatabase.ImportAsset(m_ScriptableObjectPath, ImportAssetOptions.ForceSynchronousImport | ImportAssetOptions.ForceUpdate); // create a Sprite atlas, + sprite @@ -72,6 +75,70 @@ public void AssetReference_SetMainAsset_ResetsSubAsset() Assert.IsNull(typeReference.SubObjectName); } + [Test] + public void AssetReference_SetEditorAsset_NullsOnAttemptWithWrongTypeFromDerivedType() + { + var guid = AssetDatabase.AssetPathToGUID(m_ScriptableObjectPath); + AssetReference typeConflictReference = new AssetReferenceT("badguid"); + typeConflictReference.SetEditorAsset(mainSO); + Assert.IsNull(typeConflictReference.editorAsset, "Attempting to set editor asset on an AssetReferenceT should return null if the types do not match."); + } + + [Test] + public void AssetReference_SetEditorAsset_SucceedsOnMatchedTypeAssetReference() + { + AssetReference typeCorrectReference = new AssetReferenceT("badguid"); + typeCorrectReference.SetEditorAsset(subSO); + Assert.NotNull(typeCorrectReference.editorAsset, "Attempting to set editor asset on an AssetReferenceT should return the first matching object at the guid"); + Assert.AreEqual(subSO, typeCorrectReference.editorAsset, "Attempting to set editor asset on an AssetReferenceT should return the first matching object at the guid"); + } + + [Test] + public void AssetReference_SetEditorAsset_GetsRequestedAssetTypeOnUntypedAssetReference() + { + AssetReference untypedAssetReference = new AssetReference("badguid"); + untypedAssetReference.SetEditorAsset(mainSO); + Assert.AreEqual(mainSO, untypedAssetReference.editorAsset, "Attempting to set editor asset on an untyped AssetReference should return the requested object"); + } + + [Test] + public void AssetReference_SetEditorAsset_CorrectlyRetrievesSubAsset() + { + AssetReference untypedAssetReference = new AssetReference("badguid"); + untypedAssetReference.SetEditorAsset(subSO); + Assert.AreEqual(mainSO, untypedAssetReference.editorAsset, "Attempting to use SetEditorAsset on untyped AssetReference should give main asset as editorAsset, subAsset as subAsset"); + Assert.AreEqual(subSO.name, untypedAssetReference.SubObjectName, "Attempting to use SetEditorAsset on a subObject in an untyped AssetReference should make the requested asset the subasset of the assetReference." ); + } + + [Test] + public void AssetReference_SetEditorAsset_CorrectlySetsSubAssetWhenUsingTypedReference() + { + AssetReferenceT typedAssetReference = new AssetReferenceT("badguid"); + typedAssetReference.SetEditorAsset(subSO); + Assert.AreEqual(subSO, typedAssetReference.editorAsset, "When using a typed asset reference, the editor asset should be set to the requested object even if its a subobject."); + AssetReference typedAssetReference2 = new AssetReferenceT("badguid"); + typedAssetReference2.SetEditorAsset(subSO); + Assert.AreEqual(subSO, typedAssetReference2.editorAsset, "When using a typed asset reference, the editor asset should be set to the requested object even if its a subobject."); + } + + [Test] + public void AssetReference_SetEditorAsset_ReturnsNullIfObjectTypeIsIncorrect() + { + AssetReferenceT incorrectlyTypedAssetReference = new AssetReferenceT("badguid"); + incorrectlyTypedAssetReference.SetEditorAsset(subSO); + Assert.IsNull(incorrectlyTypedAssetReference.editorAsset, "Attempting to set an editor asset of an incorrect type should return null."); + } + + [Test] + public void AssetReference_SetEditorAsset_ReturnsCorrectObjectIfMultipleOfSameTypeExist() + { + AssetReferenceT typedAssetReference = new AssetReferenceT("badguid"); + typedAssetReference.SetEditorAsset(subSO2); + Assert.AreEqual(subSO2, typedAssetReference.editorAsset, "When using a typed asset reference, the editor asset should be set to the requested object even if its a subobject."); + Assert.AreNotEqual(subSO, typedAssetReference.editorAsset, "When using a typed asset reference, the editor asset should be set to specifically the requested object, not just an object with the same type and guid."); + } + + [Test] public void AssetReferenceEditorAssetForSubObject_DifferentType() { @@ -80,10 +147,27 @@ public void AssetReferenceEditorAssetForSubObject_DifferentType() typeReference.SubObjectName = "sub"; //Test - Assert.IsNull(typeReference.editorAsset); + Assert.AreEqual(typeReference.editorAsset, AssetDatabase.LoadAssetAtPath(m_ScriptableObjectPath), "AssetReference with explicit type should get first instance of that type at that guid."); AssetReference asBase = typeReference; Assert.IsNotNull(asBase.editorAsset); - Assert.AreEqual(asBase.editorAsset, AssetDatabase.LoadAssetAtPath(m_ScriptableObjectPath)); + Assert.AreEqual(asBase.editorAsset, AssetDatabase.LoadAssetAtPath(m_ScriptableObjectPath), "AssetReference with explicit type declared under generic AssetReference should still get the first instance of the specific type at the guid."); + AssetReference baseReference = new AssetReference(guid); + Assert.AreEqual(baseReference.editorAsset, AssetDatabase.LoadAssetAtPath(m_ScriptableObjectPath), "Generic AssetReference should get the asset of the main type at the guid."); + } + + [Test] + public void AssetReferenceEditorAssetForSubObject_NullIfIncorrectType() + { + var guid = AssetDatabase.AssetPathToGUID(m_ScriptableObjectPath); + AssetReferenceT typeReference = new AssetReferenceT(guid); + typeReference.SubObjectName = "sub"; + + //Test + Assert.IsNull(typeReference.editorAsset, "Attempting to get an object of a type not located at a guid should return a null value."); + AssetReference asBase = typeReference; + Assert.IsNull(asBase.editorAsset, "Attempting to get an object type not located at a guid should return a null value even if the method of the generic AssetReference class is being called."); + AssetReference baseReference = new AssetReference(guid); + Assert.AreEqual(baseReference.editorAsset, AssetDatabase.LoadAssetAtPath(m_ScriptableObjectPath), "Generic AssetReference should get the asset of the main type at the guid."); } [Test] diff --git a/Tests/Editor/ContentUpdateTests.cs b/Tests/Editor/ContentUpdateTests.cs index 4221aadb..6dbb1f20 100644 --- a/Tests/Editor/ContentUpdateTests.cs +++ b/Tests/Editor/ContentUpdateTests.cs @@ -22,7 +22,7 @@ namespace UnityEditor.AddressableAssets.Tests public class ContentUpdateTests : AddressableAssetTestBase { protected override bool PersistSettings { get { return true; } } - + [Ignore("Editor crash https://jira.unity3d.com/browse/BPSBP-142")] [Test] public void CanCreateContentStateData() { diff --git a/Tests/Editor/GroupSchemaTests.cs b/Tests/Editor/GroupSchemaTests.cs index dbe16cd5..43afc644 100644 --- a/Tests/Editor/GroupSchemaTests.cs +++ b/Tests/Editor/GroupSchemaTests.cs @@ -1,7 +1,11 @@ using System; +using System.Collections.Generic; using System.IO; using NUnit.Framework; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.AddressableAssets.Settings.GroupSchemas; using UnityEngine; +using UnityEngine.TestTools; namespace UnityEditor.AddressableAssets.Tests { @@ -180,4 +184,197 @@ public void ModifyingGroupName_ChangesSchemaAssetPath() Assert.IsTrue(group.RemoveSchema()); } } + + class BundledAssetGroupSchemaTests : EditorAddressableAssetsTestFixture + { + [Test] + public void BundledAssetGroupSchema_OnSetGroup_SendsWarningsForNullBuildAndLoadPath() + { + AddressableAssetGroup group = null; + try + { + m_Settings.profileSettings.RemoveValue(m_Settings.profileSettings.GetVariableId(AddressableAssetSettings.kLocalLoadPath)); + m_Settings.profileSettings.RemoveValue(m_Settings.profileSettings.GetVariableId(AddressableAssetSettings.kLocalBuildPath)); + group = m_Settings.CreateGroup("Group1", false, false, false, null, typeof(BundledAssetGroupSchema)); + LogAssert.Expect(LogType.Warning, "Default path variable " + AddressableAssetSettings.kLocalBuildPath + " not found when initializing BundledAssetGroupSchema. Please manually set the path via the groups window."); + LogAssert.Expect(LogType.Warning, "Default path variable " + AddressableAssetSettings.kLocalLoadPath + " not found when initializing BundledAssetGroupSchema. Please manually set the path via the groups window."); + } + finally + { + if (group != null) + m_Settings.RemoveGroupInternal(group, true, false); + m_Settings.profileSettings.CreateValue(AddressableAssetSettings.kLocalBuildPath, AddressableAssetSettings.kLocalBuildPathValue); + m_Settings.profileSettings.CreateValue(AddressableAssetSettings.kLocalLoadPath, AddressableAssetSettings.kLocalLoadPathValue); + } + } + + [Test] + public void BundledAssetGroupSchema_BuildLoadPathsCanBeSetByReference() + { + AddressableAssetGroup group = null; + try + { + //Set up new profile state + m_Settings.profileSettings.RemoveValue(m_Settings.profileSettings.GetVariableId(AddressableAssetSettings.kLocalLoadPath)); + m_Settings.profileSettings.RemoveValue(m_Settings.profileSettings.GetVariableId(AddressableAssetSettings.kLocalBuildPath)); + m_Settings.profileSettings.CreateValue("LocalLoadPath", "loadDefault1"); + m_Settings.profileSettings.CreateValue("LocalBuildPath", "buildDefault1"); + + //Create group with BundledAssetGroupSchema + group = m_Settings.CreateGroup("Group1", false, false, false, null, typeof(BundledAssetGroupSchema)); + var schema = group.GetSchema(); + List variableNames = m_Settings.profileSettings.GetVariableNames(); + SetBundledAssetGroupSchemaPaths(m_Settings, schema.BuildPath, AddressableAssetSettings.kLocalBuildPath, "LocalBuildPath",variableNames); + SetBundledAssetGroupSchemaPaths(m_Settings, schema.LoadPath, AddressableAssetSettings.kLocalLoadPath,"LocalLoadPath", variableNames); + + var expectedLoadPath = m_Settings.profileSettings.GetValueByName(m_Settings.activeProfileId, "LocalLoadPath"); + var expectedBuildPath = m_Settings.profileSettings.GetValueByName(m_Settings.activeProfileId, "LocalBuildPath"); + + Assert.AreEqual(expectedLoadPath, schema.LoadPath.GetValue(m_Settings), "Load path was not properly set within BundledAssetGroupSchema.OnSetGroup"); + Assert.AreEqual(expectedBuildPath, schema.BuildPath.GetValue(m_Settings), "Build path was not properly set within BundledAssetGroupSchema.OnSetGroup"); + } + finally + { + if (group != null) + m_Settings.RemoveGroupInternal(group, true, false); + m_Settings.profileSettings.CreateValue(AddressableAssetSettings.kLocalBuildPath, AddressableAssetSettings.kLocalBuildPathValue); + m_Settings.profileSettings.CreateValue(AddressableAssetSettings.kLocalLoadPath, AddressableAssetSettings.kLocalLoadPathValue); + m_Settings.profileSettings.RemoveValue("LocalLoadPath"); + m_Settings.profileSettings.RemoveValue("LocalBuildPath"); + } + } + + internal void SetBundledAssetGroupSchemaPaths(AddressableAssetSettings settings, ProfileValueReference pvr, string newVariableName, string oldVariableName, List variableNames) + { + if (variableNames.Contains(newVariableName)) + pvr.SetVariableByName(settings, newVariableName); + else if (variableNames.Contains(oldVariableName)) + pvr.SetVariableByName(settings, oldVariableName); + else + Debug.LogWarning("Default path variable not found when initializing BundledAssetGroupSchema. Please manually set the path via the groups window."); + } + + [Test] + public void BundledAssetGroupSchema_OnSetGroup_DefaultsToOldVariablesIfNewNotPresent() + { + AddressableAssetGroup group = null; + try + { + //Set up new profile state + m_Settings.profileSettings.RemoveValue(m_Settings.profileSettings.GetVariableId(AddressableAssetSettings.kLocalLoadPath)); + m_Settings.profileSettings.RemoveValue(m_Settings.profileSettings.GetVariableId(AddressableAssetSettings.kLocalBuildPath)); + m_Settings.profileSettings.CreateValue("LocalLoadPath", "loadDefault1"); + m_Settings.profileSettings.CreateValue("LocalBuildPath", "buildDefault1"); + var defaultId = m_Settings.profileSettings.GetProfileId("Default"); + var profile1Id = m_Settings.profileSettings.AddProfile("BundledAssetGroupSchemaTestsProfile1", defaultId); + + + //Create group with BundledAssetGroupSchema + group = m_Settings.CreateGroup("Group1", false, false, false, null, typeof(BundledAssetGroupSchema)); + + Assert.AreEqual("loadDefault1", m_Settings.profileSettings.GetValueByName(profile1Id, "LocalLoadPath"), "Old variables value was not properly transferred over to new variable."); + Assert.AreEqual("buildDefault1", m_Settings.profileSettings.GetValueByName(profile1Id, "LocalBuildPath"), "Old variables value was not properly transferred over to new variable."); + var schema = group.GetSchema(); + var expectedLoadPath = m_Settings.profileSettings.GetValueByName(m_Settings.activeProfileId, "LocalLoadPath"); + var expectedBuildPath = m_Settings.profileSettings.GetValueByName(m_Settings.activeProfileId, "LocalBuildPath"); + + Assert.AreEqual(expectedLoadPath, schema.LoadPath.GetValue(m_Settings), "Load path was not properly set within BundledAssetGroupSchema.OnSetGroup"); + Assert.AreEqual(expectedBuildPath, schema.BuildPath.GetValue(m_Settings), "Build path was not properly set within BundledAssetGroupSchema.OnSetGroup"); + } + finally + { + if (group != null) + m_Settings.RemoveGroupInternal(group, true, false); + m_Settings.profileSettings.CreateValue(AddressableAssetSettings.kLocalBuildPath, AddressableAssetSettings.kLocalBuildPathValue); + m_Settings.profileSettings.CreateValue(AddressableAssetSettings.kLocalLoadPath, AddressableAssetSettings.kLocalLoadPathValue); + m_Settings.profileSettings.RemoveValue("LocalLoadPath"); + m_Settings.profileSettings.RemoveValue("LocalBuildPath"); + } + } + + [Test] + public void BundledAssetGroupSchema_OnSetGroup_GivenChoiceOfNewAndOldVariablesChoosesNew() + { + AddressableAssetGroup group = null; + try + { + //Set up new profile state + m_Settings.profileSettings.CreateValue("LocalLoadPath", "WrongLoadValue"); + m_Settings.profileSettings.CreateValue("LocalBuildPath", "WrongBuildValue"); + m_Settings.profileSettings.SetValue(m_Settings.activeProfileId, "Local.LoadPath", "CorrectLoadValue"); + m_Settings.profileSettings.SetValue(m_Settings.activeProfileId, "Local.BuildPath", "CorrectBuildValue"); + + //Create group with BundledAssetGroupSchema + group = m_Settings.CreateGroup("BundledAssetGroupSchemaTestGroup1", false, false, false, null, typeof(BundledAssetGroupSchema)); + + var schema = group.GetSchema(); + var expectedLoadPath = m_Settings.profileSettings.GetValueByName(m_Settings.activeProfileId, "Local.LoadPath"); + var expectedBuildPath = m_Settings.profileSettings.GetValueByName(m_Settings.activeProfileId, "Local.BuildPath"); + + var loadValue = schema.LoadPath.GetValue(m_Settings); + var buildValue = schema.BuildPath.GetValue(m_Settings); + + Assert.AreEqual(expectedLoadPath, loadValue, "Load path was not properly set within BundledAssetGroupSchema.OnSetGroup"); + Assert.AreEqual(expectedBuildPath, buildValue, "Build path was not properly set within BundledAssetGroupSchema.OnSetGroup"); + Assert.AreEqual("CorrectLoadValue", loadValue, "Path value is correctly set to the value of Local.LoadPath"); + Assert.AreEqual("CorrectBuildValue", buildValue, "Build value is correctly set to the value of Local.BuildPath"); + } + finally + { + if (group != null) + m_Settings.RemoveGroupInternal(group, true, false); + m_Settings.profileSettings.CreateValue(AddressableAssetSettings.kLocalBuildPath, AddressableAssetSettings.kLocalBuildPathValue); + m_Settings.profileSettings.CreateValue(AddressableAssetSettings.kLocalLoadPath, AddressableAssetSettings.kLocalLoadPathValue); + m_Settings.profileSettings.RemoveValue("LocalLoadPath"); + m_Settings.profileSettings.RemoveValue("LocalBuildPath"); + } + } + + [Test] + public void BundledAssetGroupSchema_OnSetGroup_SetsVariableAsExpectedWhenUserHasCorrectBuildPath() + { + AddressableAssetGroup group = null; + try + { + //Group should default to having the correct default values + group = m_Settings.CreateGroup("Group1", false, false, false, null, typeof(BundledAssetGroupSchema)); + var schema = group.GetSchema(); + var activeProfileId = m_Settings.activeProfileId; + var expectedLoadValuePreEvaluate = m_Settings.profileSettings.GetValueByName(activeProfileId, "Local.LoadPath"); + var expectedBuildValuePreEvaluate = m_Settings.profileSettings.GetValueByName(activeProfileId, "Local.BuildPath"); + Assert.AreEqual(m_Settings.profileSettings.EvaluateString(activeProfileId, expectedLoadValuePreEvaluate), schema.LoadPath.GetValue(m_Settings), "Value is not correctly set in the basic case where user has the default load path already created."); + Assert.AreEqual(m_Settings.profileSettings.EvaluateString(activeProfileId, expectedBuildValuePreEvaluate), schema.BuildPath.GetValue(m_Settings), "Value is not correctly set in the basic case where user has the default build path already created."); + } + finally + { + if (group != null) + m_Settings.RemoveGroupInternal(group, true, false); + } + } + + [Test] + public void BundledAssetGroupSchema_SetPathVariable_ProperlySetsReferenceOnPath() + { + AddressableAssetGroup group = null; + ProfileValueReference pathValue = null; + BundledAssetGroupSchema schema = null; + try + { + Type[] types = new Type[]{}; + group = m_Settings.CreateGroup("Group1", false, false, false, null, types); + List variableNames = new List(); + variableNames.Add("LocalBuildPath"); + variableNames.Add(AddressableAssetSettings.kLocalBuildPath); + schema = ScriptableObject.CreateInstance(); + schema.SetPathVariable(group.Settings, ref pathValue, AddressableAssetSettings.kLocalBuildPath, "LocalBuildPath", variableNames); + } + finally + { + if (group != null) + m_Settings.RemoveGroupInternal(group, true, false); + if (schema != null) + ScriptableObject.DestroyImmediate(schema); + } + } + } } diff --git a/Tests/Editor/HostingServices/HostingServicesManagerTests.cs b/Tests/Editor/HostingServices/HostingServicesManagerTests.cs index 6bbe3216..c6b0d6a6 100644 --- a/Tests/Editor/HostingServices/HostingServicesManagerTests.cs +++ b/Tests/Editor/HostingServices/HostingServicesManagerTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -7,6 +8,7 @@ using System.Runtime.Serialization; using System.Threading; using NUnit.Framework; +using UnityEditor.AddressableAssets.Build.DataBuilders; using UnityEditor.AddressableAssets.HostingServices; using UnityEditor.AddressableAssets.Settings; using UnityEditor.AddressableAssets.Settings.GroupSchemas; @@ -354,12 +356,96 @@ public void OnEnableShould_RegisterProfileStringEvalFuncForManager() } [Test] - public void OnEnableShould_RefreshGlobalProfileVariables() + public void OnEnableShould_RefreshGlobalProfileVariables_IfNotExitingEditMode() { m_Manager.Initialize(m_Settings); m_Manager.GlobalProfileVariables.Clear(); + bool exitingExitMode = m_Manager.exitingEditMode; + m_Manager.exitingEditMode = false; + m_Manager.OnEnable(); Assert.GreaterOrEqual(m_Manager.GlobalProfileVariables.Count, 1); + + m_Manager.exitingEditMode = exitingExitMode; + } + + [Test] + public void OnEnableShould_RefreshGlobalProfileVariables_IfExitingEditMode_AndServiceEnabled_AndUsingPackedPlayMode() + { + m_Manager.Initialize(m_Settings); + m_Manager.GlobalProfileVariables.Clear(); + bool exitingExitMode = m_Manager.exitingEditMode; + m_Manager.exitingEditMode = true; + + var svc = m_Manager.AddHostingService(typeof(TestHostingService), "test"); + svc.StartHostingService(); + + int activePlayerDataBuilderIndex = m_Settings.ActivePlayerDataBuilderIndex; + m_Settings.DataBuilders.Add(ScriptableObject.CreateInstance()); + m_Settings.ActivePlayerDataBuilderIndex = m_Settings.DataBuilders.Count - 1; + + m_Manager.OnEnable(); + Assert.GreaterOrEqual(m_Manager.GlobalProfileVariables.Count, 1); + svc.StopHostingService(); + + m_Settings.ActivePlayerDataBuilderIndex = activePlayerDataBuilderIndex; + m_Settings.DataBuilders.RemoveAt(m_Settings.DataBuilders.Count - 1); + m_Manager.exitingEditMode = exitingExitMode; + } + + public class RefreshProfileVariablesNegativeTestFactory + { + public static IEnumerable RefreshProfileVariablesNegativeTestCases + { + get + { + bool[,] testCases = + { + { true, false }, + { false, true }, + { false, false } + }; + for (int i = 0; i < testCases.GetLength(0); i++) + { + string serviceStatusText = testCases[i, 0] ? "ServiceEnabled" : "ServiceDisabled"; + string playModeTypeText = testCases[i, 1] ? "UsingPackedPlayMode" : "NotUsingPackedPlayMode"; + string name = $"OnEnableShouldNot_RefreshGlobalProfileVariables_IfExitingEditMode_And{serviceStatusText}_And{playModeTypeText}"; + yield return new TestCaseData(testCases[i, 0], testCases[i, 1]).SetName(name); + } + } + } + } + + [Test] + [TestCaseSource(typeof(RefreshProfileVariablesNegativeTestFactory), "RefreshProfileVariablesNegativeTestCases")] + public void OnEnableShouldNot_RefreshGlobalProfileVariables_IfExitingEditMode_AndConditionsAreMet(bool serviceEnabled, bool usingPackedPlayMode) + { + m_Manager.Initialize(m_Settings); + m_Manager.GlobalProfileVariables.Clear(); + bool exitingExitMode = m_Manager.exitingEditMode; + m_Manager.exitingEditMode = true; + + var svc = m_Manager.AddHostingService(typeof(TestHostingService), "test"); + if (serviceEnabled) + svc.StartHostingService(); + + int activePlayerDataBuilderIndex = m_Settings.ActivePlayerDataBuilderIndex; + if (usingPackedPlayMode) + { + m_Settings.DataBuilders.Add(ScriptableObject.CreateInstance()); + m_Settings.ActivePlayerDataBuilderIndex = m_Settings.DataBuilders.Count - 1; + } + + m_Manager.OnEnable(); + Assert.AreEqual(0, m_Manager.GlobalProfileVariables.Count); + + if (serviceEnabled) + svc.StopHostingService(); + + m_Settings.ActivePlayerDataBuilderIndex = activePlayerDataBuilderIndex; + if (usingPackedPlayMode) + m_Settings.DataBuilders.RemoveAt(m_Settings.DataBuilders.Count - 1); + m_Manager.exitingEditMode = exitingExitMode; } // OnDisable @@ -413,6 +499,7 @@ public void OnDisableShould_DeRegisterProfileStringEvalFuncsForServices() Assert.IsFalse(ProfileStringEvalDelegateIsRegistered(m_Settings, svc)); } + [Ignore("Katana instability https://jira.unity3d.com/browse/ADDR-2327")] [Test] public void OnDisableShould_StopAllServices() { @@ -501,6 +588,7 @@ public void LoggerShould_SetDebugUnityLoggerIfNull() [Test] public void RefreshGlobalProfileVariablesShould_AddOrUpdatePrivateIpAddressVar() { + m_Manager.Initialize(m_Settings); m_Manager.GlobalProfileVariables.Clear(); Assert.IsEmpty(m_Manager.GlobalProfileVariables); m_Manager.RefreshGlobalProfileVariables(); @@ -510,6 +598,7 @@ public void RefreshGlobalProfileVariablesShould_AddOrUpdatePrivateIpAddressVar() [Test] public void RefreshGlobalProfileVariablesShould_RemoveUnknownVars() { + m_Manager.Initialize(m_Settings); m_Manager.GlobalProfileVariables.Add("test", "test"); Assert.IsTrue(m_Manager.GlobalProfileVariables.ContainsKey("test")); m_Manager.RefreshGlobalProfileVariables(); diff --git a/Tests/Editor/ProfileDataSourceSettingsTests.cs b/Tests/Editor/ProfileDataSourceSettingsTests.cs index a0f2f750..e2ef75ac 100644 --- a/Tests/Editor/ProfileDataSourceSettingsTests.cs +++ b/Tests/Editor/ProfileDataSourceSettingsTests.cs @@ -78,9 +78,9 @@ public void InvalidFindGroupType_Returns_ArgumentException() public void NonExistentGroupFindGroupType_Returns_Null() { ProfileGroupType nonexistentGroup = new ProfileGroupType("Test"); - nonexistentGroup.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kBuildPath, "Test Build Path")); - nonexistentGroup.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kLoadPath, "Test Load Path")); - + bool v1Added = nonexistentGroup.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kBuildPath, "Test Build Path")); + bool v2Added = nonexistentGroup.AddVariable(new ProfileGroupType.GroupTypeVariable(AddressableAssetSettings.kLoadPath, "Test Load Path")); + Assert.IsTrue(v1Added && v2Added, "Failed to add the variables for GroupTypes"); var result = Settings.FindGroupType(nonexistentGroup); Assert.IsNull(result); } diff --git a/Tests/Editor/ProfileGroupTypeTests.cs b/Tests/Editor/ProfileGroupTypeTests.cs index 6fdb7082..1d1abc3b 100644 --- a/Tests/Editor/ProfileGroupTypeTests.cs +++ b/Tests/Editor/ProfileGroupTypeTests.cs @@ -31,8 +31,9 @@ public void CreateValidProfileGroupType_Returns_ValidProfileGroupType() ProfileGroupType.GroupTypeVariable buildPath = new ProfileGroupType.GroupTypeVariable("BuildPath", "Test Build Path"); ProfileGroupType.GroupTypeVariable loadPath = new ProfileGroupType.GroupTypeVariable("LoadPath", "Test Load Path"); ProfileGroupType profileGroupType = new ProfileGroupType("prefix"); - profileGroupType.AddVariable(buildPath); - profileGroupType.AddVariable(loadPath); + bool aAdded = profileGroupType.AddVariable(buildPath); + bool bAdded = profileGroupType.AddVariable(loadPath); + Assert.IsTrue(aAdded && bAdded, "Failed to Add variables"); Assert.True(profileGroupType.IsValidGroupType()); } @@ -41,7 +42,8 @@ public void GetPathValuesBySuffix_Returns_ExpectedPathValues() { ProfileGroupType.GroupTypeVariable buildPath = new ProfileGroupType.GroupTypeVariable("BuildPath", "Test Build Path"); ProfileGroupType profileGroupType = new ProfileGroupType("prefix"); - profileGroupType.AddVariable(buildPath); + bool variableAdded = profileGroupType.AddVariable(buildPath); + Assert.IsTrue(variableAdded, "Failed to add GroupType variable"); Assert.AreEqual("Test Build Path", profileGroupType.GetVariableBySuffix(buildPath.Suffix).Value); } @@ -50,31 +52,69 @@ public void GetName_Returns_ExpectedVariableName() { ProfileGroupType.GroupTypeVariable buildPath = new ProfileGroupType.GroupTypeVariable("BuildPath", "Test Build Path"); ProfileGroupType profileGroupType = new ProfileGroupType("prefix"); - profileGroupType.AddVariable(buildPath); + bool gtAdded = profileGroupType.AddVariable(buildPath); + Assert.IsTrue(gtAdded, $"Failed to add groupType {gtAdded}"); Assert.AreEqual("prefix.BuildPath", profileGroupType.GetName(buildPath)); } [Test] - public void AddVariableToGroupType_Returns_ExpectedNotNullVariable() + public void AddVariableToGroupType_AddsVariable() { ProfileGroupType.GroupTypeVariable buildPath = new ProfileGroupType.GroupTypeVariable("BuildPath", "Test Build Path"); ProfileGroupType.GroupTypeVariable loadPath = new ProfileGroupType.GroupTypeVariable("LoadPath", "Test Load Path"); ProfileGroupType profileGroupType = new ProfileGroupType("prefix"); - Assert.NotNull(profileGroupType.AddVariable(buildPath)); - Assert.NotNull(profileGroupType.AddVariable(loadPath)); + Assert.IsTrue(profileGroupType.AddVariable(buildPath)); + Assert.IsTrue(profileGroupType.AddVariable(loadPath)); Assert.True(profileGroupType.Variables.Count == 2); } [Test] - public void AddDuplicateVariableToGroupType_Returns_NullVariable() + public void AddDuplicateVariableToGroupType_FailsToAddVariable() { ProfileGroupType.GroupTypeVariable buildPath = new ProfileGroupType.GroupTypeVariable("BuildPath", "Test Build Path"); ProfileGroupType profileGroupType = new ProfileGroupType("prefix"); - Assert.NotNull(profileGroupType.AddVariable(buildPath)); + Assert.IsTrue(profileGroupType.AddVariable(buildPath)); LogAssert.Expect(LogType.Error, "prefix.BuildPath already exists."); - Assert.Null(profileGroupType.AddVariable(buildPath)); + Assert.IsFalse(profileGroupType.AddVariable(buildPath)); + } + + [Test] + public void AddOrUpdateVariableToGroupType_AddsVariable() + { + ProfileGroupType profileGroupType = new ProfileGroupType("TestPrefix"); + var bp = profileGroupType.GetVariableBySuffix("TestSuffix"); + Assert.IsNull(bp); + + profileGroupType.AddOrUpdateVariable(new ProfileGroupType.GroupTypeVariable("TestSuffix", "TestValue")); + + bp = profileGroupType.GetVariableBySuffix("TestSuffix"); + Assert.IsNotNull(bp); + Assert.AreEqual(bp.m_Value, "TestValue", "Unexpected GroupTypeVariable, variable value should be TestValue"); + Assert.True(profileGroupType.Variables.Count == 1); + } + + [Test] + public void AddOrUpdateVariableToGroupType_UpdatesVariable() + { + ProfileGroupType profileGroupType = new ProfileGroupType("TestPrefix"); + var bp = profileGroupType.GetVariableBySuffix("TestSuffix"); + Assert.IsNull(bp); + + profileGroupType.AddOrUpdateVariable(new ProfileGroupType.GroupTypeVariable("TestSuffix", "TestValue")); + + bp = profileGroupType.GetVariableBySuffix("TestSuffix"); + Assert.IsNotNull(bp); + Assert.AreEqual(bp.m_Value, "TestValue", "Unexpected GroupTypeVariable, variable value should be TestValue"); + Assert.True(profileGroupType.Variables.Count == 1); + + profileGroupType.AddOrUpdateVariable(new ProfileGroupType.GroupTypeVariable("TestSuffix", "UpdatedTestValue")); + + bp = profileGroupType.GetVariableBySuffix("TestSuffix"); + Assert.IsNotNull(bp); + Assert.AreEqual(bp.m_Value, "UpdatedTestValue", "Unexpected GroupTypeVariable, variable value should be UpdatedTestValue"); + Assert.True(profileGroupType.Variables.Count == 1); } [Test] diff --git a/package.json b/package.json index 65b0683a..6bf8bb1a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.unity.addressables", "displayName": "Addressables", - "version": "1.19.9", + "version": "1.19.11", "unity": "2019.4", "description": "The Addressable Asset System allows the developer to ask for an asset via its address. Once an asset (e.g. a prefab) is marked \"addressable\", it generates an address which can be called from anywhere. Wherever the asset resides (local or remote), the system will locate it and its dependencies, then return it.\n\nUse 'Window->Asset Management->Addressables' to begin working with the system.\n\nAddressables use asynchronous loading to support loading from any location with any collection of dependencies. Whether you have been using direct references, traditional asset bundles, or Resource folders, addressables provide a simpler way to make your game more dynamic. Addressables simultaneously opens up the world of asset bundles while managing all the complexity.\n\nFor usage samples, see github.com/Unity-Technologies/Addressables-Sample", "keywords": [ @@ -22,10 +22,10 @@ "repository": { "url": "https://github.cds.internal.unity3d.com/unity/Addressables.git", "type": "git", - "revision": "8c308ac7c6b21457e076d1360a4d07c5d3361316" + "revision": "461277c23420bea0d6e57f13919a4f40b7efca75" }, "upmCi": { - "footprint": "c64a636af6f5dd20230c7fa1c3099e4d88738651" + "footprint": "26fb878eb2d384ec16e99a5c37c10db52455fe71" }, "samples": [ {