com.elestrago.unity.entitas-redux 3.4.2 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  ---
4
4
 
5
+ ## [3.5.1](https://gitlab.com/elestrago-pkg/entitas-redux/-/tags/3.5.1)
6
+
7
+ ### Changed
8
+
9
+ - Use `Memory<T>` instead `List<T>` in `Systems` for frequently update systems
10
+
11
+ ---
12
+
13
+ ## [3.5.0](https://gitlab.com/elestrago-pkg/entitas-redux/-/tags/3.5.0)
14
+
15
+ ### Changed
16
+
17
+ - Use `SingleMatcher` for context component matchers
18
+
19
+ ---
20
+
5
21
  ## [3.4.2](https://gitlab.com/elestrago-pkg/entitas-redux/-/tags/3.4.2)
6
22
 
7
23
  ### Added
@@ -0,0 +1,34 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.Reflection;
4
+
5
+ namespace EntitasRedux.Core.Libs
6
+ {
7
+ public static class ListReflectionExtensions
8
+ {
9
+ // We can cache the FieldInfo objects for a slight performance improvement
10
+ // This avoids looking them up every time the method is called.
11
+ private static class ListInternals<T>
12
+ {
13
+ public static readonly FieldInfo ItemsField =
14
+ typeof(List<T>).GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance);
15
+ }
16
+
17
+ /// <summary>
18
+ /// Gets a Span<T> over the internal storage of a List<T> using reflection.
19
+ /// WARNING: This is highly fragile and depends on the internal implementation of List<T>.
20
+ /// It may break in future .NET versions. Use with extreme caution.
21
+ /// </summary>
22
+ public static Memory<T> AsMemoryReflection<T>(this List<T> list)
23
+ {
24
+ if (list == null)
25
+ return Memory<T>.Empty;
26
+
27
+ // Get the internal array and size using the cached reflection info
28
+ var items = (T[])ListInternals<T>.ItemsField.GetValue(list);
29
+
30
+ // Create a span from the internal array, respecting the list's current size
31
+ return new Memory<T>(items, 0, list.Count);
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: d86ee5f912fa4e468ee172da6bfd7615
3
+ timeCreated: 1754457641
@@ -28,7 +28,13 @@ namespace JCMG.EntitasRedux
28
28
  public interface IMatcher<TEntity>
29
29
  where TEntity : class, IEntity
30
30
  {
31
+ /// <summary>
32
+ /// Initialized in context matcher implementation
33
+ /// </summary>
34
+ public static string[] ComponentNames;
35
+
31
36
  int[] Indices { get; }
37
+
32
38
  bool Matches(TEntity entity);
33
39
  }
34
- }
40
+ }
@@ -28,26 +28,13 @@ namespace JCMG.EntitasRedux
28
28
  public partial class Matcher<TEntity> : IAllOfMatcher<TEntity>
29
29
  where TEntity : class, IEntity
30
30
  {
31
- public string[] ComponentNames { get; set; }
32
-
33
31
  private int[] _allOfIndices;
34
32
  private int[] _anyOfIndices;
35
33
 
36
34
  private int[] _indices;
37
35
  private int[] _noneOfIndices;
38
36
 
39
- public int[] Indices
40
- {
41
- get
42
- {
43
- if (_indices == null)
44
- {
45
- _indices = MergeIndices(_allOfIndices, _anyOfIndices, _noneOfIndices);
46
- }
47
-
48
- return _indices;
49
- }
50
- }
37
+ public int[] Indices => _indices ??= MergeIndices(_allOfIndices, _anyOfIndices, _noneOfIndices);
51
38
 
52
39
  public int[] AllOfIndices => _allOfIndices;
53
40
 
@@ -84,8 +71,8 @@ namespace JCMG.EntitasRedux
84
71
  public bool Matches(TEntity entity)
85
72
  {
86
73
  return (_allOfIndices == null || entity.HasComponents(_allOfIndices)) &&
87
- (_anyOfIndices == null || entity.HasAnyComponent(_anyOfIndices)) &&
88
- (_noneOfIndices == null || !entity.HasAnyComponent(_noneOfIndices));
74
+ (_anyOfIndices == null || entity.HasAnyComponent(_anyOfIndices)) &&
75
+ (_noneOfIndices == null || !entity.HasAnyComponent(_noneOfIndices));
89
76
  }
90
77
  }
