Skip to content

Commit

Permalink
+ removed some useless Exists check
Browse files Browse the repository at this point in the history
+ identifier now contains data
+ adddeferred
  • Loading branch information
andreakarasho committed Jul 21, 2024
1 parent e5ff811 commit 5745fe2
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 59 deletions.
18 changes: 14 additions & 4 deletions src/Default.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,32 @@ public static class Defaults
/// <summary>
/// Wildcard is used to specify "any component/tag".<br/>It's mostly used for queries.
/// </summary>
public struct Wildcard { public static EcsID ID = Lookup.Component<Wildcard>.Value.ID; }
public readonly struct Wildcard { public static readonly EcsID ID = Lookup.Component<Wildcard>.Value.ID; }

/// <summary>
/// Built-in tag.<br/>Shortcut for child.Add{ChildOf}(parent);
/// </summary>
public struct ChildOf { }

/// <summary>
/// Built-in tag.<br/>Used in combination with <see cref="Name"/>
/// Built-in component.<br/>Used in combination with <see cref="Name"/>
/// </summary>
public struct Identifier { }
public readonly struct Identifier
{
public static readonly EcsID ID = Lookup.Component<Identifier>.Value.ID;

public Identifier(string name) => Data = name;

public readonly string Data;
}

/// <summary>
/// Built-in tag.<br/>Used in combination with <see cref="Identifier"/>
/// </summary>
public readonly struct Name { internal Name(string value) => Value = value; public readonly string Value; }
public readonly struct Name
{
public static readonly EcsID ID = Lookup.Component<Name>.Value.ID;
}

/// <summary>
/// Built-in tag.<br/>Used to make a component/tag unique when adding a Pair.<para/>
Expand Down
2 changes: 1 addition & 1 deletion src/World.Deferred.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void EndDeferred()
}


private void SetDeferred<T>(EcsID entity) where T : struct
private void AddDeferred<T>(EcsID entity) where T : struct
{
ref readonly var cmp = ref Component<T>();

Expand Down
64 changes: 37 additions & 27 deletions src/World.Public.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public World(ulong maxComponentId = 256)
setCommon(Entity<Unset>(), nameof(Unset));

static EntityView setCommon(EntityView entity, string name)
=> entity.Add<DoNotDelete>().Set<Identifier, Name>(new (name));
=> entity.Add<DoNotDelete>().Set<Identifier>(new (name), Defaults.Name.ID);

OnPluginInitialization?.Invoke(this);
}
Expand Down Expand Up @@ -88,12 +88,12 @@ public void Dispose()
_archRoot.Clear();
_typeIndex.Clear();
_cachedComponents.Clear();
_names.Clear();

foreach (var query in _cachedQueries.Values)
query.Dispose();

_cachedQueries.Clear();
_namesToEntity.Clear();
Archetypes.Clear();
}

Expand Down Expand Up @@ -185,25 +185,22 @@ public EntityView Entity<T>() where T : struct
{
ref readonly var cmp = ref Component<T>();

var entity = Entity(cmp.ID);
if (entity.ID.IsPair())
return entity;
var entId = cmp.ID;

var name = Lookup.Component<T>.Name;

if (_namesToEntity.TryGetValue(name, out var id))
{
if (entity.ID != id)
EcsAssert.Panic(false, $"You must declare the component before the entity '{id}' named '{name}'");
}
else
if (!entId.IsPair())
{
_namesToEntity[name] = entity;
entity.Set<Identifier, Name>(new (name));
GetRecord(entity).Flags |= EntityFlags.IsUnique;
ref var record = ref GetRecord(entId);

if ((record.Flags & EntityFlags.HasName) == 0)
{
record.Flags |= EntityFlags.HasName;
var name = Lookup.Component<T>.Name;
_names[name] = entId;
Set<Identifier>(entId, new (name), Defaults.Name.ID);
}
}

return entity;
return new EntityView(this, entId);
}

