com.elestrago.unity.entitas-redux 3.2.5 → 3.3.0

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,18 @@
2
2
 
3
3
  ---
4
4
 
5
+ ## [3.3.0](https://gitlab.com/elestrago-pkg/entitas-redux/-/tags/3.3.0)
6
+
7
+ ### Added
8
+
9
+ - `Register<TCommand>` method to `ICommandBuffer` for create pool
10
+
11
+ ### Changed
12
+
13
+ - Create new command only allow for registered commands
14
+
15
+ ---
16
+
5
17
  ## [3.2.5](https://gitlab.com/elestrago-pkg/entitas-redux/-/tags/3.2.5)
6
18
 
7
19
  ### Fixed
@@ -1,56 +1,114 @@
1
1
  using System;
2
- using System.Collections.Generic;
2
+ using System.Threading;
3
3
 
4
4
  namespace JCMG.EntitasRedux.Commands
5
5
  {
6
- public abstract class CommandBuffer : ICommandBuffer, IDisposable
6
+ public abstract class CommandBuffer : ICommandBuffer
7
7
  {
8
- private static readonly List<Func<ICommandPool>> PoolFactories = new();
8
+ // Helper to get a unique, static index for each command type.
9
+ private static class CommandType
10
+ {
11
+ private static int _indexCounter;
9
12
 
10
- private static int _commandsCounter;
11
- private static event Action<Func<ICommandPool>> PoolFactoryRegister;
13
+ internal static class Index<TCommand> where TCommand : struct
14
+ {
15
+ // This value is calculated once per TCommand and cached.
16
+ public static readonly int Value = Interlocked.Increment(ref _indexCounter) - 1;
17
+ }
18
+ }
12
19
 
13
- private readonly List<ICommandPool> _pools = new();
20
+ // Use a raw array for performance. It's not readonly because we resize it.
21
+ private ICommandPool[] _pools = new ICommandPool[4];
14
22
 
15
- protected CommandBuffer()
23
+ /// <summary>
24
+ /// Registers a pool for the specified command type. This must be called
25
+ /// before creating or accessing commands of this type.
26
+ /// </summary>
27
+ public void Register<TCommand>() where TCommand : struct
16
28
  {
17
- lock (PoolFactories)
29
+ var index = CommandType.Index<TCommand>.Value;
30
+
31
+ // Ensure the array is large enough, resizing if necessary.
32
+ if (index >= _pools.Length)
18
33
  {
19
- foreach (var poolFactory in PoolFactories)
20
- _pools.Add(poolFactory());
34
+ // Resize to the exact size needed to include the new index.
35
+ Array.Resize(ref _pools, index + 1);
21
36
  }
22
37
 
23
- PoolFactoryRegister += OnPoolFactoryRegister;
38
+ // Create the pool if it doesn't exist for this buffer instance.
39
+ ref var commandPool = ref _pools[index];
40
+ commandPool ??= new CommandPool<TCommand>();
24
41
  }
25
42
 
26
- public void Dispose()
43
+ public ref TCommand Create<TCommand>() where TCommand : struct
27
44
  {
28
- PoolFactoryRegister -= OnPoolFactoryRegister;
29
- }
45
+ var pool = GetPool<TCommand>();
46
+ if (pool != null)
47
+ return ref pool.Create();
30
48
 
31
- private void OnPoolFactoryRegister(Func<ICommandPool> poolFactory) => _pools.Add(poolFactory());
49
+ #if DEBUG
50
+ throw new Exception($"[CommandBuffer] Command type '{typeof(TCommand).Name}' is not registered. " +
51
+ $"Call Register<{typeof(TCommand).Name}>() first. Command will be ignored.");
52
+ #endif
32
53
 
33
- public ref TCommand Create<TCommand>() where TCommand : struct
34
- {
35
- var pool = _pools[CommandPool<TCommand>.Index] as CommandPool<TCommand>;
36
- return ref pool.Create();
54
+ // Return a reference to a dummy variable to satisfy the ref return.
55
+ return ref Dummy<TCommand>.Value;
37
56
  }
38
57
 
39
58
  public void Create<TCommand>(TCommand command) where TCommand : struct
40
59
  {
41
- var pool = _pools[CommandPool<TCommand>.Index] as CommandPool<TCommand>;
42
- pool.Create(command);
60
+ var pool = GetPool<TCommand>();
61
+ if (pool != null)
62
+ {
63
+ pool.Create(command);
64
+ return;
65
+ }
66
+
67
+ #if DEBUG
68
+ throw new Exception($"[CommandBuffer] Command type '{typeof(TCommand).Name}' is not registered. " +
69
+ $"Call Register<{typeof(TCommand).Name}>() first. Command will be ignored.");
70
+ #endif
43
71
  }
44
72
 
45
73
  public Span<TCommand> GetCommands<TCommand>() where TCommand : struct
46
74
  {
47
- var pool = _pools[CommandPool<TCommand>.Index] as CommandPool<TCommand>;
48
- return pool.Read();
75
+ var pool = GetPool<TCommand>();
76
+ return pool != null ? pool.Read() : Span<TCommand>.Empty;
77
+ }
78
+
79
+ private CommandPool<TCommand> GetPool<TCommand>() where TCommand : struct
80
+ {
81
+ var index = CommandType.Index<TCommand>.Value;
82
+
83
+ // Use .Length for array boundary check.
84
+ if (index >= _pools.Length)
85
+ return null;
86
+
87
+ return _pools[index] as CommandPool<TCommand>;
49
88
  }
50
89
 
51
90
  public void Clear<TCommand>() where TCommand : struct
52
- => _pools[CommandPool<TCommand>.Index].Clear();
91
+ {
92
+ var index = CommandType.Index<TCommand>.Value;
93
+
94
+ // Use .Length for array boundary check.
95
+ if (index < _pools.Length)
96
+ _pools[index]?.Clear();
97
+ }
53
98
 
99
+ public void ClearAll()
100
+ {
101
+ for (var i = 0; i < _pools.Length; i++)
102
+ _pools[i]?.Clear();
103
+ }
104
+
105
+ // A helper to provide a valid ref return when a pool doesn't exist.
106
+ private static class Dummy<T> where T : struct
107
+ {
108
+ public static T Value;
109
+ }
110
+
111
+ // The interface and pool implementation are now much simpler.
54
112
  private interface ICommandPool
55
113
  {
56
114
  void Clear();
@@ -59,23 +117,9 @@ namespace JCMG.EntitasRedux.Commands
59
117
  private class CommandPool<TCommand> : ICommandPool
60
118
  where TCommand : struct
61
119
  {
62
- public static readonly int Index;
63
-
64
120
  private TCommand[] _pool = new TCommand[4];
65
121
  private int _position;
66
122
 
67
- static CommandPool()
68
- {
69
- lock (PoolFactories)
70
- {
71
- Index = _commandsCounter++;
72
- PoolFactories.Add(Factory);
73
- PoolFactoryRegister?.Invoke(Factory);
74
- }
75
- }
76
-
77
- private static CommandPool<TCommand> Factory() => new();
78
-
79
123
  public ref TCommand Create()
80
124
  {
81
125
  var position = _position++;
@@ -98,8 +142,9 @@ namespace JCMG.EntitasRedux.Commands
98
142
 
99
143
  public void Clear()
100
144
  {
145
+ // Clear only the portion of the array that was used.
146
+ Array.Clear(_pool, 0, _position);
101
147
  _position = 0;
102
- Array.Clear(_pool, 0, _pool.Length);
103
148
  }
104
149
  }
105
150
  }
@@ -4,6 +4,12 @@ namespace JCMG.EntitasRedux.Commands
4
4
  {
5
5
  public interface ICommandBuffer
6
6
  {
7
+ /// <summary>
8
+ /// Registers a pool for the specified command type. This must be called
9
+ /// before creating or accessing commands of this type.
10
+ /// </summary>
11
+ void Register<TCommand>() where TCommand : struct;
12
+
7
13
  ref TCommand Create<TCommand>() where TCommand : struct;
8
14
 
9
15
  void Create<TCommand>(TCommand command) where TCommand : struct;
@@ -11,5 +17,7 @@ namespace JCMG.EntitasRedux.Commands
11
17
  Span<TCommand> GetCommands<TCommand>() where TCommand : struct;
12
18
 
13
19
  void Clear<TCommand>() where TCommand : struct;
20
+
21
+ void ClearAll();
14
22
  }
15
23
  }
@@ -6,12 +6,18 @@ namespace JCMG.EntitasRedux.Commands
6
6
  where TCommand : struct
7
7
  {
8
8
  private readonly ICommandBuffer _commandBuffer;
9
+ private readonly bool _cleanUp;
9
10
 
10
- protected virtual bool CleanUp => true;
11
-
12
- protected CommandSystem(ICommandBuffer commandBuffer)
11
+ protected CommandSystem(ICommandBuffer commandBuffer, bool cleanUp = true)
13
12
  {
14
13
  _commandBuffer = commandBuffer;
14
+ _cleanUp = cleanUp;
15
+
16
+ // We only need to register the command type with the buffer if this system
17
+ // is responsible for cleaning it up. The buffer uses this registration to
18
+ // know which command types to manage for its internal collections.
19
+ if (_cleanUp)
20
+ _commandBuffer.Register<TCommand>();
15
21
  }
16
22
 
17
23
  protected void ExecuteCommands()
@@ -21,7 +27,7 @@ namespace JCMG.EntitasRedux.Commands
21
27
  return;
22
28
 
23
29
  Execute(commands);
24
- if (CleanUp)
30
+ if (_cleanUp)
25
31
  _commandBuffer.Clear<TCommand>();
26
32
  }
27
33
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.elestrago.unity.entitas-redux",
3
- "version": "3.2.5",
3
+ "version": "3.3.0",
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",