316 lines
11 KiB
C#
316 lines
11 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;
|
|
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<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;
|
|
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<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)
|
|
{
|
|
try
|
|
{
|
|
foreach (var att in x
|
|
//.GetCustomAttributes<CustomTypeAttribute>()
|
|
.GetType()
|
|
//.GetCustomAttributes<CustomTypeAttribute>()
|
|
.GetCustomAttributes()
|
|
.OfType<CustomTypeAttribute>()
|
|
)
|
|
{
|
|
reportBuilder.AppendLine(att.Type.FullName);
|
|
AddService(att.Type, x);
|
|
if (att.AsGlobal)
|
|
DI.Register(att.Type, x);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
BIT4Log.Warning<Entity>("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<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
|
|
} |