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

296 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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}");
}
}
}