TheInitialProject/Assets/CaoCao/Scripts/Editor/XAsset/Build/Steps/BuildBundles.cs
2024-10-23 16:59:02 +08:00

268 lines
9.9 KiB
C#

using CaoCao.XAsset;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
namespace CaoCao.Editor
{
public class BuildBundles : IBuildJobStep
{
private static bool _bXor = false; //ÊÇ·ñÐèÒª¼ÓÃÜ
private static string[] _xorList = new string[] { "hotfixb_win", "hotfixb_ios", "hotfixb_android" };
public void Start(BuildJob job)
{
if (job.bundledAssets.Count > 0)
if (!BuildBundlesWithBundledAssets(job))
return;
if (job.rawAssets.Count == 0)
return;
BuildBundlesWithRawAssets(job);
}
//"E:/HxMobileProject/Bundles/Android/hotfix/gamehotfix_game_hotfix_1724706769b660e9bb10348d54791798.bundle"
private static void BuildBundlesWithRawAssets(BuildJob job)
{
var settings = Settings.GetDefaultSettings().bundle;
if (settings.saveBundleName)
{
foreach (var asset in job.rawAssets)
{
if (string.IsNullOrEmpty(asset.path))
{
Logger.E($"RawAsset not found:{asset.path}");
continue;
}
var file = new FileInfo(asset.path);
var hash = XAsset.Utility.ComputeHash(asset.path);
var nameWithAppendHash = $"{hash}{Settings.extension}";
var name = asset.bundle.Replace(Settings.extension, string.Empty);
nameWithAppendHash = $"{name}_{nameWithAppendHash}";
var bundle = new BuildBundle
{
group = asset.bundle,
hash = hash,
file = nameWithAppendHash,
assets = new List<string> {asset.path},
size = (ulong) file.Length,
raw = true
};
var path = Settings.GetDataPath(bundle.file);
XAsset.Utility.CreateDirectoryIfNecessary(path);
//°Ñ"Assets/GameAssets/GameHotfix/game.hotfix" copy µ½ bundleĿ¼
if (!File.Exists(path))
file.CopyTo(path, true);
job.bundles.Add(bundle);
}
}
else
{
foreach (var asset in job.rawAssets)
{
if (string.IsNullOrEmpty(asset.path))
{
Logger.E($"RawAsset not found:{asset.path}");
continue;
}
var file = new FileInfo(asset.path);
var hash = XAsset.Utility.ComputeHash(asset.path);
var nameWithAppendHash = $"{hash}{Settings.extension}";
var bundle = new BuildBundle
{
group = asset.bundle,
hash = hash,
file = nameWithAppendHash,
assets = new List<string> {asset.path},
size = (ulong) file.Length,
raw = true
};
var path = Settings.GetDataPath(bundle.file);
XAsset.Utility.CreateDirectoryIfNecessary(path);
if (!File.Exists(path))
file.CopyTo(path, true);
job.bundles.Add(bundle);
}
}
}
private static bool BuildWithEncodeFunc(BuildJob job, IReadOnlyDictionary<string, BuildBundle> nameWithBundles,
IAssetBundleManifest manifest, Func<string, string, string, ulong> encodeFunc)
{
var settings = Settings.GetDefaultSettings().bundle;
var assetBundles = manifest.GetAllAssetBundles();
foreach (var assetBundle in assetBundles)
if (nameWithBundles.TryGetValue(assetBundle, out var bundle))
{
var path = Settings.GetCachePath(assetBundle);
bundle.deps = Array.ConvertAll(manifest.GetAllDependencies(assetBundle), input => nameWithBundles[input].id);
var info = new FileInfo(path);
if (info.Exists)
{
var hash = XAsset.Utility.ComputeHash(path);
var nameWithAppendHash = $"{hash}{Settings.extension}";
//"E:/HxMobileProject/BundlesCache/Android/b9d3a695563b75faf8b40843773a6262.bundle"
var buildPath = Settings.GetCachePath(nameWithAppendHash);
bundle.size = encodeFunc(path, hash, buildPath);
bundle.hash = XAsset.Utility.ComputeHash(buildPath);
bundle.file = $"{bundle.hash}{Settings.extension}";
if (settings.saveBundleName)
{
var name = assetBundle.Replace(Settings.extension, string.Empty);
bundle.file = $"{name}_{bundle.file}";
}
//"E:/HxMobileProject/Bundles/Android/assetspackb/common_asset_490b592d96dff85f5898c860db836145.bundle"
var newPath = Settings.GetDataPath(bundle.file);
XAsset.Utility.CreateDirectoryIfNecessary(newPath);
if (File.Exists(newPath))
File.Delete(newPath);
File.Move(buildPath, newPath);
}
else
{
job.TreatError($"File not found: {info}");
return false;
}
}
else
{
job.TreatError($"Bundle not found: {assetBundle}");
return false;
}
return true;
}
private static ulong EncodeWithoutEncryption(string path, string hash, string newPath)
{
var bytes = File.ReadAllBytes(path);
var size = bytes.Length;
XAsset.Utility.CreateDirectoryIfNecessary(newPath);
using (var writer = new BinaryWriter(File.OpenWrite(newPath)))
{
writer.Write(File.ReadAllBytes(path));
}
return (ulong) size;
}
private static ulong EncodeWithEncryption(string path, string hash, string newPath)
{
string pattern = @"\d+_texture"; // ÕýÔò±í´ïʽģʽ
//ÅжÏÊÇ·ñÐèÒª¼ÓÃÜ
bool bXor = false;
foreach(var p in _xorList)
{
if(path.Contains(p))
{
bXor = true;
break;
}
}
#if ENABLE_NEWENCRY //@È¡ÏûÌùͼ¼ÓÃÜ
//²»¼ÓÃÜ´Ë´¦ÎÞ´úÂë
#else
if (!bXor)
{
MatchCollection matches = Regex.Matches(path, pattern);
if (matches.Count > 0)
bXor = true;
}
#endif
var bytes = File.ReadAllBytes(path);
if (bXor)
{
byte[] hashBytes = System.Text.Encoding.UTF8.GetBytes(hash);
XAsset.Utility.GetSelfXorBytes(bytes, hashBytes);
UnityEngine.Debug.Log($"¼ÓÃÜ£º{path}");
}
ulong size = XAsset.Utility.WriteOffset + (ulong)bytes.Length;
XAsset.Utility.CreateDirectoryIfNecessary(newPath);
using (var writer = new BinaryWriter(File.OpenWrite(newPath)))
{
writer.Write(hash);
writer.Write(bytes);
}
return size;
}
private static IAssetBundleManifest BuildAssetBundles(BuildJob job)
{
if (Builder.BuildPipeline != null)
return Builder.BuildPipeline.BuildAssetBundles(Settings.PlatformCachePath, job.bundles.ConvertAll(
input =>
new AssetBundleBuild
{
assetNames = input.assets.ToArray(),
assetBundleName = input.group
}).ToArray(), job.parameters.options, EditorUserBuildSettings.activeBuildTarget);
job.TreatError("Pipeline == null");
return null;
}
private static bool BuildBundlesWithBundledAssets(BuildJob job)
{
var nameWithBundles = job.bundles.ToDictionary(o => o.group);
foreach (var asset in job.bundledAssets)
{
if (!nameWithBundles.TryGetValue(asset.bundle, out var bundle))
{
var id = job.bundles.Count;
bundle = new BuildBundle
{
id = id,
group = asset.bundle,
assets = new List<string>()
};
job.bundles.Add(bundle);
nameWithBundles[asset.bundle] = bundle;
}
bundle.assets.Add(asset.path);
}
var manifest = BuildAssetBundles(job);
if (manifest == null)
{
job.TreatError($"Failed to build AssetBundles with {job.parameters.name}.");
return false;
}
var settings = Settings.GetDefaultSettings();
if (settings.bundle.encryption)
{
if (!BuildWithEncodeFunc(job, nameWithBundles, manifest, EncodeWithEncryption))
return false;
}
else
{
if (!BuildWithEncodeFunc(job, nameWithBundles, manifest, EncodeWithoutEncryption))
return false;
}
return true;
}
}
}