91
- }
78
+ }
@@ -33,46 +33,32 @@ namespace JCMG.EntitasRedux
33
33
  /// <summary>
34
34
  /// Lazy-loaded index buffer (ThreadStatic)
35
35
  /// </summary>
36
- private static List<int> IndexBuffer => _indexBufferThreadStatic = _indexBufferThreadStatic ?? new List<int>();
36
+ private static List<int> IndexBuffer => _indexBufferThreadStatic ??= new List<int>();
37
37
 
38
38
  /// <summary>
39
39
  /// Lazy-loaded index set buffer (ThreadStatic)
40
40
  /// </summary>
41
- private static HashSet<int> IndexSetBuffer => _indexSetBufferThreadStatic = _indexSetBufferThreadStatic ?? new HashSet<int>();
41
+ private static HashSet<int> IndexSetBuffer => _indexSetBufferThreadStatic ??= new HashSet<int>();
42
42
 
43
- [ThreadStatic]
44
- private static List<int> _indexBufferThreadStatic = new();
43
+ [ThreadStatic] private static List<int> _indexBufferThreadStatic = new();
45
44
 
46
- [ThreadStatic]
47
- private static HashSet<int> _indexSetBufferThreadStatic = new();
45
+ [ThreadStatic] private static HashSet<int> _indexSetBufferThreadStatic = new();
48
46
 
49
- public static IAllOfMatcher<TEntity> AllOf(params int[] indices)
47
+ public static IAllOfMatcher<TEntity> AllOf(params int[] indices) => new Matcher<TEntity>
50
48
  {
51
- var matcher = new Matcher<TEntity>();
52
- matcher._allOfIndices = DistinctIndices(indices);
53
- return matcher;
54
- }
49
+ _allOfIndices = DistinctIndices(indices)
50
+ };
55
51
 
56
52
  public static IAllOfMatcher<TEntity> AllOf(params IMatcher<TEntity>[] matchers)
57
- {
58
- var allOfMatcher = (Matcher<TEntity>)AllOf(MergeIndices(matchers));
59
- SetComponentNames(ref allOfMatcher, matchers);
60
- return allOfMatcher;
61
- }
53
+ => AllOf(MergeIndices(matchers));
62
54
 
63
- public static IAnyOfMatcher<TEntity> AnyOf(params int[] indices)
55
+ public static IAnyOfMatcher<TEntity> AnyOf(params int[] indices) => new Matcher<TEntity>
64
56
  {
65
- var matcher = new Matcher<TEntity>();
66
- matcher._anyOfIndices = DistinctIndices(indices);
67
- return matcher;
68
- }
57
+ _anyOfIndices = DistinctIndices(indices)
58
+ };
69
59
 
70
60
  public static IAnyOfMatcher<TEntity> AnyOf(params IMatcher<TEntity>[] matchers)
71
- {
72
- var anyOfMatcher = (Matcher<TEntity>)AnyOf(MergeIndices(matchers));
73
- SetComponentNames(ref anyOfMatcher, matchers);
74
- return anyOfMatcher;
75
- }
61
+ => AnyOf(MergeIndices(matchers));
76
62
 
77
63
  private static int[] MergeIndices(int[] allOfIndices, int[] anyOfIndices, int[] noneOfIndices)
78
64
  {
@@ -115,28 +101,6 @@ namespace JCMG.EntitasRedux
115
101
  return indices;
116
102
  }
117
103
 
118
- private static string[] GetComponentNames(IMatcher<TEntity>[] matchers)
119
- {
120
- for (var i = 0; i < matchers.Length; i++)
121
- {
122
- if (matchers[i] is Matcher<TEntity> matcher && matcher.ComponentNames != null)
123
- {
124
- return matcher.ComponentNames;
125
- }
126
- }
127
-
128
- return null;
129
- }
130
-
131
- private static void SetComponentNames(ref Matcher<TEntity> matcher, IMatcher<TEntity>[] matchers)
132
- {
133
- var componentNames = GetComponentNames(matchers);
134
- if (componentNames != null)
135
- {
136
- matcher.ComponentNames = componentNames;
137
- }
138
- }
139
-
140
104
  private static int[] DistinctIndices(IList<int> indices)
