using System; using System.Reflection; using UnityEditor.Build.Pipeline.Interfaces; namespace UnityEditor.Build.Pipeline.Injector { /// <summary> /// Use to pass around information between build tasks. /// </summary> [AttributeUsage(AttributeTargets.Field)] public class InjectContextAttribute : Attribute { //public string Identifier { get; set; } /// <summary> /// Stores the how the attribute is used among build tasks. /// </summary> public ContextUsage Usage { get; set; } /// <summary> /// Stores whether using the context attribute is optional. /// </summary> public bool Optional { get; set; } /// <summary> /// Creates a new context attribute that stores information that can be passed between build tasks. /// </summary> /// <param name="usage">The usage behavior for the attribute. By default it is set to <see cref="ContextUsage.InOut"/>.</param> /// <param name="optional">Set to true if using the attribute is optional. Set to false otherwise.</param> public InjectContextAttribute(ContextUsage usage = ContextUsage.InOut, bool optional = false) { this.Usage = usage; Optional = optional; } } /// <summary> /// Options for how the attribute is used among build tasks. It can be either injected to and or extracted from a build task. /// </summary> public enum ContextUsage { /// <summary> /// Use to indicate that the attribute can be injected to and extracted from a build task. /// </summary> InOut, /// <summary> /// Use to indicate that the attribute can only be injected to a build task. /// </summary> In, /// <summary> /// Use to indicate that the attribute can only be extracted from a build task. /// </summary> Out } class ContextInjector { public static void Inject(IBuildContext context, object obj) { FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic); foreach (FieldInfo field in fields) { object[] attrs = field.GetCustomAttributes(typeof(InjectContextAttribute), true); if (attrs.Length == 0) continue; InjectContextAttribute attr = attrs[0] as InjectContextAttribute; if (attr == null || attr.Usage == ContextUsage.Out) continue; object injectionObject; if (field.FieldType == typeof(IBuildContext)) injectionObject = context; else if (!attr.Optional) injectionObject = context.GetContextObject(field.FieldType); else { IContextObject contextObject; context.TryGetContextObject(field.FieldType, out contextObject); injectionObject = contextObject; } field.SetValue(obj, injectionObject); } } public static void Extract(IBuildContext context, object obj) { FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic); foreach (FieldInfo field in fields) { object[] attrs = field.GetCustomAttributes(typeof(InjectContextAttribute), true); if (attrs.Length == 0) continue; InjectContextAttribute attr = attrs[0] as InjectContextAttribute; if (attr == null || attr.Usage == ContextUsage.In) continue; if (field.FieldType == typeof(IBuildContext)) throw new InvalidOperationException("IBuildContext can only be used with the ContextUsage.In option."); IContextObject contextObject = field.GetValue(obj) as IContextObject; if (!attr.Optional) context.SetContextObject(field.FieldType, contextObject); else if (contextObject != null) context.SetContextObject(field.FieldType, contextObject); } } } }