Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Please don't show Display Dialogue when Addressables used in batch mode.

Discussion in 'Addressables' started by WhiteDoggy, Dec 25, 2021.

  1. WhiteDoggy

    WhiteDoggy

    Joined:
    Sep 10, 2020
    Posts:
    17
    upload_2021-12-25_20-19-51.png



    Hi.
    I am using 'BuldPlayerContent' Method in my build script as in batch mode.

    problem is, it will open the Save Scene Dialogue even if it is batch mode, and even there are no dirty scenes!!!!





    1.png

    2.png


    This is my Jenkins log. I even did saved dirty scenes before execute that method but nothing was different.

    I hope you guys can make that method to choose that will use 'Save Modified Scene' method or not. Or any advise would be grateful!

    Please help!

    Unity: 2020.3.24.f1
    Package: 1.19.15
     
    Last edited: Dec 25, 2021
    Prodigga likes this.
  2. Basti_TinyRoar

    Basti_TinyRoar

    Joined:
    Oct 4, 2016
    Posts:
    11
    Hello @WhiteDoggy !
    Did you find any solution to this? I have exact the same behavior and also tried force saving open scenes already.
     
  3. WhiteDoggy

    WhiteDoggy

    Joined:
    Sep 10, 2020
    Posts:
    17
    Hi. I am sorry that i'm very late.
    Yes. I have simply created my custom pipeline class, and custom BuildScriptBase class, to do same thing except using dialogue.

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Diagnostics;
    4. using System.IO;
    5. using System.Linq;
    6. using System.Text;
    7. using UnityEditor.AddressableAssets.Build.BuildPipelineTasks;
    8. using UnityEditor.AddressableAssets.Settings;
    9. using UnityEditor.AddressableAssets.Settings.GroupSchemas;
    10. using UnityEditor.Build.Pipeline;
    11. using UnityEditor.Build.Pipeline.Interfaces;
    12. using UnityEditor.Build.Pipeline.Tasks;
    13. using UnityEditor.Build.Pipeline.Utilities;
    14. using UnityEditor.SceneManagement;
    15. using UnityEngine;
    16. using UnityEngine.AddressableAssets;
    17. using UnityEngine.AddressableAssets.Initialization;
    18. using UnityEngine.AddressableAssets.ResourceLocators;
    19. using UnityEngine.AddressableAssets.ResourceProviders;
    20. using UnityEngine.Build.Pipeline;
    21. using UnityEngine.ResourceManagement.ResourceProviders;
    22. using UnityEngine.ResourceManagement.Util;
    23. using UnityEngine.SceneManagement;
    24. using static UnityEditor.AddressableAssets.Build.ContentUpdateScript;
    25.  
    26. namespace UnityEditor.AddressableAssets.Build.DataBuilders
    27. {
    28.     using Debug = UnityEngine.Debug;
    29.  
    30.     /// <summary>
    31.     /// Build scripts used for player builds and running with bundles in the editor.
    32.     /// </summary>
    33.     [CreateAssetMenu(fileName = "NoSaveDialogueBuildScript.asset",
    34.         menuName = "Addressables/Content Builders/NoSaveDialogueBuildScript")]
    35.     public class NoSaveDialogueBuildScript : BuildScriptBase
    36.     {
    37.         /// <inheritdoc />
    38.         public override string Name
    39.         {
    40.             get { return "Default Build Script"; }
    41.         }
    42.  
    43.         internal List<ObjectInitializationData> m_ResourceProviderData;
    44.         List<AssetBundleBuild> m_AllBundleInputDefs;
    45.         List<string> m_OutputAssetBundleNames;
    46.         HashSet<string> m_CreatedProviderIds;
    47.         UnityEditor.Build.Pipeline.Utilities.LinkXmlGenerator m_Linker;
    48.         Dictionary<string, string> m_BundleToInternalId = new Dictionary<string, string>();
    49.         private string m_CatalogBuildPath;
    50.  
    51.         internal List<ObjectInitializationData> ResourceProviderData => m_ResourceProviderData.ToList();
    52.  
    53.         /// <inheritdoc />
    54.         public override bool CanBuildData<T>()
    55.         {
    56.             return typeof(T).IsAssignableFrom(typeof(AddressablesPlayerBuildResult));
    57.         }
    58.  
    59.         /// <inheritdoc />
    60.         protected override TResult BuildDataImplementation<TResult>(AddressablesDataBuilderInput builderInput)
    61.         {
    62.             TResult result = default(TResult);
    63.  
    64.             var timer = new Stopwatch();
    65.             timer.Start();
    66.             InitializeBuildContext(builderInput, out AddressableAssetsBuildContext aaContext);
    67.  
    68.             using (m_Log.ScopedStep(LogLevel.Info, "ProcessAllGroups"))
    69.             {
    70.                 var errorString = ProcessAllGroups(aaContext);
    71.                 if (!string.IsNullOrEmpty(errorString))
    72.                     result = AddressableAssetBuildResult.CreateResult<TResult>(null, 0, errorString);
    73.             }
    74.  
    75.             if (result == null)
    76.             {
    77.                 result = DoBuild<TResult>(builderInput, aaContext);
    78.             }
    79.  
    80.             if (result != null)
    81.                 result.Duration = timer.Elapsed.TotalSeconds;
    82.  
    83.             return result;
    84.         }
    85.  
    86.         internal void InitializeBuildContext(AddressablesDataBuilderInput builderInput,
    87.             out AddressableAssetsBuildContext aaContext)
    88.         {
    89.             var aaSettings = builderInput.AddressableSettings;
    90.  
    91.             m_AllBundleInputDefs = new List<AssetBundleBuild>();
    92.             m_OutputAssetBundleNames = new List<string>();
    93.             var bundleToAssetGroup = new Dictionary<string, string>();
    94.             var runtimeData = new ResourceManagerRuntimeData
    95.             {
    96.                 CertificateHandlerType = aaSettings.CertificateHandlerType,
    97.                 BuildTarget = builderInput.Target.ToString(),
    98.                 ProfileEvents = builderInput.ProfilerEventsEnabled,
    99.                 LogResourceManagerExceptions = aaSettings.buildSettings.LogResourceManagerExceptions,
    100.                 DisableCatalogUpdateOnStartup = aaSettings.DisableCatalogUpdateOnStartup,
    101.                 IsLocalCatalogInBundle = aaSettings.BundleLocalCatalog,
    102. #if UNITY_2019_3_OR_NEWER
    103.                 AddressablesVersion =
    104.                     PackageManager.PackageInfo.FindForAssembly(typeof(Addressables).Assembly)?.version,
    105. #endif
    106.                 MaxConcurrentWebRequests = aaSettings.MaxConcurrentWebRequests,
    107.                 CatalogRequestsTimeout = aaSettings.CatalogRequestsTimeout
    108.             };
    109.             m_Linker = UnityEditor.Build.Pipeline.Utilities.LinkXmlGenerator.CreateDefault();
    110.             m_Linker.AddAssemblies(new[]
    111.                 { typeof(Addressables).Assembly, typeof(UnityEngine.ResourceManagement.ResourceManager).Assembly });
    112.             m_Linker.AddTypes(runtimeData.CertificateHandlerType);
    113.  
    114.             m_ResourceProviderData = new List<ObjectInitializationData>();
    115.             aaContext = new AddressableAssetsBuildContext
    116.             {
    117.                 Settings = aaSettings,
    118.                 runtimeData = runtimeData,
    119.                 bundleToAssetGroup = bundleToAssetGroup,
    120.                 locations = new List<ContentCatalogDataEntry>(),
    121.                 providerTypes = new HashSet<Type>(),
    122.                 assetEntries = new List<AddressableAssetEntry>()
    123.             };
    124.  
    125.             m_CreatedProviderIds = new HashSet<string>();
    126.         }
    127.  
    128.         struct SBPSettingsOverwriterScope : IDisposable
    129.         {
    130.             bool m_PrevSlimResults;
    131.  
    132.             public SBPSettingsOverwriterScope(bool forceFullWriteResults)
    133.             {
    134.                 m_PrevSlimResults = ScriptableBuildPipeline.slimWriteResults;
    135.                 if (forceFullWriteResults)
    136.                     ScriptableBuildPipeline.slimWriteResults = false;
    137.             }
    138.  
    139.             public void Dispose()
    140.             {
    141.                 ScriptableBuildPipeline.slimWriteResults = m_PrevSlimResults;
    142.             }
    143.         }
    144.  
    145.         internal static string GetBuiltInShaderBundleNamePrefix(AddressableAssetsBuildContext aaContext)
    146.         {
    147.             return GetBuiltInShaderBundleNamePrefix(aaContext.Settings);
    148.         }
    149.  
    150.         internal static string GetBuiltInShaderBundleNamePrefix(AddressableAssetSettings settings)
    151.         {
    152.             string value = "";
    153.             switch (settings.ShaderBundleNaming)
    154.             {
    155.                 case ShaderBundleNaming.DefaultGroupGuid:
    156.                     value = settings.DefaultGroup.Guid;
    157.                     break;
    158.                 case ShaderBundleNaming.ProjectName:
    159.                     value = Hash128.Compute(GetProjectName()).ToString();
    160.                     break;
    161.                 case ShaderBundleNaming.Custom:
    162.                     value = settings.ShaderBundleCustomNaming;
    163.                     break;
    164.             }
    165.  
    166.             return value;
    167.         }
    168.  
    169.         void AddBundleProvider(BundledAssetGroupSchema schema)
    170.         {
    171.             var bundleProviderId = schema.GetBundleCachedProviderId();
    172.  
    173.             if (!m_CreatedProviderIds.Contains(bundleProviderId))
    174.             {
    175.                 m_CreatedProviderIds.Add(bundleProviderId);
    176.                 var bundleProviderType = schema.AssetBundleProviderType.Value;
    177.                 var bundleProviderData =
    178.                     ObjectInitializationData.CreateSerializedInitializationData(bundleProviderType, bundleProviderId);
    179.                 m_ResourceProviderData.Add(bundleProviderData);
    180.             }
    181.         }
    182.  
    183.         internal static string GetMonoScriptBundleNamePrefix(AddressableAssetsBuildContext aaContext)
    184.         {
    185.             return GetMonoScriptBundleNamePrefix(aaContext.Settings);
    186.         }
    187.  
    188.         internal static string GetMonoScriptBundleNamePrefix(AddressableAssetSettings settings)
    189.         {
    190.             string value = null;
    191.             switch (settings.MonoScriptBundleNaming)
    192.             {
    193.                 case MonoScriptBundleNaming.ProjectName:
    194.                     value = Hash128.Compute(GetProjectName()).ToString();
    195.                     break;
    196.                 case MonoScriptBundleNaming.DefaultGroupGuid:
    197.                     value = settings.DefaultGroup.Guid;
    198.                     break;
    199.                 case MonoScriptBundleNaming.Custom:
    200.                     value = settings.MonoScriptBundleCustomNaming;
    201.                     break;
    202.             }
    203.  
    204.             return value;
    205.         }
    206.  
    207.         /// <summary>
    208.         /// The method that does the actual building after all the groups have been processed.
    209.         /// </summary>
    210.         /// <param name="builderInput">The generic builderInput of the</param>
    211.         /// <param name="aaContext"></param>
    212.         /// <typeparam name="TResult"></typeparam>
    213.         /// <returns></returns>
    214.         protected virtual TResult DoBuild<TResult>(AddressablesDataBuilderInput builderInput,
    215.             AddressableAssetsBuildContext aaContext) where TResult : IDataBuilderResult
    216.         {
    217.             ExtractDataTask extractData = new ExtractDataTask();
    218.             List<CachedAssetState> carryOverCachedState = new List<CachedAssetState>();
    219.             var tempPath = Path.GetDirectoryName(Application.dataPath) + "/" + Addressables.LibraryPath +
    220.                            PlatformMappingService.GetPlatformPathSubFolder() + "/addressables_content_state.bin";
    221.  
    222.             var playerBuildVersion = builderInput.PlayerVersion;
    223.             if (m_AllBundleInputDefs.Count > 0)
    224.             {
    225.                 var buildTarget = builderInput.Target;
    226.                 var buildTargetGroup = builderInput.TargetGroup;
    227.  
    228.                 var buildParams = new AddressableAssetsBundleBuildParameters(
    229.                     aaContext.Settings,
    230.                     aaContext.bundleToAssetGroup,
    231.                     buildTarget,
    232.                     buildTargetGroup,
    233.                     aaContext.Settings.buildSettings.bundleBuildPath);
    234.  
    235.                 var builtinShaderBundleName =
    236.                     GetBuiltInShaderBundleNamePrefix(aaContext) + "_unitybuiltinshaders.bundle";
    237.  
    238.                 var schema = aaContext.Settings.DefaultGroup.GetSchema<BundledAssetGroupSchema>();
    239.                 AddBundleProvider(schema);
    240.  
    241.                 string monoScriptBundleName = GetMonoScriptBundleNamePrefix(aaContext);
    242.                 if (!string.IsNullOrEmpty(monoScriptBundleName))
    243.                     monoScriptBundleName += "_monoscripts.bundle";
    244.                 var buildTasks = RuntimeDataBuildTasks(builtinShaderBundleName, monoScriptBundleName);
    245.                 buildTasks.Add(extractData);
    246.  
    247.                 IBundleBuildResults results;
    248.                 using (m_Log.ScopedStep(LogLevel.Info, "ContentPipeline.BuildAssetBundles"))
    249.                 using (new SBPSettingsOverwriterScope(ProjectConfigData
    250.                            .GenerateBuildLayout)) // build layout generation requires full SBP write results
    251.                 {
    252.                     var exitCode = CustomPipeLine.BuildAssetBundles(buildParams,
    253.                         new BundleBuildContent(m_AllBundleInputDefs), out results, buildTasks, aaContext, m_Log);
    254.  
    255.                     if (exitCode < ReturnCode.Success)
    256.                         return AddressableAssetBuildResult.CreateResult<TResult>(null, 0, "SBP Error" + exitCode);
    257.                 }
    258.  
    259.                 var groups = aaContext.Settings.groups.Where(g => g != null);
    260.  
    261.                 var bundleRenameMap = new Dictionary<string, string>();
    262.                 var postCatalogUpdateCallbacks = new List<Action>();
    263.                 using (m_Log.ScopedStep(LogLevel.Info, "PostProcessBundles"))
    264.                 using (var progressTracker = new UnityEditor.Build.Pipeline.Utilities.ProgressTracker())
    265.                 {
    266.                     progressTracker.UpdateTask("Post Processing AssetBundles");
    267.  
    268.                     Dictionary<string, ContentCatalogDataEntry> primaryKeyToCatalogEntry =
    269.                         new Dictionary<string, ContentCatalogDataEntry>();
    270.                     foreach (var loc in aaContext.locations)
    271.                         if (loc != null && loc.Keys[0] != null && loc.Keys[0] is string &&
    272.                             !primaryKeyToCatalogEntry.ContainsKey((string)loc.Keys[0]))
    273.                             primaryKeyToCatalogEntry[(string)loc.Keys[0]] = loc;
    274.  
    275.                     foreach (var assetGroup in groups)
    276.                     {
    277.                         if (aaContext.assetGroupToBundles.TryGetValue(assetGroup, out List<string> buildBundles))
    278.                         {
    279.                             List<string> outputBundles = new List<string>();
    280.                             for (int i = 0; i < buildBundles.Count; ++i)
    281.                             {
    282.                                 var b = m_AllBundleInputDefs.FindIndex(inputDef =>
    283.                                     buildBundles[i].StartsWith(inputDef.assetBundleName));
    284.                                 outputBundles.Add(b >= 0 ? m_OutputAssetBundleNames[b] : buildBundles[i]);
    285.                             }
    286.  
    287.                             PostProcessBundles(assetGroup, buildBundles, outputBundles, results, aaContext.runtimeData,
    288.                                 aaContext.locations, builderInput.Registry, primaryKeyToCatalogEntry, bundleRenameMap,
    289.                                 postCatalogUpdateCallbacks);
    290.                         }
    291.                     }
    292.                 }
    293.  
    294.                 ProcessCatalogEntriesForBuild(aaContext, m_Log, groups, builderInput, extractData.WriteData,
    295.                     carryOverCachedState, m_BundleToInternalId);
    296.                 foreach (var postUpdateCatalogCallback in postCatalogUpdateCallbacks)
    297.                     postUpdateCatalogCallback.Invoke();
    298.  
    299.                 foreach (var r in results.WriteResults)
    300.                 {
    301.                     var resultValue = r.Value;
    302.                     m_Linker.AddTypes(resultValue.includedTypes);
    303. #if UNITY_2021_1_OR_NEWER
    304.                     m_Linker.AddSerializedClass(resultValue.includedSerializeReferenceFQN);
    305. #else
    306.                     if (resultValue.GetType().GetProperty("includedSerializeReferenceFQN") != null)
    307.                         m_Linker.AddSerializedClass(
    308.                             resultValue.GetType().GetProperty("includedSerializeReferenceFQN").GetValue(resultValue) as
    309.                                 System.Collections.Generic.IEnumerable<string>);
    310. #endif
    311.                 }
    312.  
    313.  
    314.                 if (ProjectConfigData.GenerateBuildLayout)
    315.                 {
    316.                     using (var progressTracker = new UnityEditor.Build.Pipeline.Utilities.ProgressTracker())
    317.                     {
    318.                         progressTracker.UpdateTask("Generating Build Layout");
    319.                         List<IBuildTask> tasks = new List<IBuildTask>();
    320.                         var buildLayoutTask = new BuildLayoutGenerationTask();
    321.                         buildLayoutTask.m_BundleNameRemap = bundleRenameMap;
    322.                         tasks.Add(buildLayoutTask);
    323.                         BuildTasksRunner.Run(tasks, extractData.m_BuildContext);
    324.                     }
    325.                 }
    326.             }
    327.  
    328.             var contentCatalog = new ContentCatalogData(ResourceManagerRuntimeData.kCatalogAddress);
    329.             contentCatalog.SetData(aaContext.locations.OrderBy(f => f.InternalId).ToList(),
    330.                 aaContext.Settings.OptimizeCatalogSize);
    331.  
    332.             contentCatalog.ResourceProviderData.AddRange(m_ResourceProviderData);
    333.             foreach (var t in aaContext.providerTypes)
    334.                 contentCatalog.ResourceProviderData.Add(ObjectInitializationData.CreateSerializedInitializationData(t));
    335.  
    336.             contentCatalog.InstanceProviderData =
    337.                 ObjectInitializationData.CreateSerializedInitializationData(instanceProviderType.Value);
    338.             contentCatalog.SceneProviderData =
    339.                 ObjectInitializationData.CreateSerializedInitializationData(sceneProviderType.Value);
    340.  
    341.             //save catalog
    342.             var jsonText = JsonUtility.ToJson(contentCatalog);
    343.             CreateCatalogFiles(jsonText, builderInput, aaContext);
    344.  
    345.             foreach (var pd in contentCatalog.ResourceProviderData)
    346.             {
    347.                 m_Linker.AddTypes(pd.ObjectType.Value);
    348.                 m_Linker.AddTypes(pd.GetRuntimeTypes());
    349.             }
    350.  
    351.             m_Linker.AddTypes(contentCatalog.InstanceProviderData.ObjectType.Value);
    352.             m_Linker.AddTypes(contentCatalog.InstanceProviderData.GetRuntimeTypes());
    353.             m_Linker.AddTypes(contentCatalog.SceneProviderData.ObjectType.Value);
    354.             m_Linker.AddTypes(contentCatalog.SceneProviderData.GetRuntimeTypes());
    355.  
    356.             foreach (var io in aaContext.Settings.InitializationObjects)
    357.             {
    358.                 var provider = io as IObjectInitializationDataProvider;
    359.                 if (provider != null)
    360.                 {
    361.                     var id = provider.CreateObjectInitializationData();
    362.                     aaContext.runtimeData.InitializationObjects.Add(id);
    363.                     m_Linker.AddTypes(id.ObjectType.Value);
    364.                     m_Linker.AddTypes(id.GetRuntimeTypes());
    365.                 }
    366.             }
    367.  
    368.             m_Linker.AddTypes(typeof(Addressables));
    369.             Directory.CreateDirectory(Addressables.BuildPath + "/AddressablesLink/");
    370.             m_Linker.Save(Addressables.BuildPath + "/AddressablesLink/link.xml");
    371.             var settingsPath = Addressables.BuildPath + "/" + builderInput.RuntimeSettingsFilename;
    372.             WriteFile(settingsPath, JsonUtility.ToJson(aaContext.runtimeData), builderInput.Registry);
    373.  
    374.             var opResult = AddressableAssetBuildResult.CreateResult<TResult>(settingsPath, aaContext.locations.Count);
    375.             if (extractData.BuildCache != null && builderInput.PreviousContentState == null)
    376.             {
    377.                 var allEntries = new List<AddressableAssetEntry>();
    378.                 aaContext.Settings.GetAllAssets(allEntries, false, ContentUpdateScript.GroupFilter);
    379.                 var remoteCatalogLoadPath = aaContext.Settings.BuildRemoteCatalog
    380.                     ? aaContext.Settings.RemoteCatalogLoadPath.GetValue(aaContext.Settings)
    381.                     : string.Empty;
    382.                 if (ContentUpdateScript.SaveContentState(aaContext.locations, tempPath, allEntries,
    383.                         extractData.DependencyData, playerBuildVersion, remoteCatalogLoadPath, carryOverCachedState))
    384.                 {
    385.                     string contentStatePath = ContentUpdateScript.GetContentStateDataPath(false);
    386.                     try
    387.                     {
    388.                         File.Copy(tempPath, contentStatePath, true);
    389.                         builderInput.Registry.AddFile(contentStatePath);
    390.                     }
    391.                     catch (UnauthorizedAccessException uae)
    392.                     {
    393.                         if (!AddressableAssetUtility.IsVCAssetOpenForEdit(contentStatePath))
    394.                             Debug.LogErrorFormat("Cannot access the file {0}. It may be locked by version control.",
    395.                                 contentStatePath);
    396.                         else
    397.                             Debug.LogException(uae);
    398.                     }
    399.                     catch (Exception e)
    400.                     {
    401.                         Debug.LogException(e);
    402.                     }
    403.                 }
    404.             }
    405.  
    406.             return opResult;
    407.         }
    408.  
    409.         private static void ProcessCatalogEntriesForBuild(AddressableAssetsBuildContext aaContext, IBuildLogger log,
    410.             IEnumerable<AddressableAssetGroup> validGroups, AddressablesDataBuilderInput builderInput,
    411.             IBundleWriteData writeData,
    412.             List<CachedAssetState> carryOverCachedState, Dictionary<string, string> bundleToInternalId)
    413.         {
    414.             using (log.ScopedStep(LogLevel.Info, "Catalog Entries."))
    415.             using (var progressTracker = new UnityEditor.Build.Pipeline.Utilities.ProgressTracker())
    416.             {
    417.                 progressTracker.UpdateTask("Post Processing Catalog Entries");
    418.                 Dictionary<string, ContentCatalogDataEntry> locationIdToCatalogEntryMap =
    419.                     BuildLocationIdToCatalogEntryMap(aaContext.locations);
    420.                 if (builderInput.PreviousContentState != null)
    421.                 {
    422.                     ContentUpdateContext contentUpdateContext = new ContentUpdateContext()
    423.                     {
    424.                         BundleToInternalBundleIdMap = bundleToInternalId,
    425.                         GuidToPreviousAssetStateMap =
    426.                             BuildGuidToCachedAssetStateMap(builderInput.PreviousContentState, aaContext.Settings),
    427.                         IdToCatalogDataEntryMap = locationIdToCatalogEntryMap,
    428.                         WriteData = writeData,
    429.                         ContentState = builderInput.PreviousContentState,
    430.                         Registry = builderInput.Registry,
    431.                         PreviousAssetStateCarryOver = carryOverCachedState
    432.                     };
    433.  
    434.                     RevertUnchangedAssetsToPreviousAssetState.Run(aaContext, contentUpdateContext);
    435.                 }
    436.                 else
    437.                 {
    438.                     foreach (var assetGroup in validGroups)
    439.                         SetAssetEntriesBundleFileIdToCatalogEntryBundleFileId(assetGroup.entries, bundleToInternalId,
    440.                             writeData, locationIdToCatalogEntryMap);
    441.                 }
    442.             }
    443.  
    444.             bundleToInternalId.Clear();
    445.         }
    446.  
    447.         private static Dictionary<string, ContentCatalogDataEntry> BuildLocationIdToCatalogEntryMap(
    448.             List<ContentCatalogDataEntry> locations)
    449.         {
    450.             Dictionary<string, ContentCatalogDataEntry> locationIdToCatalogEntryMap =
    451.                 new Dictionary<string, ContentCatalogDataEntry>();
    452.             foreach (var location in locations)
    453.                 locationIdToCatalogEntryMap[location.InternalId] = location;
    454.  
    455.             return locationIdToCatalogEntryMap;
    456.         }
    457.  
    458.         private static Dictionary<string, CachedAssetState> BuildGuidToCachedAssetStateMap(
    459.             AddressablesContentState contentState, AddressableAssetSettings settings)
    460.         {
    461.             Dictionary<string, CachedAssetState> addressableEntryToCachedStateMap =
    462.                 new Dictionary<string, CachedAssetState>();
    463.             foreach (var cachedInfo in contentState.cachedInfos)
    464.                 addressableEntryToCachedStateMap[cachedInfo.asset.guid.ToString()] = cachedInfo;
    465.  
    466.             return addressableEntryToCachedStateMap;
    467.         }
    468.  
    469.         internal bool CreateCatalogFiles(string jsonText, AddressablesDataBuilderInput builderInput,
    470.             AddressableAssetsBuildContext aaContext)
    471.         {
    472.             if (string.IsNullOrEmpty(jsonText) || builderInput == null || aaContext == null)
    473.             {
    474.                 Addressables.LogError("Unable to create content catalog (Null arguments).");
    475.                 return false;
    476.             }
    477.  
    478.             // Path needs to be resolved at runtime.
    479.             string localLoadPath = "{UnityEngine.AddressableAssets.Addressables.RuntimePath}/" +
    480.                                    builderInput.RuntimeCatalogFilename;
    481.             m_CatalogBuildPath = Path.Combine(Addressables.BuildPath, builderInput.RuntimeCatalogFilename);
    482.  
    483.             if (aaContext.Settings.BundleLocalCatalog)
    484.             {
    485.                 localLoadPath = localLoadPath.Replace(".json", ".bundle");
    486.                 m_CatalogBuildPath = m_CatalogBuildPath.Replace(".json", ".bundle");
    487.                 var returnCode = CreateCatalogBundle(m_CatalogBuildPath, jsonText, builderInput);
    488.                 if (returnCode != ReturnCode.Success || !File.Exists(m_CatalogBuildPath))
    489.                 {
    490.                     Addressables.LogError(
    491.                         $"An error occured during the creation of the content catalog bundle (return code {returnCode}).");
    492.                     return false;
    493.                 }
    494.             }
    495.             else
    496.             {
    497.                 WriteFile(m_CatalogBuildPath, jsonText, builderInput.Registry);
    498.             }
    499.  
    500.             string[] dependencyHashes = null;
    501.             if (aaContext.Settings.BuildRemoteCatalog)
    502.             {
    503.                 dependencyHashes = CreateRemoteCatalog(jsonText, aaContext.runtimeData.CatalogLocations,
    504.                     aaContext.Settings, builderInput, new ProviderLoadRequestOptions() { IgnoreFailures = true });
    505.             }
    506.  
    507.             aaContext.runtimeData.CatalogLocations.Add(new ResourceLocationData(
    508.                 new[] { ResourceManagerRuntimeData.kCatalogAddress },
    509.                 localLoadPath,
    510.                 typeof(ContentCatalogProvider),
    511.                 typeof(ContentCatalogData),
    512.                 dependencyHashes));
    513.  
    514.             return true;
    515.         }
    516.  
    517.         internal static string GetProjectName()
    518.         {
    519.             return new DirectoryInfo(Path.GetDirectoryName(Application.dataPath)).Name;
    520.         }
    521.  
    522.         internal ReturnCode CreateCatalogBundle(string filepath, string jsonText,
    523.             AddressablesDataBuilderInput builderInput)
    524.         {
    525.             if (string.IsNullOrEmpty(filepath) || string.IsNullOrEmpty(jsonText) || builderInput == null)
    526.             {
    527.                 throw new ArgumentException("Unable to create catalog bundle (null arguments).");
    528.             }
    529.  
    530.             // A bundle requires an actual asset
    531.             var tempFolderName = "TempCatalogFolder";
    532.  
    533.             var configFolder = AddressableAssetSettingsDefaultObject.kDefaultConfigFolder;
    534.             if (builderInput.AddressableSettings != null && builderInput.AddressableSettings.IsPersisted)
    535.                 configFolder = builderInput.AddressableSettings.ConfigFolder;
    536.  
    537.             var tempFolderPath = Path.Combine(configFolder, tempFolderName);
    538.             var tempFilePath = Path.Combine(tempFolderPath, Path.GetFileName(filepath).Replace(".bundle", ".json"));
    539.             if (!WriteFile(tempFilePath, jsonText, builderInput.Registry))
    540.             {
    541.                 throw new Exception(
    542.                     "An error occured during the creation of temporary files needed to bundle the content catalog.");
    543.             }
    544.  
    545.             AssetDatabase.Refresh();
    546.  
    547.             var bundleBuildContent = new BundleBuildContent(new[]
    548.             {
    549.                 new AssetBundleBuild()
    550.                 {
    551.                     assetBundleName = Path.GetFileName(filepath),
    552.                     assetNames = new[] { tempFilePath },
    553.                     addressableNames = new string[0]
    554.                 }
    555.             });
    556.  
    557.             var buildTasks = new List<IBuildTask>
    558.             {
    559.                 new CalculateAssetDependencyData(),
    560.                 new GenerateBundlePacking(),
    561.                 new GenerateBundleCommands(),
    562.                 new WriteSerializedFiles(),
    563.                 new ArchiveAndCompressBundles()
    564.             };
    565.  
    566.             var buildParams = new BundleBuildParameters(builderInput.Target, builderInput.TargetGroup,
    567.                 Path.GetDirectoryName(filepath));
    568.             if (builderInput.Target == BuildTarget.WebGL)
    569.                 buildParams.BundleCompression = BuildCompression.LZ4Runtime;
    570.             var retCode = ContentPipeline.BuildAssetBundles(buildParams, bundleBuildContent,
    571.                 out IBundleBuildResults result, buildTasks, m_Log);
    572.  
    573.             if (Directory.Exists(tempFolderPath))
    574.             {
    575.                 Directory.Delete(tempFolderPath, true);
    576.                 builderInput.Registry.RemoveFile(tempFilePath);
    577.             }
    578.  
    579.             var tempFolderMetaFile = tempFolderPath + ".meta";
    580.             if (File.Exists(tempFolderMetaFile))
    581.             {
    582.                 File.Delete(tempFolderMetaFile);
    583.                 builderInput.Registry.RemoveFile(tempFolderMetaFile);
    584.             }
    585.  
    586.             if (File.Exists(filepath))
    587.             {
    588.                 builderInput.Registry.AddFile(filepath);
    589.             }
    590.  
    591.             return retCode;
    592.         }
    593.  
    594.         internal static void SetAssetEntriesBundleFileIdToCatalogEntryBundleFileId(
    595.             ICollection<AddressableAssetEntry> assetEntries, Dictionary<string, string> bundleNameToInternalBundleIdMap,
    596.             IBundleWriteData writeData, Dictionary<string, ContentCatalogDataEntry> locationIdToCatalogEntryMap)
    597.         {
    598.             foreach (var loc in assetEntries)
    599.             {
    600.                 AddressableAssetEntry processedEntry = loc;
    601.                 if (loc.IsFolder && loc.SubAssets.Count > 0)
    602.                     processedEntry = loc.SubAssets[0];
    603.                 GUID guid = new GUID(processedEntry.guid);
    604.                 //For every entry in the write data we need to ensure the BundleFileId is set so we can save it correctly in the cached state
    605.                 if (writeData.AssetToFiles.TryGetValue(guid, out List<string> files))
    606.                 {
    607.                     string file = files[0];
    608.                     string fullBundleName = writeData.FileToBundle[file];
    609.                     string convertedLocation = bundleNameToInternalBundleIdMap[fullBundleName];
    610.  
    611.                     if (locationIdToCatalogEntryMap.TryGetValue(convertedLocation,
    612.                             out ContentCatalogDataEntry catalogEntry))
    613.                     {
    614.                         loc.BundleFileId = catalogEntry.InternalId;
    615.  
    616.                         //This is where we strip out the temporary hash added to the bundle name for Content Update for the AssetEntry
    617.                         if (loc.parentGroup?.GetSchema<BundledAssetGroupSchema>()?.BundleNaming ==
    618.                             BundledAssetGroupSchema.BundleNamingStyle.NoHash)
    619.                         {
    620.                             loc.BundleFileId = StripHashFromBundleLocation(loc.BundleFileId);
    621.                         }
    622.                     }
    623.                 }
    624.             }
    625.         }
    626.  
    627.         static string StripHashFromBundleLocation(string hashedBundleLocation)
    628.         {
    629.             return hashedBundleLocation.Remove(hashedBundleLocation.LastIndexOf("_")) + ".bundle";
    630.         }
    631.  
    632.         /// <inheritdoc />
    633.         protected override string ProcessGroup(AddressableAssetGroup assetGroup,
    634.             AddressableAssetsBuildContext aaContext)
    635.         {
    636.             if (assetGroup == null)
    637.                 return string.Empty;
    638.  
    639.             if (assetGroup.Schemas.Count == 0)
    640.             {
    641.                 Addressables.LogWarning(
    642.                     $"{assetGroup.Name} does not have any associated AddressableAssetGroupSchemas. " +
    643.                     $"Data from this group will not be included in the build. " +
    644.                     $"If this is unexpected the AddressableGroup may have become corrupted.");
    645.                 return string.Empty;
    646.             }
    647.  
    648.             foreach (var schema in assetGroup.Schemas)
    649.             {
    650.                 var errorString = ProcessGroupSchema(schema, assetGroup, aaContext);
    651.                 if (!string.IsNullOrEmpty(errorString))
    652.                     return errorString;
    653.             }
    654.  
    655.             return string.Empty;
    656.         }
    657.  
    658.         /// <summary>
    659.         /// Called per group per schema to evaluate that schema.  This can be an easy entry point for implementing the
    660.         ///  build aspects surrounding a custom schema.  Note, you should not rely on schemas getting called in a specific
    661.         ///  order.
    662.         /// </summary>
    663.         /// <param name="schema">The schema to process</param>
    664.         /// <param name="assetGroup">The group this schema was pulled from</param>
    665.         /// <param name="aaContext">The general Addressables build builderInput</param>
    666.         /// <returns></returns>
    667.         protected virtual string ProcessGroupSchema(AddressableAssetGroupSchema schema,
    668.             AddressableAssetGroup assetGroup, AddressableAssetsBuildContext aaContext)
    669.         {
    670.             var playerDataSchema = schema as PlayerDataGroupSchema;
    671.             if (playerDataSchema != null)
    672.                 return ProcessPlayerDataSchema(playerDataSchema, assetGroup, aaContext);
    673.             var bundledAssetSchema = schema as BundledAssetGroupSchema;
    674.             if (bundledAssetSchema != null)
    675.                 return ProcessBundledAssetSchema(bundledAssetSchema, assetGroup, aaContext);
    676.             return string.Empty;
    677.         }
    678.  
    679.         internal string ProcessPlayerDataSchema(
    680.             PlayerDataGroupSchema schema,
    681.             AddressableAssetGroup assetGroup,
    682.             AddressableAssetsBuildContext aaContext)
    683.         {
    684.             if (CreateLocationsForPlayerData(schema, assetGroup, aaContext.locations, aaContext.providerTypes))
    685.             {
    686.                 if (!m_CreatedProviderIds.Contains(typeof(LegacyResourcesProvider).Name))
    687.                 {
    688.                     m_CreatedProviderIds.Add(typeof(LegacyResourcesProvider).Name);
    689.                     m_ResourceProviderData.Add(
    690.                         ObjectInitializationData.CreateSerializedInitializationData(typeof(LegacyResourcesProvider)));
    691.                 }
    692.             }
    693.  
    694.             return string.Empty;
    695.         }
    696.  
    697.         /// <summary>
    698.         /// The processing of the bundled asset schema.  This is where the bundle(s) for a given group are actually setup.
    699.         /// </summary>
    700.         /// <param name="schema">The BundledAssetGroupSchema to process</param>
    701.         /// <param name="assetGroup">The group this schema was pulled from</param>
    702.         /// <param name="aaContext">The general Addressables build builderInput</param>
    703.         /// <returns>The error string, if any.</returns>
    704.         protected virtual string ProcessBundledAssetSchema(
    705.             BundledAssetGroupSchema schema,
    706.             AddressableAssetGroup assetGroup,
    707.             AddressableAssetsBuildContext aaContext)
    708.         {
    709.             if (schema == null || !schema.IncludeInBuild || !assetGroup.entries.Any())
    710.                 return string.Empty;
    711.  
    712.             var errorStr = ErrorCheckBundleSettings(schema, assetGroup, aaContext.Settings);
    713.             if (!string.IsNullOrEmpty(errorStr))
    714.                 return errorStr;
    715.  
    716.             AddBundleProvider(schema);
    717.  
    718.             var assetProviderId = schema.GetAssetCachedProviderId();
    719.             if (!m_CreatedProviderIds.Contains(assetProviderId))
    720.             {
    721.                 m_CreatedProviderIds.Add(assetProviderId);
    722.                 var assetProviderType = schema.BundledAssetProviderType.Value;
    723.                 var assetProviderData =
    724.                     ObjectInitializationData.CreateSerializedInitializationData(assetProviderType, assetProviderId);
    725.                 m_ResourceProviderData.Add(assetProviderData);
    726.             }
    727.  
    728. #if UNITY_2022_1_OR_NEWER
    729.            string loadPath = schema.LoadPath.GetValue(aaContext.Settings);
    730.            if (loadPath.StartsWith("http://") && PlayerSettings.insecureHttpOption == InsecureHttpOption.NotAllowed)
    731.                 Addressables.LogWarning($"Addressable group {assetGroup.Name} uses insecure http for its load path.  To allow http connections for UnityWebRequests, change your settings in Edit > Project Settings > Player > Other Settings > Configuration > Allow downloads over HTTP.");
    732. #endif
    733.             if (schema.Compression == BundledAssetGroupSchema.BundleCompressionMode.LZMA &&
    734.                 aaContext.runtimeData.BuildTarget == BuildTarget.WebGL.ToString())
    735.                 Addressables.LogWarning(
    736.                     $"Addressable group {assetGroup.Name} uses LZMA compression, which cannot be decompressed on WebGL. Use LZ4 compression instead.");
    737.  
    738.             var bundleInputDefs = new List<AssetBundleBuild>();
    739.             var list = PrepGroupBundlePacking(assetGroup, bundleInputDefs, schema);
    740.             aaContext.assetEntries.AddRange(list);
    741.             List<string> uniqueNames =
    742.                 HandleDuplicateBundleNames(bundleInputDefs, aaContext.bundleToAssetGroup, assetGroup.Guid);
    743.             m_OutputAssetBundleNames.AddRange(uniqueNames);
    744.             m_AllBundleInputDefs.AddRange(bundleInputDefs);
    745.             return string.Empty;
    746.         }
    747.  
    748.         internal static List<string> HandleDuplicateBundleNames(List<AssetBundleBuild> bundleInputDefs,
    749.             Dictionary<string, string> bundleToAssetGroup = null, string assetGroupGuid = null)
    750.         {
    751.             var generatedUniqueNames = new List<string>();
    752.             var handledNames = new HashSet<string>();
    753.  
    754.             for (int i = 0; i < bundleInputDefs.Count; i++)
    755.             {
    756.                 AssetBundleBuild bundleBuild = bundleInputDefs[i];
    757.                 string assetBundleName = bundleBuild.assetBundleName;
    758.                 if (handledNames.Contains(assetBundleName))
    759.                 {
    760.                     int count = 1;
    761.                     var newName = assetBundleName;
    762.                     while (handledNames.Contains(newName) && count < 1000)
    763.                         newName = assetBundleName.Replace(".bundle", string.Format("{0}.bundle", count++));
    764.                     assetBundleName = newName;
    765.                 }
    766.  
    767.                 string hashedAssetBundleName = HashingMethods.Calculate(assetBundleName) + ".bundle";
    768.                 generatedUniqueNames.Add(assetBundleName);
    769.                 handledNames.Add(assetBundleName);
    770.  
    771.                 bundleBuild.assetBundleName = hashedAssetBundleName;
    772.                 bundleInputDefs[i] = bundleBuild;
    773.  
    774.                 if (bundleToAssetGroup != null)
    775.                     bundleToAssetGroup.Add(hashedAssetBundleName, assetGroupGuid);
    776.             }
    777.  
    778.             return generatedUniqueNames;
    779.         }
    780.  
    781.         internal static string ErrorCheckBundleSettings(BundledAssetGroupSchema schema,
    782.             AddressableAssetGroup assetGroup, AddressableAssetSettings settings)
    783.         {
    784.             var message = string.Empty;
    785.  
    786.             string buildPath = settings.profileSettings.GetValueById(settings.activeProfileId, schema.BuildPath.Id);
    787.             string loadPath = settings.profileSettings.GetValueById(settings.activeProfileId, schema.LoadPath.Id);
    788.  
    789.             bool buildLocal = buildPath.Contains("[UnityEngine.AddressableAssets.Addressables.BuildPath]");
    790.             bool loadLocal = loadPath.Contains("{UnityEngine.AddressableAssets.Addressables.RuntimePath}");
    791.  
    792.             if (buildLocal && !loadLocal)
    793.             {
    794.                 message = "BuildPath for group '" + assetGroup.Name +
    795.                           "' is set to the dynamic-lookup version of StreamingAssets, but LoadPath is not. \n";
    796.             }
    797.             else if (!buildLocal && loadLocal)
    798.             {
    799.                 message = "LoadPath for group " + assetGroup.Name +
    800.                           " is set to the dynamic-lookup version of StreamingAssets, but BuildPath is not. These paths must both use the dynamic-lookup, or both not use it. \n";
    801.             }
    802.  
    803.             if (!string.IsNullOrEmpty(message))
    804.             {
    805.                 message += "BuildPath: '" + buildPath + "'\n";
    806.                 message += "LoadPath: '" + loadPath + "'";
    807.             }
    808.  
    809.             if (schema.Compression == BundledAssetGroupSchema.BundleCompressionMode.LZMA && (buildLocal || loadLocal))
    810.             {
    811.                 Debug.LogWarningFormat("Bundle compression is set to LZMA, but group {0} uses local content.",
    812.                     assetGroup.Name);
    813.             }
    814.  
    815.             return message;
    816.         }
    817.  
    818.         internal static string CalculateGroupHash(BundledAssetGroupSchema.BundleInternalIdMode mode,
    819.             AddressableAssetGroup assetGroup, IEnumerable<AddressableAssetEntry> entries)
    820.         {
    821.             switch (mode)
    822.             {
    823.                 case BundledAssetGroupSchema.BundleInternalIdMode.GroupGuid: return assetGroup.Guid;
    824.                 case BundledAssetGroupSchema.BundleInternalIdMode.GroupGuidProjectIdHash:
    825.                     return HashingMethods.Calculate(assetGroup.Guid, Application.cloudProjectId).ToString();
    826.                 case BundledAssetGroupSchema.BundleInternalIdMode.GroupGuidProjectIdEntriesHash:
    827.                     return HashingMethods.Calculate(assetGroup.Guid, Application.cloudProjectId,
    828.                         new HashSet<string>(entries.Select(e => e.guid))).ToString();
    829.             }
    830.  
    831.             throw new Exception("Invalid naming mode.");
    832.         }
    833.  
    834.         /// <summary>
    835.         /// Processes an AddressableAssetGroup and generates AssetBundle input definitions based on the BundlePackingMode.
    836.         /// </summary>
    837.         /// <param name="assetGroup">The AddressableAssetGroup to be processed.</param>
    838.         /// <param name="bundleInputDefs">The list of bundle definitions fed into the build pipeline AssetBundleBuild</param>
    839.         /// <param name="schema">The BundledAssetGroupSchema of used to process the assetGroup.</param>
    840.         /// <param name="entryFilter">A filter to remove AddressableAssetEntries from being processed in the build.</param>
    841.         /// <returns>The total list of AddressableAssetEntries that were processed.</returns>
    842.         public static List<AddressableAssetEntry> PrepGroupBundlePacking(AddressableAssetGroup assetGroup,
    843.             List<AssetBundleBuild> bundleInputDefs, BundledAssetGroupSchema schema,
    844.             Func<AddressableAssetEntry, bool> entryFilter = null)
    845.         {
    846.             var combinedEntries = new List<AddressableAssetEntry>();
    847.             var packingMode = schema.BundleMode;
    848.             var namingMode = schema.InternalBundleIdMode;
    849.             bool ignoreUnsupportedFilesInBuild = assetGroup.Settings.IgnoreUnsupportedFilesInBuild;
    850.  
    851.             switch (packingMode)
    852.             {
    853.                 case BundledAssetGroupSchema.BundlePackingMode.PackTogether:
    854.                 {
    855.                     var allEntries = new List<AddressableAssetEntry>();
    856.                     foreach (AddressableAssetEntry a in assetGroup.entries)
    857.                     {
    858.                         if (entryFilter != null && !entryFilter(a))
    859.                             continue;
    860.                         a.GatherAllAssets(allEntries, true, true, false, entryFilter);
    861.                     }
    862.  
    863.                     combinedEntries.AddRange(allEntries);
    864.                     GenerateBuildInputDefinitions(allEntries, bundleInputDefs,
    865.                         CalculateGroupHash(namingMode, assetGroup, allEntries), "all", ignoreUnsupportedFilesInBuild);
    866.                 }
    867.                     break;
    868.                 case BundledAssetGroupSchema.BundlePackingMode.PackSeparately:
    869.                 {
    870.                     foreach (AddressableAssetEntry a in assetGroup.entries)
    871.                     {
    872.                         if (entryFilter != null && !entryFilter(a))
    873.                             continue;
    874.                         var allEntries = new List<AddressableAssetEntry>();
    875.                         a.GatherAllAssets(allEntries, true, true, false, entryFilter);
    876.                         combinedEntries.AddRange(allEntries);
    877.                         GenerateBuildInputDefinitions(allEntries, bundleInputDefs,
    878.                             CalculateGroupHash(namingMode, assetGroup, allEntries), a.address,
    879.                             ignoreUnsupportedFilesInBuild);
    880.                     }
    881.                 }
    882.                     break;
    883.                 case BundledAssetGroupSchema.BundlePackingMode.PackTogetherByLabel:
    884.                 {
    885.                     var labelTable = new Dictionary<string, List<AddressableAssetEntry>>();
    886.                     foreach (AddressableAssetEntry a in assetGroup.entries)
    887.                     {
    888.                         if (entryFilter != null && !entryFilter(a))
    889.                             continue;
    890.                         var sb = new StringBuilder();
    891.                         foreach (var l in a.labels)
    892.                             sb.Append(l);
    893.                         var key = sb.ToString();
    894.                         List<AddressableAssetEntry> entries;
    895.                         if (!labelTable.TryGetValue(key, out entries))
    896.                             labelTable.Add(key, entries = new List<AddressableAssetEntry>());
    897.                         entries.Add(a);
    898.                     }
    899.  
    900.                     foreach (var entryGroup in labelTable)
    901.                     {
    902.                         var allEntries = new List<AddressableAssetEntry>();
    903.                         foreach (var a in entryGroup.Value)
    904.                         {
    905.                             if (entryFilter != null && !entryFilter(a))
    906.                                 continue;
    907.                             a.GatherAllAssets(allEntries, true, true, false, entryFilter);
    908.                         }
    909.  
    910.                         combinedEntries.AddRange(allEntries);
    911.                         GenerateBuildInputDefinitions(allEntries, bundleInputDefs,
    912.                             CalculateGroupHash(namingMode, assetGroup, allEntries), entryGroup.Key,
    913.                             ignoreUnsupportedFilesInBuild);
    914.                     }
    915.                 }
    916.                     break;
    917.                 default:
    918.                     throw new Exception("Unknown Packing Mode");
    919.             }
    920.  
    921.             return combinedEntries;
    922.         }
    923.  
    924.         internal static void GenerateBuildInputDefinitions(List<AddressableAssetEntry> allEntries,
    925.             List<AssetBundleBuild> buildInputDefs, string groupGuid, string address, bool ignoreUnsupportedFilesInBuild)
    926.         {
    927.             var scenes = new List<AddressableAssetEntry>();
    928.             var assets = new List<AddressableAssetEntry>();
    929.             foreach (var e in allEntries)
    930.             {
    931.                 ThrowExceptionIfInvalidFiletypeOrAddress(e, ignoreUnsupportedFilesInBuild);
    932.                 if (string.IsNullOrEmpty(e.AssetPath))
    933.                     continue;
    934.                 if (e.IsScene)
    935.                     scenes.Add(e);
    936.                 else
    937.                     assets.Add(e);
    938.             }
    939.  
    940.             if (assets.Count > 0)
    941.                 buildInputDefs.Add(GenerateBuildInputDefinition(assets, groupGuid + "_assets_" + address + ".bundle"));
    942.             if (scenes.Count > 0)
    943.                 buildInputDefs.Add(GenerateBuildInputDefinition(scenes, groupGuid + "_scenes_" + address + ".bundle"));
    944.         }
    945.  
    946.         private static void ThrowExceptionIfInvalidFiletypeOrAddress(AddressableAssetEntry entry,
    947.             bool ignoreUnsupportedFilesInBuild)
    948.         {
    949.             if (entry.guid.Length > 0 && entry.address.Contains("[") && entry.address.Contains("]"))
    950.                 throw new Exception($"Address '{entry.address}' cannot contain '[ ]'.");
    951.             if (entry.MainAssetType == typeof(DefaultAsset) && !AssetDatabase.IsValidFolder(entry.AssetPath))
    952.             {
    953.                 if (ignoreUnsupportedFilesInBuild)
    954.                     Debug.LogWarning(
    955.                         $"Cannot recognize file type for entry located at '{entry.AssetPath}'. Asset location will be ignored.");
    956.                 else
    957.                     throw new Exception(
    958.                         $"Cannot recognize file type for entry located at '{entry.AssetPath}'. Asset import failed for using an unsupported file type.");
    959.             }
    960.         }
    961.  
    962.         internal static AssetBundleBuild GenerateBuildInputDefinition(List<AddressableAssetEntry> assets, string name)
    963.         {
    964.             var assetInternalIds = new HashSet<string>();
    965.             var assetsInputDef = new AssetBundleBuild();
    966.             assetsInputDef.assetBundleName = name.ToLower().Replace(" ", "").Replace('\\', '/').Replace("//", "/");
    967.             assetsInputDef.assetNames = assets.Select(s => s.AssetPath).ToArray();
    968.             assetsInputDef.addressableNames = assets.Select(s => s.GetAssetLoadPath(true, assetInternalIds)).ToArray();
    969.             return assetsInputDef;
    970.         }
    971.  
    972.         static string[] CreateRemoteCatalog(string jsonText, List<ResourceLocationData> locations,
    973.             AddressableAssetSettings aaSettings, AddressablesDataBuilderInput builderInput,
    974.             ProviderLoadRequestOptions catalogLoadOptions)
    975.         {
    976.             string[] dependencyHashes = null;
    977.  
    978.             var contentHash = HashingMethods.Calculate(jsonText).ToString();
    979.  
    980.             var versionedFileName = aaSettings.profileSettings.EvaluateString(aaSettings.activeProfileId,
    981.                 "/catalog_" + builderInput.PlayerVersion);
    982.             var remoteBuildFolder = aaSettings.RemoteCatalogBuildPath.GetValue(aaSettings);
    983.             var remoteLoadFolder = aaSettings.RemoteCatalogLoadPath.GetValue(aaSettings);
    984.  
    985.             if (string.IsNullOrEmpty(remoteBuildFolder) ||
    986.                 string.IsNullOrEmpty(remoteLoadFolder) ||
    987.                 remoteBuildFolder == AddressableAssetProfileSettings.undefinedEntryValue ||
    988.                 remoteLoadFolder == AddressableAssetProfileSettings.undefinedEntryValue)
    989.             {
    990.                 Addressables.LogWarning(
    991.                     "Remote Build and/or Load paths are not set on the main AddressableAssetSettings asset, but 'Build Remote Catalog' is true.  Cannot create remote catalog.  In the inspector for any group, double click the 'Addressable Asset Settings' object to begin inspecting it. '" +
    992.                     remoteBuildFolder + "', '" + remoteLoadFolder + "'");
    993.             }
    994.             else
    995.             {
    996.                 var remoteJsonBuildPath = remoteBuildFolder + versionedFileName + ".json";
    997.                 var remoteHashBuildPath = remoteBuildFolder + versionedFileName + ".hash";
    998.  
    999.                 WriteFile(remoteJsonBuildPath, jsonText, builderInput.Registry);
    1000.                 WriteFile(remoteHashBuildPath, contentHash, builderInput.Registry);
    1001.  
    1002.                 dependencyHashes = new string[((int)ContentCatalogProvider.DependencyHashIndex.Count)];
    1003.                 dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] =
    1004.                     ResourceManagerRuntimeData.kCatalogAddress + "RemoteHash";
    1005.                 dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] =
    1006.                     ResourceManagerRuntimeData.kCatalogAddress + "CacheHash";
    1007.  
    1008.                 var remoteHashLoadPath = remoteLoadFolder + versionedFileName + ".hash";
    1009.                 var remoteHashLoadLocation = new ResourceLocationData(
    1010.                     new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Remote] },
    1011.                     remoteHashLoadPath,
    1012.                     typeof(TextDataProvider), typeof(string));
    1013.                 remoteHashLoadLocation.Data = catalogLoadOptions.Copy();
    1014.                 locations.Add(remoteHashLoadLocation);
    1015.  
    1016.                 var cacheLoadPath = "{UnityEngine.Application.persistentDataPath}/com.unity.addressables" +
    1017.                                     versionedFileName + ".hash";
    1018.                 var cacheLoadLocation = new ResourceLocationData(
    1019.                     new[] { dependencyHashes[(int)ContentCatalogProvider.DependencyHashIndex.Cache] },
    1020.                     cacheLoadPath,
    1021.                     typeof(TextDataProvider), typeof(string));
    1022.                 cacheLoadLocation.Data = catalogLoadOptions.Copy();
    1023.                 locations.Add(cacheLoadLocation);
    1024.             }
    1025.  
    1026.             return dependencyHashes;
    1027.         }
    1028.  
    1029.         // Tests can set this flag to prevent player script compilation. This is the most expensive part of small builds
    1030.         // and isn't needed for most tests.
    1031.         internal static bool s_SkipCompilePlayerScripts = false;
    1032.  
    1033.         static IList<IBuildTask> RuntimeDataBuildTasks(string builtinShaderBundleName, string monoScriptBundleName)
    1034.         {
    1035.             var buildTasks = new List<IBuildTask>();
    1036.  
    1037.             // Setup
    1038.             buildTasks.Add(new SwitchToBuildPlatform());
    1039.             buildTasks.Add(new RebuildSpriteAtlasCache());
    1040.  
    1041.             // Player Scripts
    1042.             if (!s_SkipCompilePlayerScripts)
    1043.                 buildTasks.Add(new BuildPlayerScripts());
    1044.             buildTasks.Add(new PostScriptsCallback());
    1045.  
    1046.             // Dependency
    1047.             buildTasks.Add(new CalculateSceneDependencyData());
    1048.             buildTasks.Add(new CalculateAssetDependencyData());
    1049.             buildTasks.Add(new AddHashToBundleNameTask());
    1050.             buildTasks.Add(new StripUnusedSpriteSources());
    1051.             buildTasks.Add(new CreateBuiltInShadersBundle(builtinShaderBundleName));
    1052.             if (!string.IsNullOrEmpty(monoScriptBundleName))
    1053.                 buildTasks.Add(new CreateMonoScriptBundle(monoScriptBundleName));
    1054.             buildTasks.Add(new PostDependencyCallback());
    1055.  
    1056.             // Packing
    1057.             buildTasks.Add(new GenerateBundlePacking());
    1058.             buildTasks.Add(new UpdateBundleObjectLayout());
    1059.             buildTasks.Add(new GenerateBundleCommands());
    1060.             buildTasks.Add(new GenerateSubAssetPathMaps());
    1061.             buildTasks.Add(new GenerateBundleMaps());
    1062.             buildTasks.Add(new PostPackingCallback());
    1063.  
    1064.             // Writing
    1065.             buildTasks.Add(new WriteSerializedFiles());
    1066.             buildTasks.Add(new ArchiveAndCompressBundles());
    1067.             buildTasks.Add(new GenerateLocationListsTask());
    1068.             buildTasks.Add(new PostWritingCallback());
    1069.  
    1070.             return buildTasks;
    1071.         }
    1072.  
    1073.         static void MoveFileToDestinationWithTimestampIfDifferent(string srcPath, string destPath, IBuildLogger log)
    1074.         {
    1075.             if (srcPath == destPath)
    1076.                 return;
    1077.  
    1078.             DateTime time = File.GetLastWriteTime(srcPath);
    1079.             DateTime destTime = File.Exists(destPath) ? File.GetLastWriteTime(destPath) : new DateTime();
    1080.  
    1081.             if (destTime == time)
    1082.                 return;
    1083.  
    1084.             using (log.ScopedStep(LogLevel.Verbose, "Move File", $"{srcPath} -> {destPath}"))
    1085.             {
    1086.                 var directory = Path.GetDirectoryName(destPath);
    1087.                 if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
    1088.                     Directory.CreateDirectory(directory);
    1089.                 else if (File.Exists(destPath))
    1090.                     File.Delete(destPath);
    1091.                 File.Move(srcPath, destPath);
    1092.             }
    1093.         }
    1094.  
    1095.         void PostProcessBundles(AddressableAssetGroup assetGroup, List<string> buildBundles, List<string> outputBundles,
    1096.             IBundleBuildResults buildResult, ResourceManagerRuntimeData runtimeData,
    1097.             List<ContentCatalogDataEntry> locations, FileRegistry registry,
    1098.             Dictionary<string, ContentCatalogDataEntry> primaryKeyToCatalogEntry,
    1099.             Dictionary<string, string> bundleRenameMap, List<Action> postCatalogUpdateCallbacks)
    1100.         {
    1101.             var schema = assetGroup.GetSchema<BundledAssetGroupSchema>();
    1102.             if (schema == null)
    1103.                 return;
    1104.  
    1105.             var path = schema.BuildPath.GetValue(assetGroup.Settings);
    1106.             if (string.IsNullOrEmpty(path))
    1107.                 return;
    1108.  
    1109.             for (int i = 0; i < buildBundles.Count; ++i)
    1110.             {
    1111.                 if (primaryKeyToCatalogEntry.TryGetValue(buildBundles[i], out ContentCatalogDataEntry dataEntry))
    1112.                 {
    1113.                     var info = buildResult.BundleInfos[buildBundles[i]];
    1114.                     var requestOptions = new AssetBundleRequestOptions
    1115.                     {
    1116.                         Crc = schema.UseAssetBundleCrc ? info.Crc : 0,
    1117.                         UseCrcForCachedBundle = schema.UseAssetBundleCrcForCachedBundles,
    1118.                         UseUnityWebRequestForLocalBundles = schema.UseUnityWebRequestForLocalBundles,
    1119.                         Hash = schema.UseAssetBundleCache ? info.Hash.ToString() : "",
    1120.                         ChunkedTransfer = schema.ChunkedTransfer,
    1121.                         RedirectLimit = schema.RedirectLimit,
    1122.                         RetryCount = schema.RetryCount,
    1123.                         Timeout = schema.Timeout,
    1124.                         BundleName = Path.GetFileNameWithoutExtension(info.FileName),
    1125.                         AssetLoadMode = schema.AssetLoadMode,
    1126.                         BundleSize = GetFileSize(info.FileName),
    1127.                         ClearOtherCachedVersionsWhenLoaded = schema.AssetBundledCacheClearBehavior ==
    1128.                                                              BundledAssetGroupSchema.CacheClearBehavior
    1129.                                                                  .ClearWhenWhenNewVersionLoaded
    1130.                     };
    1131.                     dataEntry.Data = requestOptions;
    1132.  
    1133.                     if (assetGroup == assetGroup.Settings.DefaultGroup && info.Dependencies.Length == 0 &&
    1134.                         !string.IsNullOrEmpty(info.FileName) &&
    1135.                         (info.FileName.EndsWith("_unitybuiltinshaders.bundle") ||
    1136.                          info.FileName.EndsWith("_monoscripts.bundle")))
    1137.                     {
    1138.                         outputBundles[i] = ConstructAssetBundleName(null, schema, info, outputBundles[i]);
    1139.                     }
    1140.                     else
    1141.                     {
    1142.                         int extensionLength = Path.GetExtension(outputBundles[i]).Length;
    1143.                         string[] deconstructedBundleName = outputBundles[i]
    1144.                             .Substring(0, outputBundles[i].Length - extensionLength).Split('_');
    1145.                         string reconstructedBundleName =
    1146.                             string.Join("_", deconstructedBundleName, 1, deconstructedBundleName.Length - 1) +
    1147.                             ".bundle";
    1148.                         outputBundles[i] = ConstructAssetBundleName(assetGroup, schema, info, reconstructedBundleName);
    1149.                     }
    1150.  
    1151.                     dataEntry.InternalId =
    1152.                         dataEntry.InternalId.Remove(dataEntry.InternalId.Length - buildBundles[i].Length) +
    1153.                         outputBundles[i];
    1154.                     dataEntry.Keys[0] = outputBundles[i];
    1155.                     ReplaceDependencyKeys(buildBundles[i], outputBundles[i], locations);
    1156.  
    1157.                     if (!m_BundleToInternalId.ContainsKey(buildBundles[i]))
    1158.                         m_BundleToInternalId.Add(buildBundles[i], dataEntry.InternalId);
    1159.  
    1160.                     if (dataEntry.InternalId.StartsWith("http:\\"))
    1161.                         dataEntry.InternalId = dataEntry.InternalId.Replace("http:\\", "http://").Replace("\\", "/");
    1162.                     if (dataEntry.InternalId.StartsWith("https:\\"))
    1163.                         dataEntry.InternalId = dataEntry.InternalId.Replace("https:\\", "https://").Replace("\\", "/");
    1164.                 }
    1165.                 else
    1166.                 {
    1167.                     Debug.LogWarningFormat("Unable to find ContentCatalogDataEntry for bundle {0}.", outputBundles[i]);
    1168.                 }
    1169.  
    1170.                 var targetPath = Path.Combine(path, outputBundles[i]);
    1171.                 var srcPath = Path.Combine(assetGroup.Settings.buildSettings.bundleBuildPath, buildBundles[i]);
    1172.  
    1173.                 if (assetGroup.GetSchema<BundledAssetGroupSchema>()?.BundleNaming ==
    1174.                     BundledAssetGroupSchema.BundleNamingStyle.NoHash)
    1175.                     outputBundles[i] = StripHashFromBundleLocation(outputBundles[i]);
    1176.  
    1177.                 bundleRenameMap.Add(buildBundles[i], outputBundles[i]);
    1178.                 MoveFileToDestinationWithTimestampIfDifferent(srcPath, targetPath, m_Log);
    1179.                 AddPostCatalogUpdatesInternal(assetGroup, postCatalogUpdateCallbacks, dataEntry, targetPath, registry);
    1180.  
    1181.                 registry.AddFile(targetPath);
    1182.             }
    1183.         }
    1184.  
    1185.         internal void AddPostCatalogUpdatesInternal(AddressableAssetGroup assetGroup, List<Action> postCatalogUpdates,
    1186.             ContentCatalogDataEntry dataEntry, string targetBundlePath, FileRegistry registry)
    1187.         {
    1188.             if (assetGroup.GetSchema<BundledAssetGroupSchema>()?.BundleNaming ==
    1189.                 BundledAssetGroupSchema.BundleNamingStyle.NoHash)
    1190.             {
    1191.                 postCatalogUpdates.Add(() =>
    1192.                 {
    1193.                     //This is where we strip out the temporary hash for the final bundle location and filename
    1194.                     string bundlePathWithoutHash = StripHashFromBundleLocation(targetBundlePath);
    1195.                     if (File.Exists(targetBundlePath))
    1196.                     {
    1197.                         if (File.Exists(bundlePathWithoutHash))
    1198.                             File.Delete(bundlePathWithoutHash);
    1199.                         string destFolder = Path.GetDirectoryName(bundlePathWithoutHash);
    1200.                         if (!string.IsNullOrEmpty(destFolder) && !Directory.Exists(destFolder))
    1201.                             Directory.CreateDirectory(destFolder);
    1202.  
    1203.                         File.Move(targetBundlePath, bundlePathWithoutHash);
    1204.                     }
    1205.  
    1206.                     if (registry != null)
    1207.                     {
    1208.                         if (!registry.ReplaceBundleEntry(targetBundlePath, bundlePathWithoutHash))
    1209.                             Debug.LogErrorFormat("Unable to find registered file for bundle {0}.", targetBundlePath);
    1210.                     }
    1211.  
    1212.                     if (dataEntry != null)
    1213.                         if (DataEntryDiffersFromBundleFilename(dataEntry, bundlePathWithoutHash))
    1214.                             dataEntry.InternalId = StripHashFromBundleLocation(dataEntry.InternalId);
    1215.                 });
    1216.             }
    1217.         }
    1218.  
    1219.         // if false, there is no need to remove the hash from dataEntry.InternalId
    1220.         bool DataEntryDiffersFromBundleFilename(ContentCatalogDataEntry dataEntry, string bundlePathWithoutHash)
    1221.         {
    1222.             string dataEntryId = dataEntry.InternalId;
    1223.             string dataEntryFilename = Path.GetFileName(dataEntryId);
    1224.             string bundleFileName = Path.GetFileName(bundlePathWithoutHash);
    1225.  
    1226.             return dataEntryFilename != bundleFileName;
    1227.         }
    1228.  
    1229.         /// <summary>
    1230.         /// Creates a name for an asset bundle using the provided information.
    1231.         /// </summary>
    1232.         /// <param name="assetGroup">The asset group.</param>
    1233.         /// <param name="schema">The schema of the group.</param>
    1234.         /// <param name="info">The bundle information.</param>
    1235.         /// <param name="assetBundleName">The base name of the asset bundle.</param>
    1236.         /// <returns>Returns the asset bundle name with the provided information.</returns>
    1237.         protected virtual string ConstructAssetBundleName(AddressableAssetGroup assetGroup,
    1238.             BundledAssetGroupSchema schema, BundleDetails info, string assetBundleName)
    1239.         {
    1240.             if (assetGroup != null)
    1241.             {
    1242.                 string groupName = assetGroup.Name.Replace(" ", "").Replace('\\', '/').Replace("//", "/").ToLower();
    1243.                 assetBundleName = groupName + "_" + assetBundleName;
    1244.             }
    1245.  
    1246.             string bundleNameWithHashing =
    1247.                 BuildUtility.GetNameWithHashNaming(schema.BundleNaming, info.Hash.ToString(), assetBundleName);
    1248.             //For no hash, we need the hash temporarily for content update purposes.  This will be stripped later on.
    1249.             if (schema.BundleNaming == BundledAssetGroupSchema.BundleNamingStyle.NoHash)
    1250.             {
    1251.                 bundleNameWithHashing =
    1252.                     bundleNameWithHashing.Replace(".bundle", "_" + info.Hash.ToString() + ".bundle");
    1253.             }
    1254.  
    1255.             return bundleNameWithHashing;
    1256.         }
    1257.  
    1258.         static void ReplaceDependencyKeys(string from, string to, List<ContentCatalogDataEntry> locations)
    1259.         {
    1260.             foreach (ContentCatalogDataEntry location in locations)
    1261.             {
    1262.                 for (int i = 0; i < location.Dependencies.Count; ++i)
    1263.                 {
    1264.                     string s = location.Dependencies[i] as string;
    1265.                     if (string.IsNullOrEmpty(s))
    1266.                         continue;
    1267.                     if (s == from)
    1268.                         location.Dependencies[i] = to;
    1269.                 }
    1270.             }
    1271.         }
    1272.  
    1273.         private static long GetFileSize(string fileName)
    1274.         {
    1275.             try
    1276.             {
    1277.                 return new FileInfo(fileName).Length;
    1278.             }
    1279.             catch (Exception e)
    1280.             {
    1281.                 Debug.LogException(e);
    1282.                 return 0;
    1283.             }
    1284.         }
    1285.  
    1286.         /// <inheritdoc />
    1287.         public override void ClearCachedData()
    1288.         {
    1289.             if (Directory.Exists(Addressables.BuildPath))
    1290.             {
    1291.                 try
    1292.                 {
    1293.                     var catalogPath = Addressables.BuildPath + "/catalog.json";
    1294.                     var settingsPath = Addressables.BuildPath + "/settings.json";
    1295.                     DeleteFile(catalogPath);
    1296.                     DeleteFile(settingsPath);
    1297.                     Directory.Delete(Addressables.BuildPath, true);
    1298.                 }
    1299.                 catch (Exception e)
    1300.                 {
    1301.                     Debug.LogException(e);
    1302.                 }
    1303.             }
    1304.         }
    1305.  
    1306.         /// <inheritdoc />
    1307.         public override bool IsDataBuilt()
    1308.         {
    1309.             var settingsPath = Addressables.BuildPath + "/settings.json";
    1310.             return !String.IsNullOrEmpty(m_CatalogBuildPath) &&
    1311.                    File.Exists(m_CatalogBuildPath) &&
    1312.                    File.Exists(settingsPath);
    1313.         }
    1314.     }
    1315. }
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using System.Threading;
    5. using UnityEditor.Build.Pipeline.Interfaces;
    6. using UnityEditor.Build.Pipeline.Utilities;
    7. using UnityEditor.Build.Utilities;
    8.  
    9. namespace UnityEditor.Build.Pipeline
    10. {
    11.     /// <summary>
    12.     /// Static class containing the main content building entry points into the Scriptable Build Pipeline.
    13.     /// </summary>
    14.     public static class CustomPipeLine
    15.     {
    16.         /// <summary>
    17.         /// Default temporary path used for building content data.
    18.         /// </summary>
    19.         public const string kTempBuildPath = "Temp/ContentBuildData";
    20.  
    21.         /// <summary>
    22.         /// Default temporary path used for building script data.
    23.         /// </summary>
    24.         public const string kScriptBuildPath = "Library/PlayerScriptAssemblies";
    25.  
    26.         /// <summary>
    27.         /// Default callback implementation.
    28.         /// </summary>
    29.         public static BuildCallbacks BuildCallbacks = new BuildCallbacks();
    30.  
    31.         /// <summary>
    32.         /// Default implementation of generating Asset Bundles using the Scriptable Build Pipeline.
    33.         /// </summary>
    34.         /// <param name="parameters">Set of parameters used for building asset bundles.</param>
    35.         /// <param name="content">Set of content and explicit asset bundle layout to build.</param>
    36.         /// <param name="result">Results from building the content and explicit asset bundle layout.</param>
    37.         /// <returns>Return code with status information about success or failure causes.</returns>
    38.         public static ReturnCode BuildAssetBundles(IBundleBuildParameters parameters, IBundleBuildContent content, out IBundleBuildResults result)
    39.         {
    40.             var taskList = DefaultBuildTasks.Create(DefaultBuildTasks.Preset.AssetBundleCompatible);
    41.             return BuildAssetBundles(parameters, content, out result, taskList);
    42.         }
    43.  
    44.         /// <summary>
    45.         /// Default implementation of generating Asset Bundles using the Scriptable Build Pipeline.
    46.         /// </summary>
    47.         /// <param name="parameters">Set of parameters used for building asset bundles.</param>
    48.         /// <param name="content">Set of content and explicit asset bundle layout to build.</param>
    49.         /// <param name="result">Results from building the content and explicit asset bundle layout.</param>
    50.         /// <param name="taskList">Custom task list for building asset bundles.</param>
    51.         /// <param name="contextObjects">Additional context objects to make available to the build.</param>
    52.         /// <returns>Return code with status information about success or failure causes.</returns>
    53.         public static ReturnCode BuildAssetBundles(IBundleBuildParameters parameters, IBundleBuildContent content, out IBundleBuildResults result, IList<IBuildTask> taskList, params IContextObject[] contextObjects)
    54.         {
    55.             if (BuildPipeline.isBuildingPlayer)
    56.             {
    57.                 result = null;
    58.                 BuildLogger.LogException(new InvalidOperationException("Cannot build asset bundles while a build is in progress"));
    59.                 return ReturnCode.Exception;
    60.             }
    61.  
    62.             // Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
    63.             if (parameters == null)
    64.             {
    65.                 result = null;
    66.                 BuildLogger.LogException(new ArgumentNullException("parameters"));
    67.                 return ReturnCode.Exception;
    68.             }
    69.  
    70.             // Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
    71.             if (taskList.IsNullOrEmpty())
    72.             {
    73.                 result = null;
    74.                 BuildLogger.LogException(new ArgumentException("Argument cannot be null or empty.", "taskList"));
    75.                 return ReturnCode.Exception;
    76.             }
    77.  
    78.             // Don't run if there are unsaved changes
    79.           //  if (ValidationMethods.HasDirtyScenes())
    80.           //  {
    81.            //     result = null;
    82.             //    return ReturnCode.UnsavedChanges;
    83.            // }
    84.  
    85.             ThreadingManager.WaitForOutstandingTasks();
    86.             BuildContext buildContext = new BuildContext(contextObjects);
    87.             BuildLog buildLog = null;
    88.  
    89.             IBuildLogger logger;
    90.             if (!buildContext.TryGetContextObject<IBuildLogger>(out logger))
    91.             {
    92.                 logger = buildLog = new BuildLog();
    93.                 buildContext.SetContextObject(buildLog);
    94.             }
    95.  
    96.             using (logger.ScopedStep(LogLevel.Info, "AssetDatabase.SaveAssets"))
    97.                 AssetDatabase.SaveAssets();
    98.  
    99.             ReturnCode exitCode;
    100.             result = new BundleBuildResults();
    101.  
    102. #if !CI_TESTRUNNER_PROJECT
    103.             using (new SceneStateCleanup())
    104.             using (var progressTracker = new ProgressTracker())
    105. #else
    106.             using (var progressTracker = new ProgressLoggingTracker())
    107. #endif
    108.             {
    109.                 using (new AutoBuildCacheUtility())
    110.                 using (var interfacesWrapper = new BuildInterfacesWrapper())
    111.                 using (var buildCache = new BuildCache(parameters.CacheServerHost, parameters.CacheServerPort))
    112.                 {
    113.                     Directory.CreateDirectory(parameters.TempOutputFolder);
    114.                     Directory.CreateDirectory(parameters.ScriptOutputFolder);
    115.  
    116.                     try
    117.                     {
    118.                         buildContext.SetContextObject(parameters);
    119.                         buildContext.SetContextObject(content);
    120.                         buildContext.SetContextObject(result);
    121.                         buildContext.SetContextObject(interfacesWrapper);
    122.                         buildContext.SetContextObject(progressTracker);
    123.                         buildContext.SetContextObject(buildCache);
    124.                         // If IDeterministicIdentifiers was passed in with contextObjects, don't add the default
    125.                         if (!buildContext.ContainsContextObject(typeof(IDeterministicIdentifiers)))
    126.                             buildContext.SetContextObject(parameters.ContiguousBundles ? new PrefabPackedIdentifiers() : (IDeterministicIdentifiers) new Unity5PackedIdentifiers());
    127.                         buildContext.SetContextObject(new BuildDependencyData());
    128.                         buildContext.SetContextObject(new BundleWriteData());
    129.                         buildContext.SetContextObject(BuildCallbacks);
    130.                         buildCache.SetBuildLogger(logger);
    131.                     }
    132.                     catch (Exception e)
    133.                     {
    134.                         // Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
    135.                         result = null;
    136.                         BuildLogger.LogException(e);
    137.                         return ReturnCode.Exception;
    138.                     }
    139.  
    140.                     exitCode = BuildTasksRunner.Validate(taskList, buildContext);
    141.                     if (exitCode >= ReturnCode.Success)
    142. #if SBP_PROFILER_ENABLE
    143.                         exitCode = BuildTasksRunner.RunProfiled(taskList, buildContext);
    144. #else
    145.                         exitCode = BuildTasksRunner.Run(taskList, buildContext);
    146. #endif
    147.  
    148.                     if (Directory.Exists(parameters.TempOutputFolder))
    149.                         Directory.Delete(parameters.TempOutputFolder, true);
    150.  
    151.                     if (buildLog != null)
    152.                     {
    153.                         string buildLogPath = parameters.GetOutputFilePathForIdentifier("buildlogtep.json");
    154.                         Directory.CreateDirectory(Path.GetDirectoryName(buildLogPath));
    155.                         File.WriteAllText(parameters.GetOutputFilePathForIdentifier("buildlogtep.json"), buildLog.FormatForTraceEventProfiler());
    156.                     }
    157.                 }
    158.             }
    159.  
    160.             long maximumCacheSize = ScriptableBuildPipeline.maximumCacheSize * BuildCache.k_BytesToGigaBytes;
    161.             BuildCache.PruneCache_Background(maximumCacheSize);
    162.             return exitCode;
    163.         }
    164.     }
    165. }
    166.  

    as you can see I have just simply copy and pasted from other script. though I can't remember which it was...

    And then you need to create assets from these scripts, set it to addressable Asset Settings.
     
    Last edited: Mar 30, 2022
    Basti_TinyRoar likes this.