141
105
  {
142
106
  foreach (var index in indices)
@@ -153,4 +117,4 @@ namespace JCMG.EntitasRedux
153
117
  return uniqueIndices;
154
118
  }
155
119
  }
156
- }
120
+ }
@@ -29,55 +29,36 @@ namespace JCMG.EntitasRedux
29
29
  {
30
30
  public partial class Matcher<TEntity>
31
31
  {
32
- private StringBuilder _toStringBuilder;
32
+ private static StringBuilder _toStringBuilder;
33
33
 
34
34
  private string _toStringCache;
35
35
 
36
36
  public override string ToString()
37
37
  {
38
- if (_toStringCache == null)
39
- {
40
- if (_toStringBuilder == null)
41
- {
42
- _toStringBuilder = new StringBuilder();
43
- }
38
+ if (_toStringCache != null)
39
+ return _toStringCache;
44
40
 
45
- _toStringBuilder.Length = 0;
46
- if (_allOfIndices != null)
47
- {
48
- AppendIndices(
49
- _toStringBuilder,
50
- "AllOf",
51
- _allOfIndices,
52
- ComponentNames);
53
- }
41
+ _toStringBuilder ??= new StringBuilder();
42
+ _toStringBuilder.Length = 0;
54
43
 
55
- if (_anyOfIndices != null)
56
- {
57
- if (_allOfIndices != null)
58
- {
59
- _toStringBuilder.Append(".");
60
- }
61
-
62
- AppendIndices(
63
- _toStringBuilder,
64
- "AnyOf",
65
- _anyOfIndices,
66
- ComponentNames);
67
- }
44
+ var componentNames = IMatcher<TEntity>.ComponentNames;
68
45
 
69
- if (_noneOfIndices != null)
70
- {
71
- AppendIndices(
72
- _toStringBuilder,
73
- ".NoneOf",
74
- _noneOfIndices,
75
- ComponentNames);
76
- }
46
+ if (_allOfIndices != null)
47
+ AppendIndices(_toStringBuilder, "AllOf", _allOfIndices, componentNames);
77
48
 
78
- _toStringCache = _toStringBuilder.ToString();
49
+ if (_anyOfIndices != null)
50
+ {
51
+ if (_allOfIndices != null)
52
+ _toStringBuilder.Append(".");
53
+
54
+ AppendIndices(_toStringBuilder, "AnyOf", _anyOfIndices, componentNames);
79
55
  }
80
56
 
57
+ if (_noneOfIndices != null)
58
+ AppendIndices(_toStringBuilder, ".NoneOf", _noneOfIndices, componentNames);
59
+
60
+ _toStringCache = _toStringBuilder.ToString();
61
+
81
62
  return _toStringCache;
82
63
  }
83
64
 
@@ -108,4 +89,4 @@ namespace JCMG.EntitasRedux
108
89
  sb.Append(")");
109
90
  }
110
91
  }
111
- }
92
+ }
@@ -0,0 +1,27 @@
1
+ namespace JCMG.EntitasRedux
2
+ {
3
+ public class SingleMatcher<TEntity> : IMatcher<TEntity>
4
+ where TEntity : class, IEntity
5
+ {
6
+ private readonly int _index;
7
+
8
+ private string _toStringCache;
9
+
10
+ public SingleMatcher(int index)
11
+ {
12
+ _index = index;
13
+ Indices = new[] { index };
14
+ }
15
+
16
+ public int[] Indices { get; }
17
+
18
+ public bool Matches(TEntity entity) => entity.HasComponent(_index);
19
+
20
+ public override string ToString()
21
+ {
22
+ return string.IsNullOrEmpty(_toStringCache)
23
+ ? _toStringCache = $"AllOf({IMatcher<TEntity>.ComponentNames[_index]})"
24
+ : _toStringCache;
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: 0de81d27fdf948639fc5064d90d0bd2a
3
+ timeCreated: 1754409881
@@ -23,7 +23,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
23
  THE SOFTWARE.
24
24
  */
25
25
 
26
+ using System;
26
27
  using System.Collections.Generic;
28
+ using EntitasRedux.Core.Libs;
27
29
 
28
30
  namespace JCMG.EntitasRedux
29
31
  {
@@ -51,6 +53,11 @@ namespace JCMG.EntitasRedux
51
53
  protected readonly List<ICleanupSystem> _cleanupSystems;
52
54
  protected readonly List<ITearDownSystem> _tearDownSystems;
53
55
 
56
+ private Memory<IFixedUpdateSystem> _fixedUpdateSystemsMemory;
57
+ private Memory<IUpdateSystem> _updateSystemsMemory;
58
+ private Memory<ILateUpdateSystem> _lateUpdateSystemsMemory;
59
+ private Memory<ICleanupSystem> _cleanupSystemsMemory;
60
+
54
61
  /// <summary>
55
62
  /// Creates a new Systems instance.
56
63
  /// </summary>
@@ -157,9 +164,9 @@ namespace JCMG.EntitasRedux
157
164
  /// </summary>
158
165
  public virtual void Update()
159
166
  {
160
- for (var i = 0; i < _updateSystems.Count; i++)
167
+ foreach (var system in _updateSystemsMemory.Span)
161
168
  {
162
- _updateSystems[i].Update();
169
+ system.Update();
163
170
  }
164
171
  }
165
172
 
@@ -169,9 +176,9 @@ namespace JCMG.EntitasRedux
169
176
  /// </summary>
170
177
  public virtual void FixedUpdate()
171
178
  {
172
- for (var i = 0; i < _fixedUpdateSystems.Count; i++)
179
+ foreach (var system in _fixedUpdateSystemsMemory.Span)
173
180
  {
174
- _fixedUpdateSystems[i].FixedUpdate();
181
+ system.FixedUpdate();
175
182
  }
176
183
  }
177
184
 
@@ -181,9 +188,9 @@ namespace JCMG.EntitasRedux
181
188
  /// </summary>
182
189
  public virtual void LateUpdate()
183
190
  {
184
- for (var i = 0; i < _lateUpdateSystems.Count; i++)
191
+ foreach (var system in _lateUpdateSystemsMemory.Span)
185
192
  {
186
- _lateUpdateSystems[i].LateUpdate();
193
+ system.LateUpdate();
187
194
  }
188
195
  }
189
196
 
@@ -193,6 +200,8 @@ namespace JCMG.EntitasRedux
193
200
  /// </summary>
194
201
  public virtual void Initialize()
195
202
  {
203
+ PrepareUpdateSystems();
204
+
196
205
  for (var i = 0; i < _initializeSystems.Count; i++)
197
206
  {
198
207
  _initializeSystems[i].Initialize();
@@ -205,9 +214,9 @@ namespace JCMG.EntitasRedux
205
214
  /// </summary>
206
215
  public virtual void Cleanup()
207
216
  {
208
- for (var i = 0; i < _cleanupSystems.Count; i++)
217
+ foreach (var system in _cleanupSystemsMemory.Span)
209
218
  {
210
- _cleanupSystems[i].Cleanup();
219
+ system.Cleanup();
211
220
  }
212
221
  }
213
222
 
@@ -222,5 +231,13 @@ namespace JCMG.EntitasRedux
222
231
  _tearDownSystems[i].TearDown();
223
232
  }
224
233
  }
234
+
235
+ private void PrepareUpdateSystems()
236
+ {
237
+ _fixedUpdateSystemsMemory = _fixedUpdateSystems.AsMemoryReflection();
238
+ _updateSystemsMemory = _updateSystems.AsMemoryReflection();
239
+ _lateUpdateSystemsMemory = _lateUpdateSystems.AsMemoryReflection();
240
+ _cleanupSystemsMemory = _cleanupSystems.AsMemoryReflection();
241
+ }
225
242
  }
226
243
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.elestrago.unity.entitas-redux",
3
- "version": "3.4.2",
3
+ "version": "3.5.1",
4
4
  "displayName": "JCMG Entitas Redux",
5
5
  "description": "Entitas Redux is an fast, accessible, and feature-rich ECS framework for Unity. It leverages code generation and an extensible plugin framework to make life easier for developers.",
6
6
  "category": "Unity",