initial commit

This commit is contained in:
Jo 2025-01-07 02:06:59 +01:00
parent 6715289efe
commit 788c3389af
37645 changed files with 2526849 additions and 80 deletions

View file

@ -0,0 +1,65 @@
using System;
using UnityEditor.Build.Pipeline.Interfaces;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Basic implementation of IDependencyCallback, IPackingCallback, IWritingCallback, and IScriptsCallback.
/// Uses Func implementation for callbacks. <seealso cref="IDependencyCallback"/>, <seealso cref="IPackingCallback"/>
/// <seealso cref="IWritingCallback"/>, and <seealso cref="IScriptsCallback"/>
/// </summary>
public class BuildCallbacks : IDependencyCallback, IPackingCallback, IWritingCallback, IScriptsCallback
{
/// <summary>
/// Func delegate for the callback after scripts have been compiled.
/// </summary>
public Func<IBuildParameters, IBuildResults, ReturnCode> PostScriptsCallbacks { get; set; }
/// <summary>
/// Func delegate for the callback after dependency calculation has occurred.
/// </summary>
public Func<IBuildParameters, IDependencyData, ReturnCode> PostDependencyCallback { get; set; }
/// <summary>
/// Func delegate for the callback after packing has occurred.
/// </summary>
public Func<IBuildParameters, IDependencyData, IWriteData, ReturnCode> PostPackingCallback { get; set; }
/// <summary>
/// Func delegate for the callback after writing content has occurred.
/// </summary>
public Func<IBuildParameters, IDependencyData, IWriteData, IBuildResults, ReturnCode> PostWritingCallback { get; set; }
/// <inheritdoc />
public ReturnCode PostScripts(IBuildParameters parameters, IBuildResults results)
{
if (PostScriptsCallbacks != null)
return PostScriptsCallbacks(parameters, results);
return ReturnCode.Success;
}
/// <inheritdoc />
public ReturnCode PostDependency(IBuildParameters buildParameters, IDependencyData dependencyData)
{
if (PostDependencyCallback != null)
return PostDependencyCallback(buildParameters, dependencyData);
return ReturnCode.Success;
}
/// <inheritdoc />
public ReturnCode PostPacking(IBuildParameters buildParameters, IDependencyData dependencyData, IWriteData writeData)
{
if (PostPackingCallback != null)
return PostPackingCallback(buildParameters, dependencyData, writeData);
return ReturnCode.Success;
}
/// <inheritdoc />
public ReturnCode PostWriting(IBuildParameters parameters, IDependencyData dependencyData, IWriteData writeData, IBuildResults results)
{
if (PostWritingCallback != null)
return PostWritingCallback(parameters, dependencyData, writeData, results);
return ReturnCode.Success;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 98f1571a4d4b4a3f8a65343e6ca1966d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
#if UNITY_2019_3_OR_NEWER
using UnityEditor.Build.Content;
#endif
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline.Utilities;
namespace UnityEditor.Build.Pipeline
{
#if UNITY_2019_3_OR_NEWER
/// <summary>
/// Basic implementation of ICustomAssets. Stores the list of Custom Assets generated during the Scriptable Build Pipeline.
/// <seealso cref="ICustomAssets"/>
/// </summary>
[Serializable]
public class CustomAssets : ICustomAssets
{
/// <inheritdoc />
public List<GUID> Assets { get; private set; }
/// <summary>
/// Default constructor, creates an empty CustomAssets.
/// </summary>
public CustomAssets()
{
Assets = new List<GUID>();
}
}
#endif
/// <summary>
/// Basic implementation of IBuildContent. Stores the list of Assets to feed the Scriptable Build Pipeline.
/// <seealso cref="IBuildContent"/>
/// </summary>
[Serializable]
public class BuildContent : IBuildContent
{
/// <inheritdoc />
public List<GUID> Assets { get; private set; }
/// <inheritdoc />
public List<GUID> Scenes { get; private set; }
#if UNITY_2019_3_OR_NEWER
/// <inheritdoc />
public List<CustomContent> CustomAssets { get; private set; }
#endif
/// <summary>
/// Default constructor, creates an empty BuildContent.
/// </summary>
public BuildContent() {}
/// <summary>
/// Default constructor, takes a set of Assets and converts them to the appropriate properties.
/// </summary>
/// <param name="assets">The set of Assets identified by GUID to ensure are packaged with the build</param>
public BuildContent(IEnumerable<GUID> assets)
{
if (assets == null)
throw new ArgumentNullException("assets");
Assets = new List<GUID>();
Scenes = new List<GUID>();
#if UNITY_2019_3_OR_NEWER
CustomAssets = new List<CustomContent>();
#endif
foreach (var asset in assets)
{
ValidationMethods.Status assetType = ValidationMethods.ValidAsset(asset);
if (assetType == ValidationMethods.Status.Asset)
Assets.Add(asset);
else if (assetType == ValidationMethods.Status.Scene)
Scenes.Add(asset);
else
throw new ArgumentException(string.Format("Asset '{0}' is not a valid Asset or Scene.", asset.ToString()));
}
}
}
/// <summary>
/// Basic implementation of IBundleBuildContent. Stores the list of Assets with explicit Asset Bundle layout to feed the Scriptable Build Pipeline.
/// <seealso cref="IBundleBuildContent"/>
/// </summary>
[Serializable]
public class BundleBuildContent : IBundleBuildContent
{
/// <inheritdoc />
public List<GUID> Assets { get; private set; }
/// <inheritdoc />
public List<GUID> Scenes { get; private set; }
#if UNITY_2019_3_OR_NEWER
/// <inheritdoc />
public List<CustomContent> CustomAssets { get; private set; }
/// <inheritdoc />
public Dictionary<string, List<ResourceFile>> AdditionalFiles { get; private set; }
#endif
/// <inheritdoc />
public Dictionary<GUID, string> Addresses { get; private set; }
/// <inheritdoc />
public Dictionary<string, List<GUID>> BundleLayout { get; private set; }
/// <summary>
/// Default constructor, creates an empty BundleBuildContent.
/// </summary>
public BundleBuildContent() {}
/// <summary>
/// Default constructor, takes a set of AssetBundleBuild and converts them to the appropriate properties.
/// </summary>
/// <param name="bundleBuilds">The set of AssetbundleBuild to be built.</param>
public BundleBuildContent(IEnumerable<AssetBundleBuild> bundleBuilds)
{
if (bundleBuilds == null)
throw new ArgumentNullException("bundleBuilds");
Assets = new List<GUID>();
Scenes = new List<GUID>();
Addresses = new Dictionary<GUID, string>();
BundleLayout = new Dictionary<string, List<GUID>>();
#if UNITY_2019_3_OR_NEWER
CustomAssets = new List<CustomContent>();
AdditionalFiles = new Dictionary<string, List<ResourceFile>>();
#endif
foreach (var bundleBuild in bundleBuilds)
{
List<GUID> guids;
BundleLayout.GetOrAdd(bundleBuild.assetBundleName, out guids);
ValidationMethods.Status bundleType = ValidationMethods.Status.Invalid;
for (int i = 0; i < bundleBuild.assetNames.Length; i++)
{
string assetPath = bundleBuild.assetNames[i];
GUID asset = new GUID(AssetDatabase.AssetPathToGUID(assetPath));
// Ensure the path is valid
ValidationMethods.Status status = ValidationMethods.ValidAsset(asset);
if (status == ValidationMethods.Status.Invalid)
throw new ArgumentException(string.Format("Asset '{0}' is not a valid Asset or Scene.", assetPath));
// Ensure we do not have a mixed bundle
if (bundleType == ValidationMethods.Status.Invalid)
bundleType = status;
else if (bundleType != status)
throw new ArgumentException(string.Format("Asset Bundle '{0}' is invalid because it contains mixed Asset and Scene types.", bundleBuild.assetBundleName));
string address = bundleBuild.addressableNames != null && i < bundleBuild.addressableNames.Length && !string.IsNullOrEmpty(bundleBuild.addressableNames[i]) ?
bundleBuild.addressableNames[i] : AssetDatabase.GUIDToAssetPath(asset.ToString());
// Add the guid to the bundle map
guids.Add(asset);
// Add the guid & address
Addresses.Add(asset, address);
// Add the asset to the correct collection
if (status == ValidationMethods.Status.Asset)
Assets.Add(asset);
else if (status == ValidationMethods.Status.Scene)
Scenes.Add(asset);
}
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6616141fe64e4fc2b16c015f32d0a64d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEngine;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Basic implementation of IBuildContext. Stores data generated during a build.
/// <seealso cref="IBuildContext"/>
/// </summary>
public class BuildContext : IBuildContext
{
internal Dictionary<Type, IContextObject> m_ContextObjects;
/// <summary>
/// Default constructor
/// </summary>
public BuildContext()
{
m_ContextObjects = new Dictionary<Type, IContextObject>();
}
/// <summary>
/// Default constructor, adds the passed in parameters to the context.
/// </summary>
/// <param name="buildParams">The set of initial parameters to add to the context.</param>
public BuildContext(params IContextObject[] buildParams)
{
m_ContextObjects = new Dictionary<Type, IContextObject>();
if (buildParams == null)
return;
foreach (var buildParam in buildParams)
{
if (buildParam != null)
SetContextObject(buildParam);
}
}
/// <inheritdoc />
public void SetContextObject<T>(IContextObject contextObject) where T : IContextObject
{
if (contextObject == null)
throw new ArgumentNullException("contextObject");
var type = typeof(T);
if (!type.IsInterface)
throw new InvalidOperationException(string.Format("Passed in type '{0}' is not an interface.", type));
if (!(contextObject is T))
throw new InvalidOperationException(string.Format("'{0}' is not of passed in type '{1}'.", contextObject.GetType(), type));
m_ContextObjects[typeof(T)] = contextObject;
}
/// <inheritdoc />
public void SetContextObject(Type type, IContextObject contextObject)
{
if (contextObject == null)
throw new ArgumentNullException("contextObject");
if (!type.IsInterface)
throw new InvalidOperationException(string.Format("Passed in type '{0}' is not an interface.", type));
if (!type.IsInstanceOfType(contextObject))
throw new InvalidOperationException(string.Format("'{0}' is not of passed in type '{1}'.", contextObject.GetType(), type));
m_ContextObjects[type] = contextObject;
}
private IEnumerable<Type> WalkAssignableTypes(IContextObject contextObject)
{
var iCType = typeof(IContextObject);
foreach (Type t in contextObject.GetType().GetInterfaces())
{
if (iCType.IsAssignableFrom(t) && t != iCType)
yield return t;
}
for (var current = contextObject.GetType(); current != null; current = current.BaseType)
if (iCType.IsAssignableFrom(current) && current != iCType)
yield return current;
}
/// <inheritdoc />
public void SetContextObject(IContextObject contextObject)
{
if (contextObject == null)
throw new ArgumentNullException("contextObject");
List<Type> types = new List<Type>(WalkAssignableTypes(contextObject));
if (types.Count == 0)
throw new Exception($"Could not determine context object type for object of type {contextObject.GetType().FullName}");
types.ForEach(x => m_ContextObjects[x] = contextObject);
}
/// <inheritdoc />
public bool ContainsContextObject<T>() where T : IContextObject
{
return ContainsContextObject(typeof(T));
}
/// <inheritdoc />
public bool ContainsContextObject(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
return m_ContextObjects.ContainsKey(type);
}
/// <inheritdoc />
public T GetContextObject<T>() where T : IContextObject
{
return (T)GetContextObject(typeof(T));
}
/// <inheritdoc />
public IContextObject GetContextObject(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
if (!m_ContextObjects.ContainsKey(type))
throw new Exception($"Object of Type {type} was not available within the BuildContext");
return m_ContextObjects[type];
}
/// <inheritdoc />
public bool TryGetContextObject<T>(out T contextObject) where T : IContextObject
{
IContextObject cachedContextObject;
if (m_ContextObjects.TryGetValue(typeof(T), out cachedContextObject) && cachedContextObject is T)
{
contextObject = (T)cachedContextObject;
return true;
}
contextObject = default(T);
return false;
}
/// <inheritdoc />
public bool TryGetContextObject(Type type, out IContextObject contextObject)
{
IContextObject cachedContextObject;
if (m_ContextObjects.TryGetValue(type, out cachedContextObject) && type.IsInstanceOfType(cachedContextObject))
{
contextObject = cachedContextObject;
return true;
}
contextObject = null;
return false;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fdd470c95bb040bdb705dc362b132291
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using UnityEditor.Build.Content;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline.Utilities;
using UnityEngine;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Basic implementation of IDependencyData. Stores the dependency and usage data calculated during a build.
/// <seealso cref="IDependencyData"/>
/// </summary>
[Serializable]
public class BuildDependencyData : IDependencyData
{
/// <inheritdoc />
public Dictionary<GUID, AssetLoadInfo> AssetInfo { get; private set; }
/// <inheritdoc />
public Dictionary<GUID, BuildUsageTagSet> AssetUsage { get; private set; }
/// <inheritdoc />
public Dictionary<GUID, SceneDependencyInfo> SceneInfo { get; private set; }
/// <inheritdoc />
public Dictionary<GUID, BuildUsageTagSet> SceneUsage { get; private set; }
/// <inheritdoc />
public Dictionary<GUID, Hash128> DependencyHash { get; private set; }
/// <summary>
/// Stores how lighting information is being used during a build.
/// </summary>
public BuildUsageTagGlobal GlobalUsage { get; set; }
[NonSerialized]
BuildUsageCache m_BuildUsageCache;
/// <summary>
/// Stores the dependency caching object.
/// </summary>
public BuildUsageCache DependencyUsageCache
{
get
{
if (m_BuildUsageCache == null)
m_BuildUsageCache = new BuildUsageCache();
return m_BuildUsageCache;
}
}
/// <summary>
/// Default constructor, initializes properties to defaults
/// </summary>
public BuildDependencyData()
{
AssetInfo = new Dictionary<GUID, AssetLoadInfo>();
AssetUsage = new Dictionary<GUID, BuildUsageTagSet>();
SceneInfo = new Dictionary<GUID, SceneDependencyInfo>();
SceneUsage = new Dictionary<GUID, BuildUsageTagSet>();
DependencyHash = new Dictionary<GUID, Hash128>();
m_BuildUsageCache = new BuildUsageCache();
GlobalUsage = GraphicsSettingsApi.GetGlobalUsage();
}
}
/// <summary>
/// Basic implementation of IObjectDependencyData. Stores the dependencies between objects calculated during a build.
/// <seealso cref="IObjectDependencyData"/>
/// </summary>
[Serializable]
internal class ObjectDependencyData : IObjectDependencyData
{
/// <inheritdoc />
public Dictionary<ObjectIdentifier, List<ObjectIdentifier>> ObjectDependencyMap { get; }
/// <summary>
/// Default constructor, initializes properties to defaults
/// </summary>
public ObjectDependencyData()
{
ObjectDependencyMap = new Dictionary<ObjectIdentifier, List<ObjectIdentifier>>();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 48594b0afbd3e84448546c74bf35a6b3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using UnityEditor.Build.Pipeline.Interfaces;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Basic implementation of IBuildExtendedAssetData. Stores the extended data about an asset in the build.
/// <seealso cref="IBuildExtendedAssetData"/>
/// </summary>
[Serializable]
public class BuildExtendedAssetData : IBuildExtendedAssetData
{
/// <inheritdoc />
public Dictionary<GUID, ExtendedAssetData> ExtendedData { get; private set; }
/// <summary>
/// Default constructor, initializes properties to defaults
/// </summary>
public BuildExtendedAssetData()
{
ExtendedData = new Dictionary<GUID, ExtendedAssetData>();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9b0e503817aafa447ac3b7d7db84ccc8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,189 @@
using System;
using UnityEditor.Build.Content;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline.Utilities;
using UnityEditor.Build.Player;
using UnityEngine;
namespace UnityEditor.Build.Pipeline
{
#if UNITY_2018_3_OR_NEWER
using BuildCompression = UnityEngine.BuildCompression;
#else
using BuildCompression = UnityEditor.Build.Content.BuildCompression;
#endif
/// <summary>
/// Basic implementation of IBuildParameters. Stores the set of parameters passed into the Scriptable Build Pipeline.
/// <seealso cref="IBuildParameters"/>
/// </summary>
[Serializable]
public class BuildParameters : IBuildParameters
{
/// <inheritdoc />
public BuildTarget Target { get; set; }
/// <inheritdoc />
public BuildTargetGroup Group { get; set; }
/// <inheritdoc />
public ContentBuildFlags ContentBuildFlags { get; set; }
/// <inheritdoc />
public TypeDB ScriptInfo { get; set; }
/// <inheritdoc />
public ScriptCompilationOptions ScriptOptions { get; set; }
/// <summary>
/// Default compression option to use for all built content files
/// </summary>
public BuildCompression BundleCompression { get; set; }
/// <summary>
/// Final output location where built content will be written.
/// </summary>
public string OutputFolder { get; set; }
string m_TempOutputFolder;
/// <inheritdoc />
public string TempOutputFolder
{
get { return m_TempOutputFolder; }
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("Argument cannot be null or empty.", "value");
m_TempOutputFolder = value;
}
}
string m_ScriptOutputFolder;
/// <inheritdoc />
public string ScriptOutputFolder
{
get { return m_ScriptOutputFolder; }
set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("Argument cannot be null or empty.", "value");
m_ScriptOutputFolder = value;
}
}
/// <inheritdoc />
public bool UseCache { get; set; }
/// <inheritdoc />
public string CacheServerHost { get; set; }
/// <inheritdoc />
public int CacheServerPort { get; set; }
/// <inheritdoc />
public bool WriteLinkXML { get; set; }
#if NONRECURSIVE_DEPENDENCY_DATA
/// <inheritdoc />
public bool NonRecursiveDependencies { get; set; }
#endif
internal BuildParameters() {}
/// <summary>
/// Default constructor, requires the target, group and output parameters at minimum for a successful build.
/// </summary>
/// <param name="target">The target for building content.</param>
/// <param name="group">The group for building content.</param>
/// <param name="outputFolder">The final output location for built content.</param>
public BuildParameters(BuildTarget target, BuildTargetGroup group, string outputFolder)
{
if (string.IsNullOrEmpty(outputFolder))
throw new ArgumentException("Argument cannot be null or empty.", "outputFolder");
Target = target;
Group = group;
// TODO: Validate target & group
ScriptInfo = null;
ScriptOptions = ScriptCompilationOptions.None;
#if UNITY_2018_3_OR_NEWER
BundleCompression = BuildCompression.LZMA;
#else
BundleCompression = BuildCompression.DefaultLZMA;
#endif
OutputFolder = outputFolder;
TempOutputFolder = ContentPipeline.kTempBuildPath;
ScriptOutputFolder = ContentPipeline.kScriptBuildPath;
UseCache = true;
CacheServerPort = 8126;
if (ScriptableBuildPipeline.UseBuildCacheServer)
{
CacheServerHost = ScriptableBuildPipeline.CacheServerHost;
CacheServerPort = ScriptableBuildPipeline.CacheServerPort;
}
WriteLinkXML = false;
#if NONRECURSIVE_DEPENDENCY_DATA && UNITY_2021_1_OR_NEWER
NonRecursiveDependencies = true;
#endif
}
/// <inheritdoc />
public virtual BuildSettings GetContentBuildSettings()
{
return new BuildSettings
{
group = Group,
target = Target,
typeDB = ScriptInfo,
buildFlags = ContentBuildFlags
};
}
/// <inheritdoc />
public virtual ScriptCompilationSettings GetScriptCompilationSettings()
{
return new ScriptCompilationSettings
{
group = Group,
target = Target,
options = ScriptOptions
};
}
/// <inheritdoc />
public virtual string GetOutputFilePathForIdentifier(string identifier)
{
return string.Format("{0}/{1}", OutputFolder, identifier);
}
/// <inheritdoc />
public virtual BuildCompression GetCompressionForIdentifier(string identifier)
{
return BundleCompression;
}
}
/// <summary>
/// Stores the set of parameters passed into Scriptable Build Pipeline when building bundles.
/// </summary>
[Serializable]
public class BundleBuildParameters : BuildParameters, IBundleBuildParameters
{
internal BundleBuildParameters() {}
/// <inheritdoc />
public BundleBuildParameters(BuildTarget target, BuildTargetGroup group, string outputFolder)
: base(target, group, outputFolder)
{
#if UNITY_2021_1_OR_NEWER
ContiguousBundles = true;
#endif
}
/// <inheritdoc />
public bool AppendHash { get; set; }
/// <inheritdoc />
public bool ContiguousBundles { get; set; }
/// <inheritdoc />
public bool DisableVisibleSubAssetRepresentations { get; set; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 33d6ef15c1984642bd83826064bee25d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using UnityEditor.Build.Content;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Player;
using UnityEngine;
using UnityEngine.Build.Pipeline;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Additional MetaData that is associated with a serialized file write result
/// <seealso cref="IBuildResults"/>
/// </summary>
[Serializable]
public class SerializedFileMetaData
{
/// <summary>
/// A hash of all the serialized files
/// </summary>
public Hash128 RawFileHash;
/// <summary>
/// Hash of file contents. Some resource files may choose to exclude sections of their content from this hash. For example,
/// serialized files exclude the header of their content which allows this hash not to change with new Unity versions.
/// </summary>
public Hash128 ContentHash;
}
/// <summary>
/// Basic implementation of IBuildResults. Stores the results for script compilation and content building.
/// <seealso cref="IBuildResults"/>
/// </summary>
[Serializable]
public class BuildResults : IBuildResults
{
/// <inheritdoc />
public ScriptCompilationResult ScriptResults { get; set; }
/// <inheritdoc />
public Dictionary<string, WriteResult> WriteResults { get; private set; }
/// <inheritdoc />
public Dictionary<string, SerializedFileMetaData> WriteResultsMetaData { get; private set; }
/// <inheritdoc />
public Dictionary<GUID, AssetResultData> AssetResults { get; private set; }
/// <summary>
/// Default constructor, initializes properties to defaults
/// </summary>
public BuildResults()
{
WriteResults = new Dictionary<string, WriteResult>();
}
}
/// <summary>
/// Basic implementation of IBundleBuildResults. Stores the results for script compilation and asset bundle building.
/// <seealso cref="IBundleBuildResults"/>
/// </summary>
[Serializable]
public class BundleBuildResults : IBundleBuildResults
{
/// <inheritdoc />
public ScriptCompilationResult ScriptResults { get; set; }
/// <inheritdoc />
public Dictionary<string, BundleDetails> BundleInfos { get; private set; }
/// <inheritdoc />
public Dictionary<string, WriteResult> WriteResults { get; private set; }
/// <inheritdoc />
public Dictionary<string, SerializedFileMetaData> WriteResultsMetaData { get; private set; }
/// <inheritdoc />
public Dictionary<GUID, AssetResultData> AssetResults { get; private set; }
/// <summary>
/// Default constructor, initializes properties to defaults
/// </summary>
public BundleBuildResults()
{
BundleInfos = new Dictionary<string, BundleDetails>();
WriteResults = new Dictionary<string, WriteResult>();
WriteResultsMetaData = new Dictionary<string, SerializedFileMetaData>();
AssetResults = new Dictionary<GUID, AssetResultData>();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 63ad63bf47749b944a87fce982b8b54b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using UnityEditor.Build.Pipeline.Interfaces;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Basic implementation of IBuildSpriteData. Stores the sprite importer data for a sprite asset in the build.
/// <seealso cref="IBuildSpriteData"/>
/// </summary>
[Serializable]
public class BuildSpriteData : IBuildSpriteData
{
/// <inheritdoc />
public Dictionary<GUID, SpriteImporterData> ImporterData { get; set; }
/// <summary>
/// Default constructor, initializes properties to defaults
/// </summary>
public BuildSpriteData()
{
ImporterData = new Dictionary<GUID, SpriteImporterData>();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 54aaf7e8e1f02d34182d881089f11f33
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,186 @@
using System;
using System.Collections.Generic;
using UnityEditor.Build.Pipeline.Injector;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline.Utilities;
using UnityEditor.Build.Profiler;
using UnityEditor.Build.Reporting;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Basic static class containing default implementations for BuildTask validation and running.
/// </summary>
public static class BuildTasksRunner
{
/// <summary>
/// Basic run implementation that takes a set of tasks, a context, and runs returning the build results.
/// <seealso cref="IBuildTask"/>, <seealso cref="IBuildContext"/>, and <seealso cref="ReturnCode"/>
/// </summary>
/// <param name="pipeline">The set of build tasks to run.</param>
/// <param name="context">The build context to use for this run.</param>
/// <returns>Return code with status information about success or failure causes.</returns>
public static ReturnCode Run(IList<IBuildTask> pipeline, IBuildContext context)
{
// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
if (pipeline == null)
{
BuildLogger.LogException(new ArgumentNullException("pipeline"));
return ReturnCode.Exception;
}
// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
if (context == null)
{
BuildLogger.LogException(new ArgumentNullException("context"));
return ReturnCode.Exception;
}
IProgressTracker tracker;
if (context.TryGetContextObject(out tracker))
tracker.TaskCount = pipeline.Count;
context.TryGetContextObject(out IBuildLogger logger);
foreach (IBuildTask task in pipeline)
{
{
try
{
if (!tracker.UpdateTaskUnchecked(task.GetType().Name.HumanReadable()))
return ReturnCode.Canceled;
ContextInjector.Inject(context, task);
ReturnCode result;
using (logger.ScopedStep(LogLevel.Info, task.GetType().Name))
result = task.Run();
if (result < ReturnCode.Success)
return result;
ContextInjector.Extract(context, task);
}
catch (Exception e)
{
BuildLogger.LogError("Build Task {0} failed with exception:\n{1}\n{2}", task.GetType().Name, e.Message, e.StackTrace);
return ReturnCode.Exception;
}
}
}
if (tracker is IDisposable disposable)
disposable.Dispose();
return ReturnCode.Success;
}
/// <summary>
/// Run implementation with task profiler that takes a set of tasks, a context, runs returning the build results and prints out the profiler details.
/// <seealso cref="IBuildTask"/>, <seealso cref="IBuildContext"/>, and <seealso cref="ReturnCode"/>
/// </summary>
/// <param name="pipeline">The set of build tasks to run.</param>
/// <param name="context">The build context to use for this run.</param>
/// <returns>Return code with status information about success or failure causes.</returns>
internal static ReturnCode RunProfiled(IList<IBuildTask> pipeline, IBuildContext context)
{
// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
if (pipeline == null)
{
BuildLogger.LogException(new ArgumentNullException("pipeline"));
return ReturnCode.Exception;
}
// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
if (context == null)
{
BuildLogger.LogException(new ArgumentNullException("context"));
return ReturnCode.Exception;
}
var profiler = new BuildProfiler(pipeline.Count + 1);
profiler.Start(pipeline.Count, "TotalTime");
int count = 0;
IProgressTracker tracker;
if (context.TryGetContextObject(out tracker))
tracker.TaskCount = pipeline.Count;
foreach (IBuildTask task in pipeline)
{
try
{
if (!tracker.UpdateTaskUnchecked(task.GetType().Name.HumanReadable()))
{
profiler.Stop(pipeline.Count);
profiler.Print();
return ReturnCode.Canceled;
}
ContextInjector.Inject(context, task);
profiler.Start(count, task.GetType().Name);
var result = task.Run();
profiler.Stop(count++);
if (result < ReturnCode.Success)
{
profiler.Stop(pipeline.Count);
profiler.Print();
return result;
}
ContextInjector.Extract(context, task);
}
catch (Exception e)
{
BuildLogger.LogException(e);
profiler.Stop(count);
profiler.Print();
return ReturnCode.Exception;
}
}
profiler.Stop(pipeline.Count);
profiler.Print();
return ReturnCode.Success;
}
/// <summary>
/// Basic validate implementation that takes a set of tasks, a context, and does checks to ensure the task requirements are all satisfied.
/// <seealso cref="IBuildTask"/>, <seealso cref="IBuildContext"/>, and <seealso cref="ReturnCode"/>
/// </summary>
/// <param name="pipeline">The set of build tasks to run.</param>
/// <param name="context">The build context to use for this run.</param>
/// <returns>Return code with status information about success or failure causes.</returns>
public static ReturnCode Validate(IList<IBuildTask> pipeline, IBuildContext context)
{
//// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
//if (pipeline == null)
//{
// BuildLogger.LogException(new ArgumentNullException("pipeline"));
// return ReturnCode.Exception;
//}
//// Avoid throwing exceptions in here as we don't want them bubbling up to calling user code
//if (context == null)
//{
// BuildLogger.LogException(new ArgumentNullException("context"));
// return ReturnCode.Exception;
//}
//var requiredTypes = new HashSet<Type>();
//foreach (IBuildTask task in pipeline)
// requiredTypes.UnionWith(task.RequiredContextTypes);
//var missingTypes = new List<string>();
//foreach (Type requiredType in requiredTypes)
//{
// if (!context.ContainsContextObject(requiredType))
// missingTypes.Add(requiredType.Name);
//}
//if (missingTypes.Count > 0)
//{
// BuildLogger.LogError("Missing required object types to run build pipeline:\n{0}", string.Join(", ", missingTypes.ToArray()));
// return ReturnCode.MissingRequiredObjects;
//}
return ReturnCode.Success;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cba3bf5fbe905c841b9ace7d603fb1d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using UnityEditor.Build.Content;
using UnityEditor.Build.Pipeline.Interfaces;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Basic implementation of IWriteData. Stores the write information calculated during a build.
/// <seealso cref="IWriteData"/>
/// </summary>
[Serializable]
public class BuildWriteData : IWriteData
{
/// <inheritdoc />
public Dictionary<GUID, List<string>> AssetToFiles { get; private set; }
/// <inheritdoc />
public Dictionary<string, List<ObjectIdentifier>> FileToObjects { get; private set; }
/// <inheritdoc />
public List<IWriteOperation> WriteOperations { get; private set; }
/// <summary>
/// Default constructor, initializes properties to defaults
/// </summary>
public BuildWriteData()
{
AssetToFiles = new Dictionary<GUID, List<string>>();
FileToObjects = new Dictionary<string, List<ObjectIdentifier>>();
WriteOperations = new List<IWriteOperation>();
}
}
/// <summary>
/// Basic implementation of IBundleWriteData. Stores the asset bundle write information calculated during a build.
/// <seealso cref="IBundleWriteData"/>
/// </summary>
[Serializable]
public class BundleWriteData : IBundleWriteData
{
/// <inheritdoc />
public Dictionary<GUID, List<string>> AssetToFiles { get; private set; }
/// <inheritdoc />
public Dictionary<string, List<ObjectIdentifier>> FileToObjects { get; private set; }
/// <inheritdoc />
public Dictionary<string, string> FileToBundle { get; private set; }
/// <inheritdoc />
public Dictionary<string, BuildUsageTagSet> FileToUsageSet { get; private set; }
/// <inheritdoc />
public Dictionary<string, BuildReferenceMap> FileToReferenceMap { get; private set; }
/// <inheritdoc />
public List<IWriteOperation> WriteOperations { get; private set; }
/// <summary>
/// Default constructor, initializes properties to defaults
/// </summary>
public BundleWriteData()
{
AssetToFiles = new Dictionary<GUID, List<string>>();
FileToObjects = new Dictionary<string, List<ObjectIdentifier>>();
FileToBundle = new Dictionary<string, string>();
FileToUsageSet = new Dictionary<string, BuildUsageTagSet>();
FileToReferenceMap = new Dictionary<string, BuildReferenceMap>();
WriteOperations = new List<IWriteOperation>();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2b783d170d8ed6b468a9500bbe040087
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using UnityEditor.Build.Content;
using UnityEditor.Build.Pipeline.Interfaces;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Optional context object used for overriding the location where specific objects will be serialized
/// </summary>
[Serializable]
public class BundleExplictObjectLayout : IBundleExplictObjectLayout
{
/// <inheritdoc />
public Dictionary<ObjectIdentifier, string> ExplicitObjectLocation { get; set; }
/// <summary>
/// Default constructor, initializes properties to defaults
/// </summary>
public BundleExplictObjectLayout()
{
ExplicitObjectLocation = new Dictionary<ObjectIdentifier, string>();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d723a770823401649b007044d9a978ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline.Tasks;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Basic static class containing preset build pipeline task collections.
/// </summary>
public static class DefaultBuildTasks
{
/// <summary>
/// Options for different preset build pipelines
/// </summary>
public enum Preset
{
/// <summary>
/// Use to indicate that the pipeline only executes player scripts.
/// </summary>
PlayerScriptsOnly,
/// <summary>
/// Use to indicate that the pipeline should create asset bundles.
/// </summary>
AssetBundleCompatible,
/// <summary>
/// Use to indicate that the pipeline should create asset bundles and the built-in shader bundle.
/// </summary>
AssetBundleBuiltInShaderExtraction,
/// <summary>
/// Use to indicate that the pipeline should create asset bundles, the built-in shader bundle, and MonoScript bundle.
/// </summary>
AssetBundleShaderAndScriptExtraction,
}
/// <summary>
/// Constructs and returns an IList containing the build tasks in the correct order for the preset build pipeline.
/// </summary>
/// <param name="preset">The preset build pipeline to construct and return.</param>
/// <returns>IList containing the build tasks in the correct order for the preset build pipeline.</returns>
public static IList<IBuildTask> Create(Preset preset)
{
switch (preset)
{
case Preset.PlayerScriptsOnly:
return PlayerScriptsOnly();
case Preset.AssetBundleCompatible:
return AssetBundleCompatible(false, false);
case Preset.AssetBundleBuiltInShaderExtraction:
return AssetBundleCompatible(true, false);
case Preset.AssetBundleShaderAndScriptExtraction:
return AssetBundleCompatible(true, true);
default:
throw new NotImplementedException(string.Format("Preset for '{0}' not yet implemented.", preset));
}
}
static IList<IBuildTask> PlayerScriptsOnly()
{
var buildTasks = new List<IBuildTask>();
// Setup
buildTasks.Add(new SwitchToBuildPlatform());
// Player Scripts
buildTasks.Add(new BuildPlayerScripts());
buildTasks.Add(new PostScriptsCallback());
// Dependency
// - Empty
// Packing
// - Empty
// Writing
// - Empty
return buildTasks;
}
static IList<IBuildTask> AssetBundleCompatible(bool shaderTask, bool monoscriptTask)
{
var buildTasks = new List<IBuildTask>();
// Setup
buildTasks.Add(new SwitchToBuildPlatform());
buildTasks.Add(new RebuildSpriteAtlasCache());
// Player Scripts
buildTasks.Add(new BuildPlayerScripts());
buildTasks.Add(new PostScriptsCallback());
// Dependency
buildTasks.Add(new CalculateSceneDependencyData());
#if UNITY_2019_3_OR_NEWER
buildTasks.Add(new CalculateCustomDependencyData());
#endif
buildTasks.Add(new CalculateAssetDependencyData());
buildTasks.Add(new StripUnusedSpriteSources());
if (shaderTask)
buildTasks.Add(new CreateBuiltInShadersBundle("UnityBuiltInShaders.bundle"));
if (monoscriptTask)
buildTasks.Add(new CreateMonoScriptBundle("UnityMonoScripts.bundle"));
buildTasks.Add(new PostDependencyCallback());
// Packing
buildTasks.Add(new GenerateBundlePacking());
if (shaderTask || monoscriptTask)
buildTasks.Add(new UpdateBundleObjectLayout());
buildTasks.Add(new GenerateBundleCommands());
buildTasks.Add(new GenerateSubAssetPathMaps());
buildTasks.Add(new GenerateBundleMaps());
buildTasks.Add(new PostPackingCallback());
// Writing
buildTasks.Add(new WriteSerializedFiles());
buildTasks.Add(new ArchiveAndCompressBundles());
buildTasks.Add(new AppendBundleHash());
buildTasks.Add(new GenerateLinkXml());
buildTasks.Add(new PostWritingCallback());
return buildTasks;
}
#if UNITY_2022_2_OR_NEWER
public static IList<IBuildTask> ContentFileCompatible()
{
var buildTasks = new List<IBuildTask>();
// Setup
buildTasks.Add(new SwitchToBuildPlatform());
buildTasks.Add(new RebuildSpriteAtlasCache());
// Player Scripts
buildTasks.Add(new BuildPlayerScripts());
buildTasks.Add(new PostScriptsCallback());
// Dependency
buildTasks.Add(new CalculateSceneDependencyData());
buildTasks.Add(new CalculateCustomDependencyData());
buildTasks.Add(new CalculateAssetDependencyData());
buildTasks.Add(new StripUnusedSpriteSources());
buildTasks.Add(new PostDependencyCallback());
// Packing
buildTasks.Add(new ClusterBuildLayout());
buildTasks.Add(new PostPackingCallback());
// Writing
buildTasks.Add(new WriteSerializedFiles());
buildTasks.Add(new ArchiveAndCompressBundles());
buildTasks.Add(new GenerateLinkXml());
buildTasks.Add(new PostWritingCallback());
return buildTasks;
}
#endif
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 552d6f72e940a1c4a809b635a8f40d8b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,39 @@
using UnityEditor.Build.Content;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline.Utilities;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Generates identifiers linearly for built content. Only deterministic if object order and initial Index is deterministic.
/// </summary>
public class LinearPackedIdentifiers : IDeterministicIdentifiers
{
/// <summary>
/// The index at which to start linear id assignment.
/// </summary>
public long Index { get; set; }
/// <summary>
/// Default constructor, takes an initial index at which to start linear id assignment.
/// </summary>
/// <param name="index">Initial index at which to start linear id assignment.</param>
public LinearPackedIdentifiers(long index)
{
Index = index;
}
/// <inheritdoc />
public virtual string GenerateInternalFileName(string name)
{
var hash = HashingMethods.Calculate(name).ToString();
return string.Format("CAB-{0}", hash);
}
/// <inheritdoc />
public virtual long SerializationIndexFromObjectIdentifier(ObjectIdentifier objectID)
{
return Index++;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f004933c56f4b2f4792fdcc1aca8f9b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,65 @@
using System;
using UnityEditor.Build.Content;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline.Utilities;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Generates a deterministic identifier using a MD5 hash algorithm and does not require object ordering to be deterministic.
/// This algorithm ensures objects coming from the same asset are packed closer together and can improve loading performance under certain situations.
/// </summary>
public class PrefabPackedIdentifiers : IDeterministicIdentifiers
{
/// <inheritdoc />
public virtual string GenerateInternalFileName(string name)
{
return "CAB-" + HashingMethods.Calculate(name);
}
/// <inheritdoc />
public virtual long SerializationIndexFromObjectIdentifier(ObjectIdentifier objectID)
{
byte[] assetHash;
byte[] objectHash;
bool extraArtifact = objectID.filePath.StartsWith("VirtualArtifacts/Extra/", StringComparison.Ordinal);
int hashSeed = ScriptableBuildPipeline.fileIDHashSeed;
if (extraArtifact && hashSeed != 0)
{
RawHash fileHash = HashingMethods.CalculateFile(objectID.filePath);
assetHash = HashingMethods.Calculate(hashSeed, fileHash).ToBytes();
objectHash = HashingMethods.Calculate(hashSeed, fileHash, objectID.localIdentifierInFile).ToBytes();
}
else if (extraArtifact)
{
RawHash fileHash = HashingMethods.CalculateFile(objectID.filePath);
assetHash = fileHash.ToBytes();
objectHash = HashingMethods.Calculate(fileHash, objectID.localIdentifierInFile).ToBytes();
}
else if (hashSeed != 0)
{
assetHash = HashingMethods.Calculate(hashSeed, objectID.guid, objectID.filePath).ToBytes();
objectHash = HashingMethods.Calculate(hashSeed, objectID).ToBytes();
}
else
{
assetHash = HashingMethods.Calculate(objectID.guid, objectID.filePath).ToBytes();
objectHash = HashingMethods.Calculate(objectID).ToBytes();
}
int headerSize = ScriptableBuildPipeline.prefabPackedHeaderSize;
if (headerSize < 4)
{
for (int i = 0; i < headerSize; i++)
objectHash[i] = assetHash[i];
return BitConverter.ToInt64(objectHash, 0);
}
else
{
var assetVal = BitConverter.ToUInt64(assetHash, 0);
var objectVal = BitConverter.ToUInt64(objectHash, 0);
return (long)((0xFFFFFFFF00000000 & assetVal) | (0x00000000FFFFFFFF & (objectVal ^ assetVal)));
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5046b687c98667141a9a4f0add3345be
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,54 @@
using System;
using UnityEditor.Build.Content;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline.Utilities;
namespace UnityEditor.Build.Pipeline
{
/// <summary>
/// Generates a deterministic identifier using a MD4 hash algorithm and does not require object ordering to be deterministic.
/// This algorithm generates identical results to what is used internally in <c>BuildPipeline.BuildAssetbundles</c>.
/// </summary>
public class Unity5PackedIdentifiers : IDeterministicIdentifiers
{
/// <inheritdoc />
public virtual string GenerateInternalFileName(string name)
{
return "CAB-" + HashingMethods.Calculate<MD4>(name);
}
/// <inheritdoc />
public virtual long SerializationIndexFromObjectIdentifier(ObjectIdentifier objectID)
{
RawHash hash;
bool extraArtifact = objectID.filePath.StartsWith("VirtualArtifacts/Extra/", StringComparison.Ordinal);
int hashSeed = ScriptableBuildPipeline.fileIDHashSeed;
if (extraArtifact && hashSeed != 0)
{
RawHash fileHash = HashingMethods.CalculateFile(objectID.filePath);
hash = HashingMethods.Calculate(hashSeed, fileHash, objectID.localIdentifierInFile);
}
else if (extraArtifact)
{
RawHash fileHash = HashingMethods.CalculateFile(objectID.filePath);
hash = HashingMethods.Calculate(fileHash, objectID.localIdentifierInFile);
}
else if (hashSeed != 0)
{
if (objectID.fileType == FileType.MetaAssetType || objectID.fileType == FileType.SerializedAssetType)
hash = HashingMethods.Calculate<MD4>(hashSeed, objectID.guid.ToString(), objectID.fileType, objectID.localIdentifierInFile);
else
hash = HashingMethods.Calculate<MD4>(hashSeed, objectID.filePath, objectID.localIdentifierInFile);
}
else
{
if (objectID.fileType == FileType.MetaAssetType || objectID.fileType == FileType.SerializedAssetType)
hash = HashingMethods.Calculate<MD4>(objectID.guid.ToString(), objectID.fileType, objectID.localIdentifierInFile);
else
hash = HashingMethods.Calculate<MD4>(objectID.filePath, objectID.localIdentifierInFile);
}
return BitConverter.ToInt64(hash.ToBytes(), 0);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b8ee6f8e7df445bfb88fb0372dcf691a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: