@@ -1 +1 @@ | |||
Subproject commit 114ce56f5efe5b5a2a8326ef55587ca668e72503 | |||
Subproject commit b3b6ad7f922cfdac70d1ee5c28c580ddd451a1ff |
@@ -1,6 +1,11 @@ | |||
# Svelto.ECS Changelog | |||
All notable changes to this project will be documented in this file. Changes are listed in random order of importance. | |||
## [3.4.5] - 04-2023 | |||
* improved code after internal data refactoring and fixed some bugs | |||
* Added static DynamicEntityDescriptor method to create a new DynamicEntityDescriptor without passing an array of components | |||
* factory method to build entities without entity descriptor is now internal | |||
## [3.4.4] - 04-2023 | |||
* refactored internal datastructures | |||
@@ -1,8 +1,6 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
using System.Threading; | |||
using DBC.ECS; | |||
using Svelto.Common; | |||
@@ -26,104 +24,6 @@ namespace Svelto.ECS | |||
} | |||
} | |||
public static class BurstCompatibleCounter | |||
{ | |||
public static int counter; | |||
} | |||
static public class ComponentTypeMap | |||
{ | |||
static readonly FasterDictionary<RefWrapper<Type>, ComponentID> _componentTypeMap = new FasterDictionary<RefWrapper<Type>, ComponentID>(); | |||
static readonly FasterDictionary<ComponentID, Type> _reverseComponentTypeMap = new FasterDictionary<ComponentID, Type>(); | |||
public static void Add(Type type, ComponentID idData) | |||
{ | |||
_componentTypeMap.Add(type, idData); | |||
_reverseComponentTypeMap.Add(idData, type); | |||
} | |||
public static ComponentID FetchID(Type type) | |||
{ | |||
return _componentTypeMap[type]; | |||
} | |||
public static Type FetchType(ComponentID id) | |||
{ | |||
return _reverseComponentTypeMap[id]; | |||
} | |||
} | |||
public class ComponentTypeID<T> where T : struct, _IInternalEntityComponent | |||
{ | |||
static readonly SharedStaticWrapper<ComponentID, ComponentTypeID<T>> _id; | |||
public static ComponentID id | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get => _id.Data; | |||
} | |||
//todo: any reason to not do this? If I don't, I cannot Create filters in ready functions and | |||
//I have to remove the CreateFilter method | |||
static ComponentTypeID() | |||
{ | |||
Init(); | |||
} | |||
#if UNITY_BURST | |||
[Unity.Burst.BurstDiscard] | |||
//SharedStatic values must be initialized from not burstified code | |||
#endif | |||
static void Init() | |||
{ | |||
_id.Data = Interlocked.Increment(ref BurstCompatibleCounter.counter); | |||
ComponentTypeMap.Add(typeof(T), id); | |||
} | |||
} | |||
sealed class ComponentIDDebugProxy | |||
{ | |||
public ComponentIDDebugProxy(ComponentID id) | |||
{ | |||
this._id = id; | |||
} | |||
public Type type => ComponentTypeMap.FetchType(_id); | |||
readonly ComponentID _id; | |||
} | |||
[DebuggerTypeProxy(typeof(ComponentIDDebugProxy))] | |||
public struct ComponentID: IEquatable<ComponentID> | |||
{ | |||
public static implicit operator int(ComponentID id) | |||
{ | |||
return id._id; | |||
} | |||
public static implicit operator uint(ComponentID id) | |||
{ | |||
return (uint)id._id; | |||
} | |||
public static implicit operator ComponentID(int id) | |||
{ | |||
return new ComponentID() {_id = id}; | |||
} | |||
public bool Equals(ComponentID other) | |||
{ | |||
return _id == other._id; | |||
} | |||
public override int GetHashCode() | |||
{ | |||
return _id; | |||
} | |||
int _id; | |||
} | |||
public class ComponentBuilder<T> : IComponentBuilder where T : struct, _IInternalEntityComponent | |||
{ | |||
internal static readonly Type ENTITY_COMPONENT_TYPE; | |||
@@ -0,0 +1,52 @@ | |||
using System; | |||
using System.Diagnostics; | |||
namespace Svelto.ECS | |||
{ | |||
sealed class ComponentIDDebugProxy | |||
{ | |||
public ComponentIDDebugProxy(ComponentID id) | |||
{ | |||
this._id = id; | |||
} | |||
public Type type => ComponentTypeMap.FetchType(_id); | |||
readonly ComponentID _id; | |||
} | |||
[DebuggerTypeProxy(typeof(ComponentIDDebugProxy))] | |||
public struct ComponentID: IEquatable<ComponentID> | |||
{ | |||
public static implicit operator int(ComponentID id) | |||
{ | |||
return id._id; | |||
} | |||
public static implicit operator uint(ComponentID id) | |||
{ | |||
return (uint)id._id; | |||
} | |||
public static implicit operator ComponentID(int id) | |||
{ | |||
return new ComponentID() | |||
{ | |||
_id = id | |||
}; | |||
} | |||
public bool Equals(ComponentID other) | |||
{ | |||
return _id == other._id; | |||
} | |||
public override int GetHashCode() | |||
{ | |||
return _id; | |||
} | |||
int _id; | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
using System.Runtime.CompilerServices; | |||
using System.Threading; | |||
using Svelto.Common; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public static class BurstCompatibleCounter | |||
{ | |||
public static int counter; | |||
} | |||
public class ComponentTypeID<T> where T : struct, _IInternalEntityComponent | |||
{ | |||
static readonly SharedStaticWrapper<ComponentID, ComponentTypeID<T>> _id; | |||
public static ComponentID id | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get => _id.Data; | |||
} | |||
static ComponentTypeID() | |||
{ | |||
Init(); | |||
} | |||
#if UNITY_BURST | |||
[Unity.Burst.BurstDiscard] | |||
//SharedStatic values must be initialized from not burstified code | |||
#endif | |||
static void Init() | |||
{ | |||
_id.Data = Interlocked.Increment(ref BurstCompatibleCounter.counter); | |||
ComponentTypeMap.Add(typeof(T), id); | |||
} | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
public static class ComponentTypeMap | |||
{ | |||
static readonly FasterDictionary<RefWrapper<Type>, ComponentID> _componentTypeMap = new FasterDictionary<RefWrapper<Type>, ComponentID>(); | |||
static readonly FasterDictionary<ComponentID, Type> _reverseComponentTypeMap = new FasterDictionary<ComponentID, Type>(); | |||
public static void Add(Type type, ComponentID idData) | |||
{ | |||
_componentTypeMap.Add(type, idData); | |||
_reverseComponentTypeMap.Add(idData, type); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static ComponentID FetchID(Type type) | |||
{ | |||
if (_componentTypeMap.TryGetValue(type, out var index) == false) | |||
{ | |||
//if warming up is working correctly, this should never happen | |||
var componentType = typeof(ComponentTypeID<>).MakeGenericType(type); | |||
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(componentType.TypeHandle); | |||
return _componentTypeMap[type]; | |||
} | |||
return index; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static Type FetchType(ComponentID id) | |||
{ | |||
return _reverseComponentTypeMap[id]; | |||
} | |||
} | |||
} |
@@ -7,7 +7,7 @@ namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot | |||
{ | |||
class GenericEntityFactory : IEntityFactory | |||
class GenericEntityFactory : IEntityFactory, IEntitySerializationFactory | |||
{ | |||
public GenericEntityFactory(EnginesRoot weakReference) | |||
{ | |||
@@ -14,40 +14,48 @@ namespace Svelto.ECS | |||
/// <typeparam name="TType"></typeparam> | |||
public struct DynamicEntityDescriptor<TType> : IDynamicEntityDescriptor where TType : IEntityDescriptor, new() | |||
{ | |||
internal DynamicEntityDescriptor(bool isExtendible) : this() | |||
public static DynamicEntityDescriptor<TType> CreateDynamicEntityDescriptor() | |||
{ | |||
var entityDescriptor = new DynamicEntityDescriptor<TType>(); | |||
var defaultEntities = EntityDescriptorTemplate<TType>.realDescriptor.componentsToBuild; | |||
var length = defaultEntities.Length; | |||
if (FetchEntityInfoComponent(defaultEntities) == -1) | |||
{ | |||
_componentsToBuild = new IComponentBuilder[length + 1]; | |||
entityDescriptor._componentsToBuild = new IComponentBuilder[length + 1]; | |||
Array.Copy(defaultEntities, 0, _componentsToBuild, 0, length); | |||
Array.Copy(defaultEntities, 0, entityDescriptor._componentsToBuild, 0, length); | |||
//assign it after otherwise the previous copy will overwrite the value in case the item | |||
//is already present | |||
_componentsToBuild[length] = new ComponentBuilder<EntityInfoComponent>(new EntityInfoComponent | |||
entityDescriptor._componentsToBuild[length] = new ComponentBuilder<EntityInfoComponent>(new EntityInfoComponent | |||
{ | |||
componentsToBuild = _componentsToBuild | |||
componentsToBuild = entityDescriptor._componentsToBuild | |||
}); | |||
} | |||
else | |||
{ | |||
_componentsToBuild = new IComponentBuilder[length]; | |||
entityDescriptor._componentsToBuild = new IComponentBuilder[length]; | |||
Array.Copy(defaultEntities, 0, _componentsToBuild, 0, length); | |||
Array.Copy(defaultEntities, 0, entityDescriptor._componentsToBuild, 0, length); | |||
} | |||
return entityDescriptor; | |||
} | |||
public DynamicEntityDescriptor(IComponentBuilder[] extraEntityBuilders) : this(true) | |||
public DynamicEntityDescriptor(IComponentBuilder[] extraEntityBuilders) | |||
{ | |||
this = CreateDynamicEntityDescriptor(); | |||
var extraEntitiesLength = extraEntityBuilders.Length; | |||
_componentsToBuild = Construct(extraEntitiesLength, extraEntityBuilders); | |||
} | |||
public DynamicEntityDescriptor(FasterList<IComponentBuilder> extraEntityBuilders) : this(true) | |||
public DynamicEntityDescriptor(FasterList<IComponentBuilder> extraEntityBuilders) | |||
{ | |||
this = CreateDynamicEntityDescriptor(); | |||
var extraEntities = extraEntityBuilders.ToArrayFast(out _); | |||
var extraEntitiesLength = extraEntityBuilders.count; | |||
@@ -38,7 +38,7 @@ namespace Svelto.ECS | |||
protected ExtendibleEntityDescriptor() | |||
{ | |||
_dynamicDescriptor = new DynamicEntityDescriptor<TType>(true); | |||
_dynamicDescriptor = DynamicEntityDescriptor<TType>.CreateDynamicEntityDescriptor(); | |||
} | |||
protected ExtendibleEntityDescriptor<TType> ExtendWith<T>() where T : IEntityDescriptor, new() | |||
@@ -127,6 +127,7 @@ namespace Svelto.ECS | |||
} | |||
public void ClearFilter<T>(int filterID, ExclusiveGroupStruct exclusiveGroupStruct) | |||
where T : struct, _IInternalEntityComponent | |||
{ | |||
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary)) | |||
{ | |||
@@ -137,14 +138,14 @@ namespace Svelto.ECS | |||
} | |||
} | |||
public void ClearFilters<T>(int filterID) | |||
public void ClearFilters<T>(int filterID) where T : struct, _IInternalEntityComponent | |||
{ | |||
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary)) | |||
foreach (var filtersPerGroup in fasterDictionary) | |||
filtersPerGroup.value.ClearFilter(filterID); | |||
} | |||
public void DisposeFilters<T>(ExclusiveGroupStruct exclusiveGroupStruct) | |||
public void DisposeFilters<T>(ExclusiveGroupStruct exclusiveGroupStruct) where T : struct, _IInternalEntityComponent | |||
{ | |||
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary)) | |||
{ | |||
@@ -153,7 +154,7 @@ namespace Svelto.ECS | |||
} | |||
} | |||
public void DisposeFilters<T>() | |||
public void DisposeFilters<T>() where T : struct, _IInternalEntityComponent | |||
{ | |||
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary)) | |||
foreach (var filtersPerGroup in fasterDictionary) | |||
@@ -162,7 +163,7 @@ namespace Svelto.ECS | |||
_filtersLegacy.Remove(ComponentTypeID<T>.id); | |||
} | |||
public void DisposeFilterForGroup<T>(int resetFilterID, ExclusiveGroupStruct group) | |||
public void DisposeFilterForGroup<T>(int resetFilterID, ExclusiveGroupStruct group) where T : struct, _IInternalEntityComponent | |||
{ | |||
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary)) | |||
fasterDictionary[@group].DisposeFilter(resetFilterID); | |||
@@ -185,14 +186,13 @@ namespace Svelto.ECS | |||
public bool AddEntityToFilter<N>(int filtersID, EGID egid, N mapper) where N : IEGIDMapper | |||
{ | |||
ref var filter = | |||
ref CreateOrGetFilterForGroup(filtersID, egid.groupID, new RefWrapperType(mapper.entityType)); | |||
ref var filter = ref CreateOrGetFilterForGroup(filtersID, egid.groupID, ComponentTypeMap.FetchID(mapper.entityType)); | |||
return filter.Add(egid.entityID, mapper); | |||
} | |||
internal ref LegacyFilterGroup CreateOrGetFilterForGroup(int filterID, ExclusiveGroupStruct groupID, | |||
RefWrapperType refWrapper) | |||
ComponentID refWrapper) | |||
{ | |||
var fasterDictionary = _filtersLegacy.GetOrAdd(refWrapper, | |||
() => new FasterDictionary<ExclusiveGroupStruct, LegacyGroupFilters>()); | |||
@@ -1,6 +1,7 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
@@ -15,35 +16,47 @@ namespace Svelto.ECS | |||
List<Assembly> assemblies = AssemblyUtility.GetCompatibleAssemblies(); | |||
foreach (Assembly assembly in assemblies) | |||
{ | |||
var typeOfEntityDescriptors = typeof(IEntityDescriptor); | |||
var typeOfEntityDescriptors = typeof(IEntityDescriptor); | |||
foreach (Type type in AssemblyUtility.GetTypesSafe(assembly)) | |||
foreach (Type type in AssemblyUtility.GetTypesSafe(assembly)) | |||
{ | |||
if (type.IsInterface == false && typeOfEntityDescriptors.IsAssignableFrom(type)) //IsClass and IsSealed and IsAbstract means only static classes | |||
{ | |||
if (typeOfEntityDescriptors.IsAssignableFrom(type)) //IsClass and IsSealed and IsAbstract means only static classes | |||
try | |||
{ | |||
//the main goal of this iteration is to warm up the component builders and descriptors | |||
//note: I could have just instanced the entity descriptor, but in this way I will warm up the EntityDescriptorTemplate too | |||
var warmup = typeof(EntityDescriptorTemplate<>).MakeGenericType(type); | |||
try | |||
{ | |||
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(warmup.TypeHandle); | |||
} | |||
catch | |||
{ | |||
continue; | |||
} | |||
PropertyInfo field = warmup.GetProperty("descriptor", BindingFlags.Static | BindingFlags.Public); | |||
object value = field.GetValue(null); // pass null because the field is static | |||
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(warmup.TypeHandle); | |||
} | |||
catch (Exception e) | |||
{ | |||
continue; | |||
} | |||
} | |||
} | |||
var typeOfComponents = typeof(_IInternalEntityComponent); | |||
// cast the value to your descriptor type | |||
IEntityDescriptor descriptor = (IEntityDescriptor)value; | |||
foreach (IComponentBuilder component in descriptor.componentsToBuild) | |||
{ | |||
var typeArguments = component.GetEntityComponentType(); | |||
var warmup2 = typeof(ComponentTypeID<>).MakeGenericType(typeArguments); | |||
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(warmup2.TypeHandle); | |||
} | |||
//the main goal of this iteration is to warm up the component IDs | |||
foreach (Type type in AssemblyUtility.GetTypesSafe(assembly)) | |||
{ | |||
if (type.IsInterface == false && typeOfComponents.IsAssignableFrom(type)) //IsClass and IsSealed and IsAbstract means only static classes | |||
{ | |||
try | |||
{ | |||
var componentType = typeof(ComponentTypeID<>).MakeGenericType(type); | |||
//is called only once ever, even if runs multiple times. | |||
//this warms up the component builder. There could be different implementation of components builders for the same component type in theory | |||
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(componentType.TypeHandle); | |||
} | |||
catch (Exception e) | |||
{ | |||
continue; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,4 +1,3 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
namespace Svelto.ECS | |||
@@ -52,11 +51,6 @@ namespace Svelto.ECS | |||
EntityInitializer BuildEntity<T>(EGID egid, T entityDescriptor, IEnumerable<object> implementors = null, | |||
[System.Runtime.CompilerServices.CallerMemberName] string caller = null) where T : IEntityDescriptor; | |||
//Todo: analyze if this can be internal or just related to serialization | |||
EntityInitializer BuildEntity(EGID egid, IComponentBuilder[] componentsToBuild, Type descriptorType, | |||
IEnumerable<object> implementors = null, | |||
[System.Runtime.CompilerServices.CallerMemberName] string caller = null); | |||
#if UNITY_NATIVE | |||
Svelto.ECS.Native.NativeEntityFactory ToNative<T>([System.Runtime.CompilerServices.CallerMemberName] string callerName | |||
= null) where T : IEntityDescriptor, new(); | |||
@@ -0,0 +1,12 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
namespace Svelto.ECS | |||
{ | |||
interface IEntitySerializationFactory | |||
{ | |||
EntityInitializer BuildEntity(EGID egid, IComponentBuilder[] componentsToBuild, Type descriptorType, | |||
IEnumerable<object> implementors = null, | |||
[System.Runtime.CompilerServices.CallerMemberName] string caller = null); | |||
} | |||
} |
@@ -9,7 +9,7 @@ namespace Svelto.ECS | |||
public static bool AddEntityToFilter<N>(this EntitiesDB.LegacyFilters legacyFilters, int filtersID, EGID egid, N mapper) where N : IEGIDMultiMapper | |||
{ | |||
ref var filter = | |||
ref legacyFilters.CreateOrGetFilterForGroup(filtersID, egid.groupID, new RefWrapperType(mapper.entityType)); | |||
ref legacyFilters.CreateOrGetFilterForGroup(filtersID, egid.groupID, ComponentTypeMap.FetchID(mapper.entityType)); | |||
return filter.Add(egid.entityID, mapper); | |||
} | |||
@@ -16,7 +16,7 @@ namespace Svelto.ECS.Serialization | |||
? entityDescriptor.componentsToSerialize | |||
: entityDescriptor.componentsToBuild; | |||
var initializer = factory.BuildEntity(egid, entityDescriptorEntitiesToSerialize, TypeCache<T>.type); | |||
var initializer = (factory as IEntitySerializationFactory).BuildEntity(egid, entityDescriptorEntitiesToSerialize, TypeCache<T>.type); | |||
entitySerialization.DeserializeEntityComponents(serializationData, entityDescriptor, ref initializer, | |||
serializationType); | |||
@@ -1,7 +1,7 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<AssemblyName>Svelto.ECS</AssemblyName> | |||
<LangVersion>10</LangVersion> | |||
<LangVersion>9</LangVersion> | |||
<TargetFramework>netstandard2.1</TargetFramework> | |||
<Company>Svelto</Company> | |||
<AssemblyVersion>3.4</AssemblyVersion> | |||
@@ -19,7 +19,7 @@ | |||
"svelto.ecs" | |||
], | |||
"name": "com.sebaslab.svelto.ecs", | |||
"version": "3.4.4", | |||
"version": "3.4.5", | |||
"type": "library", | |||
"unity": "2020.3" | |||
} |
@@ -1,3 +1,3 @@ | |||
{ | |||
"version": "3.4.4" | |||
"version": "3.4.5" | |||
} |