216 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C#
		
	
	
	
		
		
			
		
	
	
			216 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C#
		
	
	
	
| 
								 | 
							
								// 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;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								}
							 |