196 lines
7.8 KiB
C#
196 lines
7.8 KiB
C#
|
#if ENABLE_ADDRESSABLE_PROFILER && UNITY_2022_2_OR_NEWER
|
||
|
|
||
|
using System.Collections.Generic;
|
||
|
using System.IO;
|
||
|
using Unity.Collections;
|
||
|
using UnityEditor.AddressableAssets.Build.Layout;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.AddressableAssets;
|
||
|
using UnityEngine.ResourceManagement.Profiling;
|
||
|
|
||
|
namespace UnityEditor.AddressableAssets.Diagnostics
|
||
|
{
|
||
|
internal class BuildLayoutsManager
|
||
|
{
|
||
|
private class ActiveLayout
|
||
|
{
|
||
|
public Hash128 BuildResultHash;
|
||
|
|
||
|
private readonly Dictionary<int, BuildLayout.Bundle> m_BundleMap = new Dictionary<int, BuildLayout.Bundle>();
|
||
|
private readonly Dictionary<int, Dictionary<int,BuildLayout.ExplicitAsset>> m_BundleAssetsMap = new Dictionary<int, Dictionary<int, BuildLayout.ExplicitAsset>>();
|
||
|
|
||
|
public ActiveLayout(BuildLayout layout)
|
||
|
{
|
||
|
layout.ReadFull();
|
||
|
foreach (BuildLayout.Bundle bundle in BuildLayoutHelpers.EnumerateBundles(layout))
|
||
|
{
|
||
|
int bundleCode = bundle.InternalName.GetHashCode();
|
||
|
m_BundleMap.Add(bundleCode, bundle);
|
||
|
Dictionary<int, BuildLayout.ExplicitAsset> assetMap = new Dictionary<int, BuildLayout.ExplicitAsset>(bundle.AssetCount);
|
||
|
foreach (BuildLayout.ExplicitAsset asset in BuildLayoutHelpers.EnumerateAssets(bundle))
|
||
|
{
|
||
|
int assetCode = asset.InternalId.GetHashCode();
|
||
|
assetMap[assetCode] = asset;
|
||
|
}
|
||
|
|
||
|
m_BundleAssetsMap[bundleCode] = assetMap;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public BuildLayout.Bundle GetBundle(int bundleCode)
|
||
|
{
|
||
|
if (!m_BundleMap.TryGetValue(bundleCode, out BuildLayout.Bundle value))
|
||
|
return null;
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
public BuildLayout.ExplicitAsset GetAsset(int bundleCode, int assetCode)
|
||
|
{
|
||
|
if (!m_BundleAssetsMap.TryGetValue(bundleCode, out Dictionary<int, BuildLayout.ExplicitAsset> assetMap))
|
||
|
return null;
|
||
|
if (!assetMap.TryGetValue(assetCode, out BuildLayout.ExplicitAsset value))
|
||
|
return null;
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private Dictionary<Hash128, BuildLayout> m_BuildLayouts = new Dictionary<Hash128, BuildLayout>();
|
||
|
private readonly List<ActiveLayout> m_ActiveLayouts = new List<ActiveLayout>();
|
||
|
|
||
|
public void LoadReports()
|
||
|
{
|
||
|
m_BuildLayouts.Clear();
|
||
|
m_ActiveLayouts.Clear();
|
||
|
|
||
|
if (Directory.Exists(Addressables.BuildReportPath))
|
||
|
{
|
||
|
foreach (string file in Directory.EnumerateFiles(Addressables.BuildReportPath, "*.json", SearchOption.TopDirectoryOnly))
|
||
|
{
|
||
|
if (!TryLoadLayoutAtPath(file, out BuildLayout layout))
|
||
|
continue;
|
||
|
|
||
|
Hash128 buildHash = Hash128.Parse(layout.BuildResultHash);
|
||
|
if (m_BuildLayouts.TryGetValue(buildHash, out var other))
|
||
|
{
|
||
|
// doesn't really matter, just means multiple with the same results exist, get the latest anyway
|
||
|
int comp = layout.Header.BuildStart.CompareTo(other.Header.BuildStart);
|
||
|
if (comp > 0)
|
||
|
{
|
||
|
m_BuildLayouts[buildHash].Close();
|
||
|
m_BuildLayouts[buildHash] = layout;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
m_BuildLayouts.Add(buildHash, layout);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool LoadManualReport(string path)
|
||
|
{
|
||
|
if (!TryLoadLayoutAtPath(path, out BuildLayout layout, true))
|
||
|
return false;
|
||
|
|
||
|
// set a save for the build hash
|
||
|
EditorPrefs.SetString("com.unity.addressabes.reportFilePath_" + layout.BuildResultHash, path);
|
||
|
m_BuildLayouts[Hash128.Parse(layout.BuildResultHash)] = layout;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private bool TryLoadLayoutAtPath(string path, out BuildLayout layoutOut, bool logErrors = false)
|
||
|
{
|
||
|
layoutOut = BuildLayout.Open(path);
|
||
|
if (layoutOut == null)
|
||
|
return false;
|
||
|
if (!layoutOut.ReadHeader())
|
||
|
return false;
|
||
|
if (!string.IsNullOrEmpty(layoutOut.Header.BuildError))
|
||
|
return false;
|
||
|
Hash128 hash = Hash128.Parse(layoutOut.BuildResultHash);
|
||
|
if (!hash.isValid)
|
||
|
{
|
||
|
if (logErrors)
|
||
|
Debug.LogError($"Could not load build report at {path}. Missing BuildResultHash");
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public HashSet<Hash128> SetActiveReportsAndGetMissingBuildHashes(NativeArray<CatalogFrameData> loadedRuntimeCatalogs)
|
||
|
{
|
||
|
HashSet<ActiveLayout> oldActives = new HashSet<ActiveLayout>(m_ActiveLayouts);
|
||
|
HashSet<Hash128> missingBuildHashes = new HashSet<Hash128>();
|
||
|
for (int i = 0; i < loadedRuntimeCatalogs.Length; ++i)
|
||
|
{
|
||
|
var recordedHash = loadedRuntimeCatalogs[i].BuildResultHash;
|
||
|
var layout = m_ActiveLayouts.Find(activeLayout => activeLayout.BuildResultHash == recordedHash);
|
||
|
if (layout != null)
|
||
|
{
|
||
|
oldActives.Remove(layout);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (m_BuildLayouts.TryGetValue(recordedHash, out BuildLayout newActiveLayout))
|
||
|
m_ActiveLayouts.Add(new ActiveLayout(newActiveLayout));
|
||
|
else
|
||
|
{
|
||
|
// try get from saved manual path
|
||
|
BuildLayout buildLayout = null;
|
||
|
if (EditorPrefs.HasKey("com.unity.addressabes.reportFilePath_" + recordedHash.ToString()))
|
||
|
{
|
||
|
string path = EditorPrefs.GetString("com.unity.addressabes.reportFilePath_" + recordedHash.ToString());
|
||
|
if (TryLoadLayoutAtPath(path, out buildLayout))
|
||
|
{
|
||
|
m_BuildLayouts[Hash128.Parse(buildLayout.BuildResultHash)] = buildLayout;
|
||
|
m_ActiveLayouts.Add(new ActiveLayout(buildLayout));
|
||
|
}
|
||
|
}
|
||
|
if (buildLayout == null)
|
||
|
missingBuildHashes.Add(recordedHash);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach (ActiveLayout oldActive in oldActives)
|
||
|
m_ActiveLayouts.Remove(oldActive);
|
||
|
|
||
|
if (missingBuildHashes.Count == 0)
|
||
|
return null;
|
||
|
return missingBuildHashes;
|
||
|
}
|
||
|
|
||
|
public BuildLayout.Bundle GetBundle(int bundleCode)
|
||
|
{
|
||
|
BuildLayout.Bundle value;
|
||
|
foreach (ActiveLayout activeLayout in m_ActiveLayouts)
|
||
|
{
|
||
|
value = activeLayout.GetBundle(bundleCode);
|
||
|
if (value != null)
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public BuildLayout.ExplicitAsset GetAsset(int bundleCode, int assetCode)
|
||
|
{
|
||
|
BuildLayout.ExplicitAsset value = null;
|
||
|
foreach (ActiveLayout activeLayout in m_ActiveLayouts)
|
||
|
{
|
||
|
value = activeLayout.GetAsset(bundleCode, assetCode);
|
||
|
if (value != null)
|
||
|
{
|
||
|
// this should be fixed in layout gen bug fix
|
||
|
// keeping bundle assignment to handle any previous data
|
||
|
if (value.Bundle == null)
|
||
|
value.Bundle = value.File.Bundle;
|
||
|
return value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|