Skip to content

Commit

Permalink
Engine - ECS: moved entityScripts, entityScriptCount & scriptMap to E…
Browse files Browse the repository at this point in the history
…ntityStore.Internals
  • Loading branch information
friflo committed May 26, 2024
1 parent d503deb commit 835838f
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 51 deletions.
6 changes: 3 additions & 3 deletions Engine/Tests-internal/ECS/Test_Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,17 +184,17 @@ public static void Test_Entity_delete_with_Script()

AreEqual(1, entity1.Scripts.Length);
AreEqual(1, store.EntityScripts.Length);
AreEqual(1, store.scriptMap.Count);
AreEqual(1, store.internals.scriptMap.Count);

var script2 = new TestScript2();
entity2.AddScript(script2);

AreEqual(1, entity2.Scripts.Length);
AreEqual(2, store.EntityScripts.Length);
AreEqual(2, store.scriptMap.Count);
AreEqual(2, store.internals.scriptMap.Count);

entity1.DeleteEntity();
AreEqual(1, store.scriptMap.Count);
AreEqual(1, store.internals.scriptMap.Count);
AreEqual(1, store.EntityScripts.Length);
AreSame (script2, store.EntityScripts[0].scripts[0]);
}
Expand Down
2 changes: 1 addition & 1 deletion Engine/Tests-internal/ECS/Test_EntityStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static void Test_EntityStore_RemoveScript() {
var store = new EntityStore(PidType.RandomPids);
var entity = store.CreateEntity();
entity.AddScript(new TestScript1());
store.SetInternalField("entityScriptCount", 1);
store.internals.entityScriptCount = 1;

var e = Throws<InvalidOperationException>(() => {
entity.RemoveScript<TestScript1>();
Expand Down
8 changes: 4 additions & 4 deletions Engine/src/ECS/Entity/EntityUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,15 +196,15 @@ internal static string DataEntityToJSON(DataEntity dataEntity)
private static readonly Dictionary<Type, ScriptType> ScriptTypeByType = EntityStoreBase.Static.EntitySchema.scriptTypeByType;

internal static Script[] GetScripts(Entity entity) {
if (!entity.store.scriptMap.TryGetValue(entity.Id, out int scriptIndex)) {
if (!entity.store.internals.scriptMap.TryGetValue(entity.Id, out int scriptIndex)) {
return EmptyScripts;
}
return EntityStore.GetScripts(entity, scriptIndex);
}

internal static Script GetScript(Entity entity, Type scriptType)
{
if (!entity.store.scriptMap.TryGetValue(entity.Id, out int scriptIndex)) {
if (!entity.store.internals.scriptMap.TryGetValue(entity.Id, out int scriptIndex)) {
return null;
}
return EntityStore.GetScript(entity, scriptType, scriptIndex);
Expand Down Expand Up @@ -236,15 +236,15 @@ private static Script AddScriptInternal(Entity entity, Script script, ScriptTyp
}

internal static Script RemoveScript(Entity entity, int scriptTypeIndex) {
if (!entity.store.scriptMap.TryGetValue(entity.Id, out int scriptIndex)) {
if (!entity.store.internals.scriptMap.TryGetValue(entity.Id, out int scriptIndex)) {
return null;
}
var scriptType = ScriptTypes[scriptTypeIndex];
return entity.archetype.entityStore.RemoveScript(entity, scriptType, scriptIndex);
}

private static Script RemoveScriptType(Entity entity, ScriptType scriptType) {
if (!entity.store.scriptMap.TryGetValue(entity.Id, out int scriptIndex)) {
if (!entity.store.internals.scriptMap.TryGetValue(entity.Id, out int scriptIndex)) {
return null;
}
return entity.archetype.entityStore.RemoveScript(entity, scriptType, scriptIndex);
Expand Down
10 changes: 5 additions & 5 deletions Engine/src/ECS/Entity/Store/NodeTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ internal void DeleteNode(Entity entity)
internals.id2Pid.Remove(id);
internals.pid2Id.Remove(pid);
}
if (scriptMap.Remove(id)) {
if (internals.scriptMap.Remove(id)) {
RemoveEntityScript(id);
}
// --- remove child from parent
Expand All @@ -596,15 +596,15 @@ internal void DeleteNode(Entity entity)

private void RemoveEntityScript(int id)
{
var scripts = entityScripts;
int len = entityScriptCount - 1;
var scripts = internals.entityScripts;
int len = internals.entityScriptCount - 1;
for (int n = 1; n <= len; n++) {
if (scripts[n].id != id) continue;
for (; n < len; n++) {
scripts[n] = scripts[n + 1];
}
entityScriptCount = len;
scripts[len] = default;
internals.entityScriptCount = len;
scripts[len] = default;
break;
}
}
Expand Down
46 changes: 23 additions & 23 deletions Engine/src/ECS/Entity/Store/Scripts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ public partial class EntityStore
{
// --------------------------------- script methods ---------------------------------
internal static Script[] GetScripts(Entity entity, int scriptIndex) {
return entity.store.entityScripts[scriptIndex].scripts;
return entity.store.internals.entityScripts[scriptIndex].scripts;
}

internal static Script GetScript(Entity entity, Type scriptType, int scriptIndex)
{
var scripts = entity.store.entityScripts[scriptIndex].scripts;
var scripts = entity.store.internals.entityScripts[scriptIndex].scripts;
foreach (var script in scripts) {
if (script.GetType() == scriptType) {
return script;
Expand All @@ -28,18 +28,18 @@ internal static Script GetScript(Entity entity, Type scriptType, int scriptIndex
internal void AppendScript(Entity entity, Script script)
{
script.entity = entity;
if (!entity.store.scriptMap.TryGetValue(entity.Id, out int scriptIndex)) {
if (!entity.store.internals.scriptMap.TryGetValue(entity.Id, out int scriptIndex)) {
// case: entity has not scripts => add new Scripts entry
var lastIndex = entityScriptCount++;
scriptMap.Add(entity.Id, lastIndex);
if (entityScripts.Length == lastIndex) {
var lastIndex = internals.entityScriptCount++;
internals.scriptMap.Add(entity.Id, lastIndex);
if (internals.entityScripts.Length == lastIndex) {
var newLength = Math.Max(1, 2 * lastIndex);
ArrayUtils.Resize(ref entityScripts, newLength);
ArrayUtils.Resize(ref internals.entityScripts, newLength);
}
entityScripts[lastIndex] = new EntityScripts(entity.Id, new Script[] { script });
internals.entityScripts[lastIndex] = new EntityScripts(entity.Id, new Script[] { script });
} else {
// case: entity already has scripts => add script to its scripts
ref var scripts = ref entityScripts[scriptIndex].scripts;
ref var scripts = ref internals.entityScripts[scriptIndex].scripts;
var len = scripts.Length;
ArrayUtils.Resize(ref scripts, len + 1);
scripts[len] = script;
Expand Down Expand Up @@ -68,23 +68,23 @@ internal Script AddScript(Entity entity, Script script, ScriptType scriptType)
Script currentScript;
ScriptChangedAction action;
script.entity = entity;
if (!scriptMap.TryGetValue(entity.Id, out int scriptIndex))
if (!internals.scriptMap.TryGetValue(entity.Id, out int scriptIndex))
{
// case: entity has not scripts => add new Scripts entry
action = ScriptChangedAction.Add;
var lastIndex = entityScriptCount++;
scriptMap.Add(entity.Id, lastIndex);
if (entityScripts.Length == lastIndex) {
var lastIndex = internals.entityScriptCount++;
internals.scriptMap.Add(entity.Id, lastIndex);
if (internals.entityScripts.Length == lastIndex) {
var newLength = Math.Max(1, 2 * lastIndex);
ArrayUtils.Resize(ref entityScripts, newLength);
ArrayUtils.Resize(ref internals.entityScripts, newLength);
}
entityScripts[lastIndex] = new EntityScripts(entity.Id, new Script [] { script });
internals.entityScripts[lastIndex] = new EntityScripts(entity.Id, new Script [] { script });
currentScript = null;
goto SendEvent;
}
// case: entity has already scripts => add / replace script to / in scripts
action = ScriptChangedAction.Replace;
ref var entityScript = ref entityScripts[scriptIndex];
ref var entityScript = ref internals.entityScripts[scriptIndex];
var scripts = entityScript.scripts;
var len = scripts.Length;
for (int n = 0; n < len; n++)
Expand Down Expand Up @@ -114,7 +114,7 @@ internal Script AddScript(Entity entity, Script script, ScriptType scriptType)

internal Script RemoveScript(Entity entity, ScriptType scriptType, int scriptIndex)
{
ref var entityScript = ref entityScripts[scriptIndex];
ref var entityScript = ref internals.entityScripts[scriptIndex];
var scripts = entityScript.scripts;
var len = scripts.Length;
for (int n = 0; n < len; n++)
Expand All @@ -127,17 +127,17 @@ internal Script RemoveScript(Entity entity, ScriptType scriptType, int scriptInd
script.entity = default;
if (len == 1) {
// case: script is the only one attached to the entity => remove complete scripts entry
var lastIndex = --entityScriptCount;
var lastIndex = --internals.entityScriptCount;
if (lastIndex < 1) throw new InvalidOperationException("invariant: entityScriptCount > 0");
var lastEntityId = entityScripts[lastIndex].id;
var lastEntityId = internals.entityScripts[lastIndex].id;
// Is the Script not the last in store.entityScripts?
if (entity.Id != lastEntityId) {
// move scriptIndex of last item in store.entityScripts to the index which will be removed
entityScripts[scriptIndex] = entityScripts[lastIndex];
scriptMap[lastEntityId] = scriptIndex;
internals.entityScripts[scriptIndex] = internals.entityScripts[lastIndex];
internals.scriptMap[lastEntityId] = scriptIndex;
}
entityScripts[lastIndex] = default; // clear last Script entry
scriptMap.Remove(entity.Id);
internals.entityScripts[lastIndex] = default; // clear last Script entry
internals.scriptMap.Remove(entity.Id);
goto SendEvent;
}
// case: entity has two or more scripts. Remove the given one from its scripts
Expand Down
33 changes: 18 additions & 15 deletions Engine/src/ECS/EntityStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public sealed partial class EntityStore : EntityStoreBase
public Entity StoreRoot => storeRoot; // null if no graph origin set

/// <summary> Return all <see cref="Script"/>'s added to <see cref="Entity"/>'s in the <see cref="EntityStore"/>. </summary>
public ReadOnlySpan<EntityScripts> EntityScripts => new (entityScripts, 1, entityScriptCount - 1);
public ReadOnlySpan<EntityScripts> EntityScripts => new (internals.entityScripts, 1, internals.entityScriptCount - 1);

/// <summary> Return all <see cref="Entity"/>'s stored in the <see cref="EntityStore"/>.</summary>
/// <remarks>Property is mainly used for debugging.<br/>
Expand Down Expand Up @@ -100,13 +100,7 @@ public sealed partial class EntityStore : EntityStoreBase
// --- Note: all fields must stay private to limit the scope of mutations
[Browse(Never)] internal EntityNode[] nodes; // 8 - acts also id2pid
[Browse(Never)] private Entity storeRoot; // 16 - origin of the tree graph. null if no origin assigned
/// <summary>Contains implicit all entities with one or more <see cref="Script"/>'s to minimize iteration cost for <see cref="Script.Update"/>.</summary>
[Browse(Never)] private EntityScripts[] entityScripts; // 8 - invariant: entityScripts[0] = 0
/// <summary>Contains the <see cref="entityScripts"/> index (value) of an entity id (key)</summary>
internal readonly Dictionary<int, int> scriptMap; // 8 - invariant: entityScripts[0] = 0

/// <summary>Count of entities with one or more <see cref="Script"/>'s</summary>
[Browse(Never)] private int entityScriptCount; // 4 - invariant: > 0 and <= entityScripts.Length

// --- buffers
[Browse(Never)] private int[] idBuffer; // 8
[Browse(Never)] private readonly HashSet<int> idBufferSet; // 8
Expand All @@ -115,10 +109,19 @@ public sealed partial class EntityStore : EntityStoreBase
private Intern intern; // 88

internal struct Internals {
internal readonly Dictionary<int, int> parentMap; // 8 - store the parent (value) of an entity (key)
internal Random randPid; // 8 - generate random pid's - null if UsePidAsId
internal readonly Dictionary<long, int> pid2Id; // 8 - store the id (value) of a pid (key) - null if UsePidAsId
internal readonly Dictionary<int, long> id2Pid; // 8 - store the pid (value) of an entity id (key) - null if UsePidAsId
// --- storage for random pid's
internal readonly Dictionary<int, int> parentMap; // 8 - store the parent (value) of an entity (key)
internal Random randPid; // 8 - generate random pid's - null if UsePidAsId
internal readonly Dictionary<long, int> pid2Id; // 8 - store the id (value) of a pid (key) - null if UsePidAsId
internal readonly Dictionary<int, long> id2Pid; // 8 - store the pid (value) of an entity id (key) - null if UsePidAsId

// --- storage for entity scripts
/// <summary>Count of entities with one or more <see cref="Script"/>'s</summary>
[Browse(Never)] internal int entityScriptCount; // 4 - invariant: > 0 and <= entityScripts.Length
/// <summary>Contains implicit all entities with one or more <see cref="Script"/>'s to minimize iteration cost for <see cref="Script.Update"/>.</summary>
internal EntityScripts[] entityScripts; // 8 - invariant: entityScripts[0] = 0
/// <summary>Contains the <see cref="entityScripts"/> index (value) of an entity id (key)</summary>
internal readonly Dictionary<int, int> scriptMap; // 8 - invariant: entityScripts[0] = 0

internal Internals(PidType pidType)
{
Expand All @@ -128,6 +131,9 @@ internal Internals(PidType pidType)
pid2Id = new Dictionary<long, int>();
id2Pid = new Dictionary<int, long>();
}
scriptMap = new Dictionary<int, int>();
entityScripts = new EntityScripts[1]; // invariant: entityScripts[0] = 0
entityScriptCount = 1;
}
}

Expand Down Expand Up @@ -176,11 +182,8 @@ public EntityStore(PidType pidType)
{
intern = new Intern(pidType);
internals = new Internals(pidType);
scriptMap = new Dictionary<int, int>();
nodes = Array.Empty<EntityNode>();
EnsureNodesLength(2);
entityScripts = new EntityScripts[1]; // invariant: entityScripts[0] = 0
entityScriptCount = 1;
idBuffer = new int[1];
idBufferSet = new HashSet<int>();
dataBuffer = new DataEntity();
Expand Down

0 comments on commit 835838f

Please sign in to comment.