123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- using System.Collections.Generic;
- using UnityEngine;
- using XGame.Editor.Build.AssetBundles;
- using XGame.Framework.Json;
- using XFADefine = XGame.Framework.Asset.Define;
- namespace XGame.Editor.Build
- {
- public struct AbEncryptInfo
- {
- public long bundleId;
- public string originBundleName;
- public uint offset;
- }
- [BuildCommand((uint)BuildCommandPriority.ExportAssets)]
- class CmdExportAssets : BaseBuildCommand, ICommandExecuter
- {
- #region copy assets
- /// <summary>
- /// 异或加密使用的key值:1023
- /// </summary>
- const int encryptKey = 0x03FF;
- Dictionary<string, AbEncryptInfo> CollectAbEncryptInfos()
- {
- var abEncryptInfos = new Dictionary<string, AbEncryptInfo>();
- var abmanifest = AssetBundleBackupManifest.Load();
- if (abmanifest != null)
- {
- //manifest包的加密信息
- var encrypt = new AbEncryptInfo()
- {
- bundleId = long.Parse(XFADefine.MANIFEST_BUNDLE_NAME),
- originBundleName = XFADefine.MANIFEST_BUNDLE_NAME,
- offset = XFADefine.MANIFEST_BUNDLE_OFFSET
- };
- abEncryptInfos.Add(XFADefine.MANIFEST_BUNDLE_NAME, encrypt);
- var abInfos = abmanifest.bundleInfos;
- foreach (var abInfo in abInfos)
- {
- encrypt = new AbEncryptInfo()
- {
- bundleId = abInfo.bundleId,
- originBundleName = abInfo.nameOrGuid,
- offset = abInfo.offset
- };
- abEncryptInfos.Add(encrypt.bundleId.ToString(), encrypt);
- }
- }
- return abEncryptInfos;
- }
- private Dictionary<string, string> CollectBundleCrc()
- {
- var bundleCrcMap = new Dictionary<string, string>();
- var manifestPath = Asset.PathDefine.AssetBundleOutputPath + "/BundleCrcInfoManifest.manifest";
- if (System.IO.File.Exists(manifestPath))
- {
- var text = System.IO.File.ReadAllText(manifestPath);
- var manifest = XJson.ToObject<BundleCrcInfoManifest>(text);
- if (manifest.bundleInfos != null)
- {
- foreach (var info in manifest.bundleInfos)
- {
- bundleCrcMap.Add(info.bundleName, info.bundleCRC);
- }
- }
- }
- return bundleCrcMap;
- }
- byte[] ReadAllBytes(string assetPath, Dictionary<string, AbEncryptInfo> abEncryptInfos)
- {
- byte[] bytes = System.IO.File.ReadAllBytes(assetPath);
- if (assetPath.Contains(Asset.PathDefine.AssetBundleOutputPath))
- {
- var fileName = System.IO.Path.GetFileNameWithoutExtension(assetPath);
- if (!abEncryptInfos.TryGetValue(fileName, out var encryptInfo))
- return bytes;
- if (encryptInfo.offset <= 0) return bytes;
- var encryptData = System.Text.Encoding.UTF8.GetBytes(encryptInfo.originBundleName);
- for (var i = 0; i < encryptData.Length; i++) // 依次对字符串中各字符进行操作
- {
- var current = encryptData[i];
- encryptData[i] = (byte)(current ^ encryptKey); // 将密钥与字符异或
- }
- //var fileData = System.IO.File.ReadAllBytes(assetPath);
- var length = bytes.Length + encryptInfo.offset;
- var buffer = new byte[length];
- System.Array.Copy(encryptData, 0, buffer, 0, encryptInfo.offset);
- System.Array.Copy(bytes, 0, buffer, encryptInfo.offset, bytes.Length);
- return buffer;
- }
- return bytes;
- }
- void WriteAllBytes(string path, byte[] bytes)
- {
- var destDir = Asset.FileUtil.GetDirectoryName(path, true);
- if (!System.IO.Directory.Exists(destDir))
- System.IO.Directory.CreateDirectory(destDir);
- System.IO.File.WriteAllBytes(path, bytes);
- }
- void CopyAssets(string streamingAssetsPath, Dictionary<string, string> assetMap, Dictionary<string, AbEncryptInfo> abEncryptInfos)
- {
- foreach (var item in assetMap)
- {
- string assetPath = item.Key;
- if (!System.IO.File.Exists(assetPath))
- {
- BuildLog.Error($"Asset can not found:{assetPath}");
- return;
- }
- byte[] bytes = ReadAllBytes(assetPath, abEncryptInfos);
- string toPath = System.IO.Path.Combine(streamingAssetsPath, item.Value);
- WriteAllBytes(toPath, bytes);
- }
- }
- #endregion
- //#region split assets
- //void CollectionExpansionAssetInfos(ProductAssetsContext assetsContext, Dictionary<string, string> assetMap, out Dictionary<string, EditorAssetInfo> assetInfos, out CustomPackageInfo[] customPackageInfos)
- //{
- // assetInfos = new Dictionary<string, EditorAssetInfo>(assetMap.Count);
- // foreach (var item in assetMap)
- // {
- // EditorAssetInfo assetInfo = new EditorAssetInfo();
- // assetInfo.packageId = ManifestUtilities.MainAssetId;
- // assetInfo.path = item.Value;
- // assetInfos.Add(item.Key, assetInfo);
- // }
- // if (Context.config.ignoreSplitAssets)
- // {
- // customPackageInfos = null;
- // return;
- // }
- // CustomPackageControl customPackageControl = new CustomPackageControl(assetsContext);
- // customPackageControl.CollectPackages();
- // customPackageInfos = customPackageControl.GeneratePackages();
- // Dictionary<string, string> assetPkgMap = new Dictionary<string, string>();
- // if (null != customPackageInfos && customPackageInfos.Length > 0)
- // {
- // foreach (var pkgInfo in customPackageInfos)
- // {
- // var errors = customPackageControl.GetPackageErrors(pkgInfo.uid);
- // if (null != errors && errors.Length > 0)
- // {
- // foreach (var error in errors)
- // {
- // BuildLog.Warn("[GenExpancePackageManifest] discover error asset! uid: {0}, id: {1}, error code:{2}, is ext asset: {3} addressable: {4}\nerror asset path:{5}\nsource:{6}"
- // , pkgInfo.uid, pkgInfo.packageID, error.code, error.asset.isExtAsset, error.asset.addressable, error.asset.assetPath, error.asset.source);
- // }
- // }
- // foreach (var path in pkgInfo.assetPaths)
- // {
- // assetPkgMap.Add(path, pkgInfo.packageID);
- // }
- // }
- // }
- // foreach (var item in assetPkgMap)
- // {
- // if (!assetInfos.TryGetValue(item.Key, out var assetInfo))
- // {
- // BuildLog.Warn($"Expansion path not found in assets: {item.Key}");
- // continue;
- // }
- // assetInfo.packageId = item.Value;
- // }
- //}
- //void SplitAssets(string outputDir, string streamingAssetsPath, Dictionary<string, EditorAssetInfo> assetInfos)
- //{
- // foreach (var assetInfo in assetInfos.Values)
- // {
- // bool isMainAsset = assetInfo.packageId == ManifestUtilities.MainAssetId || string.IsNullOrEmpty(assetInfo.packageId);
- // string toPath = GetOutputPath(outputDir, assetInfo.path, isMainAsset, assetInfo.packageId);
- // var destDir = KAFileUtil.GetDirectoryName(toPath, true);
- // if (!System.IO.Directory.Exists(destDir)) System.IO.Directory.CreateDirectory(destDir);
- // string fromPath = System.IO.Path.Combine(streamingAssetsPath, assetInfo.path);
- // if (isMainAsset)
- // System.IO.File.Copy(fromPath, toPath);
- // else
- // System.IO.File.Move(fromPath, toPath);
- // }
- //}
- //#endregion
- //#region generate runtime-configs
- //ExpansionPackageManifest GenerateUniquePackageManifest(string outputDir, string streamingAssetsPath, CustomPackageInfo[] customPackageInfos, ref Dictionary<string, EditorAssetInfo> assetInfos)
- //{
- // if (null == customPackageInfos || customPackageInfos.Length <= 0) return null;
- // List<ExpansionPackageInfo> infos = new List<ExpansionPackageInfo>();
- // foreach (var item in customPackageInfos)
- // {
- // if (item.isShared) continue;
- // if ((null == item.assetPaths || item.assetPaths.Length <= 0) && (null == item.dependencies || item.dependencies.Length <= 0)) continue;
- // var info = new ExpansionPackageInfo()
- // {
- // downloadMode = item.downloadMode,
- // id = item.packageID,
- // priority = item.priority,
- // name = item.packageName,
- // updateMode = item.updateMode,
- // };
- // info.dependencies = new string[item.dependencies.Length];
- // item.dependencies.CopyTo(info.dependencies, 0);
- // infos.Add(info);
- // }
- // ExpansionPackageManifest manifest = new ExpansionPackageManifest();
- // manifest.packageInfos = infos.ToArray();
- // string outputPath = System.IO.Path.Combine(outputDir, "packages", "main", "assets");
- // ManifestUtilities.SaveUniquePackageManifest(outputPath, manifest);
- // string fromPath = System.IO.Path.Combine(outputPath, ManifestUtilities.AssetManifestRelativePath, "UniquePackages.manifest");
- // string toDir = System.IO.Path.Combine(streamingAssetsPath, ManifestUtilities.AssetManifestRelativePath);
- // if (!System.IO.Directory.Exists(toDir)) System.IO.Directory.CreateDirectory(toDir);
- // string toPath = System.IO.Path.Combine(toDir, "UniquePackages.manifest");
- // System.IO.File.Copy(fromPath, toPath);
- // EditorAssetInfo assetInfo = new EditorAssetInfo();
- // assetInfo.packageId = ManifestUtilities.MainAssetId;
- // assetInfo.path = System.IO.Path.Combine(ManifestUtilities.AssetManifestRelativePath, /*ManifestUtilities.UniquePackagesManifestFileName*/"UniquePackages.manifest").Replace('\\', '/');
- // assetInfos.Add(assetInfo.path, assetInfo);
- // Debug.Log($"GenerateUniquePackageManifest. assetInfo.path {assetInfo.path} , assetInfo {assetInfo.packageId}");
- // return manifest;
- //}
- //void GenerateAssetManifest(string outputDir, string streamingAssetsPath, ref Dictionary<string, EditorAssetInfo> assetInfos, CustomPackageInfo[] customPackageInfos)
- //{
- // List<AssetInfo> list = new List<AssetInfo>();
- // foreach (var assetInfo in assetInfos.Values)
- // {
- // bool isMainAsset = assetInfo.packageId == ManifestUtilities.MainAssetId || string.IsNullOrEmpty(assetInfo.packageId);
- // if (!isMainAsset) continue;
- // string path = GetOutputPath(outputDir, assetInfo.path, true, null);
- // AssetInfo info = new AssetInfo();
- // info.relativePath = assetInfo.path.Replace('\\', '/');
- // info.checkCodeType = ECheckCodeType.MD5;
- // info.size = new System.IO.FileInfo(path).Length;
- // info.checkCode = AssetUtilities.GetBinaryCheckCode(path, ECheckCodeType.MD5);
- // list.Add(info);
- // }
- // AssetManifest mainManifest = new AssetManifest();
- // mainManifest.assetInfos = list.ToArray();
- // string assetDir = System.IO.Path.Combine(outputDir, "packages", "main", "assets");
- // ManifestUtilities.SaveMainAssetManifest(assetDir, mainManifest);
- // string mainManifestFileName = $"{ManifestUtilities.MainAssetId}.{ManifestUtilities.ManifestExtensionName}";
- // string fromPath = System.IO.Path.Combine(assetDir, ManifestUtilities.AssetManifestRelativePath, mainManifestFileName);
- // string toDir = System.IO.Path.Combine(streamingAssetsPath, ManifestUtilities.AssetManifestRelativePath);
- // if (!System.IO.Directory.Exists(toDir)) System.IO.Directory.CreateDirectory(toDir);
- // string toPath = System.IO.Path.Combine(toDir, mainManifestFileName);
- // System.IO.File.Copy(fromPath, toPath);
- // EditorAssetInfo editorAssetInfo = new EditorAssetInfo();
- // editorAssetInfo.packageId = ManifestUtilities.MainAssetId;
- // editorAssetInfo.path = System.IO.Path.Combine(ManifestUtilities.AssetManifestRelativePath, mainManifestFileName);
- // assetInfos.Add(editorAssetInfo.path, editorAssetInfo);
- // if (null == customPackageInfos || customPackageInfos.Length <= 0) return;
- // foreach (var pkgInfo in customPackageInfos)
- // {
- // if ((null == pkgInfo.assetPaths || pkgInfo.assetPaths.Length <= 0) && (null == pkgInfo.dependencies || pkgInfo.dependencies.Length <= 0)) continue;
- // list.Clear();
- // foreach (var path in pkgInfo.assetPaths)
- // {
- // if (!assetInfos.TryGetValue(path, out var assetInfo))
- // {
- // BuildLog.Warn("Can't found asset: {0}, package: {1}", path, pkgInfo.packageID);
- // continue;
- // }
- // string outputPath = GetOutputPath(outputDir, assetInfo.path, false, pkgInfo.packageID);
- // AssetInfo info = new AssetInfo();
- // info.relativePath = assetInfo.path.Replace('\\', '/');
- // info.checkCodeType = ECheckCodeType.MD5;
- // info.size = new System.IO.FileInfo(outputPath).Length;
- // info.checkCode = AssetUtilities.GetBinaryCheckCode(outputPath, ECheckCodeType.MD5);
- // list.Add(info);
- // }
- // AssetManifest manifest = new AssetManifest();
- // manifest.assetInfos = list.ToArray();
- // assetDir = System.IO.Path.Combine(outputDir, "packages", pkgInfo.packageID, "assets");
- // ManifestUtilities.SaveExpansionAssetManifest(assetDir, pkgInfo.packageID, manifest);
- // editorAssetInfo = new EditorAssetInfo();
- // editorAssetInfo.packageId = pkgInfo.packageID;
- // editorAssetInfo.path = System.IO.Path.Combine(ManifestUtilities.AssetManifestRelativePath, $"{pkgInfo.packageID}.{ManifestUtilities.ManifestExtensionName}");
- // assetInfos.Add(editorAssetInfo.path, editorAssetInfo);
- // }
- //}
- //#endregion
- //#region generate backend-configs
- //void CollectPlacardAssets(HashSet<string> innerBundles, string dirPath, int platformTag, string streamAsstesDir, ref List<string> list)
- //{
- // var dirs = System.IO.Directory.GetDirectories(dirPath);
- // foreach (var dir in dirs)
- // {
- // var subPlatformTag = platformTag;
- // var entryPath = dir.Replace('\\', '/');
- // if (subPlatformTag != 1) subPlatformTag = KAFileUtil.VerifyPlatformPath(entryPath);
- // if (subPlatformTag == -1) continue;
- // CollectPlacardAssets(innerBundles, dir, platformTag, streamAsstesDir, ref list);
- // }
- // string[] files = System.IO.Directory.GetFiles(dirPath);
- // foreach (var file in files)
- // {
- // if (AssetUtilities.IsIgnorFile(file)) continue;
- // if (!(AssetUtilities.IsInnerAsset(file, AssetUtilities.PlacardTag) || innerBundles.Contains(file))) continue;
- // var entryPath = file.Replace('\\', '/');
- // string relativePath;
- // if (platformTag == 1)
- // {
- // //当前平台资源
- // var platformName = PlatformUtil.ActivePlatform.ToString();
- // relativePath = entryPath.Substring(entryPath.IndexOf(platformName) + platformName.Length + 1);
- // }
- // else
- // {
- // relativePath = entryPath.Substring(streamAsstesDir.Length + 1);
- // }
- // list.Add(relativePath);
- // }
- //}
- //void GeneratePlacardManifest(string backendConfigDir, ProductAssetsContext assetsContext)
- //{
- // var innerBundles = assetsContext.CollectPlacardBundles();
- // string streamAsstesDir = Kailash.Framework.Adapter.Driven.FileSystem.FileUtil.WorkPath.Replace('\\', '/');
- // List<string> placardAssets = new List<string>();
- // CollectPlacardAssets(innerBundles, streamAsstesDir, 0, streamAsstesDir, ref placardAssets);
- // List<PlacardInfo> placardInfos = new List<PlacardInfo>();
- // foreach (var item in placardAssets)
- // {
- // placardInfos.Add(new PlacardInfo() { filePath = item });
- // }
- // var manifest = new PlacardManifest();
- // manifest.placardInfos = placardInfos.ToArray();
- // string json = KailashJson.ToJson(manifest);
- // string path = System.IO.Path.Combine(backendConfigDir, "PlacardManifest.txt");
- // System.IO.File.WriteAllText(path, json);
- //}
- //void CalculateHotUpdateCheckCode(string outputDir, Dictionary<string, EditorAssetInfo> assetInfos)
- //{
- // var bundleCrcMap = CollectBundleCrc();
- // var regex = new Regex(@"CRC: (\d+)", RegexOptions.Multiline);
- // foreach (var item in assetInfos)
- // {
- // string ext = System.IO.Path.GetExtension(item.Key);
- // if (ext != ".bundle")
- // {
- // bool isMainAsset = item.Value.packageId == ManifestUtilities.MainAssetId || string.IsNullOrEmpty(item.Value.packageId);
- // string filePath = GetOutputPath(outputDir, item.Value.path, isMainAsset, item.Value.packageId);
- // item.Value.checkCode = KailashNative.GetMD5(filePath);
- // }
- // else
- // {
- // if (bundleCrcMap.TryGetValue(System.IO.Path.GetFileNameWithoutExtension(item.Key), out var bundleCrc))
- // {
- // item.Value.checkCode = bundleCrc;
- // }
- // else
- // {
- // string path = string.Format("{0}.manifest", item.Key);
- // if (System.IO.File.Exists(path))
- // {
- // string content = System.IO.File.ReadAllText(path);
- // var match = regex.Match(content);
- // item.Value.checkCode = match.Groups[1].Value;
- // }
- // else
- // {
- // BuildLog.Error($"CalculateHotUpdateCheckCode:找不到CRC配置信息。Path:{item.Key}");
- // }
- // }
- // }
- // }
- //}
- //#endregion
- string GetOutputPath(string outputDir, string relativePath, bool isMainAsset, string packageId)
- {
- return isMainAsset
- ? System.IO.Path.Combine(outputDir, "packages", "main", "assets", relativePath)
- : System.IO.Path.Combine(outputDir, "packages", packageId, "assets", relativePath);
- }
- BuildErrorCode ICommandExecuter.Execute()
- {
- var streamingAssetsPath = Application.streamingAssetsPath.Replace('\\', '/');
- if (System.IO.Directory.Exists(streamingAssetsPath))
- {
- UnityEditor.FileUtil.DeleteFileOrDirectory(streamingAssetsPath);
- UnityEditor.AssetDatabase.Refresh();
- }
- var pkgPath = System.IO.Path.Combine(Context.config.project.outputPath, "packages");
- if (System.IO.Directory.Exists(pkgPath))
- {
- UnityEditor.FileUtil.DeleteFileOrDirectory(pkgPath);
- }
- // 拷贝资源
- Dictionary<string, string> assetMap = AssetUtils.CollectionAllAssets();
- Dictionary<string, AbEncryptInfo> abEncryptInfos = CollectAbEncryptInfos();
- CopyAssets(streamingAssetsPath, assetMap, abEncryptInfos);
- //if (Context.config.editor.isNative)
- {
- //本地打包拷贝完资源即可退出
- UnityEditor.AssetDatabase.Refresh();
- return BuildErrorCode.CmdCompleted;
- }
- //var assetsContext = new ProductAssetsContext();
- //assetsContext.Init();
- //// 拆分分包资源
- //CollectionExpansionAssetInfos(assetsContext, assetMap, out Dictionary<string, EditorAssetInfo> assetInfos, out CustomPackageInfo[] customPackageInfos);
- //SplitAssets(Context.config.project.outputPath, streamingAssetsPath, assetInfos); // 移动或拷贝资源
- //// 生成专属包配置清单(Runtime):用于运行时,对分包资源进行操作
- //ExpansionPackageManifest manifest = GenerateUniquePackageManifest(Context.config.project.outputPath, streamingAssetsPath, customPackageInfos, ref assetInfos);
- //// 生成分包资源文件清单(包含主包)(Runtime):用于运行时,对分包资源进行校验
- //GenerateAssetManifest(Context.config.project.outputPath, streamingAssetsPath, ref assetInfos, customPackageInfos);
- //// 生成海报配置(Editor):用于制作更新包时,单独提取海报相关资源
- //string backendConfigDir = System.IO.Path.Combine(Context.config.project.outputPath, "backend-configs");
- //if (!System.IO.Directory.Exists(backendConfigDir)) System.IO.Directory.CreateDirectory(backendConfigDir);
- //GeneratePlacardManifest(backendConfigDir, assetsContext);
- //// 生成专属包配置清单(Editor):用于上传分包时,上传相关的分包信息
- //string json = XJson.ToJson(manifest);
- //string path = System.IO.Path.Combine(backendConfigDir, "UniquePackages.txt");
- //System.IO.File.WriteAllText(path, json);
- //// 生成所有资源清单:用于制作更新包时,对资源进行对比
- //CalculateHotUpdateCheckCode(Context.config.project.outputPath, assetInfos);
- //List<EditorAssetInfo> infos = new List<EditorAssetInfo>();
- //foreach (var info in assetInfos.Values)
- //{
- // infos.Add(info);
- //}
- //EditorAssetInfoManifest editorAssetInfoManifest = new EditorAssetInfoManifest();
- //editorAssetInfoManifest.assetInfos = infos.ToArray();
- //json = XJson.ToJson(editorAssetInfoManifest);
- //path = System.IO.Path.Combine(backendConfigDir, "AssetsManifest.txt");
- //System.IO.File.WriteAllText(path, json);
- ////由于分包会将资源从streamingAssetsPath移出,因此在最后才调用Refresh()
- //UnityEditor.AssetDatabase.Refresh();
- //return BuildErrorCode.CmdCompleted;
- }
- }
- }
|