296 lines
10 KiB
C#
296 lines
10 KiB
C#
using CaoCao.XAsset;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using UnityEngine;
|
||
|
||
namespace CaoCao.Editor
|
||
{
|
||
public class BuildVersions : IBuildJobStep
|
||
{
|
||
public void Start(BuildJob job)
|
||
{
|
||
var versions = Settings.GetDefaultVersions();
|
||
var version = versions.Get(job.parameters.name);
|
||
var manifest = XAsset.Utility.LoadFromFile<Manifest>(Settings.GetDataPath(version.file));
|
||
if (!UpdateManifest(job, manifest))
|
||
return;
|
||
|
||
SaveVersions(job, version, manifest, versions);
|
||
}
|
||
|
||
//"E:/HxMobileProject/Bundles/Android/hotfix_268c9e49444c768e1402d137a53a9d7e.json"
|
||
//"E:/HxMobileProject/BundlesCache/Android/version.json"
|
||
private static void SaveVersions(BuildJob job, XAsset.Version version, Manifest manifest, Versions versions)
|
||
{
|
||
if (job.parameters.buildNumber > 0)
|
||
version.ver = job.parameters.buildNumber;
|
||
else
|
||
version.ver++;
|
||
|
||
//ÕâÀïÌí¼Ó·Ö°ü
|
||
version.subPackage = job.parameters.subPackage;
|
||
version.name = job.parameters.name;
|
||
var json = JsonUtility.ToJson(manifest);
|
||
var bytes = Encoding.UTF8.GetBytes(json);
|
||
version.hash = XAsset.Utility.ComputeHash(bytes);
|
||
var file = version.GetFilename();
|
||
var path = Settings.GetDataPath(file);
|
||
File.WriteAllText(path, json);
|
||
|
||
job.changes.Add(file);
|
||
var settings = Settings.GetDefaultSettings();
|
||
// save version
|
||
var info = new FileInfo(path);
|
||
version.file = file;
|
||
version.size = (ulong) info.Length;
|
||
versions.Set(version);
|
||
versions.encryption = settings.bundle.encryption;
|
||
for (var index = 0; index < versions.data.Count; index++)
|
||
{
|
||
var item = versions.data[index];
|
||
|
||
if (File.Exists(Settings.GetDataPath(item.file)))
|
||
continue;
|
||
|
||
versions.data.RemoveAt(index);
|
||
index--;
|
||
}
|
||
|
||
versions.Save(Settings.GetCachePath(Versions.Filename));
|
||
}
|
||
|
||
private static bool UpdateManifest(BuildJob job, Manifest manifest)
|
||
{
|
||
var getBundles = new Dictionary<string, ManifestBundle>();
|
||
foreach (var bundle in manifest.bundles)
|
||
getBundles[bundle.name] = bundle;
|
||
|
||
var dirs = new List<string>();
|
||
var assets = new List<ManifestAsset>();
|
||
for (var index = 0; index < job.bundles.Count; index++)
|
||
{
|
||
var bundle = job.bundles[index];
|
||
AddAsset(bundle, dirs, index, assets);
|
||
if (getBundles.TryGetValue(bundle.group, out var value) && value.hash == bundle.hash && value.size == bundle.size)
|
||
continue;
|
||
|
||
//¼Ç¼±ä¸üµÄ×ÊÔ´£¬¼ÓÈëµ½job.changesÖÐ
|
||
job.changes.Add(bundle.file);
|
||
}
|
||
|
||
//ûÓбä¸ü¹ý£¬Í˳ö
|
||
if (job.changes.Count == 0 && !job.parameters.forceRebuild && job.bundles.Count == getBundles.Count)
|
||
{
|
||
job.error = $"{job.parameters.name} : Nothing to build.";
|
||
return false;
|
||
}
|
||
|
||
var map = assets.ToDictionary(a => a.path);
|
||
foreach (var asset in assets)
|
||
{
|
||
var dependencies = Settings.GetDependencies(asset.path);
|
||
var deps = new List<int>();
|
||
foreach (var dependency in dependencies)
|
||
{
|
||
if (map.TryGetValue(dependency, out var dep))
|
||
{
|
||
deps.Add(dep.id);
|
||
}
|
||
}
|
||
|
||
asset.deps = deps.ToArray();
|
||
}
|
||
|
||
manifest.Clear();
|
||
manifest.saveBundleName = Settings.GetDefaultSettings().bundle.saveBundleName;
|
||
manifest.bundles = job.bundles.ConvertAll(Converter).ToArray();
|
||
manifest.assets = assets.ToArray();
|
||
manifest.dirs = dirs.ToArray();
|
||
manifest.build = job.parameters.name;
|
||
|
||
BuildAssetPacks(manifest);
|
||
return true;
|
||
}
|
||
|
||
private static void AddAsset(BuildBundle bundle, IList<string> dirs, int index, ICollection<ManifestAsset> assets)
|
||
{
|
||
foreach (var asset in bundle.assets)
|
||
{
|
||
var buildAsset = Settings.GetAsset(asset);
|
||
if (buildAsset.addressMode == AddressMode.LoadByDependencies)
|
||
continue;
|
||
|
||
var dir = Path.GetDirectoryName(asset)?.Replace("\\", "/");
|
||
var pos = dirs.IndexOf(dir);
|
||
if (pos == -1)
|
||
{
|
||
pos = dirs.Count;
|
||
dirs.Add(dir);
|
||
}
|
||
|
||
var manifestAsset = new ManifestAsset
|
||
{
|
||
id = assets.Count,
|
||
name = Path.GetFileName(asset),
|
||
path = asset,
|
||
bundle = index,
|
||
dir = pos,
|
||
addressMode = buildAsset.addressMode
|
||
};
|
||
assets.Add(manifestAsset);
|
||
}
|
||
}
|
||
|
||
private static ManifestBundle Converter(BuildBundle input)
|
||
{
|
||
return new ManifestBundle
|
||
{
|
||
name = input.group,
|
||
size = input.size,
|
||
hash = input.hash,
|
||
deps = input.deps
|
||
};
|
||
}
|
||
|
||
private static void BuildAssetPacks(Manifest manifest)
|
||
{
|
||
manifest.packs = Array.Empty<XAsset.AssetPack>();
|
||
manifest.OnAfterDeserialize();
|
||
var packs = new List<XAsset.AssetPack>();
|
||
var packed = new HashSet<int>();
|
||
var assetPacks = new List<AssetPack>(Settings.FindAssets<AssetPack>());
|
||
assetPacks.Sort((a, b) => a.id.CompareTo(b.id));
|
||
|
||
|
||
foreach (var config in assetPacks)
|
||
{
|
||
var assets = new HashSet<string>();
|
||
Settings.Collect(config, assets);
|
||
var set = new HashSet<int>();
|
||
foreach (var asset in assets)
|
||
{
|
||
if (!manifest.TryGetAsset(asset, out var result))
|
||
continue;
|
||
|
||
var bundle = manifest.bundles[result.bundle];
|
||
set.Add(result.bundle);
|
||
set.UnionWith(bundle.deps);
|
||
}
|
||
|
||
set.ExceptWith(packed);
|
||
packed.UnionWith(set);
|
||
|
||
if (set.Count <= 0)
|
||
continue;
|
||
|
||
var bundles = new List<int>(set);
|
||
bundles.Sort();
|
||
CreateAssetPacks(manifest, config.name, packs, bundles, config.desc);
|
||
}
|
||
|
||
var unpacked = new List<int>();
|
||
for (var i = 0; i < manifest.bundles.Length; i++)
|
||
{
|
||
if (packed.Contains(i))
|
||
continue;
|
||
|
||
unpacked.Add(i);
|
||
}
|
||
|
||
if (unpacked.Count > 0)
|
||
CreateAssetPacks(manifest, "Unpacked", packs, unpacked, "Unpacked");
|
||
|
||
var setting = Settings.GetDefaultSettings();
|
||
if (setting.bundle.buildAssetPackAssets)
|
||
{
|
||
foreach (var item in packs)
|
||
PackAssets(item);
|
||
}
|
||
|
||
manifest.packs = packs.ToArray();
|
||
}
|
||
|
||
private static void CreateAssetPacks(
|
||
Manifest manifest,
|
||
string name,
|
||
ICollection<XAsset.AssetPack> packs,
|
||
IEnumerable<int> bundles,
|
||
string desc)
|
||
{
|
||
var maxSize = Settings.GetDefaultSettings().bundle.maxAssetPackSize;
|
||
var packedSize = 0UL;
|
||
var index = 0;
|
||
|
||
var pack = new XAsset.AssetPack
|
||
{
|
||
name = name,
|
||
nameIndexed = $"{manifest.build.ToLower()}_{name.ToLower()}_{index}{XAsset.AssetPack.Extension}",
|
||
desc = desc,
|
||
manifest = manifest
|
||
};
|
||
packs.Add(pack);
|
||
foreach (var id in bundles)
|
||
{
|
||
var bundle = manifest.bundles[id];
|
||
var file = new FileInfo(Settings.GetDataPath(bundle.file));
|
||
|
||
if (!file.Exists)
|
||
continue;
|
||
|
||
if (packedSize > maxSize)
|
||
{
|
||
index++;
|
||
packedSize = 0;
|
||
pack = new XAsset.AssetPack
|
||
{
|
||
name = name,
|
||
nameIndexed = $"{manifest.build.ToLower()}_{name.ToLower()}_{index}{XAsset.AssetPack.Extension}",
|
||
desc = desc,
|
||
manifest = manifest
|
||
};
|
||
packs.Add(pack);
|
||
}
|
||
|
||
packedSize += bundle.size;
|
||
pack.assets.Add(new AssetLocation {id = id, size = bundle.size});
|
||
manifest.bundles[id].pack = packs.Count - 1;
|
||
pack.size += bundle.size;
|
||
}
|
||
}
|
||
|
||
private static string GetDisplayName(ManifestBundle bundle)
|
||
{
|
||
return $"{bundle.file}({XAsset.Utility.FormatBytes(bundle.size)})";
|
||
}
|
||
|
||
private static void PackAssets(XAsset.AssetPack pack)
|
||
{
|
||
var path = Settings.GetCachePath(pack.nameIndexed);
|
||
using (var writer = new BinaryWriter(File.OpenWrite(path)))
|
||
{
|
||
foreach (var asset in pack.assets)
|
||
{
|
||
var bundle = pack.manifest.bundles[asset.id];
|
||
var bytes = File.ReadAllBytes(Settings.GetDataPath(bundle.file));
|
||
writer.Write(bundle.file);
|
||
writer.Write(bundle.size);
|
||
asset.offset = (ulong) writer.BaseStream.Position;
|
||
writer.Write(bytes);
|
||
}
|
||
}
|
||
|
||
var info = new FileInfo(path);
|
||
pack.hash = XAsset.Utility.ComputeHash(path);
|
||
pack.size = (ulong) info.Length;
|
||
pack.packed = true;
|
||
pack.file = pack.GetFilename();
|
||
var savePath = Settings.GetDataPath(pack.file);
|
||
info.CopyTo(savePath, true);
|
||
var assets = string.Join("\n\t", pack.assets.ConvertAll(input => GetDisplayName(pack.manifest.bundles[input.id])));
|
||
XAsset.Logger.I($"Pack {pack.name} to {pack.nameIndexed} with following assets({XAsset.Utility.FormatBytes(pack.size)}) :\n\t{assets}");
|
||
}
|
||
}
|
||
} |