using System; using System.Collections.Generic; using UnityEngine; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using BITKit.Entities; using Cysharp.Threading.Tasks; using UnityEngine.Profiling; using UnityEngine.UIElements; using Random = UnityEngine.Random; // ReSharper disable RedundantTypeArgumentsOfMethod namespace BITKit.Entities { [CustomType(typeof(IUnityEntity))] [CustomType(typeof(IEntity))] public class Entity : MonoBehaviour, IUnityEntity,IEntity { private readonly GenericEvent genericEvent = new(); [SerializeField,ReadOnly] private int id; [SerializeField] private bool useAwake; [SerializeField, ReadOnly] private string serviceReport = "Waiting"; public int Id { get => id; set => id = value; } public CancellationToken CancellationToken { get; private set; } public IEntityBehavior[] Behaviors { get;private set; } public bool TryGetComponent(Type type, out IEntityComponent component) { var value = genericEvent.Get(type.FullName); if (value is not null) { component = (IEntityComponent)value; return true; } component = default!; return false; } public IEntityComponent[] Components => Behaviors.Cast().ToArray(); private bool _initialized; bool Entities.IEntity.RegisterComponent(T component) { throw new InvalidOperationException("Unity Entity can't register component"); } IServiceProvider Entities.IEntity.ServiceProvider=> throw new InvalidOperationException("Unity Entity can't register component"); public void Inject(object obj) { foreach (var propertyInfo in obj .GetType() .GetProperties(ReflectionHelper.Flags) .Where(x=>x.GetCustomAttribute(true) is not null)) { var type = propertyInfo.PropertyType; var attribute = propertyInfo.GetCustomAttribute(); var currentValue = propertyInfo.GetValue(obj); try { switch (currentValue) { case null: break; case IEntityComponent entityComponent: if(entityComponent.Entity.Id == Id) continue; break; case MonoBehaviour { destroyCancellationToken: { IsCancellationRequested: false } }: continue; case not null: continue; } } catch (MissingReferenceException){} if(genericEvent.TryGetObjectDirect(type.FullName,out var value)) { propertyInfo.SetValue(obj,value,null); } else if(attribute?.CanBeNull is false) { BIT4Log.Warning($"{name}未找到{obj.GetType().Name}需要的{type.FullName}"); } } foreach (var fieldInfo in obj .GetType() .GetFields(ReflectionHelper.Flags) .Where(fieldInfo=>fieldInfo.GetCustomAttribute(true) is not null)) { var type = fieldInfo.FieldType; var attribute = fieldInfo.GetCustomAttribute(); var currentValue = fieldInfo.GetValue(obj); try { switch (currentValue) { case null: break; case Entities.IEntityComponent entityComponent: if(entityComponent.Entity.Id == Id) continue; break; case MonoBehaviour { destroyCancellationToken: { IsCancellationRequested: false } }: continue; case not null: continue; } } catch (MissingReferenceException){} if(genericEvent.TryGetObjectDirect(type.FullName,out var value)) { fieldInfo.SetValue(obj,value); } else if(attribute?.CanBeNull is false) { BIT4Log.Warning($"{name}未找到{obj.GetType().Name}需要的{type.FullName}"); //BIT4Log.Warning(genericEvent.GetDiagnostics()); } } } public void AddService(T service) { AddService(typeof(T),service); } public void AddService(object service) { AddService(service.GetType(),service); } public void AddService(Type type, object service) { genericEvent.Set(type,service); genericEvent.Set(type.FullName, service); genericEvent.SetDirect(type.FullName,service); } private bool isInitialized; public void WaitForInitializationComplete() { if (isInitialized) return; InitializeInternel(); isInitialized = true; } private void Awake() { if (Id is 0) Id = Guid.NewGuid().GetHashCode(); CancellationToken = destroyCancellationToken; Set(CancellationToken); if (useAwake) { InitializeInternel(); } } private void Start() { if (!useAwake) { InitializeInternel(); } Behaviors.ForEach(x => x.OnStart()); UnityEntitiesService.Register(this); destroyCancellationToken.Register(() => UnityEntitiesService.UnRegister(this)); } private void InitializeInternel() { if (isInitialized) return; try { var reportBuilder = new StringBuilder(); AddService(this); AddService(this); AddService(this); Behaviors = GetComponentsInChildren(true).Distinct().ToArray(); var monoBehaviours = GetComponentsInChildren(true); Behaviors.ForEach(x => x.Initialize(this)); foreach (var x in monoBehaviours) { try { foreach (var att in x //.GetCustomAttributes() .GetType() //.GetCustomAttributes() .GetCustomAttributes() .OfType() ) { reportBuilder.AppendLine(att.Type.FullName); AddService(att.Type, x); if (att.AsGlobal) DI.Register(att.Type, x); } } catch (Exception e) { BIT4Log.Warning("Failed to inject " + x.GetType().Name); throw; } serviceReport = reportBuilder.ToString(); genericEvent.Set(x.GetType(),x); } foreach (var x in monoBehaviours) { Inject(x); } Behaviors.ForEach(x => x.OnAwake()); isInitialized = true; } catch (Exception e) { Debug.LogWarning(name); Debug.LogException(e); } _initialized = true; } private void OnDestroy() { if (!_initialized) return; foreach (var x in Behaviors) { x.OnDestroyComponent(); } } private void Update() { var deltaTime = Time.fixedDeltaTime; foreach (var x in Behaviors) { x.OnUpdate(deltaTime); } } private void FixedUpdate() { var deltaTime = Time.fixedDeltaTime; foreach (var x in Behaviors) { x.OnFixedUpdate(deltaTime); } } private void LateUpdate() { var deltaTime = Time.fixedDeltaTime; foreach (var x in Behaviors) { x.OnLateUpdate(deltaTime); } } public void AddListener(Action action) => genericEvent.AddListener(action); public void Invoke(T value) => genericEvent.Invoke(value); public void RemoveListener(Action action) => genericEvent.RemoveListener(action); public void AddListener(string key, Action action) => genericEvent.AddListener(key, action); public void Invoke(string key, T value) => genericEvent.Invoke(key, value); public void Invoke() where T : new() => genericEvent.Invoke(); public void RemoveListener(string key, Action action) => genericEvent.RemoveListener(key, action); public void SetDirect(int key, object value) { genericEvent.SetDirect(key, value); } public void GetDirect(int key, out object value) { genericEvent.GetDirect(key, out value); } public void GetDirect(int key, out T value) { genericEvent.GetDirect(key, out value); } public T Get(string key = Constant.System.Internal) { var value = genericEvent.Get(key); if (value is not null || !typeof(T).IsAssignableFrom(typeof(Component))) return value; if (!TryGetComponent(out var component)) return default(T); Set(component); return component; } public void Set(T value) => genericEvent.Set(value); public void Set(string key = Constant.System.Internal, T value = default) => genericEvent.Set(key, value); } // #if UNITY_EDITOR // [UnityEditor.CustomEditor(typeof(Entity))] // public class EntityInspector : BITInspector // { // public override VisualElement CreateInspectorGUI() // { // FillDefaultInspector(); // CreateSubTitle("Identity"); // var idLabel = root.Create