123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- // ReSharper disable once RedundantUsingDirective
- using System.Linq;
- namespace SRF
- {
- using System;
- using System.Collections.Generic;
- using System.Reflection;
- using Helpers;
- using Service;
- using UnityEngine;
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field)]
- public sealed class RequiredFieldAttribute : Attribute
- {
- private bool _autoCreate;
- private bool _autoSearch;
- private bool _editorOnly = true;
- public RequiredFieldAttribute(bool autoSearch)
- {
- AutoSearch = autoSearch;
- }
- public RequiredFieldAttribute() {}
- public bool AutoSearch
- {
- get { return _autoSearch; }
- set { _autoSearch = value; }
- }
- public bool AutoCreate
- {
- get { return _autoCreate; }
- set { _autoCreate = value; }
- }
- [Obsolete]
- public bool EditorOnly
- {
- get { return _editorOnly; }
- set { _editorOnly = value; }
- }
- }
- /// <summary>
- /// Add to a field to attempt to use SRServiceManager to get an instance of the field type
- /// </summary>
- [AttributeUsage(AttributeTargets.Field)]
- public class ImportAttribute : Attribute
- {
- public readonly Type Service;
- public ImportAttribute() {}
- public ImportAttribute(Type serviceType)
- {
- Service = serviceType;
- }
- }
- public abstract class SRMonoBehaviourEx : SRMonoBehaviour
- {
- private static Dictionary<Type, IList<FieldInfo>> _checkedFields;
- private static void CheckFields(SRMonoBehaviourEx instance, bool justSet = false)
- {
- if (_checkedFields == null)
- {
- _checkedFields = new Dictionary<Type, IList<FieldInfo>>();
- }
- var t = instance.GetType();
- IList<FieldInfo> cache;
- if (!_checkedFields.TryGetValue(instance.GetType(), out cache))
- {
- cache = ScanType(t);
- _checkedFields.Add(t, cache);
- }
- PopulateObject(cache, instance, justSet);
- }
- private static void PopulateObject(IList<FieldInfo> cache, SRMonoBehaviourEx instance, bool justSet)
- {
- for (var i = 0; i < cache.Count; i++)
- {
- var f = cache[i];
- if (!EqualityComparer<object>.Default.Equals(f.Field.GetValue(instance), null))
- {
- continue;
- }
- // If import is enabled, use SRServiceManager to import the reference
- if (f.Import)
- {
- var t = f.ImportType ?? f.Field.FieldType;
- var service = SRServiceManager.GetService(t);
- if (service == null)
- {
- Debug.LogWarning("Field {0} import failed (Type {1})".Fmt(f.Field.Name, t));
- continue;
- }
- f.Field.SetValue(instance, service);
- continue;
- }
- // If autoset is enabled on field, try and find the component on the GameObject
- if (f.AutoSet)
- {
- var newValue = instance.GetComponent(f.Field.FieldType);
- if (!EqualityComparer<object>.Default.Equals(newValue, null))
- {
- f.Field.SetValue(instance, newValue);
- continue;
- }
- }
- if (justSet)
- {
- continue;
- }
- if (f.AutoCreate)
- {
- var newValue = instance.CachedGameObject.AddComponent(f.Field.FieldType);
- f.Field.SetValue(instance, newValue);
- }
- throw new UnassignedReferenceException(
- "Field {0} is unassigned, but marked with RequiredFieldAttribute".Fmt(f.Field.Name));
- }
- }
- private static List<FieldInfo> ScanType(Type t)
- {
- var cache = new List<FieldInfo>();
- // Check for attribute added to the class
- var globalAttr = SRReflection.GetAttribute<RequiredFieldAttribute>(t);
- #if NETFX_CORE
- var fields = t.GetTypeInfo().DeclaredFields.Where(f => !f.IsStatic);
- #else
- // Check each field for the attribute
- var fields = t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
- #endif
- foreach (var f in fields)
- {
- var requiredFieldAttribute = SRReflection.GetAttribute<RequiredFieldAttribute>(f);
- var importAttribute = SRReflection.GetAttribute<ImportAttribute>(f);
- if (globalAttr == null && requiredFieldAttribute == null && importAttribute == null)
- {
- continue; // Early out if no attributes found.
- }
- var info = new FieldInfo();
- info.Field = f;
- if (importAttribute != null)
- {
- info.Import = true;
- info.ImportType = importAttribute.Service;
- }
- else if (requiredFieldAttribute != null)
- {
- info.AutoSet = requiredFieldAttribute.AutoSearch;
- info.AutoCreate = requiredFieldAttribute.AutoCreate;
- }
- else
- {
- info.AutoSet = globalAttr.AutoSearch;
- info.AutoCreate = globalAttr.AutoCreate;
- }
- cache.Add(info);
- }
- return cache;
- }
- protected virtual void Awake()
- {
- CheckFields(this);
- }
- protected virtual void Start() {}
- protected virtual void Update() {}
- protected virtual void FixedUpdate() {}
- protected virtual void OnEnable() {}
- protected virtual void OnDisable() {}
- protected virtual void OnDestroy() {}
- private struct FieldInfo
- {
- public bool AutoCreate;
- public bool AutoSet;
- public System.Reflection.FieldInfo Field;
- public bool Import;
- public Type ImportType;
- }
- }
- }
|