using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using SRF.Components; using SRF.Helpers; using UnityEngine; namespace SRF.Service { [AddComponentMenu("SRF/Service/Service Manager")] public class SRServiceManager : SRAutoSingleton { [Serializable] private class Service { public object Object; public Type Type; } [Serializable] private class ServiceStub { public Func Constructor; public Type InterfaceType; public Func Selector; public Type Type; public override string ToString() { string text = InterfaceType.Name + " ("; if (Type != null) { text = text + "Type: " + Type; } else if (Selector != null) { text = text + "Selector: " + Selector; } else if (Constructor != null) { text = text + "Constructor: " + Constructor; } return text + ")"; } } public const bool EnableLogging = false; public static int LoadingCount; private readonly SRList _services = new SRList(); private List _serviceStubs; private static bool _hasQuit; public static bool IsLoading { get { return LoadingCount > 0; } } public static T GetService() where T : class { T val = GetServiceInternal(typeof(T)) as T; if (val == null && !_hasQuit) { Debug.LogWarning("Service {0} not found. (HasQuit: {1})".Fmt(typeof(T).Name, _hasQuit)); } return val; } public static object GetService(Type t) { object serviceInternal = GetServiceInternal(t); if (serviceInternal == null && !_hasQuit) { Debug.LogWarning("Service {0} not found. (HasQuit: {1})".Fmt(t.Name, _hasQuit)); } return serviceInternal; } private static object GetServiceInternal(Type t) { if (_hasQuit || !Application.isPlaying) { return null; } SRList services = SRAutoSingleton.Instance._services; for (int i = 0; i < services.Count; i++) { Service service = services[i]; if (t.IsAssignableFrom(service.Type)) { if (service.Object == null) { UnRegisterService(t); break; } return service.Object; } } return SRAutoSingleton.Instance.AutoCreateService(t); } public static bool HasService() where T : class { return HasService(typeof(T)); } public static bool HasService(Type t) { if (_hasQuit || !Application.isPlaying) { return false; } SRList services = SRAutoSingleton.Instance._services; for (int i = 0; i < services.Count; i++) { Service service = services[i]; if (t.IsAssignableFrom(service.Type)) { return service.Object != null; } } return false; } public static void RegisterService(object service) where T : class { RegisterService(typeof(T), service); } private static void RegisterService(Type t, object service) { if (_hasQuit) { return; } if (HasService(t)) { if (GetServiceInternal(t) == service) { return; } throw new Exception("Service already registered for type " + t.Name); } UnRegisterService(t); if (!t.IsInstanceOfType(service)) { throw new ArgumentException("service {0} must be assignable from type {1}".Fmt(service.GetType(), t)); } SRAutoSingleton.Instance._services.Add(new Service { Object = service, Type = t }); } public static void UnRegisterService() where T : class { UnRegisterService(typeof(T)); } private static void UnRegisterService(Type t) { if (_hasQuit || !SRAutoSingleton.HasInstance || !HasService(t)) { return; } SRList services = SRAutoSingleton.Instance._services; for (int num = services.Count - 1; num >= 0; num--) { Service service = services[num]; if (service.Type == t) { services.RemoveAt(num); } } } protected override void Awake() { _hasQuit = false; base.Awake(); UnityEngine.Object.DontDestroyOnLoad(base.CachedGameObject); base.CachedGameObject.hideFlags = HideFlags.NotEditable; } protected void UpdateStubs() { if (_serviceStubs != null) { return; } _serviceStubs = new List(); List list = new List(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { string fullName = assembly.FullName; if (fullName.StartsWith("mscorlib") || fullName.StartsWith("System") || fullName.StartsWith("UnityEngine") || fullName.StartsWith("Mono.") || fullName.StartsWith("Boo.") || fullName.StartsWith("UnityEditor") || fullName.StartsWith("Unity.") || fullName.StartsWith("UnityScript") || fullName.StartsWith("nunit.") || fullName.StartsWith("I18N") || fullName.StartsWith("ICSharpCode") || fullName.StartsWith("Newtonsoft.Json")) { continue; } try { bool flag = false; byte[] publicKeyToken = assembly.GetName().GetPublicKeyToken(); foreach (byte b in publicKeyToken) { if (b > 0) { flag = true; break; } } if (!flag) { list.AddRange(assembly.GetExportedTypes()); } } catch (Exception exception) { Debug.LogError("[SRServiceManager] Error loading assembly {0}".Fmt(assembly.FullName), this); Debug.LogException(exception); } } foreach (Type item in list) { ScanType(item); } string[] array = _serviceStubs.Select((ServiceStub p) => "\t{0}".Fmt(p)).ToArray(); } protected object AutoCreateService(Type t) { UpdateStubs(); foreach (ServiceStub serviceStub in _serviceStubs) { if (serviceStub.InterfaceType != t) { continue; } object obj = null; if (serviceStub.Constructor != null) { obj = serviceStub.Constructor(); } else { Type type = serviceStub.Type; if (type == null) { type = serviceStub.Selector(); } obj = DefaultServiceConstructor(t, type); } if (!HasService(t)) { RegisterService(t, obj); } return obj; } return null; } protected void OnApplicationQuit() { _hasQuit = true; } private static object DefaultServiceConstructor(Type serviceIntType, Type implType) { if (typeof(MonoBehaviour).IsAssignableFrom(implType)) { GameObject gameObject = new GameObject("_S_" + serviceIntType.Name); return gameObject.AddComponent(implType); } if (typeof(ScriptableObject).IsAssignableFrom(implType)) { return ScriptableObject.CreateInstance(implType); } return Activator.CreateInstance(implType); } private void ScanType(Type type) { ServiceAttribute attribute = SRReflection.GetAttribute(type); if (attribute != null) { _serviceStubs.Add(new ServiceStub { Type = type, InterfaceType = attribute.ServiceType }); } ScanTypeForConstructors(type, _serviceStubs); ScanTypeForSelectors(type, _serviceStubs); } private static void ScanTypeForSelectors(Type t, List stubs) { MethodInfo[] staticMethods = GetStaticMethods(t); MethodInfo[] array = staticMethods; foreach (MethodInfo methodInfo in array) { ServiceSelectorAttribute attrib = SRReflection.GetAttribute(methodInfo); if (attrib == null) { continue; } if (methodInfo.ReturnType != typeof(Type)) { Debug.LogError("ServiceSelector must have return type of Type ({0}.{1}())".Fmt(t.Name, methodInfo.Name)); continue; } if (methodInfo.GetParameters().Length > 0) { Debug.LogError("ServiceSelector must have no parameters ({0}.{1}())".Fmt(t.Name, methodInfo.Name)); continue; } ServiceStub serviceStub = stubs.FirstOrDefault((ServiceStub p) => p.InterfaceType == attrib.ServiceType); if (serviceStub == null) { ServiceStub serviceStub2 = new ServiceStub(); serviceStub2.InterfaceType = attrib.ServiceType; serviceStub = serviceStub2; stubs.Add(serviceStub); } serviceStub.Selector = (Func)Delegate.CreateDelegate(typeof(Func), methodInfo); } } private static void ScanTypeForConstructors(Type t, List stubs) { MethodInfo[] staticMethods = GetStaticMethods(t); MethodInfo[] array = staticMethods; foreach (MethodInfo method in array) { ServiceConstructorAttribute attrib = SRReflection.GetAttribute(method); if (attrib == null) { continue; } if (method.ReturnType != attrib.ServiceType) { Debug.LogError("ServiceConstructor must have return type of {2} ({0}.{1}())".Fmt(t.Name, method.Name, attrib.ServiceType)); continue; } if (method.GetParameters().Length > 0) { Debug.LogError("ServiceConstructor must have no parameters ({0}.{1}())".Fmt(t.Name, method.Name)); continue; } ServiceStub serviceStub = stubs.FirstOrDefault((ServiceStub p) => p.InterfaceType == attrib.ServiceType); if (serviceStub == null) { ServiceStub serviceStub2 = new ServiceStub(); serviceStub2.InterfaceType = attrib.ServiceType; serviceStub = serviceStub2; stubs.Add(serviceStub); } serviceStub.Constructor = () => method.Invoke(null, null); } } private static MethodInfo[] GetStaticMethods(Type t) { return t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } } }