From 31cb8812fe9531402208c9c571c90af83b86a653 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 9 Jul 2026 16:58:07 -0700 Subject: [PATCH 1/8] Add benchmark --- .../TransformComponentQueryBenchmark.cs | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 Robust.Benchmarks/EntityManager/TransformComponentQueryBenchmark.cs diff --git a/Robust.Benchmarks/EntityManager/TransformComponentQueryBenchmark.cs b/Robust.Benchmarks/EntityManager/TransformComponentQueryBenchmark.cs new file mode 100644 index 00000000000..84b0c328fed --- /dev/null +++ b/Robust.Benchmarks/EntityManager/TransformComponentQueryBenchmark.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; +using JetBrains.Annotations; +using Robust.Shared.Analyzers; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.UnitTesting.Server; + +namespace Robust.Benchmarks.EntityManager; + +[MemoryDiagnoser] +[Virtual] +public class TransformComponentQueryBenchmark +{ + private ISimulation _simulation = default!; + private IEntityManager _entityManager = default!; + + [UsedImplicitly] + [Params(1, 10, 100, 1000)] + public int N = 10000; + + private List Ents = default!; + + [GlobalSetup] + public void GlobalSetup() + { + _simulation = RobustServerSimulation + .NewSimulation() + .InitializeInstance(); + + _entityManager = _simulation.Resolve(); + + Ents = []; + for (var i = 0; i < N; i++) + { + Ents.Add(_entityManager.SpawnEntity(null, MapCoordinates.Nullspace)); + } + } + + [Benchmark] + public int AllEntityQueryEnumerator() + { + var a = 0; + var query = _entityManager.AllEntityQueryEnumerator(); + while (query.MoveNext(out _, out var comp)) + { + a += comp.ChildCount; + } + + return a; + } + + [Benchmark] + public int EntityQueryEnumerator() + { + var a = 0; + var query = _entityManager.EntityQueryEnumerator(); + while (query.MoveNext(out _, out var comp)) + { + a += comp.ChildCount; + } + + return a; + } + + [Benchmark] + public int GetEntityQuery() + { + var a = 0; + var query = _entityManager.GetEntityQuery(); + foreach (var uid in CollectionsMarshal.AsSpan(Ents)) + { + a += query.GetComponent(uid).ChildCount; + } + + return a; + } + + [Benchmark] + public int GetComponent() + { + var a = 0; + foreach (var uid in CollectionsMarshal.AsSpan(Ents)) + { + a += _entityManager.GetComponent(uid).ChildCount; + } + + return a; + } + + [Benchmark] + public int HasComponent() + { + var a = 0; + foreach (var uid in CollectionsMarshal.AsSpan(Ents)) + { + if (_entityManager.HasComponent(uid)) + a += 1; + } + + return a; + } + + [Benchmark] + public int TryGetComponent() + { + var a = 0; + foreach (var uid in CollectionsMarshal.AsSpan(Ents)) + { + if (_entityManager.TryGetComponent(uid, out TransformComponent? xform)) + a += xform.ChildCount; + } + + return a; + } +} From 0a027f887acc683b7e5d73244bbed5d1df6748d7 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 9 Jul 2026 16:58:29 -0700 Subject: [PATCH 2/8] Add and implement dense component attribute --- Directory.Packages.props | 1 + .../GameObjects/ArchetypeComponent.cs | 19 ++ .../ArchetypeComponentAttribute.cs | 8 + Robust.Shared/GameObjects/CompIdx.cs | 21 +- Robust.Shared/GameObjects/ComponentFactory.cs | 3 +- .../GameObjects/ComponentRegistration.cs | 5 +- .../Components/MetaDataComponent.cs | 1 + .../Transform/TransformComponent.cs | 1 + .../GameObjects/EntityManager.Components.cs | 316 ++++++++++++++++-- Robust.Shared/Robust.Shared.csproj | 1 + 10 files changed, 352 insertions(+), 24 deletions(-) create mode 100644 Robust.Shared/GameObjects/ArchetypeComponent.cs create mode 100644 Robust.Shared/GameObjects/ArchetypeComponentAttribute.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 92e4a7258df..99b403f6db7 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -11,6 +11,7 @@ 147.0.10 + diff --git a/Robust.Shared/GameObjects/ArchetypeComponent.cs b/Robust.Shared/GameObjects/ArchetypeComponent.cs new file mode 100644 index 00000000000..761a9afc4df --- /dev/null +++ b/Robust.Shared/GameObjects/ArchetypeComponent.cs @@ -0,0 +1,19 @@ +using System.Threading; + +namespace Robust.Shared.GameObjects; + +internal static class ArchetypeComponent +{ + public static int Index = -1; +} + +internal static class ArchetypeComponent +{ + // ReSharper disable once StaticMemberInGenericType + internal static readonly int Index = Interlocked.Increment(ref ArchetypeComponent.Index); + + static ArchetypeComponent() + { + CompIdx.SetArchetype(true, Index); + } +} diff --git a/Robust.Shared/GameObjects/ArchetypeComponentAttribute.cs b/Robust.Shared/GameObjects/ArchetypeComponentAttribute.cs new file mode 100644 index 00000000000..6906e1e85bc --- /dev/null +++ b/Robust.Shared/GameObjects/ArchetypeComponentAttribute.cs @@ -0,0 +1,8 @@ +using System; +using JetBrains.Annotations; + +namespace Robust.Shared.GameObjects; + +[AttributeUsage(AttributeTargets.Class, Inherited = false)] +[BaseTypeRequired(typeof(IComponent))] +public sealed class ArchetypeComponentAttribute : Attribute; diff --git a/Robust.Shared/GameObjects/CompIdx.cs b/Robust.Shared/GameObjects/CompIdx.cs index ab7d537c9ad..38db631dfdf 100644 --- a/Robust.Shared/GameObjects/CompIdx.cs +++ b/Robust.Shared/GameObjects/CompIdx.cs @@ -11,6 +11,8 @@ namespace Robust.Shared.GameObjects; public readonly struct CompIdx : IEquatable { internal readonly int Value; + internal readonly bool Archetype; + internal readonly int ArchetypeIndex; internal static CompIdx Index() => Store.Index; @@ -41,12 +43,22 @@ internal static ref T RefArray(ref T[] array, CompIdx idx) return ref array[idx.Value]; } + internal static bool GetArchetype() + { + return Store.Index.Archetype; + } + + internal static void SetArchetype(bool archetype, int index) + { + Store.Index = new CompIdx(Store.Index.Value, archetype, index); + } + private static int _CompIdxMaster = -1; private static class Store { // ReSharper disable once StaticMemberInGenericType - public static readonly CompIdx Index = new(Interlocked.Increment(ref _CompIdxMaster)); + public static CompIdx Index = new(Interlocked.Increment(ref _CompIdxMaster)); } internal CompIdx(int value) @@ -54,6 +66,13 @@ internal CompIdx(int value) Value = value; } + internal CompIdx(int value, bool archetype, int archetypeIndex) + { + Value = value; + Archetype = archetype; + ArchetypeIndex = archetypeIndex; + } + public bool Equals(CompIdx other) { return Value == other.Value; diff --git a/Robust.Shared/GameObjects/ComponentFactory.cs b/Robust.Shared/GameObjects/ComponentFactory.cs index 20bedc1d21e..851220b8870 100644 --- a/Robust.Shared/GameObjects/ComponentFactory.cs +++ b/Robust.Shared/GameObjects/ComponentFactory.cs @@ -130,8 +130,9 @@ private ComponentRegistration Register(Type type, throw new InvalidOperationException($"{lowerCaseName} is already registered, previous: {prevName}"); var unsaved = type.HasCustomAttribute(); + var archetype = type.HasCustomAttribute(); - var registration = new ComponentRegistration(name, type, idx, unsaved); + var registration = new ComponentRegistration(name, type, idx, unsaved, archetype); idxToType[idx] = type; names[name] = registration; diff --git a/Robust.Shared/GameObjects/ComponentRegistration.cs b/Robust.Shared/GameObjects/ComponentRegistration.cs index 4a5ef87fd39..94f1005ebee 100644 --- a/Robust.Shared/GameObjects/ComponentRegistration.cs +++ b/Robust.Shared/GameObjects/ComponentRegistration.cs @@ -47,14 +47,17 @@ public sealed class ComponentRegistration public FrozenDictionary NetworkedFieldLookup = FrozenDictionary.Empty; + internal bool Archetype; + // Internal for sandboxing. // Avoid content passing an instance of this to ComponentFactory to get any type they want instantiated. - internal ComponentRegistration(string name, Type type, CompIdx idx, bool unsaved = false) + internal ComponentRegistration(string name, Type type, CompIdx idx, bool unsaved = false, bool archetype = false) { Name = name; Type = type; Idx = idx; Unsaved = unsaved; + Archetype = archetype; } public override string ToString() diff --git a/Robust.Shared/GameObjects/Components/MetaDataComponent.cs b/Robust.Shared/GameObjects/Components/MetaDataComponent.cs index 9770f9b0594..5d8cadbc41f 100644 --- a/Robust.Shared/GameObjects/Components/MetaDataComponent.cs +++ b/Robust.Shared/GameObjects/Components/MetaDataComponent.cs @@ -57,6 +57,7 @@ public MetaDataComponentState(string? name, string? description, string? prototy /// /// Contains meta data about this entity that isn't component specific. /// + [ArchetypeComponent] [RegisterComponent, NetworkedComponent] public sealed partial class MetaDataComponent : Component { diff --git a/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs b/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs index f2e132d06cd..078745710a0 100644 --- a/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs +++ b/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs @@ -22,6 +22,7 @@ namespace Robust.Shared.GameObjects /// and move when their parent moves cheaply. /// /// + [ArchetypeComponent] [RegisterComponent, NetworkedComponent] public sealed partial class TransformComponent : Component, IComponentDebug { diff --git a/Robust.Shared/GameObjects/EntityManager.Components.cs b/Robust.Shared/GameObjects/EntityManager.Components.cs index b36fa6d1b2a..2f43f20dff1 100644 --- a/Robust.Shared/GameObjects/EntityManager.Components.cs +++ b/Robust.Shared/GameObjects/EntityManager.Components.cs @@ -4,9 +4,11 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; +using Arch.LowLevel.Jagged; using JetBrains.Annotations; using Robust.Shared.GameStates; using Robust.Shared.Log; @@ -42,6 +44,8 @@ private FrozenDictionary> _entTraitDict private Dictionary[] _entTraitArray = Array.Empty>(); + private JaggedArray[] _entTraitJaggedArray = Array.Empty>(); + private readonly HashSet _deleteSet = new(TypeCapacity); private UniqueIndexHkm _entCompIndex = @@ -74,6 +78,11 @@ public void ClearComponents() { dict.Clear(); } + + foreach (var array in _entTraitJaggedArray) + { + array.Clear(); + } } private void RegisterComponents(IEnumerable components) @@ -84,6 +93,24 @@ private void RegisterComponents(IEnumerable components) var dict = new Dictionary(); traitDict.Add(reg.Type, dict); CompIdx.AssignArray(ref _entTraitArray, reg.Idx, dict); + + if (!reg.Archetype) + continue; + + var type = typeof(ArchetypeComponent<>).MakeGenericType(reg.Type); + var field = type.GetField(nameof(ArchetypeComponent<>.Index), BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null); + if (field is not int archetypeIndex) + throw new UnreachableException($"Couldn't get index for archetypal component type {reg.Type}"); + + var newSize = archetypeIndex + 1; + if (_entTraitJaggedArray.Length <= newSize) + Array.Resize(ref _entTraitJaggedArray, newSize); + + foreach (ref var array in _entTraitJaggedArray.AsSpan()) + { + // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract + array ??= new JaggedArray(128); + } } _entTraitDict = traitDict.ToFrozenDictionary(); } @@ -382,6 +409,13 @@ private void AddComponentInternal(EntityUid uid, T component, ComponentRegist } } + if (CompIdx.GetArchetype()) + { + var array = _entTraitJaggedArray[ArchetypeComponent.Index]; + array.EnsureCapacity(uid.Id); + array.Add(uid.Id, component); + } + // actually ADD the component _entCompIndex.Add(uid, component); @@ -749,6 +783,12 @@ private void DeleteComponent( _entTraitArray[idx.Value].Remove(entityUid); + if (idx.Archetype) + { + var array = _entTraitJaggedArray[idx.ArchetypeIndex]; + array.Remove(entityUid.Id); + } + // TODO if terminating the entity, maybe defer this? // _entCompIndex.Remove(uid) gets called later on anyways. _entCompIndex.Remove(entityUid, component); @@ -762,6 +802,9 @@ private void DeleteComponent( [Pure] public bool HasComponent(EntityUid uid) where T : IComponent { + if (CompIdx.GetArchetype()) + return _entTraitJaggedArray[ArchetypeComponent.Index].ContainsKey(uid.Id); + var dict = _entTraitArray[CompIdx.ArrayIndex()]; DebugTools.Assert(dict != null, $"Unknown component: {typeof(T).Name}"); return dict.TryGetValue(uid, out var comp) && !comp.Deleted; @@ -889,6 +932,9 @@ public bool HasComponent([NotNullWhen(true)] EntityUid? uid, ushort netId, MetaD [MethodImpl(MethodImplOptions.AggressiveInlining)] public T GetComponent(EntityUid uid) where T : IComponent { + if (CompIdx.GetArchetype()) + return (T) _entTraitJaggedArray[ArchetypeComponent.Index][uid.Id]; + var dict = _entTraitArray[CompIdx.ArrayIndex()]; DebugTools.Assert(dict != null, $"Unknown component: {typeof(T).Name}"); if (dict.TryGetValue(uid, out var comp)) @@ -956,6 +1002,21 @@ public IComponent GetComponentInternal(EntityUid uid, CompIdx type) [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryGetComponent(EntityUid uid, [NotNullWhen(true)] out T? component) where T : IComponent? { + if (CompIdx.GetArchetype()) + { + if (_entTraitJaggedArray[ArchetypeComponent.Index].TryGetValue(uid.Id, out IComponent archetypeComp)) + { + if (!archetypeComp.Deleted) + { + component = (T)archetypeComp; + return true; + } + } + + component = default; + return false; + } + var dict = _entTraitArray[CompIdx.ArrayIndex()]; DebugTools.Assert(dict != null, $"Unknown component: {typeof(T).Name}"); if (dict.TryGetValue(uid, out var comp)) @@ -1190,14 +1251,19 @@ public EntityQuery GetEntityQuery() where TComp1 : IComponent { var comps = _entTraitArray[CompIdx.ArrayIndex()]; DebugTools.Assert(comps != null, $"Unknown component: {typeof(TComp1).Name}"); - return new EntityQuery(this, comps); + + JaggedArray? jaggedArray = null; + if (CompIdx.GetArchetype()) + jaggedArray = _entTraitJaggedArray[ArchetypeComponent.Index]; + + return new EntityQuery(this, comps, jaggedArray); } public EntityQuery GetEntityQuery(Type type) { var comps = _entTraitDict[type]; DebugTools.Assert(comps != null, $"Unknown component: {type.Name}"); - return new EntityQuery(this, comps); + return new EntityQuery(this, comps, null); } /// @@ -1411,7 +1477,12 @@ public AllEntityQueryEnumerator AllEntityQueryEnumerator() where TComp1 : IComponent { var trait1 = _entTraitArray[CompIdx.ArrayIndex()]; - return new AllEntityQueryEnumerator(trait1); + + JaggedArray? jaggedArray = null; + if (CompIdx.GetArchetype()) + jaggedArray = _entTraitJaggedArray[ArchetypeComponent.Index]; + + return new AllEntityQueryEnumerator(trait1, jaggedArray); } public AllEntityQueryEnumerator AllEntityQueryEnumerator() @@ -1420,7 +1491,16 @@ public AllEntityQueryEnumerator AllEntityQueryEnumerator()]; var trait2 = _entTraitArray[CompIdx.ArrayIndex()]; - return new AllEntityQueryEnumerator(trait1, trait2); + + JaggedArray? jaggedArray1 = null; + if (CompIdx.GetArchetype()) + jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray2 = null; + if (CompIdx.GetArchetype()) + jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + return new AllEntityQueryEnumerator(trait1, trait2, jaggedArray1, jaggedArray2); } public AllEntityQueryEnumerator AllEntityQueryEnumerator() @@ -1431,7 +1511,20 @@ public AllEntityQueryEnumerator AllEntityQueryEnumerator var trait1 = _entTraitArray[CompIdx.ArrayIndex()]; var trait2 = _entTraitArray[CompIdx.ArrayIndex()]; var trait3 = _entTraitArray[CompIdx.ArrayIndex()]; - return new AllEntityQueryEnumerator(trait1, trait2, trait3); + + JaggedArray? jaggedArray1 = null; + if (CompIdx.GetArchetype()) + jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray2 = null; + if (CompIdx.GetArchetype()) + jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray3 = null; + if (CompIdx.GetArchetype()) + jaggedArray3 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + return new AllEntityQueryEnumerator(trait1, trait2, trait3, jaggedArray1, jaggedArray2, jaggedArray3); } public AllEntityQueryEnumerator AllEntityQueryEnumerator() @@ -1444,14 +1537,36 @@ public AllEntityQueryEnumerator AllEntityQueryEn var trait2 = _entTraitArray[CompIdx.ArrayIndex()]; var trait3 = _entTraitArray[CompIdx.ArrayIndex()]; var trait4 = _entTraitArray[CompIdx.ArrayIndex()]; - return new AllEntityQueryEnumerator(trait1, trait2, trait3, trait4); + + JaggedArray? jaggedArray1 = null; + if (CompIdx.GetArchetype()) + jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray2 = null; + if (CompIdx.GetArchetype()) + jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray3 = null; + if (CompIdx.GetArchetype()) + jaggedArray3 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray4 = null; + if (CompIdx.GetArchetype()) + jaggedArray4 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + return new AllEntityQueryEnumerator(trait1, trait2, trait3, trait4, jaggedArray1, jaggedArray2, jaggedArray3, jaggedArray4); } public EntityQueryEnumerator EntityQueryEnumerator() where TComp1 : IComponent { var trait1 = _entTraitArray[CompIdx.ArrayIndex()]; - return new EntityQueryEnumerator(trait1, MetaQuery); + + JaggedArray? jaggedArray = null; + if (CompIdx.GetArchetype()) + jaggedArray = _entTraitJaggedArray[ArchetypeComponent.Index]; + + return new EntityQueryEnumerator(trait1, MetaQuery, jaggedArray); } public EntityQueryEnumerator EntityQueryEnumerator() @@ -1460,7 +1575,16 @@ public EntityQueryEnumerator EntityQueryEnumerator()]; var trait2 = _entTraitArray[CompIdx.ArrayIndex()]; - return new EntityQueryEnumerator(trait1, trait2, MetaQuery); + + JaggedArray? jaggedArray1 = null; + if (CompIdx.GetArchetype()) + jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray2 = null; + if (CompIdx.GetArchetype()) + jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + return new EntityQueryEnumerator(trait1, trait2, MetaQuery, jaggedArray1, jaggedArray2); } public EntityQueryEnumerator EntityQueryEnumerator() @@ -1471,7 +1595,20 @@ public EntityQueryEnumerator EntityQueryEnumerator()]; var trait2 = _entTraitArray[CompIdx.ArrayIndex()]; var trait3 = _entTraitArray[CompIdx.ArrayIndex()]; - return new EntityQueryEnumerator(trait1, trait2, trait3, MetaQuery); + + JaggedArray? jaggedArray1 = null; + if (CompIdx.GetArchetype()) + jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray2 = null; + if (CompIdx.GetArchetype()) + jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray3 = null; + if (CompIdx.GetArchetype()) + jaggedArray3 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + return new EntityQueryEnumerator(trait1, trait2, trait3, MetaQuery, jaggedArray1, jaggedArray2, jaggedArray3); } public EntityQueryEnumerator EntityQueryEnumerator() @@ -1485,7 +1622,23 @@ public EntityQueryEnumerator EntityQueryEnumerat var trait3 = _entTraitArray[CompIdx.ArrayIndex()]; var trait4 = _entTraitArray[CompIdx.ArrayIndex()]; - return new EntityQueryEnumerator(trait1, trait2, trait3, trait4, MetaQuery); + JaggedArray? jaggedArray1 = null; + if (CompIdx.GetArchetype()) + jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray2 = null; + if (CompIdx.GetArchetype()) + jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray3 = null; + if (CompIdx.GetArchetype()) + jaggedArray3 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + JaggedArray? jaggedArray4 = null; + if (CompIdx.GetArchetype()) + jaggedArray4 = _entTraitJaggedArray[ArchetypeComponent.Index]; + + return new EntityQueryEnumerator(trait1, trait2, trait3, trait4, MetaQuery, jaggedArray1, jaggedArray2, jaggedArray3, jaggedArray4); } /// @@ -1801,11 +1954,13 @@ public NetComponentEnumerator(Dictionary dictionary) => { private readonly EntityManager _entMan; private readonly Dictionary _traitDict; + private readonly JaggedArray? _jaggedArray; - internal EntityQuery(EntityManager entMan, Dictionary traitDict) + internal EntityQuery(EntityManager entMan, Dictionary traitDict, JaggedArray? jaggedArray) { _entMan = entMan; _traitDict = traitDict; + _jaggedArray = jaggedArray; } /// @@ -1824,6 +1979,9 @@ internal EntityQuery(EntityManager entMan, Dictionary tra [Pure] public TComp1 GetComponent(EntityUid uid) { + if (_jaggedArray != null) + return (TComp1) _jaggedArray[uid.Id]; + if (_traitDict.TryGetValue(uid, out var comp) && !comp.Deleted) return (TComp1) comp; @@ -1834,6 +1992,9 @@ public TComp1 GetComponent(EntityUid uid) [MethodImpl(MethodImplOptions.AggressiveInlining), Pure] public Entity Get(EntityUid uid) { + if (_jaggedArray != null) + return new Entity(uid, (TComp1) _jaggedArray[uid.Id]); + if (_traitDict.TryGetValue(uid, out var comp) && !comp.Deleted) return new Entity(uid, (TComp1) comp); @@ -1874,6 +2035,15 @@ public bool TryGetComponent([NotNullWhen(true)] EntityUid? uid, [NotNullWhen(tru [Pure] public bool TryGetComponent(EntityUid uid, [NotNullWhen(true)] out TComp1? component) { + if (_jaggedArray != null) + { + if (_jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp) && !archetypeComp.Deleted) + { + component = (TComp1) archetypeComp; + return true; + } + } + if (_traitDict.TryGetValue(uid, out var comp) && !comp.Deleted) { component = (TComp1) comp; @@ -1922,6 +2092,11 @@ public bool TryComp([NotNullWhen(true)] EntityUid? uid, [NotNullWhen(true)] out [Pure] public bool HasComponent(EntityUid uid) { + if (_jaggedArray != null) + { + return _jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp) && !archetypeComp.Deleted; + } + return _traitDict.TryGetValue(uid, out var comp) && !comp.Deleted; } @@ -1950,6 +2125,15 @@ public bool Resolve(EntityUid uid, [NotNullWhen(true)] ref TComp1? component, bo return true; } + if (_jaggedArray != null) + { + if (_jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp) && !archetypeComp.Deleted) + { + component = (TComp1)archetypeComp; + return true; + } + } + if (_traitDict.TryGetValue(uid, out var comp) && !comp.Deleted) { component = (TComp1)comp; @@ -2007,7 +2191,12 @@ public TComp1 Comp(EntityUid uid) [Pure] internal TComp1 GetComponentInternal(EntityUid uid) { - if (_traitDict.TryGetValue(uid, out var comp)) + if (_jaggedArray != null) + { + if (_jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp)) + return (TComp1) archetypeComp; + } + else if (_traitDict.TryGetValue(uid, out var comp)) return (TComp1) comp; throw new KeyNotFoundException($"Entity {uid} does not have a component of type {typeof(TComp1)}"); @@ -2036,6 +2225,18 @@ internal bool TryGetComponentInternal([NotNullWhen(true)] EntityUid? uid, [NotNu [Pure] internal bool TryGetComponentInternal(EntityUid uid, [NotNullWhen(true)] out TComp1? component) { + if (_jaggedArray != null) + { + if (_jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp)) + { + component = (TComp1) archetypeComp; + return true; + } + + component = default; + return false; + } + if (_traitDict.TryGetValue(uid, out var comp)) { component = (TComp1) comp; @@ -2053,6 +2254,11 @@ internal bool TryGetComponentInternal(EntityUid uid, [NotNullWhen(true)] out TCo [Pure] internal bool HasComponentInternal(EntityUid uid) { + if (_jaggedArray != null) + { + return _jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp) && !archetypeComp.Deleted; + } + return _traitDict.TryGetValue(uid, out var comp) && !comp.Deleted; } @@ -2069,7 +2275,15 @@ internal bool ResolveInternal(EntityUid uid, [NotNullWhen(true)] ref TComp1? com return true; } - if (_traitDict.TryGetValue(uid, out var comp)) + if (_jaggedArray != null) + { + if (_jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp)) + { + component = (TComp1)archetypeComp; + return true; + } + } + else if (_traitDict.TryGetValue(uid, out var comp)) { component = (TComp1)comp; return true; @@ -2254,13 +2468,16 @@ public struct EntityQueryEnumerator : IDisposable { private Dictionary.Enumerator _traitDict; private readonly EntityQuery _metaQuery; + private readonly JaggedArray? _jaggedArray; public EntityQueryEnumerator( Dictionary traitDict, - EntityQuery metaQuery) + EntityQuery metaQuery, + JaggedArray? jaggedArray = null) { _traitDict = traitDict.GetEnumerator(); _metaQuery = metaQuery; + _jaggedArray = jaggedArray; } /// @@ -2318,15 +2535,21 @@ public struct EntityQueryEnumerator : IDisposable private Dictionary.Enumerator _traitDict; private readonly Dictionary _traitDict2; private readonly EntityQuery _metaQuery; + private readonly JaggedArray? _jaggedArray1; + private readonly JaggedArray? _jaggedArray2; public EntityQueryEnumerator( Dictionary traitDict, Dictionary traitDict2, - EntityQuery metaQuery) + EntityQuery metaQuery, + JaggedArray? jaggedArray1 = null, + JaggedArray? jaggedArray2 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; _metaQuery = metaQuery; + _jaggedArray1 = jaggedArray1; + _jaggedArray2 = jaggedArray2; } /// @@ -2389,17 +2612,26 @@ public struct EntityQueryEnumerator : IDisposable private readonly Dictionary _traitDict2; private readonly Dictionary _traitDict3; private readonly EntityQuery _metaQuery; + private readonly JaggedArray? _jaggedArray1; + private readonly JaggedArray? _jaggedArray2; + private readonly JaggedArray? _jaggedArray3; public EntityQueryEnumerator( Dictionary traitDict, Dictionary traitDict2, Dictionary traitDict3, - EntityQuery metaQuery) + EntityQuery metaQuery, + JaggedArray? jaggedArray1 = null, + JaggedArray? jaggedArray2 = null, + JaggedArray? jaggedArray3 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; _traitDict3 = traitDict3; _metaQuery = metaQuery; + _jaggedArray1 = jaggedArray1; + _jaggedArray2 = jaggedArray2; + _jaggedArray3 = jaggedArray3; } /// @@ -2475,19 +2707,31 @@ public struct EntityQueryEnumerator : IDisposabl private readonly Dictionary _traitDict3; private readonly Dictionary _traitDict4; private readonly EntityQuery _metaQuery; + private readonly JaggedArray? _jaggedArray1; + private readonly JaggedArray? _jaggedArray2; + private readonly JaggedArray? _jaggedArray3; + private readonly JaggedArray? _jaggedArray4; public EntityQueryEnumerator( Dictionary traitDict, Dictionary traitDict2, Dictionary traitDict3, Dictionary traitDict4, - EntityQuery metaQuery) + EntityQuery metaQuery, + JaggedArray? jaggedArray1 = null, + JaggedArray? jaggedArray2 = null, + JaggedArray? jaggedArray3 = null, + JaggedArray? jaggedArray4 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; _traitDict3 = traitDict3; _traitDict4 = traitDict4; _metaQuery = metaQuery; + _jaggedArray1 = jaggedArray1; + _jaggedArray2 = jaggedArray2; + _jaggedArray3 = jaggedArray3; + _jaggedArray4 = jaggedArray4; } /// @@ -2598,11 +2842,14 @@ public struct AllEntityQueryEnumerator : IDisposable where TComp1 : IComponent { private Dictionary.Enumerator _traitDict; + private readonly JaggedArray? _jaggedArray; public AllEntityQueryEnumerator( - Dictionary traitDict) + Dictionary traitDict, + JaggedArray? jaggedArray = null) { _traitDict = traitDict.GetEnumerator(); + _jaggedArray = jaggedArray; } /// @@ -2649,13 +2896,19 @@ public struct AllEntityQueryEnumerator : IDisposable { private Dictionary.Enumerator _traitDict; private readonly Dictionary _traitDict2; + private readonly JaggedArray? _jaggedArray1; + private readonly JaggedArray? _jaggedArray2; public AllEntityQueryEnumerator( Dictionary traitDict, - Dictionary traitDict2) + Dictionary traitDict2, + JaggedArray? jaggedArray1 = null, + JaggedArray? jaggedArray2 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; + _jaggedArray1 = jaggedArray1; + _jaggedArray2 = jaggedArray2; } /// @@ -2711,15 +2964,24 @@ public struct AllEntityQueryEnumerator : IDisposable private Dictionary.Enumerator _traitDict; private readonly Dictionary _traitDict2; private readonly Dictionary _traitDict3; + private readonly JaggedArray? _jaggedArray1; + private readonly JaggedArray? _jaggedArray2; + private readonly JaggedArray? _jaggedArray3; public AllEntityQueryEnumerator( Dictionary traitDict, Dictionary traitDict2, - Dictionary traitDict3) + Dictionary traitDict3, + JaggedArray? jaggedArray1 = null, + JaggedArray? jaggedArray2 = null, + JaggedArray? jaggedArray3 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; _traitDict3 = traitDict3; + _jaggedArray1 = jaggedArray1; + _jaggedArray2 = jaggedArray2; + _jaggedArray3 = jaggedArray3; } /// @@ -2787,17 +3049,29 @@ public struct AllEntityQueryEnumerator : IDispos private readonly Dictionary _traitDict2; private readonly Dictionary _traitDict3; private readonly Dictionary _traitDict4; + private readonly JaggedArray? _jaggedArray1; + private readonly JaggedArray? _jaggedArray2; + private readonly JaggedArray? _jaggedArray3; + private readonly JaggedArray? _jaggedArray4; public AllEntityQueryEnumerator( Dictionary traitDict, Dictionary traitDict2, Dictionary traitDict3, - Dictionary traitDict4) + Dictionary traitDict4, + JaggedArray? jaggedArray1 = null, + JaggedArray? jaggedArray2 = null, + JaggedArray? jaggedArray3 = null, + JaggedArray? jaggedArray4 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; _traitDict3 = traitDict3; _traitDict4 = traitDict4; + _jaggedArray1 = jaggedArray1; + _jaggedArray2 = jaggedArray2; + _jaggedArray3 = jaggedArray3; + _jaggedArray4 = jaggedArray4; } /// diff --git a/Robust.Shared/Robust.Shared.csproj b/Robust.Shared/Robust.Shared.csproj index cdd7bf9746e..d338548e0d4 100644 --- a/Robust.Shared/Robust.Shared.csproj +++ b/Robust.Shared/Robust.Shared.csproj @@ -7,6 +7,7 @@ CA1416 + From d19204d703fd12b89c4123e70156c8e904bf6ee4 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 9 Jul 2026 17:01:07 -0700 Subject: [PATCH 3/8] Rename archetype to dense --- Robust.Shared/GameObjects/CompIdx.cs | 18 +-- Robust.Shared/GameObjects/ComponentFactory.cs | 4 +- .../GameObjects/ComponentRegistration.cs | 6 +- .../Components/MetaDataComponent.cs | 2 +- .../Transform/TransformComponent.cs | 2 +- ...rchetypeComponent.cs => DenseComponent.cs} | 10 +- ...ttribute.cs => DenseComponentAttribute.cs} | 2 +- .../GameObjects/EntityManager.Components.cs | 142 +++++++++--------- 8 files changed, 93 insertions(+), 93 deletions(-) rename Robust.Shared/GameObjects/{ArchetypeComponent.cs => DenseComponent.cs} (55%) rename Robust.Shared/GameObjects/{ArchetypeComponentAttribute.cs => DenseComponentAttribute.cs} (74%) diff --git a/Robust.Shared/GameObjects/CompIdx.cs b/Robust.Shared/GameObjects/CompIdx.cs index 38db631dfdf..771d50c4753 100644 --- a/Robust.Shared/GameObjects/CompIdx.cs +++ b/Robust.Shared/GameObjects/CompIdx.cs @@ -11,8 +11,8 @@ namespace Robust.Shared.GameObjects; public readonly struct CompIdx : IEquatable { internal readonly int Value; - internal readonly bool Archetype; - internal readonly int ArchetypeIndex; + internal readonly bool Dense; + internal readonly int DenseIndex; internal static CompIdx Index() => Store.Index; @@ -43,14 +43,14 @@ internal static ref T RefArray(ref T[] array, CompIdx idx) return ref array[idx.Value]; } - internal static bool GetArchetype() + internal static bool GetDense() { - return Store.Index.Archetype; + return Store.Index.Dense; } - internal static void SetArchetype(bool archetype, int index) + internal static void SetDense(bool dense, int index) { - Store.Index = new CompIdx(Store.Index.Value, archetype, index); + Store.Index = new CompIdx(Store.Index.Value, dense, index); } private static int _CompIdxMaster = -1; @@ -66,11 +66,11 @@ internal CompIdx(int value) Value = value; } - internal CompIdx(int value, bool archetype, int archetypeIndex) + internal CompIdx(int value, bool dense, int denseIndex) { Value = value; - Archetype = archetype; - ArchetypeIndex = archetypeIndex; + Dense = dense; + DenseIndex = denseIndex; } public bool Equals(CompIdx other) diff --git a/Robust.Shared/GameObjects/ComponentFactory.cs b/Robust.Shared/GameObjects/ComponentFactory.cs index 851220b8870..fde740b68d5 100644 --- a/Robust.Shared/GameObjects/ComponentFactory.cs +++ b/Robust.Shared/GameObjects/ComponentFactory.cs @@ -130,9 +130,9 @@ private ComponentRegistration Register(Type type, throw new InvalidOperationException($"{lowerCaseName} is already registered, previous: {prevName}"); var unsaved = type.HasCustomAttribute(); - var archetype = type.HasCustomAttribute(); + var dense = type.HasCustomAttribute(); - var registration = new ComponentRegistration(name, type, idx, unsaved, archetype); + var registration = new ComponentRegistration(name, type, idx, unsaved, dense); idxToType[idx] = type; names[name] = registration; diff --git a/Robust.Shared/GameObjects/ComponentRegistration.cs b/Robust.Shared/GameObjects/ComponentRegistration.cs index 94f1005ebee..533c37b330b 100644 --- a/Robust.Shared/GameObjects/ComponentRegistration.cs +++ b/Robust.Shared/GameObjects/ComponentRegistration.cs @@ -47,17 +47,17 @@ public sealed class ComponentRegistration public FrozenDictionary NetworkedFieldLookup = FrozenDictionary.Empty; - internal bool Archetype; + internal bool Dense; // Internal for sandboxing. // Avoid content passing an instance of this to ComponentFactory to get any type they want instantiated. - internal ComponentRegistration(string name, Type type, CompIdx idx, bool unsaved = false, bool archetype = false) + internal ComponentRegistration(string name, Type type, CompIdx idx, bool unsaved = false, bool dense = false) { Name = name; Type = type; Idx = idx; Unsaved = unsaved; - Archetype = archetype; + Dense = dense; } public override string ToString() diff --git a/Robust.Shared/GameObjects/Components/MetaDataComponent.cs b/Robust.Shared/GameObjects/Components/MetaDataComponent.cs index 5d8cadbc41f..04194dfe8da 100644 --- a/Robust.Shared/GameObjects/Components/MetaDataComponent.cs +++ b/Robust.Shared/GameObjects/Components/MetaDataComponent.cs @@ -57,7 +57,7 @@ public MetaDataComponentState(string? name, string? description, string? prototy /// /// Contains meta data about this entity that isn't component specific. /// - [ArchetypeComponent] + [DenseComponent] [RegisterComponent, NetworkedComponent] public sealed partial class MetaDataComponent : Component { diff --git a/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs b/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs index 078745710a0..b66a79fbd07 100644 --- a/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs +++ b/Robust.Shared/GameObjects/Components/Transform/TransformComponent.cs @@ -22,7 +22,7 @@ namespace Robust.Shared.GameObjects /// and move when their parent moves cheaply. /// /// - [ArchetypeComponent] + [DenseComponent] [RegisterComponent, NetworkedComponent] public sealed partial class TransformComponent : Component, IComponentDebug { diff --git a/Robust.Shared/GameObjects/ArchetypeComponent.cs b/Robust.Shared/GameObjects/DenseComponent.cs similarity index 55% rename from Robust.Shared/GameObjects/ArchetypeComponent.cs rename to Robust.Shared/GameObjects/DenseComponent.cs index 761a9afc4df..04aa17d363c 100644 --- a/Robust.Shared/GameObjects/ArchetypeComponent.cs +++ b/Robust.Shared/GameObjects/DenseComponent.cs @@ -2,18 +2,18 @@ namespace Robust.Shared.GameObjects; -internal static class ArchetypeComponent +internal static class DenseComponent { public static int Index = -1; } -internal static class ArchetypeComponent +internal static class DenseComponent { // ReSharper disable once StaticMemberInGenericType - internal static readonly int Index = Interlocked.Increment(ref ArchetypeComponent.Index); + internal static readonly int Index = Interlocked.Increment(ref DenseComponent.Index); - static ArchetypeComponent() + static DenseComponent() { - CompIdx.SetArchetype(true, Index); + CompIdx.SetDense(true, Index); } } diff --git a/Robust.Shared/GameObjects/ArchetypeComponentAttribute.cs b/Robust.Shared/GameObjects/DenseComponentAttribute.cs similarity index 74% rename from Robust.Shared/GameObjects/ArchetypeComponentAttribute.cs rename to Robust.Shared/GameObjects/DenseComponentAttribute.cs index 6906e1e85bc..c1ce903befb 100644 --- a/Robust.Shared/GameObjects/ArchetypeComponentAttribute.cs +++ b/Robust.Shared/GameObjects/DenseComponentAttribute.cs @@ -5,4 +5,4 @@ namespace Robust.Shared.GameObjects; [AttributeUsage(AttributeTargets.Class, Inherited = false)] [BaseTypeRequired(typeof(IComponent))] -public sealed class ArchetypeComponentAttribute : Attribute; +public sealed class DenseComponentAttribute : Attribute; diff --git a/Robust.Shared/GameObjects/EntityManager.Components.cs b/Robust.Shared/GameObjects/EntityManager.Components.cs index 2f43f20dff1..7bd8d8f2e5b 100644 --- a/Robust.Shared/GameObjects/EntityManager.Components.cs +++ b/Robust.Shared/GameObjects/EntityManager.Components.cs @@ -94,15 +94,15 @@ private void RegisterComponents(IEnumerable components) traitDict.Add(reg.Type, dict); CompIdx.AssignArray(ref _entTraitArray, reg.Idx, dict); - if (!reg.Archetype) + if (!reg.Dense) continue; - var type = typeof(ArchetypeComponent<>).MakeGenericType(reg.Type); - var field = type.GetField(nameof(ArchetypeComponent<>.Index), BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null); - if (field is not int archetypeIndex) + var type = typeof(DenseComponent<>).MakeGenericType(reg.Type); + var field = type.GetField(nameof(DenseComponent<>.Index), BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null); + if (field is not int denseIndex) throw new UnreachableException($"Couldn't get index for archetypal component type {reg.Type}"); - var newSize = archetypeIndex + 1; + var newSize = denseIndex + 1; if (_entTraitJaggedArray.Length <= newSize) Array.Resize(ref _entTraitJaggedArray, newSize); @@ -409,9 +409,9 @@ private void AddComponentInternal(EntityUid uid, T component, ComponentRegist } } - if (CompIdx.GetArchetype()) + if (CompIdx.GetDense()) { - var array = _entTraitJaggedArray[ArchetypeComponent.Index]; + var array = _entTraitJaggedArray[DenseComponent.Index]; array.EnsureCapacity(uid.Id); array.Add(uid.Id, component); } @@ -783,9 +783,9 @@ private void DeleteComponent( _entTraitArray[idx.Value].Remove(entityUid); - if (idx.Archetype) + if (idx.Dense) { - var array = _entTraitJaggedArray[idx.ArchetypeIndex]; + var array = _entTraitJaggedArray[idx.DenseIndex]; array.Remove(entityUid.Id); } @@ -802,8 +802,8 @@ private void DeleteComponent( [Pure] public bool HasComponent(EntityUid uid) where T : IComponent { - if (CompIdx.GetArchetype()) - return _entTraitJaggedArray[ArchetypeComponent.Index].ContainsKey(uid.Id); + if (CompIdx.GetDense()) + return _entTraitJaggedArray[DenseComponent.Index].ContainsKey(uid.Id); var dict = _entTraitArray[CompIdx.ArrayIndex()]; DebugTools.Assert(dict != null, $"Unknown component: {typeof(T).Name}"); @@ -932,8 +932,8 @@ public bool HasComponent([NotNullWhen(true)] EntityUid? uid, ushort netId, MetaD [MethodImpl(MethodImplOptions.AggressiveInlining)] public T GetComponent(EntityUid uid) where T : IComponent { - if (CompIdx.GetArchetype()) - return (T) _entTraitJaggedArray[ArchetypeComponent.Index][uid.Id]; + if (CompIdx.GetDense()) + return (T) _entTraitJaggedArray[DenseComponent.Index][uid.Id]; var dict = _entTraitArray[CompIdx.ArrayIndex()]; DebugTools.Assert(dict != null, $"Unknown component: {typeof(T).Name}"); @@ -1002,13 +1002,13 @@ public IComponent GetComponentInternal(EntityUid uid, CompIdx type) [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryGetComponent(EntityUid uid, [NotNullWhen(true)] out T? component) where T : IComponent? { - if (CompIdx.GetArchetype()) + if (CompIdx.GetDense()) { - if (_entTraitJaggedArray[ArchetypeComponent.Index].TryGetValue(uid.Id, out IComponent archetypeComp)) + if (_entTraitJaggedArray[DenseComponent.Index].TryGetValue(uid.Id, out IComponent denseComp)) { - if (!archetypeComp.Deleted) + if (!denseComp.Deleted) { - component = (T)archetypeComp; + component = (T)denseComp; return true; } } @@ -1253,8 +1253,8 @@ public EntityQuery GetEntityQuery() where TComp1 : IComponent DebugTools.Assert(comps != null, $"Unknown component: {typeof(TComp1).Name}"); JaggedArray? jaggedArray = null; - if (CompIdx.GetArchetype()) - jaggedArray = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray = _entTraitJaggedArray[DenseComponent.Index]; return new EntityQuery(this, comps, jaggedArray); } @@ -1479,8 +1479,8 @@ public AllEntityQueryEnumerator AllEntityQueryEnumerator() var trait1 = _entTraitArray[CompIdx.ArrayIndex()]; JaggedArray? jaggedArray = null; - if (CompIdx.GetArchetype()) - jaggedArray = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray = _entTraitJaggedArray[DenseComponent.Index]; return new AllEntityQueryEnumerator(trait1, jaggedArray); } @@ -1493,12 +1493,12 @@ public AllEntityQueryEnumerator AllEntityQueryEnumerator()]; JaggedArray? jaggedArray1 = null; - if (CompIdx.GetArchetype()) - jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray2 = null; - if (CompIdx.GetArchetype()) - jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; return new AllEntityQueryEnumerator(trait1, trait2, jaggedArray1, jaggedArray2); } @@ -1513,16 +1513,16 @@ public AllEntityQueryEnumerator AllEntityQueryEnumerator var trait3 = _entTraitArray[CompIdx.ArrayIndex()]; JaggedArray? jaggedArray1 = null; - if (CompIdx.GetArchetype()) - jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray2 = null; - if (CompIdx.GetArchetype()) - jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray3 = null; - if (CompIdx.GetArchetype()) - jaggedArray3 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray3 = _entTraitJaggedArray[DenseComponent.Index]; return new AllEntityQueryEnumerator(trait1, trait2, trait3, jaggedArray1, jaggedArray2, jaggedArray3); } @@ -1539,20 +1539,20 @@ public AllEntityQueryEnumerator AllEntityQueryEn var trait4 = _entTraitArray[CompIdx.ArrayIndex()]; JaggedArray? jaggedArray1 = null; - if (CompIdx.GetArchetype()) - jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray2 = null; - if (CompIdx.GetArchetype()) - jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray3 = null; - if (CompIdx.GetArchetype()) - jaggedArray3 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray3 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray4 = null; - if (CompIdx.GetArchetype()) - jaggedArray4 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray4 = _entTraitJaggedArray[DenseComponent.Index]; return new AllEntityQueryEnumerator(trait1, trait2, trait3, trait4, jaggedArray1, jaggedArray2, jaggedArray3, jaggedArray4); } @@ -1563,8 +1563,8 @@ public EntityQueryEnumerator EntityQueryEnumerator() var trait1 = _entTraitArray[CompIdx.ArrayIndex()]; JaggedArray? jaggedArray = null; - if (CompIdx.GetArchetype()) - jaggedArray = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray = _entTraitJaggedArray[DenseComponent.Index]; return new EntityQueryEnumerator(trait1, MetaQuery, jaggedArray); } @@ -1577,12 +1577,12 @@ public EntityQueryEnumerator EntityQueryEnumerator()]; JaggedArray? jaggedArray1 = null; - if (CompIdx.GetArchetype()) - jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray2 = null; - if (CompIdx.GetArchetype()) - jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; return new EntityQueryEnumerator(trait1, trait2, MetaQuery, jaggedArray1, jaggedArray2); } @@ -1597,16 +1597,16 @@ public EntityQueryEnumerator EntityQueryEnumerator()]; JaggedArray? jaggedArray1 = null; - if (CompIdx.GetArchetype()) - jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray2 = null; - if (CompIdx.GetArchetype()) - jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray3 = null; - if (CompIdx.GetArchetype()) - jaggedArray3 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray3 = _entTraitJaggedArray[DenseComponent.Index]; return new EntityQueryEnumerator(trait1, trait2, trait3, MetaQuery, jaggedArray1, jaggedArray2, jaggedArray3); } @@ -1623,20 +1623,20 @@ public EntityQueryEnumerator EntityQueryEnumerat var trait4 = _entTraitArray[CompIdx.ArrayIndex()]; JaggedArray? jaggedArray1 = null; - if (CompIdx.GetArchetype()) - jaggedArray1 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray2 = null; - if (CompIdx.GetArchetype()) - jaggedArray2 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray3 = null; - if (CompIdx.GetArchetype()) - jaggedArray3 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray3 = _entTraitJaggedArray[DenseComponent.Index]; JaggedArray? jaggedArray4 = null; - if (CompIdx.GetArchetype()) - jaggedArray4 = _entTraitJaggedArray[ArchetypeComponent.Index]; + if (CompIdx.GetDense()) + jaggedArray4 = _entTraitJaggedArray[DenseComponent.Index]; return new EntityQueryEnumerator(trait1, trait2, trait3, trait4, MetaQuery, jaggedArray1, jaggedArray2, jaggedArray3, jaggedArray4); } @@ -2037,9 +2037,9 @@ public bool TryGetComponent(EntityUid uid, [NotNullWhen(true)] out TComp1? compo { if (_jaggedArray != null) { - if (_jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp) && !archetypeComp.Deleted) + if (_jaggedArray.TryGetValue(uid.Id, out IComponent denseComp) && !denseComp.Deleted) { - component = (TComp1) archetypeComp; + component = (TComp1) denseComp; return true; } } @@ -2094,7 +2094,7 @@ public bool HasComponent(EntityUid uid) { if (_jaggedArray != null) { - return _jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp) && !archetypeComp.Deleted; + return _jaggedArray.TryGetValue(uid.Id, out IComponent denseComp) && !denseComp.Deleted; } return _traitDict.TryGetValue(uid, out var comp) && !comp.Deleted; @@ -2127,9 +2127,9 @@ public bool Resolve(EntityUid uid, [NotNullWhen(true)] ref TComp1? component, bo if (_jaggedArray != null) { - if (_jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp) && !archetypeComp.Deleted) + if (_jaggedArray.TryGetValue(uid.Id, out IComponent denseComp) && !denseComp.Deleted) { - component = (TComp1)archetypeComp; + component = (TComp1)denseComp; return true; } } @@ -2193,8 +2193,8 @@ internal TComp1 GetComponentInternal(EntityUid uid) { if (_jaggedArray != null) { - if (_jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp)) - return (TComp1) archetypeComp; + if (_jaggedArray.TryGetValue(uid.Id, out IComponent denseComp)) + return (TComp1) denseComp; } else if (_traitDict.TryGetValue(uid, out var comp)) return (TComp1) comp; @@ -2227,9 +2227,9 @@ internal bool TryGetComponentInternal(EntityUid uid, [NotNullWhen(true)] out TCo { if (_jaggedArray != null) { - if (_jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp)) + if (_jaggedArray.TryGetValue(uid.Id, out IComponent denseComp)) { - component = (TComp1) archetypeComp; + component = (TComp1) denseComp; return true; } @@ -2256,7 +2256,7 @@ internal bool HasComponentInternal(EntityUid uid) { if (_jaggedArray != null) { - return _jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp) && !archetypeComp.Deleted; + return _jaggedArray.TryGetValue(uid.Id, out IComponent denseComp) && !denseComp.Deleted; } return _traitDict.TryGetValue(uid, out var comp) && !comp.Deleted; @@ -2277,9 +2277,9 @@ internal bool ResolveInternal(EntityUid uid, [NotNullWhen(true)] ref TComp1? com if (_jaggedArray != null) { - if (_jaggedArray.TryGetValue(uid.Id, out IComponent archetypeComp)) + if (_jaggedArray.TryGetValue(uid.Id, out IComponent denseComp)) { - component = (TComp1)archetypeComp; + component = (TComp1)denseComp; return true; } } From abf21091e3d720fde16a1116a9d5b7b32ce4bf4c Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 9 Jul 2026 17:17:01 -0700 Subject: [PATCH 4/8] Did you know Genaray made a thing for this --- .../GameObjects/EntityManager.Components.cs | 131 +++++++++--------- 1 file changed, 66 insertions(+), 65 deletions(-) diff --git a/Robust.Shared/GameObjects/EntityManager.Components.cs b/Robust.Shared/GameObjects/EntityManager.Components.cs index 7bd8d8f2e5b..8ae784f2686 100644 --- a/Robust.Shared/GameObjects/EntityManager.Components.cs +++ b/Robust.Shared/GameObjects/EntityManager.Components.cs @@ -37,6 +37,7 @@ public partial class EntityManager private const int ComponentCollectionCapacity = 1024; private const int EntityCapacity = 1024; private const int NetComponentCapacity = 8; + private const int DenseBucketSize = 512; private FrozenDictionary> _entTraitDict = FrozenDictionary>.Empty; @@ -44,7 +45,7 @@ private FrozenDictionary> _entTraitDict private Dictionary[] _entTraitArray = Array.Empty>(); - private JaggedArray[] _entTraitJaggedArray = Array.Empty>(); + private SparseJaggedArray[] _entTraitJaggedArray = Array.Empty>(); private readonly HashSet _deleteSet = new(TypeCapacity); @@ -109,7 +110,7 @@ private void RegisterComponents(IEnumerable components) foreach (ref var array in _entTraitJaggedArray.AsSpan()) { // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract - array ??= new JaggedArray(128); + array ??= new SparseJaggedArray(DenseBucketSize); } } _entTraitDict = traitDict.ToFrozenDictionary(); @@ -1252,7 +1253,7 @@ public EntityQuery GetEntityQuery() where TComp1 : IComponent var comps = _entTraitArray[CompIdx.ArrayIndex()]; DebugTools.Assert(comps != null, $"Unknown component: {typeof(TComp1).Name}"); - JaggedArray? jaggedArray = null; + SparseJaggedArray? jaggedArray = null; if (CompIdx.GetDense()) jaggedArray = _entTraitJaggedArray[DenseComponent.Index]; @@ -1478,7 +1479,7 @@ public AllEntityQueryEnumerator AllEntityQueryEnumerator() { var trait1 = _entTraitArray[CompIdx.ArrayIndex()]; - JaggedArray? jaggedArray = null; + SparseJaggedArray? jaggedArray = null; if (CompIdx.GetDense()) jaggedArray = _entTraitJaggedArray[DenseComponent.Index]; @@ -1492,11 +1493,11 @@ public AllEntityQueryEnumerator AllEntityQueryEnumerator()]; var trait2 = _entTraitArray[CompIdx.ArrayIndex()]; - JaggedArray? jaggedArray1 = null; + SparseJaggedArray? jaggedArray1 = null; if (CompIdx.GetDense()) jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray2 = null; + SparseJaggedArray? jaggedArray2 = null; if (CompIdx.GetDense()) jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; @@ -1512,15 +1513,15 @@ public AllEntityQueryEnumerator AllEntityQueryEnumerator var trait2 = _entTraitArray[CompIdx.ArrayIndex()]; var trait3 = _entTraitArray[CompIdx.ArrayIndex()]; - JaggedArray? jaggedArray1 = null; + SparseJaggedArray? jaggedArray1 = null; if (CompIdx.GetDense()) jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray2 = null; + SparseJaggedArray? jaggedArray2 = null; if (CompIdx.GetDense()) jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray3 = null; + SparseJaggedArray? jaggedArray3 = null; if (CompIdx.GetDense()) jaggedArray3 = _entTraitJaggedArray[DenseComponent.Index]; @@ -1538,19 +1539,19 @@ public AllEntityQueryEnumerator AllEntityQueryEn var trait3 = _entTraitArray[CompIdx.ArrayIndex()]; var trait4 = _entTraitArray[CompIdx.ArrayIndex()]; - JaggedArray? jaggedArray1 = null; + SparseJaggedArray? jaggedArray1 = null; if (CompIdx.GetDense()) jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray2 = null; + SparseJaggedArray? jaggedArray2 = null; if (CompIdx.GetDense()) jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray3 = null; + SparseJaggedArray? jaggedArray3 = null; if (CompIdx.GetDense()) jaggedArray3 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray4 = null; + SparseJaggedArray? jaggedArray4 = null; if (CompIdx.GetDense()) jaggedArray4 = _entTraitJaggedArray[DenseComponent.Index]; @@ -1562,7 +1563,7 @@ public EntityQueryEnumerator EntityQueryEnumerator() { var trait1 = _entTraitArray[CompIdx.ArrayIndex()]; - JaggedArray? jaggedArray = null; + SparseJaggedArray? jaggedArray = null; if (CompIdx.GetDense()) jaggedArray = _entTraitJaggedArray[DenseComponent.Index]; @@ -1576,11 +1577,11 @@ public EntityQueryEnumerator EntityQueryEnumerator()]; var trait2 = _entTraitArray[CompIdx.ArrayIndex()]; - JaggedArray? jaggedArray1 = null; + SparseJaggedArray? jaggedArray1 = null; if (CompIdx.GetDense()) jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray2 = null; + SparseJaggedArray? jaggedArray2 = null; if (CompIdx.GetDense()) jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; @@ -1596,15 +1597,15 @@ public EntityQueryEnumerator EntityQueryEnumerator()]; var trait3 = _entTraitArray[CompIdx.ArrayIndex()]; - JaggedArray? jaggedArray1 = null; + SparseJaggedArray? jaggedArray1 = null; if (CompIdx.GetDense()) jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray2 = null; + SparseJaggedArray? jaggedArray2 = null; if (CompIdx.GetDense()) jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray3 = null; + SparseJaggedArray? jaggedArray3 = null; if (CompIdx.GetDense()) jaggedArray3 = _entTraitJaggedArray[DenseComponent.Index]; @@ -1622,19 +1623,19 @@ public EntityQueryEnumerator EntityQueryEnumerat var trait3 = _entTraitArray[CompIdx.ArrayIndex()]; var trait4 = _entTraitArray[CompIdx.ArrayIndex()]; - JaggedArray? jaggedArray1 = null; + SparseJaggedArray? jaggedArray1 = null; if (CompIdx.GetDense()) jaggedArray1 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray2 = null; + SparseJaggedArray? jaggedArray2 = null; if (CompIdx.GetDense()) jaggedArray2 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray3 = null; + SparseJaggedArray? jaggedArray3 = null; if (CompIdx.GetDense()) jaggedArray3 = _entTraitJaggedArray[DenseComponent.Index]; - JaggedArray? jaggedArray4 = null; + SparseJaggedArray? jaggedArray4 = null; if (CompIdx.GetDense()) jaggedArray4 = _entTraitJaggedArray[DenseComponent.Index]; @@ -1954,9 +1955,9 @@ public NetComponentEnumerator(Dictionary dictionary) => { private readonly EntityManager _entMan; private readonly Dictionary _traitDict; - private readonly JaggedArray? _jaggedArray; + private readonly SparseJaggedArray? _jaggedArray; - internal EntityQuery(EntityManager entMan, Dictionary traitDict, JaggedArray? jaggedArray) + internal EntityQuery(EntityManager entMan, Dictionary traitDict, SparseJaggedArray? jaggedArray) { _entMan = entMan; _traitDict = traitDict; @@ -2468,12 +2469,12 @@ public struct EntityQueryEnumerator : IDisposable { private Dictionary.Enumerator _traitDict; private readonly EntityQuery _metaQuery; - private readonly JaggedArray? _jaggedArray; + private readonly SparseJaggedArray? _jaggedArray; public EntityQueryEnumerator( Dictionary traitDict, EntityQuery metaQuery, - JaggedArray? jaggedArray = null) + SparseJaggedArray? jaggedArray = null) { _traitDict = traitDict.GetEnumerator(); _metaQuery = metaQuery; @@ -2535,15 +2536,15 @@ public struct EntityQueryEnumerator : IDisposable private Dictionary.Enumerator _traitDict; private readonly Dictionary _traitDict2; private readonly EntityQuery _metaQuery; - private readonly JaggedArray? _jaggedArray1; - private readonly JaggedArray? _jaggedArray2; + private readonly SparseJaggedArray? _jaggedArray1; + private readonly SparseJaggedArray? _jaggedArray2; public EntityQueryEnumerator( Dictionary traitDict, Dictionary traitDict2, EntityQuery metaQuery, - JaggedArray? jaggedArray1 = null, - JaggedArray? jaggedArray2 = null) + SparseJaggedArray? jaggedArray1 = null, + SparseJaggedArray? jaggedArray2 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; @@ -2612,18 +2613,18 @@ public struct EntityQueryEnumerator : IDisposable private readonly Dictionary _traitDict2; private readonly Dictionary _traitDict3; private readonly EntityQuery _metaQuery; - private readonly JaggedArray? _jaggedArray1; - private readonly JaggedArray? _jaggedArray2; - private readonly JaggedArray? _jaggedArray3; + private readonly SparseJaggedArray? _jaggedArray1; + private readonly SparseJaggedArray? _jaggedArray2; + private readonly SparseJaggedArray? _jaggedArray3; public EntityQueryEnumerator( Dictionary traitDict, Dictionary traitDict2, Dictionary traitDict3, EntityQuery metaQuery, - JaggedArray? jaggedArray1 = null, - JaggedArray? jaggedArray2 = null, - JaggedArray? jaggedArray3 = null) + SparseJaggedArray? jaggedArray1 = null, + SparseJaggedArray? jaggedArray2 = null, + SparseJaggedArray? jaggedArray3 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; @@ -2707,10 +2708,10 @@ public struct EntityQueryEnumerator : IDisposabl private readonly Dictionary _traitDict3; private readonly Dictionary _traitDict4; private readonly EntityQuery _metaQuery; - private readonly JaggedArray? _jaggedArray1; - private readonly JaggedArray? _jaggedArray2; - private readonly JaggedArray? _jaggedArray3; - private readonly JaggedArray? _jaggedArray4; + private readonly SparseJaggedArray? _jaggedArray1; + private readonly SparseJaggedArray? _jaggedArray2; + private readonly SparseJaggedArray? _jaggedArray3; + private readonly SparseJaggedArray? _jaggedArray4; public EntityQueryEnumerator( Dictionary traitDict, @@ -2718,10 +2719,10 @@ public EntityQueryEnumerator( Dictionary traitDict3, Dictionary traitDict4, EntityQuery metaQuery, - JaggedArray? jaggedArray1 = null, - JaggedArray? jaggedArray2 = null, - JaggedArray? jaggedArray3 = null, - JaggedArray? jaggedArray4 = null) + SparseJaggedArray? jaggedArray1 = null, + SparseJaggedArray? jaggedArray2 = null, + SparseJaggedArray? jaggedArray3 = null, + SparseJaggedArray? jaggedArray4 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; @@ -2842,11 +2843,11 @@ public struct AllEntityQueryEnumerator : IDisposable where TComp1 : IComponent { private Dictionary.Enumerator _traitDict; - private readonly JaggedArray? _jaggedArray; + private readonly SparseJaggedArray? _jaggedArray; public AllEntityQueryEnumerator( Dictionary traitDict, - JaggedArray? jaggedArray = null) + SparseJaggedArray? jaggedArray = null) { _traitDict = traitDict.GetEnumerator(); _jaggedArray = jaggedArray; @@ -2896,14 +2897,14 @@ public struct AllEntityQueryEnumerator : IDisposable { private Dictionary.Enumerator _traitDict; private readonly Dictionary _traitDict2; - private readonly JaggedArray? _jaggedArray1; - private readonly JaggedArray? _jaggedArray2; + private readonly SparseJaggedArray? _jaggedArray1; + private readonly SparseJaggedArray? _jaggedArray2; public AllEntityQueryEnumerator( Dictionary traitDict, Dictionary traitDict2, - JaggedArray? jaggedArray1 = null, - JaggedArray? jaggedArray2 = null) + SparseJaggedArray? jaggedArray1 = null, + SparseJaggedArray? jaggedArray2 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; @@ -2964,17 +2965,17 @@ public struct AllEntityQueryEnumerator : IDisposable private Dictionary.Enumerator _traitDict; private readonly Dictionary _traitDict2; private readonly Dictionary _traitDict3; - private readonly JaggedArray? _jaggedArray1; - private readonly JaggedArray? _jaggedArray2; - private readonly JaggedArray? _jaggedArray3; + private readonly SparseJaggedArray? _jaggedArray1; + private readonly SparseJaggedArray? _jaggedArray2; + private readonly SparseJaggedArray? _jaggedArray3; public AllEntityQueryEnumerator( Dictionary traitDict, Dictionary traitDict2, Dictionary traitDict3, - JaggedArray? jaggedArray1 = null, - JaggedArray? jaggedArray2 = null, - JaggedArray? jaggedArray3 = null) + SparseJaggedArray? jaggedArray1 = null, + SparseJaggedArray? jaggedArray2 = null, + SparseJaggedArray? jaggedArray3 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; @@ -3049,20 +3050,20 @@ public struct AllEntityQueryEnumerator : IDispos private readonly Dictionary _traitDict2; private readonly Dictionary _traitDict3; private readonly Dictionary _traitDict4; - private readonly JaggedArray? _jaggedArray1; - private readonly JaggedArray? _jaggedArray2; - private readonly JaggedArray? _jaggedArray3; - private readonly JaggedArray? _jaggedArray4; + private readonly SparseJaggedArray? _jaggedArray1; + private readonly SparseJaggedArray? _jaggedArray2; + private readonly SparseJaggedArray? _jaggedArray3; + private readonly SparseJaggedArray? _jaggedArray4; public AllEntityQueryEnumerator( Dictionary traitDict, Dictionary traitDict2, Dictionary traitDict3, Dictionary traitDict4, - JaggedArray? jaggedArray1 = null, - JaggedArray? jaggedArray2 = null, - JaggedArray? jaggedArray3 = null, - JaggedArray? jaggedArray4 = null) + SparseJaggedArray? jaggedArray1 = null, + SparseJaggedArray? jaggedArray2 = null, + SparseJaggedArray? jaggedArray3 = null, + SparseJaggedArray? jaggedArray4 = null) { _traitDict = traitDict.GetEnumerator(); _traitDict2 = traitDict2; From 59c5a60bb5aa0501d04c96bd358ff1e23c60bf87 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 9 Jul 2026 17:20:58 -0700 Subject: [PATCH 5/8] I am not running an X3D CPU --- Robust.Shared/GameObjects/EntityManager.Components.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Robust.Shared/GameObjects/EntityManager.Components.cs b/Robust.Shared/GameObjects/EntityManager.Components.cs index 8ae784f2686..2e705b8006f 100644 --- a/Robust.Shared/GameObjects/EntityManager.Components.cs +++ b/Robust.Shared/GameObjects/EntityManager.Components.cs @@ -37,7 +37,7 @@ public partial class EntityManager private const int ComponentCollectionCapacity = 1024; private const int EntityCapacity = 1024; private const int NetComponentCapacity = 8; - private const int DenseBucketSize = 512; + private const int DenseBucketSize = 256; private FrozenDictionary> _entTraitDict = FrozenDictionary>.Empty; From 0d8710cfe58bcf001977726f6f1df2a6b179dd60 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 9 Jul 2026 17:28:48 -0700 Subject: [PATCH 6/8] Doc comments --- Robust.Shared/GameObjects/DenseComponentAttribute.cs | 5 +++++ Robust.Shared/GameObjects/EntityManager.Components.cs | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Robust.Shared/GameObjects/DenseComponentAttribute.cs b/Robust.Shared/GameObjects/DenseComponentAttribute.cs index c1ce903befb..4352b476623 100644 --- a/Robust.Shared/GameObjects/DenseComponentAttribute.cs +++ b/Robust.Shared/GameObjects/DenseComponentAttribute.cs @@ -3,6 +3,11 @@ namespace Robust.Shared.GameObjects; +/// +/// Makes component operations using this component type use an array lookup instead of a dictionary lookup +/// where possible, using more memory but improving performance for components that are used very often, such as +/// and +/// [AttributeUsage(AttributeTargets.Class, Inherited = false)] [BaseTypeRequired(typeof(IComponent))] public sealed class DenseComponentAttribute : Attribute; diff --git a/Robust.Shared/GameObjects/EntityManager.Components.cs b/Robust.Shared/GameObjects/EntityManager.Components.cs index 2e705b8006f..40e8e87365a 100644 --- a/Robust.Shared/GameObjects/EntityManager.Components.cs +++ b/Robust.Shared/GameObjects/EntityManager.Components.cs @@ -45,6 +45,9 @@ private FrozenDictionary> _entTraitDict private Dictionary[] _entTraitArray = Array.Empty>(); + /// + /// Holds components that are marked with + /// private SparseJaggedArray[] _entTraitJaggedArray = Array.Empty>(); private readonly HashSet _deleteSet = new(TypeCapacity); @@ -413,7 +416,7 @@ private void AddComponentInternal(EntityUid uid, T component, ComponentRegist if (CompIdx.GetDense()) { var array = _entTraitJaggedArray[DenseComponent.Index]; - array.EnsureCapacity(uid.Id); + array.EnsureCapacity(200_000_000); array.Add(uid.Id, component); } From e04a280fd0787fab63e9d65fa95ab36a9d42b24d Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 9 Jul 2026 17:44:55 -0700 Subject: [PATCH 7/8] Remove testing code --- Robust.Shared/GameObjects/EntityManager.Components.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Robust.Shared/GameObjects/EntityManager.Components.cs b/Robust.Shared/GameObjects/EntityManager.Components.cs index 40e8e87365a..95d70387ef3 100644 --- a/Robust.Shared/GameObjects/EntityManager.Components.cs +++ b/Robust.Shared/GameObjects/EntityManager.Components.cs @@ -415,8 +415,7 @@ private void AddComponentInternal(EntityUid uid, T component, ComponentRegist if (CompIdx.GetDense()) { - var array = _entTraitJaggedArray[DenseComponent.Index]; - array.EnsureCapacity(200_000_000); + var array = _entTraitJaggedArray[DenseComponent.Index] array.Add(uid.Id, component); } From 58a6c127209f67ea2d679080fb762025a48c6910 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 9 Jul 2026 17:46:22 -0700 Subject: [PATCH 8/8] Oop --- Robust.Shared/GameObjects/EntityManager.Components.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Robust.Shared/GameObjects/EntityManager.Components.cs b/Robust.Shared/GameObjects/EntityManager.Components.cs index 95d70387ef3..2e705b8006f 100644 --- a/Robust.Shared/GameObjects/EntityManager.Components.cs +++ b/Robust.Shared/GameObjects/EntityManager.Components.cs @@ -45,9 +45,6 @@ private FrozenDictionary> _entTraitDict private Dictionary[] _entTraitArray = Array.Empty>(); - /// - /// Holds components that are marked with - /// private SparseJaggedArray[] _entTraitJaggedArray = Array.Empty>(); private readonly HashSet _deleteSet = new(TypeCapacity); @@ -415,7 +412,8 @@ private void AddComponentInternal(EntityUid uid, T component, ComponentRegist if (CompIdx.GetDense()) { - var array = _entTraitJaggedArray[DenseComponent.Index] + var array = _entTraitJaggedArray[DenseComponent.Index]; + array.EnsureCapacity(uid.Id); array.Add(uid.Id, component); }