WuhuIslandTesting/Library/PackageCache/com.unity.addressables@1.21.12/Editor/Build/Layout/BuildLayout.cs
2025-01-07 02:06:59 +01:00

1380 lines
47 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.Build.Content;
using UnityEngine;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.ResourceProviders;
namespace UnityEditor.AddressableAssets.Build.Layout
{
/// <summary>
/// A storage class used to gather data about an Addressable build.
/// </summary>
[Serializable]
public class BuildLayout
{
/// <summary>
/// Helper class to wrap header values for BuildLayout
/// </summary>
public class LayoutHeader
{
/// <summary>
/// Build layout for this header
/// </summary>
internal BuildLayout m_BuildLayout;
/// <summary>
/// Build Platform Addressables build is targeting
/// </summary>
public BuildTarget BuildTarget
{
get
{
if (m_BuildLayout == null)
return BuildTarget.NoTarget;
return m_BuildLayout.BuildTarget;
}
}
/// <summary>
/// Hash of the build results
/// </summary>
public string BuildResultHash
{
get
{
if (m_BuildLayout == null)
return null;
return m_BuildLayout.BuildResultHash;
}
}
/// <summary>
/// If the build was a new build or an update for a previous build
/// </summary>
public BuildType BuildType
{
get
{
if (m_BuildLayout == null)
return BuildType.NewBuild;
return m_BuildLayout.BuildType;
}
}
/// <summary>
/// DateTime at the start of building Addressables
/// </summary>
public DateTime BuildStart
{
get
{
if (m_BuildLayout == null)
return DateTime.MinValue;
return m_BuildLayout.BuildStart;
}
}
/// <summary>
/// Time in seconds taken to build Addressables Content
/// </summary>
public double Duration
{
get
{
if (m_BuildLayout == null)
return 0;
return m_BuildLayout.Duration;
}
}
/// <summary>
/// Null or Empty if the build completed successfully, else contains error causing the failure
/// </summary>
public string BuildError
{
get
{
if (m_BuildLayout == null)
return "";
return m_BuildLayout.BuildError;
}
}
}
/// <summary>
/// Helper object to get header values for this build layout
/// </summary>
public LayoutHeader Header
{
get
{
if (m_Header == null)
m_Header = new LayoutHeader() {m_BuildLayout = this};
return m_Header;
}
}
private LayoutHeader m_Header;
#region HeaderValues // Any values in here should also be in BuildLayoutHeader class
/// <summary>
/// Build Platform Addressables build is targeting
/// </summary>
public BuildTarget BuildTarget;
/// <summary>
/// Hash of the build results
/// </summary>
public string BuildResultHash;
/// <summary>
/// If the build was a new build or an update for a previous build
/// </summary>
public BuildType BuildType;
/// <summary>
/// DateTime at the start of building Addressables
/// </summary>
public DateTime BuildStart
{
get
{
if (m_BuildStartDateTime.Year > 2000)
return m_BuildStartDateTime;
if (DateTime.TryParse(BuildStartTime, out DateTime result))
{
m_BuildStartDateTime = result;
return m_BuildStartDateTime;
}
return DateTime.MinValue;
}
set
{
BuildStartTime = value.ToString();
}
}
private DateTime m_BuildStartDateTime;
[SerializeField]
internal string BuildStartTime;
/// <summary>
/// Time in seconds taken to build Addressables Content
/// </summary>
public double Duration;
/// <summary>
/// Null or Empty if the build completed successfully, else contains error causing the failure
/// </summary>
public string BuildError;
#endregion // End of header values
/// <summary>
/// Version of the Unity edtior used to perform the build.
/// </summary>
public string UnityVersion;
/// <summary>
/// Version of the Addressables package used to perform the build.
/// </summary>
public string PackageVersion;
/// <summary>
/// Player build version for the build, this is a timestamp if PlayerVersionOverride is not set in the settings
/// </summary>
public string PlayerBuildVersion;
/// <summary>
/// Settings used by the Addressables settings at the time of building
/// </summary>
public AddressablesEditorData AddressablesEditorSettings;
/// <summary>
/// Values used by the Addressables runtime
/// </summary>
public AddressablesRuntimeData AddressablesRuntimeSettings;
/// <summary>
/// Name of the build script to build
/// </summary>
public string BuildScript;
/// <summary>
/// Default group at the time of building
/// </summary>
[SerializeReference]
public Group DefaultGroup;
/// <summary>
/// The Addressable Groups that reference this data
/// </summary>
[SerializeReference]
public List<Group> Groups = new List<Group>();
/// <summary>
/// The List of AssetBundles that were built without a group associated to them, such as the BuiltIn Shaders Bundle and the MonoScript Bundle
/// </summary>
[SerializeReference]
public List<Bundle> BuiltInBundles = new List<Bundle>();
/// <summary>
/// List of assets with implicitly included Objects
/// </summary>
public List<AssetDuplicationData> DuplicatedAssets = new List<AssetDuplicationData>();
/// <summary>
/// The build path on disk of the default local content catalog
/// </summary>
[SerializeField]
internal string LocalCatalogBuildPath;
/// <summary>
/// The build path of the remote content catalog, if one was built
/// </summary>
[SerializeField]
internal string RemoteCatalogBuildPath;
internal string m_FilePath;
private bool m_HeaderRead = false;
private bool m_BodyRead = false;
private FileStream m_FileStream = null;
private StreamReader m_StreamReader = null;
/// <summary>
/// Used for serialising the header info for the BuildLayout.
/// Names must match values in BuildLayout class
/// </summary>
[Serializable]
private class BuildLayoutHeader
{
public BuildTarget BuildTarget;
public string BuildResultHash;
public BuildType BuildType;
public string BuildStartTime;
public double Duration;
public string BuildError;
}
/// <summary>
///
/// </summary>
/// <param name="path">Path to the BuildLayout json file on disk</param>
/// <param name="readHeader">If the basic header information should be read</param>
/// <param name="readFullFile">If the full build layout should be read</param>
/// <returns></returns>
public static BuildLayout Open(string path, bool readHeader = true, bool readFullFile = false)
{
if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path))
{
Debug.LogError($"Invalid path provided : {path}");
return null;
}
BuildLayout readLayout = new BuildLayout
{
m_FilePath = path
};
if (readFullFile)
readLayout.ReadFull();
else if (readHeader)
readLayout.ReadHeader();
return readLayout;
}
/// <summary>
/// Writes json file for the build layout to the destination path
/// </summary>
/// <param name="destinationPath">File path to write build layout</param>
/// <param name="prettyPrint">If json should be written using pretty print</param>
public void WriteToFile(string destinationPath, bool prettyPrint)
{
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
string versionElementString = "\"UnityVersion\":";
string headerJson = null;
string bodyJson = JsonUtility.ToJson(this, prettyPrint);
if (prettyPrint)
{
BuildLayoutHeader header = new BuildLayoutHeader()
{
BuildTarget = this.BuildTarget,
BuildResultHash = this.BuildResultHash,
BuildType = this.BuildType,
BuildStartTime = this.BuildStartTime,
Duration = this.Duration,
BuildError = this.BuildError
};
headerJson = JsonUtility.ToJson(header, false);
headerJson = headerJson.Remove(headerJson.Length - 1, 1) + ',';
}
int index = bodyJson.IndexOf(versionElementString);
if (prettyPrint)
bodyJson = bodyJson.Remove(0, index);
else
bodyJson = bodyJson.Insert(index, "\n");
using (FileStream s = System.IO.File.Open(destinationPath, FileMode.Create))
{
using (StreamWriter sw = new StreamWriter(s))
{
if (prettyPrint)
sw.WriteLine(headerJson);
sw.Write(bodyJson);
}
}
}
/// <summary>
/// Closes streams for loading the build layout
/// </summary>
public void Close()
{
if (m_StreamReader != null)
{
m_StreamReader.Close();
m_StreamReader = null;
}
if (m_FileStream != null)
{
m_FileStream.Close();
m_FileStream = null;
}
}
/// <summary>
/// Reads basic information about the build layout
/// </summary>
/// <param name="keepFileStreamsActive">If false, the file will be closed after reading the header line.</param>
/// <returns>true is successful, else false</returns>
public bool ReadHeader(bool keepFileStreamsActive = false)
{
if (m_HeaderRead)
return true;
if (string.IsNullOrEmpty(m_FilePath))
{
Debug.LogError("Cannot read BuildLayout header, A file has not been selected to open. Open must be called before reading any data");
return false;
}
try
{
if (m_FileStream == null)
{
m_FileStream = System.IO.File.Open(m_FilePath, FileMode.Open);
m_StreamReader = new StreamReader(m_FileStream);
}
string fileJsonText = m_StreamReader.ReadLine();
int lastComma = fileJsonText.LastIndexOf(',');
if (lastComma > 0)
{
fileJsonText = fileJsonText.Remove(lastComma) + '}';
try
{
EditorJsonUtility.FromJsonOverwrite(fileJsonText, this);
}
catch (Exception e)
{
Debug.LogError($"Failed to read header for BuildLayout at {m_FilePath}, with exception: {e.Message}");
return false;
}
}
else
{
Debug.LogError($"Failed to read header for BuildLayout at {m_FilePath}, invalid json format");
return false;
}
m_HeaderRead = true;
}
catch (Exception e)
{
Debug.LogException(e);
return false;
}
finally
{
if (!keepFileStreamsActive)
Close();
}
return true;
}
/// <summary>
/// Reads the full build layout data from file
/// </summary>
/// <returns>true is successful, else false</returns>
public bool ReadFull()
{
if (m_BodyRead)
return true;
if (string.IsNullOrEmpty(m_FilePath))
{
Debug.LogError("Cannot read BuildLayout header, BuildLayout has not open for a file");
return false;
}
try
{
if (m_FileStream == null)
{
m_FileStream = System.IO.File.Open(m_FilePath, FileMode.Open);
m_StreamReader = new StreamReader(m_FileStream);
}
else if (m_HeaderRead)
{
// reset to read the whole file
m_FileStream.Position = 0;
m_StreamReader.DiscardBufferedData();
}
string fileJsonText = m_StreamReader.ReadToEnd();
EditorJsonUtility.FromJsonOverwrite(fileJsonText, this);
m_HeaderRead = true;
m_BodyRead = true;
}
catch (Exception e)
{
Debug.LogError($"Failed to read header for BuildLayout at {m_FilePath}, with exception: {e.Message}");
return false;
}
finally
{
Close();
}
return true;
}
/// <summary>
/// Values set for the AddressablesAssetSettings at the time of building
/// </summary>
[Serializable]
public class AddressablesEditorData
{
/// <summary>
/// Hash value of the settings at the time of building
/// </summary>
public string SettingsHash;
/// <summary>
/// Active Addressables profile set at time of Building
/// </summary>
public Profile ActiveProfile;
/// <summary>
/// Addressables setting value set for building the remote catalog
/// </summary>
public bool BuildRemoteCatalog;
/// <summary>
/// Load path for the remote catalog if enabled
/// </summary>
public string RemoteCatalogLoadPath;
/// <summary>
/// Addressables setting value set for bundling the local catalog
/// </summary>
public bool BundleLocalCatalog;
/// <summary>
/// Addressables setting value set for optimising the catalog size
/// </summary>
public bool OptimizeCatalogSize;
/// <summary>
/// Addressables setting value set for time out when downloading catalogs
/// </summary>
public int CatalogRequestsTimeout;
/// <summary>
/// Runtime setting value set for the maximum number of concurrent web requests
/// </summary>
public int MaxConcurrentWebRequests;
/// <summary>
/// Addressables setting value set for is to update the remote catalog on startup
/// </summary>
public bool DisableCatalogUpdateOnStartup;
/// <summary>
/// Addressables setting value set for if the build created unique bundle ids
/// </summary>
public bool UniqueBundleIds;
/// <summary>
/// Addressables setting value set for if the build used non recursive dependency calculation
/// </summary>
public bool NonRecursiveBuilding;
/// <summary>
/// Addressables setting value set for if the build used contiguous bundle objects
/// </summary>
public bool ContiguousBundles;
/// <summary>
/// Addressables setting value set for disabling sub asset representation in the Bundle
/// </summary>
public bool DisableSubAssetRepresentations;
/// <summary>
/// Internal naming prefix of the built in shaders bundle
/// </summary>
public string ShaderBundleNaming;
/// <summary>
/// Internal naming prefix of the monoScript bundle,
/// No MonoScript bundle is built if set to disabled
/// </summary>
public string MonoScriptBundleNaming;
/// <summary>
/// Addressables setting value set for is the unity version was stripped from the built bundles
/// </summary>
public bool StripUnityVersionFromBundleBuild;
}
/// <summary>
/// Values set for runtime initialisation of Addressables
/// </summary>
[Serializable]
public class AddressablesRuntimeData
{
/// <summary>
/// Runtime setting value set for if the runtime will submit profiler events
/// </summary>
public bool ProfilerEvents;
/// <summary>
/// Runtime setting value set for if resource manager exceptions are logged or not
/// </summary>
public bool LogResourceManagerExceptions;
/// <summary>
/// Runtime setting value set for catalogs to load (First catalog found in the list is used)
/// </summary>
public List<string> CatalogLoadPaths = new List<string>();
/// <summary>
/// Hash of the build catalog
/// </summary>
public string CatalogHash;
}
/// <summary>
/// Information about the AssetBundleObject
/// </summary>
[Serializable]
public class AssetBundleObjectInfo
{
/// <summary>
/// The size, in bytes, of the AssetBundleObject
/// </summary>
public ulong Size;
}
/// <summary>
/// Key value pair of string type
/// </summary>
[Serializable]
public struct StringPair
{
/// <summary>
/// String key
/// </summary>
public string Key;
/// <summary>
/// String value
/// </summary>
public string Value;
}
/// <summary>
/// Addressables Profile data
/// </summary>
[Serializable]
public class Profile
{
/// <summary>
/// Name of the profile
/// </summary>
public string Name;
/// <summary>
/// ID assigned within the ProfileSettings of the profile
/// </summary>
public string Id;
/// <summary>
/// Profile variables assigned to the profile
/// </summary>
public StringPair[] Values;
}
/// <summary>
/// Data about the AddressableAssetGroup that gets processed during a build.
/// </summary>
[Serializable]
public class Group
{
/// <summary>
/// The Name of the AdressableAssetGroup
/// </summary>
public string Name;
/// <summary>
/// The Guid of the AddressableAssetGroup
/// </summary>
public string Guid;
/// <summary>
/// The packing mode as defined by the BundledAssetGroupSchema on the AddressableAssetGroup
/// </summary>
public string PackingMode;
/// <summary>
/// A list of the AssetBundles associated with the Group
/// </summary>
[SerializeReference]
public List<Bundle> Bundles = new List<Bundle>();
/// <summary>
/// Data about the AddressableAssetGroupSchemas associated with the Group
/// </summary>
[SerializeReference]
public List<SchemaData> Schemas = new List<SchemaData>();
}
/// <summary>
/// Data container for AddressableAssetGroupSchemas
/// </summary>
[Serializable]
public class SchemaData : ISerializationCallbackReceiver
{
/// <summary>
/// The Guid of the AddressableAssetGroupSchema
/// </summary>
public string Guid;
/// <summary>
/// The class type of the AddressableAssetGroupSchema
/// </summary>
public string Type;
/// <summary>
/// These key-value-pairs include data about the AddressableAssetGroupSchema, such as PackingMode and Compression.
/// </summary>
public List<Tuple<string, string>> KvpDetails = new List<Tuple<string, string>>();
[SerializeField]
private StringPair[] SchemaDataPairs;
/// <summary>
/// Converts the unserializable KvpDetails to a serializable type for writing
/// </summary>
public void OnBeforeSerialize()
{
SchemaDataPairs = new StringPair[KvpDetails.Count];
for (int i = 0; i < SchemaDataPairs.Length; ++i)
SchemaDataPairs[i] = new StringPair() {Key = KvpDetails[i].Item1, Value = KvpDetails[i].Item2};
}
/// <summary>
/// Writes data to KvpDetails after Deserializing to temporary data fields
/// </summary>
public void OnAfterDeserialize()
{
for (int i = 0; i < SchemaDataPairs.Length; ++i)
KvpDetails.Add(new Tuple<string, string>(SchemaDataPairs[i].Key, SchemaDataPairs[i].Value));
SchemaDataPairs = null;
}
}
/// <summary>
/// Data store for AssetBundle information.
/// </summary>
[Serializable]
public class Bundle
{
/// <summary>
/// The name of the AssetBundle
/// </summary>
public string Name;
/// <summary>
/// Name used to identify the asset bundle
/// </summary>
public string InternalName;
/// <summary>
/// The file size of the AssetBundle on disk, in bytes
/// </summary>
public ulong FileSize;
/// <summary>
/// Status of the bundle after an update build
/// </summary>
public BundleBuildStatus BuildStatus;
/// <summary>
/// The file size of all of the Expanded Dependencies of this AssetBundle, in bytes
/// Expanded dependencies are the dependencies of this AssetBundle's dependencies
/// </summary>
public ulong ExpandedDependencyFileSize;
/// <summary>
/// The file size
/// </summary>
public ulong DependencyFileSize;
/// <summary>
/// The file size of the AssetBundle on disk when uncompressed, in bytes
/// </summary>
public ulong UncompressedFileSize
{
get
{
ulong total = 0;
foreach (File file in Files)
total += file.UncompressedSize;
return total;
}
}
/// <summary>
/// The number of Assets contained within the bundle
/// </summary>
public int AssetCount = 0;
/// <summary>
/// Represents a dependency from the containing Bundle to dependentBundle, with AssetDependencies representing each of the assets in parentBundle that create the link to dependentBundle
/// </summary>
[Serializable]
public class BundleDependency
{
/// <summary>
/// The bundle that the parent bundle depends on
/// </summary>
[SerializeReference]
public Bundle DependencyBundle;
/// <summary>
/// The list of assets that link the parent bundle to the DependencyBundle
/// </summary>
public List<AssetDependency> AssetDependencies;
/// <summary>
/// Percentage of Efficiency asset usage that uses the entire dependency tree of this bundle dependency.
/// This includes DependencyBundle and all bundles beneath it.
/// Value is equal to [Total Filesize of Dependency Assets] / [Total size of all dependency bundles on disk]
/// Example: There are 3 bundles A, B, and C, that are each 10 MB on disk. A depends on 2 MB worth of assets in B, and B depends on 4 MB worth of assets in C.
/// The Efficiency of the dependencyLink from A->B would be 2/10 -> 20% and the ExpandedEfficiency of A->B would be (2 + 4)/(10 + 10) -> 6/20 -> 30%
/// </summary>
public float ExpandedEfficiency;
/// <summary>
/// The Efficiency of the connection between the parent bundle and DependencyBundle irrespective of the full dependency tree below DependencyBundle.
/// Value is equal to [Serialized Filesize of assets In Dependency Bundle Referenced By Parent]/[Total size of Dependency Bundle on disk]
/// Example: Given two Bundles A and B that are each 10 MB on disk, and A depends on 5 MB worth of assets in B, then the Efficiency of DependencyLink A->B is 5/10 = .5
/// </summary>
public float Efficiency;
private HashSet<ExplicitAsset> referencedAssets = new HashSet<ExplicitAsset>();
/// <summary>
/// The number of uniquely assets that the parent bundle uniquely references in dependency bundle. This is used to calculate Efficiency without double counting.
/// </summary>
internal ulong referencedAssetsFileSize = 0;
internal BundleDependency(Bundle b)
{
DependencyBundle = b;
AssetDependencies = new List<AssetDependency>();
}
internal void CreateAssetDependency(ExplicitAsset root, ExplicitAsset dependencyAsset)
{
if (referencedAssets.Contains(dependencyAsset))
return;
referencedAssets.Add(dependencyAsset);
AssetDependencies.Add(new AssetDependency(root, dependencyAsset));
referencedAssetsFileSize += dependencyAsset.SerializedSize;
}
/// <summary>
/// Represents a dependency from a root Asset to a dependent Asset.
/// </summary>
[Serializable]
public struct AssetDependency
{
[SerializeReference]
internal ExplicitAsset rootAsset;
[SerializeReference]
internal ExplicitAsset dependencyAsset;
internal AssetDependency(ExplicitAsset root, ExplicitAsset depAsset)
{
rootAsset = root;
dependencyAsset = depAsset;
}
}
}
internal Dictionary<Bundle, BundleDependency> BundleDependencyMap = new Dictionary<Bundle, BundleDependency>();
/// <summary>
/// A list of bundles that this bundle depends upon.
/// </summary>
[SerializeField]
public BundleDependency[] BundleDependencies = Array.Empty<BundleDependency>();
/// <summary>
/// Convert BundleDependencyMap to a format that is able to be serialized and plays nicer with
/// CalculateEfficiency - this must be called on a bundle before CalculateEfficiency can be called.
/// </summary>
internal void SerializeBundleToBundleDependency()
{
BundleDependencies = new BundleDependency[BundleDependencyMap.Values.Count];
BundleDependencyMap.Values.CopyTo(BundleDependencies, 0);
}
/// <summary>
/// Updates the BundleDependency from the current bundle to the bundle that contains referencedAsset. If no such BundleDependency exists,
/// one is created. Does nothing if rootAsset's bundle is not the current bundle or
/// if the two assets are in the same bundle.
/// </summary>
/// <param name="rootAsset"></param>
/// <param name="referencedAsset"></param>
internal void UpdateBundleDependency(ExplicitAsset rootAsset, ExplicitAsset referencedAsset)
{
if (rootAsset.Bundle != this || referencedAsset.Bundle == rootAsset.Bundle)
return;
if (!BundleDependencyMap.ContainsKey(referencedAsset.Bundle))
BundleDependencyMap.Add(referencedAsset.Bundle, new BundleDependency(referencedAsset.Bundle));
BundleDependencyMap[referencedAsset.Bundle].CreateAssetDependency(rootAsset, referencedAsset);
}
// Helper struct for calculating Efficiency
internal struct EfficiencyInfo
{
internal ulong totalAssetFileSize;
internal ulong referencedAssetFileSize;
}
/// <summary>
/// The Compression method used for the AssetBundle.
/// </summary>
public string Compression;
/// <summary>
/// Cyclic redundancy check of the content contained inside of the asset bundle.
/// This value will not change between identical asset bundles with different compression options.
/// </summary>
public uint CRC;
/// <summary>
/// The hash version of the contents contained inside of the asset bundle.
/// This value will not change between identical asset bundles with different compression options.
/// </summary>
public Hash128 Hash;
/// <summary>
/// A reference to the Group data that this AssetBundle was generated from
/// </summary>
[SerializeReference]
public Group Group;
/// <summary>
/// Path Provider uses to load the Asset Bundle
/// </summary>
public string LoadPath;
/// <summary>
/// Provider used to load the Asset Bundle
/// </summary>
public string Provider;
/// <summary>
/// Result provided by the Provider loading the Asset Bundle
/// </summary>
public string ResultType;
/// <summary>
/// List of the Files referenced by the AssetBundle
/// </summary>
[SerializeReference]
public List<File> Files = new List<File>();
/// <summary>
/// A list of the bundles that directly depend on this AssetBundle
/// </summary>
[SerializeReference]
public List<Bundle> DependentBundles = new List<Bundle>();
/// <summary>
/// A list of the direct dependencies of the AssetBundle
/// </summary>
[SerializeReference]
public List<Bundle> Dependencies;
/// <summary>
/// The second order dependencies and greater of a bundle
/// </summary>
[SerializeReference]
public List<Bundle> ExpandedDependencies;
}
/// <summary>
/// Data store for resource files generated by the build pipeline and referenced by a main File
/// </summary>
[Serializable]
public class SubFile
{
/// <summary>
/// The name of the sub-file
/// </summary>
public string Name;
/// <summary>
/// If the main File is a serialized file, this will be true.
/// </summary>
public bool IsSerializedFile;
/// <summary>
/// The size of the sub-file, in bytes
/// </summary>
public ulong Size;
}
/// <summary>
/// Data store for the main File created for the AssetBundle
/// </summary>
[Serializable]
public class File
{
/// <summary>
/// The name of the File.
/// </summary>
public string Name;
/// <summary>
/// The AssetBundle data that relates to a built file.
/// </summary>
[SerializeReference]
public Bundle Bundle;
/// <summary>
/// The file size of the AssetBundle on disk when uncompressed, in bytes
/// </summary>
public ulong UncompressedSize
{
get
{
ulong total = 0;
foreach (SubFile subFile in SubFiles)
total += subFile.Size;
return total;
}
}
/// <summary>
/// List of the resource files created by the build pipeline that a File references
/// </summary>
[SerializeReference]
public List<SubFile> SubFiles = new List<SubFile>();
/// <summary>
/// A list of the explicit asset defined in the AssetBundle
/// </summary>
[SerializeReference]
public List<ExplicitAsset> Assets = new List<ExplicitAsset>();
/// <summary>
/// A list of implicit assets built into the AssetBundle, typically through references by Assets that are explicitly defined.
/// </summary>
[SerializeReference]
public List<DataFromOtherAsset> OtherAssets = new List<DataFromOtherAsset>();
[SerializeReference]
internal List<ExplicitAsset> ExternalReferences = new List<ExplicitAsset>();
/// <summary>
/// The final filename of the AssetBundle file
/// </summary>
public string WriteResultFilename;
/// <summary>
/// Data about the AssetBundleObject
/// </summary>
public AssetBundleObjectInfo BundleObjectInfo;
/// <summary>
/// The size of the data that needs to be preloaded for this File.
/// </summary>
public int PreloadInfoSize;
/// <summary>
/// The number of Mono scripts referenced by the File
/// </summary>
public int MonoScriptCount;
/// <summary>
/// The size of the Mono scripts referenced by the File
/// </summary>
public ulong MonoScriptSize;
}
/// <summary>
/// A representation of an object in an asset file.
/// </summary>
[Serializable]
public class ObjectData
{
/// <summary>
/// FileId of Object in Asset File
/// </summary>
public long LocalIdentifierInFile;
/// <summary>
/// Object name within the Asset
/// </summary>
[SerializeField] internal string ObjectName;
/// <summary>
/// Component name if AssetType is a MonoBehaviour or Component
/// </summary>
[SerializeField] internal string ComponentName;
/// <summary>
/// Type of Object
/// </summary>
public AssetType AssetType;
/// <summary>
/// The size of the file on disk.
/// </summary>
public ulong SerializedSize;
/// <summary>
/// The size of the streamed Asset.
/// </summary>
public ulong StreamedSize;
/// <summary>
/// References to other Objects
/// </summary>
[SerializeField] internal List<ObjectReference> References = new List<ObjectReference>();
}
/// <summary>
/// Identification of an Object within the same file
/// </summary>
[Serializable]
internal class ObjectReference
{
public int AssetId;
public List<int> ObjectIds;
}
/// <summary>
/// Data store for Assets explicitly defined in an AssetBundle
/// </summary>
[Serializable]
public class ExplicitAsset
{
/// <summary>
/// The Asset Guid.
/// </summary>
public string Guid;
/// <summary>
/// The Asset path on disk
/// </summary>
public string AssetPath;
/// <summary>
/// Name used to identify the asset within the asset bundle containing it
/// </summary>
public string InternalId;
/// <summary>
/// Hash of the asset content
/// </summary>
public Hash128 AssetHash;
/// <summary>
/// Objects that consist of the overall asset
/// </summary>
public List<ObjectData> Objects = new List<ObjectData>();
/// <summary>
/// AssetType of the main Object for the Asset
/// </summary>
public AssetType MainAssetType;
/// <summary>
/// True if is a scene asset, else false
/// </summary>
public bool IsScene => AssetPath.EndsWith(".unity", StringComparison.Ordinal);
/// <summary>
/// Guid of the Addressable group this Asset entry was built using.
/// </summary>
public string GroupGuid;
/// <summary>
/// The Addressable address defined in the Addressable Group window for an Asset.
/// </summary>
public string AddressableName;
/// <summary>
/// Addressable labels for this asset entry.
/// </summary>
[SerializeField]
public string[] Labels = Array.Empty<string>();
/// <summary>
/// The size of the file on disk.
/// </summary>
public ulong SerializedSize;
/// <summary>
/// The size of the streamed Asset.
/// </summary>
public ulong StreamedSize;
/// <summary>
/// The file that the Asset was added to
/// </summary>
[SerializeReference]
public File File;
/// <summary>
/// The AssetBundle that contains the asset
/// </summary>
[SerializeReference]
public Bundle Bundle;
/// <summary>
/// List of data from other Assets referenced by an Asset in the File
/// </summary>
[SerializeReference]
public List<DataFromOtherAsset> InternalReferencedOtherAssets = new List<DataFromOtherAsset>();
/// <summary>
/// List of explicit Assets referenced by this asset that are in the same AssetBundle
/// </summary>
[SerializeReference]
public List<ExplicitAsset> InternalReferencedExplicitAssets = new List<ExplicitAsset>();
/// <summary>
/// List of explicit Assets referenced by this asset that are in a different AssetBundle
/// </summary>
[SerializeReference]
public List<ExplicitAsset> ExternallyReferencedAssets = new List<ExplicitAsset>();
/// <summary>
/// List of Assets that reference this Asset
/// </summary>
[SerializeReference]
internal List<ExplicitAsset> ReferencingAssets = new List<ExplicitAsset>();
}
/// <summary>
/// Data store for implicit Asset references
/// </summary>
[Serializable]
public class DataFromOtherAsset
{
/// <summary>
/// The Guid of the Asset
/// </summary>
public string AssetGuid;
/// <summary>
/// The Asset path on disk
/// </summary>
public string AssetPath;
/// <summary>
/// The file that the Asset was added to
/// </summary>
[SerializeReference]
public File File;
/// <summary>
/// Objects that consist of the overall asset
/// </summary>
public List<ObjectData> Objects = new List<ObjectData>();
/// <summary>
/// AssetType of the main Object for the Asset
/// </summary>
public AssetType MainAssetType;
/// <summary>
/// True if is a scene asset, else false
/// </summary>
public bool IsScene => AssetPath.EndsWith(".unity", StringComparison.Ordinal);
/// <summary>
/// A list of Assets that reference this data
/// </summary>
[SerializeReference]
public List<ExplicitAsset> ReferencingAssets = new List<ExplicitAsset>();
/// <summary>
/// The number of Objects in the data
/// </summary>
public int ObjectCount;
/// <summary>
/// The size of the data on disk
/// </summary>
public ulong SerializedSize;
/// <summary>
/// The size of the streamed data
/// </summary>
public ulong StreamedSize;
}
/// <summary>
/// Data store for duplicated Implicit Asset information
/// </summary>
[Serializable]
public class AssetDuplicationData
{
/// <summary>
/// The Guid of the Asset with duplicates
/// </summary>
public string AssetGuid;
/// <summary>
/// A list of duplicated objects and the bundles that contain them.
/// </summary>
public List<ObjectDuplicationData> DuplicatedObjects = new List<ObjectDuplicationData>();
}
/// <summary>
/// Data store for duplicated Object information
/// </summary>
[Serializable]
public class ObjectDuplicationData
{
/// <summary>
/// The local identifier for an object.
/// </summary>
public long LocalIdentifierInFile;
/// <summary>
/// A list of bundles that include the referenced file.
/// </summary>
[SerializeReference] public List<File> IncludedInBundleFiles = new List<File>();
}
}
/// <summary>
/// Utility used to quickly reference data built with the build pipeline
/// </summary>
public class LayoutLookupTables
{
/// <summary>
/// The default AssetBundle name to the Bundle data map.
/// </summary>
public Dictionary<string, BuildLayout.Bundle> Bundles = new Dictionary<string, BuildLayout.Bundle>();
/// <summary>
/// File name to File data map.
/// </summary>
public Dictionary<string, BuildLayout.File> Files = new Dictionary<string, BuildLayout.File>();
internal Dictionary<BuildLayout.File, FileObjectData> FileToFileObjectData = new Dictionary<BuildLayout.File, FileObjectData>();
/// <summary>
/// Guid to ExplicitAsset data map.
/// </summary>
public Dictionary<string, BuildLayout.ExplicitAsset> GuidToExplicitAsset = new Dictionary<string, BuildLayout.ExplicitAsset>();
/// <summary>
/// Group name to Group data map.
/// </summary>
public Dictionary<string, BuildLayout.Group> GroupLookup = new Dictionary<string, BuildLayout.Group>();
/// <summary>
/// The remapped AssetBundle name to the Bundle data map
/// </summary>
internal Dictionary<string, BuildLayout.Bundle> FilenameToBundle = new Dictionary<string, BuildLayout.Bundle>();
/// Maps used for lookups while building the BuildLayout
internal Dictionary<string, List<BuildLayout.DataFromOtherAsset>> UsedImplicits = new Dictionary<string, List<BuildLayout.DataFromOtherAsset>>();
internal Dictionary<string, AssetBundleRequestOptions> BundleNameToRequestOptions = new Dictionary<string, AssetBundleRequestOptions>();
internal Dictionary<string, AssetBundleRequestOptions> BundleNameToPreviousRequestOptions = new Dictionary<string, AssetBundleRequestOptions>();
internal Dictionary<string, ContentCatalogDataEntry> BundleNameToCatalogEntry = new Dictionary<string, ContentCatalogDataEntry>();
internal Dictionary<string, string> GroupNameToBuildPath = new Dictionary<string, string>();
internal Dictionary<string, AddressableAssetEntry> GuidToEntry = new Dictionary<string, AddressableAssetEntry>();
internal Dictionary<string, AssetType> AssetPathToTypeMap = new Dictionary<string, AssetType>();
}
internal class FileObjectData
{
// id's for internal explicit asset and implicit asset
public Dictionary<ObjectIdentifier, (int, int)> InternalObjectIds = new Dictionary<ObjectIdentifier, (int, int)>();
public Dictionary<BuildLayout.ObjectData, ObjectIdentifier> Objects = new Dictionary<BuildLayout.ObjectData, ObjectIdentifier>();
public void Add(ObjectIdentifier buildObjectIdentifier, BuildLayout.ObjectData layoutObject, int assetId, int objectIndex)
{
InternalObjectIds[buildObjectIdentifier] = (assetId, objectIndex);
Objects[layoutObject] = buildObjectIdentifier;
}
public bool TryGetObjectReferenceData(ObjectIdentifier obj, out (int, int) value)
{
if (!InternalObjectIds.TryGetValue(obj, out (int, int) data))
{
value = default;
return false;
}
value = data;
return true;
}
public bool TryGetObjectIdentifier(BuildLayout.ObjectData obj, out ObjectIdentifier objectIdOut)
{
if (!Objects.TryGetValue(obj, out objectIdOut))
{
objectIdOut = default;
return false;
}
return true;
}
}
}