268 lines
9.9 KiB
C#
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;
|
|
}
|
|
|
|
|
|
}
|
|
} |