/// <summary>
        /// Set the value of a variable for a specified profile.
        /// </summary>
        /// <param name="profileId">The profile id.</param>
        /// <param name="variableName">The property name.</param>
        /// <param name="val">The value to set the property.</param>
        public void SetValue(string profileId, string variableName, string val)
        {
            var profile = GetProfile(profileId);

            if (profile == null)
            {
                Addressables.LogError("setting variable " + variableName + " failed because profile " + profileId + " does not exist.");
                return;
            }

            var id = GetVariableId(variableName);

            if (string.IsNullOrEmpty(id))
            {
                Addressables.LogError("setting variable " + variableName + " failed because variable does not yet exist. Call CreateValue() first.");
                return;
            }

            profile.SetValueById(id, val);
            SetDirty(AddressableAssetSettings.ModificationEvent.ProfileModified, profile, true);
        }
        internal string CreateValue(string variableName, string defaultValue, bool inline)
        {
            if (m_Profiles.Count == 0)
            {
                Addressables.LogError("Attempting to add a profile variable in Addressables, but there are no profiles yet.");
            }

            var id = GetVariableId(variableName);

            if (string.IsNullOrEmpty(id))
            {
                id = GUID.Generate().ToString();
                profileEntryNames.Add(new ProfileIdData(id, variableName, inline));

                foreach (var pro in m_Profiles)
                {
                    pro.values.Add(new BuildProfile.ProfileEntry(id, defaultValue));
                }
            }
            SetDirty(AddressableAssetSettings.ModificationEvent.ProfileModified, null, true);
            return(id);
        }
                public void LoadCatalogFromBundleAsync()
                {
                    //Debug.Log($"LoadCatalogFromBundleAsync frame : {Time.frameCount}");
                    if (m_OpInProgress)
                    {
                        Addressables.LogError($"Operation in progress : A catalog is already being loaded. Please wait for the operation to complete.");
                        return;
                    }

                    m_OpInProgress                 = true;
                    m_LoadBundleRequest            = AssetBundle.LoadFromFileAsync(m_BundlePath);
                    m_LoadBundleRequest.completed += loadOp =>
                    {
                        if (loadOp is AssetBundleCreateRequest createRequest && createRequest.assetBundle != null)
                        {
                            m_CatalogAssetBundle   = createRequest.assetBundle;
                            m_LoadTextAssetRequest = m_CatalogAssetBundle.LoadAllAssetsAsync <TextAsset>();
                            if (m_LoadTextAssetRequest.isDone)
                            {
                                LoadTextAssetRequestComplete(m_LoadTextAssetRequest);
                            }
                            m_LoadTextAssetRequest.completed += LoadTextAssetRequestComplete;
                        }
    internal static List <AssetEntryRevertOperation> DetermineRequiredAssetEntryUpdates(AddressableAssetGroup group, ContentUpdateScript.ContentUpdateContext contentUpdateContext)
    {
        if (!group.HasSchema <BundledAssetGroupSchema>())
        {
            return(new List <AssetEntryRevertOperation>());
        }

        bool groupIsStaticContentGroup = group.HasSchema <ContentUpdateGroupSchema>() && group.GetSchema <ContentUpdateGroupSchema>().StaticContent;
        List <AssetEntryRevertOperation> operations = new List <AssetEntryRevertOperation>();

        foreach (AddressableAssetEntry entry in group.entries)
        {
            GUID guid = new GUID(entry.guid);
            if (!contentUpdateContext.WriteData.AssetToFiles.ContainsKey(guid))
            {
                continue;
            }

            string file = contentUpdateContext.WriteData.AssetToFiles[guid][0];
            string fullInternalBundleName = contentUpdateContext.WriteData.FileToBundle[file];
            string finalBundleWritePath   = contentUpdateContext.BundleToInternalBundleIdMap[fullInternalBundleName];

            //Ensure we can get the catalog entry for the bundle we're looking to replace
            if (!contentUpdateContext.IdToCatalogDataEntryMap.TryGetValue(finalBundleWritePath, out ContentCatalogDataEntry catalogBundleEntry))
            {
                continue;
            }

            //If new entries are added post initial build this will ensure that those new entries have their bundleFileId for SaveContentState
            entry.BundleFileId = catalogBundleEntry.InternalId;

            //If we have no cached state no reason to proceed.  This is new to the build.
            if (!contentUpdateContext.GuidToPreviousAssetStateMap.TryGetValue(entry.guid, out CachedAssetState previousAssetState))
            {
                continue;
            }

            //If the parent group is different we don't want to revert it to its previous state
            if (entry.parentGroup.Guid != previousAssetState.groupGuid)
            {
                continue;
            }

            //If the asset hash has changed and the group is not a static content update group we don't want to revert it to its previous state
            if (AssetDatabase.GetAssetDependencyHash(entry.AssetPath) != previousAssetState.asset.hash && !groupIsStaticContentGroup)
            {
                continue;
            }

            //If the previous asset state has the same bundle file id as the current build we don't want to revert it to its previous state
            if (catalogBundleEntry.InternalId == previousAssetState.bundleFileId)
            {
                continue;
            }

            var    schema    = group.GetSchema <BundledAssetGroupSchema>();
            string loadPath  = schema.LoadPath.GetValue(group.Settings);
            string buildPath = schema.BuildPath.GetValue(group.Settings);

            //Need to check and make sure our cached version exists
            if (string.IsNullOrEmpty(previousAssetState.bundleFileId))
            {
                //Logging this as an error because a CachedAssetState without a set bundleFileId is indicative of a significant issue with the build script.
                Addressables.LogError($"CachedAssetState found for {entry.AssetPath} but the bundleFileId was never set on the previous build.");
                continue;
            }

            string previousBundlePath = previousAssetState.bundleFileId?.Replace(loadPath, buildPath);

            if (!File.Exists(previousBundlePath))
            {
                //Logging this as a warning because users may choose to delete their bundles on disk which will trigger this state.
                Addressables.LogWarning($"CachedAssetState found for {entry.AssetPath} but the previous bundle at {previousBundlePath} cannot be found. " +
                                        $"The modified assets will not be able to use the previously built bundle which will result in new bundles being created " +
                                        $"for these static content groups.  This will point the Content Catalog to local bundles that do not exist on currently " +
                                        $"deployed versions of an application.");
                continue;
            }

            string builtBundlePath = contentUpdateContext.BundleToInternalBundleIdMap[fullInternalBundleName].Replace(loadPath, buildPath);

            AssetEntryRevertOperation operation = new AssetEntryRevertOperation()
            {
                BundleCatalogEntry = catalogBundleEntry,
                AssetEntry         = entry,
                CurrentBuildPath   = builtBundlePath,
                PreviousAssetState = previousAssetState,
                PreviousBuildPath  = previousBundlePath
            };

            operations.Add(operation);
        }
        return(operations);
    }