@@ -1,8 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public class AllowMultipleAttribute : Attribute | |||
{ | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 29ca2992915771b4eb047f00a7a4b7a6 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,81 +0,0 @@ | |||
#if DEBUG && !PROFILER | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
#else | |||
using System.Diagnostics; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot | |||
{ | |||
#if DEBUG && !PROFILER | |||
void CheckRemoveEntityID(EGID egid) | |||
{ | |||
// Console.LogError("<color=orange>removed</color>".FastConcat(egid.ToString())); | |||
if (_idCheckers.TryGetValue(egid.groupID, out var hash)) | |||
{ | |||
if (hash.Contains(egid.entityID) == false) | |||
throw new ECSException("Entity with not found ID is about to be removed: id: " | |||
.FastConcat(egid.entityID) | |||
.FastConcat(" groupid: ") | |||
.FastConcat(egid.groupID)); | |||
hash.Remove(egid.entityID); | |||
if (hash.Count == 0) | |||
_idCheckers.Remove(egid.groupID); | |||
} | |||
else | |||
{ | |||
throw new ECSException("Entity with not found ID is about to be removed: id: " | |||
.FastConcat(egid.entityID) | |||
.FastConcat(" groupid: ") | |||
.FastConcat(egid.groupID)); | |||
} | |||
} | |||
void CheckAddEntityID(EGID egid) | |||
{ | |||
// Console.LogError("<color=orange>added</color> ".FastConcat(egid.ToString())); | |||
if (_idCheckers.TryGetValue(egid.groupID, out var hash) == false) | |||
hash = _idCheckers[egid.groupID] = new HashSet<uint>(); | |||
else | |||
{ | |||
if (hash.Contains(egid.entityID)) | |||
throw new ECSException("Entity with used ID is about to be built: '" | |||
.FastConcat("' id: '") | |||
.FastConcat(egid.entityID) | |||
.FastConcat("' groupid: '") | |||
.FastConcat(egid.groupID) | |||
.FastConcat("'")); | |||
} | |||
hash.Add(egid.entityID); | |||
} | |||
void RemoveGroupID(ExclusiveGroup.ExclusiveGroupStruct groupID) | |||
{ | |||
_idCheckers.Remove(groupID); | |||
} | |||
readonly FasterDictionary<uint, HashSet<uint>> _idCheckers = new FasterDictionary<uint, HashSet<uint>>(); | |||
#else | |||
[Conditional("_CHECKS_DISABLED")] | |||
void CheckRemoveEntityID(EGID egid) | |||
{ | |||
} | |||
[Conditional("_CHECKS_DISABLED")] | |||
void CheckAddEntityID(EGID egid) | |||
{ | |||
} | |||
[Conditional("_CHECKS_DISABLED")] | |||
void RemoveGroupID(ExclusiveGroup.ExclusiveGroupStruct groupID) | |||
{ | |||
} | |||
#endif | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: cda6cb7ffa71b954dbe3711e152399c2 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,446 +0,0 @@ | |||
#if DISABLE_DBC || !DEBUG || PROFILER | |||
#define DISABLE_CHECKS | |||
using System.Diagnostics; | |||
#endif | |||
using System; | |||
namespace DBC.ECS | |||
{ | |||
/// <summary> | |||
/// Design By Contract Checks. | |||
/// | |||
/// Each method generates an exception or | |||
/// a trace assertion statement if the contract is broken. | |||
/// </summary> | |||
/// <remarks> | |||
/// This example shows how to call the Require method. | |||
/// Assume DBC_CHECK_PRECONDITION is defined. | |||
/// <code> | |||
/// public void Test(int x) | |||
/// { | |||
/// try | |||
/// { | |||
/// Check.Require(x > 1, "x must be > 1"); | |||
/// } | |||
/// catch (System.Exception ex) | |||
/// { | |||
/// Console.WriteLine(ex.ToString()); | |||
/// } | |||
/// } | |||
/// </code> | |||
/// If you wish to use trace assertion statements, intended for Debug scenarios, | |||
/// rather than exception handling then set | |||
/// | |||
/// <code>Check.UseAssertions = true</code> | |||
/// | |||
/// You can specify this in your application entry point and maybe make it | |||
/// dependent on conditional compilation flags or configuration file settings, e.g., | |||
/// <code> | |||
/// #if DBC_USE_ASSERTIONS | |||
/// Check.UseAssertions = true; | |||
/// #endif | |||
/// </code> | |||
/// You can direct output to a Trace listener. For example, you could insert | |||
/// <code> | |||
/// Trace.Listeners.Clear(); | |||
/// Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); | |||
/// </code> | |||
/// | |||
/// or direct output to a file or the Event Log. | |||
/// | |||
/// (Note: For ASP.NET clients use the Listeners collection | |||
/// of the Debug, not the Trace, object and, for a Release build, only exception-handling | |||
/// is possible.) | |||
/// </remarks> | |||
/// | |||
static class Check | |||
{ | |||
#region Interface | |||
/// <summary> | |||
/// Precondition check. | |||
/// </summary> | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Require(bool assertion, string message) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PreconditionException(message); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Precondition: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Precondition check. | |||
/// </summary> | |||
/// | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Require(bool assertion, string message, Exception inner) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PreconditionException(message, inner); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Precondition: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Precondition check. | |||
/// </summary> | |||
/// | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Require(bool assertion) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PreconditionException("Precondition failed."); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Precondition failed."); | |||
} | |||
} | |||
/// <summary> | |||
/// Postcondition check. | |||
/// </summary> | |||
/// | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Ensure(bool assertion, string message) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PostconditionException(message); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Postcondition: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Postcondition check. | |||
/// </summary> | |||
/// | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Ensure(bool assertion, string message, Exception inner) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PostconditionException(message, inner); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Postcondition: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Postcondition check. | |||
/// </summary> | |||
/// | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Ensure(bool assertion) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PostconditionException("Postcondition failed."); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Postcondition failed."); | |||
} | |||
} | |||
/// <summary> | |||
/// Invariant check. | |||
/// </summary> | |||
/// | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Invariant(bool assertion, string message) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new InvariantException(message); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Invariant: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Invariant check. | |||
/// </summary> | |||
/// | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Invariant(bool assertion, string message, Exception inner) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new InvariantException(message, inner); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Invariant: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Invariant check. | |||
/// </summary> | |||
/// | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Invariant(bool assertion) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new InvariantException("Invariant failed."); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Invariant failed."); | |||
} | |||
} | |||
/// <summary> | |||
/// Assertion check. | |||
/// </summary> | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Assert(bool assertion, string message) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new AssertionException(message); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Assertion: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Assertion check. | |||
/// </summary> | |||
/// | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Assert(bool assertion, string message, Exception inner) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new AssertionException(message, inner); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Assertion: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Assertion check. | |||
/// </summary> | |||
/// | |||
#if DISABLE_CHECKS | |||
[Conditional("__NEVER_DEFINED__")] | |||
#endif | |||
public static void Assert(bool assertion) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new AssertionException("Assertion failed."); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Assertion failed."); | |||
} | |||
} | |||
/// <summary> | |||
/// Set this if you wish to use Trace Assert statements | |||
/// instead of exception handling. | |||
/// (The Check class uses exception handling by default.) | |||
/// </summary> | |||
public static bool UseAssertions | |||
{ | |||
get | |||
{ | |||
return useAssertions; | |||
} | |||
set | |||
{ | |||
useAssertions = value; | |||
} | |||
} | |||
#endregion // Interface | |||
#region Implementation | |||
// No creation | |||
/// <summary> | |||
/// Is exception handling being used? | |||
/// </summary> | |||
static bool UseExceptions | |||
{ | |||
get | |||
{ | |||
return !useAssertions; | |||
} | |||
} | |||
// Are trace assertion statements being used? | |||
// Default is to use exception handling. | |||
static bool useAssertions; | |||
#endregion // Implementation | |||
} // End Check | |||
internal class Trace | |||
{ | |||
internal static void Assert(bool assertion, string v) | |||
{ | |||
#if NETFX_CORE | |||
System.Diagnostics.Contracts.Contract.Assert(assertion, v); | |||
#else | |||
System.Diagnostics.Trace.Assert(assertion, v); | |||
#endif | |||
} | |||
} | |||
#region Exceptions | |||
/// <summary> | |||
/// Exception raised when a contract is broken. | |||
/// Catch this exception type if you wish to differentiate between | |||
/// any DesignByContract exception and other runtime exceptions. | |||
/// | |||
/// </summary> | |||
public class DesignByContractException : Exception | |||
{ | |||
protected DesignByContractException() {} | |||
protected DesignByContractException(string message) : base(message) {} | |||
protected DesignByContractException(string message, Exception inner) : base(message, inner) {} | |||
} | |||
/// <summary> | |||
/// Exception raised when a precondition fails. | |||
/// </summary> | |||
public class PreconditionException : DesignByContractException | |||
{ | |||
/// <summary> | |||
/// Precondition Exception. | |||
/// </summary> | |||
public PreconditionException() {} | |||
/// <summary> | |||
/// Precondition Exception. | |||
/// </summary> | |||
public PreconditionException(string message) : base(message) {} | |||
/// <summary> | |||
/// Precondition Exception. | |||
/// </summary> | |||
public PreconditionException(string message, Exception inner) : base(message, inner) {} | |||
} | |||
/// <summary> | |||
/// Exception raised when a postcondition fails. | |||
/// </summary> | |||
public class PostconditionException : DesignByContractException | |||
{ | |||
/// <summary> | |||
/// Postcondition Exception. | |||
/// </summary> | |||
public PostconditionException() {} | |||
/// <summary> | |||
/// Postcondition Exception. | |||
/// </summary> | |||
public PostconditionException(string message) : base(message) {} | |||
/// <summary> | |||
/// Postcondition Exception. | |||
/// </summary> | |||
public PostconditionException(string message, Exception inner) : base(message, inner) {} | |||
} | |||
/// <summary> | |||
/// Exception raised when an invariant fails. | |||
/// </summary> | |||
public class InvariantException : DesignByContractException | |||
{ | |||
/// <summary> | |||
/// Invariant Exception. | |||
/// </summary> | |||
public InvariantException() {} | |||
/// <summary> | |||
/// Invariant Exception. | |||
/// </summary> | |||
public InvariantException(string message) : base(message) {} | |||
/// <summary> | |||
/// Invariant Exception. | |||
/// </summary> | |||
public InvariantException(string message, Exception inner) : base(message, inner) {} | |||
} | |||
/// <summary> | |||
/// Exception raised when an assertion fails. | |||
/// </summary> | |||
public class AssertionException : DesignByContractException | |||
{ | |||
/// <summary> | |||
/// Assertion Exception. | |||
/// </summary> | |||
public AssertionException() {} | |||
/// <summary> | |||
/// Assertion Exception. | |||
/// </summary> | |||
public AssertionException(string message) : base(message) {} | |||
/// <summary> | |||
/// Assertion Exception. | |||
/// </summary> | |||
public AssertionException(string message, Exception inner) : base(message, inner) {} | |||
} | |||
#endregion // Exception classes | |||
} // End Design By Contract |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: f25d12935fd762e40841aa5c56e603e4 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,8 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 9d98d8ed291a59c4890021f6391142ca | |||
folderAsset: yes | |||
DefaultImporter: | |||
externalObjects: {} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,46 +0,0 @@ | |||
using System; | |||
using System.Linq.Expressions; | |||
using System.Reflection; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
static class SetEGIDWithoutBoxing<T> where T : struct, IEntityStruct | |||
{ | |||
internal delegate void ActionCast(ref T target, EGID egid); | |||
public static readonly ActionCast SetIDWithoutBoxing = MakeSetter(); | |||
static ActionCast MakeSetter() | |||
{ | |||
if (EntityBuilder<T>.HAS_EGID) | |||
{ | |||
#if !ENABLE_IL2CPP | |||
Type myTypeA = typeof(T); | |||
PropertyInfo myFieldInfo = myTypeA.GetProperty("ID"); | |||
ParameterExpression targetExp = Expression.Parameter(typeof(T).MakeByRefType(), "target"); | |||
ParameterExpression valueExp = Expression.Parameter(typeof(EGID), "value"); | |||
MemberExpression fieldExp = Expression.Property(targetExp, myFieldInfo); | |||
BinaryExpression assignExp = Expression.Assign(fieldExp, valueExp); | |||
var setter = Expression.Lambda<ActionCast>(assignExp, targetExp, valueExp).Compile(); | |||
return setter; | |||
#else | |||
return (ref T target, EGID value) => | |||
{ | |||
var needEgid = (target as INeedEGID); | |||
needEgid.ID = value; | |||
target = (T) needEgid; | |||
}; | |||
#endif | |||
} | |||
return null; | |||
} | |||
public static void Warmup() | |||
{ | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 1e8610cc771cdeb46a808788e49b21d1 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,222 +0,0 @@ | |||
using System; | |||
using Svelto.Common; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public interface ITypeSafeDictionary | |||
{ | |||
int Count { get; } | |||
ITypeSafeDictionary Create(); | |||
void AddEntitiesToEngines( | |||
FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> entityViewEnginesDb, | |||
ITypeSafeDictionary realDic, in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group); | |||
void RemoveEntitiesFromEngines(FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> entityViewEnginesDB, | |||
in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group); | |||
void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId); | |||
void MoveEntityFromEngines(EGID fromEntityGid, EGID? toEntityID, ITypeSafeDictionary toGroup, | |||
FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> engines, in PlatformProfiler profiler); | |||
void AddEntityToDictionary(EGID fromEntityGid, EGID toEntityID, ITypeSafeDictionary toGroup); | |||
void RemoveEntityFromDictionary(EGID fromEntityGid, in PlatformProfiler profiler); | |||
void SetCapacity(uint size); | |||
void Trim(); | |||
void Clear(); | |||
void FastClear(); | |||
bool Has(uint entityIdEntityId); | |||
} | |||
class TypeSafeDictionary<TValue> : FasterDictionary<uint, TValue>, | |||
ITypeSafeDictionary where TValue : struct, IEntityStruct | |||
{ | |||
static readonly Type _type = typeof(TValue); | |||
static readonly string _typeName = _type.Name; | |||
static readonly bool _hasEgid = typeof(INeedEGID).IsAssignableFrom(_type); | |||
public TypeSafeDictionary(uint size) : base(size) {} | |||
public TypeSafeDictionary() {} | |||
public void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId) | |||
{ | |||
var typeSafeDictionary = entitiesToSubmit as TypeSafeDictionary<TValue>; | |||
foreach (var tuple in typeSafeDictionary) | |||
{ | |||
try | |||
{ | |||
if (_hasEgid) SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref tuple.Value, new EGID(tuple.Key, groupId)); | |||
Add(tuple.Key, tuple.Value); | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new TypeSafeDictionaryException( | |||
"trying to add an EntityView with the same ID more than once Entity: " | |||
.FastConcat(typeof(TValue).ToString()).FastConcat(", group ").FastConcat(groupId).FastConcat(", id ").FastConcat(tuple.Key), e); | |||
} | |||
} | |||
} | |||
public void AddEntitiesToEngines( | |||
FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> entityViewEnginesDB, | |||
ITypeSafeDictionary realDic, in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group) | |||
{ | |||
var typeSafeDictionary = realDic as TypeSafeDictionary<TValue>; | |||
//this can be optimized, should pass all the entities and not restart the process for each one | |||
foreach (var value in this) | |||
AddEntityViewToEngines(entityViewEnginesDB, ref typeSafeDictionary.GetValueByRef(value.Key), null, | |||
in profiler, new EGID(value.Key, group)); | |||
} | |||
public void RemoveEntitiesFromEngines( | |||
FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> entityViewEnginesDB, | |||
in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group) | |||
{ | |||
foreach (var value in this) | |||
RemoveEntityViewFromEngines(entityViewEnginesDB, ref GetValueByRef(value.Key), null, in profiler, | |||
new EGID(value.Key, group)); | |||
} | |||
public bool Has(uint entityIdEntityId) | |||
{ | |||
return ContainsKey(entityIdEntityId); | |||
} | |||
public void RemoveEntityFromDictionary(EGID fromEntityGid, in PlatformProfiler profiler) | |||
{ | |||
Remove(fromEntityGid.entityID); | |||
} | |||
public void AddEntityToDictionary(EGID fromEntityGid, EGID toEntityID, ITypeSafeDictionary toGroup) | |||
{ | |||
var valueIndex = GetIndex(fromEntityGid.entityID); | |||
if (toGroup != null) | |||
{ | |||
var toGroupCasted = toGroup as TypeSafeDictionary<TValue>; | |||
ref var entity = ref valuesArray[valueIndex]; | |||
if (_hasEgid) SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref entity, toEntityID); | |||
toGroupCasted.Add(fromEntityGid.entityID, entity); | |||
} | |||
} | |||
public void MoveEntityFromEngines(EGID fromEntityGid, EGID? toEntityID, ITypeSafeDictionary toGroup, | |||
FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> engines, in PlatformProfiler profiler) | |||
{ | |||
var valueIndex = GetIndex(fromEntityGid.entityID); | |||
ref var entity = ref valuesArray[valueIndex]; | |||
if (toGroup != null) | |||
{ | |||
RemoveEntityViewFromEngines(engines, ref entity, fromEntityGid.groupID, in profiler, | |||
fromEntityGid); | |||
var toGroupCasted = toGroup as TypeSafeDictionary<TValue>; | |||
var previousGroup = fromEntityGid.groupID; | |||
if (_hasEgid) SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref entity, toEntityID.Value); | |||
var index = toGroupCasted.GetIndex(toEntityID.Value.entityID); | |||
AddEntityViewToEngines(engines, ref toGroupCasted.valuesArray[index], previousGroup, | |||
in profiler, toEntityID.Value); | |||
} | |||
else | |||
RemoveEntityViewFromEngines(engines, ref entity, null, in profiler, fromEntityGid); | |||
} | |||
public ITypeSafeDictionary Create() | |||
{ | |||
return new TypeSafeDictionary<TValue>(); | |||
} | |||
void AddEntityViewToEngines(FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> entityViewEnginesDB, | |||
ref TValue entity, ExclusiveGroup.ExclusiveGroupStruct? previousGroup, | |||
in PlatformProfiler profiler, EGID egid) | |||
{ | |||
//get all the engines linked to TValue | |||
if (!entityViewEnginesDB.TryGetValue(new RefWrapper<Type>(_type), out var entityViewsEngines)) return; | |||
if (previousGroup == null) | |||
{ | |||
for (var i = 0; i < entityViewsEngines.Count; i++) | |||
try | |||
{ | |||
using (profiler.Sample(entityViewsEngines[i], _typeName)) | |||
{ | |||
(entityViewsEngines[i] as IReactOnAddAndRemove<TValue>).Add(ref entity, egid); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new ECSException( | |||
"Code crashed inside Add callback ".FastConcat(typeof(TValue).ToString()), e); | |||
} | |||
} | |||
else | |||
{ | |||
for (var i = 0; i < entityViewsEngines.Count; i++) | |||
try | |||
{ | |||
using (profiler.Sample(entityViewsEngines[i], _typeName)) | |||
{ | |||
(entityViewsEngines[i] as IReactOnSwap<TValue>).MovedTo(ref entity, previousGroup.Value, | |||
egid); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new ECSException( | |||
"Code crashed inside MovedTo callback ".FastConcat(typeof(TValue).ToString()), e); | |||
} | |||
} | |||
} | |||
static void RemoveEntityViewFromEngines( | |||
FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> @group, ref TValue entity, | |||
ExclusiveGroup.ExclusiveGroupStruct? previousGroup, in PlatformProfiler profiler, EGID egid) | |||
{ | |||
if (!@group.TryGetValue(new RefWrapper<Type>(_type), out var entityViewsEngines)) return; | |||
if (previousGroup == null) | |||
{ | |||
for (var i = 0; i < entityViewsEngines.Count; i++) | |||
try | |||
{ | |||
using (profiler.Sample(entityViewsEngines[i], _typeName)) | |||
(entityViewsEngines[i] as IReactOnAddAndRemove<TValue>).Remove(ref entity, egid); | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new ECSException( | |||
"Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()), e); | |||
} | |||
} | |||
#if SEEMS_UNNECESSARY | |||
else | |||
{ | |||
for (var i = 0; i < entityViewsEngines.Count; i++) | |||
try | |||
{ | |||
using (profiler.Sample(entityViewsEngines[i], _typeName)) | |||
(entityViewsEngines[i] as IReactOnSwap<TValue>).MovedFrom(ref entity, egid); | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new ECSException( | |||
"Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()), e); | |||
} | |||
} | |||
#endif | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 5e812f7d5c7a03d4faebd6bbc9a06a2a | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,12 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public class TypeSafeDictionaryException : Exception | |||
{ | |||
public TypeSafeDictionaryException(string message, Exception exception) : | |||
base(message, exception) | |||
{ | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 8c21456b4b0c7c9409264d02670f7f4c | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,8 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 67be04a8cde247c4d93885b1ff03ddec | |||
folderAsset: yes | |||
DefaultImporter: | |||
externalObjects: {} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,21 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public class DispatchOnChange<T> : DispatchOnSet<T> where T:IEquatable<T> | |||
{ | |||
public DispatchOnChange(EGID senderID) : base(senderID) | |||
{ } | |||
public new T value | |||
{ | |||
set | |||
{ | |||
if (value.Equals(_value) == false) | |||
base.value = value; | |||
} | |||
get => _value; | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 8b6d96ff87b04c140ad95db4cb267540 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,42 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public class DispatchOnSet<T> | |||
{ | |||
public DispatchOnSet(EGID senderID) | |||
{ | |||
_senderID = senderID; | |||
} | |||
public T value | |||
{ | |||
set | |||
{ | |||
_value = value; | |||
if (_paused == false) | |||
_subscribers(_senderID, value); | |||
} | |||
} | |||
public void NotifyOnValueSet(Action<EGID, T> action) | |||
{ | |||
_subscribers += action; | |||
} | |||
public void StopNotify(Action<EGID, T> action) | |||
{ | |||
_subscribers -= action; | |||
} | |||
public void PauseNotify() { _paused = true; } | |||
public void ResumeNotify() { _paused = false; } | |||
protected T _value; | |||
readonly EGID _senderID; | |||
Action<EGID, T> _subscribers; | |||
bool _paused; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: f3455e49716d5f44c9ed8da0880dead2 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,128 +0,0 @@ | |||
using System; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
/// <summary> | |||
/// DynamicEntityDescriptor can be used to add entity views to an existing EntityDescriptor that act as flags, | |||
/// at building time. | |||
/// This method allocates, so it shouldn't be abused | |||
/// </summary> | |||
/// <typeparam name="TType"></typeparam> | |||
public struct DynamicEntityDescriptor<TType> : IEntityDescriptor where TType : IEntityDescriptor, new() | |||
{ | |||
internal DynamicEntityDescriptor(bool isExtendible) : this() | |||
{ | |||
var defaultEntities = EntityDescriptorTemplate<TType>.descriptor.entitiesToBuild; | |||
var length = defaultEntities.Length; | |||
_entitiesToBuild = new IEntityBuilder[length + 1]; | |||
Array.Copy(defaultEntities, 0, _entitiesToBuild, 0, length); | |||
//assign it after otherwise the previous copy will overwrite the value in case the item | |||
//is already present | |||
_entitiesToBuild[length] = new EntityBuilder<EntityStructInfoView> | |||
( | |||
new EntityStructInfoView | |||
{ | |||
entitiesToBuild = _entitiesToBuild | |||
} | |||
); | |||
} | |||
public DynamicEntityDescriptor(IEntityBuilder[] extraEntityBuilders) : this() | |||
{ | |||
var extraEntitiesLength = extraEntityBuilders.Length; | |||
_entitiesToBuild = Construct(extraEntitiesLength, extraEntityBuilders, | |||
EntityDescriptorTemplate<TType>.descriptor.entitiesToBuild); | |||
} | |||
public DynamicEntityDescriptor(FasterList<IEntityBuilder> extraEntityBuilders) : this() | |||
{ | |||
var extraEntities = extraEntityBuilders.ToArrayFast(); | |||
var extraEntitiesLength = extraEntityBuilders.Count; | |||
_entitiesToBuild = Construct(extraEntitiesLength, extraEntities, | |||
EntityDescriptorTemplate<TType>.descriptor.entitiesToBuild); | |||
} | |||
public void ExtendWith<T>() where T : IEntityDescriptor, new() | |||
{ | |||
var newEntitiesToBuild = EntityDescriptorTemplate<T>.descriptor.entitiesToBuild; | |||
_entitiesToBuild = Construct(newEntitiesToBuild.Length, newEntitiesToBuild, _entitiesToBuild); | |||
} | |||
public void ExtendWith(IEntityBuilder[] extraEntities) | |||
{ | |||
_entitiesToBuild = Construct(extraEntities.Length, extraEntities, _entitiesToBuild); | |||
} | |||
static IEntityBuilder[] Construct(int extraEntitiesLength, IEntityBuilder[] extraEntities, | |||
IEntityBuilder[] startingEntities) | |||
{ | |||
IEntityBuilder[] localEntitiesToBuild; | |||
if (extraEntitiesLength == 0) | |||
{ | |||
localEntitiesToBuild = startingEntities; | |||
return localEntitiesToBuild; | |||
} | |||
var defaultEntities = startingEntities; | |||
var length = defaultEntities.Length; | |||
var index = SetupSpecialEntityStruct(defaultEntities, out localEntitiesToBuild, extraEntitiesLength); | |||
Array.Copy(extraEntities, 0, localEntitiesToBuild, length, extraEntitiesLength); | |||
//assign it after otherwise the previous copy will overwrite the value in case the item | |||
//is already present | |||
localEntitiesToBuild[index] = new EntityBuilder<EntityStructInfoView> | |||
( | |||
new EntityStructInfoView | |||
{ | |||
entitiesToBuild = localEntitiesToBuild | |||
} | |||
); | |||
return localEntitiesToBuild; | |||
} | |||
static int SetupSpecialEntityStruct(IEntityBuilder[] defaultEntities, out IEntityBuilder[] entitiesToBuild, | |||
int extraLenght) | |||
{ | |||
int length = defaultEntities.Length; | |||
int index = -1; | |||
for (var i = 0; i < length; i++) | |||
{ | |||
//the special entity already exists | |||
if (defaultEntities[i].GetEntityType() == EntityBuilderUtilities.ENTITY_STRUCT_INFO_VIEW) | |||
{ | |||
index = i; | |||
break; | |||
} | |||
} | |||
if (index == -1) | |||
{ | |||
index = length + extraLenght; | |||
entitiesToBuild = new IEntityBuilder[index + 1]; | |||
} | |||
else | |||
entitiesToBuild = new IEntityBuilder[length + extraLenght]; | |||
Array.Copy(defaultEntities, 0, entitiesToBuild, 0, length); | |||
return index; | |||
} | |||
public IEntityBuilder[] entitiesToBuild => _entitiesToBuild; | |||
IEntityBuilder[] _entitiesToBuild; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: f44f311aa89faee408fe3591032a1bb9 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,13 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public class ECSException : Exception | |||
{ | |||
public ECSException(string message):base("<color=red>".FastConcat(message, "</color>")) | |||
{} | |||
public ECSException(string message, Exception innerE):base("<color=red>".FastConcat(message, "</color>"), innerE) | |||
{} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: ffc933f6fa0c64f46aa6e501ccac1eca | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,8 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: ed2ee43790d8ab0408efcd5ee7b4e80f | |||
folderAsset: yes | |||
DefaultImporter: | |||
externalObjects: {} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,47 +0,0 @@ | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Experimental | |||
{ | |||
public struct ECSResources<T> | |||
{ | |||
internal uint id; | |||
public static implicit operator T(ECSResources<T> ecsString) { return ResourcesECSDB<T>.FromECS(ecsString.id); } | |||
} | |||
static class ResourcesECSDB<T> | |||
{ | |||
static readonly FasterList<T> _resources = new FasterList<T>(); | |||
internal static ref T resources(uint id) | |||
{ | |||
return ref _resources[(int) id - 1]; | |||
} | |||
internal static uint ToECS(T resource) | |||
{ | |||
_resources.Add(resource); | |||
return (uint)_resources.Count; | |||
} | |||
public static T FromECS(uint id) | |||
{ | |||
if (id - 1 < _resources.Count) | |||
return _resources[(int) id - 1]; | |||
return default; | |||
} | |||
} | |||
public static class ResourceExtensions | |||
{ | |||
public static void Set<T>(ref this ECSResources<T> resource, T newText) | |||
{ | |||
if (resource.id != 0) | |||
ResourcesECSDB<T>.resources(resource.id) = newText; | |||
else | |||
resource.id = ResourcesECSDB<T>.ToECS(newText); | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 5afcd85ad92ffb344b04a1aa675814bf | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,38 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS.Experimental | |||
{ | |||
[Serialization.DoNotSerialize] | |||
public struct ECSString:IEquatable<ECSString> | |||
{ | |||
uint id; | |||
public ECSString(string newText) | |||
{ | |||
id = ResourcesECSDB<string>.ToECS(newText); | |||
} | |||
public static implicit operator string(ECSString ecsString) | |||
{ | |||
return ResourcesECSDB<string>.FromECS(ecsString.id); | |||
} | |||
public void Set(string newText) | |||
{ | |||
if (id != 0) | |||
ResourcesECSDB<string>.resources(id) = newText; | |||
else | |||
id = ResourcesECSDB<string>.ToECS(newText); | |||
} | |||
public bool Equals(ECSString other) | |||
{ | |||
return other.id == id; | |||
} | |||
public override string ToString() | |||
{ | |||
return ResourcesECSDB<string>.FromECS(id); | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: a851028d58ed0754fa529a196e952859 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,77 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
#pragma warning disable 660,661 | |||
namespace Svelto.ECS | |||
{ | |||
//todo: add debug map | |||
[Serialization.DoNotSerialize] | |||
[Serializable] | |||
public struct EGID:IEquatable<EGID>,IEqualityComparer<EGID>,IComparable<EGID> | |||
{ | |||
public uint entityID => (uint) (_GID & 0xFFFFFFFF); | |||
public ExclusiveGroup.ExclusiveGroupStruct groupID => new ExclusiveGroup.ExclusiveGroupStruct((uint) (_GID >> 32)); | |||
public static bool operator ==(EGID obj1, EGID obj2) | |||
{ | |||
return obj1._GID == obj2._GID; | |||
} | |||
public static bool operator !=(EGID obj1, EGID obj2) | |||
{ | |||
return obj1._GID != obj2._GID; | |||
} | |||
public EGID(uint entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) : this() | |||
{ | |||
_GID = MAKE_GLOBAL_ID(entityID, groupID); | |||
} | |||
static ulong MAKE_GLOBAL_ID(uint entityId, uint groupId) | |||
{ | |||
return (ulong)groupId << 32 | ((ulong)entityId & 0xFFFFFFFF); | |||
} | |||
public static explicit operator uint(EGID id) | |||
{ | |||
return id.entityID; | |||
} | |||
//in the way it's used, ulong must be always the same for each id/group | |||
public static explicit operator ulong(EGID id) { return id._GID; } | |||
public bool Equals(EGID other) | |||
{ | |||
return _GID == other._GID; | |||
} | |||
public bool Equals(EGID x, EGID y) | |||
{ | |||
return x == y; | |||
} | |||
public int GetHashCode(EGID obj) | |||
{ | |||
return _GID.GetHashCode(); | |||
} | |||
public int CompareTo(EGID other) | |||
{ | |||
return _GID.CompareTo(other._GID); | |||
} | |||
internal EGID(uint entityID, uint groupID) : this() | |||
{ | |||
_GID = MAKE_GLOBAL_ID(entityID, groupID); | |||
} | |||
public override string ToString() | |||
{ | |||
return "id ".FastConcat(entityID).FastConcat(" group ").FastConcat(groupID); | |||
} | |||
readonly ulong _GID; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 107bb03a12307bb4f961b85b782e22e1 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,37 +0,0 @@ | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using System.Runtime.InteropServices; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
public struct EGIDMapper<T> where T : struct, IEntityStruct | |||
{ | |||
internal FasterDictionary<uint, T> map; | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ref T Entity(uint entityID) | |||
{ | |||
#if DEBUG && !PROFILER | |||
if (map.TryFindIndex(entityID, out var findIndex) == false) | |||
throw new Exception("Entity not found in this group ".FastConcat(typeof(T).ToString())); | |||
#else | |||
map.TryFindIndex(entityID, out var findIndex); | |||
#endif | |||
return ref map.valuesArray[findIndex]; | |||
} | |||
public bool TryGetEntity(uint entityID, out T value) | |||
{ | |||
if (map.TryFindIndex(entityID, out var index)) | |||
{ | |||
value = map.GetDirectValue(index); | |||
return true; | |||
} | |||
value = default; | |||
return false; | |||
} | |||
} | |||
} | |||
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: c28b51f353894904c831577c2c725122 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,86 +0,0 @@ | |||
using System; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot | |||
{ | |||
internal class DoubleBufferedEntitiesToAdd | |||
{ | |||
const int MaximumNumberOfItemsPerFrameBeforeToClear = 100; | |||
internal void Swap() | |||
{ | |||
Swap(ref current, ref other); | |||
Swap(ref currentEntitiesCreatedPerGroup, ref otherEntitiesCreatedPerGroup); | |||
} | |||
void Swap<T>(ref T item1, ref T item2) | |||
{ | |||
var toSwap = item2; | |||
item2 = item1; | |||
item1 = toSwap; | |||
} | |||
public void ClearOther() | |||
{ | |||
//do not clear the groups created so far, they will be reused, unless they are too many! | |||
var otherCount = other.Count; | |||
if (otherCount > MaximumNumberOfItemsPerFrameBeforeToClear) | |||
{ | |||
otherEntitiesCreatedPerGroup.FastClear(); | |||
other.FastClear(); | |||
return; | |||
} | |||
var otherValuesArray = other.valuesArray; | |||
for (int i = 0; i < otherCount; ++i) | |||
{ | |||
var safeDictionariesCount = otherValuesArray[i].Count; | |||
var safeDictionaries = otherValuesArray[i].valuesArray; | |||
//do not remove the dictionaries of entities per type created so far, they will be reused | |||
if (safeDictionariesCount <= MaximumNumberOfItemsPerFrameBeforeToClear) | |||
{ | |||
for (int j = 0; j < safeDictionariesCount; ++j) | |||
{ | |||
//clear the dictionary of entities create do far (it won't allocate though) | |||
safeDictionaries[j].FastClear(); | |||
} | |||
} | |||
else | |||
{ | |||
otherValuesArray[i].FastClear(); | |||
} | |||
} | |||
otherEntitiesCreatedPerGroup.FastClear(); | |||
} | |||
internal FasterDictionary<uint, uint> currentEntitiesCreatedPerGroup; | |||
internal FasterDictionary<uint, uint> otherEntitiesCreatedPerGroup; | |||
internal FasterDictionary<uint, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>> current; | |||
internal FasterDictionary<uint, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>> other; | |||
readonly FasterDictionary<uint, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>> | |||
_entityViewsToAddBufferA = | |||
new FasterDictionary<uint, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>>(); | |||
readonly FasterDictionary<uint, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>> | |||
_entityViewsToAddBufferB = | |||
new FasterDictionary<uint, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>>(); | |||
readonly FasterDictionary<uint, uint> _entitiesCreatedPerGroupA = new FasterDictionary<uint, uint>(); | |||
readonly FasterDictionary<uint, uint> _entitiesCreatedPerGroupB = new FasterDictionary<uint, uint>(); | |||
public DoubleBufferedEntitiesToAdd() | |||
{ | |||
currentEntitiesCreatedPerGroup = _entitiesCreatedPerGroupA; | |||
otherEntitiesCreatedPerGroup = _entitiesCreatedPerGroupB; | |||
current = _entityViewsToAddBufferA; | |||
other = _entityViewsToAddBufferB; | |||
} | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 317edb22c6fdcb447a576d39d928aae7 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,143 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.ECS.Schedulers; | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot | |||
{ | |||
public struct EntitiesSubmitter | |||
{ | |||
public EntitiesSubmitter(EnginesRoot enginesRoot) | |||
{ | |||
_weakReference = new DataStructures.WeakReference<EnginesRoot>(enginesRoot); | |||
} | |||
public void Invoke() | |||
{ | |||
if (_weakReference.IsValid) | |||
_weakReference.Target.SubmitEntityViews(); | |||
} | |||
readonly DataStructures.WeakReference<EnginesRoot> _weakReference; | |||
} | |||
/// <summary> | |||
/// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot | |||
/// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks | |||
/// periodically if new entity must be submitted to the database and the engines. It's an external | |||
/// dependencies to be independent by the running platform as the user can define it. | |||
/// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why | |||
/// it must receive a weak reference of the EnginesRoot callback. | |||
/// </summary> | |||
public EnginesRoot(IEntitySubmissionScheduler entityViewScheduler) | |||
{ | |||
_entitiesOperations = new FasterDictionary<ulong, EntitySubmitOperation>(); | |||
_reactiveEnginesAddRemove = new FasterDictionary<RefWrapper<Type>, FasterList<IEngine>>(); | |||
_reactiveEnginesSwap = new FasterDictionary<RefWrapper<Type>, FasterList<IEngine>>(); | |||
_enginesSet = new FasterList<IEngine>(); | |||
_enginesTypeSet = new HashSet<Type>(); | |||
_disposableEngines = new FasterList<IDisposable>(); | |||
_transientEntitiesOperations = new FasterList<EntitySubmitOperation>(); | |||
_groupEntityViewsDB = new FasterDictionary<uint, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>>(); | |||
_groupsPerEntity = new FasterDictionary<RefWrapper<Type>, FasterDictionary<uint, ITypeSafeDictionary>>(); | |||
_groupedEntityToAdd = new DoubleBufferedEntitiesToAdd(); | |||
_entitiesStream = new EntitiesStream(); | |||
_entitiesDB = new EntitiesDB(_groupEntityViewsDB, _groupsPerEntity, _entitiesStream); | |||
_scheduler = entityViewScheduler; | |||
_scheduler.onTick = new EntitiesSubmitter(this); | |||
} | |||
public EnginesRoot(IEntitySubmissionScheduler entityViewScheduler, bool isDeserializationOnly):this(entityViewScheduler) | |||
{ | |||
_isDeserializationOnly = isDeserializationOnly; | |||
} | |||
public void AddEngine(IEngine engine) | |||
{ | |||
var type = engine.GetType(); | |||
var refWrapper = new RefWrapper<Type>(type); | |||
DBC.ECS.Check.Require( | |||
_enginesTypeSet.Contains(refWrapper) == false || | |||
type.ContainsCustomAttribute(typeof(AllowMultipleAttribute)) == true, | |||
"The same engine has been added more than once, if intentional, use [AllowMultiple] class attribute " | |||
.FastConcat(engine.ToString())); | |||
try | |||
{ | |||
if (engine is IReactOnAddAndRemove viewEngine) | |||
CheckEntityViewsEngine(viewEngine, _reactiveEnginesAddRemove); | |||
if (engine is IReactOnSwap viewEngineSwap) | |||
CheckEntityViewsEngine(viewEngineSwap, _reactiveEnginesSwap); | |||
_enginesTypeSet.Add(refWrapper); | |||
_enginesSet.Add(engine); | |||
if (engine is IDisposable) | |||
_disposableEngines.Add(engine as IDisposable); | |||
if (engine is IQueryingEntitiesEngine queryableEntityViewEngine) | |||
{ | |||
queryableEntityViewEngine.entitiesDB = _entitiesDB; | |||
queryableEntityViewEngine.Ready(); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new ECSException("Code crashed while adding engine ".FastConcat(engine.GetType().ToString(), " "), e); | |||
} | |||
} | |||
void CheckEntityViewsEngine<T>(T engine, FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> engines) | |||
where T : class, IEngine | |||
{ | |||
var interfaces = engine.GetType().GetInterfaces(); | |||
foreach (var interf in interfaces) | |||
{ | |||
if (interf.IsGenericTypeEx() && typeof(T).IsAssignableFrom(interf)) | |||
{ | |||
var genericArguments = interf.GetGenericArgumentsEx(); | |||
AddEngine(engine, genericArguments, engines); | |||
} | |||
} | |||
} | |||
static void AddEngine<T>(T engine, Type[] entityViewTypes, | |||
FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> engines) | |||
where T : class, IEngine | |||
{ | |||
for (var i = 0; i < entityViewTypes.Length; i++) | |||
{ | |||
var type = entityViewTypes[i]; | |||
AddEngine(engine, engines, type); | |||
} | |||
} | |||
static void AddEngine<T>(T engine, FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> engines, Type type) | |||
where T : class, IEngine | |||
{ | |||
if (engines.TryGetValue(new RefWrapper<Type>(type), out var list) == false) | |||
{ | |||
list = new FasterList<IEngine>(); | |||
engines.Add(new RefWrapper<Type>(type), list); | |||
} | |||
list.Add(engine); | |||
} | |||
readonly FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> _reactiveEnginesAddRemove; | |||
readonly FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> _reactiveEnginesSwap; | |||
readonly FasterList<IDisposable> _disposableEngines; | |||
readonly FasterList<IEngine> _enginesSet; | |||
readonly HashSet<Type> _enginesTypeSet; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 63f9381d3d2e91f4eb2f890bb36c605b | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,305 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
using Svelto.Common; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot : IDisposable | |||
{ | |||
/// <summary> | |||
/// Dispose an EngineRoot once not used anymore, so that all the | |||
/// engines are notified with the entities removed. | |||
/// It's a clean up process. | |||
/// </summary> | |||
public void Dispose() | |||
{ | |||
using (var profiler = new PlatformProfiler("Final Dispose")) | |||
{ | |||
foreach (var groups in _groupEntityViewsDB) | |||
{ | |||
foreach (var entityList in groups.Value) | |||
{ | |||
entityList.Value.RemoveEntitiesFromEngines(_reactiveEnginesAddRemove, | |||
profiler, new ExclusiveGroup.ExclusiveGroupStruct(groups.Key)); | |||
} | |||
} | |||
_groupEntityViewsDB.Clear(); | |||
_groupsPerEntity.Clear(); | |||
foreach (var engine in _disposableEngines) | |||
engine.Dispose(); | |||
_disposableEngines.Clear(); | |||
_enginesSet.Clear(); | |||
_enginesTypeSet.Clear(); | |||
_reactiveEnginesSwap.Clear(); | |||
_reactiveEnginesAddRemove.Clear(); | |||
_entitiesOperations.Clear(); | |||
_transientEntitiesOperations.Clear(); | |||
_scheduler.Dispose(); | |||
#if DEBUG && !PROFILER | |||
_idCheckers.Clear(); | |||
#endif | |||
_groupedEntityToAdd = null; | |||
_entitiesStream.Dispose(); | |||
} | |||
GC.SuppressFinalize(this); | |||
} | |||
~EnginesRoot() | |||
{ | |||
Console.LogWarning("Engines Root has been garbage collected, don't forget to call Dispose()!"); | |||
Dispose(); | |||
} | |||
///-------------------------------------------- | |||
/// | |||
public IEntityStreamConsumerFactory GenerateConsumerFactory() | |||
{ | |||
return new GenericEntityStreamConsumerFactory(this); | |||
} | |||
public IEntityFactory GenerateEntityFactory() | |||
{ | |||
return new GenericEntityFactory(this); | |||
} | |||
public IEntityFunctions GenerateEntityFunctions() | |||
{ | |||
return new GenericEntityFunctions(this); | |||
} | |||
///-------------------------------------------- | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
EntityStructInitializer BuildEntity(EGID entityID, IEntityBuilder[] entitiesToBuild, | |||
IEnumerable<object> implementors = null) | |||
{ | |||
CheckAddEntityID(entityID); | |||
var dic = EntityFactory.BuildGroupedEntities(entityID, _groupedEntityToAdd, | |||
entitiesToBuild, implementors); | |||
return new EntityStructInitializer(entityID, dic); | |||
} | |||
///-------------------------------------------- | |||
void Preallocate<T>(uint groupID, uint size) where T : IEntityDescriptor, new() | |||
{ | |||
var entityViewsToBuild = EntityDescriptorTemplate<T>.descriptor.entitiesToBuild; | |||
var numberOfEntityViews = entityViewsToBuild.Length; | |||
//reserve space in the database | |||
if (_groupEntityViewsDB.TryGetValue(groupID, out var group) == false) | |||
group = _groupEntityViewsDB[groupID] = new FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>(); | |||
for (var index = 0; index < numberOfEntityViews; index++) | |||
{ | |||
var entityViewBuilder = entityViewsToBuild[index]; | |||
var entityViewType = entityViewBuilder.GetEntityType(); | |||
var refWrapper = new RefWrapper<Type>(entityViewType); | |||
if (group.TryGetValue(refWrapper, out var dbList) == false) | |||
group[refWrapper] = entityViewBuilder.Preallocate(ref dbList, size); | |||
else | |||
dbList.SetCapacity(size); | |||
if (_groupsPerEntity.TryGetValue(refWrapper, out var groupedGroup) == false) | |||
groupedGroup = _groupsPerEntity[refWrapper] = | |||
new FasterDictionary<uint, ITypeSafeDictionary>(); | |||
groupedGroup[groupID] = dbList; | |||
} | |||
} | |||
///-------------------------------------------- | |||
/// | |||
void MoveEntityFromAndToEngines(IEntityBuilder[] entityBuilders, EGID fromEntityGID, EGID? toEntityGID) | |||
{ | |||
using (var sampler = new PlatformProfiler("Move Entity From Engines")) | |||
{ | |||
//for each entity view generated by the entity descriptor | |||
if (_groupEntityViewsDB.TryGetValue(fromEntityGID.groupID, out var fromGroup) == false) | |||
throw new ECSException("from group not found eid: ".FastConcat(fromEntityGID.entityID) | |||
.FastConcat(" group: ").FastConcat(fromEntityGID.groupID)); | |||
//Check if there is an EntityInfoView linked to this entity, if so it's a DynamicEntityDescriptor! | |||
if (fromGroup.TryGetValue(new RefWrapper<Type>(EntityBuilderUtilities.ENTITY_STRUCT_INFO_VIEW), | |||
out var entityInfoViewDic) && | |||
(entityInfoViewDic as TypeSafeDictionary<EntityStructInfoView>).TryGetValue( | |||
fromEntityGID.entityID, out var entityInfoView)) | |||
MoveEntities(fromEntityGID, toEntityGID, entityInfoView.entitiesToBuild, fromGroup, sampler); | |||
//otherwise it's a normal static entity descriptor | |||
else | |||
MoveEntities(fromEntityGID, toEntityGID, entityBuilders, fromGroup, sampler); | |||
} | |||
} | |||
void MoveEntities(EGID fromEntityGID, EGID? toEntityGID, IEntityBuilder[] entitiesToMove, | |||
FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> fromGroup, PlatformProfiler sampler) | |||
{ | |||
FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> toGroup = null; | |||
if (toEntityGID != null) | |||
{ | |||
var toGroupID = toEntityGID.Value.groupID; | |||
if (_groupEntityViewsDB.TryGetValue(toGroupID, out toGroup) == false) | |||
toGroup = _groupEntityViewsDB[toGroupID] = new FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>(); | |||
//Add all the entities to the dictionary | |||
for (var i = 0; i < entitiesToMove.Length; i++) | |||
CopyEntityToDictionary(fromEntityGID, toEntityGID.Value, fromGroup, toGroup, | |||
entitiesToMove[i].GetEntityType()); | |||
} | |||
//call all the callbacks | |||
for (var i = 0; i < entitiesToMove.Length; i++) | |||
MoveEntityViewFromAndToEngines(fromEntityGID, toEntityGID, fromGroup, toGroup, | |||
entitiesToMove[i].GetEntityType(), sampler); | |||
//then remove all the entities from the dictionary | |||
for (var i = 0; i < entitiesToMove.Length; i++) | |||
RemoveEntityFromDictionary(fromEntityGID, fromGroup, entitiesToMove[i].GetEntityType(), sampler); | |||
} | |||
void CopyEntityToDictionary(EGID entityGID, EGID toEntityGID, | |||
FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> fromGroup, | |||
FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> toGroup, Type entityViewType) | |||
{ | |||
var wrapper = new RefWrapper<Type>(entityViewType); | |||
if (fromGroup.TryGetValue(wrapper, out var fromTypeSafeDictionary) == false) | |||
{ | |||
throw new ECSException("no entities in from group eid: ".FastConcat(entityGID.entityID) | |||
.FastConcat(" group: ").FastConcat(entityGID.groupID)); | |||
} | |||
#if DEBUG && !PROFILER | |||
if (fromTypeSafeDictionary.Has(entityGID.entityID) == false) | |||
{ | |||
throw new EntityNotFoundException(entityGID, entityViewType); | |||
} | |||
#endif | |||
if (toGroup.TryGetValue(wrapper, out var toEntitiesDictionary) == false) | |||
{ | |||
toEntitiesDictionary = fromTypeSafeDictionary.Create(); | |||
toGroup.Add(wrapper, toEntitiesDictionary); | |||
} | |||
//todo: this must be unit tested properly | |||
if (_groupsPerEntity.TryGetValue(wrapper, out var groupedGroup) == false) | |||
groupedGroup = _groupsPerEntity[wrapper] = | |||
new FasterDictionary<uint, ITypeSafeDictionary>(); | |||
groupedGroup[toEntityGID.groupID] = toEntitiesDictionary; | |||
fromTypeSafeDictionary.AddEntityToDictionary(entityGID, toEntityGID, toEntitiesDictionary); | |||
} | |||
void MoveEntityViewFromAndToEngines(EGID entityGID, EGID? toEntityGID, | |||
FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> fromGroup, | |||
FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> toGroup, Type entityViewType, | |||
in PlatformProfiler profiler) | |||
{ | |||
//add all the entities | |||
var refWrapper = new RefWrapper<Type>(entityViewType); | |||
if (fromGroup.TryGetValue(refWrapper, out var fromTypeSafeDictionary) == false) | |||
{ | |||
throw new ECSException("no entities in from group eid: ".FastConcat(entityGID.entityID) | |||
.FastConcat(" group: ").FastConcat(entityGID.groupID)); | |||
} | |||
ITypeSafeDictionary toEntitiesDictionary = null; | |||
if (toGroup != null) | |||
toEntitiesDictionary = toGroup[refWrapper]; //this is guaranteed to exist by AddEntityToDictionary | |||
#if DEBUG && !PROFILER | |||
if (fromTypeSafeDictionary.Has(entityGID.entityID) == false) | |||
throw new EntityNotFoundException(entityGID, entityViewType); | |||
#endif | |||
fromTypeSafeDictionary.MoveEntityFromEngines(entityGID, toEntityGID, | |||
toEntitiesDictionary, toEntityGID == null ? _reactiveEnginesAddRemove : _reactiveEnginesSwap, | |||
in profiler); | |||
} | |||
void RemoveEntityFromDictionary(EGID entityGID, | |||
FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> fromGroup, Type entityViewType, | |||
in PlatformProfiler profiler) | |||
{ | |||
var refWrapper = new RefWrapper<Type>(entityViewType); | |||
if (fromGroup.TryGetValue(refWrapper, out var fromTypeSafeDictionary) == false) | |||
{ | |||
throw new ECSException("no entities in from group eid: ".FastConcat(entityGID.entityID) | |||
.FastConcat(" group: ").FastConcat(entityGID.groupID)); | |||
} | |||
fromTypeSafeDictionary.RemoveEntityFromDictionary(entityGID, profiler); | |||
if (fromTypeSafeDictionary.Count == 0) //clean up | |||
{ | |||
//todo: this must be unit tested properly | |||
_groupsPerEntity[refWrapper].Remove(entityGID.groupID); | |||
//I don't remove the group if empty on purpose, in case it needs to be reused | |||
} | |||
} | |||
/// <summary> | |||
/// Todo: I should keep the group, but I need to mark the group as deleted for the Exist function to work | |||
/// </summary> | |||
/// <param name="groupID"></param> | |||
/// <param name="profiler"></param> | |||
void RemoveGroupAndEntitiesFromDB(uint groupID, in PlatformProfiler profiler) | |||
{ | |||
var dictionariesOfEntities = _groupEntityViewsDB[groupID]; | |||
foreach (var dictionaryOfEntities in dictionariesOfEntities) | |||
{ | |||
dictionaryOfEntities.Value.RemoveEntitiesFromEngines(_reactiveEnginesAddRemove, profiler, | |||
new ExclusiveGroup.ExclusiveGroupStruct(groupID)); | |||
var groupedGroupOfEntities = _groupsPerEntity[dictionaryOfEntities.Key]; | |||
groupedGroupOfEntities.Remove(groupID); | |||
} | |||
//careful, in this case I assume you really don't want to use this group anymore | |||
//so I remove it from the database | |||
_groupEntityViewsDB.Remove(groupID); | |||
} | |||
internal Consumer<T> GenerateConsumer<T>(string name, uint capacity) where T : unmanaged, IEntityStruct | |||
{ | |||
return _entitiesStream.GenerateConsumer<T>(name, capacity); | |||
} | |||
public Consumer<T> GenerateConsumer<T>(ExclusiveGroup group, string name, uint capacity) where T : unmanaged, | |||
IEntityStruct | |||
{ | |||
return _entitiesStream.GenerateConsumer<T>(group, name, capacity); | |||
} | |||
//one datastructure rule them all: | |||
//split by group | |||
//split by type per group. It's possible to get all the entities of a give type T per group thanks | |||
//to the FasterDictionary capabilities OR it's possible to get a specific entityView indexed by | |||
//ID. This ID doesn't need to be the EGID, it can be just the entityID | |||
//for each group id, save a dictionary indexed by entity type of entities indexed by id | |||
//ITypeSafeDictionary = Key = entityID, Value = EntityStruct | |||
readonly FasterDictionary<uint, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>> _groupEntityViewsDB; | |||
//for each entity view type, return the groups (dictionary of entities indexed by entity id) where they are | |||
//found indexed by group id | |||
//EntityViewType //groupID //entityID, EntityStruct | |||
readonly FasterDictionary<RefWrapper<Type>, FasterDictionary<uint, ITypeSafeDictionary>> _groupsPerEntity; | |||
readonly EntitiesDB _entitiesDB; | |||
readonly EntitiesStream _entitiesStream; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 40a3f08b64dbbfc42b7863e5c17636ea | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,57 +0,0 @@ | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot | |||
{ | |||
class GenericEntityFactory : IEntityFactory | |||
{ | |||
public GenericEntityFactory(EnginesRoot weakReference) | |||
{ | |||
_enginesRoot = new WeakReference<EnginesRoot>(weakReference); | |||
} | |||
public EntityStructInitializer BuildEntity<T>(uint entityID, | |||
ExclusiveGroup.ExclusiveGroupStruct groupStructId, IEnumerable<object> implementors = null) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
return _enginesRoot.Target.BuildEntity(new EGID(entityID, groupStructId), | |||
EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, implementors); | |||
} | |||
public EntityStructInitializer BuildEntity<T>(EGID egid, IEnumerable<object> implementors = null) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
return _enginesRoot.Target.BuildEntity(egid, | |||
EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, implementors); | |||
} | |||
public EntityStructInitializer BuildEntity<T>(EGID egid, T entityDescriptor, | |||
IEnumerable<object> implementors) | |||
where T : IEntityDescriptor | |||
{ | |||
return _enginesRoot.Target.BuildEntity(egid, entityDescriptor.entitiesToBuild, implementors); | |||
} | |||
public EntityStructInitializer BuildEntity<T>(uint entityID, | |||
ExclusiveGroup.ExclusiveGroupStruct groupStructId, T descriptorEntity, IEnumerable<object> implementors) | |||
where T : IEntityDescriptor | |||
{ | |||
return _enginesRoot.Target.BuildEntity(new EGID(entityID, groupStructId), | |||
descriptorEntity.entitiesToBuild, | |||
implementors); | |||
} | |||
public void PreallocateEntitySpace<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId, uint size) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
_enginesRoot.Target.Preallocate<T>(groupStructId, size); | |||
} | |||
//enginesRoot is a weakreference because GenericEntityStreamConsumerFactory can be injected inside | |||
//engines of other enginesRoot | |||
readonly WeakReference<EnginesRoot> _enginesRoot; | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: c6b2d3dc41496964f91001a6f66be98a | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,130 +0,0 @@ | |||
using System.Diagnostics; | |||
using System.Runtime.CompilerServices; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot | |||
{ | |||
/// <summary> | |||
/// todo: EnginesRoot was a weakreference to give the change to inject | |||
/// entityfunctions from other engines root. It probably should be reverted | |||
/// </summary> | |||
sealed class GenericEntityFunctions : IEntityFunctions | |||
{ | |||
internal GenericEntityFunctions(EnginesRoot weakReference) | |||
{ | |||
_enginesRoot = new WeakReference<EnginesRoot>(weakReference); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void RemoveEntity<T>(uint entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) where T : | |||
IEntityDescriptor, new() | |||
{ | |||
RemoveEntity<T>(new EGID(entityID, groupID)); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void RemoveEntity<T>(EGID entityEGID) where T : IEntityDescriptor, new() | |||
{ | |||
_enginesRoot.Target.CheckRemoveEntityID(entityEGID); | |||
_enginesRoot.Target.QueueEntitySubmitOperation<T>( | |||
new EntitySubmitOperation(EntitySubmitOperationType.Remove, entityEGID, entityEGID, | |||
EntityDescriptorTemplate<T>.descriptor.entitiesToBuild)); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void RemoveGroupAndEntities(ExclusiveGroup.ExclusiveGroupStruct groupID) | |||
{ | |||
_enginesRoot.Target.RemoveGroupID(groupID); | |||
_enginesRoot.Target.QueueEntitySubmitOperation( | |||
new EntitySubmitOperation(EntitySubmitOperationType.RemoveGroup, new EGID(0, groupID), new EGID())); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void SwapEntityGroup<T>(uint entityID, ExclusiveGroup.ExclusiveGroupStruct fromGroupID, | |||
ExclusiveGroup.ExclusiveGroupStruct toGroupID) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
SwapEntityGroup<T>(new EGID(entityID, fromGroupID), toGroupID); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void SwapEntityGroup<T>(EGID fromID, ExclusiveGroup.ExclusiveGroupStruct toGroupID) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
SwapEntityGroup<T>(fromID, new EGID(fromID.entityID, (uint) toGroupID)); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void SwapEntityGroup<T>(EGID fromID, ExclusiveGroup.ExclusiveGroupStruct toGroupID | |||
, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
if (fromID.groupID != mustBeFromGroup) | |||
throw new ECSException("Entity is not coming from the expected group"); | |||
SwapEntityGroup<T>(fromID, toGroupID); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void SwapEntityGroup<T>(EGID fromID, EGID toID | |||
, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
if (fromID.groupID != mustBeFromGroup) | |||
throw new ECSException("Entity is not coming from the expected group"); | |||
SwapEntityGroup<T>(fromID, toID); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void SwapEntityGroup<T>(EGID fromID, EGID toID) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
_enginesRoot.Target.CheckRemoveEntityID(fromID); | |||
_enginesRoot.Target.CheckAddEntityID(toID); | |||
_enginesRoot.Target.QueueEntitySubmitOperation<T>( | |||
new EntitySubmitOperation(EntitySubmitOperationType.Swap, | |||
fromID, toID, EntityDescriptorTemplate<T>.descriptor.entitiesToBuild)); | |||
} | |||
//enginesRoot is a weakreference because GenericEntityStreamConsumerFactory can be injected inside | |||
//engines of other enginesRoot | |||
readonly WeakReference<EnginesRoot> _enginesRoot; | |||
} | |||
void QueueEntitySubmitOperation(EntitySubmitOperation entitySubmitOperation) | |||
{ | |||
#if DEBUG && !PROFILER | |||
entitySubmitOperation.trace = new StackFrame(1, true); | |||
#endif | |||
_entitiesOperations.Add((ulong) entitySubmitOperation.fromID, entitySubmitOperation); | |||
} | |||
void QueueEntitySubmitOperation<T>(EntitySubmitOperation entitySubmitOperation) where T : IEntityDescriptor | |||
{ | |||
#if DEBUG && !PROFILER | |||
entitySubmitOperation.trace = new StackFrame(1, true); | |||
if (_entitiesOperations.TryGetValue((ulong) entitySubmitOperation.fromID, out var entitySubmitedOperation)) | |||
{ | |||
if (entitySubmitedOperation != entitySubmitOperation) | |||
throw new ECSException("Only one entity operation per submission is allowed" | |||
.FastConcat(" entityViewType: ") | |||
.FastConcat(typeof(T).Name) | |||
.FastConcat(" submission type ", entitySubmitOperation.type.ToString(), | |||
" from ID: ", entitySubmitOperation.fromID.entityID.ToString()) | |||
.FastConcat(" previous operation type: ", | |||
_entitiesOperations[(ulong) entitySubmitOperation.fromID].type | |||
.ToString())); | |||
} | |||
else | |||
#endif | |||
_entitiesOperations.Set((ulong) entitySubmitOperation.fromID, entitySubmitOperation); | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: dfc6ec8bc3879b04aae4ab41ecd01e63 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,162 +0,0 @@ | |||
using System; | |||
using Svelto.Common; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.ECS.Schedulers; | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot | |||
{ | |||
readonly FasterList<EntitySubmitOperation> _transientEntitiesOperations; | |||
void SubmitEntityViews() | |||
{ | |||
using (var profiler = new PlatformProfiler("Svelto.ECS - Entities Submission")) | |||
{ | |||
int iterations = 0; | |||
do | |||
{ | |||
SingleSubmission(profiler); | |||
} while ((_groupedEntityToAdd.currentEntitiesCreatedPerGroup.Count > 0 || | |||
_entitiesOperations.Count > 0) && ++iterations < 5); | |||
#if DEBUG && !PROFILER | |||
if (iterations == 5) | |||
throw new ECSException("possible circular submission detected"); | |||
#endif | |||
} | |||
} | |||
void SingleSubmission(in PlatformProfiler profiler) | |||
{ | |||
if (_entitiesOperations.Count > 0) | |||
{ | |||
using (profiler.Sample("Remove and Swap operations")) | |||
{ | |||
_transientEntitiesOperations.FastClear(); | |||
var entitySubmitOperations = _entitiesOperations.GetValuesArray(out var count); | |||
_transientEntitiesOperations.AddRange(entitySubmitOperations, count); | |||
_entitiesOperations.FastClear(); | |||
var entitiesOperations = _transientEntitiesOperations.ToArrayFast(); | |||
for (var i = 0; i < _transientEntitiesOperations.Count; i++) | |||
{ | |||
try | |||
{ | |||
switch (entitiesOperations[i].type) | |||
{ | |||
case EntitySubmitOperationType.Swap: | |||
MoveEntityFromAndToEngines(entitiesOperations[i].builders, | |||
entitiesOperations[i].fromID, | |||
entitiesOperations[i].toID); | |||
break; | |||
case EntitySubmitOperationType.Remove: | |||
MoveEntityFromAndToEngines(entitiesOperations[i].builders, | |||
entitiesOperations[i].fromID, null); | |||
break; | |||
case EntitySubmitOperationType.RemoveGroup: | |||
RemoveGroupAndEntitiesFromDB( | |||
entitiesOperations[i].fromID.groupID, profiler); | |||
break; | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
var str = "Crash while executing Entity Operation " | |||
.FastConcat(entitiesOperations[i].type.ToString()); | |||
throw new ECSException(str.FastConcat(" ") | |||
#if DEBUG && !PROFILER | |||
.FastConcat(entitiesOperations[i].trace.ToString()) | |||
#endif | |||
, e); | |||
} | |||
} | |||
} | |||
} | |||
_groupedEntityToAdd.Swap(); | |||
if (_groupedEntityToAdd.otherEntitiesCreatedPerGroup.Count > 0) | |||
{ | |||
using (profiler.Sample("Add operations")) | |||
{ | |||
try | |||
{ | |||
AddEntityViewsToTheDBAndSuitableEngines(profiler); | |||
} | |||
finally | |||
{ | |||
using (profiler.Sample("clear operates double buffering")) | |||
{ | |||
//other can be cleared now, but let's avoid deleting the dictionary every time | |||
_groupedEntityToAdd.ClearOther(); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
void AddEntityViewsToTheDBAndSuitableEngines(in PlatformProfiler profiler) | |||
{ | |||
using (profiler.Sample("Add entities to database")) | |||
{ | |||
//each group is indexed by entity view type. for each type there is a dictionary indexed by entityID | |||
foreach (var groupOfEntitiesToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup) | |||
{ | |||
var groupID = groupOfEntitiesToSubmit.Key; | |||
//if the group doesn't exist in the current DB let's create it first | |||
if (_groupEntityViewsDB.TryGetValue(groupID, out var groupDB) == false) | |||
groupDB = _groupEntityViewsDB[groupID] = | |||
new FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>(); | |||
//add the entityViews in the group | |||
foreach (var entityViewsToSubmit in _groupedEntityToAdd.other[groupID]) | |||
{ | |||
var type = entityViewsToSubmit.Key; | |||
var typeSafeDictionary = entityViewsToSubmit.Value; | |||
var wrapper = new RefWrapper<Type>(type); | |||
if (groupDB.TryGetValue(wrapper, out var dbDic) == false) | |||
dbDic = groupDB[wrapper] = typeSafeDictionary.Create(); | |||
//Fill the DB with the entity views generate this frame. | |||
dbDic.AddEntitiesFromDictionary(typeSafeDictionary, groupID); | |||
if (_groupsPerEntity.TryGetValue(wrapper, out var groupedGroup) == false) | |||
groupedGroup = _groupsPerEntity[wrapper] = | |||
new FasterDictionary<uint, ITypeSafeDictionary>(); | |||
groupedGroup[groupID] = dbDic; | |||
} | |||
} | |||
} | |||
//then submit everything in the engines, so that the DB is up to date with all the entity views and struct | |||
//created by the entity built | |||
using (profiler.Sample("Add entities to engines")) | |||
{ | |||
foreach (var groupToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup) | |||
{ | |||
var groupID = groupToSubmit.Key; | |||
var groupDB = _groupEntityViewsDB[groupID]; | |||
foreach (var entityViewsToSubmit in _groupedEntityToAdd.other[groupID]) | |||
{ | |||
var realDic = groupDB[new RefWrapper<Type>(entityViewsToSubmit.Key)]; | |||
entityViewsToSubmit.Value.AddEntitiesToEngines(_reactiveEnginesAddRemove, realDic, in profiler, | |||
new ExclusiveGroup.ExclusiveGroupStruct(groupToSubmit.Key)); | |||
} | |||
} | |||
} | |||
} | |||
DoubleBufferedEntitiesToAdd _groupedEntityToAdd; | |||
readonly IEntitySubmissionScheduler _scheduler; | |||
readonly FasterDictionary<ulong, EntitySubmitOperation> _entitiesOperations; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 52487a06d015a94438830b74e5a5d7f7 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,301 +0,0 @@ | |||
#if DEBUG && !PROFILER | |||
#define ENABLE_DEBUG_FUNC | |||
#endif | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
partial class EntitiesDB : IEntitiesDB | |||
{ | |||
internal EntitiesDB( | |||
FasterDictionary<uint, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>> groupEntityViewsDB, | |||
FasterDictionary<RefWrapper<Type>, FasterDictionary<uint, ITypeSafeDictionary>> groupsPerEntity, | |||
EntitiesStream entityStream) | |||
{ | |||
_groupEntityViewsDB = groupEntityViewsDB; | |||
_groupsPerEntity = groupsPerEntity; | |||
_entityStream = entityStream; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ref T QueryUniqueEntity<T>(ExclusiveGroup.ExclusiveGroupStruct group) where T : struct, IEntityStruct | |||
{ | |||
var entities = QueryEntities<T>(group, out var count); | |||
if (count == 0) | |||
throw new ECSException("Unique entity not found '".FastConcat(typeof(T).ToString()).FastConcat("'")); | |||
if (count != 1) | |||
throw new ECSException("Unique entities must be unique! '".FastConcat(typeof(T).ToString()) | |||
.FastConcat("'")); | |||
return ref entities[0]; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ref T QueryEntity<T>(EGID entityGID) where T : struct, IEntityStruct | |||
{ | |||
T[] array; | |||
if ((array = QueryEntitiesAndIndexInternal<T>(entityGID, out var index)) != null) | |||
return ref array[index]; | |||
throw new EntityNotFoundException(entityGID, typeof(T)); | |||
} | |||
public ref T QueryEntity<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct group) where T : struct, IEntityStruct | |||
{ | |||
return ref QueryEntity<T>(new EGID(id, group)); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public T[] QueryEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out uint count) | |||
where T : struct, IEntityStruct | |||
{ | |||
uint group = groupStruct; | |||
count = 0; | |||
if (SafeQueryEntityDictionary(group, out TypeSafeDictionary<T> typeSafeDictionary) == false) | |||
return RetrieveEmptyEntityViewArray<T>(); | |||
return typeSafeDictionary.GetValuesArray(out count); | |||
} | |||
public EntityCollection<T> QueryEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) | |||
where T : struct, IEntityStruct | |||
{ | |||
return new EntityCollection<T>(QueryEntities<T>(groupStruct, out var count), count); | |||
} | |||
public EntityCollection<T1, T2> QueryEntities<T1, T2>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) | |||
where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct | |||
{ | |||
return new EntityCollection<T1, T2>(QueryEntities<T1, T2>(groupStruct, out var count), count); | |||
} | |||
public EntityCollection<T1, T2, T3> QueryEntities<T1, T2, T3>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) | |||
where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct where T3 : struct, IEntityStruct | |||
{ | |||
return new EntityCollection<T1, T2, T3>(QueryEntities<T1, T2, T3>(groupStruct, out var count), count); | |||
} | |||
public EntityCollections<T> QueryEntities<T>(ExclusiveGroup[] groups) where T : struct, IEntityStruct | |||
{ | |||
return new EntityCollections<T>(this, groups); | |||
} | |||
public EntityCollections<T1, T2> QueryEntities<T1, T2>(ExclusiveGroup[] groups) | |||
where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct | |||
{ | |||
return new EntityCollections<T1, T2>(this, groups); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public (T1[], T2[]) QueryEntities<T1, T2>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out uint count) | |||
where T1 : struct, IEntityStruct | |||
where T2 : struct, IEntityStruct | |||
{ | |||
var T1entities = QueryEntities<T1>(groupStruct, out var countCheck); | |||
var T2entities = QueryEntities<T2>(groupStruct, out count); | |||
if (count != countCheck) | |||
{ | |||
throw new ECSException("Entity views count do not match in group. Entity 1: ' count: " | |||
.FastConcat(countCheck) | |||
.FastConcat(typeof(T1).ToString()) | |||
.FastConcat("'. Entity 2: ' count: ".FastConcat(count) | |||
.FastConcat(typeof(T2).ToString()) | |||
.FastConcat("'"))); | |||
} | |||
return (T1entities, T2entities); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public (T1[], T2[], T3[]) QueryEntities | |||
<T1, T2, T3>(ExclusiveGroup.ExclusiveGroupStruct groupStruct, out uint count) | |||
where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct where T3 : struct, IEntityStruct | |||
{ | |||
var T1entities = QueryEntities<T1>(groupStruct, out var countCheck1); | |||
var T2entities = QueryEntities<T2>(groupStruct, out var countCheck2); | |||
var T3entities = QueryEntities<T3>(groupStruct, out count); | |||
if (count != countCheck1 || count != countCheck2) | |||
throw new ECSException("Entity views count do not match in group. Entity 1: " | |||
.FastConcat(typeof(T1).ToString()).FastConcat(" count: ").FastConcat(countCheck1).FastConcat( | |||
" Entity 2: ".FastConcat(typeof(T2).ToString()) | |||
.FastConcat(" count: ").FastConcat(countCheck2) | |||
.FastConcat(" Entity 3: ".FastConcat(typeof(T3).ToString())).FastConcat(" count: ") | |||
.FastConcat(count))); | |||
return (T1entities, T2entities, T3entities); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public EGIDMapper<T> QueryMappedEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId) | |||
where T : struct, IEntityStruct | |||
{ | |||
if (SafeQueryEntityDictionary(groupStructId, out TypeSafeDictionary<T> typeSafeDictionary) == false) | |||
throw new EntityGroupNotFoundException(groupStructId, typeof(T)); | |||
EGIDMapper<T> mapper; | |||
mapper.map = typeSafeDictionary; | |||
return mapper; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool TryQueryMappedEntities<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId, | |||
out EGIDMapper<T> mapper) | |||
where T : struct, IEntityStruct | |||
{ | |||
mapper = default; | |||
if (SafeQueryEntityDictionary(groupStructId, out TypeSafeDictionary<T> typeSafeDictionary) == false) | |||
return false; | |||
mapper.map = typeSafeDictionary; | |||
return true; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public T[] QueryEntitiesAndIndex<T>(EGID entityGID, out uint index) where T : struct, IEntityStruct | |||
{ | |||
T[] array; | |||
if ((array = QueryEntitiesAndIndexInternal<T>(entityGID, out index)) != null) | |||
return array; | |||
throw new EntityNotFoundException(entityGID, typeof(T)); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool TryQueryEntitiesAndIndex<T>(EGID entityGid, out uint index, out T[] array) | |||
where T : struct, IEntityStruct | |||
{ | |||
if ((array = QueryEntitiesAndIndexInternal<T>(entityGid, out index)) != null) | |||
return true; | |||
return false; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public T[] QueryEntitiesAndIndex<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index) | |||
where T : struct, IEntityStruct | |||
{ | |||
return QueryEntitiesAndIndex<T>(new EGID(id, group), out index); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool TryQueryEntitiesAndIndex<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct group, out uint index, | |||
out T[] array) where T : struct, IEntityStruct | |||
{ | |||
return TryQueryEntitiesAndIndex(new EGID(id, group), out index, out array); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Exists<T>(EGID entityGID) where T : struct, IEntityStruct | |||
{ | |||
if (SafeQueryEntityDictionary(entityGID.groupID, out TypeSafeDictionary<T> casted) == false) return false; | |||
return casted != null && casted.ContainsKey(entityGID.entityID); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Exists<T>(uint id, ExclusiveGroup.ExclusiveGroupStruct group) where T : struct, IEntityStruct | |||
{ | |||
if (SafeQueryEntityDictionary(group, out TypeSafeDictionary<T> casted) == false) return false; | |||
return casted != null && casted.ContainsKey(id); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Exists(ExclusiveGroup.ExclusiveGroupStruct gid) | |||
{ | |||
return _groupEntityViewsDB.ContainsKey(gid); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool HasAny<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T : struct, IEntityStruct | |||
{ | |||
QueryEntities<T>(groupStruct, out var count); | |||
return count > 0; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public uint Count<T>(ExclusiveGroup.ExclusiveGroupStruct groupStruct) where T : struct, IEntityStruct | |||
{ | |||
QueryEntities<T>(groupStruct, out var count); | |||
return count; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void PublishEntityChange<T>(EGID egid) where T : unmanaged, IEntityStruct | |||
{ | |||
_entityStream.PublishEntity(ref QueryEntity<T>(egid), egid); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
T[] QueryEntitiesAndIndexInternal<T>(EGID entityGID, out uint index) where T : struct, IEntityStruct | |||
{ | |||
index = 0; | |||
if (SafeQueryEntityDictionary(entityGID.groupID, out TypeSafeDictionary<T> safeDictionary) == false) | |||
return null; | |||
if (safeDictionary.TryFindIndex(entityGID.entityID, out index) == false) | |||
return null; | |||
return safeDictionary.GetValuesArray(out _); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
bool SafeQueryEntityDictionary<T>(uint group, out TypeSafeDictionary<T> typeSafeDictionary) | |||
where T : struct, IEntityStruct | |||
{ | |||
if (UnsafeQueryEntityDictionary(group, TypeCache<T>.type, out var safeDictionary) == false) | |||
{ | |||
typeSafeDictionary = default; | |||
return false; | |||
} | |||
//return the indexes entities if they exist | |||
typeSafeDictionary = safeDictionary as TypeSafeDictionary<T>; | |||
return true; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
internal bool UnsafeQueryEntityDictionary(uint group, Type type, out ITypeSafeDictionary typeSafeDictionary) | |||
{ | |||
//search for the group | |||
if (_groupEntityViewsDB.TryGetValue(group, out var entitiesInGroupPerType) == false) | |||
{ | |||
typeSafeDictionary = null; | |||
return false; | |||
} | |||
//search for the indexed entities in the group | |||
return entitiesInGroupPerType.TryGetValue(new RefWrapper<Type>(type), out typeSafeDictionary); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
static T[] RetrieveEmptyEntityViewArray<T>() | |||
{ | |||
return EmptyList<T>.emptyArray; | |||
} | |||
//grouped set of entity views, this is the standard way to handle entity views entity views are grouped per | |||
//group, then indexable per type, then indexable per EGID. however the TypeSafeDictionary can return an array of | |||
//values directly, that can be iterated over, so that is possible to iterate over all the entity views of | |||
//a specific type inside a specific group. | |||
readonly FasterDictionary<uint, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>> _groupEntityViewsDB; | |||
//needed to be able to iterate over all the entities of the same type regardless the group | |||
//may change in future | |||
readonly FasterDictionary<RefWrapper<Type>, FasterDictionary<uint, ITypeSafeDictionary>> _groupsPerEntity; | |||
readonly EntitiesStream _entityStream; | |||
static class EmptyList<T> | |||
{ | |||
internal static readonly T[] emptyArray = new T[0]; | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: cb0042f8a957c1a4d8eb8998a0e4eef9 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,138 +0,0 @@ | |||
#if !DEBUG || PROFILER | |||
#define DISABLE_CHECKS | |||
using System.Diagnostics; | |||
#endif | |||
using System; | |||
using System.Reflection; | |||
namespace Svelto.ECS | |||
{ | |||
internal static class EntityBuilderUtilities | |||
{ | |||
const string MSG = "Entity Structs field and Entity View Struct components must hold value types."; | |||
#if DISABLE_CHECKS | |||
[Conditional("_CHECKS_DISABLED")] | |||
#endif | |||
public static void CheckFields(Type entityStructType, bool needsReflection, bool isStringAllowed = false) | |||
{ | |||
if (entityStructType == ENTITY_STRUCT_INFO_VIEW || | |||
entityStructType == EGIDType || | |||
entityStructType == EXCLUSIVEGROUPSTRUCTTYPE || | |||
entityStructType == SERIALIZABLE_ENTITY_STRUCT) | |||
{ | |||
return; | |||
} | |||
if (needsReflection == false) | |||
{ | |||
if (entityStructType.IsClass) | |||
{ | |||
throw new EntityStructException("EntityStructs must be structs.", entityStructType); | |||
} | |||
FieldInfo[] fields = entityStructType.GetFields(BindingFlags.Public | BindingFlags.Instance); | |||
for (var i = fields.Length - 1; i >= 0; --i) | |||
{ | |||
FieldInfo fieldInfo = fields[i]; | |||
Type fieldType = fieldInfo.FieldType; | |||
SubCheckFields(fieldType, entityStructType, isStringAllowed); | |||
} | |||
} | |||
else | |||
{ | |||
FieldInfo[] fields = entityStructType.GetFields(BindingFlags.Public | BindingFlags.Instance); | |||
if (fields.Length < 1) | |||
{ | |||
ProcessError("Entity View Structs must hold only entity components interfaces.", entityStructType); | |||
} | |||
for (int i = fields.Length - 1; i >= 0; --i) | |||
{ | |||
FieldInfo fieldInfo = fields[i]; | |||
if (fieldInfo.FieldType.IsInterfaceEx() == false) | |||
{ | |||
ProcessError("Entity View Structs must hold only entity components interfaces.", | |||
entityStructType); | |||
} | |||
PropertyInfo[] properties = fieldInfo.FieldType.GetProperties( | |||
BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); | |||
for (int j = properties.Length - 1; j >= 0; --j) | |||
{ | |||
if (properties[j].PropertyType.IsGenericType) | |||
{ | |||
Type genericTypeDefinition = properties[j].PropertyType.GetGenericTypeDefinition(); | |||
if (genericTypeDefinition == DISPATCHONSETTYPE || | |||
genericTypeDefinition == DISPATCHONCHANGETYPE) | |||
{ | |||
continue; | |||
} | |||
} | |||
Type propertyType = properties[j].PropertyType; | |||
if (propertyType != STRINGTYPE) | |||
{ | |||
//for EntityViewStructs, component fields that are structs that hold strings | |||
//are allowed | |||
SubCheckFields(propertyType, entityStructType, isStringAllowed: true); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
static void SubCheckFields(Type fieldType, Type entityStructType, bool isStringAllowed = false) | |||
{ | |||
if (fieldType.IsPrimitive || fieldType.IsValueType || (isStringAllowed == true && fieldType == STRINGTYPE)) | |||
{ | |||
if (fieldType.IsValueType && !fieldType.IsEnum && fieldType.IsPrimitive == false) | |||
{ | |||
CheckFields(fieldType, false, isStringAllowed); | |||
} | |||
return; | |||
} | |||
ProcessError(MSG, entityStructType, fieldType); | |||
} | |||
static void ProcessError(string message, Type entityViewType, Type fieldType = null) | |||
{ | |||
if (fieldType != null) | |||
{ | |||
throw new EntityStructException(message, entityViewType, fieldType); | |||
} | |||
throw new EntityStructException(message, entityViewType); | |||
} | |||
static readonly Type DISPATCHONCHANGETYPE = typeof(DispatchOnChange<>); | |||
static readonly Type DISPATCHONSETTYPE = typeof(DispatchOnSet<>); | |||
static readonly Type EGIDType = typeof(EGID); | |||
static readonly Type EXCLUSIVEGROUPSTRUCTTYPE = typeof(ExclusiveGroup.ExclusiveGroupStruct); | |||
static readonly Type SERIALIZABLE_ENTITY_STRUCT = typeof(SerializableEntityStruct); | |||
static readonly Type STRINGTYPE = typeof(string); | |||
internal static readonly Type ENTITY_STRUCT_INFO_VIEW = typeof(EntityStructInfoView); | |||
} | |||
public class EntityStructException : Exception | |||
{ | |||
public EntityStructException(string message, Type entityViewType, Type type) : | |||
base(message.FastConcat(" entity view: '", entityViewType.ToString(), "', field: '", type.ToString())) | |||
{ | |||
} | |||
public EntityStructException(string message, Type entityViewType) : | |||
base(message.FastConcat(" entity view: ", entityViewType.ToString())) | |||
{ | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: bbdea957dc4279b449608942ff29174e | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,146 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Hybrid; | |||
using Svelto.ECS.Internal; | |||
using Svelto.Utilities; | |||
namespace Svelto.ECS | |||
{ | |||
public class EntityBuilder<T> : IEntityBuilder where T : struct, IEntityStruct | |||
{ | |||
static class EntityView | |||
{ | |||
internal static readonly FasterList<KeyValuePair<Type, ActionCast<T>>> cachedFields; | |||
internal static readonly Dictionary<Type, Type[]> cachedTypes; | |||
#if DEBUG && !PROFILER | |||
internal static readonly Dictionary<Type, ECSTuple<object, int>> implementorsByType; | |||
#else | |||
internal static readonly Dictionary<Type, object> implementorsByType; | |||
#endif | |||
static EntityView() | |||
{ | |||
cachedFields = new FasterList<KeyValuePair<Type, ActionCast<T>>>(); | |||
var type = typeof(T); | |||
var fields = type.GetFields(BindingFlags.Public | | |||
BindingFlags.Instance); | |||
for (var i = fields.Length - 1; i >= 0; --i) | |||
{ | |||
var field = fields[i]; | |||
var setter = FastInvoke<T>.MakeSetter(field); | |||
cachedFields.Add(new KeyValuePair<Type, ActionCast<T>>(field.FieldType, setter)); | |||
} | |||
cachedTypes = new Dictionary<Type, Type[]>(); | |||
#if DEBUG && !PROFILER | |||
implementorsByType = new Dictionary<Type, ECSTuple<object, int>>(); | |||
#else | |||
implementorsByType = new Dictionary<Type, object>(); | |||
#endif | |||
} | |||
internal static void InitCache() | |||
{} | |||
internal static void BuildEntityView(out T entityView) | |||
{ | |||
entityView = new T(); | |||
} | |||
} | |||
public EntityBuilder() | |||
{ | |||
_initializer = DEFAULT_IT; | |||
EntityBuilderUtilities.CheckFields(ENTITY_VIEW_TYPE, NEEDS_REFLECTION); | |||
if (NEEDS_REFLECTION) | |||
EntityView.InitCache(); | |||
} | |||
public EntityBuilder(in T initializer) : this() | |||
{ | |||
_initializer = initializer; | |||
} | |||
public void BuildEntityAndAddToList(ref ITypeSafeDictionary dictionary, EGID egid, | |||
IEnumerable<object> implementors) | |||
{ | |||
if (dictionary == null) | |||
dictionary = new TypeSafeDictionary<T>(); | |||
var castedDic = dictionary as TypeSafeDictionary<T>; | |||
if (NEEDS_REFLECTION) | |||
{ | |||
DBC.ECS.Check.Require(implementors != null, | |||
$"Implementors not found while building an EntityView `{typeof(T)}`"); | |||
DBC.ECS.Check.Require(castedDic.ContainsKey(egid.entityID) == false, | |||
$"building an entity with already used entity id! id: '{(ulong) egid}', {ENTITY_VIEW_NAME}"); | |||
EntityView.BuildEntityView(out var entityView); | |||
this.FillEntityView(ref entityView, entityViewBlazingFastReflection, implementors, | |||
EntityView.implementorsByType, EntityView.cachedTypes); | |||
castedDic.Add(egid.entityID, entityView); | |||
} | |||
else | |||
{ | |||
DBC.ECS.Check.Require(!castedDic.ContainsKey(egid.entityID), | |||
$"building an entity with already used entity id! id: '{egid.entityID}'"); | |||
castedDic.Add(egid.entityID, _initializer); | |||
} | |||
} | |||
ITypeSafeDictionary IEntityBuilder.Preallocate(ref ITypeSafeDictionary dictionary, uint size) | |||
{ | |||
return Preallocate(ref dictionary, size); | |||
} | |||
static ITypeSafeDictionary Preallocate(ref ITypeSafeDictionary dictionary, uint size) | |||
{ | |||
if (dictionary == null) | |||
dictionary = new TypeSafeDictionary<T>(size); | |||
else | |||
dictionary.SetCapacity(size); | |||
return dictionary; | |||
} | |||
public Type GetEntityType() | |||
{ | |||
return ENTITY_VIEW_TYPE; | |||
} | |||
static EntityBuilder() | |||
{ | |||
ENTITY_VIEW_TYPE = typeof(T); | |||
DEFAULT_IT = default; | |||
NEEDS_REFLECTION = typeof(IEntityViewStruct).IsAssignableFrom(ENTITY_VIEW_TYPE); | |||
HAS_EGID = typeof(INeedEGID).IsAssignableFrom(ENTITY_VIEW_TYPE); | |||
ENTITY_VIEW_NAME = ENTITY_VIEW_TYPE.ToString(); | |||
SetEGIDWithoutBoxing<T>.Warmup(); | |||
} | |||
readonly T _initializer; | |||
static FasterList<KeyValuePair<Type, ActionCast<T>>> entityViewBlazingFastReflection => | |||
EntityView.cachedFields; | |||
internal static readonly Type ENTITY_VIEW_TYPE; | |||
public static readonly bool HAS_EGID; | |||
static readonly T DEFAULT_IT; | |||
static readonly bool NEEDS_REFLECTION; | |||
static readonly string ENTITY_VIEW_NAME; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 18b343f034fedc946a8a1bea33d0d3b3 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,8 +0,0 @@ | |||
diff a/Assets/Svelto/Svelto.ECS/EntityBuilder.cs b/Assets/Svelto/Svelto.ECS/EntityBuilder.cs (rejected hunks) | |||
@@ -1,5 +1,6 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
+using DBC.ECS; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Hybrid; | |||
using Svelto.ECS.Internal; |
@@ -1,7 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: cb0c0429aca72c945b88d01cd901f218 | |||
DefaultImporter: | |||
externalObjects: {} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,326 +0,0 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
namespace Svelto.ECS | |||
{ | |||
public struct EntityCollection<T> | |||
{ | |||
public EntityCollection(T[] array, uint count) | |||
{ | |||
_array = array; | |||
_count = count; | |||
} | |||
public EntityIterator GetEnumerator() | |||
{ | |||
return new EntityIterator(_array, _count); | |||
} | |||
readonly T[] _array; | |||
readonly uint _count; | |||
public struct EntityIterator : IEnumerator<T> | |||
{ | |||
public EntityIterator(T[] array, uint count) : this() | |||
{ | |||
_array = array; | |||
_count = count; | |||
_index = -1; | |||
} | |||
public bool MoveNext() | |||
{ | |||
return ++_index < _count; | |||
} | |||
public void Reset() | |||
{ | |||
_index = -1; | |||
} | |||
public ref T Current => ref _array[_index]; | |||
T IEnumerator<T>.Current => throw new NotImplementedException(); | |||
object IEnumerator.Current => throw new NotImplementedException(); | |||
public void Dispose() {} | |||
readonly T[] _array; | |||
readonly uint _count; | |||
int _index; | |||
} | |||
} | |||
public struct EntityCollection<T1, T2> | |||
{ | |||
public EntityCollection(in (T1[], T2[]) array, uint count) | |||
{ | |||
_array = array; | |||
_count = count; | |||
} | |||
public EntityIterator GetEnumerator() | |||
{ | |||
return new EntityIterator(_array, _count); | |||
} | |||
readonly (T1[], T2[]) _array; | |||
readonly uint _count; | |||
public struct EntityIterator : IEnumerator<ValueRef<T1, T2>> | |||
{ | |||
public EntityIterator((T1[], T2[]) array, uint count) : this() | |||
{ | |||
_array = array; | |||
_count = count; | |||
_index = -1; | |||
} | |||
public bool MoveNext() | |||
{ | |||
return ++_index < _count; | |||
} | |||
public void Reset() | |||
{ | |||
_index = -1; | |||
} | |||
public ValueRef<T1, T2> Current => new ValueRef<T1, T2>(_array, (uint) _index); | |||
ValueRef<T1, T2> IEnumerator<ValueRef<T1, T2>>. Current => throw new NotImplementedException(); | |||
object IEnumerator.Current => throw new NotImplementedException(); | |||
public void Dispose() {} | |||
readonly (T1[], T2[]) _array; | |||
readonly uint _count; | |||
int _index; | |||
} | |||
} | |||
public struct EntityCollection<T1, T2, T3> | |||
{ | |||
public EntityCollection(in (T1[], T2[], T3[]) array, uint count) | |||
{ | |||
_array = array; | |||
_count = count; | |||
} | |||
public EntityIterator GetEnumerator() | |||
{ | |||
return new EntityIterator(_array, _count); | |||
} | |||
readonly (T1[], T2[], T3[]) _array; | |||
readonly uint _count; | |||
public struct EntityIterator : IEnumerator<ValueRef<T1, T2, T3>> | |||
{ | |||
public EntityIterator((T1[], T2[], T3[]) array, uint count) : this() | |||
{ | |||
_array = array; | |||
_count = count; | |||
_index = -1; | |||
} | |||
public bool MoveNext() | |||
{ | |||
return ++_index < _count; | |||
} | |||
public void Reset() | |||
{ | |||
_index = -1; | |||
} | |||
public ValueRef<T1, T2, T3> Current => new ValueRef<T1, T2, T3>(_array, (uint) _index); | |||
ValueRef<T1, T2, T3> IEnumerator<ValueRef<T1, T2, T3>>.Current => throw new NotImplementedException(); | |||
object IEnumerator. Current => throw new NotImplementedException(); | |||
public void Dispose() {} | |||
readonly (T1[], T2[], T3[]) _array; | |||
readonly uint _count; | |||
int _index; | |||
} | |||
} | |||
public struct EntityCollections<T> where T : struct, IEntityStruct | |||
{ | |||
public EntityCollections(IEntitiesDB db, ExclusiveGroup[] groups) : this() | |||
{ | |||
_db = db; | |||
_groups = groups; | |||
} | |||
public EntityGroupsIterator GetEnumerator() | |||
{ | |||
return new EntityGroupsIterator(_db, _groups); | |||
} | |||
readonly IEntitiesDB _db; | |||
readonly ExclusiveGroup[] _groups; | |||
public struct EntityGroupsIterator : IEnumerator<T> | |||
{ | |||
public EntityGroupsIterator(IEntitiesDB db, ExclusiveGroup[] groups) : this() | |||
{ | |||
_db = db; | |||
_groups = groups; | |||
_indexGroup = -1; | |||
_index = -1; | |||
} | |||
public bool MoveNext() | |||
{ | |||
while (_index + 1 >= _count && ++_indexGroup < _groups.Length) | |||
{ | |||
_index = -1; | |||
_array = _db.QueryEntities<T>(_groups[_indexGroup], out _count); | |||
} | |||
return ++_index < _count; | |||
} | |||
public void Reset() | |||
{ | |||
_index = -1; | |||
_indexGroup = -1; | |||
_count = 0; | |||
} | |||
public ref T Current => ref _array[_index]; | |||
T IEnumerator<T>.Current => throw new NotImplementedException(); | |||
object IEnumerator.Current => throw new NotImplementedException(); | |||
public void Dispose() {} | |||
readonly IEntitiesDB _db; | |||
readonly ExclusiveGroup[] _groups; | |||
T[] _array; | |||
uint _count; | |||
int _index; | |||
int _indexGroup; | |||
} | |||
} | |||
public struct EntityCollections<T1, T2> where T1 : struct, IEntityStruct where T2 : struct, IEntityStruct | |||
{ | |||
public EntityCollections(IEntitiesDB db, ExclusiveGroup[] groups) : this() | |||
{ | |||
_db = db; | |||
_groups = groups; | |||
} | |||
public EntityGroupsIterator GetEnumerator() | |||
{ | |||
return new EntityGroupsIterator(_db, _groups); | |||
} | |||
readonly IEntitiesDB _db; | |||
readonly ExclusiveGroup[] _groups; | |||
public struct EntityGroupsIterator : IEnumerator<ValueRef<T1, T2>> | |||
{ | |||
public EntityGroupsIterator(IEntitiesDB db, ExclusiveGroup[] groups) : this() | |||
{ | |||
_db = db; | |||
_groups = groups; | |||
_indexGroup = -1; | |||
_index = -1; | |||
} | |||
public bool MoveNext() | |||
{ | |||
while (_index + 1 >= _count && ++_indexGroup < _groups.Length) | |||
{ | |||
_index = -1; | |||
var array1 = _db.QueryEntities<T1>(_groups[_indexGroup], out _count); | |||
var array2 = _db.QueryEntities<T2>(_groups[_indexGroup], out var count1); | |||
_array = (array1, array2); | |||
#if DEBUG && !PROFILER | |||
if (_count != count1) | |||
throw new ECSException("number of entities in group doesn't match"); | |||
#endif | |||
} | |||
return ++_index < _count; | |||
} | |||
public void Reset() | |||
{ | |||
_index = -1; | |||
_indexGroup = -1; | |||
var array1 = _db.QueryEntities<T1>(_groups[0], out _count); | |||
var array2 = _db.QueryEntities<T2>(_groups[0], out var count1); | |||
_array = (array1, array2); | |||
#if DEBUG && !PROFILER | |||
if (_count != count1) | |||
throw new ECSException("number of entities in group doesn't match"); | |||
#endif | |||
} | |||
public ValueRef<T1, T2> Current | |||
{ | |||
get | |||
{ | |||
var valueRef = new ValueRef<T1, T2>(_array, (uint) _index); | |||
return valueRef; | |||
} | |||
} | |||
ValueRef<T1, T2> IEnumerator<ValueRef<T1, T2>>.Current => throw new NotImplementedException(); | |||
object IEnumerator.Current => throw new NotImplementedException(); | |||
public void Dispose() {} | |||
readonly IEntitiesDB _db; | |||
readonly ExclusiveGroup[] _groups; | |||
uint _count; | |||
int _index; | |||
int _indexGroup; | |||
(T1[], T2[]) _array; | |||
} | |||
} | |||
public struct ValueRef<T1, T2> | |||
{ | |||
readonly (T1[], T2[]) array; | |||
readonly uint index; | |||
public ValueRef(in (T1[], T2[]) entity1, uint i) | |||
{ | |||
array = entity1; | |||
index = i; | |||
} | |||
public ref T1 entityStructA => ref array.Item1[index]; | |||
public ref T2 entityStructB => ref array.Item2[index]; | |||
} | |||
public struct ValueRef<T1, T2, T3> | |||
{ | |||
readonly (T1[], T2[], T3[]) array; | |||
readonly uint index; | |||
public ValueRef(in (T1[], T2[], T3[]) entity1, uint i) | |||
{ | |||
array = entity1; | |||
index = i; | |||
} | |||
public ref T1 entityStructA => ref array.Item1[index]; | |||
public ref T2 entityStructB => ref array.Item2[index]; | |||
public ref T3 entityStructC => ref array.Item3[index]; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: b477a77cde9842c4938fe4c4143d6479 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,17 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityDescriptor | |||
{ | |||
IEntityBuilder[] entitiesToBuild { get; } | |||
} | |||
static class EntityDescriptorTemplate<TType> where TType : IEntityDescriptor, new() | |||
{ | |||
static EntityDescriptorTemplate() | |||
{ | |||
descriptor = new TType(); | |||
} | |||
public static IEntityDescriptor descriptor { get; } | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 1ecaeae9d21e0e8458a05cf7608e782a | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,97 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
static class EntityFactory | |||
{ | |||
public static FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> BuildGroupedEntities(EGID egid, | |||
EnginesRoot.DoubleBufferedEntitiesToAdd groupEntitiesToAdd, | |||
IEntityBuilder[] entitiesToBuild, | |||
IEnumerable<object> implementors) | |||
{ | |||
var group = FetchEntityGroup(egid.groupID, groupEntitiesToAdd); | |||
BuildEntitiesAndAddToGroup(egid, group, entitiesToBuild, implementors); | |||
return group; | |||
} | |||
static FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> FetchEntityGroup(uint groupID, | |||
EnginesRoot.DoubleBufferedEntitiesToAdd groupEntityViewsByType) | |||
{ | |||
if (groupEntityViewsByType.current.TryGetValue(groupID, out var group) == false) | |||
{ | |||
group = new FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>(); | |||
groupEntityViewsByType.current.Add(groupID, group); | |||
} | |||
if (groupEntityViewsByType.currentEntitiesCreatedPerGroup.TryGetValue(groupID, out var value) == false) | |||
groupEntityViewsByType.currentEntitiesCreatedPerGroup[groupID] = 0; | |||
else | |||
groupEntityViewsByType.currentEntitiesCreatedPerGroup[groupID] = value+1; | |||
return group; | |||
} | |||
static void BuildEntitiesAndAddToGroup(EGID entityID, | |||
FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> group, | |||
IEntityBuilder[] entityBuilders, IEnumerable<object> implementors) | |||
{ | |||
#if DEBUG && !PROFILER | |||
HashSet<Type> types = new HashSet<Type>(); | |||
#endif | |||
InternalBuild(entityID, group, entityBuilders, implementors | |||
#if DEBUG && !PROFILER | |||
, types | |||
#endif | |||
); | |||
} | |||
static void InternalBuild(EGID entityID, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> group, | |||
IEntityBuilder[] entityBuilders, IEnumerable<object> implementors | |||
#if DEBUG && !PROFILER | |||
, HashSet<Type> types | |||
#endif | |||
) | |||
{ | |||
var count = entityBuilders.Length; | |||
#if DEBUG && !PROFILER | |||
for (var index = 0; index < count; ++index) | |||
{ | |||
var entityViewType = entityBuilders[index].GetEntityType(); | |||
if (types.Contains(entityViewType)) | |||
{ | |||
throw new ECSException("EntityBuilders must be unique inside an EntityDescriptor"); | |||
} | |||
types.Add(entityViewType); | |||
} | |||
#endif | |||
for (var index = 0; index < count; ++index) | |||
{ | |||
var entityStructBuilder = entityBuilders[index]; | |||
var entityViewType = entityStructBuilder.GetEntityType(); | |||
BuildEntity(entityID, group, entityViewType, entityStructBuilder, implementors); | |||
} | |||
} | |||
static void BuildEntity(EGID entityID, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> group, | |||
Type entityViewType, IEntityBuilder entityBuilder, IEnumerable<object> implementors) | |||
{ | |||
var entityViewsPoolWillBeCreated = | |||
group.TryGetValue(new RefWrapper<Type>(entityViewType), out var safeDictionary) == false; | |||
//passing the undefined entityViewsByType inside the entityViewBuilder will allow it to be created with the | |||
//correct type and casted back to the undefined list. that's how the list will be eventually of the target | |||
//type. | |||
entityBuilder.BuildEntityAndAddToList(ref safeDictionary, entityID, implementors); | |||
if (entityViewsPoolWillBeCreated) | |||
group.Add(new RefWrapper<Type>(entityViewType), safeDictionary); | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 73604bc7f8d240e4e8730f9f28705114 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,12 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
class EntityGroupNotFoundException : Exception | |||
{ | |||
public EntityGroupNotFoundException(uint groupId, Type type) | |||
: base("entity group not found ".FastConcat(type.ToString())) | |||
{ | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 4263819fdb1fe88498346ad16e7cfc08 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,11 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public struct EntityHierarchyStruct: IEntityStruct, INeedEGID | |||
{ | |||
public readonly ExclusiveGroup.ExclusiveGroupStruct parentGroup; | |||
public EntityHierarchyStruct(ExclusiveGroup group): this() { parentGroup = group; } | |||
public EGID ID { get; set; } | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: ed0c5daf03d0e29458868443df80b239 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,7 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
struct EntityStructInfoView: IEntityStruct | |||
{ | |||
public IEntityBuilder[] entitiesToBuild; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 9de43f2cdb7017f4cb3cd7ecf923b932 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,12 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public class EntityNotFoundException : Exception | |||
{ | |||
public EntityNotFoundException(EGID entityEGID, Type entityType) : base( | |||
$"entity of type '{entityType}' with ID '{entityEGID.entityID}', group '{(uint) entityEGID.groupID}' not found!") | |||
{ | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 77beec6a936d3ad4f94b89eb4a28b14f | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,163 +0,0 @@ | |||
using System; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
/// <summary> | |||
/// Do not use this class in place of a normal polling. | |||
/// I eventually realised than in ECS no form of communication other than polling entity components can exist. | |||
/// Using groups, you can have always an optimal set of entity components to poll, so EntityStreams must be used | |||
/// only if: | |||
/// - you want to polling engine to be able to track all the entity changes happening in between polls and not | |||
/// just the current state | |||
/// - you want a thread-safe way to read entity states, which includes all the state changes and not the last | |||
/// one only | |||
/// - you want to communicate between EnginesRoots | |||
/// </summary> | |||
class EntitiesStream : IDisposable | |||
{ | |||
internal Consumer<T> GenerateConsumer<T>(string name, uint capacity) where T : unmanaged, IEntityStruct | |||
{ | |||
if (_streams.ContainsKey(TypeRefWrapper<T>.wrapper) == false) _streams[TypeRefWrapper<T>.wrapper] = new EntityStream<T>(); | |||
return (_streams[TypeRefWrapper<T>.wrapper] as EntityStream<T>).GenerateConsumer(name, capacity); | |||
} | |||
public Consumer<T> GenerateConsumer<T>(ExclusiveGroup group, string name, uint capacity) | |||
where T : unmanaged, IEntityStruct | |||
{ | |||
if (_streams.ContainsKey(TypeRefWrapper<T>.wrapper) == false) _streams[TypeRefWrapper<T>.wrapper] = new EntityStream<T>(); | |||
return (_streams[TypeRefWrapper<T>.wrapper] as EntityStream<T>).GenerateConsumer(group, name, capacity); | |||
} | |||
internal void PublishEntity<T>(ref T entity, EGID egid) where T : unmanaged, IEntityStruct | |||
{ | |||
if (_streams.TryGetValue(TypeRefWrapper<T>.wrapper, out var typeSafeStream)) | |||
(typeSafeStream as EntityStream<T>).PublishEntity(ref entity, egid); | |||
else | |||
Console.LogDebug("No Consumers are waiting for this entity to change ", typeof(T)); | |||
} | |||
readonly ThreadSafeDictionary<RefWrapper<Type>, ITypeSafeStream> _streams = | |||
new ThreadSafeDictionary<RefWrapper<Type>, ITypeSafeStream>(); | |||
public void Dispose() | |||
{ | |||
_streams.Clear(); | |||
} | |||
} | |||
interface ITypeSafeStream | |||
{} | |||
class EntityStream<T> : ITypeSafeStream where T : unmanaged, IEntityStruct | |||
{ | |||
public void PublishEntity(ref T entity, EGID egid) | |||
{ | |||
for (int i = 0; i < _consumers.Count; i++) | |||
{ | |||
if (_consumers[i]._hasGroup) | |||
{ | |||
if (egid.groupID == _consumers[i]._group) | |||
{ | |||
_consumers[i].Enqueue(entity, egid); | |||
} | |||
} | |||
else | |||
{ | |||
_consumers[i].Enqueue(entity, egid); | |||
} | |||
} | |||
} | |||
public Consumer<T> GenerateConsumer(string name, uint capacity) | |||
{ | |||
var consumer = new Consumer<T>(name, capacity, this); | |||
_consumers.Add(consumer); | |||
return consumer; | |||
} | |||
public Consumer<T> GenerateConsumer(ExclusiveGroup group, string name, uint capacity) | |||
{ | |||
var consumer = new Consumer<T>(group, name, capacity, this); | |||
_consumers.Add(consumer); | |||
return consumer; | |||
} | |||
public void RemoveConsumer(Consumer<T> consumer) | |||
{ | |||
_consumers.UnorderedRemove(consumer); | |||
} | |||
readonly FasterListThreadSafe<Consumer<T>> _consumers = new FasterListThreadSafe<Consumer<T>>(); | |||
} | |||
public struct Consumer<T> : IDisposable where T : unmanaged, IEntityStruct | |||
{ | |||
internal Consumer(string name, uint capacity, EntityStream<T> stream):this() | |||
{ | |||
#if DEBUG && !PROFILER | |||
_name = name; | |||
#endif | |||
_ringBuffer = new RingBuffer<ValueTuple<T, EGID>>((int) capacity, | |||
#if DEBUG && !PROFILER | |||
_name | |||
#else | |||
string.Empty | |||
#endif | |||
); | |||
_stream = stream; | |||
} | |||
internal Consumer(ExclusiveGroup group, string name, uint capacity, EntityStream<T> stream) : this(name, | |||
capacity, stream) | |||
{ | |||
_group = group; | |||
_hasGroup = true; | |||
} | |||
internal void Enqueue(in T entity, in EGID egid) | |||
{ | |||
_ringBuffer.Enqueue((entity, egid)); | |||
} | |||
public bool TryDequeue(out T entity) | |||
{ | |||
var tryDequeue = _ringBuffer.TryDequeue(out var values); | |||
entity = values.Item1; | |||
return tryDequeue; | |||
} | |||
public bool TryDequeue(out T entity, out EGID id) | |||
{ | |||
var tryDequeue = _ringBuffer.TryDequeue(out var values); | |||
entity = values.Item1; | |||
id = values.Item2; | |||
return tryDequeue; | |||
} | |||
public void Flush() { _ringBuffer.Reset(); } | |||
public void Dispose() { _stream.RemoveConsumer(this); } | |||
public uint Count() { return (uint) _ringBuffer.Count; } | |||
readonly RingBuffer<ValueTuple<T, EGID>> _ringBuffer; | |||
readonly EntityStream<T> _stream; | |||
internal readonly ExclusiveGroup _group; | |||
internal readonly bool _hasGroup; | |||
#if DEBUG && !PROFILER | |||
readonly string _name; | |||
#endif | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: b3ae4a042b4e3304c921fe85e830ff4c | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,75 +0,0 @@ | |||
using System; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public ref struct EntityStructInitializer | |||
{ | |||
public EntityStructInitializer(EGID id, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> group) | |||
{ | |||
_group = group; | |||
_ID = id; | |||
} | |||
public void Init<T>(T initializer) where T : struct, IEntityStruct | |||
{ | |||
if (_group.TryGetValue(new RefWrapper<Type>(EntityBuilder<T>.ENTITY_VIEW_TYPE), | |||
out var typeSafeDictionary) == false) return; | |||
var dictionary = (TypeSafeDictionary<T>) typeSafeDictionary; | |||
if (EntityBuilder<T>.HAS_EGID) | |||
SetEGIDWithoutBoxing<T>.SetIDWithoutBoxing(ref initializer, _ID); | |||
if (dictionary.TryFindIndex(_ID.entityID, out var findElementIndex)) | |||
dictionary.GetDirectValue(findElementIndex) = initializer; | |||
} | |||
public void CopyFrom<T>(T initializer) where T : struct, IEntityStruct | |||
{ | |||
var dictionary = (TypeSafeDictionary<T>) _group[new RefWrapper<Type>(EntityBuilder<T>.ENTITY_VIEW_TYPE)]; | |||
if (EntityBuilder<T>.HAS_EGID) | |||
SetEGIDWithoutBoxing<T>.SetIDWithoutBoxing(ref initializer, _ID); | |||
dictionary[_ID.entityID] = initializer; | |||
} | |||
public ref T GetOrCreate<T>() where T : struct, IEntityStruct | |||
{ | |||
ref var entityDictionary = ref _group.GetOrCreate(new RefWrapper<Type>(EntityBuilder<T>.ENTITY_VIEW_TYPE) | |||
, () => new TypeSafeDictionary<T>()); | |||
var dictionary = (TypeSafeDictionary<T>) entityDictionary; | |||
return ref dictionary.GetOrCreate(_ID.entityID); | |||
} | |||
public T Get<T>() where T : struct, IEntityStruct | |||
{ | |||
return (_group[new RefWrapper<Type>(EntityBuilder<T>.ENTITY_VIEW_TYPE)] as TypeSafeDictionary<T>)[_ID.entityID]; | |||
} | |||
public bool Has<T>() where T : struct, IEntityStruct | |||
{ | |||
if (_group.TryGetValue(new RefWrapper<Type>(EntityBuilder<T>.ENTITY_VIEW_TYPE), | |||
out var typeSafeDictionary)) | |||
{ | |||
var dictionary = (TypeSafeDictionary<T>) typeSafeDictionary; | |||
if (dictionary.ContainsKey(_ID.entityID)) | |||
return true; | |||
} | |||
return false; | |||
} | |||
public static EntityStructInitializer CreateEmptyInitializer() | |||
{ | |||
return new EntityStructInitializer(new EGID(), new FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>()); | |||
} | |||
readonly EGID _ID; | |||
readonly FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> _group; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 5cb5eea9477898947b16db259b700950 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,9 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS.Schedulers | |||
{ | |||
public interface IEntitySubmissionScheduler: IDisposable | |||
{ | |||
EnginesRoot.EntitiesSubmitter onTick { set; } | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 55fb2dc75e765c9478ff524a893e54a5 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,53 +0,0 @@ | |||
using System; | |||
using System.Diagnostics; | |||
namespace Svelto.ECS | |||
{ | |||
#pragma warning disable 660,661 | |||
struct EntitySubmitOperation | |||
#pragma warning restore 660,661 | |||
: IEquatable<EntitySubmitOperation> | |||
{ | |||
public readonly EntitySubmitOperationType type; | |||
public readonly IEntityBuilder[] builders; | |||
public readonly EGID fromID; | |||
public readonly EGID toID; | |||
#if DEBUG && !PROFILER | |||
public StackFrame trace; | |||
#endif | |||
public EntitySubmitOperation(EntitySubmitOperationType operation, EGID from, EGID to, | |||
IEntityBuilder[] builders = null) | |||
{ | |||
type = operation; | |||
this.builders = builders; | |||
fromID = from; | |||
toID = to; | |||
#if DEBUG && !PROFILER | |||
trace = default; | |||
#endif | |||
} | |||
public static bool operator ==(EntitySubmitOperation obj1, EntitySubmitOperation obj2) | |||
{ | |||
return obj1.Equals(obj2); | |||
} | |||
public static bool operator !=(EntitySubmitOperation obj1, EntitySubmitOperation obj2) | |||
{ | |||
return obj1.Equals(obj2) == false; | |||
} | |||
public bool Equals(EntitySubmitOperation other) | |||
{ | |||
return type == other.type && fromID == other.fromID && toID == other.toID; | |||
} | |||
} | |||
enum EntitySubmitOperationType | |||
{ | |||
Swap, | |||
Remove, | |||
RemoveGroup | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 10e7122095a379642afacb59dda231ed | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,125 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.Utilities; | |||
namespace Svelto.ECS | |||
{ | |||
#if DEBUG && !PROFILER | |||
struct ECSTuple<T1, T2> | |||
{ | |||
public readonly T1 implementorType; | |||
public T2 numberOfImplementations; | |||
public ECSTuple(T1 implementor, T2 v) | |||
{ | |||
implementorType = implementor; | |||
numberOfImplementations = v; | |||
} | |||
} | |||
#endif | |||
static class EntityViewUtility | |||
{ | |||
public static void FillEntityView<T>(this IEntityBuilder entityBuilder | |||
, ref T entityView | |||
, FasterList<KeyValuePair<Type, ActionCast<T>>> | |||
entityViewBlazingFastReflection | |||
, IEnumerable<object> implementors, | |||
#if DEBUG && !PROFILER | |||
Dictionary<Type, ECSTuple<object, int>> implementorsByType | |||
#else | |||
Dictionary<Type, object> implementorsByType | |||
#endif | |||
, Dictionary<Type, Type[]> cachedTypes | |||
) | |||
{ | |||
//efficient way to collect the fields of every EntityViewType | |||
var setters = | |||
FasterList<KeyValuePair<Type, ActionCast<T>>>.NoVirt.ToArrayFast(entityViewBlazingFastReflection, out var count); | |||
foreach (var implementor in implementors) | |||
{ | |||
if (implementor != null) | |||
{ | |||
var type = implementor.GetType(); | |||
if (cachedTypes.TryGetValue(type, out var interfaces) == false) | |||
interfaces = cachedTypes[type] = type.GetInterfacesEx(); | |||
for (var iindex = 0; iindex < interfaces.Length; iindex++) | |||
{ | |||
var componentType = interfaces[iindex]; | |||
#if DEBUG && !PROFILER | |||
if (implementorsByType.TryGetValue(componentType, out var implementorData)) | |||
{ | |||
implementorData.numberOfImplementations++; | |||
implementorsByType[componentType] = implementorData; | |||
} | |||
else | |||
implementorsByType[componentType] = new ECSTuple<object, int>(implementor, 1); | |||
#else | |||
implementorsByType[componentType] = implementor; | |||
#endif | |||
} | |||
} | |||
#if DEBUG && !PROFILER | |||
else | |||
{ | |||
Console.Log(NULL_IMPLEMENTOR_ERROR.FastConcat(" entityView ", | |||
entityBuilder.GetEntityType().ToString())); | |||
} | |||
#endif | |||
} | |||
for (var i = 0; i < count; i++) | |||
{ | |||
var fieldSetter = setters[i]; | |||
var fieldType = fieldSetter.Key; | |||
#if DEBUG && !PROFILER | |||
ECSTuple<object, int> component; | |||
#else | |||
object component; | |||
#endif | |||
if (implementorsByType.TryGetValue(fieldType, out component) == false) | |||
{ | |||
var e = new ECSException(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name + | |||
" - EntityView: " + entityBuilder.GetEntityType().Name); | |||
throw e; | |||
} | |||
#if DEBUG && !PROFILER | |||
if (component.numberOfImplementations > 1) | |||
throw new ECSException(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat( | |||
"Component Type: ", fieldType.Name, | |||
" implementor: ", | |||
component.implementorType | |||
.ToString()) + | |||
" - EntityView: " + | |||
entityBuilder.GetEntityType().Name); | |||
#endif | |||
#if DEBUG && !PROFILER | |||
fieldSetter.Value(ref entityView, component.implementorType); | |||
#else | |||
fieldSetter.Value(ref entityView, component); | |||
#endif | |||
} | |||
implementorsByType.Clear(); | |||
} | |||
const string DUPLICATE_IMPLEMENTOR_ERROR = | |||
"<color=teal>Svelto.ECS</color> the same component is implemented with more than one implementor. This is " + | |||
"considered an error and MUST be fixed. "; | |||
const string NULL_IMPLEMENTOR_ERROR = | |||
"<color=teal>Svelto.ECS</color> Null implementor, please be careful about the implementors passed to avoid " + | |||
"performance loss "; | |||
const string NOT_FOUND_EXCEPTION = "<color=teal>Svelto.ECS</color> Implementor not found for an EntityView. "; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: d94149e37622cb44bad46dccfc619115 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,265 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
#pragma warning disable 660,661 | |||
namespace Svelto.ECS | |||
{ | |||
/// <summary> | |||
/// Exclusive Groups guarantee that the GroupID is unique. | |||
/// | |||
/// The best way to use it is like: | |||
/// | |||
/// public static class MyExclusiveGroups //(can be as many as you want) | |||
/// { | |||
/// public static ExclusiveGroup MyExclusiveGroup1 = new ExclusiveGroup(); | |||
/// | |||
/// public static ExclusiveGroup[] GroupOfGroups = { MyExclusiveGroup1, ...}; //for each on this! | |||
/// } | |||
/// </summary> | |||
/// | |||
///use this like: | |||
/// public class TriggersGroup : ExclusiveGroup<TriggersGroup> {} | |||
public abstract class NamedExclusiveGroup<T>:ExclusiveGroup | |||
{ | |||
public static ExclusiveGroup Group = new ExclusiveGroup(); | |||
public static string name = typeof(T).FullName; | |||
public NamedExclusiveGroup() { } | |||
public NamedExclusiveGroup(string recognizeAs) : base(recognizeAs) | |||
{} | |||
public NamedExclusiveGroup(ushort range) : base(range) | |||
{} | |||
} | |||
public class ExclusiveGroup | |||
{ | |||
public ExclusiveGroup() | |||
{ | |||
_group = ExclusiveGroupStruct.Generate(); | |||
} | |||
public ExclusiveGroup(string recognizeAs) | |||
{ | |||
_group = ExclusiveGroupStruct.Generate(); | |||
_serialisedGroups.Add(recognizeAs, _group); | |||
} | |||
public ExclusiveGroup(ushort range) | |||
{ | |||
_group = new ExclusiveGroupStruct(range); | |||
#if DEBUG | |||
_range = range; | |||
#endif | |||
} | |||
public static implicit operator ExclusiveGroupStruct(ExclusiveGroup group) | |||
{ | |||
return group._group; | |||
} | |||
public static explicit operator uint(ExclusiveGroup group) | |||
{ | |||
return group._group; | |||
} | |||
public static ExclusiveGroupStruct operator+(ExclusiveGroup a, uint b) | |||
{ | |||
#if DEBUG | |||
if (a._range == 0) | |||
throw new ECSException("adding values to a not ranged ExclusiveGroup"); | |||
if (b >= a._range) | |||
throw new ECSException("Using out of range group"); | |||
#endif | |||
return a._group + b; | |||
} | |||
readonly ExclusiveGroupStruct _group; | |||
//I use this as parameter because it must not be possible to pass null Exclusive Groups. | |||
public struct ExclusiveGroupStruct : IEquatable<ExclusiveGroupStruct>, IComparable<ExclusiveGroupStruct>, | |||
IEqualityComparer<ExclusiveGroupStruct> | |||
{ | |||
public static bool operator ==(ExclusiveGroupStruct c1, ExclusiveGroupStruct c2) | |||
{ | |||
return c1.Equals(c2); | |||
} | |||
public static bool operator !=(ExclusiveGroupStruct c1, ExclusiveGroupStruct c2) | |||
{ | |||
return c1.Equals(c2) == false; | |||
} | |||
public bool Equals(ExclusiveGroupStruct other) | |||
{ | |||
return other._id == _id; | |||
} | |||
public int CompareTo(ExclusiveGroupStruct other) | |||
{ | |||
return other._id.CompareTo(_id); | |||
} | |||
public bool Equals(ExclusiveGroupStruct x, ExclusiveGroupStruct y) | |||
{ | |||
return x._id == y._id; | |||
} | |||
public int GetHashCode(ExclusiveGroupStruct obj) | |||
{ | |||
return _id.GetHashCode(); | |||
} | |||
internal static ExclusiveGroupStruct Generate() | |||
{ | |||
ExclusiveGroupStruct groupStruct; | |||
groupStruct._id = _globalId; | |||
DBC.ECS.Check.Require(_globalId + 1 < ushort.MaxValue, "too many exclusive groups created"); | |||
_globalId++; | |||
return groupStruct; | |||
} | |||
/// <summary> | |||
/// Use this constructor to reserve N groups | |||
/// </summary> | |||
internal ExclusiveGroupStruct(ushort range) | |||
{ | |||
_id = _globalId; | |||
DBC.ECS.Check.Require(_globalId + range < ushort.MaxValue, "too many exclusive groups created"); | |||
_globalId += range; | |||
} | |||
internal ExclusiveGroupStruct(uint groupID) | |||
{ | |||
_id = groupID; | |||
} | |||
public ExclusiveGroupStruct(byte[] data, uint pos) | |||
{ | |||
_id = (uint)( | |||
data[pos++] | |||
| data[pos++] << 8 | |||
| data[pos++] << 16 | |||
| data[pos++] << 24 | |||
); | |||
DBC.ECS.Check.Ensure(_id < _globalId, "Invalid group ID deserialiased"); | |||
} | |||
public static implicit operator uint(ExclusiveGroupStruct groupStruct) | |||
{ | |||
return groupStruct._id; | |||
} | |||
public static ExclusiveGroupStruct operator+(ExclusiveGroupStruct a, uint b) | |||
{ | |||
var group = new ExclusiveGroupStruct(); | |||
group._id = a._id + b; | |||
return group; | |||
} | |||
uint _id; | |||
static uint _globalId; | |||
} | |||
public static ExclusiveGroupStruct Search(string holderGroupName) | |||
{ | |||
if (_serialisedGroups.ContainsKey(holderGroupName) == false) | |||
throw new Exception("Named Group Not Found ".FastConcat(holderGroupName)); | |||
return _serialisedGroups[holderGroupName]; | |||
} | |||
static readonly Dictionary<string, ExclusiveGroupStruct> _serialisedGroups = new Dictionary<string, | |||
ExclusiveGroupStruct>(); | |||
#if DEBUG | |||
readonly ushort _range; | |||
#endif | |||
} | |||
} | |||
#if future | |||
public static void ConstructStaticGroups() | |||
{ | |||
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); | |||
// Assemblies or types aren't guaranteed to be returned in the same order, | |||
// and I couldn't find proof that `GetTypes()` returns them in fixed order either, | |||
// even for builds made with the exact same source code. | |||
// So will sort reflection results by name before constructing groups. | |||
var groupFields = new List<KeyValuePair<string, FieldInfo>>(); | |||
foreach (Assembly assembly in assemblies) | |||
{ | |||
Type[] types = GetTypesSafe(assembly); | |||
foreach (Type type in types) | |||
{ | |||
if (type == null || !type.IsClass) | |||
{ | |||
continue; | |||
} | |||
// Groups defined as static members in static classes | |||
if (type.IsSealed && type.IsAbstract) | |||
{ | |||
FieldInfo[] fields = type.GetFields(); | |||
foreach(var field in fields) | |||
{ | |||
if (field.IsStatic && typeof(ExclusiveGroup).IsAssignableFrom(field.FieldType)) | |||
{ | |||
groupFields.Add(new KeyValuePair<string, FieldInfo>($"{type.FullName}.{field.Name}", field)); | |||
} | |||
} | |||
} | |||
// Groups defined as classes | |||
else if (type.BaseType != null | |||
&& type.BaseType.IsGenericType | |||
&& type.BaseType.GetGenericTypeDefinition() == typeof(ExclusiveGroup<>)) | |||
{ | |||
FieldInfo field = type.GetField("Group", | |||
BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy); | |||
groupFields.Add(new KeyValuePair<string, FieldInfo>(type.FullName, field)); | |||
} | |||
} | |||
} | |||
groupFields.Sort((a, b) => string.CompareOrdinal(a.Key, b.Key)); | |||
for (int i = 0; i < groupFields.Count; ++i) | |||
{ | |||
groupFields[i].Value.GetValue(null); | |||
#if DEBUG | |||
var group = (ExclusiveGroup) groupFields[i].Value.GetValue(null); | |||
groupNames[(uint) group] = groupFields[i].Key; | |||
#endif | |||
} | |||
} | |||
static Type[] GetTypesSafe(Assembly assembly) | |||
{ | |||
try | |||
{ | |||
Type[] types = assembly.GetTypes(); | |||
return types; | |||
} | |||
catch (ReflectionTypeLoadException e) | |||
{ | |||
return e.Types; | |||
} | |||
} | |||
#if DEBUG | |||
static string[] groupNames = new string[ushort.MaxValue]; | |||
#endif | |||
#endif |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 8e5781b2e98b00946971f8e44b2f30be | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,61 +0,0 @@ | |||
using System; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
partial class EntitiesDB | |||
{ | |||
public void ExecuteOnAllEntities<T>(Action<T[], ExclusiveGroup.ExclusiveGroupStruct, uint, IEntitiesDB> action) | |||
where T : struct, IEntityStruct | |||
{ | |||
var type = typeof(T); | |||
if (_groupsPerEntity.TryGetValue(new RefWrapper<Type>(type), out var dictionary)) | |||
{ | |||
foreach (var pair in dictionary) | |||
{ | |||
var entities = (pair.Value as TypeSafeDictionary<T>).GetValuesArray(out var innerCount); | |||
if (innerCount > 0) | |||
action(entities, new ExclusiveGroup.ExclusiveGroupStruct(pair.Key), innerCount, this); | |||
} | |||
} | |||
} | |||
public void ExecuteOnAllEntities | |||
<T, W>(W value, Action<T[], ExclusiveGroup.ExclusiveGroupStruct, uint, IEntitiesDB, W> action) | |||
where T : struct, IEntityStruct | |||
{ | |||
var type = typeof(T); | |||
if (_groupsPerEntity.TryGetValue(new RefWrapper<Type>(type), out var dic)) | |||
{ | |||
foreach (var pair in dic) | |||
{ | |||
var entities = (pair.Value as TypeSafeDictionary<T>).GetValuesArray(out var innerCount); | |||
if (innerCount > 0) | |||
action(entities, new ExclusiveGroup.ExclusiveGroupStruct(pair.Key), innerCount, this, value); | |||
} | |||
} | |||
} | |||
public void ExecuteOnAllEntities | |||
<T, W>(ref W value, ExecuteOnAllEntitiesAction<T, W> action) | |||
where T : struct, IEntityStruct | |||
{ | |||
var type = typeof(T); | |||
if (_groupsPerEntity.TryGetValue(new RefWrapper<Type>(type), out var dic)) | |||
{ | |||
foreach (var pair in dic) | |||
{ | |||
var entities = (pair.Value as TypeSafeDictionary<T>).GetValuesArray(out var innerCount); | |||
if (innerCount > 0) | |||
action(entities, new ExclusiveGroup.ExclusiveGroupStruct(pair.Key), innerCount, this, ref value); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 41fabce3b90aa014bb62d54ab7d21ae1 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,48 +0,0 @@ | |||
using System; | |||
using Svelto.ECS.Serialization; | |||
namespace Svelto.ECS | |||
{ | |||
/// <summary> | |||
/// Inherit from an ExtendibleEntityDescriptor to extend a base entity descriptor that can be used | |||
/// to swap and remove specialized entities from abstract engines | |||
/// </summary> | |||
/// <typeparam name="TType"></typeparam> | |||
public class ExtendibleEntityDescriptor<TType> : IEntityDescriptor where TType : IEntityDescriptor, new() | |||
{ | |||
static ExtendibleEntityDescriptor() | |||
{ | |||
if (typeof(ISerializableEntityDescriptor).IsAssignableFrom(typeof(TType))) | |||
throw new Exception( | |||
$"SerializableEntityDescriptors cannot be used as base entity descriptor: {typeof(TType)}"); | |||
} | |||
public ExtendibleEntityDescriptor(IEntityBuilder[] extraEntities) | |||
{ | |||
_dynamicDescriptor = new DynamicEntityDescriptor<TType>(extraEntities); | |||
} | |||
public ExtendibleEntityDescriptor() | |||
{ | |||
_dynamicDescriptor = new DynamicEntityDescriptor<TType>(true); | |||
} | |||
public ExtendibleEntityDescriptor<TType> ExtendWith<T>() where T : IEntityDescriptor, new() | |||
{ | |||
_dynamicDescriptor.ExtendWith<T>(); | |||
return this; | |||
} | |||
public ExtendibleEntityDescriptor<TType> ExtendWith(IEntityBuilder[] extraEntities) | |||
{ | |||
_dynamicDescriptor.ExtendWith(extraEntities); | |||
return this; | |||
} | |||
public IEntityBuilder[] entitiesToBuild => _dynamicDescriptor.entitiesToBuild; | |||
DynamicEntityDescriptor<TType> _dynamicDescriptor; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 87e1dec70e121e8499d5f7f2ac225394 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,8 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: db3beea83bcdd5e43b03e4014f7854f3 | |||
folderAsset: yes | |||
DefaultImporter: | |||
externalObjects: {} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,8 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: f938e83cfb62e2e47880cdca7f0db7d2 | |||
folderAsset: yes | |||
DefaultImporter: | |||
externalObjects: {} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,24 +0,0 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
using UnityEngine; | |||
namespace Svelto.ECS.Unity | |||
{ | |||
public abstract class GenericEntityDescriptorHolder<T>: | |||
MonoBehaviour , IEntityDescriptorHolder | |||
where T: IEntityDescriptor, new() | |||
{ | |||
public IEntityDescriptor GetDescriptor() | |||
{ | |||
return EntityDescriptorTemplate<T>.descriptor; | |||
} | |||
public string groupName => _groupName; | |||
public ushort id => _id; | |||
#pragma warning disable 649 | |||
[SerializeField] string _groupName; | |||
[SerializeField] ushort _id; | |||
#pragma warning restore 649 | |||
} | |||
} | |||
#endif |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 868c4160bf062904793f49af221b1178 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,99 +0,0 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
using UnityEngine; | |||
namespace Svelto.ECS.Unity | |||
{ | |||
public static class SveltoGUIHelper | |||
{ | |||
public static T CreateFromPrefab<T>(ref uint startIndex, Transform contextHolder, IEntityFactory factory, | |||
ExclusiveGroup group, string groupNamePostfix = null) where T : MonoBehaviour, IEntityDescriptorHolder | |||
{ | |||
var holder = Create<T>(new EGID(startIndex++, group), contextHolder, factory); | |||
var childs = contextHolder.GetComponentsInChildren<IEntityDescriptorHolder>(true); | |||
foreach (var child in childs) | |||
{ | |||
if (child.GetType() != typeof(T)) | |||
{ | |||
var monoBehaviour = child as MonoBehaviour; | |||
var childImplementors = monoBehaviour.GetComponents<IImplementor>(); | |||
startIndex = InternalBuildAll( | |||
startIndex, | |||
child, | |||
factory, | |||
group, | |||
childImplementors, | |||
groupNamePostfix); | |||
} | |||
} | |||
return holder; | |||
} | |||
public static T Create<T>(EGID ID, Transform contextHolder, IEntityFactory factory) | |||
where T : MonoBehaviour, IEntityDescriptorHolder | |||
{ | |||
var holder = contextHolder.GetComponentInChildren<T>(true); | |||
DBC.ECS.Check.Assert(holder != null, $"`{nameof(holder)}` is null! No component of type " + | |||
$"`{typeof(T)}` was found between its children."); | |||
var implementors = holder.GetComponents<IImplementor>(); | |||
factory.BuildEntity(ID, holder.GetDescriptor(), implementors); | |||
return holder; | |||
} | |||
public static EntityStructInitializer CreateWithEntity<T>(EGID ID, Transform contextHolder, | |||
IEntityFactory factory, out T holder) | |||
where T : MonoBehaviour, IEntityDescriptorHolder | |||
{ | |||
holder = contextHolder.GetComponentInChildren<T>(true); | |||
var implementors = holder.GetComponents<IImplementor>(); | |||
return factory.BuildEntity(ID, holder.GetDescriptor(), implementors); | |||
} | |||
public static uint CreateAll<T>(uint startIndex, ExclusiveGroup group, | |||
Transform contextHolder, IEntityFactory factory, string groupNamePostfix = null) where T : MonoBehaviour, IEntityDescriptorHolder | |||
{ | |||
var holders = contextHolder.GetComponentsInChildren<T>(true); | |||
foreach (var holder in holders) | |||
{ | |||
var implementors = holder.GetComponents<IImplementor>(); | |||
startIndex = InternalBuildAll(startIndex, holder, factory, group, implementors, groupNamePostfix); | |||
} | |||
return startIndex; | |||
} | |||
static uint InternalBuildAll(uint startIndex, IEntityDescriptorHolder descriptorHolder, | |||
IEntityFactory factory, ExclusiveGroup group, IImplementor[] implementors, string groupNamePostfix) | |||
{ | |||
ExclusiveGroup.ExclusiveGroupStruct realGroup = group; | |||
if (string.IsNullOrEmpty(descriptorHolder.groupName) == false) | |||
{ | |||
realGroup = ExclusiveGroup.Search(!string.IsNullOrEmpty(groupNamePostfix) | |||
? $"{descriptorHolder.groupName}{groupNamePostfix}" | |||
: descriptorHolder.groupName); | |||
} | |||
EGID egid; | |||
var holderId = descriptorHolder.id; | |||
if (holderId == 0) | |||
egid = new EGID(startIndex++, realGroup); | |||
else | |||
egid = new EGID(holderId, realGroup); | |||
var init = factory.BuildEntity(egid, descriptorHolder.GetDescriptor(), implementors); | |||
init.Init(new EntityHierarchyStruct(group)); | |||
return startIndex; | |||
} | |||
} | |||
} | |||
#endif |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 8dcc6bf8a648e51428a0a4c300dc0457 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,66 +0,0 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
using Object = UnityEngine.Object; | |||
using System; | |||
using System.Collections; | |||
using UnityEngine; | |||
namespace Svelto.ECS.Schedulers.Unity | |||
{ | |||
//The EntitySubmissionScheduler has been introduced to make the entity views submission logic platform independent | |||
//You can customize the scheduler if you wish | |||
public class UnityEntitySubmissionScheduler : IEntitySubmissionScheduler | |||
{ | |||
class Scheduler : MonoBehaviour | |||
{ | |||
public Scheduler() | |||
{ | |||
_coroutine = Coroutine(); | |||
} | |||
void Update() | |||
{ | |||
_coroutine.MoveNext(); | |||
} | |||
IEnumerator Coroutine() | |||
{ | |||
while (true) | |||
{ | |||
yield return _wait; | |||
onTick.Invoke(); | |||
} | |||
} | |||
readonly WaitForEndOfFrame _wait = new WaitForEndOfFrame(); | |||
readonly IEnumerator _coroutine; | |||
public EnginesRoot.EntitiesSubmitter onTick; | |||
} | |||
public UnityEntitySubmissionScheduler(string name = "ECSScheduler") { _name = name; } | |||
public void Dispose() | |||
{ | |||
Object.Destroy(_scheduler.gameObject); | |||
} | |||
public EnginesRoot.EntitiesSubmitter onTick | |||
{ | |||
set | |||
{ | |||
if (_scheduler == null) | |||
{ | |||
_scheduler = new GameObject(_name).AddComponent<Scheduler>(); | |||
GameObject.DontDestroyOnLoad(_scheduler.gameObject); | |||
} | |||
_scheduler.onTick = value; | |||
} | |||
} | |||
Scheduler _scheduler; | |||
readonly string _name; | |||
} | |||
} | |||
#endif |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 8f3708168c40939408e5d0f10a9e0fb5 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,104 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class GenericEntityDescriptor<T> : IEntityDescriptor where T : struct, IEntityStruct | |||
{ | |||
static readonly IEntityBuilder[] _entityBuilders; | |||
static GenericEntityDescriptor() { _entityBuilders = new IEntityBuilder[] {new EntityBuilder<T>()}; } | |||
public IEntityBuilder[] entitiesToBuild => _entityBuilders; | |||
} | |||
public abstract class GenericEntityDescriptor<T, U> : IEntityDescriptor | |||
where T : struct, IEntityStruct where U : struct, IEntityStruct | |||
{ | |||
static readonly IEntityBuilder[] _entityBuilders; | |||
static GenericEntityDescriptor() | |||
{ | |||
_entityBuilders = new IEntityBuilder[] {new EntityBuilder<T>(), new EntityBuilder<U>()}; | |||
} | |||
public IEntityBuilder[] entitiesToBuild => _entityBuilders; | |||
} | |||
public abstract class GenericEntityDescriptor<T, U, V> : IEntityDescriptor | |||
where T : struct, IEntityStruct where U : struct, IEntityStruct where V : struct, IEntityStruct | |||
{ | |||
static readonly IEntityBuilder[] _entityBuilders; | |||
static GenericEntityDescriptor() | |||
{ | |||
_entityBuilders = new IEntityBuilder[] | |||
{ | |||
new EntityBuilder<T>(), | |||
new EntityBuilder<U>(), | |||
new EntityBuilder<V>() | |||
}; | |||
} | |||
public IEntityBuilder[] entitiesToBuild => _entityBuilders; | |||
} | |||
public abstract class GenericEntityDescriptor<T, U, V, W> : IEntityDescriptor | |||
where T : struct, IEntityStruct where U : struct, IEntityStruct where V : struct, IEntityStruct | |||
where W : struct, IEntityStruct | |||
{ | |||
static readonly IEntityBuilder[] _entityBuilders; | |||
static GenericEntityDescriptor() | |||
{ | |||
_entityBuilders = new IEntityBuilder[] | |||
{ | |||
new EntityBuilder<T>(), | |||
new EntityBuilder<U>(), | |||
new EntityBuilder<V>(), | |||
new EntityBuilder<W>() | |||
}; | |||
} | |||
public IEntityBuilder[] entitiesToBuild => _entityBuilders; | |||
} | |||
public abstract class GenericEntityDescriptor<T, U, V, W, X> : IEntityDescriptor | |||
where T : struct, IEntityStruct where U : struct, IEntityStruct where V : struct, IEntityStruct | |||
where W : struct, IEntityStruct where X : struct, IEntityStruct | |||
{ | |||
static readonly IEntityBuilder[] _entityBuilders; | |||
static GenericEntityDescriptor() | |||
{ | |||
_entityBuilders = new IEntityBuilder[] | |||
{ | |||
new EntityBuilder<T>(), | |||
new EntityBuilder<U>(), | |||
new EntityBuilder<V>(), | |||
new EntityBuilder<W>(), | |||
new EntityBuilder<X>() | |||
}; | |||
} | |||
public IEntityBuilder[] entitiesToBuild => _entityBuilders; | |||
} | |||
public abstract class GenericEntityDescriptor<T, U, V, W, X, Y> : IEntityDescriptor | |||
where T : struct, IEntityStruct where U : struct, IEntityStruct where V : struct, IEntityStruct | |||
where W : struct, IEntityStruct where X : struct, IEntityStruct where Y : struct, IEntityStruct | |||
{ | |||
static readonly IEntityBuilder[] _entityBuilders; | |||
static GenericEntityDescriptor() | |||
{ | |||
_entityBuilders = new IEntityBuilder[] | |||
{ | |||
new EntityBuilder<T>(), | |||
new EntityBuilder<U>(), | |||
new EntityBuilder<V>(), | |||
new EntityBuilder<W>(), | |||
new EntityBuilder<X>(), | |||
new EntityBuilder<Y>() | |||
}; | |||
} | |||
public IEntityBuilder[] entitiesToBuild => _entityBuilders; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 73d7a47d7c041014c8e4cdc0c90a0671 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,33 +0,0 @@ | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
class GenericEntityStreamConsumerFactory : IEntityStreamConsumerFactory | |||
{ | |||
public GenericEntityStreamConsumerFactory(EnginesRoot weakReference) | |||
{ | |||
_enginesRoot = new WeakReference<EnginesRoot>(weakReference); | |||
} | |||
public Consumer<T> GenerateConsumer<T>(string name, uint capacity) where T : unmanaged, IEntityStruct | |||
{ | |||
return _enginesRoot.Target.GenerateConsumer<T>(name, capacity); | |||
} | |||
public Consumer<T> GenerateConsumer<T>(ExclusiveGroup group, string name, uint capacity) where T : unmanaged, IEntityStruct | |||
{ | |||
return _enginesRoot.Target.GenerateConsumer<T>(group, name, capacity); | |||
} | |||
//enginesRoot is a weakreference because GenericEntityStreamConsumerFactory can be injected inside | |||
//engines of other enginesRoot | |||
readonly WeakReference<EnginesRoot> _enginesRoot; | |||
} | |||
public interface IEntityStreamConsumerFactory | |||
{ | |||
Consumer<T> GenerateConsumer<T>(string name, uint capacity) where T : unmanaged, IEntityStruct; | |||
Consumer<T> GenerateConsumer<T>(ExclusiveGroup group, string name, uint capacity) | |||
where T : unmanaged, IEntityStruct; | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 02c9be62e6bdb9a49aa9596249bb16b1 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,8 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: e4a4259b54484b04ace0e48754701671 | |||
folderAsset: yes | |||
DefaultImporter: | |||
externalObjects: {} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,6 +0,0 @@ | |||
namespace Svelto.ECS.Hybrid | |||
{ | |||
public interface IEntityViewStruct:IEntityStruct, INeedEGID | |||
{} | |||
} | |||
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: ce31f0fb3a7e1554bb6f3a31128f2bc4 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,6 +0,0 @@ | |||
namespace Svelto.ECS.Unity | |||
{ | |||
public interface IImplementor | |||
{ | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: 6f0dfd0f03d543e469f9c04c79e343be | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -1,17 +0,0 @@ | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public interface IReactEngine: IEngine | |||
{} | |||
public interface IReactOnAddAndRemove : IReactEngine | |||
{} | |||
public interface IReactOnSwap : IReactEngine | |||
{} | |||
} | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEngine | |||
{} | |||
} |
@@ -1,11 +0,0 @@ | |||
fileFormatVersion: 2 | |||
guid: fd83d8a0efbd6f54c89b86f87e1fe8f7 | |||
MonoImporter: | |||
externalObjects: {} | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |