268 lines
9.7 KiB
C#
268 lines
9.7 KiB
C#
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;
|
|
// ReSharper disable RedundantTypeArgumentsOfMethod
|
|
|
|
namespace BITKit.Entities
|
|
{
|
|
[CustomType(typeof(IUnityEntity))]
|
|
[CustomType(typeof(IEntity))]
|
|
public class Entity : MonoBehaviour, IUnityEntity
|
|
{
|
|
private readonly GenericEvent genericEvent = new();
|
|
|
|
|
|
public int Id { get; set; }
|
|
public CancellationToken CancellationToken { get; private set; }
|
|
public IEntityBehavior[] Behaviors { get;private set; }
|
|
public IEntityComponent[] Components => Behaviors.Cast<IEntityComponent>().ToArray();
|
|
private bool _initialized;
|
|
bool Entities.IEntity.RegisterComponent<T>(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<InjectAttribute>(true) is not null))
|
|
{
|
|
var type = propertyInfo.PropertyType;
|
|
var attribute = propertyInfo.GetCustomAttribute<InjectAttribute>();
|
|
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<Entity>($"{name}未找到{obj.GetType().Name}需要的{type.FullName}");
|
|
}
|
|
}
|
|
foreach (var fieldInfo in obj
|
|
.GetType()
|
|
.GetFields(ReflectionHelper.Flags)
|
|
.Where(fieldInfo=>fieldInfo.GetCustomAttribute<InjectAttribute>(true) is not null))
|
|
{
|
|
var type = fieldInfo.FieldType;
|
|
var attribute = fieldInfo.GetCustomAttribute<InjectAttribute>();
|
|
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<Entity>($"{name}未找到{obj.GetType().Name}需要的{type.FullName}");
|
|
//BIT4Log.Warning<Entity>(genericEvent.GetDiagnostics());
|
|
}
|
|
}
|
|
}
|
|
|
|
public void AddService<T>(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;
|
|
Start();
|
|
isInitialized = true;
|
|
}
|
|
private void Awake()
|
|
{
|
|
if (Id.IsDefault())
|
|
Id = GetInstanceID();
|
|
CancellationToken = gameObject.GetCancellationTokenOnDestroy();
|
|
Set(CancellationToken);
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
if (isInitialized) return;
|
|
try
|
|
{
|
|
AddService<IEntity>(this);
|
|
AddService<Entity>(this);
|
|
AddService<IUnityEntity>(this);
|
|
|
|
Behaviors = GetComponentsInChildren<IEntityBehavior>(true).Distinct().ToArray();
|
|
var monoBehaviours = GetComponentsInChildren<MonoBehaviour>(true);
|
|
Behaviors.ForEach(x => x.Initialize(this));
|
|
foreach (var x in monoBehaviours)
|
|
{
|
|
foreach (var att in x
|
|
//.GetCustomAttributes<CustomTypeAttribute>()
|
|
.GetType()
|
|
//.GetCustomAttributes<CustomTypeAttribute>()
|
|
.GetCustomAttributes()
|
|
.OfType<CustomTypeAttribute>()
|
|
)
|
|
{
|
|
AddService(att.Type, x);
|
|
if (att.AsGlobal)
|
|
DI.Register(att.Type, x);
|
|
}
|
|
|
|
genericEvent.Set(x.GetType(),x);
|
|
}
|
|
foreach (var x in monoBehaviours)
|
|
{
|
|
Inject(x);
|
|
}
|
|
|
|
|
|
Behaviors.ForEach(x => x.OnAwake());
|
|
Behaviors.ForEach(x => x.OnStart());
|
|
isInitialized = true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogWarning(name);
|
|
Debug.LogException(e);
|
|
}
|
|
UnityEntitiesService.Register(this);
|
|
destroyCancellationToken.Register(() => UnityEntitiesService.UnRegister(this));
|
|
_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<T>(Action<T> action) => genericEvent.AddListener<T>(action);
|
|
public void Invoke<T>(T value) => genericEvent.Invoke<T>(value);
|
|
public void RemoveListener<T>(Action<T> action) => genericEvent.RemoveListener<T>(action);
|
|
public void AddListener<T>(string key, Action<T> action) => genericEvent.AddListener<T>(key, action);
|
|
public void Invoke<T>(string key, T value) => genericEvent.Invoke<T>(key, value);
|
|
public void Invoke<T>() where T : new() => genericEvent.Invoke<T>();
|
|
public void RemoveListener<T>(string key, Action<T> action) => genericEvent.RemoveListener<T>(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<T>(int key, out T value)
|
|
{
|
|
genericEvent.GetDirect(key, out value);
|
|
}
|
|
|
|
public T Get<T>(string key = Constant.System.Internal)
|
|
{
|
|
var value = genericEvent.Get<T>(key);
|
|
if (value is not null || !typeof(T).IsAssignableFrom(typeof(Component))) return value;
|
|
if (!TryGetComponent<T>(out var component)) return default(T);
|
|
Set<T>(component);
|
|
return component;
|
|
}
|
|
public void Set<T>(T value) => genericEvent.Set<T>(value);
|
|
public void Set<T>(string key = Constant.System.Internal, T value = default) => genericEvent.Set<T>(key, value);
|
|
}
|
|
#if UNITY_EDITOR
|
|
[UnityEditor.CustomEditor(typeof(Entity))]
|
|
public class EntityInspector : BITInspector<Entity>
|
|
{
|
|
public override VisualElement CreateInspectorGUI()
|
|
{
|
|
FillDefaultInspector();
|
|
CreateSubTitle("Identity");
|
|
var idLabel = root.Create<Label>();
|
|
idLabel.text = agent.Id.ToString();
|
|
return root;
|
|
}
|
|
}
|
|
#endif
|
|
} |