Skip to content

Commit

Permalink
create entity deferred op
Browse files Browse the repository at this point in the history
  • Loading branch information
andreakarasho committed Apr 17, 2024
1 parent ef9aa57 commit dadcc35
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 16 deletions.
23 changes: 23 additions & 0 deletions src/World.Deferred.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace TinyEcs;
public sealed partial class World
{
private readonly ConcurrentQueue<DeferredOp> _operations = new();
private readonly ConcurrentDictionary<EcsID, EcsID> _createdEntities = new();
private readonly ConcurrentDictionary<EcsID, DictionarySlim<EcsID, object?>> _deferredSets = new();
private WorldState _worldState = new () { State = WorldStateTypes.Normal, Locks = 0 };
private readonly object _worldStateLock = new object();
Expand Down Expand Up @@ -144,6 +145,19 @@ private void UnsetDeferred(EcsID entity, EcsID id)
}
}

private void CreateDeferred(EcsID entity)
{
var cmd = new DeferredOp()
{
Op = DeferredOpTypes.CreateEntity,
Entity = entity,
};

_operations.Enqueue(cmd);

_createdEntities[entity] = entity;
}

private void DeleteDeferred(EcsID entity)
{
var cmd = new DeferredOp()
Expand All @@ -160,6 +174,10 @@ private void DeleteDeferred(EcsID entity)
}
}

private bool ExistsDeferred(EcsID entity)
=> entity.IsPair ? _createdEntities.ContainsKey(entity.First) &&
_createdEntities.ContainsKey(entity.Second) : _createdEntities.ContainsKey(entity);

private bool HasDeferred<T>(EcsID entity) where T : struct
=> _deferredSets.TryGetValue(entity, out var dict) && dict.ContainsKey(Component<T>().ID);

Expand Down Expand Up @@ -196,6 +214,9 @@ private void Merge()
{
switch (op.Op)
{
case DeferredOpTypes.CreateEntity:
var ent = Entity(op.Entity);
break;
case DeferredOpTypes.DestroyEntity:
Delete(op.Entity);
break;
Expand Down Expand Up @@ -231,6 +252,7 @@ private void Merge()
}

_deferredSets.Clear();
_createdEntities.Clear();
}

enum WorldStateTypes
Expand All @@ -256,6 +278,7 @@ struct DeferredOp

enum DeferredOpTypes : byte
{
CreateEntity,
DestroyEntity,
SetComponent,
UnsetComponent,
Expand Down
11 changes: 11 additions & 0 deletions src/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ internal EntityView NewEmpty(ulong id = 0)
{
lock (_newEntLock)
{
if (IsDeferred)
{
if (id == 0)
id = ++_entities.MaxID;
CreateDeferred(id);
return new EntityView(this, id);
}

ref var record = ref (
id > 0 ? ref _entities.Add(id, default!) : ref _entities.CreateNew(out id)
);
Expand Down Expand Up @@ -203,6 +211,9 @@ public void Delete(EcsID entity)

public bool Exists(EcsID entity)
{
if (IsDeferred && ExistsDeferred(entity))
return true;

if (entity.IsPair)
{
return _entities.Contains(entity.First) && _entities.Contains(entity.Second);
Expand Down
31 changes: 15 additions & 16 deletions tests/Deferred.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ namespace TinyEcs.Tests
{
public class DeferredTest
{
struct JustForTest { }

[Fact]
public void Deferred_CheckWorldState()
{
Expand All @@ -12,31 +14,28 @@ public void Deferred_CheckWorldState()
Assert.False(ctx.World.IsDeferred);
}

[Theory]
[InlineData(1_000)]
[InlineData(1_000_00)]
[InlineData(1_000_000)]
public void Deferred_NewEntity(int amount)
[Fact]
public void Deferred_NewEntity()
{
using var ctx = new Context();

var count = ctx.World.EntityCount;
var expected = count + amount * 2;

var t0 = new Thread(() => { for (var i = 0; i < amount; ++i) ctx.World.Entity(); })
{ IsBackground = true };
var t1 = new Thread(() => { for (var i = 0; i < amount; ++i) ctx.World.Entity(); })
{ IsBackground = true };

ctx.World.BeginDeferred();
t0.Start();
t1.Start();
var e0 = ctx.World.Entity("An entity");
var e1 = ctx.World.Entity();
var e2 = ctx.World.Entity<JustForTest>();

t0.Join();
t1.Join();
Assert.True(e0.Exists());
Assert.True(e1.Exists());
Assert.True(e2.Exists());
ctx.World.EndDeferred();

Assert.Equal(expected, ctx.World.EntityCount);
Assert.True(e0.Exists());
Assert.True(e1.Exists());
Assert.True(e2.Exists());

Assert.Equal(count + 3, ctx.World.EntityCount);
}

[Fact]
Expand Down

0 comments on commit dadcc35

Please sign in to comment.