update Hybridity implementation

This commit is contained in:
Mikhail 2023-11-08 15:15:10 +08:00
parent b49be251a5
commit 6354d91769
8 changed files with 289 additions and 210 deletions

View File

@ -37,6 +37,12 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void PrintWarning(object v) => Print(EcsConsts.DEBUG_WARNING_TAG, v);
public static void PrintError(object v) => Print(EcsConsts.DEBUG_ERROR_TAG, v);
public static void Print()
{
#if !DISABLE_DRAGONECS_DEBUGGER
DebugService.Instance.Print("");
#endif
}
public static void Print(object v)
{
#if !DISABLE_DRAGONECS_DEBUGGER

View File

@ -10,60 +10,6 @@ namespace DCFApixels.DragonECS
{
private const BindingFlags RFL_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
private struct ProcessInterface
{
public Type interfaceType;
public string processName;
public ProcessInterface(Type interfaceType, string processName)
{
this.interfaceType = interfaceType;
this.processName = processName;
}
}
private static Dictionary<Type, ProcessInterface> _processes = new Dictionary<Type, ProcessInterface>();
static EcsDebugUtility()
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (!type.IsInterface)
continue;
if (type.GetInterface(nameof(IEcsProcess)) != null)
{
string name = type.Name;
if (name[0] == 'I' && name.Length > 1 && char.IsUpper(name[1]))
name = name.Substring(1);
name = Regex.Replace(name, @"\bEcs|Process\b", "");
_processes.Add(type, new ProcessInterface(type, name));
}
}
}
}
#region Process
public static bool IsProcessInterface(Type type)
{
if (type.IsGenericType) type = type.GetGenericTypeDefinition();
return _processes.ContainsKey(type);
}
public static string GetProcessInterfaceName(Type type)
{
if (type.IsGenericType) type = type.GetGenericTypeDefinition();
return _processes[type].processName;
}
public static bool TryGetProcessInterfaceName(Type type, out string name)
{
if (type.IsGenericType) type = type.GetGenericTypeDefinition();
bool result = _processes.TryGetValue(type, out ProcessInterface data);
name = data.processName;
return result;
}
#endregion
#region GetGenericTypeName
public static string GetGenericTypeFullName<T>(int maxDepth = 2) => GetGenericTypeFullName(typeof(T), maxDepth);
public static string GetGenericTypeFullName(Type type, int maxDepth = 2) => GetGenericTypeNameInternal(type, maxDepth, true);

View File

@ -6,6 +6,7 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using static DCFApixels.DragonECS.EcsDebugUtility;
namespace DCFApixels.DragonECS
@ -263,4 +264,85 @@ namespace DCFApixels.DragonECS
}
}
#endregion
public static class EcsProcessUtility
{
private struct ProcessInterface
{
public Type interfaceType;
public string processName;
public ProcessInterface(Type interfaceType, string processName)
{
this.interfaceType = interfaceType;
this.processName = processName;
}
}
private static Dictionary<Type, ProcessInterface> _processes = new Dictionary<Type, ProcessInterface>();
private static HashSet<Type> _systems = new HashSet<Type>();
static EcsProcessUtility()
{
Type processBasicInterface = typeof(IEcsProcess);
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.GetInterface(nameof(IEcsProcess)) != null || type == processBasicInterface)
{
if (type.IsInterface)
{
string name = type.Name;
if (name[0] == 'I' && name.Length > 1 && char.IsUpper(name[1]))
name = name.Substring(1);
name = Regex.Replace(name, @"\bEcs|Process\b", "");
if (Regex.IsMatch(name, "`\\w{1,}$"))
{
var s = name.Split("`");
name = s[0] + $"<{s[1]}>";
}
_processes.Add(type, new ProcessInterface(type, name));
}
else
{
_systems.Add(type);
}
}
}
}
}
#region Systems
public static bool IsSystem(Type type) => _systems.Contains(type);
public static bool IsEcsSystem(this Type type) => _systems.Contains(type);
#endregion
#region Process
public static bool IsProcessInterface(Type type)
{
if (type.IsGenericType) type = type.GetGenericTypeDefinition();
return _processes.ContainsKey(type);
}
public static bool IsEcsProcessInterface(this Type type) => IsProcessInterface(type);
public static string GetProcessInterfaceName(Type type)
{
if (type.IsGenericType) type = type.GetGenericTypeDefinition();
return _processes[type].processName;
}
public static bool TryGetProcessInterfaceName(Type type, out string name)
{
if (type.IsGenericType) type = type.GetGenericTypeDefinition();
bool result = _processes.TryGetValue(type, out ProcessInterface data);
name = data.processName;
return result;
}
public static IEnumerable<Type> GetEcsProcessInterfaces(this Type self)
{
return self.GetInterfaces().Where(o=> o.IsEcsProcessInterface());
}
#endregion
}
}

View File

@ -73,7 +73,7 @@ namespace DCFApixels.DragonECS
if (_poolIds.Contains(EcsTypeCode.Get<TPool>()))
throw new EcsFrameworkException("The pool has already been created.");
Type componentType = typeof(TPool).GetInterfaces().First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>));
Type componentType = typeof(TPool).GetInterfaces().First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>)).GetGenericArguments()[0];
int componentTypeCode = EcsTypeCode.Get(componentType);
if (_componentIds.TryGetValue(componentTypeCode, out int componentID))

View File

@ -1,13 +1,24 @@
using DCFApixels.DragonECS.Utils;
using DCFApixels.DragonECS.Internal;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using UnityEngine;
using static UnityEditor.Progress;
namespace DCFApixels.DragonECS
{
namespace Internal
{
public interface IEcsHybridPoolInternal : IEcsPool
{
void AddRefInternal(int entityID, object component, bool isAppend);
void DelInternal(int entityID, bool isAppend);
}
}
/// <summary>Pool for IEcsHybridComponent components</summary>
public sealed class EcsHybridPool<T> : IEcsPoolImplementation<T>, IEcsHybridPool<T>, IEnumerable<T> //IEnumerable<T> - IntelliSense hack
public sealed class EcsHybridPool<T> : IEcsPoolImplementation<T>, IEcsHybridPool<T>, IEcsHybridPoolInternal, IEnumerable<T> //IEnumerable<T> - IntelliSense hack
where T : IEcsHybridComponent
{
private EcsWorld _source;
@ -31,25 +42,12 @@ namespace DCFApixels.DragonECS
public EcsWorld World => _source;
#endregion
#region Init
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
{
_source = world;
_componentID = componentID;
const int capacity = 512;
_mapping = new int[world.Capacity];
_recycledItems = new int[128];
_recycledItemsCount = 0;
_items = new T[capacity];
_entities = new int[capacity];
_itemsCount = 0;
}
#endregion
#region Methods
public void Add(int entityID, T component)
void IEcsHybridPoolInternal.AddRefInternal(int entityID, object component, bool isMain)
{
AddInternal(entityID, (T)component, isMain);
}
private void AddInternal(int entityID, T component, bool isMain)
{
ref int itemIndex = ref _mapping[entityID];
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
@ -71,40 +69,23 @@ namespace DCFApixels.DragonECS
}
this.IncrementEntityComponentCount(entityID);
_listeners.InvokeOnAdd(entityID);
if(isMain)
component.OnAddToPool(_source.GetEntityLong(entityID));
_items[itemIndex] = component;
_entities[itemIndex] = entityID;
}
public void Add(int entityID, T component)
{
HybridMapping mapping = _source.GetHybridMapping(component.GetType());
mapping.GetTargetTypePool().AddRefInternal(entityID, component, false);
foreach (var pool in mapping.GetPools())
pool.AddRefInternal(entityID, component, true);
}
public void Set(int entityID, T component)
{
ref int itemIndex = ref _mapping[entityID];
if(itemIndex <= 0)
{//null
if (_recycledItemsCount > 0)
{
itemIndex = _recycledItems[--_recycledItemsCount];
_itemsCount++;
}
else
{
itemIndex = ++_itemsCount;
if (itemIndex >= _items.Length)
{
Array.Resize(ref _items, _items.Length << 1);
Array.Resize(ref _entities, _items.Length);
}
}
this.IncrementEntityComponentCount(entityID);
}
else
{//not null
_listeners.InvokeOnDel(entityID);
_items[itemIndex].OnDelFromPool(_source.GetEntityLong(entityID));
}
_listeners.InvokeOnAdd(entityID);
component.OnAddToPool(_source.GetEntityLong(entityID));
_items[itemIndex] = component;
_entities[itemIndex] = entityID;
if(Has(entityID))
Del(entityID);
Add(entityID, component);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Get(int entityID)
@ -128,13 +109,18 @@ namespace DCFApixels.DragonECS
{
return _mapping[entityID] > 0;
}
public void Del(int entityID)
void IEcsHybridPoolInternal.DelInternal(int entityID, bool isMain)
{
DelInternal(entityID, isMain);
}
private void DelInternal(int entityID, bool isMain)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID);
#endif
ref int itemIndex = ref _mapping[entityID];
T component = _items[itemIndex];
if(isMain)
component.OnDelFromPool(_source.GetEntityLong(entityID));
if (_recycledItemsCount >= _recycledItems.Length)
Array.Resize(ref _recycledItems, _recycledItems.Length << 1);
@ -145,6 +131,14 @@ namespace DCFApixels.DragonECS
this.DecrementEntityComponentCount(entityID);
_listeners.InvokeOnDel(entityID);
}
public void Del(int entityID)
{
var component = Get(entityID);
HybridMapping mapping = _source.GetHybridMapping(component.GetType());
mapping.GetTargetTypePool().DelInternal(entityID, false);
foreach (var pool in mapping.GetPools())
pool.DelInternal(entityID, true);
}
public void TryDel(int entityID)
{
if (Has(entityID)) Del(entityID);
@ -175,6 +169,20 @@ namespace DCFApixels.DragonECS
#endregion
#region Callbacks
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
{
_source = world;
_componentID = componentID;
const int capacity = 512;
_mapping = new int[world.Capacity];
_recycledItems = new int[128];
_recycledItemsCount = 0;
_items = new T[capacity];
_entities = new int[capacity];
_itemsCount = 0;
}
void IEcsPoolImplementation.OnWorldResize(int newSize)
{
Array.Resize(ref _mapping, newSize);
@ -218,13 +226,11 @@ namespace DCFApixels.DragonECS
void OnAddToPool(entlong entity);
void OnDelFromPool(entlong entity);
}
public static class IEcsHybridComponentExtensions
public static class EcsHybridPoolExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNullOrNotAlive(this IEcsHybridComponent self) => self == null || self.IsAlive;
}
public static class EcsHybridPoolExt
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsHybridPool<T> GetPool<T>(this EcsWorld self) where T : IEcsHybridComponent
{
@ -253,65 +259,94 @@ namespace DCFApixels.DragonECS
}
}
public static class InterfaceMatrix
public partial class EcsWorld
{
private static SparseArray<InterfaceMatrixEdge> _edges = new SparseArray<InterfaceMatrixEdge>();
private static SparseArray64<InterfaceMatrixEdge> _matrix = new SparseArray64<InterfaceMatrixEdge>();
public static bool HasEdge<TParent, TChild>()
private Dictionary<Type, HybridMapping> _mappings = new Dictionary<Type, HybridMapping>();
internal HybridMapping GetHybridMapping(Type type)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!InterfaceIsDeclared<TParent>() || !InterfaceIsDeclared<TChild>())
EcsDebug.PrintWarning($"{nameof(TParent)} or {nameof(TChild)} not declared.");
#endif
return _matrix.Contains(InterfaceId<TParent>._id, InterfaceId<TChild>._id);
if(!_mappings.TryGetValue(type, out HybridMapping mapping))
{
mapping = new HybridMapping(this, type);
_mappings.Add(type, mapping);
}
public static bool InterfaceIsDeclared<T>() => _edges.Contains(InterfaceId<T>._id);
public static void DeclareInterfacesFromClass<T>()
{
Type type = typeof(T);
if (type.IsInterface)
throw new ArgumentException($"The argument {nameof(T)} cannot be an interface");
return mapping;
}
}
internal class InterfaceMatrixEdge
{
private static int _increment = 0;
public readonly int id;
public readonly Type parentType;
public readonly Type childType;
public readonly int parentID;
public readonly int childID;
public static InterfaceMatrixEdge New<TParent, TChild>()
internal class HybridMapping
{
return new InterfaceMatrixEdge(
typeof(TParent),
typeof(TChild),
InterfaceId<TParent>._id,
InterfaceId<TChild>._id);
}
public InterfaceMatrixEdge(Type parentType, Type childType, int parentID, int childID)
private EcsWorld _source;
private object[] _sourceForReflection;
private Type _type;
private IEcsHybridPoolInternal _targetTypePool;
private List<IEcsHybridPoolInternal> _relatedPools;
private static Type hybridPoolType = typeof(EcsHybridPool<>);
private static MethodInfo getHybridPoolMethod = typeof(EcsHybridPoolExtensions).GetMethod($"{nameof(EcsHybridPoolExtensions.GetPool)}", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
private static HashSet<Type> _hybridComponents = new HashSet<Type>();
static HybridMapping()
{
id = _increment++;
this.parentType = parentType;
this.childType = childType;
this.parentID = parentID;
this.childID = childID;
Type hybridComponentType = typeof(IEcsHybridComponent);
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.GetInterface(nameof(IEcsHybridComponent)) != null && type != hybridComponentType)
{
_hybridComponents.Add(type);
}
}
internal static class InterfaceId
{
internal static int _increment;
}
internal static class InterfaceId<T>
}
public static bool IsEcsHybridComponentType(Type type)
{
public static int _id = InterfaceId._increment++;
return _hybridComponents.Contains(type);
}
public HybridMapping(EcsWorld source, Type type)
{
if (!type.IsClass)
throw new ArgumentException();
_source = source;
_type = type;
_relatedPools = new List<IEcsHybridPoolInternal>();
_sourceForReflection = new object[]{ source };
_targetTypePool = CreateHybridPool(type);
foreach (var item in type.GetInterfaces())
{
if(IsEcsHybridComponentType(item))
{
_relatedPools.Add(CreateHybridPool(item));
}
}
Type baseType = type.BaseType;
while(baseType != typeof(object) && IsEcsHybridComponentType(baseType))
{
_relatedPools.Add(CreateHybridPool(baseType));
baseType = baseType.BaseType;
}
}
private IEcsHybridPoolInternal CreateHybridPool(Type componentType)
{
//var x = (IEcsHybridPoolInternal)getHybridPoolMethod.MakeGenericMethod(componentType).Invoke(null, _sourceForReflection);
//Debug.Log("_" + x.ComponentID + "_" +x.ComponentType.Name);
//return x;
return (IEcsHybridPoolInternal)getHybridPoolMethod.MakeGenericMethod(componentType).Invoke(null, _sourceForReflection);
}
public IEcsHybridPoolInternal GetTargetTypePool()
{
return _targetTypePool;
}
public List<IEcsHybridPoolInternal> GetPools()
{
return _relatedPools;
}
}
}

