private static FileEntry EncryptData(PackageBuildInfo buildInfo, string name, byte[] bytes) { var encFilePath = Path.Combine(buildInfo.packagePath, name); var password = buildInfo.data.encryptionKey + name; var key = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(password)); var iv = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(password + Manifest.EncryptionSalt)); buildInfo.filelist.Add(name); if (File.Exists(encFilePath)) { File.Delete(encFilePath); } using (var fout = File.Open(encFilePath, FileMode.Create, FileAccess.Write, FileShare.Write)) { using (var algo = Rijndael.Create()) { algo.Padding = PaddingMode.Zeros; var cryptor = algo.CreateEncryptor(key, iv); Utils.ChunkedStream.Encrypt(cryptor, buildInfo.data.chunkSize, bytes, fout); } } var fileEntry = GenFileEntry(name, encFilePath); fileEntry.rsize = bytes.Length; return(fileEntry); }
// write manifest & checksum of manifest private static void WriteManifest(PackageBuildInfo buildInfo, Manifest manifest) { var json = JsonUtility.ToJson(manifest); var bytes = Encoding.UTF8.GetBytes(json); var manifestRawPath = Path.Combine(buildInfo.packagePath, Manifest.ManifestFileName + ".json"); var manifestChecksumPath = Path.Combine(buildInfo.packagePath, Manifest.ChecksumFileName); byte[] zData; using (var zStream = new MemoryStream()) { using (var outputStream = new GZipOutputStream(zStream)) { outputStream.SetLevel(Deflater.BEST_COMPRESSION); outputStream.Write(bytes, 0, bytes.Length); outputStream.Flush(); } zStream.Flush(); zData = zStream.ToArray(); } buildInfo.filelist.Add(Manifest.ManifestFileName); buildInfo.filelist.Add(Manifest.ManifestFileName + ".json"); var fileEntry = AsManifestEntry(EncryptData(buildInfo, Manifest.ManifestFileName, zData), buildInfo.data.chunkSize); var fileEntryJson = JsonUtility.ToJson(fileEntry); Debug.LogFormat("write manifest: {0}", fileEntryJson); File.WriteAllBytes(manifestRawPath, bytes); File.WriteAllText(manifestChecksumPath, fileEntryJson); }
//TODO: zip 打包拆包 public static ZipArchiveManifest BuildZipArchives(PackageBuildInfo buildInfo, List <ZipArchiveBuild> builds) { var manifest = new ZipArchiveManifest(); foreach (var build in builds) { var entry = new ZipArchiveManifestEntry() { name = build.name, }; manifest.archives.Add(entry); var zipArchiveFileName = Path.Combine(buildInfo.zipArchivePath, entry.name); if (File.Exists(zipArchiveFileName)) { File.Delete(zipArchiveFileName); } using (var zip = new ZipOutputStream(File.Open(zipArchiveFileName, FileMode.Create, FileAccess.Write, FileShare.Write))) { zip.IsStreamOwner = true; foreach (var assetPath in build.assetPaths) { BuildZipArchiveObject(zip, assetPath, entry); } } } return(manifest); }
private static FileEntry EncryptFile(BundleBuilderData data, PackageBuildInfo buildInfo, string sourcePath, string name) { var rawFilePath = Path.Combine(sourcePath, name); var bytes = File.ReadAllBytes(rawFilePath); return(EncryptData(buildInfo, name, bytes)); }
// write embedded manifest to streamingassets private static void WriteEmbeddedManifest(PackageBuildInfo buildInfo, EmbeddedManifest embeddedManifest) { if (embeddedManifest.bundles.Count > 0) { var json = JsonUtility.ToJson(embeddedManifest); var manifestPath = Path.Combine(buildInfo.packagePath, Manifest.EmbeddedManifestFileName); File.WriteAllText(manifestPath, json); buildInfo.filelist.Add(Manifest.EmbeddedManifestFileName); } }
public static List <ZipArchiveBuild> GenerateZipArchiveBuilds(PackageBuildInfo buildInfo) { var data = buildInfo.data; var builds = new List <ZipArchiveBuild>(); foreach (var bundle in data.bundles) { if (bundle.type != Manifest.BundleType.ZipArchive) { continue; } for (var splitIndex = 0; splitIndex < bundle.splits.Count; splitIndex++) { var bundleSplit = bundle.splits[splitIndex]; for (var sliceIndex = 0; sliceIndex < bundleSplit.slices.Count; sliceIndex++) { var bundleSlice = bundleSplit.slices[sliceIndex]; if (bundleSlice.IsBuild(buildInfo.buildPlatform)) { var assetNames = new List <string>(); for (int assetIndex = 0, assetCount = bundleSlice.GetAssetCount(); assetIndex < assetCount; assetIndex++) { var assetGuid = bundleSlice.GetAssetGuid(assetIndex); if (data.IsPackAsset(assetGuid)) { var assetPath = AssetDatabase.GUIDToAssetPath(assetGuid); assetNames.Add(assetPath); } } if (assetNames.Count != 0) { var build = new ZipArchiveBuild(); build.name = bundleSlice.name; build.assetPaths = assetNames; builds.Add(build); // Debug.Log($"{build.assetBundleName}: {build.assetNames.Length}"); } else { Debug.Log($"skip empty bundle slice {bundleSlice.name}"); } } } } } return(builds); }
public static FileListManifest BuildFileLists(PackageBuildInfo buildInfo, BundleBuilderData.BundleInfo[] builds) { var build = new FileListManifest(); foreach (var bundle in builds) { var entry = new FileListManifestEntry() { name = bundle.name, }; build.fileLists.Add(entry); var filename = Path.Combine(buildInfo.packagePath, bundle.name); var manifest = new UnityFS.FileListManifest(); foreach (var bundleSplit in bundle.splits) { foreach (var bundleSlice in bundleSplit.slices) { if (bundleSlice.IsBuild(buildInfo.buildPlatform)) { var assetCount = bundleSlice.GetAssetCount(); for (var assetIndex = 0; assetIndex < assetCount; assetIndex++) { var assetGuid = bundleSlice.GetAssetGuid(assetIndex); var assetPath = AssetDatabase.GUIDToAssetPath(assetGuid); var fileEntry = GenFileEntry(assetPath, assetPath); manifest.files.Add(fileEntry); if (CopyRawFile(buildInfo.packagePath, assetPath)) { var fileListManifestFileInfo = new FileListManifestFileInfo() { assetPath = assetPath, streamingAssets = bundleSlice.streamingAssets }; build.fileEntrys.Add(fileListManifestFileInfo); } // FileUtil.CopyFileOrDirectory(assetPath, outPath); // Debug.LogFormat("gen {0} from {1}", outFilePath, assetPath); } } } } var jsonString = JsonUtility.ToJson(manifest); File.WriteAllText(filename, jsonString); } return(build); }
public static RawFileManifest BuildRawFiles(PackageBuildInfo buildInfo, RawFileBuild[] builds) { var manifest = new RawFileManifest(); // foreach (var build in builds) // { // var entry = new RawFileManifestEntry() // { // name = build.name, // }; // manifest.xxx.Add(entry); // // } return(manifest); }
public static AssetBundleBuild[] GenerateAssetBundleBuilds(PackageBuildInfo buildInfo) { var data = buildInfo.data; var builds = new List <AssetBundleBuild>(); foreach (var bundle in data.bundles) { if (bundle.type != Manifest.BundleType.AssetBundle) { continue; } for (var splitIndex = 0; splitIndex < bundle.splits.Count; splitIndex++) { var bundleSplit = bundle.splits[splitIndex]; for (var sliceIndex = 0; sliceIndex < bundleSplit.slices.Count; sliceIndex++) { var bundleSlice = bundleSplit.slices[sliceIndex]; if (bundleSlice.IsBuild(buildInfo.buildPlatform)) { var assetNames = new List <string>(); for (var assetIndex = 0; assetIndex < bundleSlice.assetGuids.Count; assetIndex++) { var assetGuid = bundleSlice.assetGuids[assetIndex]; if (data.IsPackAsset(assetGuid)) { var assetPath = AssetDatabase.GUIDToAssetPath(assetGuid); assetNames.Add(assetPath); } } if (assetNames.Count != 0) { var names = assetNames.ToArray(); var build = new AssetBundleBuild(); build.assetBundleName = bundleSlice.name; build.assetNames = names; build.addressableNames = names; builds.Add(build); // Debug.Log($"{build.assetBundleName}: {build.assetNames.Length}"); } } } } } return(builds.ToArray()); }
private static void Cleanup(PackageBuildInfo buildInfo, AssetBundleManifest assetBundleManifest, ZipArchiveManifest zipArchiveManifest, FileListManifest fileListManifest, RawFileManifest rawFileManifest, EmbeddedManifest embeddedManifest) { foreach (var dir in Directory.GetDirectories(buildInfo.packagePath)) { CleanupRecursively(dir, "Assets", fileListManifest, false); } foreach (var file in Directory.GetFiles(buildInfo.packagePath)) { var match = false; var fi = new FileInfo(file); var filename = fi.Name; if (builtinFiles.Contains(filename)) { match = true; } if (!match && buildInfo.filelist.Contains(filename)) { match = true; } if (!match && filename == Manifest.EmbeddedManifestFileName && embeddedManifest.bundles.Count > 0) { match = true; } if (!match) { Debug.LogWarning("delete unused file: " + filename); try { fi.Delete(); } catch (Exception exception) { Debug.LogError(exception); } } } }
// 生成打包 private static void _BuildPackages(PackageBuildInfo packageBuildInfo) { Debug.Log($"building bundles..."); Scan(packageBuildInfo.data); var assetBundleBuilds = GenerateAssetBundleBuilds(packageBuildInfo); var zipArchiveBuilds = GenerateZipArchiveBuilds(packageBuildInfo); var fileListBuilds = GenerateFileListBuilds(packageBuildInfo); var rawFileBuilds = GenerateRawFileBuilds(packageBuildInfo); AssetBundleManifest assetBundleManifest = null; ZipArchiveManifest zipArchiveManifest = null; FileListManifest fileListManifest = null; RawFileManifest rawFileManifest = null; if (assetBundleBuilds.Length != 0) { assetBundleManifest = BuildAssetBundles(packageBuildInfo, assetBundleBuilds); } if (zipArchiveBuilds.Count != 0) { zipArchiveManifest = BuildZipArchives(packageBuildInfo, zipArchiveBuilds); } if (fileListBuilds.Length != 0) { fileListManifest = BuildFileLists(packageBuildInfo, fileListBuilds); } if (rawFileBuilds.Length != 0) { rawFileManifest = BuildRawFiles(packageBuildInfo, rawFileBuilds); } var embeddedManifest = BuildFinalPackages(packageBuildInfo, assetBundleManifest, zipArchiveManifest, fileListManifest, rawFileManifest); Cleanup(packageBuildInfo, assetBundleManifest, zipArchiveManifest, fileListManifest, rawFileManifest, embeddedManifest); packageBuildInfo.DoAnalyze(); packageBuildInfo.data.build++; packageBuildInfo.data.MarkAsDirty(); Debug.Log( $"{packageBuildInfo.packagePath}: build bundles finished. {assetBundleBuilds.Length} assetbundles. {zipArchiveBuilds.Count} zip archives. {fileListBuilds.Length} file lists. {embeddedManifest.bundles.Count} bundles to streamingassets."); }
public static AssetBundleManifest BuildAssetBundles(PackageBuildInfo buildInfo, AssetBundleBuild[] assetBundleBuilds) { var options = BuildAssetBundleOptions.None; if (buildInfo.data.disableTypeTree) { options |= BuildAssetBundleOptions.DisableWriteTypeTree; } if (buildInfo.data.lz4Compression) { options |= BuildAssetBundleOptions.ChunkBasedCompression; } return(BuildPipeline.BuildAssetBundles(buildInfo.assetBundlePath, assetBundleBuilds, options, buildInfo.buildTarget)); }
public static BundleBuilderData.BundleInfo[] GenerateFileListBuilds(PackageBuildInfo buildInfo) { var data = buildInfo.data; var list = new List <BundleBuilderData.BundleInfo>(); foreach (var bundle in data.bundles) { if (bundle.type != Manifest.BundleType.FileList) { continue; } list.Add(bundle); } return(list.ToArray()); }
public static RawFileBuild[] GenerateRawFileBuilds(PackageBuildInfo buildInfo) { var data = buildInfo.data; var list = new List <RawFileBuild>(); foreach (var bundle in data.bundles) { if (bundle.type != Manifest.BundleType.RawFile) { continue; } for (var splitIndex = 0; splitIndex < bundle.splits.Count; splitIndex++) { var bundleSplit = bundle.splits[splitIndex]; for (var sliceIndex = 0; sliceIndex < bundleSplit.slices.Count; sliceIndex++) { var bundleSlice = bundleSplit.slices[sliceIndex]; if (bundleSlice.IsBuild(buildInfo.buildPlatform)) { var assetNames = new List <string>(); for (int assetIndex = 0, assetCount = bundleSlice.GetAssetCount(); assetIndex < assetCount; assetIndex++) { var assetPath = bundleSlice.GetAssetPath(assetIndex); if (data.IsPackAsset(assetPath)) { assetNames.Add(assetPath); } } if (assetNames.Count != 0) { var names = assetNames.ToArray(); var build = new RawFileBuild(); build.name = bundleSlice.name; build.assetNames = names; list.Add(build); // Debug.Log($"{build.assetBundleName}: {build.assetNames.Length}"); } } } } } return(list.ToArray()); }
public static FileEntry EncryptFileEntry(BundleBuilderData data, PackageBuildInfo buildInfo, bool encrypted, string name, string sourcePath) { if (encrypted) { return(EncryptFile(data, buildInfo, sourcePath, name)); } var targetFilePath = Path.Combine(buildInfo.packagePath, name); if (sourcePath != buildInfo.packagePath) { var rawFilePath = Path.Combine(sourcePath, name); File.Copy(rawFilePath, targetFilePath, true); } buildInfo.filelist.Add(name); return(GenFileEntry(name, targetFilePath)); }
// 计算指定 slice 中最高的资源优先级作为包优先级 (最低不低于 bundleInfo定义的优先级) private static int GetPriority(PackageBuildInfo buildInfo, BundleBuilderData.BundleInfo bundleInfo, BundleBuilderData.BundleSlice bundleSlice) { var priority = bundleInfo.priority; for (int i = 0, size = bundleSlice.assetGuids.Count; i < size; i++) { var guid = bundleSlice.assetGuids[i]; var attrs = buildInfo.data.GetAssetAttributes(guid); if (attrs != null) { if (attrs.priority > priority) { priority = attrs.priority; } } } return(priority); }
// 计算指定 slice 中最高的资源优先级作为包优先级 (最低不低于 bundleInfo定义的优先级) private static int GetPriority(PackageBuildInfo buildInfo, BundleBuilderData.BundleInfo bundleInfo, BundleBuilderData.BundleSlice bundleSlice) { var priority = bundleInfo.priority; for (int assetIndex = 0, assetCount = bundleSlice.GetAssetCount(); assetIndex < assetCount; assetIndex++) { var assetPath = bundleSlice.GetAssetPath(assetIndex); var attrs = buildInfo.data.GetAssetPathAttributes(assetPath); if (attrs != null) { if (attrs.priority > priority) { priority = attrs.priority; } } } return(priority); }
// 生成最终包文件, 生成最终清单 public static EmbeddedManifest BuildFinalPackages(PackageBuildInfo buildInfo, AssetBundleManifest assetBundleManifest, ZipArchiveManifest zipArchiveManifest, FileListManifest fileListManifest, RawFileManifest rawFileManifest) { var data = buildInfo.data; var manifest = new Manifest(); manifest.chunkSize = data.chunkSize; manifest.build = buildInfo.data.build; manifest.timestamp = (int)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds; manifest.tag = buildInfo.sharedBuildInfo.tag; var embeddedManifest = new EmbeddedManifest(); if (assetBundleManifest != null) { var assetBundles = assetBundleManifest.GetAllAssetBundles(); foreach (var assetBundle in assetBundles) { BundleBuilderData.BundleInfo bundleInfo; BundleBuilderData.BundleSplit bundleSplit; BundleBuilderData.BundleSlice bundleSlice; if (TryGetBundleSlice(data, assetBundle, out bundleInfo, out bundleSplit, out bundleSlice)) { // Debug.Log(bundleInfo.name); var fileEntry = EncryptFileEntry(data, buildInfo, bundleSplit.encrypted, bundleSlice.name, buildInfo.assetBundlePath); var bundle = new Manifest.BundleInfo(); bundle.comment = bundleInfo.note; bundle.tag = bundleInfo.tag; bundle.encrypted = bundleSplit.encrypted; bundle.rsize = fileEntry.rsize; bundle.type = Manifest.BundleType.AssetBundle; bundle.name = fileEntry.name; bundle.checksum = fileEntry.checksum; bundle.size = fileEntry.size; bundle.load = bundleInfo.load; bundle.priority = GetPriority(buildInfo, bundleInfo, bundleSlice); if (bundleSlice.lastBuildSize != fileEntry.size) { bundleSlice.lastBuildSize = fileEntry.size; data.MarkAsDirty(); } for (int assetIndex = 0, assetCount = bundleSlice.GetAssetCount(); assetIndex < assetCount; assetIndex++) { var assetPath = bundleSlice.GetAssetPath(assetIndex); bundle.assets.Add(assetPath); } bundle.dependencies = assetBundleManifest.GetAllDependencies(assetBundle); buildInfo.CreateEntry(bundle); manifest.bundles.Add(bundle); if (bundleSlice.streamingAssets || data.streamingAssetsAnyway) { embeddedManifest.bundles.Add(fileEntry); } } } } if (zipArchiveManifest != null) { foreach (var zipArchive in zipArchiveManifest.archives) { BundleBuilderData.BundleInfo bundleInfo; BundleBuilderData.BundleSplit bundleSplit; BundleBuilderData.BundleSlice bundleSlice; if (TryGetBundleSlice(data, zipArchive.name, out bundleInfo, out bundleSplit, out bundleSlice)) { var fileEntry = EncryptFileEntry(data, buildInfo, bundleSplit.encrypted, zipArchive.name, buildInfo.zipArchivePath); var bundle = new Manifest.BundleInfo(); bundle.comment = bundleInfo.note; bundle.tag = bundleInfo.tag; bundle.encrypted = bundleSplit.encrypted; bundle.rsize = fileEntry.rsize; bundle.type = Manifest.BundleType.ZipArchive; bundle.name = fileEntry.name; bundle.checksum = fileEntry.checksum; bundle.size = fileEntry.size; bundle.load = bundleInfo.load; bundle.priority = GetPriority(buildInfo, bundleInfo, bundleSlice); foreach (var assetPath in zipArchive.assets) { bundle.assets.Add(assetPath); } manifest.bundles.Add(bundle); if (bundleSlice.streamingAssets || data.streamingAssetsAnyway) { embeddedManifest.bundles.Add(fileEntry); } } } } if (fileListManifest != null) { foreach (var fileList in fileListManifest.fileLists) { var bundleInfo = GetBundleInfo(data, fileList.name); var fileListPath = Path.Combine(buildInfo.packagePath, fileList.name); var fileEntry = GenFileEntry(fileList.name, fileListPath); var bundle = new Manifest.BundleInfo(); bundle.comment = bundleInfo.note; bundle.tag = bundleInfo.tag; bundle.type = Manifest.BundleType.FileList; bundle.name = fileList.name; bundle.checksum = fileEntry.checksum; bundle.size = fileEntry.size; bundle.load = bundleInfo.load; bundle.priority = bundleInfo.priority; buildInfo.filelist.Add(fileList.name); foreach (var bundleTargets in bundleInfo.targets) { var targetPath = bundleTargets.targetPath; bundle.assets.Add(targetPath); } manifest.bundles.Add(bundle); if (bundleInfo.streamingAssets || data.streamingAssetsAnyway) { embeddedManifest.bundles.Add(fileEntry); } } } WriteManifest(buildInfo, manifest); WriteEmbeddedManifest(buildInfo, embeddedManifest); if (buildInfo.buildTarget == EditorUserBuildSettings.activeBuildTarget) { BuildStreamingAssets(buildInfo, fileListManifest); } return(embeddedManifest); }
// 将首包资源复制到 StreamingAssets 目录 (在 BuildPlayer 之前调用) public static void BuildStreamingAssets(PackageBuildInfo buildInfo, FileListManifest fileListManifest) { var packagePath = buildInfo.packagePath; var embeddedManifest = ReadEmbeddedManifest(packagePath); if (embeddedManifest != null && embeddedManifest.bundles.Count > 0) { File.Copy(Path.Combine(packagePath, Manifest.EmbeddedManifestFileName), Path.Combine(buildInfo.streamingAssetsPath, Manifest.EmbeddedManifestFileName), true); if (buildInfo.data.streamingAssetsManifest) { File.Copy(Path.Combine(packagePath, Manifest.ManifestFileName), Path.Combine(buildInfo.streamingAssetsPath, Manifest.ManifestFileName), true); File.Copy(Path.Combine(packagePath, Manifest.ChecksumFileName), Path.Combine(buildInfo.streamingAssetsPath, Manifest.ChecksumFileName), true); } foreach (var bundleInfo in embeddedManifest.bundles) { // Debug.LogFormat("copy {0}", bundleInfo.name); File.Copy(Path.Combine(packagePath, bundleInfo.name), Path.Combine(buildInfo.streamingAssetsPath, bundleInfo.name), true); } if (fileListManifest != null) { foreach (var entry in fileListManifest.fileEntrys) { if (entry.streamingAssets && CopyRawFile(buildInfo.streamingAssetsPath, entry.assetPath)) { Debug.LogWarningFormat("copy xxx {0}", entry.assetPath); } } } AssetDatabase.Refresh(); // cleanup foreach (var dir in Directory.GetDirectories(buildInfo.streamingAssetsPath)) { CleanupRecursively(dir, "Assets", fileListManifest, true); } foreach (var file in Directory.GetFiles(buildInfo.streamingAssetsPath)) { var fi = new FileInfo(file); var match = false; if (fi.Name == Manifest.EmbeddedManifestFileName || fi.Name == Manifest.EmbeddedManifestFileName + ".meta") { continue; } foreach (var bundleInfo in embeddedManifest.bundles) { if (fi.Name == bundleInfo.name || fi.Name == bundleInfo.name + ".meta") { match = true; break; } } if (!match) { if (buildInfo.data.streamingAssetsManifest) { if (!builtinFiles.Contains(fi.Name)) { fi.Delete(); } } else { fi.Delete(); } } } AssetDatabase.Refresh(); } else { PathUtils.CleanupDirectoryRecursively(buildInfo.streamingAssetsPath); } }