// Unity C# reference source
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
using UnityEngine;
using UnityEngine.Internal;
using UnityEngine.Scripting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor.AssetImporters;
using Object = UnityEngine.Object;
using UnityEditor.Profiling;
using UnityEditor.Callbacks;
namespace UnityEditor
{
// AssetPostprocessor lets you hook into the import pipeline and run scripts prior or after importing assets.
public partial class AssetPostprocessor
{
internal struct PostprocessorInfo
{
public Type Type { get; }
public string[] Methods { get; }
public uint Version { get; }
public int Priority { get; }
///
/// StaticDependency is true if any method in the postprocessor is not part of the NonAutomaticDependencyMethods list.
/// This is used to know which PostprocessorInfo should be used for the static importer dependency hash.
///
public bool StaticDependency { get; }
public PostprocessorInfo(Type assetPostprocessorType, int importerPriority)
{
Type = assetPostprocessorType;
Methods = null;
Version = 0;
StaticDependency = false;
Priority = importerPriority;
}
public PostprocessorInfo(Type assetPostprocessorType, string[] implementedMethods)
{
Type = assetPostprocessorType;
Methods = implementedMethods;
StaticDependency = Methods.Intersect(AssetPostprocessingInternal.k_NonAutomaticDependencyMethods).Count() != Methods.Length;
var inst = (AssetPostprocessor)Activator.CreateInstance(assetPostprocessorType);
Version = inst.GetVersion();
Priority = inst.GetPostprocessOrder();
}
}
private string m_PathName;
private AssetImportContext m_Context;
// The path name of the asset being imported.
public string assetPath { get { return m_PathName; } set { m_PathName = value; } }
// The context of the import, used to specify dependencies
public AssetImportContext context { get { return m_Context; } internal set { m_Context = value; } }
// Logs an import warning to the console.
[ExcludeFromDocs]
[Obsolete("Use context.LogImportWarning(string) instead.")]
public void LogWarning(string warning)
{
Object context = null;
LogWarning(warning, context);
}
[Obsolete("Use context.LogImportWarning(string, Object) instead.")]
public void LogWarning(string warning, [DefaultValue("null")] Object context)
{
if (m_Context != null)
m_Context.LogImportWarning(warning, context);
else
Debug.LogWarning(warning, context);
}
// Logs an import error message to the console.
[ExcludeFromDocs]
[Obsolete("Use context.LogImportError(string) instead.")]
public void LogError(string warning)
{
Object context = null;
LogError(warning, context);
}
[Obsolete("Use context.LogImportError(string, Object) instead.")]
public void LogError(string warning, [DefaultValue("null")] Object context)
{
if (m_Context != null)
m_Context.LogImportError(warning, context);
else
Debug.LogError(warning, context);
}
// Returns the version of the asset postprocessor.
public virtual uint GetVersion() { return 0; }
// Reference to the asset importer
public AssetImporter assetImporter { get { return AssetImporter.GetAtPath(assetPath); } }
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
[Obsolete("To set or get the preview, call EditorUtility.SetAssetPreview or AssetPreview.GetAssetPreview instead", true)]
public Texture2D preview { get { return null; } set {} }
// Override the order in which importers are processed.
public virtual int GetPostprocessOrder() { return 0; }
}
class OnPostprocessAllAssetsCallbackCollection : OrderedCallbackCollection
{
public class MethodInfoCallback : Callback
{
public MethodInfo Method { get; }
public override Type classType => Method.DeclaringType;
public bool MethodDomainReload { get; }
public override string name => classType.FullName;
public MethodInfoCallback(MethodInfo method, bool methodDomainReload)
{
Method = method;
MethodDomainReload = methodDomainReload;
}
public override IEnumerable GetCustomAttributes() => Method.GetCustomAttributes();
}
public override string name => "OnPostprocessAllAssets";
public override List GetCallbacks()
{
var methodArgTypes = new Type[] { typeof(string).MakeArrayType(), typeof(string).MakeArrayType(), typeof(string).MakeArrayType(), typeof(string).MakeArrayType() };
var methodDomainReloadParamArgTypes = new Type[] { methodArgTypes[0], methodArgTypes[1], methodArgTypes[2], methodArgTypes[3], typeof(bool) };
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
var callbacks = new List();
foreach (var assetPostprocessorClass in TypeCache.GetTypesDerivedFrom())
{
var method = assetPostprocessorClass.GetMethod("OnPostprocessAllAssets", flags, null, methodArgTypes, null);
if (method != null)
{
callbacks.Add(new MethodInfoCallback(method, false));
}
else
{
// OnPostprocessAllAssets with didDomainReload parameter
method = assetPostprocessorClass.GetMethod("OnPostprocessAllAssets", flags, null, methodDomainReloadParamArgTypes, null);
if (method != null)
{
callbacks.Add(new MethodInfoCallback(method, true));
}
}
}
return callbacks;
}
}
internal class AssetPostprocessingInternal
{
// What is it:
// Static postprocessor methods always called for each importer that are part of importer static dependency.
// No new postprocessors should be added to these lists. Please reach out to #devs-import-workflow to talk about new additions.
internal static readonly string[] k_NonAutomaticDependencyMethods =
{
"OnPreprocessAsset",
};
static readonly string[] k_ModelImporterPostprocessors =
{
"OnPreprocessModel",
"OnPostprocessMeshHierarchy",
"OnPostprocessModel",
"OnPreprocessAnimation",
"OnPostprocessAnimation",
"OnPostprocessGameObjectWithAnimatedUserProperties",
"OnPostprocessGameObjectWithUserProperties",
"OnPostprocessMaterial",
"OnAssignMaterialModel",
"OnPreprocessMaterialDescription",
};
static readonly string[] k_DynamicModelImporterPostprocessors =
{
"OnPreprocessCameraDescription",
"OnPreprocessLightDescription"
};
static readonly string[] k_TextureImporterPostprocessors =
{
"OnPreprocessTexture",
"OnPostprocessTexture",
"OnPostprocessCubemap",
"OnPostprocessSprites",
"OnPostprocessTexture3D",
"OnPostprocessTexture2DArray"
};
static readonly string[] k_IHVImporterPostprocessors =
{
"OnPostprocessTexture",
};
static readonly string[] k_AudioImporterPostprocessors =
{
"OnPreprocessAudio",
"OnPostprocessAudio",
};
static readonly string[] k_SpeedTreeImporterPostprocessors =
{
"OnPreprocessSpeedTree",
"OnPostprocessSpeedTree",
};
static readonly string[] k_PrefabImporterPostprocessors =
{
"OnPostprocessPrefab",
};
static readonly string[] k_CameraPostprocessors =
{
"OnPreprocessCameraDescription",
};
static readonly string[] k_LightPostprocessors =
{
"OnPreprocessLightDescription",
};
static readonly string[] k_TexturePreprocessors =
{
"OnPreprocessTexture",
};
static readonly string[] k_Texture2DPostprocessors =
{
"OnPostprocessTexture",
};
static readonly string[] k_Texture2DArrayPostprocessors =
{
"OnPostprocessTexture2DArray"
};
static readonly string[] k_Texture3DPostprocessors =
{
"OnPostprocessTexture3D"
};
static readonly string[] k_TextureCubePostprocessors =
{
"OnPostprocessCubemap"
};
static readonly string[] k_SpritePostprocessors =
{
"OnPostprocessSprites",
};
static Dictionary s_PostprocessorMethodsByDependencyKey;
static Dictionary s_StaticPostprocessorMethodsByImporterType;
static Dictionary s_DynamicPostprocessorMethodsByImporterType;
// Internal for debugging purposes. We can generate dependency graphs to help understand issues.
internal static OnPostprocessAllAssetsCallbackCollection s_OnPostprocessAllAssetsCallbacks = new OnPostprocessAllAssetsCallbackCollection();
static AssetPostprocessingInternal()
{
s_StaticPostprocessorMethodsByImporterType = new Dictionary();
s_StaticPostprocessorMethodsByImporterType.Add(typeof(ModelImporter), k_ModelImporterPostprocessors);
s_StaticPostprocessorMethodsByImporterType.Add(typeof(IHVImageFormatImporter), k_IHVImporterPostprocessors);
s_StaticPostprocessorMethodsByImporterType.Add(typeof(SpeedTreeImporter), k_SpeedTreeImporterPostprocessors);
s_StaticPostprocessorMethodsByImporterType.Add(typeof(AudioImporter), k_AudioImporterPostprocessors);
s_StaticPostprocessorMethodsByImporterType.Add(typeof(PrefabImporter), k_PrefabImporterPostprocessors);
s_DynamicPostprocessorMethodsByImporterType = new Dictionary();
s_DynamicPostprocessorMethodsByImporterType.Add(typeof(ModelImporter), k_DynamicModelImporterPostprocessors);
s_DynamicPostprocessorMethodsByImporterType.Add(typeof(TextureImporter), k_TextureImporterPostprocessors);
s_PostprocessorMethodsByDependencyKey = new Dictionary();
s_PostprocessorMethodsByDependencyKey.Add(kCameraPostprocessorDependencyName, k_CameraPostprocessors);
s_PostprocessorMethodsByDependencyKey.Add(kLightPostprocessorDependencyName, k_LightPostprocessors);
s_PostprocessorMethodsByDependencyKey.Add(kTexturePreprocessorDependencyName, k_TexturePreprocessors);
s_PostprocessorMethodsByDependencyKey.Add(kTexture2DPostprocessorDependencyName, k_Texture2DPostprocessors);
s_PostprocessorMethodsByDependencyKey.Add(kTexture2DArrayPostprocessorDependencyName, k_Texture2DArrayPostprocessors);
s_PostprocessorMethodsByDependencyKey.Add(kTexture3DPostprocessorDependencyName, k_Texture3DPostprocessors);
s_PostprocessorMethodsByDependencyKey.Add(kTextureCubePostprocessorDependencyName, k_TextureCubePostprocessors);
s_PostprocessorMethodsByDependencyKey.Add(kTextureSpritePostprocessorDependencyName, k_SpritePostprocessors);
}
[Serializable]
class AssetPostProcessorAnalyticsData
{
public string importActionId;
public List postProcessorCalls = new List();
}
[Serializable]
struct AssetPostProcessorMethodCallAnalyticsData
{
public string methodName;
public float duration_sec;
public int invocationCount;
}
static void LogPostProcessorMissingDefaultConstructor(Type type)
{
Debug.LogErrorFormat("{0} requires a default constructor to be used as an asset post processor", type);
}
[RequiredByNativeCode]
// Postprocess on all assets once an automatic import has completed
static void PostprocessAllAssets(string[] importedAssets, string[] addedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromPathAssets, bool didDomainReload)
{
object[] args = { importedAssets, deletedAssets, movedAssets, movedFromPathAssets };
object[] argsWithDidDomainReload = { importedAssets, deletedAssets, movedAssets, movedFromPathAssets, didDomainReload};
var containsNoAssets = importedAssets.Length == 0 && addedAssets.Length == 0 && deletedAssets.Length == 0 && movedAssets.Length == 0 && movedFromPathAssets.Length == 0;
foreach (OnPostprocessAllAssetsCallbackCollection.MethodInfoCallback assetPostProcessor in s_OnPostprocessAllAssetsCallbacks.sortedCallbacks)
{
try
{
if (assetPostProcessor.MethodDomainReload)
{
using (new EditorPerformanceMarker($"{assetPostProcessor.classType.Name}.OnPostprocessAllAssets", assetPostProcessor.classType).Auto())
InvokeMethod(assetPostProcessor.Method, argsWithDidDomainReload);
}
else
{
if (containsNoAssets)
continue;
using (new EditorPerformanceMarker($"{assetPostProcessor.classType.Name}.OnPostprocessAllAssets", assetPostProcessor.classType).Auto())
InvokeMethod(assetPostProcessor.Method, args);
}
}
catch (Exception e)
{
Debug.LogException(e);
}
}
using (new EditorPerformanceMarker("SyncVS.PostprocessSyncProject").Auto())
CodeEditorProjectSync.PostprocessSyncProject(importedAssets, addedAssets, deletedAssets, movedAssets, movedFromPathAssets);
}
internal class CompareAssetImportPriority : IComparer, IComparer
{
public int Compare(AssetPostprocessor.PostprocessorInfo x, AssetPostprocessor.PostprocessorInfo y)
{
int xo = x.Priority;
int yo = y.Priority;
var compare = xo.CompareTo(yo);
if (compare == 0)
{
compare = x.Type.FullName.CompareTo(y.Type.FullName);
if (compare == 0)
compare = x.Type.AssemblyQualifiedName.CompareTo(y.Type.AssemblyQualifiedName);
}
return compare;
}
public int Compare(AssetPostprocessor x, AssetPostprocessor y)
{
var xi = new AssetPostprocessor.PostprocessorInfo(x.GetType(), x.GetPostprocessOrder());
var yi = new AssetPostprocessor.PostprocessorInfo(y.GetType(), y.GetPostprocessOrder());
return Compare(xi, yi);
}
}
private static string BuildStaticDependencyHashString(SortedSet list)
{
var hashStr = "";
foreach (var info in list)
{
if (info.StaticDependency)
{
hashStr += info.Type.AssemblyQualifiedName;
hashStr += '.';
hashStr += info.Version;
hashStr += '|';
}
}
return hashStr;
}
private static string BuildHashString(SortedList list)
{
var hashStr = "";
foreach (var pair in list)
{
hashStr += pair.Key;
hashStr += '.';
hashStr += pair.Value;
hashStr += '|';
}
return hashStr;
}
internal const string kCameraPostprocessorDependencyName = "postprocessor/camera";
internal const string kLightPostprocessorDependencyName = "postprocessor/light";
internal const string kTexture2DPostprocessorDependencyName = "postprocessor/texture2D";
internal const string kTextureCubePostprocessorDependencyName = "postprocessor/textureCube";
internal const string kTexture3DPostprocessorDependencyName = "postprocessor/texture3D";
internal const string kTexture2DArrayPostprocessorDependencyName = "postprocessor/texture2DArray";
internal const string kTextureSpritePostprocessorDependencyName = "postprocessor/textureSprite";
internal const string kTexturePreprocessorDependencyName = "postprocessor/texturePreprocessor";
static Stack> m_PostprocessStack = null;
static SortedSet m_ImportProcessors = null;
static Type[] m_PostprocessorClasses = null;
static string m_MeshProcessorsHashString = null;
static string m_AudioProcessorsHashString = null;
static string m_SpeedTreeProcessorsHashString = null;
static string m_PrefabProcessorsHashString = null;
static string m_CameraProcessorsHashString = null;
static string m_LightProcessorsHashString = null;
static string m_Texture2DProcessorsHashString = null;
static string m_TextureCubeProcessorsHashString = null;
static string m_Texture3DPostprocessorDependencyName = null;
static string m_Texture2DArrayDependencyName = null;
static string m_TextureSpriteDependencyName = null;
static string m_TexturePreprocessorDependencyName = null;
static Dictionary> s_StaticPostprocessorsPerImporterType = new Dictionary>();
static Dictionary> s_DynamicPostprocessorsPerImporterType = new Dictionary>();
static Stack s_AnalyticsEventsStack = new Stack();
static Type[] GetCachedAssetPostprocessorClasses()
{
if (m_PostprocessorClasses == null)
m_PostprocessorClasses = TypeCache.GetTypesDerivedFrom().ToArray();
return m_PostprocessorClasses;
}
[RequiredByNativeCode]
static void InitPostprocessorsForTextureGenerator(string pathName)
{
var analyticsEvent = new AssetPostProcessorAnalyticsData();
analyticsEvent.importActionId = "None";
s_AnalyticsEventsStack.Push(analyticsEvent);
m_ImportProcessors = new SortedSet(new CompareAssetImportPriority());
foreach (var postprocessorInfo in GetSortedStaticPostprocessorTypes(typeof(TextureImporter)))
{
var assetPostprocessor = (AssetPostprocessor)Activator.CreateInstance(postprocessorInfo.Type);
assetPostprocessor.assetPath = pathName;
assetPostprocessor.context = null;
m_ImportProcessors.Add(assetPostprocessor);
}
foreach (var postprocessorInfo in GetSortedDynamicPostprocessorTypes(typeof(TextureImporter)))
{
var assetPostprocessor = (AssetPostprocessor)Activator.CreateInstance(postprocessorInfo.Type);
assetPostprocessor.assetPath = pathName;
assetPostprocessor.context = null;
m_ImportProcessors.Add(assetPostprocessor);
}
// Setup postprocessing stack to support reentrancy (Import asset immediate)
if (m_PostprocessStack == null)
m_PostprocessStack = new Stack>();
m_PostprocessStack.Push(m_ImportProcessors);
}
[RequiredByNativeCode]
static void InitPostprocessors(AssetImportContext context, string pathName, Type importerType, double importStartTime)
{
var analyticsEvent = new AssetPostProcessorAnalyticsData();
analyticsEvent.importActionId = ((int)Math.Floor(importStartTime * 1000)).ToString();
s_AnalyticsEventsStack.Push(analyticsEvent);
m_ImportProcessors = new SortedSet(new CompareAssetImportPriority());
foreach (var postprocessorInfo in GetSortedStaticPostprocessorTypes(importerType))
{
var assetPostprocessor = (AssetPostprocessor)Activator.CreateInstance(postprocessorInfo.Type);
assetPostprocessor.assetPath = pathName;
assetPostprocessor.context = context;
m_ImportProcessors.Add(assetPostprocessor);
}
foreach (var postprocessorInfo in GetSortedDynamicPostprocessorTypes(importerType))
{
var assetPostprocessor = (AssetPostprocessor)Activator.CreateInstance(postprocessorInfo.Type);
assetPostprocessor.assetPath = pathName;
assetPostprocessor.context = context;
m_ImportProcessors.Add(assetPostprocessor);
}
// Setup postprocessing stack to support reentrancy (Import asset immediate)
if (m_PostprocessStack == null)
m_PostprocessStack = new Stack>();
m_PostprocessStack.Push(m_ImportProcessors);
}
[RequiredByNativeCode]
static void CleanupPostprocessors()
{
if (m_PostprocessStack != null)
{
m_PostprocessStack.Pop();
m_ImportProcessors = m_PostprocessStack.Count > 0 ? m_PostprocessStack.Peek() : null;
}
if (s_AnalyticsEventsStack.Count > 0)
{
var lastEvent = s_AnalyticsEventsStack.Pop();
if (lastEvent.postProcessorCalls.Count > 0)
EditorAnalytics.SendAssetPostprocessorsUsage(lastEvent);
}
}
static bool ImplementsAnyOfTheses(Type type, IEnumerable methods, out List usedMethods)
{
usedMethods = new List(methods.Where(method => type.GetMethod(method, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null));
return usedMethods.Count > 0;
}
/*
* Returns the list of actual dynamic postprocessor methods for a particular asset.
* Note: That where the asset is not yet imported, this list will be empty.
*/
internal static SortedSet GetSortedDynamicPostprocessorsForAsset(string path)
{
var list = new SortedSet(new CompareAssetImportPriority());
var guid = AssetDatabase.GUIDFromAssetPath(path);
if (guid.Empty())
return list;
//Artifact Infos may contains multiple artifacts, associated with different version of the object (E.g. Main, Preview etc.)
var artifactInfos = AssetDatabase.GetArtifactInfos(guid);
var allMethodsNames = new List();
foreach (var info in artifactInfos)
{
if (!info.isCurrentArtifact)
continue;
foreach (var kvp in info.dependencies)
{
if (kvp.Value.type == ArtifactInfoDependencyType.Dynamic)
{
//Try to retrieve Postprocessor Methods associated with the supplied Dependency keys
string dependencyName = kvp.Key.Replace(ArtifactDifferenceReporter.kEnvironment_CustomDependency + "/", "");
if (s_PostprocessorMethodsByDependencyKey.TryGetValue(dependencyName, out var methodNames))
allMethodsNames.AddRange(methodNames);
}
}
}
if (allMethodsNames.Count == 0)
return list;
/*
* The asset has dynamic dependencies to an Asset Postprocessor, so let's find any Postprocessors which
* implements those methods.
*/
var distinctMethodNames = allMethodsNames.Distinct();
foreach (Type assetPostprocessorClass in GetCachedAssetPostprocessorClasses())
{
if (ImplementsAnyOfTheses(assetPostprocessorClass, distinctMethodNames, out var methods))
{
if (assetPostprocessorClass.GetConstructors().Any(t => t.GetParameters().Count() == 0))
list.Add(new AssetPostprocessor.PostprocessorInfo(assetPostprocessorClass, methods.ToArray()));
else
LogPostProcessorMissingDefaultConstructor(assetPostprocessorClass);
}
}
return list;
}
internal static SortedSet GetSortedStaticPostprocessorTypes(Type importer)
{
var defaultMethods = new string[]
{
"OnPreprocessAsset"
};
return GetSortedPostprocessorTypes(importer, s_StaticPostprocessorMethodsByImporterType, defaultMethods,
s_StaticPostprocessorsPerImporterType);
}
/*
* Returns the list of *possible* dynamic postprocessor methods associated with a particular importer type.
* See also: GetSortedDynamicPostprocessorsForAsset, to get the actual postprocessor methods for a given asset.
*/
internal static SortedSet GetSortedDynamicPostprocessorTypes(Type importer)
{
return GetSortedPostprocessorTypes(importer, s_DynamicPostprocessorMethodsByImporterType, new string[0],
s_DynamicPostprocessorsPerImporterType);
}
static SortedSet GetSortedPostprocessorTypes(Type importer, Dictionary postprocessorMethodsByImporterType, string[] defaultMethods, Dictionary> cache)
{
if (cache.TryGetValue(importer, out var cachedPostprocessors))
return cachedPostprocessors;
var list = new SortedSet(new CompareAssetImportPriority());
var allMethodsNames = defaultMethods.ToList();
var methodsType = importer;
while (methodsType != null && methodsType != typeof(AssetImporter))
{
if (postprocessorMethodsByImporterType.TryGetValue(methodsType, out var methodNames))
allMethodsNames.AddRange(methodNames);
methodsType = methodsType.BaseType;
}
foreach (Type assetPostprocessorClass in GetCachedAssetPostprocessorClasses())
{
if (ImplementsAnyOfTheses(assetPostprocessorClass, allMethodsNames, out var methods))
{
if (assetPostprocessorClass.GetConstructors().Any(t => t.GetParameters().Count() == 0))
list.Add(new AssetPostprocessor.PostprocessorInfo(assetPostprocessorClass, methods.ToArray()));
else
LogPostProcessorMissingDefaultConstructor(assetPostprocessorClass);
}
}
cache.Add(importer, list);
return list;
}
[RequiredByNativeCode]
static string GetMeshProcessorsHashString()
{
if (m_MeshProcessorsHashString != null)
return m_MeshProcessorsHashString;
m_MeshProcessorsHashString = BuildStaticDependencyHashString(GetSortedStaticPostprocessorTypes(typeof(ModelImporter)));
return m_MeshProcessorsHashString;
}
[RequiredByNativeCode]
static void PreprocessAsset()
{
foreach (AssetPostprocessor inst in m_ImportProcessors)
{
InvokeMethodIfAvailable(inst, "OnPreprocessAsset", null);
}
}
[RequiredByNativeCode]
static void PreprocessModel(string pathName)
{
CallPostProcessMethods("OnPreprocessModel", null);
}
[RequiredByNativeCode]
static void PreprocessSpeedTree(string pathName)
{
CallPostProcessMethods("OnPreprocessSpeedTree", null);
}
[RequiredByNativeCode]
static void PreprocessAnimation(string pathName)
{
CallPostProcessMethods("OnPreprocessAnimation", null);
}
[RequiredByNativeCode]
static void PostprocessAnimation(GameObject root, AnimationClip clip)
{
object[] args = { root, clip };
CallPostProcessMethods("OnPostprocessAnimation", args);
}
[RequiredByNativeCode]
static Material ProcessMeshAssignMaterial(Renderer renderer, Material material)
{
object[] args = { material, renderer };
Material assignedMaterial;
CallPostProcessMethodsUntilReturnedObjectIsValid("OnAssignMaterialModel", args, out assignedMaterial);
return assignedMaterial;
}
[RequiredByNativeCode]
static bool ProcessMeshHasAssignMaterial()
{
foreach (AssetPostprocessor inst in m_ImportProcessors)
{
if (inst.GetType().GetMethod("OnAssignMaterialModel", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null)
return true;
}
return false;
}
[RequiredByNativeCode]
static void PostprocessMeshHierarchy(GameObject root)
{
object[] args = { root };
CallPostProcessMethods("OnPostprocessMeshHierarchy", args);
}
[RequiredByNativeCode]
static void PostprocessMesh(GameObject gameObject)
{
object[] args = { gameObject };
CallPostProcessMethods("OnPostprocessModel", args);
}
[RequiredByNativeCode]
static void PostprocessSpeedTree(GameObject gameObject)
{
object[] args = { gameObject };
CallPostProcessMethods("OnPostprocessSpeedTree", args);
}
[RequiredByNativeCode]
static void PostprocessMaterial(Material material)
{
object[] args = { material };
CallPostProcessMethods("OnPostprocessMaterial", args);
}
[RequiredByNativeCode]
static void PreprocessCameraDescription(AssetImportContext assetImportContext, CameraDescription description, Camera camera, AnimationClip[] animations)
{
assetImportContext.DependsOnCustomDependency(kCameraPostprocessorDependencyName);
object[] args = { description, camera, animations };
CallPostProcessMethods("OnPreprocessCameraDescription", args);
}
[RequiredByNativeCode]
static void PreprocessLightDescription(AssetImportContext assetImportContext, LightDescription description, Light light, AnimationClip[] animations)
{
assetImportContext.DependsOnCustomDependency(kLightPostprocessorDependencyName);
object[] args = { description, light, animations };
CallPostProcessMethods("OnPreprocessLightDescription", args);
}
[RequiredByNativeCode]
static void PreprocessMaterialDescription(MaterialDescription description, Material material, AnimationClip[] animations)
{
object[] args = { description, material, animations };
CallPostProcessMethods("OnPreprocessMaterialDescription", args);
}
[RequiredByNativeCode]
static void PostprocessGameObjectWithUserProperties(GameObject go, string[] prop_names, object[] prop_values)
{
object[] args = { go, prop_names, prop_values };
CallPostProcessMethods("OnPostprocessGameObjectWithUserProperties", args);
}
[RequiredByNativeCode]
static EditorCurveBinding[] PostprocessGameObjectWithAnimatedUserProperties(GameObject go, EditorCurveBinding[] bindings)
{
object[] args = { go, bindings };
CallPostProcessMethods("OnPostprocessGameObjectWithAnimatedUserProperties", args);
return bindings;
}
[RequiredByNativeCode]
static void PreprocessTexture(string pathName, AssetImportContext context)
{
if (context != null)
{
context.DependsOnCustomDependency(kTexturePreprocessorDependencyName);
}
CallPostProcessMethods("OnPreprocessTexture", null);
}
[RequiredByNativeCode]
static void PreprocessTextureFromScript(string pathName)
{
CallPostProcessMethods("OnPreprocessTexture", null);
}
[RequiredByNativeCode]
static void PostprocessTexture(Texture2D tex, string pathName, AssetImportContext context)
{
if (context != null)
{
context.DependsOnCustomDependency(kTexture2DPostprocessorDependencyName);
}
object[] args = { tex };
CallPostProcessMethods("OnPostprocessTexture", args);
}
[RequiredByNativeCode]
static void PostprocessTextureFromScript(Texture2D tex, string pathName)
{
object[] args = { tex };
CallPostProcessMethods("OnPostprocessTexture", args);
}
[RequiredByNativeCode]
static void PostprocessCubemap(Cubemap tex, string pathName, AssetImportContext context)
{
if (context != null)
{
context.DependsOnCustomDependency(kTextureCubePostprocessorDependencyName);
}
object[] args = { tex };
CallPostProcessMethods("OnPostprocessCubemap", args);
}
[RequiredByNativeCode]
static void PostprocessCubemapFromScript(Cubemap tex, string pathName)
{
object[] args = { tex };
CallPostProcessMethods("OnPostprocessCubemap", args);
}
[RequiredByNativeCode]
static void PostprocessTexture3D(Texture3D tex, string pathName, AssetImportContext context)
{
if (context != null)
{
context.DependsOnCustomDependency(kTexture3DPostprocessorDependencyName);
}
object[] args = { tex };
CallPostProcessMethods("OnPostprocessTexture3D", args);
}
[RequiredByNativeCode]
static void PostprocessTexture3DFromScript(Texture3D tex, string pathName)
{
object[] args = { tex };
CallPostProcessMethods("OnPostprocessTexture3D", args);
}
[RequiredByNativeCode]
static void PostprocessTexture2DArray(Texture2DArray tex, string pathName, AssetImportContext context)
{
if (context != null)
{
context.DependsOnCustomDependency(kTexture2DArrayPostprocessorDependencyName);
}
object[] args = { tex };
CallPostProcessMethods("OnPostprocessTexture2DArray", args);
}
[RequiredByNativeCode]
static void PostprocessTexture2DArrayFromScript(Texture2DArray tex, string pathName)
{
object[] args = { tex };
CallPostProcessMethods("OnPostprocessTexture2DArray", args);
}
[RequiredByNativeCode]
static void PostprocessSprites(Texture2D tex, string pathName, Sprite[] sprites, AssetImportContext context)
{
if (context != null)
{
context.DependsOnCustomDependency(kTextureSpritePostprocessorDependencyName);
}
object[] args = { tex, sprites };
CallPostProcessMethods("OnPostprocessSprites", args);
}
[RequiredByNativeCode]
static void PostprocessSpritesFromScript(Texture2D tex, string pathName, Sprite[] sprites)
{
object[] args = { tex, sprites };
CallPostProcessMethods("OnPostprocessSprites", args);
}
[RequiredByNativeCode]
static string GetAudioProcessorsHashString()
{
if (m_AudioProcessorsHashString != null)
return m_AudioProcessorsHashString;
m_AudioProcessorsHashString = BuildStaticDependencyHashString(GetSortedStaticPostprocessorTypes(typeof(AudioImporter)));
return m_AudioProcessorsHashString;
}
[RequiredByNativeCode]
static void PreprocessAudio(string pathName)
{
CallPostProcessMethods("OnPreprocessAudio", null);
}
[RequiredByNativeCode]
static void PostprocessAudio(AudioClip clip, string pathName)
{
object[] args = { clip };
CallPostProcessMethods("OnPostprocessAudio", args);
}
[RequiredByNativeCode]
static string GetPrefabProcessorsHashString()
{
if (m_PrefabProcessorsHashString != null)
return m_PrefabProcessorsHashString;
m_PrefabProcessorsHashString = BuildStaticDependencyHashString(GetSortedStaticPostprocessorTypes(typeof(PrefabImporter)));
return m_PrefabProcessorsHashString;
}
[RequiredByNativeCode]
static void PostprocessPrefab(GameObject prefabAssetRoot)
{
object[] args = { prefabAssetRoot };
CallPostProcessMethods("OnPostprocessPrefab", args);
}
[RequiredByNativeCode]
static void PostprocessAssetbundleNameChanged(string assetPath, string previousAssetBundleName, string newAssetBundleName)
{
object[] args = { assetPath, previousAssetBundleName, newAssetBundleName };
foreach (var assetPostprocessorClass in GetCachedAssetPostprocessorClasses())
{
var assetPostprocessor = Activator.CreateInstance(assetPostprocessorClass) as AssetPostprocessor;
InvokeMethodIfAvailable(assetPostprocessor, "OnPostprocessAssetbundleNameChanged", args);
}
}
[RequiredByNativeCode]
static string GetSpeedTreeProcessorsHashString()
{
if (m_SpeedTreeProcessorsHashString != null)
return m_SpeedTreeProcessorsHashString;
m_SpeedTreeProcessorsHashString = BuildStaticDependencyHashString(GetSortedStaticPostprocessorTypes(typeof(SpeedTreeImporter)));
return m_SpeedTreeProcessorsHashString;
}
[InitializeOnLoadMethod]
static void RefreshCustomDependencies()
{
AssetDatabase.RegisterCustomDependency(kCameraPostprocessorDependencyName, Hash128.Compute(GetCameraProcessorsHashString()));
AssetDatabase.RegisterCustomDependency(kLightPostprocessorDependencyName, Hash128.Compute(GetLightProcessorsHashString()));
AssetDatabase.RegisterCustomDependency(kTexture2DPostprocessorDependencyName, Hash128.Compute(GetTexture2DProcessorsHashString()));
AssetDatabase.RegisterCustomDependency(kTextureCubePostprocessorDependencyName, Hash128.Compute(GetTextureCubeProcessorsHashString()));
AssetDatabase.RegisterCustomDependency(kTexture3DPostprocessorDependencyName, Hash128.Compute(GetTexture3DProcessorsHashString()));
AssetDatabase.RegisterCustomDependency(kTexture2DArrayPostprocessorDependencyName, Hash128.Compute(GetTexture2DArrayProcessorsHashString()));
AssetDatabase.RegisterCustomDependency(kTextureSpritePostprocessorDependencyName, Hash128.Compute(GetTextureSpriteProcessorsHashString()));
AssetDatabase.RegisterCustomDependency(kTexturePreprocessorDependencyName, Hash128.Compute(GetTexturePreProcessorsHashString()));
}
static void GetProcessorHashString(string methodName, ref string hashString)
{
if (hashString != null)
return;
var versionsByType = new SortedList();
foreach (var assetPostprocessorClass in GetCachedAssetPostprocessorClasses())
{
try
{
if (assetPostprocessorClass.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) != null)
{
var inst = Activator.CreateInstance(assetPostprocessorClass) as AssetPostprocessor;
uint version = inst.GetVersion();
versionsByType.Add(assetPostprocessorClass.FullName, version);
}
}
catch (MissingMethodException)
{
LogPostProcessorMissingDefaultConstructor(assetPostprocessorClass);
}
catch (Exception e)
{
Debug.LogException(e);
}
}
hashString = BuildHashString(versionsByType);
}
[RequiredByNativeCode]
static string GetCameraProcessorsHashString()
{
GetProcessorHashString("OnPreprocessCameraDescription", ref m_CameraProcessorsHashString);
return m_CameraProcessorsHashString;
}
[RequiredByNativeCode]
static string GetLightProcessorsHashString()
{
GetProcessorHashString("OnPreprocessLightDescription", ref m_LightProcessorsHashString);
return m_LightProcessorsHashString;
}
[RequiredByNativeCode]
static string GetTexturePreProcessorsHashString()
{
GetProcessorHashString("OnPreprocessTexture", ref m_TexturePreprocessorDependencyName);
return m_TexturePreprocessorDependencyName;
}
[RequiredByNativeCode]
static string GetTexture2DProcessorsHashString()
{
GetProcessorHashString("OnPostprocessTexture", ref m_Texture2DProcessorsHashString);
return m_Texture2DProcessorsHashString;
}
[RequiredByNativeCode]
static string GetTextureCubeProcessorsHashString()
{
GetProcessorHashString("OnPostprocessCubemap", ref m_TextureCubeProcessorsHashString);
return m_TextureCubeProcessorsHashString;
}
[RequiredByNativeCode]
static string GetTexture3DProcessorsHashString()
{
GetProcessorHashString("OnPostprocessTexture3D", ref m_Texture3DPostprocessorDependencyName);
return m_Texture3DPostprocessorDependencyName;
}
[RequiredByNativeCode]
static string GetTexture2DArrayProcessorsHashString()
{
GetProcessorHashString("OnPostprocessTexture2DArray", ref m_Texture2DArrayDependencyName);
return m_Texture2DArrayDependencyName;
}
[RequiredByNativeCode]
static string GetTextureSpriteProcessorsHashString()
{
GetProcessorHashString("OnPostprocessSprites", ref m_TextureSpriteDependencyName);
return m_TextureSpriteDependencyName;
}
static bool IsAssetPostprocessorAnalyticsEnabled()
{
return EditorAnalytics.enabled;
}
static void CallPostProcessMethodsUntilReturnedObjectIsValid(string methodName, object[] args, out T returnedObject) where T : class
{
returnedObject = default(T);
int invocationCount = 0;
float startTime = Time.realtimeSinceStartup;
foreach (AssetPostprocessor inst in m_ImportProcessors)
{
if (InvokeMethodIfAvailable(inst, methodName, args, ref returnedObject))
{
invocationCount++;
break;
}
}
if (IsAssetPostprocessorAnalyticsEnabled() && invocationCount > 0)
{
var methodCallAnalytics = new AssetPostProcessorMethodCallAnalyticsData();
methodCallAnalytics.invocationCount = invocationCount;
methodCallAnalytics.methodName = methodName;
methodCallAnalytics.duration_sec = Time.realtimeSinceStartup - startTime;
s_AnalyticsEventsStack.Peek().postProcessorCalls.Add(methodCallAnalytics);
}
}
static void CallPostProcessMethods(string methodName, object[] args)
{
if (m_ImportProcessors == null)
{
throw new Exception("m_ImportProcessors is null, InitPostProcessors should be called before any of the post process methods are called.");
}
if (IsAssetPostprocessorAnalyticsEnabled())
{
int invocationCount = 0;
float startTime = Time.realtimeSinceStartup;
foreach (AssetPostprocessor inst in m_ImportProcessors)
{
if (InvokeMethodIfAvailable(inst, methodName, args))
invocationCount++;
}
if (invocationCount > 0)
{
var methodCallAnalytics = new AssetPostProcessorMethodCallAnalyticsData();
methodCallAnalytics.invocationCount = invocationCount;
methodCallAnalytics.methodName = methodName;
methodCallAnalytics.duration_sec = Time.realtimeSinceStartup - startTime;
s_AnalyticsEventsStack.Peek().postProcessorCalls.Add(methodCallAnalytics);
}
}
else
{
foreach (AssetPostprocessor inst in m_ImportProcessors)
{
InvokeMethodIfAvailable(inst, methodName, args);
}
}
}
static object InvokeMethod(MethodInfo method, object[] args)
{
object res = null;
using (new EditorPerformanceMarker(method.DeclaringType.Name + "." + method.Name, method.DeclaringType).Auto())
{
res = method.Invoke(null, args);
}
return res;
}
static bool InvokeMethodIfAvailable(object target, string methodName, object[] args)
{
var type = target.GetType();
MethodInfo method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (method != null)
{
using (new EditorPerformanceMarker(type.Name + "." + methodName, type).Auto())
{
method.Invoke(target, args);
}
return true;
}
return false;
}
static bool InvokeMethodIfAvailable(object target, string methodName, object[] args, ref T returnedObject) where T : class
{
var type = target.GetType();
MethodInfo method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (method != null)
{
using (new EditorPerformanceMarker(type.Name + "." + methodName, type).Auto())
{
returnedObject = method.Invoke(target, args) as T;
}
return returnedObject != null;
}
return false;
}
}
}