public static void Build() { if (Directory.Exists(folderPath)) { Directory.Delete(folderPath, true); } if (Directory.Exists(k_TmpPath)) { Directory.Delete(k_TmpPath, true); } Directory.CreateDirectory(folderPath); Directory.CreateDirectory(k_TmpPath); IBundleBuildParameters buildParams = new BundleBuildParameters(EditorUserBuildSettings.activeBuildTarget, BuildTargetGroup.Unknown, folderPath); buildParams.TempOutputFolder = k_TmpPath; IBundleBuildContent buildContent = new BundleBuildContent(ContentBuildInterface.GenerateAssetBundleBuilds()); IBundleBuildResults results; List <IBuildTask> taskList = DefaultBuildTasks.Create(DefaultBuildTasks.Preset.AssetBundleBuiltInShaderExtraction) as List <IBuildTask>; taskList.Add(new RefreshAssetDatabase()); taskList.Add(new CreateBuiltTimeReport()); ReturnCode exitCode = ContentPipelineProfiled.BuildAssetBundles(buildParams, buildContent, out results, taskList, new Profiler("Total")); Debug.Log("Building completed with " + exitCode); }
/// <summary> /// SBP构建 /// </summary> /// <returns>The build pipeline.</returns> ReturnCode ScriptableBuildPipeline() { var buildContent = GetBundleContent(); //new BundleBuildContent(ContentBuildInterface.GenerateAssetBundleBuilds()); var buildParams = new BundleBuildParameters(settings.buildTarget, settings.buildGroup, settings.outputPath); if (settings.compressionType == CompressionType.None) { buildParams.BundleCompression = BuildCompression.DefaultUncompressed; } else if (settings.compressionType == CompressionType.Lzma) { buildParams.BundleCompression = BuildCompression.DefaultLZMA; } else if (settings.compressionType == CompressionType.Lz4 || settings.compressionType == CompressionType.Lz4HC) { buildParams.BundleCompression = BuildCompression.DefaultLZ4; } IBundleBuildResults results; ReturnCode exitCode; exitCode = ContentPipeline.BuildAssetBundles(buildParams, buildContent, out results); return(exitCode); }
public static void Build(Setting setting) { if (setting == null) { return; } var path = setting.BuildInfo.OutputPath; if (!Path.IsPathRooted(path)) { path = Path.GetFullPath(Path.Combine(Application.dataPath, "..", path)); } var buildContent = new BundleBuildContent(ContentBuildInterface.GenerateAssetBundleBuilds()); var buildParam = new BundleBuildParameters(setting.BuildInfo.Target, setting.BuildInfo.TargetGroup, path); buildParam.ScriptOptions = ScriptCompilationOptions.None; buildParam.BundleCompression = UnityEngine.BuildCompression.LZ4; var settingContext = new LibCraftopiaSetting(setting); var tasks = BuildPipeline.CreatPipeline(); var code = ContentPipeline.BuildAssetBundles(buildParam, buildContent, out var result, tasks, settingContext); if (code < 0) { UnityEngine.Debug.LogError("Build failed"); } }
/// <summary> /// The BundleBuildContent class contains information about all of the Assets you want to build into the BuildMap /// Assets are referenced to by a GUID object, and the Addresses can be obtained and modified by using a GUID to /// refer to each asset and identify its Address /// </summary> /// <param name="outputPath"></param> /// <param name="compressionMode"></param> /// <param name="buildTarget"></param> /// <param name="buildGroup"></param> /// <param name="results"></param> /// <returns></returns> public static ReturnCode BuildAssetBundles(string outputPath, CompressionType compressionMode, BuildTarget buildTarget, BuildTargetGroup buildGroup, out IBundleBuildResults results) { BundleBuildContent buildContent = new BundleBuildContent(ContentBuildInterface.GenerateAssetBundleBuilds()); // Go through assets content and set their address to its filename for (int i = 0; i < buildContent.Assets.Count; ++i) { GUID g = buildContent.Assets[i]; // Get the current address as the full filepath and change it to just be the filename buildContent.Addresses[g] = Path.GetFileNameWithoutExtension(buildContent.Addresses[g]); } BundleBuildParameters buildParams = new BundleBuildParameters(buildTarget, buildGroup, outputPath); switch (compressionMode) { case CompressionType.None: buildParams.BundleCompression = BuildCompression.Uncompressed; break; case CompressionType.Lz4: buildParams.BundleCompression = BuildCompression.LZ4; break; default: buildParams.BundleCompression = BuildCompression.LZMA; break; } return(ContentPipeline.BuildAssetBundles(buildParams, buildContent, out results)); }
public static void Build() { ReadCommandLine(); if (Directory.Exists(folderPath)) { Directory.Delete(folderPath, true); } if (Directory.Exists(k_TmpPath)) { Directory.Delete(k_TmpPath, true); } Directory.CreateDirectory(folderPath); Directory.CreateDirectory(k_TmpPath); IBundleBuildParameters buildParams = new BundleBuildParameters(EditorUserBuildSettings.activeBuildTarget, BuildTargetGroup.Unknown, folderPath); buildParams.TempOutputFolder = k_TmpPath; IBundleBuildContent buildContent = new BundleBuildContent(ContentBuildInterface.GenerateAssetBundleBuilds()); IBundleBuildResults results; List <IBuildTask> taskList = DefaultBuildTasks.Create(DefaultBuildTasks.Preset.AssetBundleBuiltInShaderExtraction) as List <IBuildTask>; taskList.Add(new RefreshAssetDatabase()); // we add a callback after generating information about how to build each bundle ContentPipeline.BuildCallbacks.PostPackingCallback += PostPackingCallback; ReturnCode exitCode = ContentPipeline.BuildAssetBundles(buildParams, buildContent, out results, taskList); Debug.Log("Building completed with " + exitCode); }
/// <summary> /// The cache server serving ScriptableBuildPipeline must be dedicated to the build process. /// Be sure to not mix the two. Due to how the cache server stores the data, data collisions are /// like and problems will occur /// /// see: https://github.com/Unity-Technologies/unity-cache-server /// </summary> public static void SetupBuildCacheServer(BundleBuildParameters buildParams) { // setup to a cache server running locally with ip set to 8127 // we can set the port when starting the cache server as showing in https://github.com/Unity-Technologies/unity-cache-server#usage with -p buildParams.UseCache = true; buildParams.CacheServerHost = "127.0.0.1"; buildParams.CacheServerPort = 8127; // 8126 is default, }
static ReturnCode WriteSceneBundles(BundleBuildParameters parameters, string[] scenes) { var bundles = new AssetBundleBuild[1]; bundles[0].assetBundleName = "scenes.bundle"; bundles[0].assetNames = scenes; var content = new BundleBuildContent(bundles); return(ContentPipeline.BuildAssetBundles(parameters, content, out var result)); }
internal ReturnCode CreateCatalogBundle(string filepath, string jsonText, AddressablesDataBuilderInput builderInput) { if (string.IsNullOrEmpty(filepath) || string.IsNullOrEmpty(jsonText) || builderInput == null) { throw new ArgumentException("Unable to create catalog bundle (null arguments)."); } // A bundle requires an actual asset var tempFolderName = "TempCatalogFolder"; var tempFolderPath = Path.Combine(AddressableAssetSettingsDefaultObject.kDefaultConfigFolder, tempFolderName); var tempFilePath = Path.Combine(tempFolderPath, Path.GetFileName(filepath).Replace(".bundle", ".json")); if (!WriteFile(tempFilePath, jsonText, builderInput.Registry)) { throw new Exception("An error occured during the creation of temporary files needed to bundle the content catalog."); } AssetDatabase.Refresh(); var bundleBuildContent = new BundleBuildContent(new[] { new AssetBundleBuild() { assetBundleName = Path.GetFileName(filepath), assetNames = new[] { tempFilePath }, addressableNames = new string[0] } }); var buildTasks = new List <IBuildTask> { new CalculateAssetDependencyData(), new GenerateBundlePacking(), new GenerateBundleCommands(), new WriteSerializedFiles(), new ArchiveAndCompressBundles() }; var buildParams = new BundleBuildParameters(builderInput.Target, builderInput.TargetGroup, Path.GetDirectoryName(filepath)); var retCode = ContentPipeline.BuildAssetBundles(buildParams, bundleBuildContent, out IBundleBuildResults result, buildTasks); if (Directory.Exists(tempFolderPath)) { Directory.Delete(tempFolderPath, true); builderInput.Registry.RemoveFile(tempFilePath); } if (File.Exists(filepath)) { builderInput.Registry.AddFile(filepath); } return(retCode); }
/// <summary> 指定されたアセットバンドルをビルド </summary> public BuildResult Build(string outputPath, AssetBundleBuild[] buildMap) { var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(BuildTarget); var buildParams = new BundleBuildParameters(BuildTarget, buildTargetGroup, outputPath) { BundleCompression = BuildCompression.LZ4, }; var buildContent = new BundleBuildContent(buildMap); var tasks = DefaultBuildTasks.Create(DefaultBuildTasks.Preset.AssetBundleBuiltInShaderExtraction); var exitCode = ContentPipeline.BuildAssetBundles(buildParams, buildContent, out var results, tasks); return(new BuildResult(exitCode, results)); }
static IBundleBuildParameters GetBuildParameters() { if (Directory.Exists(k_FolderPath)) { Directory.Delete(k_FolderPath, true); } if (Directory.Exists(k_TmpPath)) { Directory.Delete(k_TmpPath, true); } Directory.CreateDirectory(k_FolderPath); Directory.CreateDirectory(k_TmpPath); IBundleBuildParameters buildParams = new BundleBuildParameters(EditorUserBuildSettings.activeBuildTarget, EditorUserBuildSettings.selectedBuildTargetGroup, k_FolderPath); buildParams.TempOutputFolder = k_TmpPath; return(buildParams); }
static ReturnCode WriteRenderPipelineBundles(BundleBuildParameters parameters) { var srp = UnityEngine.Rendering.GraphicsSettings.defaultRenderPipeline; if (srp == null) { return(ReturnCode.SuccessNotRun); } var bundles = new AssetBundleBuild[1]; bundles[0].assetBundleName = "renderpipeline.bundle"; bundles[0].assetNames = new[] { AssetDatabase.GetAssetPath(UnityEngine.Rendering.GraphicsSettings.defaultRenderPipeline) }; bundles[0].addressableNames = new[] { "DefaultRenderPipeline" }; var content = new BundleBuildContent(bundles); return(ContentPipeline.BuildAssetBundles(parameters, content, out var result)); }
static ReturnCode WriteResourcesBundles(BundleBuildParameters parameters) { // Resources loading path handling has a few rules: // - Paths are relative to resources folder // - Paths are lowercase // - Paths have extensions removed // So "C:\Project\Assets\MyGame\Resources\SO\SomeAsset.asset" becomes "so\someAsset" // On the loading side, all paths passed in have ToLower() run on them. var assetPaths = GetResourcesAssetPaths(); var bundles = new AssetBundleBuild[] { new AssetBundleBuild() { assetBundleName = "resources.bundle", assetNames = assetPaths.Select(x => x.ToString()).ToArray(), addressableNames = assetPaths.Select(x => { const string k_Folder = "/resources/"; const int k_FolderLength = 11; // Hack for PostProcessing stack var shader = AssetDatabase.LoadAssetAtPath <Shader>(x.ToString()); if (shader != null) { return(shader.name.ToLower()); } var path = x.ChangeExtension("").ToString().ToLower(); var index = path.ToLower().LastIndexOf(k_Folder); if (index > -1) { path = path.Substring(index + k_FolderLength); } return(path); }).ToArray() } }; var content = new BundleBuildContent(bundles); return(ContentPipeline.BuildAssetBundles(parameters, content, out var result)); }
public static void Build() { Clear(); var Mods = ModsEditor.GetMods(); int length = Mods.Length; for (int i = 0; i < length; i++) { var ModInfo = ModsEditor.GetModInfo(Mods[i]); var ModOutPutFolder = OutPutFolder + "/" + ModInfo.PackageName; Directory.CreateDirectory(ModOutPutFolder); //生成ModInfo文件 using (StreamWriter sw = File.CreateText(ModOutPutFolder + "/" + ModInfo.PackageName + ".json")) { sw.Write(JsonConvert.SerializeObject(ModInfo)); } //Windows64版本构建 //构建参数 var param = new BundleBuildParameters(BuildTarget.StandaloneWindows64, BuildTargetGroup.Standalone, ModOutPutFolder); param.BundleCompression = BuildCompression.LZ4; //填入资源 var content = new BundleBuildContent(new AssetBundleBuild[] { GetAllAssets(ModInfo, "winmod") }); IBundleBuildResults results; //构建包 ReturnCode code = ContentPipeline.BuildAssetBundles(param, content, out results); if (code != ReturnCode.Success) { if (code == ReturnCode.Canceled) { return;//如果取消,直接返回 } Debug.LogError("构建失败!错误原因:" + code.ToString()); } } }
public static ReturnCode BuildAssetBundles(string outputPath, CompressionType compressionMode, BuildTarget buildTarget, BuildTargetGroup buildGroup, out IBundleBuildResults results) { BundleBuildContent buildContent = new BundleBuildContent(ContentBuildInterface.GenerateAssetBundleBuilds()); BundleBuildParameters buildParams = new BundleBuildParameters(buildTarget, buildGroup, outputPath); SetupBuildCacheServer(buildParams); switch (compressionMode) { case CompressionType.None: buildParams.BundleCompression = BuildCompression.Uncompressed; break; case CompressionType.Lz4: buildParams.BundleCompression = BuildCompression.LZ4; break; default: buildParams.BundleCompression = BuildCompression.LZMA; break; } return(ContentPipeline.BuildAssetBundles(buildParams, buildContent, out results)); }
// This function is responsible for providing all the subscenes to the build. // // The way these files get generated is that we have a SceneWithBuildConfiguration file, (which is a bit of a hack to work around the inability for scriptable importers to take arguments, so // instead we create a different file that points to the scene we want to import, and points to the buildconfiguration we want to import it for). The SubsceneImporter will import this file, // and it will make 3 (relevant) kind of files: // - headerfile // - entitybinaryformat file (the actual entities payloads) // - a SerializedFile that has an array of UnityEngine.Object PPtrs that are used by this entity file. // // The first two we deal with very simply: they just need to be copied into the build, and we're done. // the third one, we will feed as input to the Scriptable build pipeline (which is actually about creating assetbundles), and create an assetbundle that // has all those objects in it that the 3rd file referred to. We do this with a batch api, first we loop through all subscenes, and register with this batch // api which assetbundles we'd like to see produced, and then at the end, we say "okay make them please". this assetbundle creation api has a caching system // that is separate from the assetpipeline caching system, so if all goes well, the call to produce these assetbundles will return very fast and did nothing. // // The reason for the strange looking api, where a two callbacks get passed in is to make integration of the new incremental buildpipeline easier, as this code // needs to be compatible both with the current buildpipeline in the dots-repo, as well as with the incremental buildpipeline. When that is merged, we can simplify this. public static void PrepareAdditionalFiles(GUID[] sceneGuids, ArtifactKey[] entitySceneArtifacts, BuildTarget target, Action <string, string> RegisterFileCopy, string outputStreamingAssetsDirectory, string buildWorkingDirectory) { if (target == BuildTarget.NoTarget) { throw new InvalidOperationException($"Invalid build target '{target.ToString()}'."); } if (target != EditorUserBuildSettings.activeBuildTarget) { throw new InvalidOperationException($"ActiveBuildTarget must be switched before the {nameof(SubSceneBuildCode)} runs."); } Assert.AreEqual(sceneGuids.Length, entitySceneArtifacts.Length); var content = new BundleBuildContent(new AssetBundleBuild[0]); var bundleNames = new HashSet <string>(); var subScenePaths = new Dictionary <Hash128, string>(); var dependencyInputData = new Dictionary <SceneSection, SectionDependencyInfo>(); var refExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesUnityObjectReferences); var headerExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesHeader); var binaryExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesBinary); string conversionLogExtension = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesConversionLog); var group = BuildPipeline.GetBuildTargetGroup(target); var parameters = new BundleBuildParameters(target, @group, buildWorkingDirectory) { BundleCompression = BuildCompression.LZ4Runtime }; var artifactHashes = new UnityEngine.Hash128[entitySceneArtifacts.Length]; AssetDatabaseCompatibility.ProduceArtifactsRefreshIfNecessary(entitySceneArtifacts, artifactHashes); for (int i = 0; i != entitySceneArtifacts.Length; i++) { var sceneGuid = sceneGuids[i]; var sceneBuildConfigGuid = entitySceneArtifacts[i].guid; var artifactHash = artifactHashes[i]; bool foundEntityHeader = false; if (!artifactHash.isValid) { throw new Exception($"Building EntityScene artifact failed: '{AssetDatabaseCompatibility.GuidToPath(sceneGuid)}' ({sceneGuid}). There were exceptions during the entity scene imports."); } AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out var artifactPaths); foreach (var artifactPath in artifactPaths) { //UnityEngine.Debug.Log($"guid: {sceneGuid} artifact: '{artifactPath}'"); //@TODO: This looks like a workaround. Whats going on here? var ext = Path.GetExtension(artifactPath).Replace(".", ""); if (ext == conversionLogExtension) { var res = ConversionLogUtils.PrintConversionLogToUnityConsole(artifactPath); if (res.HasException) { throw new Exception("Building entity scenes failed. There were exceptions during the entity scene imports."); } } else if (ext == headerExt) { foundEntityHeader = true; if (!string.IsNullOrEmpty(artifactPaths.FirstOrDefault(a => a.EndsWith(refExt)))) { subScenePaths[sceneGuid] = artifactPath; } else { //if there are no reference bundles, then deduplication can be skipped var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesHeader, -1); DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile); } } else if (ext == binaryExt) { var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesBinary, EntityScenesPaths.GetSectionIndexFromPath(artifactPath)); DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile); } else if (ext == refExt) { content.CustomAssets.Add(new CustomContent { Asset = sceneBuildConfigGuid, Processor = (guid, processor) => { var sectionIndex = EntityScenesPaths.GetSectionIndexFromPath(artifactPath); processor.GetObjectIdentifiersAndTypesForSerializedFile(artifactPath, out ObjectIdentifier[] objectIds, out Type[] types);
public static NPath BuildSlimGameManagers(BuildTarget target, string[] scenes, bool development, string typeDBDirectory) { NPath tempPath; WriteManagerParameters mParams; WriteParameters wParams; WriteCommand[] writeCommands; PreloadInfo preloadInfo; // Setup { tempPath = TempDataPath; tempPath.CreateDirectory(); tempPath.Combine("Resources").MakeAbsolute().CreateDirectory(); //work around bug in unity's TypeDBHelper where it assumes Library/Type will exist new NPath("Library/Type").EnsureDirectoryExists(); mParams = new WriteManagerParameters { settings = new UnityEditor.Build.Content.BuildSettings { target = target, group = UnityEditor.BuildPipeline.GetBuildTargetGroup(target), buildFlags = development ? ContentBuildFlags.DevelopmentBuild : ContentBuildFlags.None, typeDB = TypeDbHelper.GetForPlayer(typeDBDirectory) }, globalUsage = ContentBuildInterface.GetGlobalUsageFromGraphicsSettings(), referenceMap = new BuildReferenceMap() }; wParams = new WriteParameters { settings = mParams.settings, globalUsage = mParams.globalUsage, referenceMap = mParams.referenceMap, usageSet = new BuildUsageTagSet() }; writeCommands = new[] { new WriteCommand { fileName = "unity_builtin_extra", internalName = "Resources/unity_builtin_extra", serializeObjects = new List <SerializationInfo>() }, new WriteCommand { fileName = "globalgamemanagers.assets", internalName = "globalgamemanagers.assets", serializeObjects = new List <SerializationInfo>() } }; preloadInfo = new PreloadInfo { preloadObjects = new List <ObjectIdentifier>() }; } // Dependency Calculation { var dependencyResults = ContentBuildInterface.CalculatePlayerDependenciesForGameManagers(mParams.settings, mParams.globalUsage, wParams.usageSet); var referencedObjects = dependencyResults.referencedObjects.ToArray(); var types = ContentBuildInterface.GetTypeForObjects(referencedObjects); for (int i = 0; i < referencedObjects.Length; i++) { if (referencedObjects[i].guid == k_UnityBuiltinResources) { // unity default resources contain scripts that need to be preloaded if (types[i] == typeof(MonoScript)) { preloadInfo.preloadObjects.Add(referencedObjects[i]); } // Prebuild player specific default resources file, don't remap local identifiers mParams.referenceMap.AddMapping("Library/unity default resources", referencedObjects[i].localIdentifierInFile, referencedObjects[i]); } else if (referencedObjects[i].guid == k_UnityBuiltinExtraResources) { if (types[i] == typeof(Shader)) { var command = writeCommands[0]; // Resources/unity_builtin_extra // Don't remap local identifiers var info = new SerializationInfo { serializationObject = referencedObjects[i], serializationIndex = referencedObjects[i].localIdentifierInFile }; command.serializeObjects.Add(info); mParams.referenceMap.AddMapping(command.internalName, info.serializationIndex, info.serializationObject); } else { var command = writeCommands[1]; // globalgamemanagers.assets // Squash / Remap local identifiers, starting at 2 (PreloadData 1) var info = new SerializationInfo { serializationObject = referencedObjects[i], serializationIndex = command.serializeObjects.Count + 2 }; command.serializeObjects.Add(info); mParams.referenceMap.AddMapping(command.internalName, info.serializationIndex, info.serializationObject); } } else if (types[i] == typeof(MonoScript)) { //globalgamemanagers.assets //error because we can't support all the ggm features in slim builds } else { //globalgamemanagers.assets //error because we can't support all the ggm features in slim builds } } } // Writing globalgamemanagers { var writeResults = ContentBuildInterface.WriteGameManagersSerializedFile(tempPath.ToString(), mParams); EditorUtility.ClearProgressBar(); //if (writeResults.serializedObjects.Count == 0) return "FAIL"; } // Writing globalgamemanagers.assets { wParams.writeCommand = writeCommands[1]; wParams.preloadInfo = preloadInfo; var writeResults = ContentBuildInterface.WriteSerializedFile(tempPath.ToString(), wParams); EditorUtility.ClearProgressBar(); //if (writeResults.serializedObjects.Count == 0) return "FAIL"; } // Writing unity_builtin_extra" { wParams.writeCommand = writeCommands[0]; wParams.preloadInfo = null; // unity_builtin_extras requires absolutepath writing, so fixup the internalName and referenceMap for this wParams.writeCommand.internalName = tempPath.Combine(wParams.writeCommand.internalName).MakeAbsolute().ToString(); wParams.referenceMap.AddMappings(wParams.writeCommand.internalName, wParams.writeCommand.serializeObjects.ToArray(), true); var writeResults = ContentBuildInterface.WriteSerializedFile(tempPath.Combine("Resources").ToString(), wParams); EditorUtility.ClearProgressBar(); //if (writeResults.serializedObjects.Count == 0) return "FAIL"; } { var parameters = new BundleBuildParameters(mParams.settings.target, mParams.settings.group, TempStreamingAssetsPath.ToString()); parameters.BundleCompression = UnityEngine.BuildCompression.Uncompressed; parameters.ScriptInfo = mParams.settings.typeDB; // Writing scenes.bundle { WriteSceneBundles(parameters, scenes); //if (???) return "FAIL"; } // Writing resources.bundle { WriteResourcesBundles(parameters); //if (???) return "FAIL"; } { WriteRenderPipelineBundles(parameters); //if (???) return "FAIL"; } } return(tempPath); }
// This function is responsible for providing all the subscenes to the build. // // The way these files get generated is that we have a SceneWithBuildConfiguration file, (which is a bit of a hack to work around the inability for scriptable importers to take arguments, so // instead we create a different file that points to the scene we want to import, and points to the buildconfiguration we want to import it for). The SubsceneImporter will import this file, // and it will make 3 (relevant) kind of files: // - headerfile // - entitybinaryformat file (the actual entities payloads) // - a SerializedFile that has an array of UnityEngine.Object PPtrs that are used by this entity file. // // The first two we deal with very simply: they just need to be copied into the build, and we're done. // the third one, we will feed as input to the Scriptable build pipeline (which is actually about creating assetbundles), and create an assetbundle that // has all those objects in it that the 3rd file referred to. We do this with a batch api, first we loop through all subscenes, and register with this batch // api which assetbundles we'd like to see produced, and then at the end, we say "okay make them please". this assetbundle creation api has a caching system // that is separate from the assetpipeline caching system, so if all goes well, the call to produce these assetbundles will return very fast and did nothing. // // The reason for the strange looking api, where a two callbacks get passed in is to make integration of the new incremental buildpipeline easier, as this code // needs to be compatible both with the current buildpipeline in the dots-repo, as well as with the incremental buildpipeline. When that is merged, we can simplify this. public static void PrepareAdditionalFiles(string buildConfigurationGuid, string[] scenePathsForBuild, BuildTarget target, Action <string, string> RegisterFileCopy, string outputStreamingAssetsDirectory, string buildWorkingDirectory) { if (target == BuildTarget.NoTarget) { throw new InvalidOperationException($"Invalid build target '{target.ToString()}'."); } if (target != EditorUserBuildSettings.activeBuildTarget) { throw new InvalidOperationException($"ActiveBuildTarget must be switched before the {nameof(SubSceneBuildCode)} runs."); } var content = new BundleBuildContent(new AssetBundleBuild[0]); var bundleNames = new HashSet <string>(); var subSceneGuids = scenePathsForBuild.SelectMany(scenePath => SceneMetaDataImporter.GetSubSceneGuids(AssetDatabase.AssetPathToGUID(scenePath))).Distinct().ToList(); var subScenePaths = new Dictionary <Hash128, string>(); var dependencyInputData = new Dictionary <SceneSection, SectionDependencyInfo>(); var refExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesUnityObjectReferences); var headerExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesHeader); var binaryExt = EntityScenesPaths.GetExtension(EntityScenesPaths.PathType.EntitiesBinary); var group = BuildPipeline.GetBuildTargetGroup(target); var parameters = new BundleBuildParameters(target, @group, buildWorkingDirectory) { BundleCompression = BuildCompression.LZ4Runtime }; var requiresRefresh = false; var sceneBuildConfigGuids = new NativeArray <GUID>(subSceneGuids.Count, Allocator.TempJob); for (int i = 0; i != sceneBuildConfigGuids.Length; i++) { sceneBuildConfigGuids[i] = SceneWithBuildConfigurationGUIDs.EnsureExistsFor(subSceneGuids[i], new Hash128(buildConfigurationGuid), out var thisRequiresRefresh); requiresRefresh |= thisRequiresRefresh; } if (requiresRefresh) { AssetDatabase.Refresh(); } var artifactHashes = new NativeArray <UnityEngine.Hash128>(subSceneGuids.Count, Allocator.TempJob); AssetDatabaseCompatibility.ProduceArtifactsRefreshIfNecessary(sceneBuildConfigGuids, typeof(SubSceneImporter), artifactHashes); for (int i = 0; i != sceneBuildConfigGuids.Length; i++) { var sceneGuid = subSceneGuids[i]; var sceneBuildConfigGuid = sceneBuildConfigGuids[i]; var artifactHash = artifactHashes[i]; bool foundEntityHeader = false; AssetDatabaseCompatibility.GetArtifactPaths(artifactHash, out var artifactPaths); foreach (var artifactPath in artifactPaths) { //@TODO: This looks like a workaround. Whats going on here? var ext = Path.GetExtension(artifactPath).Replace(".", ""); if (ext == headerExt) { foundEntityHeader = true; if (!string.IsNullOrEmpty(artifactPaths.FirstOrDefault(a => a.EndsWith(refExt)))) { subScenePaths[sceneGuid] = artifactPath; } else { //if there are no reference bundles, then deduplication can be skipped var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesHeader, -1); DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile); } } else if (ext == binaryExt) { var destinationFile = EntityScenesPaths.RelativePathFolderFor(sceneGuid, EntityScenesPaths.PathType.EntitiesBinary, EntityScenesPaths.GetSectionIndexFromPath(artifactPath)); DoCopy(RegisterFileCopy, outputStreamingAssetsDirectory, artifactPath, destinationFile); } if (ext == refExt) { content.CustomAssets.Add(new CustomContent { Asset = sceneBuildConfigGuid, Processor = (guid, processor) => { var sectionIndex = EntityScenesPaths.GetSectionIndexFromPath(artifactPath); processor.GetObjectIdentifiersAndTypesForSerializedFile(artifactPath, out ObjectIdentifier[] objectIds, out Type[] types);
internal void BuildGroup(ABGroup group) { if (Settings == null) { throw new FileNotFoundException("Setttings not found", "ABSettings.asset"); } if (group == null) { throw new NullReferenceException("SimpleGroupAssetBundles is null"); } string buildPath = string.Empty; string localLoadPath = string.Empty; string remoteLoadPath = string.Empty; BuildTarget buildTarget = BuildTarget.StandaloneWindows; BuildTargetGroup buildTargetGroup = BuildTargetGroup.Standalone; if (group.IsCustomSettings) { buildPath = group.BuildPath; localLoadPath = group.LocalLoadPath; remoteLoadPath = group.RemoteLoadPath; buildTarget = group.BuildTarget; buildTargetGroup = group.BuildTargetGroup; } else { buildPath = $"{Settings.BuildPath}/{group.BuildPath}"; localLoadPath = $"{Settings.LocalLoadPath}/{group.LocalLoadPath}"; remoteLoadPath = $"{Settings.RemoteLoadPath}/{group.RemoteLoadPath}"; buildTarget = Settings.BuildTarget; buildTargetGroup = Settings.BuildTargetGroup; } if (buildPath.IndexOfAny(Path.GetInvalidPathChars()) != -1) { throw new DirectoryNotFoundException("BuildPath invalid chars"); } if (localLoadPath.IndexOfAny(Path.GetInvalidPathChars()) != -1) { throw new DirectoryNotFoundException("LocalLoadPath invalid chars"); } if (remoteLoadPath.IndexOfAny(Path.GetInvalidPathChars()) != -1) { throw new DirectoryNotFoundException("LocalLoadPath invalid chars"); } if (group.BundleBuilds == null || group.BundleBuilds.Count() <= 0) { Debug.LogWarning($"Бандлы для билда группы {group.Name} являются null или их нет. Билд этой группы не будет производиться"); return; } if (!Directory.Exists(buildPath)) { try { Directory.CreateDirectory(buildPath); } catch (IOException ex) { throw ex; throw new IOException("Путь билда указывает на файл"); } catch (NotSupportedException ex) { throw ex; throw new NotSupportedException("Путь билда содержит двоеточие (:), которое не является частью метки"); } } _currentManifest = new ABManifest(); _currentManifest.Name = group.Name; _currentManifest.Version = group.Version; _currentManifest.LocalLoadPath = localLoadPath; _currentManifest.RemoteLoadPath = remoteLoadPath; foreach (var item in group.BundleBuilds) { _currentManifest.Bundles.Add(new BundleInfo { Name = item.assetBundleName }); } var parameters = new BundleBuildParameters(buildTarget, buildTargetGroup, buildPath); parameters.BundleCompression = group.Compression; var buildContent = new BundleBuildContent(group.BundleBuilds); foreach (var item in buildContent.Assets) { _currentManifest.Assets.Add(new AssetInfo() { Name = buildContent.Addresses[item], Path = AssetDatabase.GUIDToAssetPath(item.ToString()) }); } foreach (var item in buildContent.Scenes) { _currentManifest.Scenes.Add(new AssetInfo() { Name = buildContent.Addresses[item], Path = AssetDatabase.GUIDToAssetPath(item.ToString()) }); } IBundleBuildResults results; var returnCode = ContentPipeline.BuildAssetBundles(parameters, buildContent, out results, new[] { new ArchiveAndCompressBundles() }); if (returnCode == ReturnCode.Success) { string jsonContent = JsonUtility.ToJson(_currentManifest); using (var sw = File.CreateText(Path.Combine(buildPath, $"manifest-{group.Name}.json"))) { sw.Write(jsonContent); } } }
public static void BuildAll() { Clear(); var Mods = ModsEditor.GetMods(); int length = Mods.Length; for (int i = 0; i < length; i++) { var ModInfo = ModsEditor.GetModInfo(Mods[i]); var ModOutPutFolder = OutPutFolder + "/" + ModInfo.PackageName; //Windows64版本构建 //构建参数 var param = new BundleBuildParameters(BuildTarget.StandaloneWindows64, BuildTargetGroup.Standalone, ModOutPutFolder); param.BundleCompression = BuildCompression.LZ4; //填入资源 var content = new BundleBuildContent(new AssetBundleBuild[] { GetAllAssets(ModInfo, "winmod") }); IBundleBuildResults results; //构建包 ReturnCode code = ContentPipeline.BuildAssetBundles(param, content, out results); if (code != ReturnCode.Success) { if (code == ReturnCode.Canceled) { return;//如果取消,直接返回 } Debug.LogError("构建失败!错误原因:" + code.ToString()); } //OSX版本构建 //构建参数 param.Target = BuildTarget.StandaloneOSX; //填入资源 content = new BundleBuildContent(new AssetBundleBuild[] { GetAllAssets(ModInfo, "osxmod") }); results = null; //构建包 code = ContentPipeline.BuildAssetBundles(param, content, out results); if (code != ReturnCode.Success) { if (code == ReturnCode.Canceled) { return;//如果取消,直接返回 } Debug.LogError("构建失败!错误原因:" + code.ToString()); } //Linux版本构建 //构建参数 param.Target = BuildTarget.StandaloneLinux64; //填入资源 content = new BundleBuildContent(new AssetBundleBuild[] { GetAllAssets(ModInfo, "linuxmod") }); results = null; //构建包 code = ContentPipeline.BuildAssetBundles(param, content, out results); if (code != ReturnCode.Success) { if (code == ReturnCode.Canceled) { return;//如果取消,直接返回 } Debug.LogError("构建失败!错误原因:" + code.ToString()); } //Android版本构建 //构建参数 param.Target = BuildTarget.Android; param.Group = BuildTargetGroup.Android; //填入资源 content = new BundleBuildContent(new AssetBundleBuild[] { GetAllAssets(ModInfo, "androidmod") }); results = null; //构建包 code = ContentPipeline.BuildAssetBundles(param, content, out results); if (code != ReturnCode.Success) { if (code == ReturnCode.Canceled) { return;//如果取消,直接返回 } Debug.LogError("构建失败!错误原因:" + code.ToString()); } //ios版本构建 //构建参数 param.Target = BuildTarget.iOS; param.Group = BuildTargetGroup.iOS; //填入资源 content = new BundleBuildContent(new AssetBundleBuild[] { GetAllAssets(ModInfo, "iosmod") }); results = null; //构建包 code = ContentPipeline.BuildAssetBundles(param, content, out results); if (code != ReturnCode.Success) { if (code == ReturnCode.Canceled) { return;//如果取消,直接返回 } Debug.LogError("构建失败!错误原因:" + code.ToString()); } //生成ModInfo文件 ModInfo = ModsEditor.GetModInfo(Mods[i]);//由于构建后资源会被释放,这里需要重载 using (FileStream fs = File.Create(ModOutPutFolder + "/" + ModInfo.PackageName + ".json")) { StreamWriter sw = new StreamWriter(fs); sw.Write(JsonConvert.SerializeObject(ModInfo)); sw.Dispose(); } } }