using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
#if !NET_STANDARD_2_0
using System.Reflection.Emit;
#endif
using UnityEngine;
namespace SoftMasking {
///
/// Mark an implementation of the IMaterialReplacer interface with this attribute to
/// register it in the global material replacer chain. The global replacers will be
/// used automatically by all SoftMasks.
///
/// Globally registered replacers are called in order of ascending of their `order`
/// value. The traversal is stopped on the first IMaterialReplacer which returns a
/// non-null value and this returned value is then used as a replacement.
///
/// Implementation of IMaterialReplacer marked by this attribute should have a
/// default constructor.
///
///
///
[AttributeUsage(AttributeTargets.Class)]
public class GlobalMaterialReplacerAttribute : Attribute { }
///
/// Used by SoftMask to automatically replace materials which don't support
/// Soft Mask by those that do.
///
///
public interface IMaterialReplacer {
///
/// Determines the mutual order in which IMaterialReplacers will be called.
/// The lesser the return value, the earlier it will be called, that is,
/// replacers are sorted by ascending of the `order` value.
/// The order of default implementation is 0. If you want your function to be
/// called before, return a value lesser than 0.
///
int order { get; }
///
/// Should return null if this replacer can't replace the given material.
///
Material Replace(Material material);
}
public static class MaterialReplacer {
static List _globalReplacers;
///
/// Returns the collection of all globally registered replacers.
///
///
public static IEnumerable globalReplacers {
get {
if (_globalReplacers == null)
_globalReplacers = CollectGlobalReplacers().ToList();
return _globalReplacers;
}
}
static IEnumerable CollectGlobalReplacers() {
return AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypesSafe())
.Where(t => IsMaterialReplacerType(t))
.Select(t => TryCreateInstance(t))
.Where(t => t != null);
}
static bool IsMaterialReplacerType(Type t) {
#if NET_STANDARD_2_0
var isTypeBuilder = false;
#else
var isTypeBuilder = t is TypeBuilder;
#endif
return !isTypeBuilder
&& !t.IsAbstract
&& t.IsDefined(typeof(GlobalMaterialReplacerAttribute), false)
&& typeof(IMaterialReplacer).IsAssignableFrom(t);
}
static IMaterialReplacer TryCreateInstance(Type t) {
try {
return (IMaterialReplacer)Activator.CreateInstance(t);
} catch (Exception ex) {
Debug.LogErrorFormat("Could not create instance of {0}: {1}", t.Name, ex);
return null;
}
}
static IEnumerable GetTypesSafe(this Assembly asm) {
try {
return asm.GetTypes();
} catch (ReflectionTypeLoadException e) {
return e.Types.Where(t => t != null);
}
}
}
public class MaterialReplacerChain : IMaterialReplacer {
readonly List _replacers;
public MaterialReplacerChain(IEnumerable replacers, IMaterialReplacer yetAnother) {
_replacers = replacers.ToList();
_replacers.Add(yetAnother);
Initialize();
}
public int order { get; private set; }
public Material Replace(Material material) {
for (int i = 0; i < _replacers.Count; ++i) {
var result = _replacers[i].Replace(material);
if (result != null)
return result;
}
return null;
}
void Initialize() {
_replacers.Sort((a, b) => a.order.CompareTo(b.order));
order = _replacers[0].order;
}
}
}