View File

@ -31,22 +31,6 @@ namespace DCFApixels.DragonECS
public EcsWorld World => _source;
#endregion
#region Init
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
{
_source = world;
_componentID = componentID;
const int capacity = 512;
_mapping = new int[world.Capacity];
_recycledItems = new int[128];
_recycledItemsCount = 0;
_items = new T[capacity];
_itemsCount = 0;
}
#endregion
#region Methods
public ref T Add(int entityID)
{
@ -149,6 +133,19 @@ namespace DCFApixels.DragonECS
#endregion
#region Callbacks
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
{
_source = world;
_componentID = componentID;
const int capacity = 512;
_mapping = new int[world.Capacity];
_recycledItems = new int[128];
_recycledItemsCount = 0;
_items = new T[capacity];
_itemsCount = 0;
}
void IEcsPoolImplementation.OnWorldResize(int newSize)
{
Array.Resize(ref _mapping, newSize);

View File

@ -26,17 +26,6 @@ namespace DCFApixels.DragonECS
public EcsWorld World => _source;
#endregion
#region Init
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
{
_source = world;
_componentID = componentID;
_mapping = new bool[world.Capacity];
_count = 0;
}
#endregion
#region Method
public void Add(int entityID)
{
@ -114,6 +103,14 @@ namespace DCFApixels.DragonECS
#endregion
#region Callbacks
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
{
_source = world;
_componentID = componentID;
_mapping = new bool[world.Capacity];
_count = 0;
}
void IEcsPoolImplementation.OnWorldResize(int newSize)
{
Array.Resize(ref _mapping, newSize);

View File

@ -1,12 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS
namespace DCFApixels.DragonECS.Internal
{
namespace Internal
{
internal static class EcsTypeCode
public static class EcsTypeCode
{
private static readonly Dictionary<Type, int> _codes = new Dictionary<Type, int>();
private static int _incremetn = 1;
@ -21,11 +20,28 @@ namespace DCFApixels.DragonECS
return code;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Get<T>() => Cache<T>.code;
private static class Cache<T>
{
public static readonly int code = Get(typeof(T));
public static int Get<T>() => EcsTypeCodeCache<T>.code;
public static bool Has(Type type) => _codes.ContainsKey(type);
public static bool Has<T>() => _codes.ContainsKey(typeof(T));
public static IEnumerable<TypeCodeInfo> GetDeclared() => _codes.Select(o => new TypeCodeInfo(o.Key, o.Value));
}
public static class EcsTypeCodeCache<T>
{
public static readonly int code = EcsTypeCode.Get(typeof(T));
}
public struct TypeCodeInfo
{
public Type type;
public int code;
public TypeCodeInfo(Type type, int code)
{
this.type = type;
this.code = code;
}
public override string ToString()
{
return this.AutoToString(false) + "\n\r";
}
}
}