diff --git a/Entitas/Entitas/Systems/MultiReactiveSystem.cs b/Entitas/Entitas/Systems/MultiReactiveSystem.cs index 7749c460e..3d7fca010 100644 --- a/Entitas/Entitas/Systems/MultiReactiveSystem.cs +++ b/Entitas/Entitas/Systems/MultiReactiveSystem.cs @@ -12,16 +12,19 @@ public abstract class MultiReactiveSystem : IReactiveSystem where TContexts : class, IContexts { readonly ICollector[] _collectors; + readonly HashSet _collectedEntities; readonly List _buffer; string _toStringCache; protected MultiReactiveSystem(TContexts contexts) { _collectors = GetTrigger(contexts); + _collectedEntities = new HashSet(); _buffer = new List(); } protected MultiReactiveSystem(ICollector[] collectors) { _collectors = collectors; + _collectedEntities = new HashSet(); _buffer = new List(); } @@ -65,17 +68,18 @@ public void Execute() { for (int i = 0; i < _collectors.Length; i++) { var collector = _collectors[i]; if (collector.count != 0) { - foreach (var e in collector.GetCollectedEntities()) { - if (Filter(e)) { - e.Retain(this); - _buffer.Add(e); - } - } - + _collectedEntities.UnionWith(collector.GetCollectedEntities()); collector.ClearCollectedEntities(); } } + foreach (var e in _collectedEntities) { + if (Filter(e)) { + e.Retain(this); + _buffer.Add(e); + } + } + if (_buffer.Count != 0) { try { Execute(_buffer); @@ -83,6 +87,7 @@ public void Execute() { for (int i = 0; i < _buffer.Count; i++) { _buffer[i].Release(this); } + _collectedEntities.Clear(); _buffer.Clear(); } } diff --git a/Tests/Tests/Fixtures/Systems/MultiTriggeredMultiReactiveSystemSpy.cs b/Tests/Tests/Fixtures/Systems/MultiTriggeredMultiReactiveSystemSpy.cs new file mode 100644 index 000000000..147e4ca12 --- /dev/null +++ b/Tests/Tests/Fixtures/Systems/MultiTriggeredMultiReactiveSystemSpy.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using Entitas; + +public class MultiTriggeredMultiReactiveSystemSpy : MultiReactiveSystem { + + public int didExecute { get { return _didExecute; } } + public IEntity[] entities { get { return _entities; } } + + public Action> executeAction; + + protected int _didExecute; + protected IEntity[] _entities; + + public MultiTriggeredMultiReactiveSystemSpy(Contexts contexts) : base(contexts) { + } + + protected override ICollector[] GetTrigger(Contexts contexts) { + return new ICollector[] { + contexts.test.CreateCollector(TestMatcher.NameAge), + contexts.test.CreateCollector(TestMatcher.NameAge.Removed()) + }; + } + + protected override bool Filter(IMyEntity entity) { + return true; + } + + protected override void Execute(List entities) { + _didExecute += 1; + + if (entities != null) { + _entities = entities.ToArray(); + } else { + _entities = null; + } + + if (executeAction != null) { + executeAction(entities); + } + } +} diff --git a/Tests/Tests/Tests.csproj b/Tests/Tests/Tests.csproj index a6c6dd3b8..2e06119f7 100644 --- a/Tests/Tests/Tests.csproj +++ b/Tests/Tests/Tests.csproj @@ -52,6 +52,7 @@ + diff --git a/Tests/Tests/Tests/Entitas/describe_MultiReactiveSystem.cs b/Tests/Tests/Tests/Entitas/describe_MultiReactiveSystem.cs index 76ededa84..e7c4b70e7 100644 --- a/Tests/Tests/Tests/Entitas/describe_MultiReactiveSystem.cs +++ b/Tests/Tests/Tests/Entitas/describe_MultiReactiveSystem.cs @@ -4,43 +4,82 @@ class describe_MultiReactiveSystem : nspec { void when_executing() { - MultiReactiveSystemSpy system = null; - TestEntity e1 = null; - Test2Entity e2 = null; + context["when triggered"] = () => { - before = () => { - var contexts = new Contexts(); - system = new MultiReactiveSystemSpy(contexts); - system.executeAction = entities => { - foreach (var e in entities) { - e.nameAge.age += 10; - } + MultiReactiveSystemSpy system = null; + TestEntity e1 = null; + Test2Entity e2 = null; + + before = () => { + var contexts = new Contexts(); + system = new MultiReactiveSystemSpy(contexts); + system.executeAction = entities => { + foreach (var e in entities) { + e.nameAge.age += 10; + } + }; + + e1 = contexts.test.CreateEntity(); + e1.AddNameAge("Max", 42); + + e2 = contexts.test2.CreateEntity(); + e2.AddNameAge("Jack", 24); + + system.Execute(); }; - e1 = contexts.test.CreateEntity(); - e1.AddNameAge("Max", 42); + it["processes entities from different contexts"] = () => { + system.entities.Length.should_be(2); + system.entities.should_contain(e1); + system.entities.should_contain(e2); - e2 = contexts.test2.CreateEntity(); - e2.AddNameAge("Jack", 24); + e1.nameAge.age.should_be(52); + e2.nameAge.age.should_be(34); + }; - system.Execute(); - }; + it["executes once"] = () => { + system.didExecute.should_be(1); + }; - it["processes entities from different contexts"] = () => { - system.entities.Length.should_be(2); - system.entities.should_contain(e1); - system.entities.should_contain(e2); + it["retains once even when multiple collectors contain entity"] = () => { + system.didExecute.should_be(1); + }; - e1.nameAge.age.should_be(52); - e2.nameAge.age.should_be(34); + it["can ToString"] = () => { + system.ToString().should_be("MultiReactiveSystem(MultiReactiveSystemSpy)"); + }; }; - it["executes once"] = () => { - system.didExecute.should_be(1); - }; - it["can ToString"] = () => { - system.ToString().should_be("MultiReactiveSystem(MultiReactiveSystemSpy)"); + + context["when multiple collectors are triggered with same entity"] = () => { + + MultiTriggeredMultiReactiveSystemSpy system = null; + TestEntity e1 = null; + + before = () => { + var contexts = new Contexts(); + system = new MultiTriggeredMultiReactiveSystemSpy(contexts); + e1 = contexts.test.CreateEntity(); + e1.AddNameAge("Max", 42); + + e1.RemoveNameAge(); + + system.Execute(); + }; + + it["executes once"] = () => { + system.didExecute.should_be(1); + }; + + it["merges collected entities and removes duplicates"] = () => { + system.entities.Length.should_be(1); + }; + + it["clears merged collected entities"] = () => { + system.Execute(); + system.didExecute.should_be(1); + }; }; } }