using System; using System.Collections.Generic; using System.IO; using System.Threading; using UnityEditor.Build.Pipeline.Interfaces; using UnityEditor.Build.Pipeline.Utilities; using UnityEditor.Build.Utilities; using UnityEditor.Modules; namespace UnityEditor.Build.Pipeline { /// /// Static class containing the main content building entry points into the Scriptable Build Pipeline. /// public static class ContentPipeline { /// /// Default temporary path used for building content data. /// public const string kTempBuildPath = "Temp/ContentBuildData"; /// /// Default temporary path used for building script data. /// public const string kScriptBuildPath = "Library/PlayerScriptAssemblies"; /// /// Default callback implementation. /// public static BuildCallbacks BuildCallbacks = new BuildCallbacks(); /// /// Default implementation of generating Asset Bundles using the Scriptable Build Pipeline. /// /// Set of parameters used for building asset bundles. /// Set of content and explicit asset bundle layout to build. /// Results from building the content and explicit asset bundle layout. /// Return code with status information about success or failure causes. public static ReturnCode BuildAssetBundles(IBundleBuildParameters parameters, IBundleBuildContent content, out IBundleBuildResults result) { var taskList = DefaultBuildTasks.Create(DefaultBuildTasks.Preset.AssetBundleCompatible); return BuildAssetBundles(parameters, content, out result, taskList); } /// /// Default implementation of generating Asset Bundles using the Scriptable Build Pipeline. /// /// Set of parameters used for building asset bundles. /// Set of content and explicit asset bundle layout to build. /// Results from building the content and explicit asset bundle layout. /// Custom task list for building asset bundles. /// Additional context objects to make available to the build. /// Return code with status information about success or failure causes. public static ReturnCode BuildAssetBundles(IBundleBuildParameters parameters, IBundleBuildContent content, out IBundleBuildResults result, IList taskList, params IContextObject[] contextObjects) { if (BuildPipeline.isBuildingPlayer) { result = null; BuildLogger.LogException(new InvalidOperationException("Cannot build asset bundles while a build is in progress")); return ReturnCode.Exception; } // Avoid throwing exceptions in here as we don't want them bubbling up to calling user code if (parameters == null) { result = null; BuildLogger.LogException(new ArgumentNullException("parameters")); return ReturnCode.Exception; } // Avoid throwing exceptions in here as we don't want them bubbling up to calling user code if (taskList.IsNullOrEmpty()) { result = null; BuildLogger.LogException(new ArgumentException("Argument cannot be null or empty.", "taskList")); return ReturnCode.Exception; } var contentBuildSettings = parameters.GetContentBuildSettings(); if (!CanBuildPlayer(contentBuildSettings.target, contentBuildSettings.group)) { result = null; BuildLogger.LogException(new InvalidOperationException("Unable to build with the current configuration, please check the Build Settings.")); return ReturnCode.Exception; } // Don't run if there are unsaved changes if (ValidationMethods.HasDirtyScenes()) { result = null; return ReturnCode.UnsavedChanges; } ThreadingManager.WaitForOutstandingTasks(); BuildContext buildContext = new BuildContext(contextObjects); BuildLog buildLog = null; IBuildLogger logger; if (!buildContext.TryGetContextObject(out logger)) { logger = buildLog = new BuildLog(); buildContext.SetContextObject(buildLog); } using (logger.ScopedStep(LogLevel.Info, "AssetDatabase.SaveAssets")) AssetDatabase.SaveAssets(); ReturnCode exitCode; result = new BundleBuildResults(); #if !CI_TESTRUNNER_PROJECT using (new SceneStateCleanup()) using (var progressTracker = new ProgressTracker()) #else using (var progressTracker = new ProgressLoggingTracker()) #endif { using (new AutoBuildCacheUtility()) using (var interfacesWrapper = new BuildInterfacesWrapper()) using (var buildCache = new BuildCache(parameters.CacheServerHost, parameters.CacheServerPort)) { BuildCacheUtility.SetCurrentBuildContent(content); Directory.CreateDirectory(parameters.TempOutputFolder); Directory.CreateDirectory(parameters.ScriptOutputFolder); try { buildContext.SetContextObject(parameters); buildContext.SetContextObject(content); buildContext.SetContextObject(result); buildContext.SetContextObject(interfacesWrapper); buildContext.SetContextObject(progressTracker); buildContext.SetContextObject(buildCache); // If IDeterministicIdentifiers was passed in with contextObjects, don't add the default if (!buildContext.ContainsContextObject(typeof(IDeterministicIdentifiers))) buildContext.SetContextObject(parameters.ContiguousBundles ? new PrefabPackedIdentifiers() : (IDeterministicIdentifiers)new Unity5PackedIdentifiers()); buildContext.SetContextObject(new BuildDependencyData()); buildContext.SetContextObject(new ObjectDependencyData()); buildContext.SetContextObject(new BundleWriteData()); buildContext.SetContextObject(BuildCallbacks); buildCache.SetBuildLogger(logger); } catch (Exception e) { // Avoid throwing exceptions in here as we don't want them bubbling up to calling user code result = null; BuildLogger.LogException(e); return ReturnCode.Exception; } exitCode = BuildTasksRunner.Validate(taskList, buildContext); if (exitCode >= ReturnCode.Success) #if SBP_PROFILER_ENABLE exitCode = BuildTasksRunner.RunProfiled(taskList, buildContext); #else exitCode = BuildTasksRunner.Run(taskList, buildContext); #endif if (Directory.Exists(parameters.TempOutputFolder)) Directory.Delete(parameters.TempOutputFolder, true); if (buildLog != null) { string buildLogPath = parameters.GetOutputFilePathForIdentifier("buildlogtep.json"); Directory.CreateDirectory(Path.GetDirectoryName(buildLogPath)); File.WriteAllText(parameters.GetOutputFilePathForIdentifier("buildlogtep.json"), buildLog.FormatForTraceEventProfiler()); } } } long maximumCacheSize = ScriptableBuildPipeline.maximumCacheSize * BuildCache.k_BytesToGigaBytes; BuildCache.PruneCache_Background(maximumCacheSize); return exitCode; } //Functionality has been removed due to issues with APV in yamato for package release (https://jira.unity3d.com/browse/BPSBP-735) private static bool CanBuildPlayer(BuildTarget target, BuildTargetGroup targetGroup) { // The Editor APIs we need only exist in 2021.3 and later. For earlier versions, assume we can build. //#if UNITY_2021_3_OR_NEWER // var module = ModuleManager.GetTargetStringFrom(targetGroup, target); // var buildWindowExtension = ModuleManager.GetBuildWindowExtension(module); // return buildWindowExtension != null ? buildWindowExtension.EnabledBuildButton() : false; //#else return true; //#endif } } }