/// <summary>
Expand All @@ -214,20 +211,20 @@ public EntityView Entity<T>() where T : struct
/// <returns></returns>
public EntityView Entity(string name)
{
if (string.IsNullOrEmpty(name))
if (string.IsNullOrWhiteSpace(name))
return EntityView.Invalid;

EntityView entity;
if (_namesToEntity.TryGetValue(name, out var id))
if (_names.TryGetValue(name, out var id) && (GetRecord(id).Flags & EntityFlags.HasName) != 0)
{
entity = Entity(id);
}
else
{
entity = Entity();
_namesToEntity[name] = entity;
entity.Set<Identifier, Name>(new (name));
GetRecord(entity).Flags |= EntityFlags.IsUnique;
GetRecord(entity).Flags |= EntityFlags.HasName;
_names[name] = entity;
entity.Set<Identifier>(new (name), Defaults.Name.ID);
}

return entity;
Expand Down Expand Up @@ -258,12 +255,12 @@ public void Delete(EcsID entity)

if (record.Flags != EntityFlags.None)
{
if ((record.Flags & EntityFlags.IsUnique) != 0)
if ((record.Flags & EntityFlags.HasName) != 0)
{
if (Has<Identifier, Name>(entity))
{
var name = Get<Identifier, Name>(entity).Value;
_namesToEntity.Remove(name, out var _);
var name = Get<Identifier>(entity, Defaults.Name.ID).Data;
_names.Remove(name, out var _);
}
}

Expand Down Expand Up @@ -371,7 +368,7 @@ public void Add<T>(EcsID entity) where T : struct

if (IsDeferred && !Has(entity, cmp.ID))
{
SetDeferred<T>(entity);
AddDeferred<T>(entity);

return;
}
Expand Down Expand Up @@ -451,7 +448,7 @@ public void Unset(EcsID entity, EcsID id)
/// <param name="entity"></param>
/// <returns></returns>
public bool Has<T>(EcsID entity) where T : struct
=> Exists(entity) && Has(entity, Component<T>().ID);
=> Has(entity, Component<T>().ID);

/// <summary>
/// Check if the entity has a component or tag.<br/>
Expand Down Expand Up @@ -488,6 +485,19 @@ public ref T Get<T>(EcsID entity) where T : struct
return ref GetUntrusted<T>(entity, cmp.ID, cmp.Size);
}

/// <summary>
/// Get the name associated to the entity.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public string Name(EcsID id)
{
ref var record = ref GetRecord(id);
if ((record.Flags & EntityFlags.HasName) != 0)
return Get<Identifier>(id, Defaults.Name.ID).Data;
return string.Empty;
}

/// <summary>
/// Print the archetype graph.
/// </summary>
Expand Down
36 changes: 15 additions & 21 deletions src/World.Relationship.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,21 @@ private ref readonly ComponentInfo Hack<TAction, TTarget>()

private void CheckUnique(EcsID entity, EcsID action)
{
if (Exists(action))
// only one (A, *)
if (Entity(action).Has<Unique>())
{
// only one (A, *)
if (Entity(action).Has<Unique>())
var targetId = Target(entity, action);
if (targetId != 0)
{
var targetId = Target(entity, action);
if (targetId != 0)
{
Unset(entity, action, targetId);
}
Unset(entity, action, targetId);
}
}
}

private void CheckSymmetric(EcsID entity, EcsID action, EcsID target)
{
// (R, B) to A will also add (R, A) to B.
if (Exists(action) && Entity(action).Has<Symmetric>() && !Has(target, action, entity))
if (Entity(action).Has<Symmetric>() && !Has(target, action, entity))
{
var pairId = IDOp.Pair(action, entity);

Expand Down Expand Up @@ -120,12 +117,12 @@ public void Add<TAction>(EcsID entity, EcsID target)

if (IsDeferred && !Has(entity, act.ID, target))
{
SetDeferred(entity, pairId);
SetDeferred(entity, pairId, null, 0, false);

return;
}

_ = AttachComponent(entity, pairId, act.Size, act.IsManaged);
_ = AttachComponent(entity, pairId, 0, false);
}

/// <summary>
Expand All @@ -149,7 +146,7 @@ public void Set<TAction>(EcsID entity, TAction action, EcsID target)

if (IsDeferred && !Has(entity, act.ID, target))
{
SetDeferred(entity, pairId);
SetDeferred(entity, pairId, action, act.Size, act.IsManaged);

return;
}
Expand Down Expand Up @@ -251,7 +248,7 @@ public bool Has<TAction>(EcsID entity, EcsID target)
public bool Has(EcsID entity, EcsID action, EcsID target)
{
var pairId = IDOp.Pair(action, target);
return Exists(entity) && Has(entity, pairId);
return Has(entity, pairId);
}

/// <summary>
Expand All @@ -265,8 +262,10 @@ public void Unset<TAction, TTarget>(EcsID entity)
where TAction : struct
where TTarget : struct
{
ref readonly var linkedCmp = ref Hack<TAction, TTarget>();
Unset<Relation<TAction, TTarget>>(entity);
var first = Component<TAction>().ID;
var second = Component<TTarget>().ID;
var pairId = IDOp.Pair(first, second);
Unset(entity, pairId);
}

/// <summary>
Expand Down Expand Up @@ -557,12 +556,7 @@ public static class NameEx
/// <returns></returns>
public static string Name(this EntityView entity)
{
if (entity.Has<Identifier, Name>())
{
return entity.Get<Identifier, Name>().Value;
}

return entity.ID.ToString();
return entity.World.Name(entity.ID);
}
}

Expand Down
24 changes: 18 additions & 6 deletions src/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ public sealed partial class World : IDisposable
internal delegate Query QueryFactoryDel(World world, ReadOnlySpan<IQueryTerm> terms);

private readonly Archetype _archRoot;
private readonly EntitySparseSet<EcsRecord> _entities = new();
private readonly FastIdLookup<Archetype> _typeIndex = new();
private readonly EntitySparseSet<EcsRecord> _entities = new ();
private readonly FastIdLookup<Archetype> _typeIndex = new ();
private readonly ComponentComparer _comparer;
private readonly EcsID _maxCmpId;
private readonly Dictionary<EcsID, Query> _cachedQueries = new ();
private readonly object _newEntLock = new object();
private readonly ConcurrentDictionary<string, EcsID> _namesToEntity = new ();
private readonly FastIdLookup<EcsID> _cachedComponents = new ();
private readonly ComponentInfo[] _cache = new ComponentInfo[1024];
private readonly Dictionary<string, EcsID> _names = new ();
private readonly object _newEntLock = new ();

private static readonly Comparison<ComponentInfo> _comparisonCmps = (a, b)
=> ComponentComparer.CompareTerms(null!, a.ID, b.ID);
Expand Down Expand Up @@ -111,10 +110,21 @@ private void DetachComponent(EcsID entity, EcsID id)
if (id.IsPair())
{
(var first, var second) = id.Pair();
if ((record.Flags & EntityFlags.HasName) != 0)
{
if (first == Defaults.Identifier.ID && second == Defaults.Name.ID)
{


record.Flags &= ~EntityFlags.HasName;
}
}

GetRecord(GetAlive(first)).Flags &= ~EntityFlags.IsAction;
GetRecord(GetAlive(second)).Flags &= ~EntityFlags.IsTarget;
}


OnComponentUnset?.Invoke(record.EntityView(), new ComponentInfo(id, -1, false));

BeginDeferred();
Expand Down Expand Up @@ -273,5 +283,7 @@ enum EntityFlags
None = 1 << 0,
IsAction = 1 << 1,
IsTarget = 1 << 2,
IsUnique = 1 << 3
IsUnique = 1 << 3,
IsSymmetric = 1 << 4,
HasName = 1 << 5
}
17 changes: 17 additions & 0 deletions tests/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,23 @@ public void Declare_NamedEntity_Before_Tag()
Assert.Equal(ctx.World.Entity<NormalTag>(), a);
}

[Fact]
public void Entity_Name()
{
using var ctx = new Context();

var a = ctx.World.Entity("a");
Assert.Equal("a", a.Name());

a.Unset<Defaults.Identifier, Defaults.Name>();
Assert.Equal("", a.Name());

var aa = ctx.World.Entity("a");
Assert.True(a.ID != aa.ID);

Assert.Equal("a", aa.Name());
}

[Fact]
public void Entity_Has_Wildcard()
{
Expand Down

0 comments on commit 5745fe2

Please sign in to comment.