From 790e36b2d31877e9785ff73a6025646624a0d350 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 24 Oct 2019 13:13:43 -0700 Subject: [PATCH] graph logic depends on MoonTools.Core.Graph --- encompass-cs/Engine.cs | 26 +- encompass-cs/Graph/DirectedGraph.cs | 420 ---------------------------- encompass-cs/WorldBuilder.cs | 6 +- encompass-cs/encompass-cs.csproj | 5 +- test/DirectedGraphTest.cs | 374 ------------------------- test/WorldBuilderTest.cs | 13 +- 6 files changed, 42 insertions(+), 802 deletions(-) delete mode 100644 encompass-cs/Graph/DirectedGraph.cs delete mode 100644 test/DirectedGraphTest.cs diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index 17255c3..92f01d1 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -11,8 +11,10 @@ namespace Encompass /// They are responsible for reading the World state, reading messages, emitting messages, and creating or mutating Entities and Components. /// Engines run once per World Update. /// - public abstract class Engine + public abstract class Engine : IEquatable { + public Guid ID; + internal readonly HashSet sendTypes = new HashSet(); internal readonly HashSet receiveTypes = new HashSet(); internal readonly Dictionary writePriorities = new Dictionary(); @@ -24,6 +26,8 @@ namespace Encompass protected Engine() { + ID = Guid.NewGuid(); + var sendsAttribute = GetType().GetCustomAttribute(false); if (sendsAttribute != null) { @@ -62,6 +66,26 @@ namespace Encompass } } + public override bool Equals(object obj) + { + if (obj is Engine) + { + return this.Equals((Engine)obj); + } + + return false; + } + + public bool Equals(Engine other) + { + return other.ID == ID; + } + + public override int GetHashCode() + { + return ID.GetHashCode(); + } + internal void AssignEntityManager(EntityManager entityManager) { this.entityManager = entityManager; diff --git a/encompass-cs/Graph/DirectedGraph.cs b/encompass-cs/Graph/DirectedGraph.cs deleted file mode 100644 index b60db0d..0000000 --- a/encompass-cs/Graph/DirectedGraph.cs +++ /dev/null @@ -1,420 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; - -namespace Encompass -{ - public enum SearchSymbol - { - start, - finish - } - - public class DirectedGraph - { - private class SimpleCycleComparer : IEqualityComparer> - { - public bool Equals(IEnumerable x, IEnumerable y) - { - return x.SequenceEqual(y); - } - - public int GetHashCode(IEnumerable obj) - { - return obj.Aggregate(0, (current, next) => current.GetHashCode() ^ next.GetHashCode()); - } - } - - protected List _vertices = new List(); - protected Dictionary> _neighbors = new Dictionary>(); - - public IEnumerable Vertices { get { return _vertices; } } - - /* - * GRAPH STRUCTURE METHODS - */ - - public void AddVertex(T vertex) - { - if (!VertexExists(vertex)) - { - _vertices.Add(vertex); - _neighbors.Add(vertex, new HashSet()); - } - } - - public void AddVertices(params T[] vertices) - { - foreach (var vertex in vertices) - { - AddVertex(vertex); - } - } - - public bool VertexExists(T vertex) - { - return Vertices.Contains(vertex); - } - - public void RemoveVertex(T vertex) - { - var edgesToRemove = new List>(); - - if (VertexExists(vertex)) - { - foreach (var entry in _neighbors) - { - if (entry.Value.Contains(vertex)) - { - edgesToRemove.Add(Tuple.Create(entry.Key, vertex)); - } - } - - foreach (var edge in edgesToRemove) - { - RemoveEdge(edge.Item1, edge.Item2); - } - - _vertices.Remove(vertex); - _neighbors.Remove(vertex); - } - } - - public void AddEdge(T v, T u) - { - if (VertexExists(v) && VertexExists(u)) - { - _neighbors[v].Add(u); - } - } - - public void AddEdges(params Tuple[] edges) - { - foreach (var edge in edges) - { - AddEdge(edge.Item1, edge.Item2); - } - } - - public void RemoveEdge(T v, T u) - { - _neighbors[v].Remove(u); - } - - public IEnumerable Neighbors(T vertex) - { - if (VertexExists(vertex)) - { - return _neighbors[vertex]; - } - else - { - return Enumerable.Empty(); - } - } - - /* - * GRAPH ANALYSIS METHODS - */ - - public Dictionary> NodeDFS() - { - var discovered = new HashSet(); - uint time = 0; - var output = new Dictionary>(); - - foreach (var vertex in Vertices) - { - output.Add(vertex, new Dictionary()); - } - - void dfsHelper(T v) - { - discovered.Add(v); - time++; - output[v].Add(SearchSymbol.start, time); - - foreach (var neighbor in Neighbors(v)) - { - if (!discovered.Contains(neighbor)) - { - dfsHelper(neighbor); - } - } - - time++; - output[v].Add(SearchSymbol.finish, time); - } - - foreach (var vertex in Vertices) - { - if (!discovered.Contains(vertex)) - { - dfsHelper(vertex); - } - } - - return output; - } - - public bool Cyclic() - { - return StronglyConnectedComponents().Any((scc) => scc.Count() > 1); - } - - public IEnumerable TopologicalSort() - { - var dfs = NodeDFS(); - var priority = new SortedList(); - foreach (var entry in dfs) - { - priority.Add(entry.Value[SearchSymbol.finish], entry.Key); - } - return priority.Values.Reverse(); - } - - public IEnumerable> StronglyConnectedComponents() - { - var preorder = new Dictionary(); - var lowlink = new Dictionary(); - var sccFound = new Dictionary(); - var sccQueue = new Stack(); - - var result = new List>(); - - uint preorderCounter = 0; - - foreach (var source in Vertices) - { - if (!sccFound.ContainsKey(source)) - { - var queue = new Stack(); - queue.Push(source); - - while (queue.Count > 0) - { - var v = queue.Peek(); - if (!preorder.ContainsKey(v)) - { - preorderCounter++; - preorder[v] = preorderCounter; - } - - var done = true; - var vNeighbors = Neighbors(v); - foreach (var w in vNeighbors) - { - if (!preorder.ContainsKey(w)) - { - queue.Push(w); - done = false; - break; - } - } - - if (done) - { - lowlink[v] = preorder[v]; - foreach (var w in vNeighbors) - { - if (!sccFound.ContainsKey(w)) - { - if (preorder[w] > preorder[v]) - { - lowlink[v] = Math.Min(lowlink[v], lowlink[w]); - } - else - { - lowlink[v] = Math.Min(lowlink[v], preorder[w]); - } - } - } - queue.Pop(); - if (lowlink[v] == preorder[v]) - { - sccFound[v] = true; - var scc = new List - { - v - }; - while (sccQueue.Count > 0 && preorder[sccQueue.Peek()] > preorder[v]) - { - var k = sccQueue.Pop(); - sccFound[k] = true; - scc.Add(k); - } - result.Add(scc); - } - else - { - sccQueue.Push(v); - } - } - } - } - } - - return result; - } - - public IEnumerable> SimpleCycles() - { - void unblock(T thisnode, HashSet blocked, Dictionary> B) - { - var stack = new Stack(); - stack.Push(thisnode); - - while (stack.Count > 0) - { - var node = stack.Pop(); - if (blocked.Contains(thisnode)) - { - blocked.Remove(thisnode); - if (B.ContainsKey(node)) - { - foreach (var n in B[node]) - { - if (!stack.Contains(n)) - { - stack.Push(n); - } - } - B[node].Clear(); - } - } - } - } - - List> result = new List>(); - var subGraph = Clone(); - - var sccs = new Stack>(); - foreach (var scc in StronglyConnectedComponents()) - { - sccs.Push(scc); - } - - while (sccs.Count > 0) - { - var scc = new Stack(sccs.Pop()); - var startNode = scc.Pop(); - var path = new Stack(); - path.Push(startNode); - var blocked = new HashSet - { - startNode - }; - var closed = new HashSet(); - var B = new Dictionary>(); - var stack = new Stack>>(); - stack.Push(Tuple.Create(startNode, new Stack(subGraph.Neighbors(startNode)))); - - while (stack.Count > 0) - { - var entry = stack.Peek(); - var thisnode = entry.Item1; - var neighbors = entry.Item2; - - if (neighbors.Count > 0) - { - var nextNode = neighbors.Pop(); - - if (nextNode.Equals(startNode)) - { - var resultPath = new List(); - foreach (var v in path) - { - resultPath.Add(v); - } - result.Add(resultPath); - foreach (var v in path) - { - closed.Add(v); - } - } - else if (!blocked.Contains(nextNode)) - { - path.Push(nextNode); - stack.Push(Tuple.Create(nextNode, new Stack(subGraph.Neighbors(nextNode)))); - closed.Remove(nextNode); - blocked.Add(nextNode); - continue; - } - } - - if (neighbors.Count == 0) - { - if (closed.Contains(thisnode)) - { - unblock(thisnode, blocked, B); - } - else - { - foreach (var neighbor in subGraph.Neighbors(thisnode)) - { - if (!B.ContainsKey(neighbor)) - { - B[neighbor] = new HashSet(); - } - B[neighbor].Add(thisnode); - } - } - - stack.Pop(); - path.Pop(); - } - } - - subGraph.RemoveVertex(startNode); - var H = subGraph.SubGraph(scc.ToArray()); - var HSccs = H.StronglyConnectedComponents(); - foreach (var HScc in HSccs) - { - sccs.Push(HScc); - } - } - - return result.Distinct(new SimpleCycleComparer()); - } - - public DirectedGraph Clone() - { - var clone = new DirectedGraph(); - clone.AddVertices(Vertices.ToArray()); - - foreach (var v in Vertices) - { - foreach (var n in Neighbors(v)) - { - clone.AddEdge(v, n); - } - } - - return clone; - } - - public DirectedGraph SubGraph(params T[] subVertices) - { - var subGraph = new DirectedGraph(); - subGraph.AddVertices(subVertices.ToArray()); - - foreach (var v in Vertices) - { - if (Vertices.Contains(v)) - { - var neighbors = Neighbors(v); - foreach (var u in neighbors) - { - if (subVertices.Contains(u)) - { - subGraph.AddEdge(v, u); - } - } - } - } - - return subGraph; - } - } -} diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index f5c0a0a..7498caf 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -4,6 +4,8 @@ using System.Reflection; using System.Linq; using Encompass.Exceptions; using Encompass.Engines; +using MoonTools.Core.Graph; +using MoonTools.Core.Graph.Extensions; namespace Encompass { @@ -18,7 +20,7 @@ namespace Encompass public class WorldBuilder { private readonly List engines = new List(); - private readonly DirectedGraph engineGraph = new DirectedGraph(); + private readonly DirectedGraph engineGraph = GraphBuilder.DirectedGraph(); private readonly ComponentManager componentManager; private readonly EntityManager entityManager; @@ -102,7 +104,7 @@ namespace Encompass engine.AssignComponentMessageManager(componentMessageManager); engines.Add(engine); - engineGraph.AddVertex(engine); + engineGraph.AddNode(engine); var messageReceiveTypes = engine.receiveTypes; var messageSendTypes = engine.sendTypes; diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index 25db1eb..34fb166 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 Encompass @@ -24,5 +24,6 @@ + - + \ No newline at end of file diff --git a/test/DirectedGraphTest.cs b/test/DirectedGraphTest.cs deleted file mode 100644 index 2a3731e..0000000 --- a/test/DirectedGraphTest.cs +++ /dev/null @@ -1,374 +0,0 @@ -using NUnit.Framework; -using FluentAssertions; - -using System; -using System.Linq; - -using Encompass; -using System.Collections.Generic; - -namespace Tests -{ - public class DirectedGraphTest - { - [Test] - public void AddVertex() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertex(4); - - Assert.That(myGraph.Vertices, Does.Contain(4)); - } - - [Test] - public void AddVertices() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices(4, 20, 69); - - Assert.IsTrue(myGraph.VertexExists(4)); - Assert.IsTrue(myGraph.VertexExists(20)); - Assert.IsTrue(myGraph.VertexExists(69)); - } - - [Test] - public void AddEdge() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices(5, 6); - myGraph.AddEdge(5, 6); - - Assert.That(myGraph.Neighbors(5), Does.Contain(6)); - } - - [Test] - public void AddEdges() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices(1, 2, 3, 4); - myGraph.AddEdges( - Tuple.Create(1, 2), - Tuple.Create(2, 3), - Tuple.Create(2, 4), - Tuple.Create(3, 4) - ); - - Assert.That(myGraph.Neighbors(1), Does.Contain(2)); - Assert.That(myGraph.Neighbors(2), Does.Contain(3)); - Assert.That(myGraph.Neighbors(2), Does.Contain(4)); - Assert.That(myGraph.Neighbors(3), Does.Contain(4)); - Assert.That(myGraph.Neighbors(1), Does.Not.Contain(4)); - } - - [Test] - public void RemoveEdge() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices(1, 2, 3, 4); - myGraph.AddEdges( - Tuple.Create(1, 2), - Tuple.Create(2, 3), - Tuple.Create(2, 4), - Tuple.Create(3, 4) - ); - - myGraph.RemoveEdge(2, 3); - - Assert.That(myGraph.Neighbors(2), Does.Not.Contain(3)); - Assert.That(myGraph.Neighbors(2), Does.Contain(4)); - } - - [Test] - public void RemoveVertex() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices(1, 2, 3, 4); - myGraph.AddEdges( - Tuple.Create(1, 2), - Tuple.Create(2, 3), - Tuple.Create(2, 4), - Tuple.Create(3, 4) - ); - - myGraph.RemoveVertex(2); - - myGraph.Vertices.Should().NotContain(2); - myGraph.Neighbors(1).Should().NotContain(2); - myGraph.Neighbors(3).Should().Contain(4); - } - - [Test] - public void NodeDFS() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices('a', 'b', 'c', 'd'); - myGraph.AddEdges( - Tuple.Create('a', 'b'), - Tuple.Create('a', 'c'), - Tuple.Create('b', 'd') - ); - - var result = myGraph.NodeDFS(); - - Assert.That(result['a'][SearchSymbol.start], Is.EqualTo(1)); - Assert.That(result['a'][SearchSymbol.finish], Is.EqualTo(8)); - - Assert.That(result['b'][SearchSymbol.start], Is.EqualTo(2)); - Assert.That(result['b'][SearchSymbol.finish], Is.EqualTo(5)); - - Assert.That(result['c'][SearchSymbol.start], Is.EqualTo(6)); - Assert.That(result['c'][SearchSymbol.finish], Is.EqualTo(7)); - - Assert.That(result['d'][SearchSymbol.start], Is.EqualTo(3)); - Assert.That(result['d'][SearchSymbol.finish], Is.EqualTo(4)); - } - - [Test] - public void TopologicalSortSimple() - { - var simpleGraph = new DirectedGraph(); - simpleGraph.AddVertices('a', 'b', 'c', 'd'); - simpleGraph.AddEdges( - Tuple.Create('a', 'b'), - Tuple.Create('a', 'c'), - Tuple.Create('b', 'a'), - Tuple.Create('b', 'd') - ); - - Assert.That(simpleGraph.TopologicalSort(), Is.EqualTo(new char[] { 'a', 'c', 'b', 'd' })); - } - - [Test] - public void TopologicalSortComplex() - { - var complexGraph = new DirectedGraph(); - complexGraph.AddVertices('a', 'b', 'c', 'd', 'e', 'f', 'g', 't', 'm'); - complexGraph.AddEdges( - Tuple.Create('a', 'b'), - Tuple.Create('a', 'c'), - Tuple.Create('a', 'd'), - Tuple.Create('b', 'f'), - Tuple.Create('b', 'g'), - Tuple.Create('c', 'g'), - Tuple.Create('e', 't'), - Tuple.Create('t', 'm') - ); - - Assert.That( - complexGraph.TopologicalSort(), - Is.EqualTo(new char[] { 'e', 't', 'm', 'a', 'd', 'c', 'b', 'g', 'f' }) - ); - } - - [Test] - public void StronglyConnectedComponentsSimple() - { - var simpleGraph = new DirectedGraph(); - simpleGraph.AddVertices(1, 2, 3); - simpleGraph.AddEdges( - Tuple.Create(1, 2), - Tuple.Create(2, 3), - Tuple.Create(3, 2), - Tuple.Create(2, 1) - ); - - var result = simpleGraph.StronglyConnectedComponents(); - var scc = new int[] { 1, 2, 3 }; - - result.Should().ContainEquivalentOf(scc); - Assert.That(result.Count, Is.EqualTo(1)); - } - - [Test] - public void StronglyConnectedComponentsMedium() - { - var mediumGraph = new DirectedGraph(); - mediumGraph.AddVertices(1, 2, 3, 4); - mediumGraph.AddEdges( - Tuple.Create(1, 2), - Tuple.Create(1, 3), - Tuple.Create(1, 4), - Tuple.Create(4, 2), - Tuple.Create(3, 4), - Tuple.Create(2, 3) - ); - - var result = mediumGraph.StronglyConnectedComponents(); - var sccA = new int[] { 2, 3, 4 }; - var sccB = new int[] { 1 }; - - result.Should().ContainEquivalentOf(sccA); - result.Should().ContainEquivalentOf(sccB); - Assert.That(result.Count, Is.EqualTo(2)); - } - - [Test] - public void StronglyConnectedComponentsComplex() - { - var complexGraph = new DirectedGraph(); - complexGraph.AddVertices(1, 2, 3, 4, 5, 6, 7, 8); - complexGraph.AddEdges( - Tuple.Create(1, 2), - Tuple.Create(2, 3), - Tuple.Create(2, 8), - Tuple.Create(3, 4), - Tuple.Create(3, 7), - Tuple.Create(4, 5), - Tuple.Create(5, 3), - Tuple.Create(5, 6), - Tuple.Create(7, 4), - Tuple.Create(7, 6), - Tuple.Create(8, 1), - Tuple.Create(8, 7) - ); - - var result = complexGraph.StronglyConnectedComponents(); - var sccA = new int[] { 3, 4, 5, 7 }; - var sccB = new int[] { 1, 2, 8 }; - var sccC = new int[] { 6 }; - - result.Should().ContainEquivalentOf(sccA); - result.Should().ContainEquivalentOf(sccB); - result.Should().ContainEquivalentOf(sccC); - Assert.That(result.Count, Is.EqualTo(3)); - } - - [Test] - public void Clone() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices(1, 2, 3, 4); - myGraph.AddEdges( - Tuple.Create(1, 1), - Tuple.Create(1, 2), - Tuple.Create(2, 3), - Tuple.Create(2, 1), - Tuple.Create(3, 4) - ); - - var clone = myGraph.Clone(); - Assert.That(clone, Is.Not.EqualTo(myGraph)); - clone.Vertices.Should().BeEquivalentTo(1, 2, 3, 4); - clone.Neighbors(1).Should().BeEquivalentTo(1, 2); - clone.Neighbors(2).Should().BeEquivalentTo(3, 1); - clone.Neighbors(3).Should().BeEquivalentTo(4); - } - - [Test] - public void SubGraph() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices(1, 2, 3, 4); - myGraph.AddEdges( - Tuple.Create(1, 1), - Tuple.Create(1, 2), - Tuple.Create(2, 3), - Tuple.Create(2, 1), - Tuple.Create(3, 4) - ); - - var subGraph = myGraph.SubGraph(1, 2, 3); - subGraph.Vertices.Should().BeEquivalentTo(1, 2, 3); - subGraph.Neighbors(1).Should().BeEquivalentTo(1, 2); - subGraph.Neighbors(2).Should().BeEquivalentTo(1, 3); - subGraph.Neighbors(3).Should().NotContain(4); - } - - [Test] - public void SimpleCyclesSimple() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices(0, 1, 2); - myGraph.AddEdges( - Tuple.Create(0, 0), - Tuple.Create(0, 1), - Tuple.Create(0, 2), - Tuple.Create(1, 2), - Tuple.Create(2, 0), - Tuple.Create(2, 1), - Tuple.Create(2, 2) - ); - - var result = myGraph.SimpleCycles(); - - var cycleA = new int[] { 0 }; - var cycleB = new int[] { 0, 1, 2 }; - var cycleC = new int[] { 0, 2 }; - var cycleD = new int[] { 1, 2 }; - var cycleE = new int[] { 2 }; - - result.Should().ContainEquivalentOf(cycleA); - result.Should().ContainEquivalentOf(cycleB); - result.Should().ContainEquivalentOf(cycleC); - result.Should().ContainEquivalentOf(cycleD); - result.Should().ContainEquivalentOf(cycleE); - result.Should().HaveCount(5); - } - - [Test] - public void SimpleCyclesComplex() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); - myGraph.AddEdges( - Tuple.Create(0, 1), - Tuple.Create(1, 2), - Tuple.Create(2, 3), - Tuple.Create(3, 0), - Tuple.Create(0, 3), - Tuple.Create(3, 4), - Tuple.Create(4, 5), - Tuple.Create(5, 0), - Tuple.Create(0, 1), - Tuple.Create(1, 6), - Tuple.Create(6, 7), - Tuple.Create(7, 8), - Tuple.Create(8, 0), - Tuple.Create(8, 9) - ); - - var result = myGraph.SimpleCycles(); - var cycleA = new int[] { 0, 3 }; - var cycleB = new int[] { 0, 1, 2, 3, 4, 5 }; - var cycleC = new int[] { 0, 1, 2, 3 }; - var cycleD = new int[] { 0, 3, 4, 5 }; - var cycleE = new int[] { 0, 1, 6, 7, 8 }; - - result.Should().ContainEquivalentOf(cycleA); - result.Should().ContainEquivalentOf(cycleB); - result.Should().ContainEquivalentOf(cycleC); - result.Should().ContainEquivalentOf(cycleD); - result.Should().ContainEquivalentOf(cycleE); - result.Should().HaveCount(5); - } - - [Test] - public void Cyclic() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices(1, 2, 3, 4); - myGraph.AddEdges( - Tuple.Create(1, 2), - Tuple.Create(2, 3), - Tuple.Create(3, 1), - Tuple.Create(3, 4) - ); - - Assert.That(myGraph.Cyclic(), Is.True); - } - - [Test] - public void Acyclic() - { - var myGraph = new DirectedGraph(); - myGraph.AddVertices(1, 2, 3, 4); - myGraph.AddEdges( - Tuple.Create(1, 2), - Tuple.Create(2, 3), - Tuple.Create(3, 4) - ); - - Assert.That(myGraph.Cyclic(), Is.False); - } - } -} diff --git a/test/WorldBuilderTest.cs b/test/WorldBuilderTest.cs index 111b4ba..f1f84fa 100644 --- a/test/WorldBuilderTest.cs +++ b/test/WorldBuilderTest.cs @@ -462,13 +462,20 @@ namespace Tests { var worldBuilder = new WorldBuilder(); + worldBuilder.AddEngine(new AEngine()); + worldBuilder.AddEngine(new BEngine()); + worldBuilder.AddEngine(new CEngine()); + worldBuilder.AddEngine(new DEngine()); + + Assert.DoesNotThrow(() => worldBuilder.Build()); + + worldBuilder = new WorldBuilder(); + var engineA = worldBuilder.AddEngine(new AEngine()); var engineB = worldBuilder.AddEngine(new BEngine()); var engineC = worldBuilder.AddEngine(new CEngine()); var engineD = worldBuilder.AddEngine(new DEngine()); - Assert.DoesNotThrow(() => worldBuilder.Build()); - var world = worldBuilder.Build(); world.Update(0.01f); @@ -495,7 +502,7 @@ namespace Tests var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new ReadMessageEngine()); - worldBuilder.SendMessageDelayed(new AMessage {}, 0.5); + worldBuilder.SendMessageDelayed(new AMessage { }, 0.5); var world = worldBuilder.Build();