From cbde7d8f4a8bc5df79c5bc8c3d6cebd2be11d66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastiano=20Mandal=C3=A0?= Date: Sat, 11 Nov 2017 10:37:41 +0000 Subject: [PATCH 01/22] working on the new typesafe svelto.ecs --- DataStructures/FasterList.cs | 20 +- DataStructures/IGraphNode.cs | 16 + .../LeftLeaningKeyedRedBlackTree.cs | 627 ++++++++++++++ DataStructures/LeftLeaningRedBlackTree.cs | 789 ++++++++++++++++++ DataStructures/PriorityQueue.cs | 108 +++ ECS/DataStructures/TypeSafeDictionary.cs | 23 + ECS/DataStructures/TypeSafeList.cs | 51 ++ ECS/EngineNodeDB.cs | 60 +- ECS/EnginesRoot.cs | 592 ++++++------- ECS/EntityDescriptor.cs | 274 +++--- .../Unity/UnitySumbmissionNodeScheduler.cs | 8 + ECS/GenericEntityDescriptor.cs | 19 + ECS/GenericEntityDescriptorHolder.cs | 3 +- ECS/IEngine.cs | 11 +- ECS/IEngineNodeDB.cs | 15 +- ECS/INode.cs | 9 +- ECS/MultiNodesEngine.cs | 87 +- ECS/NodeBuilder.cs | 77 ++ .../EngineProfiler/EngineProfilerInspector.cs | 2 +- ECS/Profiler/EngineProfiler.cs | 18 +- ECS/Profiler/EngineProfilerBehaviour.cs | 2 +- ECS/SingleNodeEngine.cs | 26 +- ECS/StructNodes.cs | 91 +- Factories/IGameObjectFactory.cs | 2 + Factories/IMonoBehaviourFactory.cs | 3 + Observer/Observable.cs | 42 + Observer/Observer.cs | 111 +++ Utilities/Console.cs | 37 +- Utilities/NetFXCoreWrappers.cs | 125 +++ Utilities/ThreadUtility.cs | 16 + WeakEvents/WeakAction.cs | 9 +- WeakEvents/WeakActionStruct.cs | 10 +- WeakEvents/WeakEvent.cs | 47 +- 33 files changed, 2708 insertions(+), 622 deletions(-) create mode 100644 DataStructures/IGraphNode.cs create mode 100644 DataStructures/LeftLeaningKeyedRedBlackTree.cs create mode 100644 DataStructures/LeftLeaningRedBlackTree.cs create mode 100644 DataStructures/PriorityQueue.cs create mode 100644 ECS/DataStructures/TypeSafeDictionary.cs create mode 100644 ECS/DataStructures/TypeSafeList.cs create mode 100644 ECS/NodeBuilder.cs create mode 100644 Observer/Observable.cs create mode 100644 Observer/Observer.cs create mode 100644 Utilities/NetFXCoreWrappers.cs create mode 100644 Utilities/ThreadUtility.cs diff --git a/DataStructures/FasterList.cs b/DataStructures/FasterList.cs index d87c13b..cfd9825 100644 --- a/DataStructures/FasterList.cs +++ b/DataStructures/FasterList.cs @@ -466,10 +466,7 @@ namespace Svelto.DataStructures readonly FasterList _list; } - public interface IFasterList - {} - - public class FasterList : IList, IFasterList + public class FasterList : IList { const int MIN_SIZE = 4; @@ -562,7 +559,7 @@ namespace Svelto.DataStructures while (items.MoveNext()) _buffer[_count++] = items.Current; } - + public void AddRange(ICollection items) { AddRange(items.GetEnumerator(), items.Count); @@ -803,5 +800,18 @@ namespace Svelto.DataStructures T[] _buffer; int _count; + + public static class NoVirt + { + public static int Count(FasterList fasterList) + { + return fasterList._count; + } + + public static T[] ToArrayFast(FasterList fasterList) + { + return fasterList._buffer; + } + } } } diff --git a/DataStructures/IGraphNode.cs b/DataStructures/IGraphNode.cs new file mode 100644 index 0000000..05a8c8e --- /dev/null +++ b/DataStructures/IGraphNode.cs @@ -0,0 +1,16 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18408 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ +using System; + +public interface IGraphNode +{ + void VisitNeighbours(System.Action onVisiting); +} + diff --git a/DataStructures/LeftLeaningKeyedRedBlackTree.cs b/DataStructures/LeftLeaningKeyedRedBlackTree.cs new file mode 100644 index 0000000..0de1ae1 --- /dev/null +++ b/DataStructures/LeftLeaningKeyedRedBlackTree.cs @@ -0,0 +1,627 @@ +// Uncomment this to enable the following debugging aids: +// LeftLeaningRedBlackTree.HtmlFragment +// LeftLeaningRedBlackTree.Node.HtmlFragment +// LeftLeaningRedBlackTree.AssertInvariants +// #define DEBUGGING + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +/// +/// Implements a left-leaning red-black tree. +/// +/// +/// Based on the research paper "Left-leaning Red-Black Trees" +/// by Robert Sedgewick. More information available at: +/// http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf +/// http://www.cs.princeton.edu/~rs/talks/LLRB/08Penn.pdf +/// +/// Type of keys. +public class LeftLeaningKeyedRedBlackTree where TKey: IComparable +{ + /// + /// Stores the root node of the tree. + /// + private Node _rootNode; + + /// + /// Represents a node of the tree. + /// + /// + /// Using fields instead of properties drops execution time by about 40%. + /// + [DebuggerDisplay("Key={Key}")] + private class Node + { + /// + /// Gets or sets the node's key. + /// + public TKey Key; + + /// + /// Gets or sets the left node. + /// + public Node Left; + + /// + /// Gets or sets the right node. + /// + public Node Right; + + /// + /// Gets or sets the color of the node. + /// + public bool IsBlack; + +#if DEBUGGING + /// + /// Gets an HTML fragment representing the node and its children. + /// + public string HtmlFragment + { + get + { + return + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "
" + Key + ", " + Value + " [" + Siblings + "]
" + (null != Left ? Left.HtmlFragment : "[null]") + "" + (null != Right ? Right.HtmlFragment : "[null]") + "
"; + } + } +#endif + } + + /// + /// Adds a key/value pair to the tree. + /// + /// Key to add. + public void Add(TKey key) + { + _rootNode = Add(_rootNode, key); + _rootNode.IsBlack = true; +#if DEBUGGING + AssertInvariants(); +#endif + } + + /// + /// Removes a key/value pair from the tree. + /// + /// Key to remove. + /// True if key/value present and removed. + public bool Remove(TKey key) + { + int initialCount = Count; + if (null != _rootNode) + { + _rootNode = Remove(_rootNode, key); + if (null != _rootNode) + { + _rootNode.IsBlack = true; + } + } +#if DEBUGGING + AssertInvariants(); +#endif + return initialCount != Count; + } + + /// + /// Removes all nodes in the tree. + /// + public void Clear() + { + _rootNode = null; + Count = 0; +#if DEBUGGING + AssertInvariants(); +#endif + } + + /// + /// Gets a sorted list of keys in the tree. + /// + /// Sorted list of keys. + public IEnumerable GetKeys() + { + TKey lastKey = default(TKey); + bool lastKeyValid = false; + return Traverse( + _rootNode, + n => !lastKeyValid || !object.Equals(lastKey, n.Key), + n => + { + lastKey = n.Key; + lastKeyValid = true; + return lastKey; + }); + } + + /// + /// Gets the count of key/value pairs in the tree. + /// + public int Count { get; private set; } + + /// + /// Gets the minimum key in the tree. + /// + public TKey MinimumKey + { + get { return GetExtreme(_rootNode, n => n.Left, n => n.Key); } + } + + /// + /// Gets the maximum key in the tree. + /// + public TKey MaximumKey + { + get { return GetExtreme(_rootNode, n => n.Right, n => n.Key); } + } + + /// + /// Returns true if the specified node is red. + /// + /// Specified node. + /// True if specified node is red. + private static bool IsRed(Node node) + { + if (null == node) + { + // "Virtual" leaf nodes are always black + return false; + } + return !node.IsBlack; + } + + /// + /// Adds the specified key/value pair below the specified root node. + /// + /// Specified node. + /// Key to add. + /// Value to add. + /// New root node. + private Node Add(Node node, TKey key) + { + if (null == node) + { + // Insert new node + Count++; + return new Node { Key = key }; + } + + if (IsRed(node.Left) && IsRed(node.Right)) + { + // Split node with two red children + FlipColor(node); + } + + // Find right place for new node + int comparisonResult = KeyComparison(key, node.Key); + if (comparisonResult < 0) + { + node.Left = Add(node.Left, key); + } + else if (0 < comparisonResult) + { + node.Right = Add(node.Right, key); + } + + if (IsRed(node.Right)) + { + // Rotate to prevent red node on right + node = RotateLeft(node); + } + + if (IsRed(node.Left) && IsRed(node.Left.Left)) + { + // Rotate to prevent consecutive red nodes + node = RotateRight(node); + } + + return node; + } + + /// + /// Removes the specified key/value pair from below the specified node. + /// + /// Specified node. + /// Key to remove. + /// True if key/value present and removed. + private Node Remove(Node node, TKey key) + { + int comparisonResult = KeyComparison(key, node.Key); + if (comparisonResult < 0) + { + // * Continue search if left is present + if (null != node.Left) + { + if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + { + // Move a red node over + node = MoveRedLeft(node); + } + + // Remove from left + node.Left = Remove(node.Left, key); + } + } + else + { + if (IsRed(node.Left)) + { + // Flip a 3 node or unbalance a 4 node + node = RotateRight(node); + } + if ((0 == KeyComparison(key, node.Key)) && (null == node.Right)) + { + // Remove leaf node + Debug.Assert(null == node.Left, "About to remove an extra node."); + Count--; + // Leaf node is gone + return null; + } + // * Continue search if right is present + if (null != node.Right) + { + if (!IsRed(node.Right) && !IsRed(node.Right.Left)) + { + // Move a red node over + node = MoveRedRight(node); + } + if (0 == KeyComparison(key, node.Key)) + { + // Remove leaf node + Count--; + // Find the smallest node on the right, swap, and remove it + Node m = GetExtreme(node.Right, n => n.Left, n => n); + node.Key = m.Key; + node.Right = DeleteMinimum(node.Right); + } + else + { + // Remove from right + node.Right = Remove(node.Right, key); + } + } + } + + // Maintain invariants + return FixUp(node); + } + + /// + /// Flip the colors of the specified node and its direct children. + /// + /// Specified node. + private static void FlipColor(Node node) + { + node.IsBlack = !node.IsBlack; + node.Left.IsBlack = !node.Left.IsBlack; + node.Right.IsBlack = !node.Right.IsBlack; + } + + /// + /// Rotate the specified node "left". + /// + /// Specified node. + /// New root node. + private static Node RotateLeft(Node node) + { + Node x = node.Right; + node.Right = x.Left; + x.Left = node; + x.IsBlack = node.IsBlack; + node.IsBlack = false; + return x; + } + + /// + /// Rotate the specified node "right". + /// + /// Specified node. + /// New root node. + private static Node RotateRight(Node node) + { + Node x = node.Left; + node.Left = x.Right; + x.Right = node; + x.IsBlack = node.IsBlack; + node.IsBlack = false; + return x; + } + + /// + /// Moves a red node from the right child to the left child. + /// + /// Parent node. + /// New root node. + private static Node MoveRedLeft(Node node) + { + FlipColor(node); + if (IsRed(node.Right.Left)) + { + node.Right = RotateRight(node.Right); + node = RotateLeft(node); + FlipColor(node); + + // * Avoid creating right-leaning nodes + if (IsRed(node.Right.Right)) + { + node.Right = RotateLeft(node.Right); + } + } + return node; + } + + /// + /// Moves a red node from the left child to the right child. + /// + /// Parent node. + /// New root node. + private static Node MoveRedRight(Node node) + { + FlipColor(node); + if (IsRed(node.Left.Left)) + { + node = RotateRight(node); + FlipColor(node); + } + return node; + } + + /// + /// Deletes the minimum node under the specified node. + /// + /// Specified node. + /// New root node. + private Node DeleteMinimum(Node node) + { + if (null == node.Left) + { + // Nothing to do + return null; + } + + if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + { + // Move red node left + node = MoveRedLeft(node); + } + + // Recursively delete + node.Left = DeleteMinimum(node.Left); + + // Maintain invariants + return FixUp(node); + } + + /// + /// Maintains invariants by adjusting the specified nodes children. + /// + /// Specified node. + /// New root node. + private static Node FixUp(Node node) + { + if (IsRed(node.Right)) + { + // Avoid right-leaning node + node = RotateLeft(node); + } + + if (IsRed(node.Left) && IsRed(node.Left.Left)) + { + // Balance 4-node + node = RotateRight(node); + } + + if (IsRed(node.Left) && IsRed(node.Right)) + { + // Push red up + FlipColor(node); + } + + // * Avoid leaving behind right-leaning nodes + if ((null != node.Left) && IsRed(node.Left.Right) && !IsRed(node.Left.Left)) + { + node.Left = RotateLeft(node.Left); + if (IsRed(node.Left)) + { + // Balance 4-node + node = RotateRight(node); + } + } + + return node; + } + + /// + /// Gets the (first) node corresponding to the specified key. + /// + /// Key to search for. + /// Corresponding node or null if none found. + private Node GetNodeForKey(TKey key) + { + // Initialize + Node node = _rootNode; + while (null != node) + { + // Compare keys and go left/right + int comparisonResult = key.CompareTo(node.Key); + if (comparisonResult < 0) + { + node = node.Left; + } + else if (0 < comparisonResult) + { + node = node.Right; + } + else + { + // Match; return node + return node; + } + } + + // No match found + return null; + } + + /// + /// Gets an extreme (ex: minimum/maximum) value. + /// + /// Type of value. + /// Node to start from. + /// Successor function. + /// Selector function. + /// Extreme value. + private static T GetExtreme(Node node, Func successor, Func selector) + { + // Initialize + T extreme = default(T); + Node current = node; + while (null != current) + { + // Go to extreme + extreme = selector(current); + current = successor(current); + } + return extreme; + } + + /// + /// Traverses a subset of the sequence of nodes in order and selects the specified nodes. + /// + /// Type of elements. + /// Starting node. + /// Condition method. + /// Selector method. + /// Sequence of selected nodes. + private IEnumerable Traverse(Node node, Func condition, Func selector) + { + // Create a stack to avoid recursion + Stack stack = new Stack(); + Node current = node; + while (null != current) + { + if (null != current.Left) + { + // Save current state and go left + stack.Push(current); + current = current.Left; + } + else + { + do + { + // Select current node if relevant + if (condition(current)) + { + yield return selector(current); + } + // Go right - or up if nothing to the right + current = current.Right; + } + while ((null == current) && + (0 < stack.Count) && + (null != (current = stack.Pop()))); + } + } + } + + /// + /// Compares the specified keys (primary) and values (secondary). + /// + /// The left key. + /// The right key. + /// CompareTo-style results: -1 if left is less, 0 if equal, and 1 if greater than right. + private int KeyComparison(TKey leftKey, TKey rightKey) + { + return leftKey.CompareTo(rightKey); + } + +#if DEBUGGING + /// + /// Asserts that tree invariants are not violated. + /// + private void AssertInvariants() + { + // Root is black + Debug.Assert((null == _rootNode) || _rootNode.IsBlack, "Root is not black"); + // Every path contains the same number of black nodes + Dictionary parents = new Dictionary.Node, LeftLeaningRedBlackTree.Node>(); + foreach (Node node in Traverse(_rootNode, n => true, n => n)) + { + if (null != node.Left) + { + parents[node.Left] = node; + } + if (null != node.Right) + { + parents[node.Right] = node; + } + } + if (null != _rootNode) + { + parents[_rootNode] = null; + } + int treeCount = -1; + foreach (Node node in Traverse(_rootNode, n => (null == n.Left) || (null == n.Right), n => n)) + { + int pathCount = 0; + Node current = node; + while (null != current) + { + if (current.IsBlack) + { + pathCount++; + } + current = parents[current]; + } + Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black nodes."); + treeCount = pathCount; + } + // Verify node properties... + foreach (Node node in Traverse(_rootNode, n => true, n => n)) + { + // Left node is less + if (null != node.Left) + { + Debug.Assert(0 > KeyAndValueComparison(node.Left.Key, node.Left.Value, node.Key, node.Value), "Left node is greater than its parent."); + } + // Right node is greater + if (null != node.Right) + { + Debug.Assert(0 < KeyAndValueComparison(node.Right.Key, node.Right.Value, node.Key, node.Value), "Right node is less than its parent."); + } + // Both children of a red node are black + Debug.Assert(!IsRed(node) || (!IsRed(node.Left) && !IsRed(node.Right)), "Red node has a red child."); + // Always left-leaning + Debug.Assert(!IsRed(node.Right) || IsRed(node.Left), "Node is not left-leaning."); + // No consecutive reds (subset of previous rule) + //Debug.Assert(!(IsRed(node) && IsRed(node.Left))); + } + } + + /// + /// Gets an HTML fragment representing the tree. + /// + public string HtmlDocument + { + get + { + return + "" + + "" + + (null != _rootNode ? _rootNode.HtmlFragment : "[null]") + + "" + + ""; + } + } +#endif +} diff --git a/DataStructures/LeftLeaningRedBlackTree.cs b/DataStructures/LeftLeaningRedBlackTree.cs new file mode 100644 index 0000000..b6e3712 --- /dev/null +++ b/DataStructures/LeftLeaningRedBlackTree.cs @@ -0,0 +1,789 @@ +// Uncomment this to enable the following debugging aids: +// LeftLeaningRedBlackTree.HtmlFragment +// LeftLeaningRedBlackTree.Node.HtmlFragment +// LeftLeaningRedBlackTree.AssertInvariants +// #define DEBUGGING + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +/// +/// Implements a left-leaning red-black tree. +/// +/// +/// Based on the research paper "Left-leaning Red-Black Trees" +/// by Robert Sedgewick. More information available at: +/// http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf +/// http://www.cs.princeton.edu/~rs/talks/LLRB/08Penn.pdf +/// +/// Type of keys. +/// Type of values. +public class LeftLeaningRedBlackTree +{ + /// + /// Stores the key comparison function. + /// + private Comparison _keyComparison; + + /// + /// Stores the value comparison function. + /// + private Comparison _valueComparison; + + /// + /// Stores the root node of the tree. + /// + private Node _rootNode; + + /// + /// Represents a node of the tree. + /// + /// + /// Using fields instead of properties drops execution time by about 40%. + /// + [DebuggerDisplay("Key={Key}, Value={Value}, Siblings={Siblings}")] + private class Node + { + /// + /// Gets or sets the node's key. + /// + public TKey Key; + + /// + /// Gets or sets the node's value. + /// + public TValue Value; + + /// + /// Gets or sets the left node. + /// + public Node Left; + + /// + /// Gets or sets the right node. + /// + public Node Right; + + /// + /// Gets or sets the color of the node. + /// + public bool IsBlack; + + /// + /// Gets or sets the number of "siblings" (nodes with the same key/value). + /// + public int Siblings; + +#if DEBUGGING + /// + /// Gets an HTML fragment representing the node and its children. + /// + public string HtmlFragment + { + get + { + return + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "
" + Key + ", " + Value + " [" + Siblings + "]
" + (null != Left ? Left.HtmlFragment : "[null]") + "" + (null != Right ? Right.HtmlFragment : "[null]") + "
"; + } + } +#endif + } + + /// + /// Initializes a new instance of the LeftLeaningRedBlackTree class implementing a normal dictionary. + /// + /// The key comparison function. + public LeftLeaningRedBlackTree(Comparison keyComparison) + { + if (null == keyComparison) + { + throw new ArgumentNullException("keyComparison"); + } + _keyComparison = keyComparison; + } + + /// + /// Initializes a new instance of the LeftLeaningRedBlackTree class implementing an ordered multi-dictionary. + /// + /// The key comparison function. + /// The value comparison function. + public LeftLeaningRedBlackTree(Comparison keyComparison, Comparison valueComparison) + : this(keyComparison) + { + if (null == valueComparison) + { + throw new ArgumentNullException("valueComparison"); + } + _valueComparison = valueComparison; + } + + /// + /// Gets a value indicating whether the tree is acting as an ordered multi-dictionary. + /// + private bool IsMultiDictionary + { + get { return null != _valueComparison; } + } + + /// + /// Adds a key/value pair to the tree. + /// + /// Key to add. + /// Value to add. + public void Add(TKey key, TValue value) + { + _rootNode = Add(_rootNode, key, value); + _rootNode.IsBlack = true; +#if DEBUGGING + AssertInvariants(); +#endif + } + + /// + /// Removes a key (and its associated value) from a normal (non-multi) dictionary. + /// + /// Key to remove. + /// True if key present and removed. + public bool Remove(TKey key) + { + if (IsMultiDictionary) + { + throw new InvalidOperationException("Remove is only supported when acting as a normal (non-multi) dictionary."); + } + return Remove(key, default(TValue)); + } + + /// + /// Removes a key/value pair from the tree. + /// + /// Key to remove. + /// Value to remove. + /// True if key/value present and removed. + public bool Remove(TKey key, TValue value) + { + int initialCount = Count; + if (null != _rootNode) + { + _rootNode = Remove(_rootNode, key, value); + if (null != _rootNode) + { + _rootNode.IsBlack = true; + } + } +#if DEBUGGING + AssertInvariants(); +#endif + return initialCount != Count; + } + + /// + /// Removes all nodes in the tree. + /// + public void Clear() + { + _rootNode = null; + Count = 0; +#if DEBUGGING + AssertInvariants(); +#endif + } + + /// + /// Gets a sorted list of keys in the tree. + /// + /// Sorted list of keys. + public IEnumerable GetKeys() + { + TKey lastKey = default(TKey); + bool lastKeyValid = false; + return Traverse( + _rootNode, + n => !lastKeyValid || !object.Equals(lastKey, n.Key), + n => + { + lastKey = n.Key; + lastKeyValid = true; + return lastKey; + }); + } + + /// + /// Gets the value associated with the specified key in a normal (non-multi) dictionary. + /// + /// Specified key. + /// Value associated with the specified key. + public TValue GetValueForKey(TKey key) + { + if (IsMultiDictionary) + { + throw new InvalidOperationException("GetValueForKey is only supported when acting as a normal (non-multi) dictionary."); + } + Node node = GetNodeForKey(key); + if (null != node) + { + return node.Value; + } + else + { + throw new KeyNotFoundException(); + } + } + + /// + /// Gets a sequence of the values associated with the specified key. + /// + /// Specified key. + /// Sequence of values. + public IEnumerable GetValuesForKey(TKey key) + { + return Traverse(GetNodeForKey(key), n => 0 == _keyComparison(n.Key, key), n => n.Value); + } + + /// + /// Gets a sequence of all the values in the tree. + /// + /// Sequence of all values. + public IEnumerable GetValuesForAllKeys() + { + return Traverse(_rootNode, n => true, n => n.Value); + } + + /// + /// Gets the count of key/value pairs in the tree. + /// + public int Count { get; private set; } + + /// + /// Gets the minimum key in the tree. + /// + public TKey MinimumKey + { + get { return GetExtreme(_rootNode, n => n.Left, n => n.Key); } + } + + /// + /// Gets the maximum key in the tree. + /// + public TKey MaximumKey + { + get { return GetExtreme(_rootNode, n => n.Right, n => n.Key); } + } + + /// + /// Returns true if the specified node is red. + /// + /// Specified node. + /// True if specified node is red. + private static bool IsRed(Node node) + { + if (null == node) + { + // "Virtual" leaf nodes are always black + return false; + } + return !node.IsBlack; + } + + /// + /// Adds the specified key/value pair below the specified root node. + /// + /// Specified node. + /// Key to add. + /// Value to add. + /// New root node. + private Node Add(Node node, TKey key, TValue value) + { + if (null == node) + { + // Insert new node + Count++; + return new Node { Key = key, Value = value }; + } + + if (IsRed(node.Left) && IsRed(node.Right)) + { + // Split node with two red children + FlipColor(node); + } + + // Find right place for new node + int comparisonResult = KeyAndValueComparison(key, value, node.Key, node.Value); + if (comparisonResult < 0) + { + node.Left = Add(node.Left, key, value); + } + else if (0 < comparisonResult) + { + node.Right = Add(node.Right, key, value); + } + else + { + if (IsMultiDictionary) + { + // Store the presence of a "duplicate" node + node.Siblings++; + Count++; + } + else + { + // Replace the value of the existing node + node.Value = value; + } + } + + if (IsRed(node.Right)) + { + // Rotate to prevent red node on right + node = RotateLeft(node); + } + + if (IsRed(node.Left) && IsRed(node.Left.Left)) + { + // Rotate to prevent consecutive red nodes + node = RotateRight(node); + } + + return node; + } + + /// + /// Removes the specified key/value pair from below the specified node. + /// + /// Specified node. + /// Key to remove. + /// Value to remove. + /// True if key/value present and removed. + private Node Remove(Node node, TKey key, TValue value) + { + int comparisonResult = KeyAndValueComparison(key, value, node.Key, node.Value); + if (comparisonResult < 0) + { + // * Continue search if left is present + if (null != node.Left) + { + if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + { + // Move a red node over + node = MoveRedLeft(node); + } + + // Remove from left + node.Left = Remove(node.Left, key, value); + } + } + else + { + if (IsRed(node.Left)) + { + // Flip a 3 node or unbalance a 4 node + node = RotateRight(node); + } + if ((0 == KeyAndValueComparison(key, value, node.Key, node.Value)) && (null == node.Right)) + { + // Remove leaf node + Debug.Assert(null == node.Left, "About to remove an extra node."); + Count--; + if (0 < node.Siblings) + { + // Record the removal of the "duplicate" node + Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); + node.Siblings--; + return node; + } + else + { + // Leaf node is gone + return null; + } + } + // * Continue search if right is present + if (null != node.Right) + { + if (!IsRed(node.Right) && !IsRed(node.Right.Left)) + { + // Move a red node over + node = MoveRedRight(node); + } + if (0 == KeyAndValueComparison(key, value, node.Key, node.Value)) + { + // Remove leaf node + Count--; + if (0 < node.Siblings) + { + // Record the removal of the "duplicate" node + Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); + node.Siblings--; + } + else + { + // Find the smallest node on the right, swap, and remove it + Node m = GetExtreme(node.Right, n => n.Left, n => n); + node.Key = m.Key; + node.Value = m.Value; + node.Siblings = m.Siblings; + node.Right = DeleteMinimum(node.Right); + } + } + else + { + // Remove from right + node.Right = Remove(node.Right, key, value); + } + } + } + + // Maintain invariants + return FixUp(node); + } + + /// + /// Flip the colors of the specified node and its direct children. + /// + /// Specified node. + private static void FlipColor(Node node) + { + node.IsBlack = !node.IsBlack; + node.Left.IsBlack = !node.Left.IsBlack; + node.Right.IsBlack = !node.Right.IsBlack; + } + + /// + /// Rotate the specified node "left". + /// + /// Specified node. + /// New root node. + private static Node RotateLeft(Node node) + { + Node x = node.Right; + node.Right = x.Left; + x.Left = node; + x.IsBlack = node.IsBlack; + node.IsBlack = false; + return x; + } + + /// + /// Rotate the specified node "right". + /// + /// Specified node. + /// New root node. + private static Node RotateRight(Node node) + { + Node x = node.Left; + node.Left = x.Right; + x.Right = node; + x.IsBlack = node.IsBlack; + node.IsBlack = false; + return x; + } + + /// + /// Moves a red node from the right child to the left child. + /// + /// Parent node. + /// New root node. + private static Node MoveRedLeft(Node node) + { + FlipColor(node); + if (IsRed(node.Right.Left)) + { + node.Right = RotateRight(node.Right); + node = RotateLeft(node); + FlipColor(node); + + // * Avoid creating right-leaning nodes + if (IsRed(node.Right.Right)) + { + node.Right = RotateLeft(node.Right); + } + } + return node; + } + + /// + /// Moves a red node from the left child to the right child. + /// + /// Parent node. + /// New root node. + private static Node MoveRedRight(Node node) + { + FlipColor(node); + if (IsRed(node.Left.Left)) + { + node = RotateRight(node); + FlipColor(node); + } + return node; + } + + /// + /// Deletes the minimum node under the specified node. + /// + /// Specified node. + /// New root node. + private Node DeleteMinimum(Node node) + { + if (null == node.Left) + { + // Nothing to do + return null; + } + + if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + { + // Move red node left + node = MoveRedLeft(node); + } + + // Recursively delete + node.Left = DeleteMinimum(node.Left); + + // Maintain invariants + return FixUp(node); + } + + /// + /// Maintains invariants by adjusting the specified nodes children. + /// + /// Specified node. + /// New root node. + private static Node FixUp(Node node) + { + if (IsRed(node.Right)) + { + // Avoid right-leaning node + node = RotateLeft(node); + } + + if (IsRed(node.Left) && IsRed(node.Left.Left)) + { + // Balance 4-node + node = RotateRight(node); + } + + if (IsRed(node.Left) && IsRed(node.Right)) + { + // Push red up + FlipColor(node); + } + + // * Avoid leaving behind right-leaning nodes + if ((null != node.Left) && IsRed(node.Left.Right) && !IsRed(node.Left.Left)) + { + node.Left = RotateLeft(node.Left); + if (IsRed(node.Left)) + { + // Balance 4-node + node = RotateRight(node); + } + } + + return node; + } + + /// + /// Gets the (first) node corresponding to the specified key. + /// + /// Key to search for. + /// Corresponding node or null if none found. + private Node GetNodeForKey(TKey key) + { + // Initialize + Node node = _rootNode; + while (null != node) + { + // Compare keys and go left/right + int comparisonResult = _keyComparison(key, node.Key); + if (comparisonResult < 0) + { + node = node.Left; + } + else if (0 < comparisonResult) + { + node = node.Right; + } + else + { + // Match; return node + return node; + } + } + + // No match found + return null; + } + + /// + /// Gets an extreme (ex: minimum/maximum) value. + /// + /// Type of value. + /// Node to start from. + /// Successor function. + /// Selector function. + /// Extreme value. + private static T GetExtreme(Node node, Func successor, Func selector) + { + // Initialize + T extreme = default(T); + Node current = node; + while (null != current) + { + // Go to extreme + extreme = selector(current); + current = successor(current); + } + return extreme; + } + + /// + /// Traverses a subset of the sequence of nodes in order and selects the specified nodes. + /// + /// Type of elements. + /// Starting node. + /// Condition method. + /// Selector method. + /// Sequence of selected nodes. + private IEnumerable Traverse(Node node, Func condition, Func selector) + { + // Create a stack to avoid recursion + Stack stack = new Stack(); + Node current = node; + while (null != current) + { + if (null != current.Left) + { + // Save current state and go left + stack.Push(current); + current = current.Left; + } + else + { + do + { + for (int i = 0; i <= current.Siblings; i++) + { + // Select current node if relevant + if (condition(current)) + { + yield return selector(current); + } + } + // Go right - or up if nothing to the right + current = current.Right; + } + while ((null == current) && + (0 < stack.Count) && + (null != (current = stack.Pop()))); + } + } + } + + /// + /// Compares the specified keys (primary) and values (secondary). + /// + /// The left key. + /// The left value. + /// The right key. + /// The right value. + /// CompareTo-style results: -1 if left is less, 0 if equal, and 1 if greater than right. + private int KeyAndValueComparison(TKey leftKey, TValue leftValue, TKey rightKey, TValue rightValue) + { + // Compare keys + int comparisonResult = _keyComparison(leftKey, rightKey); + if ((0 == comparisonResult) && (null != _valueComparison)) + { + // Keys match; compare values + comparisonResult = _valueComparison(leftValue, rightValue); + } + return comparisonResult; + } + +#if DEBUGGING + /// + /// Asserts that tree invariants are not violated. + /// + private void AssertInvariants() + { + // Root is black + Debug.Assert((null == _rootNode) || _rootNode.IsBlack, "Root is not black"); + // Every path contains the same number of black nodes + Dictionary parents = new Dictionary.Node, LeftLeaningRedBlackTree.Node>(); + foreach (Node node in Traverse(_rootNode, n => true, n => n)) + { + if (null != node.Left) + { + parents[node.Left] = node; + } + if (null != node.Right) + { + parents[node.Right] = node; + } + } + if (null != _rootNode) + { + parents[_rootNode] = null; + } + int treeCount = -1; + foreach (Node node in Traverse(_rootNode, n => (null == n.Left) || (null == n.Right), n => n)) + { + int pathCount = 0; + Node current = node; + while (null != current) + { + if (current.IsBlack) + { + pathCount++; + } + current = parents[current]; + } + Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black nodes."); + treeCount = pathCount; + } + // Verify node properties... + foreach (Node node in Traverse(_rootNode, n => true, n => n)) + { + // Left node is less + if (null != node.Left) + { + Debug.Assert(0 > KeyAndValueComparison(node.Left.Key, node.Left.Value, node.Key, node.Value), "Left node is greater than its parent."); + } + // Right node is greater + if (null != node.Right) + { + Debug.Assert(0 < KeyAndValueComparison(node.Right.Key, node.Right.Value, node.Key, node.Value), "Right node is less than its parent."); + } + // Both children of a red node are black + Debug.Assert(!IsRed(node) || (!IsRed(node.Left) && !IsRed(node.Right)), "Red node has a red child."); + // Always left-leaning + Debug.Assert(!IsRed(node.Right) || IsRed(node.Left), "Node is not left-leaning."); + // No consecutive reds (subset of previous rule) + //Debug.Assert(!(IsRed(node) && IsRed(node.Left))); + } + } + + /// + /// Gets an HTML fragment representing the tree. + /// + public string HtmlDocument + { + get + { + return + "" + + "" + + (null != _rootNode ? _rootNode.HtmlFragment : "[null]") + + "" + + ""; + } + } +#endif +} diff --git a/DataStructures/PriorityQueue.cs b/DataStructures/PriorityQueue.cs new file mode 100644 index 0000000..f314d94 --- /dev/null +++ b/DataStructures/PriorityQueue.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Collections; + +// By James McCaffrey11/02/2012 + +sealed public class PriorityQueue:IEnumerable where T : IComparable +{ + private List data; + + public PriorityQueue () + { + this.data = new List (); + } + + IEnumerator System.Collections.IEnumerable.GetEnumerator () + { + // Lets call the generic version here + return this.GetEnumerator (); + } + + public IEnumerator GetEnumerator () + { + return data.GetEnumerator () as IEnumerator; + } + + public void Enqueue (T item) + { + data.Add (item); + int ci = data.Count - 1; // child index; start at end + while (ci > 0) { + int pi = (ci - 1) / 2; // parent index + if (data [ci].CompareTo (data [pi]) >= 0) + break; // child item is larger than (or equal) parent so we're done + T tmp = data [ci]; + data [ci] = data [pi]; + data [pi] = tmp; + ci = pi; + } + } + + public T Dequeue() + { + // assumes pq is not empty; up to calling code + int li = data.Count - 1; // last index (before removal) + T frontItem = data [0]; // fetch the front + data [0] = data [li]; + data.RemoveAt (li); + + --li; // last index (after removal) + int pi = 0; // parent index. start at front of pq + while (true) + { + int ci = pi * 2 + 1; // left child index of parent + if (ci > li) + break; // no children so done + int rc = ci + 1; // right child + if (rc <= li && data [rc].CompareTo (data [ci]) < 0) // if there is a rc (ci + 1), and it is smaller than left child, use the rc instead + ci = rc; + if (data [pi].CompareTo (data [ci]) <= 0) + break; // parent is smaller than (or equal to) smallest child so done + T tmp = data [pi]; + data [pi] = data [ci]; + data [ci] = tmp; // swap parent and child + pi = ci; + } + + return frontItem; + } + + public T Peek () + { + T frontItem = data [0]; + return frontItem; + } + + public int Count () + { + return data.Count; + } + + public override string ToString () + { + string s = ""; + for (int i = 0; i < data.Count; ++i) + s += data [i].ToString () + " "; + s += "count = " + data.Count; + return s; + } + + public bool IsConsistent () + { + // is the heap property true for all data? + if (data.Count == 0) + return true; + int li = data.Count - 1; // last index + for (int pi = 0; pi < data.Count; ++pi) { // each parent index + int lci = 2 * pi + 1; // left child index + int rci = 2 * pi + 2; // right child index + + if (lci <= li && data [pi].CompareTo (data [lci]) > 0) + return false; // if lc exists and it's greater than parent then bad. + if (rci <= li && data [pi].CompareTo (data [rci]) > 0) + return false; // check the right child too. + } + return true; // passed all checks + } // IsConsistent +} // PriorityQueue diff --git a/ECS/DataStructures/TypeSafeDictionary.cs b/ECS/DataStructures/TypeSafeDictionary.cs new file mode 100644 index 0000000..022ebe5 --- /dev/null +++ b/ECS/DataStructures/TypeSafeDictionary.cs @@ -0,0 +1,23 @@ +using Svelto.DataStructures; +using System.Collections.Generic; + +namespace Svelto.ECS +{ + /// + /// This is just a place holder at the moment + /// I always wanted to create my own Dictionary + /// data structure as excercise, but never had the + /// time to. At the moment I need the custom interface + /// wrapped though. + /// + + public interface ITypeSafeDictionary + { + + } + + public class TypeSafeDictionary : Dictionary, ITypeSafeDictionary + { + internal static readonly ReadOnlyDictionary Default = new ReadOnlyDictionary(new TypeSafeDictionary()); + } +} diff --git a/ECS/DataStructures/TypeSafeList.cs b/ECS/DataStructures/TypeSafeList.cs new file mode 100644 index 0000000..cac7c4b --- /dev/null +++ b/ECS/DataStructures/TypeSafeList.cs @@ -0,0 +1,51 @@ +using Svelto.DataStructures; +using Svelto.ECS.Internal; + +namespace Svelto.ECS +{ + public interface ITypeSafeList + { + void Clear(); + void AddRange(ITypeSafeList nodeListValue); + + ITypeSafeList Create(); + ITypeSafeDictionary CreateIndexedDictionary(); + void AddToIndexedDictionary(ITypeSafeDictionary nodesDic); + } + + public class TypeSafeFasterList : FasterList, ITypeSafeList + { + public TypeSafeFasterList() + { + } + + public void AddRange(ITypeSafeList nodeListValue) + { + AddRange(nodeListValue as FasterList); + } + + public ITypeSafeList Create() + { + return new TypeSafeFasterList(); + } + + public ITypeSafeDictionary CreateIndexedDictionary() + { + return new TypeSafeDictionary(); + } + + public void AddToIndexedDictionary(ITypeSafeDictionary nodesDic) + { + var dic = nodesDic as TypeSafeDictionary; + + var buffer = NoVirt.ToArrayFast(this); + + for (int i = 0; i < Count; i++) + { + T node = buffer[i]; + + dic[(node as NodeWithID).ID] = node; + } + } + } +} diff --git a/ECS/EngineNodeDB.cs b/ECS/EngineNodeDB.cs index 0bb5bb8..9e26351 100644 --- a/ECS/EngineNodeDB.cs +++ b/ECS/EngineNodeDB.cs @@ -6,104 +6,102 @@ namespace Svelto.ECS { public class EngineNodeDB : IEngineNodeDB { - internal EngineNodeDB( Dictionary> nodesDB, - Dictionary> nodesDBdic, - Dictionary> metaNodesDB) + internal EngineNodeDB( Dictionary nodesDB, + Dictionary nodesDBdic, + Dictionary metaNodesDB) { _nodesDB = nodesDB; _nodesDBdic = nodesDBdic; _metaNodesDB = metaNodesDB; } - public FasterReadOnlyListCast QueryNodes() where T:INode + public FasterReadOnlyList QueryNodes() { var type = typeof(T); - FasterList nodes; + ITypeSafeList nodes; if (_nodesDB.TryGetValue(type, out nodes) == false) return RetrieveEmptyNodeList(); - return new FasterReadOnlyListCast(nodes); + return new FasterReadOnlyList((FasterList)nodes); } - public ReadOnlyDictionary QueryIndexableNodes() where T:INode + public ReadOnlyDictionary QueryIndexableNodes() { var type = typeof(T); - Dictionary nodes; + ITypeSafeDictionary nodes; if (_nodesDBdic.TryGetValue(type, out nodes) == false) - return _defaultEmptyNodeDict; + return TypeSafeDictionary.Default; - return new ReadOnlyDictionary(nodes); + return new ReadOnlyDictionary(nodes as Dictionary); } - public T QueryMetaNode(int metaEntityID) where T : INode + public T QueryMetaNode(int metaEntityID) { return QueryNode(metaEntityID); } - public bool TryQueryMetaNode(int metaEntityID, out T node) where T : INode + public bool TryQueryMetaNode(int metaEntityID, out T node) { return TryQueryNode(metaEntityID, out node); } - public FasterReadOnlyListCast QueryMetaNodes() where T : INode + public FasterReadOnlyList QueryMetaNodes() { var type = typeof(T); - FasterList nodes; + ITypeSafeList nodes; if (_metaNodesDB.TryGetValue(type, out nodes) == false) return RetrieveEmptyNodeList(); - return new FasterReadOnlyListCast(nodes); + return new FasterReadOnlyList((FasterList)nodes); } - public bool TryQueryNode(int ID, out T node) where T:INode + public bool TryQueryNode(int ID, out T node) { var type = typeof(T); - INode internalNode; + T internalNode; - Dictionary nodes; + ITypeSafeDictionary nodes; if (_nodesDBdic.TryGetValue(type, out nodes) && - nodes.TryGetValue(ID, out internalNode)) + (nodes as Dictionary).TryGetValue(ID, out internalNode)) { - node = (T)internalNode; + node = internalNode; return true; } - + node = default(T); return false; } - public T QueryNode(int ID) where T:INode + public T QueryNode(int ID) { var type = typeof(T); - INode internalNode; Dictionary nodes; + T internalNode; ITypeSafeDictionary nodes; if (_nodesDBdic.TryGetValue(type, out nodes) && - nodes.TryGetValue(ID, out internalNode)) + (nodes as Dictionary).TryGetValue(ID, out internalNode)) return (T)internalNode; throw new Exception("Node Not Found"); } - static FasterReadOnlyListCast RetrieveEmptyNodeList() where T : INode + static FasterReadOnlyList RetrieveEmptyNodeList() { - return FasterReadOnlyListCast.DefaultList; + return FasterReadOnlyList.DefaultList; } - readonly Dictionary> _nodesDB; - readonly Dictionary> _nodesDBdic; - readonly Dictionary> _metaNodesDB; - - readonly ReadOnlyDictionary _defaultEmptyNodeDict = new ReadOnlyDictionary(new Dictionary()); + readonly Dictionary _nodesDB; + readonly Dictionary _nodesDBdic; + readonly Dictionary _metaNodesDB; } } diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs index bc9c6df..3deadf8 100644 --- a/ECS/EnginesRoot.cs +++ b/ECS/EnginesRoot.cs @@ -3,14 +3,24 @@ using System.Collections.Generic; using Svelto.DataStructures; using Svelto.ECS.Internal; using Svelto.ECS.NodeSchedulers; -using WeakReference = Svelto.DataStructures.WeakReference; +using System.Reflection; +using Svelto.Utilities; +using UnityEngine.UI; +using UnityEngine.XR.WSA.Persistence; #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR using Svelto.ECS.Profiler; #endif -#if NETFX_CORE -using System.Reflection; -#endif + +namespace Svelto.ECS.Internal +{ + struct BuildNodeCallbackStruct + { + public Action _internalRemove; + public Action _internalEnable; + public Action _internalDisable; + } +} namespace Svelto.ECS { @@ -22,22 +32,22 @@ namespace Svelto.ECS _activableEngines = new Dictionary>(); _otherEngines = new FasterList(); - _engineRootWeakReference = new WeakReference(this); + //_engineRootWeakReference = new DataStructures.WeakReference(this); - _nodesDB = new Dictionary>(); - _nodesDBdic = new Dictionary>(); + _nodesDB = new Dictionary(); + _metaNodesDB = new Dictionary(); + _nodesDBdic = new Dictionary(); - _nodesToAdd = new FasterList(); - _metaNodesToAdd = new FasterList(); - - _metaNodesDB = new Dictionary>(); - _sharedStructNodeLists = new SharedStructNodeLists(); - _sharedGroupedStructNodeLists = new SharedGroupedStructNodesLists(); + _nodesToAdd = new Dictionary(); + _metaNodesToAdd = new Dictionary(); + _groupedNodesToAdd = new Dictionary>(); + + _callBackStruct = new BuildNodeCallbackStruct(); - _internalRemove = InternalRemove; - _internalDisable = InternalDisable; - _internalEnable = InternalEnable; - _internalMetaRemove = InternalMetaRemove; + /* _callBackStruct._internalRemove = InternalRemove; + _callBackStruct._internalDisable = InternalDisable; + _callBackStruct._internalEnable = InternalEnable; + _callBackStruct._internalMetaRemove = InternalMetaRemove;*/ _scheduler = nodeScheduler; _scheduler.Schedule(SubmitNodes); @@ -54,77 +64,53 @@ namespace Svelto.ECS #endif } - void SubmitNodes() + public void BuildEntity(int ID, EntityDescriptor ed) { - int metaNodesCount = _metaNodesToAdd.Count; - int nodesCount = _nodesToAdd.Count; - - if (metaNodesCount + nodesCount == 0) return; - - bool newNodesHaveBeenAddedWhileIterating; - int startNodes = 0; - int startMetaNodes = 0; - int numberOfReenteringLoops = 0; - - do - { - var nodesToAdd = _nodesToAdd.ToArrayFast(); - - for (int i = startNodes; i < nodesCount; i++) - { - var node = nodesToAdd[i]; - var nodeType = node.GetType(); - - AddNodeToTheDB(node, nodeType); - var nodeWithId = node as INodeWithID; - if (nodeWithId != null) - AddNodeToNodesDictionary(nodeWithId, nodeType); - } - - var metaNodesToAdd = _metaNodesToAdd.ToArrayFast(); - - for (int i = startMetaNodes; i < metaNodesCount; i++) - { - var node = metaNodesToAdd[i]; - var nodeType = node.GetType(); - - AddNodeToMetaDB(node, nodeType); - var nodeWithId = node as INodeWithID; - if (nodeWithId != null) - AddNodeToNodesDictionary(nodeWithId, nodeType); - } - - for (int i = startNodes; i < nodesCount; i++) - { - var node = nodesToAdd[i]; - AddNodeToTheSuitableEngines(node, node.GetType()); - } - - for (int i = startMetaNodes; i < metaNodesCount; i++) - { - var node = metaNodesToAdd[i]; - AddNodeToTheSuitableEngines(node, node.GetType()); - } - - newNodesHaveBeenAddedWhileIterating = - _metaNodesToAdd.Count > metaNodesCount || - _nodesToAdd.Count > nodesCount; - - startNodes = nodesCount; - startMetaNodes = metaNodesCount; - - if (numberOfReenteringLoops > 5) - throw new Exception("possible infinite loop found creating Entities inside INodesEngine Add method, please consider building entities outside INodesEngine Add method"); - - numberOfReenteringLoops++; - - metaNodesCount = _metaNodesToAdd.Count; - nodesCount = _nodesToAdd.Count; + ed.BuildNodes(ID, _nodesToAdd, ref _callBackStruct); + } - } while (newNodesHaveBeenAddedWhileIterating); + /// + /// A meta entity is a way to manage a set of entitites that are not easily + /// queriable otherwise. For example you may want to group existing entities + /// by size and type and then use the meta entity node to manage the data + /// shared among the single entities of the same type and size. This will + /// prevent the scenario where the coder is forced to parse all the entities to + /// find the ones of the same size and type. + /// Since the entities are managed through the shared node, the same + /// shared node must be found on the single entities of the same type and size. + /// The shared node of the meta entity is then used by engines that are meant + /// to manage a group of entities through a single node. + /// The same engine can manage several meta entities nodes too. + /// The Engine manages the logic of the Meta Node data and other engines + /// can read back this data through the normal entity as the shared node + /// will be present in their descriptor too. + /// It's a way to control a group of Entities through a node only. + /// This set of entities can share exactly the same node reference if + /// built through this function. In this way, if you need to set a variable + /// on a group of entities, instead to inject N nodes and iterate over + /// them to set the same value, you can inject just one node, set the value + /// and be sure that the value is shared between entities. + /// + /// + /// + public void BuildMetaEntity(int metaEntityID, EntityDescriptor ed) + { + ed.BuildNodes(metaEntityID, _metaNodesToAdd, ref _callBackStruct); + } - _nodesToAdd.Clear(); - _metaNodesToAdd.Clear(); + /// + /// Using this function is like building a normal entity, but the nodes + /// are grouped by groupID to be better processed inside engines and + /// improve cache locality. Only IGroupStructNodeWithID nodes are grouped + /// other nodes are managed as usual. + /// + /// + /// + /// + public void BuildEntityInGroup(int entityID, int groupID, + EntityDescriptor ed) + { + ed.BuildGroupedNodes(entityID, groupID, _groupedNodesToAdd, ref _callBackStruct); } public void AddEngine(IEngine engine) @@ -133,9 +119,9 @@ namespace Svelto.ECS EngineProfiler.AddEngine(engine); #endif var queryableNodeEngine = engine as IQueryableNodeEngine; - if (queryableNodeEngine != null) - queryableNodeEngine.nodesDB = - new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB); + if (queryableNodeEngine != null) + queryableNodeEngine.nodesDB = + new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB); var engineType = engine.GetType(); var implementedInterfaces = engineType.GetInterfaces(); @@ -167,12 +153,8 @@ namespace Svelto.ECS if (type.IsAssignableFrom(interfaceType) == false) continue; -#if !NETFX_CORE - if (false == interfaceType.IsGenericType) -#else - if (false == interfaceType.IsConstructedGenericType) -#endif + if (false == interfaceType.IsGenericTypeEx()) { continue; } @@ -189,21 +171,9 @@ namespace Svelto.ECS bool engineAdded = false; - if (_implementedInterfaceTypes.ContainsKey(_structNodeEngineType)) - { - ((IStructNodeEngine)engine).CreateStructNodes - (_sharedStructNodeLists); - } - - if (_implementedInterfaceTypes.ContainsKey(_groupedStructNodesEngineType)) - { - ((IGroupedStructNodesEngine)engine).CreateStructNodes - (_sharedGroupedStructNodeLists); - } - Type[] arguments; if (_implementedInterfaceTypes.TryGetValue(_activableNodeEngineType, - out arguments)) + out arguments)) { AddEngine(engine, arguments, _activableEngines); @@ -230,15 +200,9 @@ namespace Svelto.ECS bool CheckNodesEngine(IEngine engine, Type engineType, ref bool engineAdded) { -#if !NETFX_CORE - var baseType = engineType.BaseType; + var baseType = engineType.GetBaseType(); - if (baseType.IsGenericType -#else - var baseType = engineType.GetTypeInfo().BaseType; - - if (baseType.IsConstructedGenericType -#endif + if (baseType.IsGenericTypeEx() && engine is INodeEngine) { AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines); @@ -251,76 +215,8 @@ namespace Svelto.ECS return false; } - public void BuildEntity(int ID, EntityDescriptor ed) - { - var entityNodes = ed.BuildNodes(ID, - _internalRemove, - _internalEnable, - _internalDisable - ); - - _nodesToAdd.AddRange(entityNodes); - } - - /// - /// A meta entity is a way to manage a set of entitites that are not easily - /// queriable otherwise. For example you may want to group existing entities - /// by size and type and then use the meta entity node to manage the data - /// shared among the single entities of the same type and size. This will - /// prevent the scenario where the coder is forced to parse all the entities to - /// find the ones of the same size and type. - /// Since the entities are managed through the shared node, the same - /// shared node must be found on the single entities of the same type and size. - /// The shared node of the meta entity is then used by engines that are meant - /// to manage a group of entities through a single node. - /// The same engine can manage several meta entities nodes too. - /// The Engine manages the logic of the Meta Node data and other engines - /// can read back this data through the normal entity as the shared node - /// will be present in their descriptor too. - /// - /// - /// - public void BuildMetaEntity(int metaEntityID, EntityDescriptor ed) - { - var entityNodes = ed.BuildNodes(metaEntityID, - _internalMetaRemove, - _internalEnable, - _internalDisable - ); - - _metaNodesToAdd.AddRange(entityNodes); - } - - /// - /// Using this function is like building a normal entity, but the nodes - /// are grouped by groupID to be better processed inside engines and - /// improve cache locality. Only IGroupStructNodeWithID nodes are grouped - /// other nodes are managed as usual. - /// - /// - /// - /// - public void BuildEntityInGroup(int entityID, int groupID, - EntityDescriptor ed) - { - var entityNodes = ed.BuildNodes(entityID, - _internalRemove, - _internalEnable, - _internalDisable - ); - - _nodesToAdd.AddRange(entityNodes); - - for (int i = 0; i < entityNodes.Count; i++) - { - var groupNode = entityNodes[i] as IGroupedStructNodeWithID; - if (groupNode != null) - groupNode.groupID = groupID; - } - } - static void AddEngine(IEngine engine, Type[] types, - Dictionary> engines) + Dictionary> engines) { for (int i = 0; i < types.Length; i++) { @@ -339,186 +235,229 @@ namespace Svelto.ECS } } - void AddNodeToMetaDB(INode node, Type nodeType) + static void AddNodesToTheDBAndSuitableEngines(Dictionary nodesToAdd, + Dictionary> nodeEngines, + Dictionary nodesDBdic, + Dictionary nodesDB) { - FasterList nodes; - if (_metaNodesDB.TryGetValue(nodeType, out nodes) == false) - nodes = _metaNodesDB[nodeType] = new FasterList(); + foreach (var nodeList in nodesToAdd) + { + ITypeSafeList dbList; - nodes.Add(node); - } + if (nodesDB.TryGetValue(nodeList.Key, out dbList) == false) + dbList = nodesDB[nodeList.Key] = nodeList.Value.Create(); - void AddNodeToTheDB(T node, Type nodeType) where T : INode - { - FasterList nodes; - if (_nodesDB.TryGetValue(nodeType, out nodes) == false) - nodes = _nodesDB[nodeType] = new FasterList(); + dbList.AddRange(nodeList.Value); - nodes.Add(node); + AddNodeToNodesDictionary(nodesDBdic, nodeList.Value, nodeList.Key); + AddNodesToTheSuitableEngines(nodeEngines, nodeList.Value, nodeList.Key); + } } - - void AddNodeToNodesDictionary(T node, Type nodeType) where T : INodeWithID + + static void AddNodeToNodesDictionary(Dictionary nodesDBdic, ITypeSafeList nodes, Type nodeType) { - Dictionary nodesDic; + ITypeSafeDictionary nodesDic; - if (_nodesDBdic.TryGetValue(nodeType, out nodesDic) == false) - nodesDic = _nodesDBdic[nodeType] = new Dictionary(); + if (nodesDBdic.TryGetValue(nodeType, out nodesDic) == false) + nodesDic = nodesDBdic[nodeType] = nodes.CreateIndexedDictionary(); - nodesDic.Add(node.ID, node); + nodes.AddToIndexedDictionary(nodesDic); } - void AddNodeToTheSuitableEngines(INode node, Type nodeType) + static void AddNodesToTheSuitableEngines(Dictionary> nodeEngines, ITypeSafeList nodes, Type nodeType) { FasterList enginesForNode; - if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) + if (nodeEngines.TryGetValue(nodeType, out enginesForNode)) { for (int j = 0; j < enginesForNode.Count; j++) { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR EngineProfiler.MonitorAddDuration(AddNodeToEngine, enginesForNode[j] as INodeEngine, node); #else - (enginesForNode[j] as INodeEngine).Add(node); + (enginesForNode[j] as INodeEngine).Add(nodes); #endif } } } + /* + void RemoveNodeFromTheDB(T node, Type nodeType) where T : INode + { + FasterList nodes; + if (_nodesDB.TryGetValue(nodeType, out nodes) == true) + nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? + } - void RemoveNodeFromTheDB(T node, Type nodeType) where T : INode - { - FasterList nodes; - if (_nodesDB.TryGetValue(nodeType, out nodes) == true) - nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? - } + void RemoveNodeFromMetaDB(T node, Type nodeType) where T : INode + { + FasterList nodes; + if (_metaNodesDB.TryGetValue(nodeType, out nodes) == true) + nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? + } - void RemoveNodeFromMetaDB(T node, Type nodeType) where T : INode - { - FasterList nodes; - if (_metaNodesDB.TryGetValue(nodeType, out nodes) == true) - nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? - } + void RemoveNodeFromNodesDictionary(T node, Type nodeType) where T : INodeWithID + { + Dictionary nodesDic; - void RemoveNodeFromNodesDictionary(T node, Type nodeType) where T : INodeWithID - { - Dictionary nodesDic; + if (_nodesDBdic.TryGetValue(nodeType, out nodesDic)) + nodesDic.Remove(node.ID); + } - if (_nodesDBdic.TryGetValue(nodeType, out nodesDic)) - nodesDic.Remove(node.ID); - } + void RemoveNodeFromEngines(T node, Type nodeType) where T : INode + { + FasterList enginesForNode; + + if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) + { + for (int j = 0; j < enginesForNode.Count; j++) + { + #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); + #else + (enginesForNode[j] as INodeEngine).Remove(node); + #endif + } + } + } - void RemoveNodeFromEngines(T node, Type nodeType) where T : INode - { - FasterList enginesForNode; + void DisableNodeFromEngines(INode node, Type nodeType) + { + FasterList enginesForNode; + + if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) + { + for (int j = 0; j < enginesForNode.Count; j++) + { + (enginesForNode[j] as IActivableNodeEngine).Disable(node); + } + } + } - if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) + void EnableNodeFromEngines(INode node, Type nodeType) { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); -#else - (enginesForNode[j] as INodeEngine).Remove(node); -#endif + FasterList enginesForNode; + + if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) + { + for (int j = 0; j < enginesForNode.Count; j++) + { + (enginesForNode[j] as IActivableNodeEngine).Enable(node); + } + } + } + #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + void AddNodeToEngine(IEngine engine, INode node) + { + (engine as INodeEngine).Add(node); } - } - } - void DisableNodeFromEngines(INode node, Type nodeType) - { - FasterList enginesForNode; + void RemoveNodeFromEngine(IEngine engine, INode node) + { + (engine as INodeEngine).Remove(node); + } + #endif + /* + void InternalDisable(FasterList nodes) + { + if (_engineRootWeakReference.IsValid == false) + return; + + for (int i = 0; i < nodes.Count; i++) + { + var node = nodes[i]; + Type nodeType = node.GetType(); + DisableNodeFromEngines(node, nodeType); + } + } - if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) + void InternalEnable(FasterList nodes) { - (enginesForNode[j] as IActivableNodeEngine).Disable(node); + if (_engineRootWeakReference.IsValid == false) + return; + + for (int i = 0; i < nodes.Count; i++) + { + var node = nodes[i]; + Type nodeType = node.GetType(); + EnableNodeFromEngines(node, nodeType); + } } - } - } - void EnableNodeFromEngines(INode node, Type nodeType) - { - FasterList enginesForNode; + void InternalRemove(IFasterList nodes) + { + if (_engineRootWeakReference.IsValid == false) + return; - if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) + for (int i = 0; i < nodes.Count; i++) + { + var node = nodes[i]; + Type nodeType = node.GetType(); + + RemoveNodeFromEngines(node, nodeType); + RemoveNodeFromTheDB(node, node.GetType()); + + var nodeWithId = node as INodeWithID; + if (nodeWithId != null) + RemoveNodeFromNodesDictionary(nodeWithId, nodeType); + } + } + + void InternalMetaRemove(FasterList nodes) { - (enginesForNode[j] as IActivableNodeEngine).Enable(node); + for (int i = 0; i < nodes.Count; i++) + { + var node = nodes[i]; + Type nodeType = node.GetType(); + + RemoveNodeFromEngines(node, nodeType); + RemoveNodeFromMetaDB(node, nodeType); + + var nodeWithId = node as INodeWithID; + if (nodeWithId != null) + RemoveNodeFromNodesDictionary(nodeWithId, nodeType); + } } - } - } -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - void AddNodeToEngine(IEngine engine, INode node) - { - (engine as INodeEngine).Add(node); - } - void RemoveNodeFromEngine(IEngine engine, INode node) - { - (engine as INodeEngine).Remove(node); - } -#endif + readonly DataStructures.WeakReference _engineRootWeakReference; + + */ - void InternalDisable(FasterList nodes) + void SubmitNodes() { - if (_engineRootWeakReference.IsValid == false) - return; + int metaNodesCount = _metaNodesToAdd.Count; + int nodesCount = _nodesToAdd.Count; - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); - DisableNodeFromEngines(node, nodeType); - } - } + if (metaNodesCount + nodesCount == 0) return; - void InternalEnable(FasterList nodes) - { - if (_engineRootWeakReference.IsValid == false) - return; + bool newNodesHaveBeenAddedWhileIterating; + int startNodes = 0; + int startMetaNodes = 0; + int numberOfReenteringLoops = 0; - for (int i = 0; i < nodes.Count; i++) + do { - var node = nodes[i]; - Type nodeType = node.GetType(); - EnableNodeFromEngines(node, nodeType); - } - } + AddNodesToTheDBAndSuitableEngines(_nodesToAdd, _nodeEngines, _nodesDBdic, _nodesDB); + AddNodesToTheDBAndSuitableEngines(_metaNodesToAdd, _nodeEngines, _nodesDBdic, _metaNodesDB); - void InternalRemove(FasterList nodes) - { - if (_engineRootWeakReference.IsValid == false) - return; + newNodesHaveBeenAddedWhileIterating = + _metaNodesToAdd.Count > metaNodesCount || + _nodesToAdd.Count > nodesCount; - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); + startNodes = nodesCount; + startMetaNodes = metaNodesCount; - RemoveNodeFromEngines(node, nodeType); - RemoveNodeFromTheDB(node, node.GetType()); + if (numberOfReenteringLoops > 5) + throw new Exception("possible infinite loop found creating Entities inside INodesEngine Add method, please consider building entities outside INodesEngine Add method"); - var nodeWithId = node as INodeWithID; - if (nodeWithId != null) - RemoveNodeFromNodesDictionary(nodeWithId, nodeType); - } - } + numberOfReenteringLoops++; - void InternalMetaRemove(FasterList nodes) - { - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); + metaNodesCount = _metaNodesToAdd.Count; + nodesCount = _nodesToAdd.Count; - RemoveNodeFromEngines(node, nodeType); - RemoveNodeFromMetaDB(node, nodeType); + } while (newNodesHaveBeenAddedWhileIterating); - var nodeWithId = node as INodeWithID; - if (nodeWithId != null) - RemoveNodeFromNodesDictionary(nodeWithId, nodeType); - } + _nodesToAdd.Clear(); + _metaNodesToAdd.Clear(); } readonly Dictionary> _nodeEngines; @@ -526,30 +465,27 @@ namespace Svelto.ECS readonly FasterList _otherEngines; - readonly Dictionary> _nodesDB; - readonly Dictionary> _metaNodesDB; - - readonly Dictionary> _nodesDBdic; - - readonly FasterList _nodesToAdd; - readonly FasterList _metaNodesToAdd; - - readonly WeakReference _engineRootWeakReference; - readonly SharedStructNodeLists _sharedStructNodeLists; - readonly SharedGroupedStructNodesLists _sharedGroupedStructNodeLists; + readonly Dictionary _nodesDB; + readonly Dictionary _metaNodesDB; + readonly Dictionary> _groupNodesDB; + + readonly Dictionary _nodesDBdic; + /// + /// Need to think about how to make BuildEntity thread safe as well + /// + readonly Dictionary _nodesToAdd; + readonly Dictionary _metaNodesToAdd; + readonly Dictionary> _groupedNodesToAdd; + readonly NodeSubmissionScheduler _scheduler; - readonly Action> _internalRemove; - readonly Action> _internalEnable; - readonly Action> _internalDisable; - readonly Action> _internalMetaRemove; - readonly Type _structNodeEngineType; readonly Type _groupedStructNodesEngineType; readonly Type _activableNodeEngineType; readonly Dictionary _implementedInterfaceTypes; + + BuildNodeCallbackStruct _callBackStruct; } -} - +} \ No newline at end of file diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs index cf459b2..6c96c06 100644 --- a/ECS/EntityDescriptor.cs +++ b/ECS/EntityDescriptor.cs @@ -2,22 +2,26 @@ using System; using System.Collections.Generic; using System.Reflection; using Svelto.DataStructures; -#if NETFX_CORE -using BindingFlags = System.Reflection.BindingFlags; -#endif +using Svelto.ECS.Internal; namespace Svelto.ECS { public class EntityDescriptor { protected EntityDescriptor() - { - } + {} + + /// + /// if you want to avoid allocation in run-time, you can prebuild + /// EntityDescriptors and use them to build entities at different + /// times + /// protected EntityDescriptor(INodeBuilder[] nodesToBuild) { _nodesToBuild = new FasterList(nodesToBuild); } - protected EntityDescriptor(INodeBuilder[] nodesToBuild, params object[] componentsImplementor):this(nodesToBuild) + protected EntityDescriptor(INodeBuilder[] nodesToBuild, + params object[] componentsImplementor):this(nodesToBuild) { ProcessImplementors(componentsImplementor); } @@ -26,105 +30,160 @@ namespace Svelto.ECS { ProcessImplementors(componentsImplementor); } + + public void AddNodes(params INodeBuilder[] nodesWithID) + { + _nodesToBuild.AddRange(nodesWithID); + } - void ProcessImplementors(object[] implementors) + internal void BuildGroupedNodes + (int entityID, int groupID, + Dictionary> groupNodes, + ref BuildNodeCallbackStruct callBackstruct) { - for (int index = 0; index < implementors.Length; index++) + for (int index = 0; index < _nodesToBuild.Count; index++) { - var implementor = implementors[index]; - if (implementor == null) - { - Utility.Console.LogWarning( - "Null implementor, are you using a wild GetComponents to fetch it? " - .FastConcat(ToString())); - } - else + var nodeBuilder = _nodesToBuild[index]; + var nodeType = nodeBuilder.GetNodeType(); + + Dictionary groupedNodesTyped; + + if (groupNodes.TryGetValue(nodeType, out groupedNodesTyped) == false) { - if (implementor is IRemoveEntityComponent) - _removingImplementors.Add(implementor as IRemoveEntityComponent); - if (implementor is IDisableEntityComponent) - _disablingImplementors.Add(implementor as IDisableEntityComponent); - if (implementor is IEnableEntityComponent) - _enablingImplementors.Add(implementor as IEnableEntityComponent); + groupedNodesTyped = new Dictionary(); + + groupNodes.Add(nodeType, groupedNodesTyped); + }; + + ITypeSafeList nodes; - var interfaces = implementor.GetType().GetInterfaces(); - for (int iindex = 0; iindex < interfaces.Length; iindex++) - { - _implementorsByType[interfaces[iindex]] = implementor; - } + var mustAdd = groupedNodesTyped.TryGetValue(groupID, out nodes) == false; + + var node = nodeBuilder.BuildAndAddToList(ref nodes, entityID); + + if (mustAdd) + groupedNodesTyped[groupID] = nodes; + + if (node != null && nodeBuilder.reflects != FillNodeMode.None) + { + node = FillNode(node, nodeBuilder.reflects); + + SetupImplementors(ref callBackstruct, nodes); } - } - } - public void AddNodes(params INodeBuilder[] nodesWithID) - { - _nodesToBuild.AddRange(nodesWithID); + /* var groupNode = node as IGroupedNode; + if (groupNode != null) + groupNode.groupID = groupID;*/ + } } - public virtual FasterList BuildNodes(int ID) + internal void BuildNodes(int entityID, + Dictionary nodesToAdd, + ref BuildNodeCallbackStruct callBackstruct) { - var nodes = new FasterList(); - for (int index = 0; index < _nodesToBuild.Count; index++) { var nodeBuilder = _nodesToBuild[index]; - var node = nodeBuilder.Build(ID); + var nodeType = nodeBuilder.GetNodeType(); - if (nodeBuilder.reflects != FillNodeMode.None) - node = FillNode(node, nodeBuilder.reflects); + ITypeSafeList nodes; - nodes.Add(node); - } + var mustAdd = nodesToAdd.TryGetValue(nodeType, out nodes) == false; + + var node = nodeBuilder.BuildAndAddToList(ref nodes, entityID); - return nodes; - } + if (mustAdd) + nodesToAdd[nodeType] = nodes; - internal FasterList BuildNodes(int ID, - Action> removeEntity, - Action> enableEntity, - Action> disableEntity) + if (node != null && nodeBuilder.reflects != FillNodeMode.None) + { + FillNode(node, nodeBuilder.reflects); + + SetupImplementors(ref callBackstruct, nodes); + } + } + } + + void ProcessImplementors(object[] implementors) { - var nodes = BuildNodes(ID); - - SetupImplementors(removeEntity, enableEntity, disableEntity, nodes); + for (int index = 0; index < implementors.Length; index++) + { + var implementor = implementors[index]; + + if (implementor != null) + { + if (implementor is IRemoveEntityComponent) + _removingImplementors.Add(new DataStructures.WeakReference(implementor as IRemoveEntityComponent)); + if (implementor is IDisableEntityComponent) + _disablingImplementors.Add(new DataStructures.WeakReference(implementor as IDisableEntityComponent)); + if (implementor is IEnableEntityComponent) + _enablingImplementors.Add(new DataStructures.WeakReference(implementor as IEnableEntityComponent)); - return nodes; + var interfaces = implementor.GetType().GetInterfaces(); + var weakReference = new DataStructures.WeakReference(implementor); + + for (int iindex = 0; iindex < interfaces.Length; iindex++) + { + var componentType = interfaces[iindex]; + + _implementorsByType[componentType] = weakReference; +#if DEBUG && !PROFILER + if (_implementorCounterByType.ContainsKey(componentType) == false) + _implementorCounterByType[componentType] = 1; + else + _implementorCounterByType[componentType]++; +#endif + } + } +#if DEBUG && !PROFILER + else + Utility.Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat(ToString())); +#endif + } } void SetupImplementors( - Action> removeEntity, - Action> enableEntity, - Action> disableEntity, - FasterList nodes) + ref BuildNodeCallbackStruct callBackstruct, + ITypeSafeList nodes) { - Action removeEntityAction = () => { removeEntity(nodes); nodes.Clear(); }; - Action disableEntityAction = () => disableEntity(nodes); - Action enableEntityAction = () => enableEntity(nodes); - - for (int index = 0; index < _removingImplementors.Count; index++) - _removingImplementors[index].removeEntity = removeEntityAction; - for (int index = 0; index < _disablingImplementors.Count; index++) - _disablingImplementors[index].disableEntity = disableEntityAction; - for (int index = 0; index < _enablingImplementors.Count; index++) - _enablingImplementors[index].enableEntity = enableEntityAction; + var RemoveEntity = callBackstruct._internalRemove; + var DisableEntity = callBackstruct._internalDisable; + var EnableEntity = callBackstruct._internalEnable; + + Action removeEntityAction = () => { RemoveEntity(nodes); nodes.Clear(); }; + Action disableEntityAction = () => DisableEntity(nodes); + Action enableEntityAction = () => EnableEntity(nodes); + + int removingImplementorsCount = _removingImplementors.Count; + for (int index = 0; index < removingImplementorsCount; index++) + _removingImplementors[index].Target.removeEntity = removeEntityAction; + + int disablingImplementorsCount = _disablingImplementors.Count; + for (int index = 0; index < disablingImplementorsCount; index++) + _disablingImplementors[index].Target.disableEntity = disableEntityAction; + + int enablingImplementorsCount = _enablingImplementors.Count; + for (int index = 0; index < enablingImplementorsCount; index++) + _enablingImplementors[index].Target.enableEntity = enableEntityAction; } TNode FillNode(TNode node, FillNodeMode mode) where TNode : INode { - var fields = node.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); + var fields = node.GetType().GetFields(BindingFlags.Public | + BindingFlags.Instance); for (int i = fields.Length - 1; i >= 0; --i) { var field = fields[i]; Type fieldType = field.FieldType; - object component; - - if ((_implementorsByType.TryGetValue(fieldType, out component)) == false) + DataStructures.WeakReference component; + + if (_implementorsByType.TryGetValue(fieldType, out component) == false) { if (mode == FillNodeMode.Strict) { Exception e = - new Exception("Svelto.ECS: Implementor not found for a Node. " + "Implementor Type: " + + new Exception(NOT_FOUND_EXCEPTION + field.FieldType.Name + " - Node: " + node.GetType().Name + " - EntityDescriptor " + this); @@ -132,65 +191,36 @@ namespace Svelto.ECS } } else - field.SetValue(node, component); - } - - return node; - } - - readonly FasterList _disablingImplementors = new FasterList(); - readonly FasterList _removingImplementors = new FasterList(); - readonly FasterList _enablingImplementors = new FasterList(); - readonly Dictionary _implementorsByType = new Dictionary(); - - readonly FasterList _nodesToBuild; - } - - public interface INodeBuilder - { - INode Build(int ID); - - FillNodeMode reflects { get; } - } - - public class NodeBuilder : INodeBuilder where NodeType : NodeWithID, new() - { - public INode Build(int ID) - { - NodeWithID node = NodeWithID.BuildNode(ID); - - return (NodeType)node; - } - - public FillNodeMode reflects { get { return FillNodeMode.Strict; } } - } + field.SetValue(node, component.Target); + +#if DEBUG && !PROFILER + { + if (_implementorCounterByType[fieldType] != 1) + { + Utility.Console.LogError( + DUPLICATE_IMPLEMENTOR_ERROR.FastConcat("component: ", fieldType.ToString(), + " implementor: ", component.Target.ToString())); + } + } +#endif - public class StructNodeBuilder : INodeBuilder - where NodeType : struct, IStructNodeWithID - { - public INode Build(int ID) - { - var shortID = (short)ID; - IStructNodeWithID node = default(NodeType); - node.ID = shortID; + } return node; } - public virtual FillNodeMode reflects { get { return FillNodeMode.Relaxed; } } - } + readonly FasterList> _disablingImplementors = new FasterList>(); + readonly FasterList> _removingImplementors = new FasterList>(); + readonly FasterList> _enablingImplementors = new FasterList>(); - public class FastStructNodeBuilder : StructNodeBuilder - where NodeType : struct, IStructNodeWithID - { - public override FillNodeMode reflects { get { return FillNodeMode.None; } } - } - - public enum FillNodeMode - { - Strict, - Relaxed, + readonly Dictionary> _implementorsByType = new Dictionary>(); +#if DEBUG && !PROFILER + readonly Dictionary _implementorCounterByType = new Dictionary(); +#endif + readonly FasterList _nodesToBuild; - None + const string DUPLICATE_IMPLEMENTOR_ERROR = "the same component is implemented with more than one implementor. This is considered an error and MUST be fixed. "; + const string NULL_IMPLEMENTOR_ERROR = "Null implementor, are you using a wild GetComponents to fetch it? "; + const string NOT_FOUND_EXCEPTION = "Svelto.ECS: Implementor not found for a Node. Implementor Type: "; } } diff --git a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs b/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs index 9241fdf..5e0d363 100644 --- a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs +++ b/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs @@ -5,6 +5,14 @@ using UnityEngine; namespace Svelto.ECS.NodeSchedulers { + //The NodeSubmissionScheduler has been introduced to make + //the node submission logic platform indipendent. + //Please don't be tempted to create your own submission to + //adapt to your game level code design. For example, + //you may be tempted to write a submission logic to submit + //the nodes immediatly just because convenient for your game + //logic. This is not how it works. + public class UnitySumbmissionNodeScheduler : NodeSubmissionScheduler { public UnitySumbmissionNodeScheduler() diff --git a/ECS/GenericEntityDescriptor.cs b/ECS/GenericEntityDescriptor.cs index 472cdff..f0c87ff 100644 --- a/ECS/GenericEntityDescriptor.cs +++ b/ECS/GenericEntityDescriptor.cs @@ -140,6 +140,25 @@ namespace Svelto.ECS static readonly INodeBuilder[] _nodesToBuild; } + + public class GenericMixedEntityDescriptor : EntityDescriptor + where T : INodeBuilder, new() + where U : INodeBuilder, new() + { + static GenericMixedEntityDescriptor() + { + _nodesToBuild = new INodeBuilder[] + { + new T(), + new U(), + }; + } + public GenericMixedEntityDescriptor(params object[] componentsImplementor) : + base(_nodesToBuild, componentsImplementor) + { } + + static readonly INodeBuilder[] _nodesToBuild; + } public class GenericMixedEntityDescriptor : EntityDescriptor where T : INodeBuilder, new() diff --git a/ECS/GenericEntityDescriptorHolder.cs b/ECS/GenericEntityDescriptorHolder.cs index 4e51570..05c8ac5 100644 --- a/ECS/GenericEntityDescriptorHolder.cs +++ b/ECS/GenericEntityDescriptorHolder.cs @@ -3,7 +3,8 @@ using System; namespace Svelto.ECS { - public class GenericEntityDescriptorHolder: UnityEngine.MonoBehaviour, IEntityDescriptorHolder where T:EntityDescriptor + public class GenericEntityDescriptorHolder: + UnityEngine.MonoBehaviour, IEntityDescriptorHolder where T:EntityDescriptor { public EntityDescriptor BuildDescriptorType(object[] externalImplentors) { diff --git a/ECS/IEngine.cs b/ECS/IEngine.cs index d811e9a..0a4629a 100644 --- a/ECS/IEngine.cs +++ b/ECS/IEngine.cs @@ -1,3 +1,4 @@ +using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS.Internal @@ -14,14 +15,14 @@ namespace Svelto.ECS.Internal public interface IActivableNodeEngine : IEngine { - void Enable(INode obj); - void Disable(INode obj); + void Enable(ITypeSafeList nodes); + void Disable(ITypeSafeList nodes); } public interface INodeEngine : IEngine { - void Add(INode obj); - void Remove(INode obj); + void Add(ITypeSafeList nodes); + void Remove(ITypeSafeList nodes); } public interface INodesEngine : INodeEngine @@ -56,7 +57,7 @@ namespace Svelto.ECS /// usually the ID is the owner of the nodes of that /// group /// - public interface IGroupedStructNodesEngine : IGroupedStructNodesEngine where T:struct, IGroupedStructNodeWithID + public interface IGroupedStructNodesEngine : IGroupedStructNodesEngine where T:struct, IGroupedNode { } } diff --git a/ECS/IEngineNodeDB.cs b/ECS/IEngineNodeDB.cs index e2ee74f..3906d79 100644 --- a/ECS/IEngineNodeDB.cs +++ b/ECS/IEngineNodeDB.cs @@ -4,16 +4,15 @@ namespace Svelto.ECS { public interface IEngineNodeDB { - ReadOnlyDictionary QueryIndexableNodes() where T:INode; + ReadOnlyDictionary QueryIndexableNodes(); - bool TryQueryNode(int ID, out T node) where T:INode; - T QueryNode(int ID) where T:INode; - - FasterReadOnlyListCast QueryNodes() where T:INode; + bool TryQueryNode(int ID, out T node); + T QueryNode(int ID); + FasterReadOnlyList QueryNodes(); - bool TryQueryMetaNode(int metaEntityID, out T node) where T : INode; - T QueryMetaNode(int metaEntityID) where T : INode; - FasterReadOnlyListCast QueryMetaNodes() where T : INode; + bool TryQueryMetaNode(int metaEntityID, out T node); + T QueryMetaNode(int metaEntityID); + FasterReadOnlyList QueryMetaNodes(); } } diff --git a/ECS/INode.cs b/ECS/INode.cs index f9b0c81..fc53c55 100644 --- a/ECS/INode.cs +++ b/ECS/INode.cs @@ -3,22 +3,17 @@ namespace Svelto.ECS public interface INode {} - public interface INodeWithID:INode - { - int ID { get; } - } - public interface IStructNodeWithID : INode { int ID { get; set; } } - public interface IGroupedStructNodeWithID : IStructNodeWithID + public interface IGroupedNode { int groupID { get; set; } } - public class NodeWithID: INodeWithID + public class NodeWithID: INode { public static TNodeType BuildNode(int ID) where TNodeType: NodeWithID, new() { diff --git a/ECS/MultiNodesEngine.cs b/ECS/MultiNodesEngine.cs index 2907917..97cb3ac 100644 --- a/ECS/MultiNodesEngine.cs +++ b/ECS/MultiNodesEngine.cs @@ -1,9 +1,9 @@ +using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS.Internal { - public abstract class MultiNodesEngine - where T : INode + public abstract class MultiNodesEngine where T:class { protected abstract void AddNode(T node); protected abstract void RemoveNode(T node); @@ -16,32 +16,89 @@ namespace Svelto.ECS { public abstract System.Type[] AcceptedNodes(); - public abstract void Add(INode node); - public abstract void Remove(INode node); + public abstract void Add(ITypeSafeList nodeWrapper); + public abstract void Remove(ITypeSafeList nodeWrapper); } public abstract class MultiNodesEngine : MultiNodesEngine, - INodeEngine - where T : INode - where U : INode + INodeEngine where T:class where U:class { protected abstract void AddNode(U node); protected abstract void RemoveNode(U node); - public void Add(INode node) + public virtual void Add(ITypeSafeList nodes) { - if (node is T) - AddNode((T)node); + if (nodes is FasterList) + { + var strongTypeNodes = (FasterList)nodes; + + for (int i = 0; i < strongTypeNodes.Count; i++) + { + AddNode(strongTypeNodes[i]); + } + } else - AddNode((U)node); + if (nodes is FasterList) + { + var strongTypeNodes = (FasterList)nodes; + + for (int i = 0; i < strongTypeNodes.Count; i++) + { + AddNode(strongTypeNodes[i]); + } + } } - public void Remove(INode node) + public virtual void Remove(ITypeSafeList nodeWrapper) { - if (node is T) - RemoveNode((T)node); + /* if (nodeWrapper is NodeWrapper) + { + T node; + nodeWrapper.GetNode(out node); + + RemoveNode(ref node); + } + else + { + U node; + nodeWrapper.GetNode(out node); + + RemoveNode(ref node); + }*/ + } + } + + public abstract class MultiNodesEngine : MultiNodesEngine where T: class where U : class + { + protected abstract void AddNode(V node); + protected abstract void RemoveNode(V node); + + public override void Add(ITypeSafeList nodes) + { + if (nodes is FasterList) + { + var strongTypeNodes = (FasterList)nodes; + + for (int i = 0; i < strongTypeNodes.Count; i++) + { + AddNode(strongTypeNodes[i]); + } + } + else + base.Add(nodes); + } + + public override void Remove(ITypeSafeList nodeWrapper) + { + /* if (nodeWrapper is V) + { + V node; + nodeWrapper.GetNode(out node); + + RemoveNode(ref node); + } else - RemoveNode((U)node); + base.Remove(nodeWrapper);*/ } } } \ No newline at end of file diff --git a/ECS/NodeBuilder.cs b/ECS/NodeBuilder.cs new file mode 100644 index 0000000..17b9c34 --- /dev/null +++ b/ECS/NodeBuilder.cs @@ -0,0 +1,77 @@ +using System; +using Svelto.DataStructures; +using Svelto.ECS.Internal; + +namespace Svelto.ECS +{ + public interface INodeBuilder + { + INode BuildAndAddToList(ref ITypeSafeList list, int entityID); + + Type GetNodeType(); + + FillNodeMode reflects { get; } + } + + public class NodeBuilder : INodeBuilder where NodeType : NodeWithID, new() + { + public INode BuildAndAddToList(ref ITypeSafeList list, int entityID) + { + if (list == null) + list = new TypeSafeFasterList(); + + var castedList = list as FasterList; + + var node = NodeWithID.BuildNode(entityID); + + castedList.Add(node); + + return node; + } + + public FillNodeMode reflects + { + get { return FillNodeMode.Strict; } + } + + public Type GetNodeType() + { + return typeof(NodeType); + } + } + + public class StructNodeBuilder : INodeBuilder where NodeType : struct, IStructNodeWithID + { + public INode BuildAndAddToList(ref ITypeSafeList list, int entityID) + { + var node = default(NodeType); + node.ID = entityID; + + if (list == null) + list = new TypeSafeFasterList(); + + var castedList = list as FasterList; + + castedList.Add(node); + + return null; + } + + public Type GetNodeType() + { + return typeof(NodeType); + } + + public virtual FillNodeMode reflects + { + get { return FillNodeMode.None; } + } + } + + public enum FillNodeMode + { + Strict, + + None + } +} \ No newline at end of file diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs index b1fb2da..d774c2b 100644 --- a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs +++ b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs @@ -1,4 +1,4 @@ -#if UNITY_EDITOR +#if asdUNITY_EDITOR using System; using System.Collections.Generic; using UnityEditor; diff --git a/ECS/Profiler/EngineProfiler.cs b/ECS/Profiler/EngineProfiler.cs index 0612925..c659c87 100644 --- a/ECS/Profiler/EngineProfiler.cs +++ b/ECS/Profiler/EngineProfiler.cs @@ -1,3 +1,4 @@ +#if asdDEBUG using System; using System.Collections.Generic; using System.Diagnostics; @@ -12,31 +13,31 @@ namespace Svelto.ECS.Profiler { static readonly Stopwatch _stopwatch = new Stopwatch(); - public static void MonitorAddDuration(Action addingFunc, INodeEngine engine, INode node) + public static void MonitorAddDuration(Action addingFunc, INodeEngine engine, INodeWrapper node) { EngineInfo info; + if (engineInfos.TryGetValue(engine.GetType(), out info)) { - _stopwatch.Reset(); _stopwatch.Start(); addingFunc(engine, node); - _stopwatch.Stop(); + _stopwatch.Reset(); info.AddAddDuration(_stopwatch.Elapsed.TotalMilliseconds); } } - public static void MonitorRemoveDuration(Action removeFunc, INodeEngine engine, INode node) + public static void MonitorRemoveDuration(Action removeFunc, INodeEngine engine, INodeWrapper node) { EngineInfo info; + if (engineInfos.TryGetValue(engine.GetType(), out info)) { - _stopwatch.Reset(); _stopwatch.Start(); removeFunc(engine, node); - engine.Remove(node); - _stopwatch.Stop(); - + // engine.Remove(node); + _stopwatch.Reset(); + info.AddRemoveDuration(_stopwatch.Elapsed.TotalMilliseconds); } } @@ -60,3 +61,4 @@ namespace Svelto.ECS.Profiler public static readonly Dictionary engineInfos = new Dictionary(); } } +#endif \ No newline at end of file diff --git a/ECS/Profiler/EngineProfilerBehaviour.cs b/ECS/Profiler/EngineProfilerBehaviour.cs index a350ae7..bb046bb 100644 --- a/ECS/Profiler/EngineProfilerBehaviour.cs +++ b/ECS/Profiler/EngineProfilerBehaviour.cs @@ -1,4 +1,4 @@ -#if UNITY_EDITOR +#if asdUNITY_EDITOR using System; using System.Collections.Generic; using UnityEngine; diff --git a/ECS/SingleNodeEngine.cs b/ECS/SingleNodeEngine.cs index f4c58a1..85ad0d9 100644 --- a/ECS/SingleNodeEngine.cs +++ b/ECS/SingleNodeEngine.cs @@ -1,21 +1,31 @@ +using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS { - public abstract class SingleNodeEngine : INodeEngine - where TNodeType : INode + public abstract class SingleNodeEngine : INodeEngine where T:class { - public void Add(INode obj) + public void Add(ITypeSafeList nodes) { - Add((TNodeType) obj); + var strongTypeNodes = (FasterList)nodes; + + for (int i = 0; i < strongTypeNodes.Count; i++) + { + Add(strongTypeNodes[i]); //when byref returns will be vailable, this should be passed by reference, not copy! + } } - public void Remove(INode obj) + public void Remove(ITypeSafeList nodes) { - Remove((TNodeType) obj); + /* + T node; + + nodeWrapper.GetNode(out node); + + Remove(node);*/ } - protected abstract void Add(TNodeType node); - protected abstract void Remove(TNodeType node); + protected abstract void Add(T node); + protected abstract void Remove(T node); } } diff --git a/ECS/StructNodes.cs b/ECS/StructNodes.cs index 85ca30d..6a6a60a 100644 --- a/ECS/StructNodes.cs +++ b/ECS/StructNodes.cs @@ -5,7 +5,7 @@ using Svelto.ECS.Internal; namespace Svelto.ECS { - public class StructNodes where T:struct, IStructNodeWithID + public sealed class StructNodes where T:struct, IStructNodeWithID { public T[] GetList(out int numberOfItems) { @@ -15,7 +15,7 @@ namespace Svelto.ECS public StructNodes(SharedStructNodeLists container) { - _internalList = container.GetList(); + _internalList = SharedStructNodeLists.NoVirt.GetList(container); } public void Add(T node) @@ -28,19 +28,20 @@ namespace Svelto.ECS readonly FasterList _internalList; } - public class StructGroupNodes - where T : struct, IGroupedStructNodeWithID + public struct StructGroupNodes + where T : struct, IStructNodeWithID { public StructGroupNodes(SharedGroupedStructNodesLists container) { _container = container; + indices = new Dictionary(); } public void Add(int groupID, T node) { T convert = (T)node; - var fasterList = (_container.GetList(groupID) as FasterList); + var fasterList = (SharedGroupedStructNodesLists.NoVirt.GetList(_container, groupID) as FasterList); indices[node.ID] = fasterList.Count; fasterList.Add(convert); @@ -48,7 +49,7 @@ namespace Svelto.ECS public void Remove(int groupID, T node) { - var fasterList = (_container.GetList(groupID) as FasterList); + var fasterList = (SharedGroupedStructNodesLists.NoVirt.GetList(_container, groupID) as FasterList); var index = indices[node.ID]; indices.Remove(node.ID); @@ -58,77 +59,83 @@ namespace Svelto.ECS public T[] GetList(int groupID, out int numberOfItems) { - var fasterList = (_container.GetList(groupID) as FasterList); - numberOfItems = fasterList.Count; - return fasterList.ToArrayFast(); + var fasterList = (SharedGroupedStructNodesLists.NoVirt.GetList(_container, groupID) as FasterList); + numberOfItems = FasterList.NoVirt.Count(fasterList); + return FasterList.NoVirt.ToArrayFast(fasterList); } readonly SharedGroupedStructNodesLists _container; - readonly Dictionary indices = new Dictionary(); + readonly Dictionary indices; } public class SharedStructNodeLists { - readonly Dictionary _collection; - internal SharedStructNodeLists() { - _collection = new Dictionary(); + _collection = new Dictionary(); } - internal FasterList GetList() where T:struct + internal static class NoVirt { - IFasterList list; - if (_collection.TryGetValue(typeof (T), out list)) + internal static FasterList GetList(SharedStructNodeLists obj) where T : struct { - return list as FasterList; - } + ITypeSafeList list; + if (obj._collection.TryGetValue(typeof(T), out list)) + { + return list as FasterList; + } - list = new FasterList(); + list = new TypeSafeFasterList(); - _collection.Add(typeof (T), list); + obj._collection.Add(typeof(T), list); - return (FasterList) list; + return (FasterList)list; + } } + + readonly Dictionary _collection; } public class SharedGroupedStructNodesLists { internal SharedGroupedStructNodesLists() { - _collection = new Dictionary>(); + _collection = new Dictionary>(); } - internal IFasterList GetList(int groupID) where T : struct + internal static class NoVirt { - Dictionary dic = GetGroup(); - IFasterList localList; - - if (dic.TryGetValue(groupID, out localList)) - return localList; + internal static ITypeSafeList GetList(SharedGroupedStructNodesLists list, int groupID) where T : struct + { + Dictionary dic = GetGroup(list); + ITypeSafeList localList; - localList = new FasterList(); - dic.Add(groupID, localList); + if (dic.TryGetValue(groupID, out localList)) + return localList; - return localList; - } + localList = new TypeSafeFasterList(); + dic.Add(groupID, localList); - internal Dictionary GetGroup() where T : struct - { - Dictionary dic; + return localList; + } - if (_collection.TryGetValue(typeof(T), out dic)) + internal static Dictionary GetGroup(SharedGroupedStructNodesLists list) where T : struct { - return dic; - } + Dictionary dic; + + if (list._collection.TryGetValue(typeof(T), out dic)) + { + return dic; + } - dic = new Dictionary(); + dic = new Dictionary(); - _collection.Add(typeof(T), dic); + list._collection.Add(typeof(T), dic); - return dic; + return dic; + } } - readonly Dictionary> _collection; + readonly Dictionary> _collection; } } \ No newline at end of file diff --git a/Factories/IGameObjectFactory.cs b/Factories/IGameObjectFactory.cs index 7879bf3..03f35ce 100644 --- a/Factories/IGameObjectFactory.cs +++ b/Factories/IGameObjectFactory.cs @@ -1,3 +1,4 @@ +#if UNITY_5_3_OR_NEWER || UNITY_5 using UnityEngine; namespace Svelto.Factories @@ -10,3 +11,4 @@ namespace Svelto.Factories GameObject Build(GameObject prefab); } } +#endif \ No newline at end of file diff --git a/Factories/IMonoBehaviourFactory.cs b/Factories/IMonoBehaviourFactory.cs index cbf5e05..f32a349 100644 --- a/Factories/IMonoBehaviourFactory.cs +++ b/Factories/IMonoBehaviourFactory.cs @@ -1,3 +1,5 @@ +#if UNITY_5_3_OR_NEWER || UNITY_5 + using System; using UnityEngine; @@ -9,3 +11,4 @@ namespace Svelto.Factories } } +#endif \ No newline at end of file diff --git a/Observer/Observable.cs b/Observer/Observable.cs new file mode 100644 index 0000000..0741b1b --- /dev/null +++ b/Observer/Observable.cs @@ -0,0 +1,42 @@ +using System; + +namespace Svelto.Observer +{ + public delegate void ObserverAction(ref DispatchType parameter); + + public interface IObservable + { + event Action Notify; + + void Dispatch(); + } + + public interface IObservable + { + event ObserverAction Notify; + + void Dispatch(ref DispatchType parameter); + } + + public class Observable:IObservable + { + public event ObserverAction Notify; + + public void Dispatch(ref DispatchType parameter) + { + if (Notify != null) + Notify(ref parameter); + } + } + + public class Observable:IObservable + { + public event Action Notify; + + public void Dispatch() + { + if (Notify != null) + Notify(); + } + } +} diff --git a/Observer/Observer.cs b/Observer/Observer.cs new file mode 100644 index 0000000..7871f47 --- /dev/null +++ b/Observer/Observer.cs @@ -0,0 +1,111 @@ +using System; + +namespace Svelto.Observer.InterNamespace +{ + public abstract class Observer : IObserver + { + protected Observer(Observable observable) + { + observable.Notify += OnObservableDispatched; + + _unsubscribe = () => observable.Notify -= OnObservableDispatched; + } + + public void AddAction(ObserverAction action) + { + _actions += action; + } + + public void RemoveAction(ObserverAction action) + { + _actions -= action; + } + + public void Unsubscribe() + { + _unsubscribe(); + } + + void OnObservableDispatched(ref DispatchType dispatchNotification) + { + if (_actions != null) + { + var actionType = TypeMap(ref dispatchNotification); + + _actions(ref actionType); + } + } + + protected abstract ActionType TypeMap(ref DispatchType dispatchNotification); + + ObserverAction _actions; + Action _unsubscribe; + } +} + +namespace Svelto.Observer.IntraNamespace +{ + public class Observer : InterNamespace.Observer + { + public Observer(Observable observable) : base(observable) + { } + + protected override DispatchType TypeMap(ref DispatchType dispatchNotification) + { + return dispatchNotification; + } + } +} + +namespace Svelto.Observer +{ + public class Observer: IObserver + { + public Observer(Observable observable) + { + observable.Notify += OnObservableDispatched; + + _unsubscribe = () => observable.Notify -= OnObservableDispatched; + } + + public void AddAction(Action action) + { + _actions += action; + } + + public void RemoveAction(Action action) + { + _actions -= action; + } + + public void Unsubscribe() + { + _unsubscribe(); + } + + void OnObservableDispatched() + { + if (_actions != null) + _actions(); + } + + Action _actions; + readonly Action _unsubscribe; + } + + public interface IObserver + { + void AddAction(ObserverAction action); + void RemoveAction(ObserverAction action); + + void Unsubscribe(); + } + + public interface IObserver + { + void AddAction(Action action); + void RemoveAction(Action action); + + void Unsubscribe(); + } +} \ No newline at end of file diff --git a/Utilities/Console.cs b/Utilities/Console.cs index cf11720..c5ca1a5 100644 --- a/Utilities/Console.cs +++ b/Utilities/Console.cs @@ -11,22 +11,25 @@ namespace Utility public static class Console { static StringBuilder _stringBuilder = new StringBuilder(256); -#if UNITY_5_3_OR_NEWER || UNITY_5 - public static ILogger logger = new SlowLoggerUnity(); -#else - public static ILogger logger = new SimpleLogger(); -#endif + + public static ILogger logger; + public static volatile bool BatchLog = false; //Hack, have to find the right solution - public static Action onException; + public static Action onException; static Console() { - onException = (e, obj, message, stack) => - { - UnityEngine.Debug.LogException(e, (UnityEngine.Object)obj); - }; +#if UNITY_5_3_OR_NEWER || UNITY_5 + logger = new SlowLoggerUnity(); + onException = (e, message, stack) => + { + UnityEngine.Debug.LogException(e, null); + }; +#else + logger = new SimpleLogger(); +#endif } public static void Log(string txt) @@ -67,11 +70,6 @@ namespace Utility } public static void LogException(Exception e) - { - LogException(e, null); - } - - public static void LogException(Exception e, UnityEngine.Object obj) { string toPrint; string stackTrace; @@ -96,7 +94,8 @@ namespace Utility toPrint = _stringBuilder.ToString(); } - onException(e, obj, toPrint, stackTrace); + if (onException != null) + onException(e, toPrint, stackTrace); } public static void LogWarning(string txt) @@ -142,8 +141,12 @@ namespace Utility toPrint = _stringBuilder.ToString(); } -#if !UNITY_EDITOR && !NETFX_CORE +#if !UNITY_EDITOR +#if !NETFX_CORE System.Console.WriteLine(toPrint); +#else + //find a way to adopt a logger externally, if this is still needed +#endif #else UnityEngine.Debug.Log(toPrint); #endif diff --git a/Utilities/NetFXCoreWrappers.cs b/Utilities/NetFXCoreWrappers.cs new file mode 100644 index 0000000..b172b0b --- /dev/null +++ b/Utilities/NetFXCoreWrappers.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Threading; +using Svelto.DataStructures; + +namespace Svelto.Utilities +{ + public static class NetFXCoreWrappers + { + public static MethodInfo GetMethodInfoEx(this Delegate delegateEx) + { +#if NETFX_CORE + var method = delegateEx.GetMethodInfo(); +#else + var method = delegateEx.Method; +#endif + return method; + } + + public static Type GetDeclaringType(this MemberInfo memberInfo) + { +#if NETFX_CORE + return memberInfo.DeclaringType; +#else + return memberInfo.ReflectedType; +#endif + } + + public static Type GetBaseType(this Type type) + { +#if NETFX_CORE + return type.BaseType(); +#else + return type.BaseType; +#endif + } + + public static IEnumerable GetCustomAttributes(this Type type, bool inherit) + { +#if !NETFX_CORE + return Attribute.GetCustomAttributes(type, inherit); +#else + return type.GetTypeInfo().GetCustomAttributes(inherit); +#endif + } + + public static bool ContainsCustomAttribute(this MemberInfo memberInfo, Type customAttribute, bool inherit) + { +#if !NETFX_CORE + return Attribute.IsDefined(memberInfo, customAttribute, inherit); +#else + return memberInfo.GetCustomAttribute(customAttribute, inherit) != null; +#endif + } + + public static bool IsGenericTypeEx(this Type type) + { +#if !NETFX_CORE + return type.IsGenericType; +#else + return type.IsConstructedGenericType; +#endif + } + + public static MemberInfo[] FindWritablePropertiesWithCustomAttribute(this Type contract, + Type customAttributeType) + { + FasterList propertyList = new FasterList(8); + + do + { + var propertyInfos = contract.GetProperties(System.Reflection.BindingFlags.Public | + System.Reflection.BindingFlags.NonPublic | + System.Reflection.BindingFlags.DeclaredOnly | + System.Reflection.BindingFlags.Instance); + + for (int i = 0; i < propertyInfos.Length; i++) + { + PropertyInfo propertyInfo = propertyInfos[i]; + + if (propertyInfo.CanWrite && + propertyInfo.ContainsCustomAttribute(customAttributeType, false) == true) + propertyList.Add(propertyInfo); + } + + contract = contract.GetBaseType(); + } while (contract != null); + + if (propertyList.Count > 0) + return propertyList.ToArray(); + + return null; + } + + public static bool IsCompilerGenerated(this Type t) + { +#if NETFX_CORE + var attr = t.GetTypeInfo().GetCustomAttribute(typeof(CompilerGeneratedAttribute)); + + return attr != null; +#else + var attr = Attribute.IsDefined(t, typeof(CompilerGeneratedAttribute)); + + return attr; +#endif + } + + public static bool IsCompilerGenerated(this MemberInfo memberInfo) + { +#if NETFX_CORE + var attr = memberInfo.DeclaringType.GetTypeInfo().GetCustomAttribute(_compilerType); + + return attr != null; +#else + var attr = Attribute.IsDefined(memberInfo, _compilerType); + + return attr; +#endif + } + + static readonly Type _compilerType = typeof(CompilerGeneratedAttribute); + } +} diff --git a/Utilities/ThreadUtility.cs b/Utilities/ThreadUtility.cs new file mode 100644 index 0000000..9c87991 --- /dev/null +++ b/Utilities/ThreadUtility.cs @@ -0,0 +1,16 @@ +using System.Threading; + +namespace Svelto.Utilities +{ + public static class ThreadUtility + { + public static void MemoryBarrier() + { +#if NETFX_CORE || NET_4_6 + Interlocked.MemoryBarrier(); +#else + Thread.MemoryBarrier(); +#endif + } + } +} \ No newline at end of file diff --git a/WeakEvents/WeakAction.cs b/WeakEvents/WeakAction.cs index 8c5ece6..042bf62 100644 --- a/WeakEvents/WeakAction.cs +++ b/WeakEvents/WeakAction.cs @@ -1,6 +1,7 @@ using System; using System.Reflection; using System.Runtime.CompilerServices; +using Svelto.Utilities; namespace Svelto.WeakEvents { @@ -71,14 +72,8 @@ namespace Svelto.WeakEvents Method = method; -#if NETFX_CORE - var attributes = (CompilerGeneratedAttribute[])method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); - if (attributes.Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#else - if (method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) + if (method.IsCompilerGenerated() == true) throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#endif } protected void Invoke_Internal(object[] data) diff --git a/WeakEvents/WeakActionStruct.cs b/WeakEvents/WeakActionStruct.cs index 7686934..a073cea 100644 --- a/WeakEvents/WeakActionStruct.cs +++ b/WeakEvents/WeakActionStruct.cs @@ -2,6 +2,7 @@ using System; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Svelto.Utilities; //careful, you must handle the destruction of the GCHandles! namespace Svelto.WeakEvents @@ -116,15 +117,8 @@ namespace Svelto.WeakEvents methodOut = method; #if DEBUG && !PROFILER -#if NETFX_CORE - Method = listener.GetMethodInfo(); - var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); - if(attributes.Length != 0) + if (method.IsCompilerGenerated() == true) throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#else - if (method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#endif #endif } diff --git a/WeakEvents/WeakEvent.cs b/WeakEvents/WeakEvent.cs index 485df35..814f68b 100644 --- a/WeakEvents/WeakEvent.cs +++ b/WeakEvents/WeakEvent.cs @@ -1,6 +1,7 @@ using Svelto.DataStructures; using System; using System.Reflection; +using Svelto.Utilities; namespace Svelto.WeakEvents { @@ -9,7 +10,7 @@ namespace Svelto.WeakEvents public static WeakEvent operator+(WeakEvent c1, Action x) { if (c1 == null) c1 = new WeakEvent(); - c1._subscribers.Add(new WeakActionStruct(x)); + c1.Add(x); return c1; } @@ -17,11 +18,21 @@ namespace Svelto.WeakEvents public static WeakEvent operator-(WeakEvent c1, Action x) { DesignByContract.Check.Require(x != null); - c1.Remove(x.Target, x.GetMethodInfoEx()); + c1.Remove(x); return c1; } + public void Add(Action x) + { + _subscribers.Add(new WeakActionStruct(x)); + } + + public void Remove(Action x) + { + RemoveInternal(x.Target, x.GetMethodInfoEx()); + } + public void Invoke() { for (int i = 0; i < _subscribers.Count; i++) @@ -29,7 +40,7 @@ namespace Svelto.WeakEvents _subscribers.UnorderedRemoveAt(i--); } - void Remove(object thisObject, MethodInfo thisMethod) + void RemoveInternal(object thisObject, MethodInfo thisMethod) { for (int i = 0; i < _subscribers.Count; ++i) { @@ -58,7 +69,7 @@ namespace Svelto.WeakEvents public static WeakEvent operator+(WeakEvent c1, Action x) { if (c1 == null) c1 = new WeakEvent(); - c1._subscribers.Add(new WeakActionStruct(x)); + c1.Add(x); return c1; } @@ -66,11 +77,21 @@ namespace Svelto.WeakEvents public static WeakEvent operator-(WeakEvent c1, Action x) { DesignByContract.Check.Require(x != null); - c1.Remove(x.Target, x.GetMethodInfoEx()); + c1.Remove(x); return c1; } + public void Add(Action x) + { + _subscribers.Add(new WeakActionStruct(x)); + } + + public void Remove(Action x) + { + RemoveInternal(x.Target, x.GetMethodInfoEx()); + } + public void Invoke(T1 arg1) { args[0] = arg1; @@ -80,7 +101,7 @@ namespace Svelto.WeakEvents _subscribers.UnorderedRemoveAt(i--); } - void Remove(object thisObject, MethodInfo thisMethod) + void RemoveInternal(object thisObject, MethodInfo thisMethod) { for (int i = 0; i < _subscribers.Count; ++i) { @@ -119,11 +140,21 @@ namespace Svelto.WeakEvents public static WeakEvent operator-(WeakEvent c1, Action x) { DesignByContract.Check.Require(x != null); - c1.Remove(x.Target, x.GetMethodInfoEx()); + c1.Remove(x); return c1; } + public void Add(Action x) + { + _subscribers.Add(new WeakActionStruct(x)); + } + + public void Remove(Action x) + { + RemoveInternal(x.Target, x.GetMethodInfoEx()); + } + public void Invoke(T1 arg1, T2 arg2) { args[0] = arg1; @@ -134,7 +165,7 @@ namespace Svelto.WeakEvents _subscribers.UnorderedRemoveAt(i--); } - void Remove(object thisObject, MethodInfo thisMethod) + void RemoveInternal(object thisObject, MethodInfo thisMethod) { for (int i = 0; i < _subscribers.Count; ++i) { From 5897f66b2d3d1980cd567d4b3236110290be4b31 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Fri, 8 Dec 2017 18:18:26 +0000 Subject: [PATCH 02/22] - INodesEngine is now Legacy. EnginesRoot still support it, but I will probably add a new Legacy Engine Root to support INodesEngine. Best thing would be to transform all the INodesEngine into MultiNodesEngine - Support for grouped nodes (adding and querying them) is almost complete - EngineRoot and EngineNodeDB can now support nodes as struct and class - INodeEngine Add and Remove functions accept only NodeWithID (classes only) - --- ECS/DataStructures/TypeSafeDictionary.cs | 35 +- .../TypeSafeFasterListForECS.cs | 82 ++++ ECS/DataStructures/TypeSafeList.cs | 51 -- ECS/EngineNodeDB.cs | 58 ++- ECS/EnginesRoot.cs | 459 ++++++++++-------- ECS/EntityDescriptor.cs | 162 +++---- ECS/IEngine.cs | 20 +- ECS/IEngineNodeDB.cs | 18 +- ECS/INode.cs | 12 +- ECS/MultiNodesEngine.cs | 101 ++-- ECS/NodeBuilder.cs | 33 +- .../EngineProfiler/EngineProfilerInspector.cs | 4 +- ECS/Profiler/EngineProfiler.cs | 10 +- ECS/Profiler/EngineProfilerBehaviour.cs | 2 +- ECS/SingleNodeEngine.cs | 21 +- ECS/StructNodes.cs | 30 +- 16 files changed, 612 insertions(+), 486 deletions(-) create mode 100644 ECS/DataStructures/TypeSafeFasterListForECS.cs delete mode 100644 ECS/DataStructures/TypeSafeList.cs diff --git a/ECS/DataStructures/TypeSafeDictionary.cs b/ECS/DataStructures/TypeSafeDictionary.cs index 022ebe5..e399ba1 100644 --- a/ECS/DataStructures/TypeSafeDictionary.cs +++ b/ECS/DataStructures/TypeSafeDictionary.cs @@ -1,7 +1,8 @@ using Svelto.DataStructures; using System.Collections.Generic; +using Svelto.ECS.Internal; -namespace Svelto.ECS +namespace Svelto.ECS.Internal { /// /// This is just a place holder at the moment @@ -13,11 +14,37 @@ namespace Svelto.ECS public interface ITypeSafeDictionary { - + void FillWithIndexedNodes(ITypeSafeList nodes); + void Remove(int entityId); + NodeWithID GetIndexedNode(int entityID); } - public class TypeSafeDictionary : Dictionary, ITypeSafeDictionary + class TypeSafeDictionary : Dictionary, ITypeSafeDictionary where TValue:NodeWithID { - internal static readonly ReadOnlyDictionary Default = new ReadOnlyDictionary(new TypeSafeDictionary()); + internal static readonly ReadOnlyDictionary Default = + new ReadOnlyDictionary(new Dictionary()); + + public void FillWithIndexedNodes(ITypeSafeList nodes) + { + int count; + var buffer = FasterList.NoVirt.ToArrayFast((FasterList) nodes, out count); + + for (int i = 0; i < count; i++) + { + var node = buffer[i]; + + Add(node.ID, node); + } + } + + public void Remove(int entityId) + { + throw new System.NotImplementedException(); + } + + public NodeWithID GetIndexedNode(int entityID) + { + return this[entityID]; + } } } diff --git a/ECS/DataStructures/TypeSafeFasterListForECS.cs b/ECS/DataStructures/TypeSafeFasterListForECS.cs new file mode 100644 index 0000000..e6e47a3 --- /dev/null +++ b/ECS/DataStructures/TypeSafeFasterListForECS.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Svelto.DataStructures; + +namespace Svelto.ECS.Internal +{ + public interface ITypeSafeList: IEnumerable + { + void AddRange(ITypeSafeList nodeListValue); + + ITypeSafeList Create(); + bool isQueryiableNode { get; } + void UnorderedRemove(int index); + ITypeSafeDictionary CreateIndexedDictionary(); + } + + class TypeSafeFasterListForECS: FasterList where T:INode + { + protected TypeSafeFasterListForECS() + { + _mappedIndices = new Dictionary(); + } + + public void UnorderedRemove(int mappedIndex) + { + var index = _mappedIndices[mappedIndex]; + _mappedIndices.Remove(mappedIndex); + + if (UnorderedRemoveAt(index)) + _mappedIndices[this[index].ID] = index; + } + + public void AddRange(ITypeSafeList nodeListValue) + { + var index = this.Count; + + AddRange(nodeListValue as FasterList); + + for (int i = index; i < Count; ++i) + _mappedIndices[this[i].ID] = this.Count; + } + + readonly Dictionary _mappedIndices; + } + + class TypeSafeFasterListForECSForStructs : TypeSafeFasterListForECS, ITypeSafeList where T:struct, INode + { + public ITypeSafeList Create() + { + return new TypeSafeFasterListForECSForStructs(); + } + + public bool isQueryiableNode + { + get { return false; } + } + + public ITypeSafeDictionary CreateIndexedDictionary() + { + throw new Exception("Not Allowed"); + } + } + + class TypeSafeFasterListForECSForClasses : TypeSafeFasterListForECS, ITypeSafeList where T:NodeWithID + { + public ITypeSafeList Create() + { + return new TypeSafeFasterListForECSForClasses(); + } + + public bool isQueryiableNode + { + get { return true; } + } + + public ITypeSafeDictionary CreateIndexedDictionary() + { + return new TypeSafeDictionary(); + } + } +} diff --git a/ECS/DataStructures/TypeSafeList.cs b/ECS/DataStructures/TypeSafeList.cs deleted file mode 100644 index cac7c4b..0000000 --- a/ECS/DataStructures/TypeSafeList.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Svelto.DataStructures; -using Svelto.ECS.Internal; - -namespace Svelto.ECS -{ - public interface ITypeSafeList - { - void Clear(); - void AddRange(ITypeSafeList nodeListValue); - - ITypeSafeList Create(); - ITypeSafeDictionary CreateIndexedDictionary(); - void AddToIndexedDictionary(ITypeSafeDictionary nodesDic); - } - - public class TypeSafeFasterList : FasterList, ITypeSafeList - { - public TypeSafeFasterList() - { - } - - public void AddRange(ITypeSafeList nodeListValue) - { - AddRange(nodeListValue as FasterList); - } - - public ITypeSafeList Create() - { - return new TypeSafeFasterList(); - } - - public ITypeSafeDictionary CreateIndexedDictionary() - { - return new TypeSafeDictionary(); - } - - public void AddToIndexedDictionary(ITypeSafeDictionary nodesDic) - { - var dic = nodesDic as TypeSafeDictionary; - - var buffer = NoVirt.ToArrayFast(this); - - for (int i = 0; i < Count; i++) - { - T node = buffer[i]; - - dic[(node as NodeWithID).ID] = node; - } - } - } -} diff --git a/ECS/EngineNodeDB.cs b/ECS/EngineNodeDB.cs index 9e26351..126dd46 100644 --- a/ECS/EngineNodeDB.cs +++ b/ECS/EngineNodeDB.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Svelto.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS { @@ -8,11 +9,13 @@ namespace Svelto.ECS { internal EngineNodeDB( Dictionary nodesDB, Dictionary nodesDBdic, - Dictionary metaNodesDB) + Dictionary metaNodesDB, + Dictionary> groupNodesDB) { _nodesDB = nodesDB; _nodesDBdic = nodesDBdic; _metaNodesDB = metaNodesDB; + _groupNodesDB = groupNodesDB; } public FasterReadOnlyList QueryNodes() @@ -27,24 +30,46 @@ namespace Svelto.ECS return new FasterReadOnlyList((FasterList)nodes); } - public ReadOnlyDictionary QueryIndexableNodes() + public FasterReadOnlyList QueryGroupedNodes(int @group) + { + return new FasterReadOnlyList(_groupNodesDB[group] as FasterList); + } + + public T[] QueryNodesAsArray(out int count) where T : struct + { + var type = typeof(T); + count = 0; + + ITypeSafeList nodes; + + if (_nodesDB.TryGetValue(type, out nodes) == false) + return null; + + var castedNodes = (FasterList)nodes; + + count = castedNodes.Count; + + return castedNodes.ToArrayFast(); + } + + public ReadOnlyDictionary QueryIndexableNodes() where T:NodeWithID { var type = typeof(T); ITypeSafeDictionary nodes; if (_nodesDBdic.TryGetValue(type, out nodes) == false) - return TypeSafeDictionary.Default; + return TypeSafeDictionary.Default; return new ReadOnlyDictionary(nodes as Dictionary); } - public T QueryMetaNode(int metaEntityID) + public T QueryMetaNode(int metaEntityID) where T:NodeWithID { return QueryNode(metaEntityID); } - public bool TryQueryMetaNode(int metaEntityID, out T node) + public bool TryQueryMetaNode(int metaEntityID, out T node) where T:NodeWithID { return TryQueryNode(metaEntityID, out node); } @@ -61,18 +86,22 @@ namespace Svelto.ECS return new FasterReadOnlyList((FasterList)nodes); } - public bool TryQueryNode(int ID, out T node) + public bool TryQueryNode(int ID, out T node) where T:NodeWithID { var type = typeof(T); T internalNode; ITypeSafeDictionary nodes; + TypeSafeDictionary casted; - if (_nodesDBdic.TryGetValue(type, out nodes) && - (nodes as Dictionary).TryGetValue(ID, out internalNode)) + _nodesDBdic.TryGetValue(type, out nodes); + casted = nodes as TypeSafeDictionary; + + if (casted != null && + casted.TryGetValue(ID, out internalNode)) { - node = internalNode; + node = (T) internalNode; return true; } @@ -82,14 +111,18 @@ namespace Svelto.ECS return false; } - public T QueryNode(int ID) + public T QueryNode(int ID) where T:NodeWithID { var type = typeof(T); T internalNode; ITypeSafeDictionary nodes; + TypeSafeDictionary casted; + + _nodesDBdic.TryGetValue(type, out nodes); + casted = nodes as TypeSafeDictionary; - if (_nodesDBdic.TryGetValue(type, out nodes) && - (nodes as Dictionary).TryGetValue(ID, out internalNode)) + if (casted != null && + casted.TryGetValue(ID, out internalNode)) return (T)internalNode; throw new Exception("Node Not Found"); @@ -103,5 +136,6 @@ namespace Svelto.ECS readonly Dictionary _nodesDB; readonly Dictionary _nodesDBdic; readonly Dictionary _metaNodesDB; + readonly Dictionary> _groupNodesDB; } } diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs index 3deadf8..7602238 100644 --- a/ECS/EnginesRoot.cs +++ b/ECS/EnginesRoot.cs @@ -1,12 +1,13 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Linq; using Svelto.DataStructures; using Svelto.ECS.Internal; +using Svelto.ECS.Legacy; using Svelto.ECS.NodeSchedulers; -using System.Reflection; +using Svelto.ECS.Profiler; using Svelto.Utilities; -using UnityEngine.UI; -using UnityEngine.XR.WSA.Persistence; #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR using Svelto.ECS.Profiler; @@ -16,9 +17,9 @@ namespace Svelto.ECS.Internal { struct BuildNodeCallbackStruct { - public Action _internalRemove; - public Action _internalEnable; - public Action _internalDisable; + public Action, int> internalRemove; + public Action, int> internalEnable; + public Action, int> internalDisable; } } @@ -32,22 +33,37 @@ namespace Svelto.ECS _activableEngines = new Dictionary>(); _otherEngines = new FasterList(); - //_engineRootWeakReference = new DataStructures.WeakReference(this); + _engineRootWeakReference = new DataStructures.WeakReference(this); _nodesDB = new Dictionary(); _metaNodesDB = new Dictionary(); + _groupNodesDB = new Dictionary>(); _nodesDBdic = new Dictionary(); + + _sharedStructNodeLists = new SharedStructNodeLists(); + _sharedGroupedStructNodeLists = new SharedGroupedStructNodesLists(); + + _nodesToAdd = new DoubleBufferedNodes>(); + _metaNodesToAdd = new DoubleBufferedNodes>(); + _groupedNodesToAdd = new DoubleBufferedNodes>>(); + + _callBackStructForBuiltGroupedNodes = new BuildNodeCallbackStruct(); - _nodesToAdd = new Dictionary(); - _metaNodesToAdd = new Dictionary(); - _groupedNodesToAdd = new Dictionary>(); + _callBackStructForBuiltGroupedNodes.internalRemove = InternalRemove; + _callBackStructForBuiltGroupedNodes.internalDisable = InternalDisable; + _callBackStructForBuiltGroupedNodes.internalEnable = InternalEnable; - _callBackStruct = new BuildNodeCallbackStruct(); + _callBackStructForBuiltNodes = new BuildNodeCallbackStruct(); - /* _callBackStruct._internalRemove = InternalRemove; - _callBackStruct._internalDisable = InternalDisable; - _callBackStruct._internalEnable = InternalEnable; - _callBackStruct._internalMetaRemove = InternalMetaRemove;*/ + _callBackStructForBuiltNodes.internalRemove = InternalGroupedRemove; + _callBackStructForBuiltNodes.internalDisable = InternalDisable; + _callBackStructForBuiltNodes.internalEnable = InternalEnable; + + _callBackStructForBuiltMetaNodes = new BuildNodeCallbackStruct(); + + _callBackStructForBuiltMetaNodes.internalRemove = InternalMetaRemove; + _callBackStructForBuiltMetaNodes.internalDisable = InternalDisable; + _callBackStructForBuiltMetaNodes.internalEnable = InternalEnable; _scheduler = nodeScheduler; _scheduler.Schedule(SubmitNodes); @@ -58,15 +74,15 @@ namespace Svelto.ECS _implementedInterfaceTypes = new Dictionary(); -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - GameObject debugEngineObject = new GameObject("Engine Debugger"); +#if UNITY_EDITOR + UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); debugEngineObject.gameObject.AddComponent(); #endif } public void BuildEntity(int ID, EntityDescriptor ed) { - ed.BuildNodes(ID, _nodesToAdd, ref _callBackStruct); + ed.BuildNodes(ID, _nodesToAdd.other, ref _callBackStructForBuiltNodes); } /// @@ -95,7 +111,7 @@ namespace Svelto.ECS /// public void BuildMetaEntity(int metaEntityID, EntityDescriptor ed) { - ed.BuildNodes(metaEntityID, _metaNodesToAdd, ref _callBackStruct); + ed.BuildNodes(metaEntityID, _metaNodesToAdd.other, ref _callBackStructForBuiltMetaNodes); } /// @@ -110,18 +126,18 @@ namespace Svelto.ECS public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptor ed) { - ed.BuildGroupedNodes(entityID, groupID, _groupedNodesToAdd, ref _callBackStruct); + ed.BuildGroupedNodes(entityID, groupID, _groupedNodesToAdd.other, ref _callBackStructForBuiltGroupedNodes); } public void AddEngine(IEngine engine) { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +#if UNITY_EDITOR EngineProfiler.AddEngine(engine); #endif var queryableNodeEngine = engine as IQueryableNodeEngine; if (queryableNodeEngine != null) queryableNodeEngine.nodesDB = - new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB); + new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB, _groupNodesDB); var engineType = engine.GetType(); var implementedInterfaces = engineType.GetInterfaces(); @@ -171,6 +187,18 @@ namespace Svelto.ECS bool engineAdded = false; + if (_implementedInterfaceTypes.ContainsKey(_structNodeEngineType)) + { + ((IStructNodeEngine)engine).CreateStructNodes + (_sharedStructNodeLists); + } + + if (_implementedInterfaceTypes.ContainsKey(_groupedStructNodesEngineType)) + { + ((IGroupedStructNodesEngine)engine).CreateStructNodes + (_sharedGroupedStructNodeLists); + } + Type[] arguments; if (_implementedInterfaceTypes.TryGetValue(_activableNodeEngineType, out arguments)) @@ -235,36 +263,75 @@ namespace Svelto.ECS } } - static void AddNodesToTheDBAndSuitableEngines(Dictionary nodesToAdd, + static void AddNodesToTheDBAndSuitableEngines(Dictionary nodesToAdd, Dictionary> nodeEngines, Dictionary nodesDBdic, Dictionary nodesDB) { foreach (var nodeList in nodesToAdd) { - ITypeSafeList dbList; + AddNodeToDB(nodesDB, nodeList); - if (nodesDB.TryGetValue(nodeList.Key, out dbList) == false) - dbList = nodesDB[nodeList.Key] = nodeList.Value.Create(); + if (nodeList.Value.isQueryiableNode) + { + AddNodeToNodesDictionary(nodesDBdic, nodeList.Value, nodeList.Key); + + foreach (var node in nodeList.Value) + AddNodeToTheSuitableEngines(nodeEngines, node as NodeWithID, nodeList.Key); + } + } + } - dbList.AddRange(nodeList.Value); + static void AddGroupNodesToTheDBAndSuitableEngines(Dictionary> groupedNodesToAdd, + Dictionary> nodeEngines, + Dictionary nodesDBdic, + Dictionary> groupNodesDB, + Dictionary nodesDB) + { + foreach (var group in groupedNodesToAdd) + { + AddNodesToTheDBAndSuitableEngines(group.Value, nodeEngines, nodesDBdic, nodesDB); - AddNodeToNodesDictionary(nodesDBdic, nodeList.Value, nodeList.Key); - AddNodesToTheSuitableEngines(nodeEngines, nodeList.Value, nodeList.Key); + AddNodesToGroupDB(groupNodesDB, @group); } } + + static void AddNodesToGroupDB(Dictionary> groupNodesDB, + KeyValuePair> @group) + { + Dictionary groupedNodesByType; + + if (groupNodesDB.TryGetValue(@group.Key, out groupedNodesByType) == false) + groupedNodesByType = groupNodesDB[@group.Key] = new Dictionary(); + + foreach (var node in @group.Value) + { + groupedNodesByType.Add(node.Key, node.Value); + } + } + + static void AddNodeToDB(Dictionary nodesDB, KeyValuePair nodeList) + { + ITypeSafeList dbList; + + if (nodesDB.TryGetValue(nodeList.Key, out dbList) == false) + dbList = nodesDB[nodeList.Key] = nodeList.Value.Create(); + + dbList.AddRange(nodeList.Value); + } - static void AddNodeToNodesDictionary(Dictionary nodesDBdic, ITypeSafeList nodes, Type nodeType) + static void AddNodeToNodesDictionary(Dictionary nodesDBdic, + ITypeSafeList nodes, Type nodeType) { ITypeSafeDictionary nodesDic; - + if (nodesDBdic.TryGetValue(nodeType, out nodesDic) == false) nodesDic = nodesDBdic[nodeType] = nodes.CreateIndexedDictionary(); - nodes.AddToIndexedDictionary(nodesDic); + nodesDic.FillWithIndexedNodes(nodes); } - static void AddNodesToTheSuitableEngines(Dictionary> nodeEngines, ITypeSafeList nodes, Type nodeType) + static void AddNodeToTheSuitableEngines(Dictionary> nodeEngines, NodeWithID node, Type nodeType) { FasterList enginesForNode; @@ -273,191 +340,170 @@ namespace Svelto.ECS for (int j = 0; j < enginesForNode.Count; j++) { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorAddDuration(AddNodeToEngine, enginesForNode[j] as INodeEngine, node); + EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); #else - (enginesForNode[j] as INodeEngine).Add(nodes); + (enginesForNode[j] as INodeEngine).Add(node); #endif } } } - /* - void RemoveNodeFromTheDB(T node, Type nodeType) where T : INode - { - FasterList nodes; - if (_nodesDB.TryGetValue(nodeType, out nodes) == true) - nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? - } +/* + void DisableNodeFromEngines(INode node, Type nodeType) + { + ITypeSafeList enginesForNode; - void RemoveNodeFromMetaDB(T node, Type nodeType) where T : INode + if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) + { + for (int j = 0; j < enginesForNode.Count; j++) { - FasterList nodes; - if (_metaNodesDB.TryGetValue(nodeType, out nodes) == true) - nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? + (enginesForNode[j] as IActivableNodeEngine).Disable(node); } + } + } - void RemoveNodeFromNodesDictionary(T node, Type nodeType) where T : INodeWithID - { - Dictionary nodesDic; - - if (_nodesDBdic.TryGetValue(nodeType, out nodesDic)) - nodesDic.Remove(node.ID); - } + void EnableNodeFromEngines(INode node, Type nodeType) + { + ITypeSafeList enginesForNode; - void RemoveNodeFromEngines(T node, Type nodeType) where T : INode + if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) + { + for (int j = 0; j < enginesForNode.Count; j++) { - FasterList enginesForNode; - - if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) - { - #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); - #else - (enginesForNode[j] as INodeEngine).Remove(node); - #endif - } - } + (enginesForNode[j] as IActivableNodeEngine).Enable(node); } + } + }*/ +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + void AddNodeToEngine(IEngine engine, INode node) + { + (engine as INodeEngine).Add(node); + } - void DisableNodeFromEngines(INode node, Type nodeType) - { - FasterList enginesForNode; - - if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) - { - (enginesForNode[j] as IActivableNodeEngine).Disable(node); - } - } - } + void RemoveNodeFromEngine(IEngine engine, INode node) + { + (engine as INodeEngine).Remove(node); + } +#endif - void EnableNodeFromEngines(INode node, Type nodeType) - { - FasterList enginesForNode; - - if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) - { - (enginesForNode[j] as IActivableNodeEngine).Enable(node); - } - } - } - #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - void AddNodeToEngine(IEngine engine, INode node) - { - (engine as INodeEngine).Add(node); - } + void InternalDisable(FasterList nodeBuilders, int entityID) + { +/* if (_engineRootWeakReference.IsValid == false) + return; - void RemoveNodeFromEngine(IEngine engine, INode node) - { - (engine as INodeEngine).Remove(node); - } - #endif - /* - void InternalDisable(FasterList nodes) - { - if (_engineRootWeakReference.IsValid == false) - return; - - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); - DisableNodeFromEngines(node, nodeType); - } - } + for (int i = 0; i < nodes.Count; i++) + { + var node = nodes[i]; + Type nodeType = node.GetType(); + + DisableNodeFromEngines(node, nodeType); + }*/ + } - void InternalEnable(FasterList nodes) - { - if (_engineRootWeakReference.IsValid == false) - return; - - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); - EnableNodeFromEngines(node, nodeType); - } - } + void InternalEnable(FasterList nodeBuilders, int entityID) + {/* + if (_engineRootWeakReference.IsValid == false) + return; - void InternalRemove(IFasterList nodes) - { - if (_engineRootWeakReference.IsValid == false) - return; + for (int i = 0; i < nodes.Count; i++) + { + var node = nodes[i]; + Type nodeType = node.GetType(); + EnableNodeFromEngines(node, nodeType); + }*/ + } - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); + void InternalRemove(FasterList nodeBuilders, int entityID) + { + if (_engineRootWeakReference.IsValid == false) + return; - RemoveNodeFromEngines(node, nodeType); - RemoveNodeFromTheDB(node, node.GetType()); + int nodeBuildersCount = nodeBuilders.Count; + for (int i = 0; i < nodeBuildersCount; i++) + { + Type nodeType = nodeBuilders[i].GetType(); - var nodeWithId = node as INodeWithID; - if (nodeWithId != null) - RemoveNodeFromNodesDictionary(nodeWithId, nodeType); - } - } + ITypeSafeList nodes; + if (_nodesDB.TryGetValue(nodeType, out nodes) == true) + nodes.UnorderedRemove(entityID); - void InternalMetaRemove(FasterList nodes) + if (nodes.isQueryiableNode) { - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); - - RemoveNodeFromEngines(node, nodeType); - RemoveNodeFromMetaDB(node, nodeType); - - var nodeWithId = node as INodeWithID; - if (nodeWithId != null) - RemoveNodeFromNodesDictionary(nodeWithId, nodeType); - } + var node = _nodesDBdic[nodeType].GetIndexedNode(entityID); + + _nodesDBdic[nodeType].Remove(entityID); + + RemoveNodeFromEngines(_nodeEngines, node, nodeType); } + } + } + + void InternalGroupedRemove(FasterList nodeBuilders, int entityID) + { + } - readonly DataStructures.WeakReference _engineRootWeakReference; + void InternalMetaRemove(FasterList nodeBuilders, int entityID) + { + } + + static void RemoveNodeFromEngines(Dictionary> nodeEngines, NodeWithID node, Type nodeType) + { + FasterList enginesForNode; - */ + if (nodeEngines.TryGetValue(nodeType, out enginesForNode)) + { + for (int j = 0; j < enginesForNode.Count; j++) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); +#else + (enginesForNode[j] as INodeEngine).Remove(node); +#endif + } + } + } void SubmitNodes() { - int metaNodesCount = _metaNodesToAdd.Count; - int nodesCount = _nodesToAdd.Count; - - if (metaNodesCount + nodesCount == 0) return; + _nodesToAdd.Swap(); + _metaNodesToAdd.Swap(); + _groupedNodesToAdd.Swap(); + + bool newNodesHaveBeenAddedWhileIterating = + _metaNodesToAdd.Count > 0 + || _nodesToAdd.Count > 0 + || _groupedNodesToAdd.Count > 0; - bool newNodesHaveBeenAddedWhileIterating; - int startNodes = 0; - int startMetaNodes = 0; int numberOfReenteringLoops = 0; - do + while (newNodesHaveBeenAddedWhileIterating) { - AddNodesToTheDBAndSuitableEngines(_nodesToAdd, _nodeEngines, _nodesDBdic, _nodesDB); - AddNodesToTheDBAndSuitableEngines(_metaNodesToAdd, _nodeEngines, _nodesDBdic, _metaNodesDB); - + if ( _nodesToAdd.Count > 0) + AddNodesToTheDBAndSuitableEngines(_nodesToAdd.current, _nodeEngines, _nodesDBdic, _nodesDB); + + if ( _metaNodesToAdd.Count > 0) + AddNodesToTheDBAndSuitableEngines(_metaNodesToAdd.current, _nodeEngines, _nodesDBdic, _metaNodesDB); + + if (_groupedNodesToAdd.Count > 0) + AddGroupNodesToTheDBAndSuitableEngines(_groupedNodesToAdd.current, _nodeEngines, _nodesDBdic, _groupNodesDB, _nodesDB); + + _nodesToAdd.Clear(); + _metaNodesToAdd.Clear(); + _groupedNodesToAdd.Clear(); + + _nodesToAdd.Swap(); + _metaNodesToAdd.Swap(); + _groupedNodesToAdd.Swap(); + newNodesHaveBeenAddedWhileIterating = - _metaNodesToAdd.Count > metaNodesCount || - _nodesToAdd.Count > nodesCount; - - startNodes = nodesCount; - startMetaNodes = metaNodesCount; + _metaNodesToAdd.Count > 0 + || _nodesToAdd.Count > 0 + || _groupedNodesToAdd.Count > 0; if (numberOfReenteringLoops > 5) throw new Exception("possible infinite loop found creating Entities inside INodesEngine Add method, please consider building entities outside INodesEngine Add method"); numberOfReenteringLoops++; - - metaNodesCount = _metaNodesToAdd.Count; - nodesCount = _nodesToAdd.Count; - - } while (newNodesHaveBeenAddedWhileIterating); - - _nodesToAdd.Clear(); - _metaNodesToAdd.Clear(); + } } readonly Dictionary> _nodeEngines; @@ -467,25 +513,60 @@ namespace Svelto.ECS readonly Dictionary _nodesDB; readonly Dictionary _metaNodesDB; - readonly Dictionary> _groupNodesDB; + readonly Dictionary> _groupNodesDB; readonly Dictionary _nodesDBdic; - /// - /// Need to think about how to make BuildEntity thread safe as well - /// - readonly Dictionary _nodesToAdd; - readonly Dictionary _metaNodesToAdd; - readonly Dictionary> _groupedNodesToAdd; + readonly DoubleBufferedNodes> _nodesToAdd; + readonly DoubleBufferedNodes> _metaNodesToAdd; + readonly DoubleBufferedNodes>> _groupedNodesToAdd; readonly NodeSubmissionScheduler _scheduler; readonly Type _structNodeEngineType; readonly Type _groupedStructNodesEngineType; readonly Type _activableNodeEngineType; + + readonly SharedStructNodeLists _sharedStructNodeLists; + readonly SharedGroupedStructNodesLists _sharedGroupedStructNodeLists; - readonly Dictionary _implementedInterfaceTypes; + readonly Dictionary _implementedInterfaceTypes; + readonly DataStructures.WeakReference _engineRootWeakReference; - BuildNodeCallbackStruct _callBackStruct; + BuildNodeCallbackStruct _callBackStructForBuiltNodes; + BuildNodeCallbackStruct _callBackStructForBuiltGroupedNodes; + BuildNodeCallbackStruct _callBackStructForBuiltMetaNodes; + + class DoubleBufferedNodes where T : class, IDictionary, new() + { + readonly T _nodesToAddBufferA = new T(); + readonly T _nodesToAddBufferB = new T(); + + public DoubleBufferedNodes() + { + this.other = _nodesToAddBufferA; + this.current = _nodesToAddBufferB; + } + + public T other { get; private set; } + public T current { get; private set; } + + public int Count + { + get { return current.Count; } + } + + public void Clear() + { + current.Clear(); + } + + public void Swap() + { + var toSwap = other; + other = current; + current = toSwap; + } + } } } \ No newline at end of file diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs index 6c96c06..6202eac 100644 --- a/ECS/EntityDescriptor.cs +++ b/ECS/EntityDescriptor.cs @@ -8,24 +8,6 @@ namespace Svelto.ECS { public class EntityDescriptor { - protected EntityDescriptor() - {} - - /// - /// if you want to avoid allocation in run-time, you can prebuild - /// EntityDescriptors and use them to build entities at different - /// times - /// - protected EntityDescriptor(INodeBuilder[] nodesToBuild) - { - _nodesToBuild = new FasterList(nodesToBuild); - } - protected EntityDescriptor(INodeBuilder[] nodesToBuild, - params object[] componentsImplementor):this(nodesToBuild) - { - ProcessImplementors(componentsImplementor); - } - public void AddImplementors(params object[] componentsImplementor) { ProcessImplementors(componentsImplementor); @@ -38,7 +20,7 @@ namespace Svelto.ECS internal void BuildGroupedNodes (int entityID, int groupID, - Dictionary> groupNodes, + Dictionary> groupNodesByType, ref BuildNodeCallbackStruct callBackstruct) { for (int index = 0; index < _nodesToBuild.Count; index++) @@ -46,62 +28,68 @@ namespace Svelto.ECS var nodeBuilder = _nodesToBuild[index]; var nodeType = nodeBuilder.GetNodeType(); - Dictionary groupedNodesTyped; + Dictionary groupedNodesTyped; - if (groupNodes.TryGetValue(nodeType, out groupedNodesTyped) == false) + if (groupNodesByType.TryGetValue(groupID, out groupedNodesTyped) == false) { - groupedNodesTyped = new Dictionary(); + groupedNodesTyped = new Dictionary(); - groupNodes.Add(nodeType, groupedNodesTyped); + groupNodesByType.Add(groupID, groupedNodesTyped); }; - - ITypeSafeList nodes; - - var mustAdd = groupedNodesTyped.TryGetValue(groupID, out nodes) == false; - - var node = nodeBuilder.BuildAndAddToList(ref nodes, entityID); - - if (mustAdd) - groupedNodesTyped[groupID] = nodes; - - if (node != null && nodeBuilder.reflects != FillNodeMode.None) - { - node = FillNode(node, nodeBuilder.reflects); - - SetupImplementors(ref callBackstruct, nodes); - } - - /* var groupNode = node as IGroupedNode; - if (groupNode != null) - groupNode.groupID = groupID;*/ + + BuildAndFillNode(entityID, groupedNodesTyped, nodeType, nodeBuilder); } + + SetupImplementors(ref callBackstruct, entityID); } internal void BuildNodes(int entityID, - Dictionary nodesToAdd, + Dictionary nodesByType, ref BuildNodeCallbackStruct callBackstruct) { - for (int index = 0; index < _nodesToBuild.Count; index++) + int count = _nodesToBuild.Count; + + for (int index = 0; index < count; index++) { var nodeBuilder = _nodesToBuild[index]; var nodeType = nodeBuilder.GetNodeType(); + + BuildAndFillNode(entityID, nodesByType, nodeType, nodeBuilder); + } + + SetupImplementors(ref callBackstruct, entityID); + } + + void BuildAndFillNode(int entityID, Dictionary groupedNodesTyped, Type nodeType, INodeBuilder nodeBuilder) + { + ITypeSafeList nodes; - ITypeSafeList nodes; - - var mustAdd = nodesToAdd.TryGetValue(nodeType, out nodes) == false; - - var node = nodeBuilder.BuildAndAddToList(ref nodes, entityID); + var nodesPoolWillBeCreated = groupedNodesTyped.TryGetValue(nodeType, out nodes) == false; + var nodeObjectToFill = nodeBuilder.BuildNodeAndAddToList(ref nodes, entityID); - if (mustAdd) - nodesToAdd[nodeType] = nodes; + if (nodesPoolWillBeCreated) + groupedNodesTyped.Add(nodeType, nodes); - if (node != null && nodeBuilder.reflects != FillNodeMode.None) - { - FillNode(node, nodeBuilder.reflects); - - SetupImplementors(ref callBackstruct, nodes); - } - } + //the semantic of this code must still be improved + //but only classes can be filled, so I am aware + //it's a NodeWithID + if (nodeObjectToFill != null) + FillNode(nodeObjectToFill as NodeWithID); + } + + /// + /// if you want to avoid allocation in run-time, you can prebuild + /// EntityDescriptors and use them to build entities at different + /// times + /// + protected EntityDescriptor(INodeBuilder[] nodesToBuild) + { + _nodesToBuild = new FasterList(nodesToBuild); + } + protected EntityDescriptor(INodeBuilder[] nodesToBuild, + params object[] componentsImplementor):this(nodesToBuild) + { + ProcessImplementors(componentsImplementor); } void ProcessImplementors(object[] implementors) @@ -144,30 +132,41 @@ namespace Svelto.ECS void SetupImplementors( ref BuildNodeCallbackStruct callBackstruct, - ITypeSafeList nodes) + int entityID) { - var RemoveEntity = callBackstruct._internalRemove; - var DisableEntity = callBackstruct._internalDisable; - var EnableEntity = callBackstruct._internalEnable; + var RemoveEntity = callBackstruct.internalRemove; + var DisableEntity = callBackstruct.internalDisable; + var EnableEntity = callBackstruct.internalEnable; - Action removeEntityAction = () => { RemoveEntity(nodes); nodes.Clear(); }; - Action disableEntityAction = () => DisableEntity(nodes); - Action enableEntityAction = () => EnableEntity(nodes); - int removingImplementorsCount = _removingImplementors.Count; - for (int index = 0; index < removingImplementorsCount; index++) - _removingImplementors[index].Target.removeEntity = removeEntityAction; - + if (removingImplementorsCount > 0) + { + Action removeEntityAction = () => RemoveEntity(_nodesToBuild, entityID); + + for (int index = 0; index < removingImplementorsCount; index++) + _removingImplementors[index].Target.removeEntity = removeEntityAction; + } + int disablingImplementorsCount = _disablingImplementors.Count; - for (int index = 0; index < disablingImplementorsCount; index++) - _disablingImplementors[index].Target.disableEntity = disableEntityAction; - + if (disablingImplementorsCount > 0) + { + Action disableEntityAction = () => DisableEntity(_nodesToBuild, entityID); + + for (int index = 0; index < disablingImplementorsCount; index++) + _disablingImplementors[index].Target.disableEntity = disableEntityAction; + } + int enablingImplementorsCount = _enablingImplementors.Count; - for (int index = 0; index < enablingImplementorsCount; index++) - _enablingImplementors[index].Target.enableEntity = enableEntityAction; + if (enablingImplementorsCount > 0) + { + Action enableEntityAction = () => EnableEntity(_nodesToBuild, entityID); + + for (int index = 0; index < enablingImplementorsCount; index++) + _enablingImplementors[index].Target.enableEntity = enableEntityAction; + } } - TNode FillNode(TNode node, FillNodeMode mode) where TNode : INode + void FillNode(TNode node) where TNode : NodeWithID { var fields = node.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); @@ -180,15 +179,12 @@ namespace Svelto.ECS if (_implementorsByType.TryGetValue(fieldType, out component) == false) { - if (mode == FillNodeMode.Strict) - { Exception e = new Exception(NOT_FOUND_EXCEPTION + field.FieldType.Name + " - Node: " + node.GetType().Name + " - EntityDescriptor " + this); throw e; - } } else field.SetValue(node, component.Target); @@ -205,10 +201,8 @@ namespace Svelto.ECS #endif } - - return node; } - + readonly FasterList> _disablingImplementors = new FasterList>(); readonly FasterList> _removingImplementors = new FasterList>(); readonly FasterList> _enablingImplementors = new FasterList>(); @@ -217,8 +211,8 @@ namespace Svelto.ECS #if DEBUG && !PROFILER readonly Dictionary _implementorCounterByType = new Dictionary(); #endif - readonly FasterList _nodesToBuild; - + readonly FasterList _nodesToBuild; + const string DUPLICATE_IMPLEMENTOR_ERROR = "the same component is implemented with more than one implementor. This is considered an error and MUST be fixed. "; const string NULL_IMPLEMENTOR_ERROR = "Null implementor, are you using a wild GetComponents to fetch it? "; const string NOT_FOUND_EXCEPTION = "Svelto.ECS: Implementor not found for a Node. Implementor Type: "; diff --git a/ECS/IEngine.cs b/ECS/IEngine.cs index 0a4629a..bb4c012 100644 --- a/ECS/IEngine.cs +++ b/ECS/IEngine.cs @@ -1,4 +1,4 @@ -using Svelto.DataStructures; +using Rewired.Utils; using Svelto.ECS.Internal; namespace Svelto.ECS.Internal @@ -15,16 +15,19 @@ namespace Svelto.ECS.Internal public interface IActivableNodeEngine : IEngine { - void Enable(ITypeSafeList nodes); - void Disable(ITypeSafeList nodes); + void Enable(NodeWithID node); + void Disable(NodeWithID node); } public interface INodeEngine : IEngine { - void Add(ITypeSafeList nodes); - void Remove(ITypeSafeList nodes); + void Add(NodeWithID node); + void Remove(NodeWithID node); } +} +namespace Svelto.ECS.Legacy +{ public interface INodesEngine : INodeEngine { System.Type[] AcceptedNodes(); @@ -57,7 +60,10 @@ namespace Svelto.ECS /// usually the ID is the owner of the nodes of that /// group /// - public interface IGroupedStructNodesEngine : IGroupedStructNodesEngine where T:struct, IGroupedNode - { } + public interface IGroupedStructNodesEngine : IGroupedStructNodesEngine where T : struct, IGroupedNode + { + void Add(ref T node); + void Remove(ref T node); + } } diff --git a/ECS/IEngineNodeDB.cs b/ECS/IEngineNodeDB.cs index 3906d79..05a2c6f 100644 --- a/ECS/IEngineNodeDB.cs +++ b/ECS/IEngineNodeDB.cs @@ -4,15 +4,19 @@ namespace Svelto.ECS { public interface IEngineNodeDB { - ReadOnlyDictionary QueryIndexableNodes(); - - bool TryQueryNode(int ID, out T node); - T QueryNode(int ID); FasterReadOnlyList QueryNodes(); - - bool TryQueryMetaNode(int metaEntityID, out T node); - T QueryMetaNode(int metaEntityID); FasterReadOnlyList QueryMetaNodes(); + FasterReadOnlyList QueryGroupedNodes(int group); + + T[] QueryNodesAsArray(out int count) where T:struct; + + ReadOnlyDictionary QueryIndexableNodes() where T:NodeWithID; + + bool TryQueryNode(int ID, out T node) where T:NodeWithID; + T QueryNode(int ID) where T:NodeWithID; + + bool TryQueryMetaNode(int metaEntityID, out T node) where T:NodeWithID; + T QueryMetaNode(int metaEntityID) where T:NodeWithID; } } diff --git a/ECS/INode.cs b/ECS/INode.cs index fc53c55..4876a86 100644 --- a/ECS/INode.cs +++ b/ECS/INode.cs @@ -1,17 +1,19 @@ namespace Svelto.ECS { public interface INode - {} - - public interface IStructNodeWithID : INode { - int ID { get; set; } + int ID { get; } } - + public interface IGroupedNode { int groupID { get; set; } } + + public interface IStructNodeWithID : INode + { + new int ID { get; set; } + } public class NodeWithID: INode { diff --git a/ECS/MultiNodesEngine.cs b/ECS/MultiNodesEngine.cs index 97cb3ac..3559310 100644 --- a/ECS/MultiNodesEngine.cs +++ b/ECS/MultiNodesEngine.cs @@ -3,102 +3,83 @@ using Svelto.ECS.Internal; namespace Svelto.ECS.Internal { - public abstract class MultiNodesEngine where T:class + public abstract class MultiNodesEngine:INodeEngine where T:NodeWithID { - protected abstract void AddNode(T node); - protected abstract void RemoveNode(T node); + protected abstract void Add(T node); + protected abstract void Remove(T node); + + public virtual void Add(NodeWithID node) + { + Add((T) node); + } + + public virtual void Remove(NodeWithID node) + { + Remove((T) node); + } } } namespace Svelto.ECS { - public abstract class MultiNodesEngine : INodesEngine - { - public abstract System.Type[] AcceptedNodes(); - - public abstract void Add(ITypeSafeList nodeWrapper); - public abstract void Remove(ITypeSafeList nodeWrapper); - } - - public abstract class MultiNodesEngine : MultiNodesEngine, - INodeEngine where T:class where U:class + public abstract class MultiNodesEngine : MultiNodesEngine + where T:NodeWithID where U:NodeWithID { - protected abstract void AddNode(U node); - protected abstract void RemoveNode(U node); + protected abstract void Add(U node); + protected abstract void Remove(U node); - public virtual void Add(ITypeSafeList nodes) + public override void Add(NodeWithID node) { - if (nodes is FasterList) + var castedNode = node as U; + if (castedNode != null) { - var strongTypeNodes = (FasterList)nodes; - - for (int i = 0; i < strongTypeNodes.Count; i++) - { - AddNode(strongTypeNodes[i]); - } + Add(castedNode); } else - if (nodes is FasterList) { - var strongTypeNodes = (FasterList)nodes; - - for (int i = 0; i < strongTypeNodes.Count; i++) - { - AddNode(strongTypeNodes[i]); - } + base.Add(node); } } - public virtual void Remove(ITypeSafeList nodeWrapper) + public override void Remove(NodeWithID node) { - /* if (nodeWrapper is NodeWrapper) + if (node is U) { - T node; - nodeWrapper.GetNode(out node); - - RemoveNode(ref node); + Remove((U) node); } else { - U node; - nodeWrapper.GetNode(out node); - - RemoveNode(ref node); - }*/ + base.Remove(node); + } } } - public abstract class MultiNodesEngine : MultiNodesEngine where T: class where U : class + public abstract class MultiNodesEngine : MultiNodesEngine + where T: NodeWithID where U : NodeWithID where V:NodeWithID { - protected abstract void AddNode(V node); - protected abstract void RemoveNode(V node); + protected abstract void Add(V node); + protected abstract void Remove(V node); - public override void Add(ITypeSafeList nodes) + public override void Add(NodeWithID node) { - if (nodes is FasterList) + var castedNode = node as V; + if (castedNode != null) { - var strongTypeNodes = (FasterList)nodes; - - for (int i = 0; i < strongTypeNodes.Count; i++) - { - AddNode(strongTypeNodes[i]); - } + Add(castedNode); } else - base.Add(nodes); + base.Add(node); } - public override void Remove(ITypeSafeList nodeWrapper) + public override void Remove(NodeWithID node) { - /* if (nodeWrapper is V) + var castedNode = node as V; + if (castedNode != null) { - V node; - nodeWrapper.GetNode(out node); - - RemoveNode(ref node); + Remove(castedNode); } else - base.Remove(nodeWrapper);*/ + base.Remove(node); } } } \ No newline at end of file diff --git a/ECS/NodeBuilder.cs b/ECS/NodeBuilder.cs index 17b9c34..70deb96 100644 --- a/ECS/NodeBuilder.cs +++ b/ECS/NodeBuilder.cs @@ -6,21 +6,19 @@ namespace Svelto.ECS { public interface INodeBuilder { - INode BuildAndAddToList(ref ITypeSafeList list, int entityID); + INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID); Type GetNodeType(); - - FillNodeMode reflects { get; } } public class NodeBuilder : INodeBuilder where NodeType : NodeWithID, new() { - public INode BuildAndAddToList(ref ITypeSafeList list, int entityID) + public INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID) { if (list == null) - list = new TypeSafeFasterList(); + list = new TypeSafeFasterListForECSForClasses(); - var castedList = list as FasterList; + var castedList = list as TypeSafeFasterListForECSForClasses; var node = NodeWithID.BuildNode(entityID); @@ -29,11 +27,6 @@ namespace Svelto.ECS return node; } - public FillNodeMode reflects - { - get { return FillNodeMode.Strict; } - } - public Type GetNodeType() { return typeof(NodeType); @@ -42,15 +35,15 @@ namespace Svelto.ECS public class StructNodeBuilder : INodeBuilder where NodeType : struct, IStructNodeWithID { - public INode BuildAndAddToList(ref ITypeSafeList list, int entityID) + public INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID) { var node = default(NodeType); node.ID = entityID; if (list == null) - list = new TypeSafeFasterList(); + list = new TypeSafeFasterListForECSForStructs(); - var castedList = list as FasterList; + var castedList = list as TypeSafeFasterListForECSForStructs; castedList.Add(node); @@ -61,17 +54,5 @@ namespace Svelto.ECS { return typeof(NodeType); } - - public virtual FillNodeMode reflects - { - get { return FillNodeMode.None; } - } - } - - public enum FillNodeMode - { - Strict, - - None } } \ No newline at end of file diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs index d774c2b..0947e8a 100644 --- a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs +++ b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs @@ -1,6 +1,6 @@ -#if asdUNITY_EDITOR +#if UNITY_EDITOR + using System; -using System.Collections.Generic; using UnityEditor; using UnityEngine; diff --git a/ECS/Profiler/EngineProfiler.cs b/ECS/Profiler/EngineProfiler.cs index c659c87..14ed4c7 100644 --- a/ECS/Profiler/EngineProfiler.cs +++ b/ECS/Profiler/EngineProfiler.cs @@ -1,4 +1,3 @@ -#if asdDEBUG using System; using System.Collections.Generic; using System.Diagnostics; @@ -13,10 +12,9 @@ namespace Svelto.ECS.Profiler { static readonly Stopwatch _stopwatch = new Stopwatch(); - public static void MonitorAddDuration(Action addingFunc, INodeEngine engine, INodeWrapper node) + public static void MonitorAddDuration(Action addingFunc, INodeEngine engine, INode node) { EngineInfo info; - if (engineInfos.TryGetValue(engine.GetType(), out info)) { _stopwatch.Start(); @@ -27,15 +25,14 @@ namespace Svelto.ECS.Profiler } } - public static void MonitorRemoveDuration(Action removeFunc, INodeEngine engine, INodeWrapper node) + public static void MonitorRemoveDuration(Action removeFunc, INodeEngine engine, NodeWithID node) { EngineInfo info; - if (engineInfos.TryGetValue(engine.GetType(), out info)) { _stopwatch.Start(); removeFunc(engine, node); - // engine.Remove(node); + engine.Remove(node); _stopwatch.Reset(); info.AddRemoveDuration(_stopwatch.Elapsed.TotalMilliseconds); @@ -61,4 +58,3 @@ namespace Svelto.ECS.Profiler public static readonly Dictionary engineInfos = new Dictionary(); } } -#endif \ No newline at end of file diff --git a/ECS/Profiler/EngineProfilerBehaviour.cs b/ECS/Profiler/EngineProfilerBehaviour.cs index bb046bb..a350ae7 100644 --- a/ECS/Profiler/EngineProfilerBehaviour.cs +++ b/ECS/Profiler/EngineProfilerBehaviour.cs @@ -1,4 +1,4 @@ -#if asdUNITY_EDITOR +#if UNITY_EDITOR using System; using System.Collections.Generic; using UnityEngine; diff --git a/ECS/SingleNodeEngine.cs b/ECS/SingleNodeEngine.cs index 85ad0d9..82b6727 100644 --- a/ECS/SingleNodeEngine.cs +++ b/ECS/SingleNodeEngine.cs @@ -1,28 +1,17 @@ -using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS { - public abstract class SingleNodeEngine : INodeEngine where T:class + public abstract class SingleNodeEngine : INodeEngine where T:NodeWithID { - public void Add(ITypeSafeList nodes) + public void Add(NodeWithID node) { - var strongTypeNodes = (FasterList)nodes; - - for (int i = 0; i < strongTypeNodes.Count; i++) - { - Add(strongTypeNodes[i]); //when byref returns will be vailable, this should be passed by reference, not copy! - } + Add((T)node); //when byref returns will be vailable, this should be passed by reference, not copy! } - public void Remove(ITypeSafeList nodes) + public void Remove(NodeWithID node) { - /* - T node; - - nodeWrapper.GetNode(out node); - - Remove(node);*/ + Remove((T)node); } protected abstract void Add(T node); diff --git a/ECS/StructNodes.cs b/ECS/StructNodes.cs index 6a6a60a..0ccaf94 100644 --- a/ECS/StructNodes.cs +++ b/ECS/StructNodes.cs @@ -60,8 +60,8 @@ namespace Svelto.ECS public T[] GetList(int groupID, out int numberOfItems) { var fasterList = (SharedGroupedStructNodesLists.NoVirt.GetList(_container, groupID) as FasterList); - numberOfItems = FasterList.NoVirt.Count(fasterList); - return FasterList.NoVirt.ToArrayFast(fasterList); + + return FasterList.NoVirt.ToArrayFast(fasterList, out numberOfItems); } readonly SharedGroupedStructNodesLists _container; @@ -72,20 +72,20 @@ namespace Svelto.ECS { internal SharedStructNodeLists() { - _collection = new Dictionary(); + _collection = new Dictionary(); } internal static class NoVirt { internal static FasterList GetList(SharedStructNodeLists obj) where T : struct { - ITypeSafeList list; + IFasterList list; if (obj._collection.TryGetValue(typeof(T), out list)) { return list as FasterList; } - list = new TypeSafeFasterList(); + list = new FasterList(); obj._collection.Add(typeof(T), list); @@ -93,42 +93,42 @@ namespace Svelto.ECS } } - readonly Dictionary _collection; + readonly Dictionary _collection; } public class SharedGroupedStructNodesLists { internal SharedGroupedStructNodesLists() { - _collection = new Dictionary>(); + _collection = new Dictionary>(); } internal static class NoVirt { - internal static ITypeSafeList GetList(SharedGroupedStructNodesLists list, int groupID) where T : struct + internal static IFasterList GetList(SharedGroupedStructNodesLists list, int groupID) where T : struct { - Dictionary dic = GetGroup(list); - ITypeSafeList localList; + Dictionary dic = GetGroup(list); + IFasterList localList; if (dic.TryGetValue(groupID, out localList)) return localList; - localList = new TypeSafeFasterList(); + localList = new FasterList(); dic.Add(groupID, localList); return localList; } - internal static Dictionary GetGroup(SharedGroupedStructNodesLists list) where T : struct + internal static Dictionary GetGroup(SharedGroupedStructNodesLists list) where T : struct { - Dictionary dic; + Dictionary dic; if (list._collection.TryGetValue(typeof(T), out dic)) { return dic; } - dic = new Dictionary(); + dic = new Dictionary(); list._collection.Add(typeof(T), dic); @@ -136,6 +136,6 @@ namespace Svelto.ECS } } - readonly Dictionary> _collection; + readonly Dictionary> _collection; } } \ No newline at end of file From 0f98e9264a8d1c8dda001ac0310e784c912c898a Mon Sep 17 00:00:00 2001 From: sebas77 Date: Fri, 8 Dec 2017 18:19:50 +0000 Subject: [PATCH 03/22] new FasterList --- DataStructures/FasterList.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/DataStructures/FasterList.cs b/DataStructures/FasterList.cs index cfd9825..384683c 100644 --- a/DataStructures/FasterList.cs +++ b/DataStructures/FasterList.cs @@ -466,7 +466,10 @@ namespace Svelto.DataStructures readonly FasterList _list; } - public class FasterList : IList + public interface IFasterList + {} + + public class FasterList : IList, IFasterList { const int MIN_SIZE = 4; @@ -807,9 +810,11 @@ namespace Svelto.DataStructures { return fasterList._count; } - - public static T[] ToArrayFast(FasterList fasterList) + + public static T[] ToArrayFast(FasterList fasterList, out int count) { + count = fasterList._count; + return fasterList._buffer; } } From 52019c75f496d2e63f3ae2395475f356fec3ab58 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Sat, 23 Dec 2017 00:10:43 +0000 Subject: [PATCH 04/22] Svelto-ECS 2.0 first draft --- Context/Factories/MonoBehaviourFactory.cs | 1 - Context/IUnityCompositionRoot.cs | 11 + Context/IWaitForFrameworkDestruction.cs | 2 - Context/IWaitForFrameworkInitialization.cs | 2 - Context/UnityContext.cs | 5 + DataStructures/FasterList.cs | 16 +- DataStructures/IGraphNode.cs | 2 +- .../LeftLeaningKeyedRedBlackTree.cs | 400 +++++----- DataStructures/LeftLeaningRedBlackTree.cs | 440 +++++------ DataStructures/LockFreeQueue.cs | 65 +- .../PriorityQueue/HeapPriorityQueue.cs | 200 +++-- .../PriorityQueue/IPriorityQueue.cs | 10 +- .../PriorityQueue/PriorityQueueNode.cs | 6 +- ECS/DataStructures/TypeSafeDictionary.cs | 25 +- .../TypeSafeFasterListForECS.cs | 46 +- ECS/EngineNodeDB.cs | 159 ++-- ECS/EnginesRoot.cs | 743 ++++++++++-------- ECS/EntityDescriptor.cs | 220 ------ ECS/EntityDescriptorTemplate.cs | 221 ++++++ ECS/Experimental/StructNodeCollections.cs | 178 +++++ .../Unity/GenericEntityDescriptorHolder.cs | 14 + .../Unity/UnitySumbmissionNodeScheduler.cs | 26 +- ECS/GenericEntityDescriptor.cs | 262 ++---- ECS/GenericEntityDescriptorHolder.cs | 31 - ECS/ICallBackOnAddEngine.cs | 7 - ECS/IEngine.cs | 66 +- ECS/IEngineNodeDB.cs | 22 +- ECS/IEnginesInterfaces.cs | 31 + ECS/IEnginesRoot.cs | 16 - ECS/IEntityDescriptorHolder.cs | 6 +- ECS/INode.cs | 65 +- ECS/IRemoveEntityComponent.cs | 19 - ECS/MixedEntityDescriptor.cs | 107 +++ ECS/MultiNodesEngine.cs | 72 +- ECS/NodeBuilder.cs | 49 +- ECS/NodeSubmissionScheduler.cs | 8 +- ECS/Profiler/EngineInfo.cs | 16 +- ECS/Profiler/EngineProfiler.cs | 10 +- ECS/RemoveEntityImplementor.cs | 42 + ECS/SingleNodeEngine.cs | 14 +- ECS/StructNodes.cs | 141 ---- ECS/note.txt | 4 +- Utilities/FastInvoke.cs | 24 + Utilities/Murmur3.cs | 1 - Utilities/NetFXCoreWrappers.cs | 1 - WeakEvents/WeakAction.cs | 1 - WeakEvents/WeakActionStruct.cs | 1 - WeakEvents/WeakEvent.cs | 1 - 48 files changed, 1984 insertions(+), 1825 deletions(-) create mode 100644 Context/IUnityCompositionRoot.cs delete mode 100644 ECS/EntityDescriptor.cs create mode 100644 ECS/EntityDescriptorTemplate.cs create mode 100644 ECS/Experimental/StructNodeCollections.cs create mode 100644 ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs delete mode 100644 ECS/GenericEntityDescriptorHolder.cs delete mode 100644 ECS/ICallBackOnAddEngine.cs create mode 100644 ECS/IEnginesInterfaces.cs delete mode 100644 ECS/IEnginesRoot.cs delete mode 100644 ECS/IRemoveEntityComponent.cs create mode 100644 ECS/MixedEntityDescriptor.cs create mode 100644 ECS/RemoveEntityImplementor.cs delete mode 100644 ECS/StructNodes.cs create mode 100644 Utilities/FastInvoke.cs diff --git a/Context/Factories/MonoBehaviourFactory.cs b/Context/Factories/MonoBehaviourFactory.cs index 7f862ab..bd376b6 100644 --- a/Context/Factories/MonoBehaviourFactory.cs +++ b/Context/Factories/MonoBehaviourFactory.cs @@ -2,7 +2,6 @@ #region using System; -using Svelto.DataStructures; using UnityEngine; #endregion diff --git a/Context/IUnityCompositionRoot.cs b/Context/IUnityCompositionRoot.cs new file mode 100644 index 0000000..c4db99a --- /dev/null +++ b/Context/IUnityCompositionRoot.cs @@ -0,0 +1,11 @@ +#if UNITY_5 || UNITY_5_3_OR_NEWER +namespace Svelto.Context +{ + public interface IUnityCompositionRoot + { + void OnContextCreated(UnityContext contextHolder); + void OnContextInitialized(); + void OnContextDestroyed(); + } +} +#endif \ No newline at end of file diff --git a/Context/IWaitForFrameworkDestruction.cs b/Context/IWaitForFrameworkDestruction.cs index 622fa3e..e830787 100644 --- a/Context/IWaitForFrameworkDestruction.cs +++ b/Context/IWaitForFrameworkDestruction.cs @@ -1,5 +1,3 @@ -using System; - namespace Svelto.Context { public interface IWaitForFrameworkDestruction diff --git a/Context/IWaitForFrameworkInitialization.cs b/Context/IWaitForFrameworkInitialization.cs index 937cbbc..f1b8dfb 100644 --- a/Context/IWaitForFrameworkInitialization.cs +++ b/Context/IWaitForFrameworkInitialization.cs @@ -1,5 +1,3 @@ -using System; - namespace Svelto.Context { public interface IWaitForFrameworkInitialization diff --git a/Context/UnityContext.cs b/Context/UnityContext.cs index 9591861..925a147 100644 --- a/Context/UnityContext.cs +++ b/Context/UnityContext.cs @@ -13,6 +13,11 @@ public abstract class UnityContext:MonoBehaviour } } +//a Unity context is a platform specific context wrapper. +//Unity will drive the ICompositionRoot interface. +//OnContextCreated is called during the Awake of this MB +//OnContextInitialized is called one frame after the MB started +//OnContextDestroyed is called when the MB is destroyed public class UnityContext: UnityContext where T:class, ICompositionRoot, new() { protected override void OnAwake() diff --git a/DataStructures/FasterList.cs b/DataStructures/FasterList.cs index 384683c..bc4c4f1 100644 --- a/DataStructures/FasterList.cs +++ b/DataStructures/FasterList.cs @@ -120,17 +120,20 @@ namespace Svelto.DataStructures public struct FasterReadOnlyList : IList { - public static FasterReadOnlyList DefaultList = new FasterReadOnlyList(new FasterList()); - + public static FasterReadOnlyList DefaultList = new FasterReadOnlyList(FasterList.DefaultList); + public int Count { get { return _list.Count; } } public bool IsReadOnly { get { return true; } } public FasterReadOnlyList(FasterList list) { _list = list; + + int count; + _buffer = FasterList.NoVirt.ToArrayFast(list, out count); } - public T this[int index] { get { return _list[index]; } set { throw new NotImplementedException(); } } + public T this[int index] { get { return _buffer[index]; } set { throw new NotImplementedException(); } } public FasterListEnumerator GetEnumerator() { @@ -188,6 +191,7 @@ namespace Svelto.DataStructures } readonly FasterList _list; + private readonly T[] _buffer; } public struct FasterListThreadSafe : IList @@ -396,7 +400,7 @@ namespace Svelto.DataStructures public struct FasterReadOnlyListCast : IList where U:T { - public static FasterReadOnlyListCast DefaultList = new FasterReadOnlyListCast(new FasterList()); + public static readonly FasterReadOnlyListCast DefaultList = new FasterReadOnlyListCast(new FasterList()); public int Count { get { return _list.Count; } } public bool IsReadOnly { get { return true; } } @@ -471,6 +475,8 @@ namespace Svelto.DataStructures public class FasterList : IList, IFasterList { + public static readonly FasterList DefaultList = new FasterList(); + const int MIN_SIZE = 4; public int Count @@ -631,7 +637,7 @@ namespace Svelto.DataStructures { var comp = EqualityComparer.Default; - for (var index = _count - 1; index >= 0; --index) + for (var index = 0; index < _count; index++) if (comp.Equals(_buffer[index], item)) return index; diff --git a/DataStructures/IGraphNode.cs b/DataStructures/IGraphNode.cs index 05a8c8e..e1fc894 100644 --- a/DataStructures/IGraphNode.cs +++ b/DataStructures/IGraphNode.cs @@ -9,7 +9,7 @@ //------------------------------------------------------------------------------ using System; -public interface IGraphNode +public interface IGraphEntityView { void VisitNeighbours(System.Action onVisiting); } diff --git a/DataStructures/LeftLeaningKeyedRedBlackTree.cs b/DataStructures/LeftLeaningKeyedRedBlackTree.cs index 0de1ae1..94f285b 100644 --- a/DataStructures/LeftLeaningKeyedRedBlackTree.cs +++ b/DataStructures/LeftLeaningKeyedRedBlackTree.cs @@ -1,6 +1,6 @@ // Uncomment this to enable the following debugging aids: // LeftLeaningRedBlackTree.HtmlFragment -// LeftLeaningRedBlackTree.Node.HtmlFragment +// LeftLeaningRedBlackTree.EntityView.HtmlFragment // LeftLeaningRedBlackTree.AssertInvariants // #define DEBUGGING @@ -21,42 +21,42 @@ using System.Diagnostics; public class LeftLeaningKeyedRedBlackTree where TKey: IComparable { /// - /// Stores the root node of the tree. + /// Stores the root entityView of the tree. /// - private Node _rootNode; + private EntityView _rootEntityView; /// - /// Represents a node of the tree. + /// Represents a entityView of the tree. /// /// /// Using fields instead of properties drops execution time by about 40%. /// [DebuggerDisplay("Key={Key}")] - private class Node + private class EntityView { /// - /// Gets or sets the node's key. + /// Gets or sets the entityView's key. /// public TKey Key; /// - /// Gets or sets the left node. + /// Gets or sets the left entityView. /// - public Node Left; + public EntityView Left; /// - /// Gets or sets the right node. + /// Gets or sets the right entityView. /// - public Node Right; + public EntityView Right; /// - /// Gets or sets the color of the node. + /// Gets or sets the color of the entityView. /// public bool IsBlack; #if DEBUGGING /// - /// Gets an HTML fragment representing the node and its children. + /// Gets an HTML fragment representing the entityView and its children. /// public string HtmlFragment { @@ -83,8 +83,8 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable /// Key to add. public void Add(TKey key) { - _rootNode = Add(_rootNode, key); - _rootNode.IsBlack = true; + _rootEntityView = Add(_rootEntityView, key); + _rootEntityView.IsBlack = true; #if DEBUGGING AssertInvariants(); #endif @@ -98,12 +98,12 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable public bool Remove(TKey key) { int initialCount = Count; - if (null != _rootNode) + if (null != _rootEntityView) { - _rootNode = Remove(_rootNode, key); - if (null != _rootNode) + _rootEntityView = Remove(_rootEntityView, key); + if (null != _rootEntityView) { - _rootNode.IsBlack = true; + _rootEntityView.IsBlack = true; } } #if DEBUGGING @@ -113,11 +113,11 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable } /// - /// Removes all nodes in the tree. + /// Removes all entityViews in the tree. /// public void Clear() { - _rootNode = null; + _rootEntityView = null; Count = 0; #if DEBUGGING AssertInvariants(); @@ -133,7 +133,7 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable TKey lastKey = default(TKey); bool lastKeyValid = false; return Traverse( - _rootNode, + _rootEntityView, n => !lastKeyValid || !object.Equals(lastKey, n.Key), n => { @@ -153,7 +153,7 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable /// public TKey MinimumKey { - get { return GetExtreme(_rootNode, n => n.Left, n => n.Key); } + get { return GetExtreme(_rootEntityView, n => n.Left, n => n.Key); } } /// @@ -161,310 +161,310 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable /// public TKey MaximumKey { - get { return GetExtreme(_rootNode, n => n.Right, n => n.Key); } + get { return GetExtreme(_rootEntityView, n => n.Right, n => n.Key); } } /// - /// Returns true if the specified node is red. + /// Returns true if the specified entityView is red. /// - /// Specified node. - /// True if specified node is red. - private static bool IsRed(Node node) + /// Specified entityView. + /// True if specified entityView is red. + private static bool IsRed(EntityView entityView) { - if (null == node) + if (null == entityView) { - // "Virtual" leaf nodes are always black + // "Virtual" leaf entityViews are always black return false; } - return !node.IsBlack; + return !entityView.IsBlack; } /// - /// Adds the specified key/value pair below the specified root node. + /// Adds the specified key/value pair below the specified root entityView. /// - /// Specified node. + /// Specified entityView. /// Key to add. /// Value to add. - /// New root node. - private Node Add(Node node, TKey key) + /// New root entityView. + private EntityView Add(EntityView entityView, TKey key) { - if (null == node) + if (null == entityView) { - // Insert new node + // Insert new entityView Count++; - return new Node { Key = key }; + return new EntityView { Key = key }; } - if (IsRed(node.Left) && IsRed(node.Right)) + if (IsRed(entityView.Left) && IsRed(entityView.Right)) { - // Split node with two red children - FlipColor(node); + // Split entityView with two red children + FlipColor(entityView); } - // Find right place for new node - int comparisonResult = KeyComparison(key, node.Key); + // Find right place for new entityView + int comparisonResult = KeyComparison(key, entityView.Key); if (comparisonResult < 0) { - node.Left = Add(node.Left, key); + entityView.Left = Add(entityView.Left, key); } else if (0 < comparisonResult) { - node.Right = Add(node.Right, key); + entityView.Right = Add(entityView.Right, key); } - if (IsRed(node.Right)) + if (IsRed(entityView.Right)) { - // Rotate to prevent red node on right - node = RotateLeft(node); + // Rotate to prevent red entityView on right + entityView = RotateLeft(entityView); } - if (IsRed(node.Left) && IsRed(node.Left.Left)) + if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) { - // Rotate to prevent consecutive red nodes - node = RotateRight(node); + // Rotate to prevent consecutive red entityViews + entityView = RotateRight(entityView); } - return node; + return entityView; } /// - /// Removes the specified key/value pair from below the specified node. + /// Removes the specified key/value pair from below the specified entityView. /// - /// Specified node. + /// Specified entityView. /// Key to remove. /// True if key/value present and removed. - private Node Remove(Node node, TKey key) + private EntityView Remove(EntityView entityView, TKey key) { - int comparisonResult = KeyComparison(key, node.Key); + int comparisonResult = KeyComparison(key, entityView.Key); if (comparisonResult < 0) { // * Continue search if left is present - if (null != node.Left) + if (null != entityView.Left) { - if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) { - // Move a red node over - node = MoveRedLeft(node); + // Move a red entityView over + entityView = MoveRedLeft(entityView); } // Remove from left - node.Left = Remove(node.Left, key); + entityView.Left = Remove(entityView.Left, key); } } else { - if (IsRed(node.Left)) + if (IsRed(entityView.Left)) { - // Flip a 3 node or unbalance a 4 node - node = RotateRight(node); + // Flip a 3 entityView or unbalance a 4 entityView + entityView = RotateRight(entityView); } - if ((0 == KeyComparison(key, node.Key)) && (null == node.Right)) + if ((0 == KeyComparison(key, entityView.Key)) && (null == entityView.Right)) { - // Remove leaf node - Debug.Assert(null == node.Left, "About to remove an extra node."); + // Remove leaf entityView + Debug.Assert(null == entityView.Left, "About to remove an extra entityView."); Count--; - // Leaf node is gone + // Leaf entityView is gone return null; } // * Continue search if right is present - if (null != node.Right) + if (null != entityView.Right) { - if (!IsRed(node.Right) && !IsRed(node.Right.Left)) + if (!IsRed(entityView.Right) && !IsRed(entityView.Right.Left)) { - // Move a red node over - node = MoveRedRight(node); + // Move a red entityView over + entityView = MoveRedRight(entityView); } - if (0 == KeyComparison(key, node.Key)) + if (0 == KeyComparison(key, entityView.Key)) { - // Remove leaf node + // Remove leaf entityView Count--; - // Find the smallest node on the right, swap, and remove it - Node m = GetExtreme(node.Right, n => n.Left, n => n); - node.Key = m.Key; - node.Right = DeleteMinimum(node.Right); + // Find the smallest entityView on the right, swap, and remove it + EntityView m = GetExtreme(entityView.Right, n => n.Left, n => n); + entityView.Key = m.Key; + entityView.Right = DeleteMinimum(entityView.Right); } else { // Remove from right - node.Right = Remove(node.Right, key); + entityView.Right = Remove(entityView.Right, key); } } } // Maintain invariants - return FixUp(node); + return FixUp(entityView); } /// - /// Flip the colors of the specified node and its direct children. + /// Flip the colors of the specified entityView and its direct children. /// - /// Specified node. - private static void FlipColor(Node node) + /// Specified entityView. + private static void FlipColor(EntityView entityView) { - node.IsBlack = !node.IsBlack; - node.Left.IsBlack = !node.Left.IsBlack; - node.Right.IsBlack = !node.Right.IsBlack; + entityView.IsBlack = !entityView.IsBlack; + entityView.Left.IsBlack = !entityView.Left.IsBlack; + entityView.Right.IsBlack = !entityView.Right.IsBlack; } /// - /// Rotate the specified node "left". + /// Rotate the specified entityView "left". /// - /// Specified node. - /// New root node. - private static Node RotateLeft(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView RotateLeft(EntityView entityView) { - Node x = node.Right; - node.Right = x.Left; - x.Left = node; - x.IsBlack = node.IsBlack; - node.IsBlack = false; + EntityView x = entityView.Right; + entityView.Right = x.Left; + x.Left = entityView; + x.IsBlack = entityView.IsBlack; + entityView.IsBlack = false; return x; } /// - /// Rotate the specified node "right". + /// Rotate the specified entityView "right". /// - /// Specified node. - /// New root node. - private static Node RotateRight(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView RotateRight(EntityView entityView) { - Node x = node.Left; - node.Left = x.Right; - x.Right = node; - x.IsBlack = node.IsBlack; - node.IsBlack = false; + EntityView x = entityView.Left; + entityView.Left = x.Right; + x.Right = entityView; + x.IsBlack = entityView.IsBlack; + entityView.IsBlack = false; return x; } /// - /// Moves a red node from the right child to the left child. + /// Moves a red entityView from the right child to the left child. /// - /// Parent node. - /// New root node. - private static Node MoveRedLeft(Node node) + /// Parent entityView. + /// New root entityView. + private static EntityView MoveRedLeft(EntityView entityView) { - FlipColor(node); - if (IsRed(node.Right.Left)) + FlipColor(entityView); + if (IsRed(entityView.Right.Left)) { - node.Right = RotateRight(node.Right); - node = RotateLeft(node); - FlipColor(node); + entityView.Right = RotateRight(entityView.Right); + entityView = RotateLeft(entityView); + FlipColor(entityView); - // * Avoid creating right-leaning nodes - if (IsRed(node.Right.Right)) + // * Avoid creating right-leaning entityViews + if (IsRed(entityView.Right.Right)) { - node.Right = RotateLeft(node.Right); + entityView.Right = RotateLeft(entityView.Right); } } - return node; + return entityView; } /// - /// Moves a red node from the left child to the right child. + /// Moves a red entityView from the left child to the right child. /// - /// Parent node. - /// New root node. - private static Node MoveRedRight(Node node) + /// Parent entityView. + /// New root entityView. + private static EntityView MoveRedRight(EntityView entityView) { - FlipColor(node); - if (IsRed(node.Left.Left)) + FlipColor(entityView); + if (IsRed(entityView.Left.Left)) { - node = RotateRight(node); - FlipColor(node); + entityView = RotateRight(entityView); + FlipColor(entityView); } - return node; + return entityView; } /// - /// Deletes the minimum node under the specified node. + /// Deletes the minimum entityView under the specified entityView. /// - /// Specified node. - /// New root node. - private Node DeleteMinimum(Node node) + /// Specified entityView. + /// New root entityView. + private EntityView DeleteMinimum(EntityView entityView) { - if (null == node.Left) + if (null == entityView.Left) { // Nothing to do return null; } - if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) { - // Move red node left - node = MoveRedLeft(node); + // Move red entityView left + entityView = MoveRedLeft(entityView); } // Recursively delete - node.Left = DeleteMinimum(node.Left); + entityView.Left = DeleteMinimum(entityView.Left); // Maintain invariants - return FixUp(node); + return FixUp(entityView); } /// - /// Maintains invariants by adjusting the specified nodes children. + /// Maintains invariants by adjusting the specified entityViews children. /// - /// Specified node. - /// New root node. - private static Node FixUp(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView FixUp(EntityView entityView) { - if (IsRed(node.Right)) + if (IsRed(entityView.Right)) { - // Avoid right-leaning node - node = RotateLeft(node); + // Avoid right-leaning entityView + entityView = RotateLeft(entityView); } - if (IsRed(node.Left) && IsRed(node.Left.Left)) + if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) { - // Balance 4-node - node = RotateRight(node); + // Balance 4-entityView + entityView = RotateRight(entityView); } - if (IsRed(node.Left) && IsRed(node.Right)) + if (IsRed(entityView.Left) && IsRed(entityView.Right)) { // Push red up - FlipColor(node); + FlipColor(entityView); } - // * Avoid leaving behind right-leaning nodes - if ((null != node.Left) && IsRed(node.Left.Right) && !IsRed(node.Left.Left)) + // * Avoid leaving behind right-leaning entityViews + if ((null != entityView.Left) && IsRed(entityView.Left.Right) && !IsRed(entityView.Left.Left)) { - node.Left = RotateLeft(node.Left); - if (IsRed(node.Left)) + entityView.Left = RotateLeft(entityView.Left); + if (IsRed(entityView.Left)) { - // Balance 4-node - node = RotateRight(node); + // Balance 4-entityView + entityView = RotateRight(entityView); } } - return node; + return entityView; } /// - /// Gets the (first) node corresponding to the specified key. + /// Gets the (first) entityView corresponding to the specified key. /// /// Key to search for. - /// Corresponding node or null if none found. - private Node GetNodeForKey(TKey key) + /// Corresponding entityView or null if none found. + private EntityView GetEntityViewForKey(TKey key) { // Initialize - Node node = _rootNode; - while (null != node) + EntityView entityView = _rootEntityView; + while (null != entityView) { // Compare keys and go left/right - int comparisonResult = key.CompareTo(node.Key); + int comparisonResult = key.CompareTo(entityView.Key); if (comparisonResult < 0) { - node = node.Left; + entityView = entityView.Left; } else if (0 < comparisonResult) { - node = node.Right; + entityView = entityView.Right; } else { - // Match; return node - return node; + // Match; return entityView + return entityView; } } @@ -476,15 +476,15 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable /// Gets an extreme (ex: minimum/maximum) value. /// /// Type of value. - /// Node to start from. + /// EntityView to start from. /// Successor function. /// Selector function. /// Extreme value. - private static T GetExtreme(Node node, Func successor, Func selector) + private static T GetExtreme(EntityView entityView, Func successor, Func selector) { // Initialize T extreme = default(T); - Node current = node; + EntityView current = entityView; while (null != current) { // Go to extreme @@ -495,18 +495,18 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable } /// - /// Traverses a subset of the sequence of nodes in order and selects the specified nodes. + /// Traverses a subset of the sequence of entityViews in order and selects the specified entityViews. /// /// Type of elements. - /// Starting node. + /// Starting entityView. /// Condition method. /// Selector method. - /// Sequence of selected nodes. - private IEnumerable Traverse(Node node, Func condition, Func selector) + /// Sequence of selected entityViews. + private IEnumerable Traverse(EntityView entityView, Func condition, Func selector) { // Create a stack to avoid recursion - Stack stack = new Stack(); - Node current = node; + Stack stack = new Stack(); + EntityView current = entityView; while (null != current) { if (null != current.Left) @@ -519,7 +519,7 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable { do { - // Select current node if relevant + // Select current entityView if relevant if (condition(current)) { yield return selector(current); @@ -552,29 +552,29 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable private void AssertInvariants() { // Root is black - Debug.Assert((null == _rootNode) || _rootNode.IsBlack, "Root is not black"); - // Every path contains the same number of black nodes - Dictionary parents = new Dictionary.Node, LeftLeaningRedBlackTree.Node>(); - foreach (Node node in Traverse(_rootNode, n => true, n => n)) + Debug.Assert((null == _rootEntityView) || _rootEntityView.IsBlack, "Root is not black"); + // Every path contains the same number of black entityViews + Dictionary parents = new Dictionary.EntityView, LeftLeaningRedBlackTree.EntityView>(); + foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) { - if (null != node.Left) + if (null != entityView.Left) { - parents[node.Left] = node; + parents[entityView.Left] = entityView; } - if (null != node.Right) + if (null != entityView.Right) { - parents[node.Right] = node; + parents[entityView.Right] = entityView; } } - if (null != _rootNode) + if (null != _rootEntityView) { - parents[_rootNode] = null; + parents[_rootEntityView] = null; } int treeCount = -1; - foreach (Node node in Traverse(_rootNode, n => (null == n.Left) || (null == n.Right), n => n)) + foreach (EntityView entityView in Traverse(_rootEntityView, n => (null == n.Left) || (null == n.Right), n => n)) { int pathCount = 0; - Node current = node; + EntityView current = entityView; while (null != current) { if (current.IsBlack) @@ -583,28 +583,28 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable } current = parents[current]; } - Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black nodes."); + Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black entityViews."); treeCount = pathCount; } - // Verify node properties... - foreach (Node node in Traverse(_rootNode, n => true, n => n)) + // Verify entityView properties... + foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) { - // Left node is less - if (null != node.Left) + // Left entityView is less + if (null != entityView.Left) { - Debug.Assert(0 > KeyAndValueComparison(node.Left.Key, node.Left.Value, node.Key, node.Value), "Left node is greater than its parent."); + Debug.Assert(0 > KeyAndValueComparison(entityView.Left.Key, entityView.Left.Value, entityView.Key, entityView.Value), "Left entityView is greater than its parent."); } - // Right node is greater - if (null != node.Right) + // Right entityView is greater + if (null != entityView.Right) { - Debug.Assert(0 < KeyAndValueComparison(node.Right.Key, node.Right.Value, node.Key, node.Value), "Right node is less than its parent."); + Debug.Assert(0 < KeyAndValueComparison(entityView.Right.Key, entityView.Right.Value, entityView.Key, entityView.Value), "Right entityView is less than its parent."); } - // Both children of a red node are black - Debug.Assert(!IsRed(node) || (!IsRed(node.Left) && !IsRed(node.Right)), "Red node has a red child."); + // Both children of a red entityView are black + Debug.Assert(!IsRed(entityView) || (!IsRed(entityView.Left) && !IsRed(entityView.Right)), "Red entityView has a red child."); // Always left-leaning - Debug.Assert(!IsRed(node.Right) || IsRed(node.Left), "Node is not left-leaning."); + Debug.Assert(!IsRed(entityView.Right) || IsRed(entityView.Left), "EntityView is not left-leaning."); // No consecutive reds (subset of previous rule) - //Debug.Assert(!(IsRed(node) && IsRed(node.Left))); + //Debug.Assert(!(IsRed(entityView) && IsRed(entityView.Left))); } } @@ -618,7 +618,7 @@ public class LeftLeaningKeyedRedBlackTree where TKey: IComparable return "" + "" + - (null != _rootNode ? _rootNode.HtmlFragment : "[null]") + + (null != _rootEntityView ? _rootEntityView.HtmlFragment : "[null]") + "" + ""; } diff --git a/DataStructures/LeftLeaningRedBlackTree.cs b/DataStructures/LeftLeaningRedBlackTree.cs index b6e3712..f109135 100644 --- a/DataStructures/LeftLeaningRedBlackTree.cs +++ b/DataStructures/LeftLeaningRedBlackTree.cs @@ -1,6 +1,6 @@ // Uncomment this to enable the following debugging aids: // LeftLeaningRedBlackTree.HtmlFragment -// LeftLeaningRedBlackTree.Node.HtmlFragment +// LeftLeaningRedBlackTree.EntityView.HtmlFragment // LeftLeaningRedBlackTree.AssertInvariants // #define DEBUGGING @@ -32,52 +32,52 @@ public class LeftLeaningRedBlackTree private Comparison _valueComparison; /// - /// Stores the root node of the tree. + /// Stores the root entityView of the tree. /// - private Node _rootNode; + private EntityView _rootEntityView; /// - /// Represents a node of the tree. + /// Represents a entityView of the tree. /// /// /// Using fields instead of properties drops execution time by about 40%. /// [DebuggerDisplay("Key={Key}, Value={Value}, Siblings={Siblings}")] - private class Node + private class EntityView { /// - /// Gets or sets the node's key. + /// Gets or sets the entityView's key. /// public TKey Key; /// - /// Gets or sets the node's value. + /// Gets or sets the entityView's value. /// public TValue Value; /// - /// Gets or sets the left node. + /// Gets or sets the left entityView. /// - public Node Left; + public EntityView Left; /// - /// Gets or sets the right node. + /// Gets or sets the right entityView. /// - public Node Right; + public EntityView Right; /// - /// Gets or sets the color of the node. + /// Gets or sets the color of the entityView. /// public bool IsBlack; /// - /// Gets or sets the number of "siblings" (nodes with the same key/value). + /// Gets or sets the number of "siblings" (entityViews with the same key/value). /// public int Siblings; #if DEBUGGING /// - /// Gets an HTML fragment representing the node and its children. + /// Gets an HTML fragment representing the entityView and its children. /// public string HtmlFragment { @@ -141,8 +141,8 @@ public class LeftLeaningRedBlackTree /// Value to add. public void Add(TKey key, TValue value) { - _rootNode = Add(_rootNode, key, value); - _rootNode.IsBlack = true; + _rootEntityView = Add(_rootEntityView, key, value); + _rootEntityView.IsBlack = true; #if DEBUGGING AssertInvariants(); #endif @@ -171,12 +171,12 @@ public class LeftLeaningRedBlackTree public bool Remove(TKey key, TValue value) { int initialCount = Count; - if (null != _rootNode) + if (null != _rootEntityView) { - _rootNode = Remove(_rootNode, key, value); - if (null != _rootNode) + _rootEntityView = Remove(_rootEntityView, key, value); + if (null != _rootEntityView) { - _rootNode.IsBlack = true; + _rootEntityView.IsBlack = true; } } #if DEBUGGING @@ -186,11 +186,11 @@ public class LeftLeaningRedBlackTree } /// - /// Removes all nodes in the tree. + /// Removes all entityViews in the tree. /// public void Clear() { - _rootNode = null; + _rootEntityView = null; Count = 0; #if DEBUGGING AssertInvariants(); @@ -206,7 +206,7 @@ public class LeftLeaningRedBlackTree TKey lastKey = default(TKey); bool lastKeyValid = false; return Traverse( - _rootNode, + _rootEntityView, n => !lastKeyValid || !object.Equals(lastKey, n.Key), n => { @@ -227,10 +227,10 @@ public class LeftLeaningRedBlackTree { throw new InvalidOperationException("GetValueForKey is only supported when acting as a normal (non-multi) dictionary."); } - Node node = GetNodeForKey(key); - if (null != node) + EntityView entityView = GetEntityViewForKey(key); + if (null != entityView) { - return node.Value; + return entityView.Value; } else { @@ -245,7 +245,7 @@ public class LeftLeaningRedBlackTree /// Sequence of values. public IEnumerable GetValuesForKey(TKey key) { - return Traverse(GetNodeForKey(key), n => 0 == _keyComparison(n.Key, key), n => n.Value); + return Traverse(GetEntityViewForKey(key), n => 0 == _keyComparison(n.Key, key), n => n.Value); } /// @@ -254,7 +254,7 @@ public class LeftLeaningRedBlackTree /// Sequence of all values. public IEnumerable GetValuesForAllKeys() { - return Traverse(_rootNode, n => true, n => n.Value); + return Traverse(_rootEntityView, n => true, n => n.Value); } /// @@ -267,7 +267,7 @@ public class LeftLeaningRedBlackTree /// public TKey MinimumKey { - get { return GetExtreme(_rootNode, n => n.Left, n => n.Key); } + get { return GetExtreme(_rootEntityView, n => n.Left, n => n.Key); } } /// @@ -275,346 +275,346 @@ public class LeftLeaningRedBlackTree /// public TKey MaximumKey { - get { return GetExtreme(_rootNode, n => n.Right, n => n.Key); } + get { return GetExtreme(_rootEntityView, n => n.Right, n => n.Key); } } /// - /// Returns true if the specified node is red. + /// Returns true if the specified entityView is red. /// - /// Specified node. - /// True if specified node is red. - private static bool IsRed(Node node) + /// Specified entityView. + /// True if specified entityView is red. + private static bool IsRed(EntityView entityView) { - if (null == node) + if (null == entityView) { - // "Virtual" leaf nodes are always black + // "Virtual" leaf entityViews are always black return false; } - return !node.IsBlack; + return !entityView.IsBlack; } /// - /// Adds the specified key/value pair below the specified root node. + /// Adds the specified key/value pair below the specified root entityView. /// - /// Specified node. + /// Specified entityView. /// Key to add. /// Value to add. - /// New root node. - private Node Add(Node node, TKey key, TValue value) + /// New root entityView. + private EntityView Add(EntityView entityView, TKey key, TValue value) { - if (null == node) + if (null == entityView) { - // Insert new node + // Insert new entityView Count++; - return new Node { Key = key, Value = value }; + return new EntityView { Key = key, Value = value }; } - if (IsRed(node.Left) && IsRed(node.Right)) + if (IsRed(entityView.Left) && IsRed(entityView.Right)) { - // Split node with two red children - FlipColor(node); + // Split entityView with two red children + FlipColor(entityView); } - // Find right place for new node - int comparisonResult = KeyAndValueComparison(key, value, node.Key, node.Value); + // Find right place for new entityView + int comparisonResult = KeyAndValueComparison(key, value, entityView.Key, entityView.Value); if (comparisonResult < 0) { - node.Left = Add(node.Left, key, value); + entityView.Left = Add(entityView.Left, key, value); } else if (0 < comparisonResult) { - node.Right = Add(node.Right, key, value); + entityView.Right = Add(entityView.Right, key, value); } else { if (IsMultiDictionary) { - // Store the presence of a "duplicate" node - node.Siblings++; + // Store the presence of a "duplicate" entityView + entityView.Siblings++; Count++; } else { - // Replace the value of the existing node - node.Value = value; + // Replace the value of the existing entityView + entityView.Value = value; } } - if (IsRed(node.Right)) + if (IsRed(entityView.Right)) { - // Rotate to prevent red node on right - node = RotateLeft(node); + // Rotate to prevent red entityView on right + entityView = RotateLeft(entityView); } - if (IsRed(node.Left) && IsRed(node.Left.Left)) + if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) { - // Rotate to prevent consecutive red nodes - node = RotateRight(node); + // Rotate to prevent consecutive red entityViews + entityView = RotateRight(entityView); } - return node; + return entityView; } /// - /// Removes the specified key/value pair from below the specified node. + /// Removes the specified key/value pair from below the specified entityView. /// - /// Specified node. + /// Specified entityView. /// Key to remove. /// Value to remove. /// True if key/value present and removed. - private Node Remove(Node node, TKey key, TValue value) + private EntityView Remove(EntityView entityView, TKey key, TValue value) { - int comparisonResult = KeyAndValueComparison(key, value, node.Key, node.Value); + int comparisonResult = KeyAndValueComparison(key, value, entityView.Key, entityView.Value); if (comparisonResult < 0) { // * Continue search if left is present - if (null != node.Left) + if (null != entityView.Left) { - if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) { - // Move a red node over - node = MoveRedLeft(node); + // Move a red entityView over + entityView = MoveRedLeft(entityView); } // Remove from left - node.Left = Remove(node.Left, key, value); + entityView.Left = Remove(entityView.Left, key, value); } } else { - if (IsRed(node.Left)) + if (IsRed(entityView.Left)) { - // Flip a 3 node or unbalance a 4 node - node = RotateRight(node); + // Flip a 3 entityView or unbalance a 4 entityView + entityView = RotateRight(entityView); } - if ((0 == KeyAndValueComparison(key, value, node.Key, node.Value)) && (null == node.Right)) + if ((0 == KeyAndValueComparison(key, value, entityView.Key, entityView.Value)) && (null == entityView.Right)) { - // Remove leaf node - Debug.Assert(null == node.Left, "About to remove an extra node."); + // Remove leaf entityView + Debug.Assert(null == entityView.Left, "About to remove an extra entityView."); Count--; - if (0 < node.Siblings) + if (0 < entityView.Siblings) { - // Record the removal of the "duplicate" node + // Record the removal of the "duplicate" entityView Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); - node.Siblings--; - return node; + entityView.Siblings--; + return entityView; } else { - // Leaf node is gone + // Leaf entityView is gone return null; } } // * Continue search if right is present - if (null != node.Right) + if (null != entityView.Right) { - if (!IsRed(node.Right) && !IsRed(node.Right.Left)) + if (!IsRed(entityView.Right) && !IsRed(entityView.Right.Left)) { - // Move a red node over - node = MoveRedRight(node); + // Move a red entityView over + entityView = MoveRedRight(entityView); } - if (0 == KeyAndValueComparison(key, value, node.Key, node.Value)) + if (0 == KeyAndValueComparison(key, value, entityView.Key, entityView.Value)) { - // Remove leaf node + // Remove leaf entityView Count--; - if (0 < node.Siblings) + if (0 < entityView.Siblings) { - // Record the removal of the "duplicate" node + // Record the removal of the "duplicate" entityView Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); - node.Siblings--; + entityView.Siblings--; } else { - // Find the smallest node on the right, swap, and remove it - Node m = GetExtreme(node.Right, n => n.Left, n => n); - node.Key = m.Key; - node.Value = m.Value; - node.Siblings = m.Siblings; - node.Right = DeleteMinimum(node.Right); + // Find the smallest entityView on the right, swap, and remove it + EntityView m = GetExtreme(entityView.Right, n => n.Left, n => n); + entityView.Key = m.Key; + entityView.Value = m.Value; + entityView.Siblings = m.Siblings; + entityView.Right = DeleteMinimum(entityView.Right); } } else { // Remove from right - node.Right = Remove(node.Right, key, value); + entityView.Right = Remove(entityView.Right, key, value); } } } // Maintain invariants - return FixUp(node); + return FixUp(entityView); } /// - /// Flip the colors of the specified node and its direct children. + /// Flip the colors of the specified entityView and its direct children. /// - /// Specified node. - private static void FlipColor(Node node) + /// Specified entityView. + private static void FlipColor(EntityView entityView) { - node.IsBlack = !node.IsBlack; - node.Left.IsBlack = !node.Left.IsBlack; - node.Right.IsBlack = !node.Right.IsBlack; + entityView.IsBlack = !entityView.IsBlack; + entityView.Left.IsBlack = !entityView.Left.IsBlack; + entityView.Right.IsBlack = !entityView.Right.IsBlack; } /// - /// Rotate the specified node "left". + /// Rotate the specified entityView "left". /// - /// Specified node. - /// New root node. - private static Node RotateLeft(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView RotateLeft(EntityView entityView) { - Node x = node.Right; - node.Right = x.Left; - x.Left = node; - x.IsBlack = node.IsBlack; - node.IsBlack = false; + EntityView x = entityView.Right; + entityView.Right = x.Left; + x.Left = entityView; + x.IsBlack = entityView.IsBlack; + entityView.IsBlack = false; return x; } /// - /// Rotate the specified node "right". + /// Rotate the specified entityView "right". /// - /// Specified node. - /// New root node. - private static Node RotateRight(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView RotateRight(EntityView entityView) { - Node x = node.Left; - node.Left = x.Right; - x.Right = node; - x.IsBlack = node.IsBlack; - node.IsBlack = false; + EntityView x = entityView.Left; + entityView.Left = x.Right; + x.Right = entityView; + x.IsBlack = entityView.IsBlack; + entityView.IsBlack = false; return x; } /// - /// Moves a red node from the right child to the left child. + /// Moves a red entityView from the right child to the left child. /// - /// Parent node. - /// New root node. - private static Node MoveRedLeft(Node node) + /// Parent entityView. + /// New root entityView. + private static EntityView MoveRedLeft(EntityView entityView) { - FlipColor(node); - if (IsRed(node.Right.Left)) + FlipColor(entityView); + if (IsRed(entityView.Right.Left)) { - node.Right = RotateRight(node.Right); - node = RotateLeft(node); - FlipColor(node); + entityView.Right = RotateRight(entityView.Right); + entityView = RotateLeft(entityView); + FlipColor(entityView); - // * Avoid creating right-leaning nodes - if (IsRed(node.Right.Right)) + // * Avoid creating right-leaning entityViews + if (IsRed(entityView.Right.Right)) { - node.Right = RotateLeft(node.Right); + entityView.Right = RotateLeft(entityView.Right); } } - return node; + return entityView; } /// - /// Moves a red node from the left child to the right child. + /// Moves a red entityView from the left child to the right child. /// - /// Parent node. - /// New root node. - private static Node MoveRedRight(Node node) + /// Parent entityView. + /// New root entityView. + private static EntityView MoveRedRight(EntityView entityView) { - FlipColor(node); - if (IsRed(node.Left.Left)) + FlipColor(entityView); + if (IsRed(entityView.Left.Left)) { - node = RotateRight(node); - FlipColor(node); + entityView = RotateRight(entityView); + FlipColor(entityView); } - return node; + return entityView; } /// - /// Deletes the minimum node under the specified node. + /// Deletes the minimum entityView under the specified entityView. /// - /// Specified node. - /// New root node. - private Node DeleteMinimum(Node node) + /// Specified entityView. + /// New root entityView. + private EntityView DeleteMinimum(EntityView entityView) { - if (null == node.Left) + if (null == entityView.Left) { // Nothing to do return null; } - if (!IsRed(node.Left) && !IsRed(node.Left.Left)) + if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) { - // Move red node left - node = MoveRedLeft(node); + // Move red entityView left + entityView = MoveRedLeft(entityView); } // Recursively delete - node.Left = DeleteMinimum(node.Left); + entityView.Left = DeleteMinimum(entityView.Left); // Maintain invariants - return FixUp(node); + return FixUp(entityView); } /// - /// Maintains invariants by adjusting the specified nodes children. + /// Maintains invariants by adjusting the specified entityViews children. /// - /// Specified node. - /// New root node. - private static Node FixUp(Node node) + /// Specified entityView. + /// New root entityView. + private static EntityView FixUp(EntityView entityView) { - if (IsRed(node.Right)) + if (IsRed(entityView.Right)) { - // Avoid right-leaning node - node = RotateLeft(node); + // Avoid right-leaning entityView + entityView = RotateLeft(entityView); } - if (IsRed(node.Left) && IsRed(node.Left.Left)) + if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) { - // Balance 4-node - node = RotateRight(node); + // Balance 4-entityView + entityView = RotateRight(entityView); } - if (IsRed(node.Left) && IsRed(node.Right)) + if (IsRed(entityView.Left) && IsRed(entityView.Right)) { // Push red up - FlipColor(node); + FlipColor(entityView); } - // * Avoid leaving behind right-leaning nodes - if ((null != node.Left) && IsRed(node.Left.Right) && !IsRed(node.Left.Left)) + // * Avoid leaving behind right-leaning entityViews + if ((null != entityView.Left) && IsRed(entityView.Left.Right) && !IsRed(entityView.Left.Left)) { - node.Left = RotateLeft(node.Left); - if (IsRed(node.Left)) + entityView.Left = RotateLeft(entityView.Left); + if (IsRed(entityView.Left)) { - // Balance 4-node - node = RotateRight(node); + // Balance 4-entityView + entityView = RotateRight(entityView); } } - return node; + return entityView; } /// - /// Gets the (first) node corresponding to the specified key. + /// Gets the (first) entityView corresponding to the specified key. /// /// Key to search for. - /// Corresponding node or null if none found. - private Node GetNodeForKey(TKey key) + /// Corresponding entityView or null if none found. + private EntityView GetEntityViewForKey(TKey key) { // Initialize - Node node = _rootNode; - while (null != node) + EntityView entityView = _rootEntityView; + while (null != entityView) { // Compare keys and go left/right - int comparisonResult = _keyComparison(key, node.Key); + int comparisonResult = _keyComparison(key, entityView.Key); if (comparisonResult < 0) { - node = node.Left; + entityView = entityView.Left; } else if (0 < comparisonResult) { - node = node.Right; + entityView = entityView.Right; } else { - // Match; return node - return node; + // Match; return entityView + return entityView; } } @@ -626,15 +626,15 @@ public class LeftLeaningRedBlackTree /// Gets an extreme (ex: minimum/maximum) value. /// /// Type of value. - /// Node to start from. + /// EntityView to start from. /// Successor function. /// Selector function. /// Extreme value. - private static T GetExtreme(Node node, Func successor, Func selector) + private static T GetExtreme(EntityView entityView, Func successor, Func selector) { // Initialize T extreme = default(T); - Node current = node; + EntityView current = entityView; while (null != current) { // Go to extreme @@ -645,18 +645,18 @@ public class LeftLeaningRedBlackTree } /// - /// Traverses a subset of the sequence of nodes in order and selects the specified nodes. + /// Traverses a subset of the sequence of entityViews in order and selects the specified entityViews. /// /// Type of elements. - /// Starting node. + /// Starting entityView. /// Condition method. /// Selector method. - /// Sequence of selected nodes. - private IEnumerable Traverse(Node node, Func condition, Func selector) + /// Sequence of selected entityViews. + private IEnumerable Traverse(EntityView entityView, Func condition, Func selector) { // Create a stack to avoid recursion - Stack stack = new Stack(); - Node current = node; + Stack stack = new Stack(); + EntityView current = entityView; while (null != current) { if (null != current.Left) @@ -671,7 +671,7 @@ public class LeftLeaningRedBlackTree { for (int i = 0; i <= current.Siblings; i++) { - // Select current node if relevant + // Select current entityView if relevant if (condition(current)) { yield return selector(current); @@ -714,29 +714,29 @@ public class LeftLeaningRedBlackTree private void AssertInvariants() { // Root is black - Debug.Assert((null == _rootNode) || _rootNode.IsBlack, "Root is not black"); - // Every path contains the same number of black nodes - Dictionary parents = new Dictionary.Node, LeftLeaningRedBlackTree.Node>(); - foreach (Node node in Traverse(_rootNode, n => true, n => n)) + Debug.Assert((null == _rootEntityView) || _rootEntityView.IsBlack, "Root is not black"); + // Every path contains the same number of black entityViews + Dictionary parents = new Dictionary.EntityView, LeftLeaningRedBlackTree.EntityView>(); + foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) { - if (null != node.Left) + if (null != entityView.Left) { - parents[node.Left] = node; + parents[entityView.Left] = entityView; } - if (null != node.Right) + if (null != entityView.Right) { - parents[node.Right] = node; + parents[entityView.Right] = entityView; } } - if (null != _rootNode) + if (null != _rootEntityView) { - parents[_rootNode] = null; + parents[_rootEntityView] = null; } int treeCount = -1; - foreach (Node node in Traverse(_rootNode, n => (null == n.Left) || (null == n.Right), n => n)) + foreach (EntityView entityView in Traverse(_rootEntityView, n => (null == n.Left) || (null == n.Right), n => n)) { int pathCount = 0; - Node current = node; + EntityView current = entityView; while (null != current) { if (current.IsBlack) @@ -745,28 +745,28 @@ public class LeftLeaningRedBlackTree } current = parents[current]; } - Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black nodes."); + Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black entityViews."); treeCount = pathCount; } - // Verify node properties... - foreach (Node node in Traverse(_rootNode, n => true, n => n)) + // Verify entityView properties... + foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) { - // Left node is less - if (null != node.Left) + // Left entityView is less + if (null != entityView.Left) { - Debug.Assert(0 > KeyAndValueComparison(node.Left.Key, node.Left.Value, node.Key, node.Value), "Left node is greater than its parent."); + Debug.Assert(0 > KeyAndValueComparison(entityView.Left.Key, entityView.Left.Value, entityView.Key, entityView.Value), "Left entityView is greater than its parent."); } - // Right node is greater - if (null != node.Right) + // Right entityView is greater + if (null != entityView.Right) { - Debug.Assert(0 < KeyAndValueComparison(node.Right.Key, node.Right.Value, node.Key, node.Value), "Right node is less than its parent."); + Debug.Assert(0 < KeyAndValueComparison(entityView.Right.Key, entityView.Right.Value, entityView.Key, entityView.Value), "Right entityView is less than its parent."); } - // Both children of a red node are black - Debug.Assert(!IsRed(node) || (!IsRed(node.Left) && !IsRed(node.Right)), "Red node has a red child."); + // Both children of a red entityView are black + Debug.Assert(!IsRed(entityView) || (!IsRed(entityView.Left) && !IsRed(entityView.Right)), "Red entityView has a red child."); // Always left-leaning - Debug.Assert(!IsRed(node.Right) || IsRed(node.Left), "Node is not left-leaning."); + Debug.Assert(!IsRed(entityView.Right) || IsRed(entityView.Left), "EntityView is not left-leaning."); // No consecutive reds (subset of previous rule) - //Debug.Assert(!(IsRed(node) && IsRed(node.Left))); + //Debug.Assert(!(IsRed(entityView) && IsRed(entityView.Left))); } } @@ -780,7 +780,7 @@ public class LeftLeaningRedBlackTree return "" + "" + - (null != _rootNode ? _rootNode.HtmlFragment : "[null]") + + (null != _rootEntityView ? _rootEntityView.HtmlFragment : "[null]") + "" + ""; } diff --git a/DataStructures/LockFreeQueue.cs b/DataStructures/LockFreeQueue.cs index 4c55f39..4b936be 100644 --- a/DataStructures/LockFreeQueue.cs +++ b/DataStructures/LockFreeQueue.cs @@ -1,14 +1,13 @@ -using System.Collections.Generic; using System.Threading; //from unify wiki namespace Svelto.DataStructures { - public class SingleLinkNode + public class SingleLinkEntityView { // Note; the Next member cannot be a property since // it participates in many CAS operations - public SingleLinkNode Next; + public SingleLinkEntityView Next; public T Item; } @@ -24,33 +23,33 @@ namespace Svelto.DataStructures public class LockFreeLinkPool { - private SingleLinkNode head; + private SingleLinkEntityView head; public LockFreeLinkPool() { - head = new SingleLinkNode(); + head = new SingleLinkEntityView(); } - public void Push(SingleLinkNode newNode) + public void Push(SingleLinkEntityView newEntityView) { - newNode.Item = default(T); + newEntityView.Item = default(T); do { - newNode.Next = head.Next; - } while (!SyncMethods.CAS>(ref head.Next, newNode.Next, newNode)); + newEntityView.Next = head.Next; + } while (!SyncMethods.CAS>(ref head.Next, newEntityView.Next, newEntityView)); return; } - public bool Pop(out SingleLinkNode node) + public bool Pop(out SingleLinkEntityView entityView) { do { - node = head.Next; - if (node == null) + entityView = head.Next; + if (entityView == null) { return false; } - } while (!SyncMethods.CAS>(ref head.Next, node, node.Next)); + } while (!SyncMethods.CAS>(ref head.Next, entityView, entityView.Next)); return true; } } @@ -58,35 +57,35 @@ namespace Svelto.DataStructures public class LockFreeQueue { - SingleLinkNode head; - SingleLinkNode tail; + SingleLinkEntityView head; + SingleLinkEntityView tail; LockFreeLinkPool trash; public LockFreeQueue() { - head = new SingleLinkNode(); + head = new SingleLinkEntityView(); tail = head; trash = new LockFreeLinkPool(); } public void Enqueue(T item) { - SingleLinkNode oldTail = null; - SingleLinkNode oldTailNext; + SingleLinkEntityView oldTail = null; + SingleLinkEntityView oldTailNext; - SingleLinkNode newNode; - if (!trash.Pop(out newNode)) + SingleLinkEntityView newEntityView; + if (!trash.Pop(out newEntityView)) { - newNode = new SingleLinkNode(); + newEntityView = new SingleLinkEntityView(); } else { - newNode.Next = null; + newEntityView.Next = null; } - newNode.Item = item; + newEntityView.Item = item; - bool newNodeWasAdded = false; - while (!newNodeWasAdded) + bool newEntityViewWasAdded = false; + while (!newEntityViewWasAdded) { oldTail = tail; oldTailNext = oldTail.Next; @@ -94,26 +93,26 @@ namespace Svelto.DataStructures if (tail == oldTail) { if (oldTailNext == null) - newNodeWasAdded = SyncMethods.CAS>(ref tail.Next, null, newNode); + newEntityViewWasAdded = SyncMethods.CAS>(ref tail.Next, null, newEntityView); else - SyncMethods.CAS>(ref tail, oldTail, oldTailNext); + SyncMethods.CAS>(ref tail, oldTail, oldTailNext); } } - SyncMethods.CAS>(ref tail, oldTail, newNode); + SyncMethods.CAS>(ref tail, oldTail, newEntityView); } public bool Dequeue(out T item) { item = default(T); - SingleLinkNode oldHead = null; + SingleLinkEntityView oldHead = null; bool haveAdvancedHead = false; while (!haveAdvancedHead) { oldHead = head; - SingleLinkNode oldTail = tail; - SingleLinkNode oldHeadNext = oldHead.Next; + SingleLinkEntityView oldTail = tail; + SingleLinkEntityView oldHeadNext = oldHead.Next; if (oldHead == head) { @@ -123,12 +122,12 @@ namespace Svelto.DataStructures { return false; } - SyncMethods.CAS>(ref tail, oldTail, oldHeadNext); + SyncMethods.CAS>(ref tail, oldTail, oldHeadNext); } else { item = oldHeadNext.Item; - haveAdvancedHead = SyncMethods.CAS>(ref head, oldHead, oldHeadNext); + haveAdvancedHead = SyncMethods.CAS>(ref head, oldHead, oldHeadNext); if (haveAdvancedHead) { trash.Push(oldHead); diff --git a/DataStructures/PriorityQueue/HeapPriorityQueue.cs b/DataStructures/PriorityQueue/HeapPriorityQueue.cs index 606acd5..bd8764b 100644 --- a/DataStructures/PriorityQueue/HeapPriorityQueue.cs +++ b/DataStructures/PriorityQueue/HeapPriorityQueue.cs @@ -1,7 +1,5 @@ using System.Collections; using System.Collections.Generic; -using System.Runtime.CompilerServices; -using Svelto.DataStructures; namespace Svelto.DataStructures { @@ -9,40 +7,40 @@ namespace Svelto.DataStructures /// An implementation of a min-Priority Queue using a heap. Has O(1) .Contains()! /// See https://bitbucket.org/BlueRaja/high-speed-priority-queue-for-c/wiki/Getting%20Started for more information /// - /// The values in the queue. Must implement the PriorityQueueNode interface + /// The values in the queue. Must implement the PriorityQueueEntityView interface public sealed class HeapPriorityQueue : IPriorityQueue - where T : PriorityQueueNode + where T : PriorityQueueEntityView { - private int _numNodes; - private readonly FasterList _nodes; - private long _numNodesEverEnqueued; + private int _numEntityViews; + private readonly FasterList _entityViews; + private long _numEntityViewsEverEnqueued; /// /// Instantiate a new Priority Queue /// - /// The max nodes ever allowed to be enqueued (going over this will cause an exception) + /// The max entityViews ever allowed to be enqueued (going over this will cause an exception) public HeapPriorityQueue() { - _numNodes = 0; - _nodes = new FasterList(); - _numNodesEverEnqueued = 0; + _numEntityViews = 0; + _entityViews = new FasterList(); + _numEntityViewsEverEnqueued = 0; } public HeapPriorityQueue(int initialSize) { - _numNodes = 0; - _nodes = new FasterList(initialSize); - _numNodesEverEnqueued = 0; + _numEntityViews = 0; + _entityViews = new FasterList(initialSize); + _numEntityViewsEverEnqueued = 0; } /// - /// Returns the number of nodes in the queue. O(1) + /// Returns the number of entityViews in the queue. O(1) /// public int Count { get { - return _numNodes; + return _numEntityViews; } } @@ -54,119 +52,119 @@ namespace Svelto.DataStructures { get { - return _nodes.Count - 1; + return _entityViews.Count - 1; } } /// - /// Removes every node from the queue. O(n) (So, don't do this often!) + /// Removes every entityView from the queue. O(n) (So, don't do this often!) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public void Clear() { - _nodes.FastClear(); + _entityViews.FastClear(); - _numNodes = 0; + _numEntityViews = 0; } /// - /// Returns (in O(1)!) whether the given node is in the queue. O(1) + /// Returns (in O(1)!) whether the given entityView is in the queue. O(1) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public bool Contains(T node) + public bool Contains(T entityView) { - return (_nodes[node.QueueIndex] == node); + return (_entityViews[entityView.QueueIndex] == entityView); } /// - /// Enqueue a node - .Priority must be set beforehand! O(log n) + /// Enqueue a entityView - .Priority must be set beforehand! O(log n) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public void Enqueue(T node, double priority) + public void Enqueue(T entityView, double priority) { - node.Priority = priority; - _numNodes++; - if (_nodes.Count < _numNodes) - _nodes.Resize(_numNodes + 1); - - _nodes[_numNodes] = node; - node.QueueIndex = _numNodes; - node.InsertionIndex = _numNodesEverEnqueued++; - CascadeUp(_nodes[_numNodes]); + entityView.Priority = priority; + _numEntityViews++; + if (_entityViews.Count < _numEntityViews) + _entityViews.Resize(_numEntityViews + 1); + + _entityViews[_numEntityViews] = entityView; + entityView.QueueIndex = _numEntityViews; + entityView.InsertionIndex = _numEntityViewsEverEnqueued++; + CascadeUp(_entityViews[_numEntityViews]); } #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - private void Swap(T node1, T node2) + private void Swap(T entityView1, T entityView2) { - //Swap the nodes - _nodes[node1.QueueIndex] = node2; - _nodes[node2.QueueIndex] = node1; + //Swap the entityViews + _entityViews[entityView1.QueueIndex] = entityView2; + _entityViews[entityView2.QueueIndex] = entityView1; //Swap their indicies - int temp = node1.QueueIndex; - node1.QueueIndex = node2.QueueIndex; - node2.QueueIndex = temp; + int temp = entityView1.QueueIndex; + entityView1.QueueIndex = entityView2.QueueIndex; + entityView2.QueueIndex = temp; } //Performance appears to be slightly better when this is NOT inlined o_O - private void CascadeUp(T node) + private void CascadeUp(T entityView) { //aka Heapify-up - int parent = node.QueueIndex / 2; + int parent = entityView.QueueIndex / 2; while(parent >= 1) { - T parentNode = _nodes[parent]; - if(HasHigherPriority(parentNode, node)) + T parentEntityView = _entityViews[parent]; + if(HasHigherPriority(parentEntityView, entityView)) break; - //Node has lower priority value, so move it up the heap - Swap(node, parentNode); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() + //EntityView has lower priority value, so move it up the heap + Swap(entityView, parentEntityView); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() - parent = node.QueueIndex / 2; + parent = entityView.QueueIndex / 2; } } #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - private void CascadeDown(T node) + private void CascadeDown(T entityView) { //aka Heapify-down T newParent; - int finalQueueIndex = node.QueueIndex; + int finalQueueIndex = entityView.QueueIndex; while(true) { - newParent = node; + newParent = entityView; int childLeftIndex = 2 * finalQueueIndex; - //Check if the left-child is higher-priority than the current node - if(childLeftIndex > _numNodes) + //Check if the left-child is higher-priority than the current entityView + if(childLeftIndex > _numEntityViews) { - //This could be placed outside the loop, but then we'd have to check newParent != node twice - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; + //This could be placed outside the loop, but then we'd have to check newParent != entityView twice + entityView.QueueIndex = finalQueueIndex; + _entityViews[finalQueueIndex] = entityView; break; } - T childLeft = _nodes[childLeftIndex]; + T childLeft = _entityViews[childLeftIndex]; if(HasHigherPriority(childLeft, newParent)) { newParent = childLeft; } - //Check if the right-child is higher-priority than either the current node or the left child + //Check if the right-child is higher-priority than either the current entityView or the left child int childRightIndex = childLeftIndex + 1; - if(childRightIndex <= _numNodes) + if(childRightIndex <= _numEntityViews) { - T childRight = _nodes[childRightIndex]; + T childRight = _entityViews[childRightIndex]; if(HasHigherPriority(childRight, newParent)) { newParent = childRight; @@ -174,11 +172,11 @@ namespace Svelto.DataStructures } //If either of the children has higher (smaller) priority, swap and continue cascading - if(newParent != node) + if(newParent != entityView) { - //Move new parent to its new index. node will be moved once, at the end + //Move new parent to its new index. entityView will be moved once, at the end //Doing it this way is one less assignment operation than calling Swap() - _nodes[finalQueueIndex] = newParent; + _entityViews[finalQueueIndex] = newParent; int temp = newParent.QueueIndex; newParent.QueueIndex = finalQueueIndex; @@ -187,8 +185,8 @@ namespace Svelto.DataStructures else { //See note above - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; + entityView.QueueIndex = finalQueueIndex; + _entityViews[finalQueueIndex] = entityView; break; } } @@ -196,7 +194,7 @@ namespace Svelto.DataStructures /// /// Returns true if 'higher' has higher priority than 'lower', false otherwise. - /// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false + /// Note that calling HasHigherPriority(entityView, entityView) (ie. both arguments the same entityView) will return false /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -208,11 +206,11 @@ namespace Svelto.DataStructures } /// - /// Removes the head of the queue (node with highest priority; ties are broken by order of insertion), and returns it. O(log n) + /// Removes the head of the queue (entityView with highest priority; ties are broken by order of insertion), and returns it. O(log n) /// public T Dequeue() { - T returnMe = _nodes[1]; + T returnMe = _entityViews[1]; Remove(returnMe); return returnMe; } @@ -224,77 +222,77 @@ namespace Svelto.DataStructures { get { - return _nodes[1]; + return _entityViews[1]; } } /// - /// This method must be called on a node every time its priority changes while it is in the queue. + /// This method must be called on a entityView every time its priority changes while it is in the queue. /// Forgetting to call this method will result in a corrupted queue! /// O(log n) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public void UpdatePriority(T node, double priority) + public void UpdatePriority(T entityView, double priority) { - node.Priority = priority; - OnNodeUpdated(node); + entityView.Priority = priority; + OnEntityViewUpdated(entityView); } - private void OnNodeUpdated(T node) + private void OnEntityViewUpdated(T entityView) { - //Bubble the updated node up or down as appropriate - int parentIndex = node.QueueIndex / 2; - T parentNode = _nodes[parentIndex]; + //Bubble the updated entityView up or down as appropriate + int parentIndex = entityView.QueueIndex / 2; + T parentEntityView = _entityViews[parentIndex]; - if(parentIndex > 0 && HasHigherPriority(node, parentNode)) + if(parentIndex > 0 && HasHigherPriority(entityView, parentEntityView)) { - CascadeUp(node); + CascadeUp(entityView); } else { - //Note that CascadeDown will be called if parentNode == node (that is, node is the root) - CascadeDown(node); + //Note that CascadeDown will be called if parentEntityView == entityView (that is, entityView is the root) + CascadeDown(entityView); } } /// - /// Removes a node from the queue. Note that the node does not need to be the head of the queue. O(log n) + /// Removes a entityView from the queue. Note that the entityView does not need to be the head of the queue. O(log n) /// - public void Remove(T node) + public void Remove(T entityView) { - if(_numNodes <= 1) + if(_numEntityViews <= 1) { - _nodes[1] = null; - _numNodes = 0; + _entityViews[1] = null; + _numEntityViews = 0; return; } - //Make sure the node is the last node in the queue + //Make sure the entityView is the last entityView in the queue bool wasSwapped = false; - T formerLastNode = _nodes[_numNodes]; - if(node.QueueIndex != _numNodes) + T formerLastEntityView = _entityViews[_numEntityViews]; + if(entityView.QueueIndex != _numEntityViews) { - //Swap the node with the last node - Swap(node, formerLastNode); + //Swap the entityView with the last entityView + Swap(entityView, formerLastEntityView); wasSwapped = true; } - _numNodes--; - _nodes[node.QueueIndex] = null; + _numEntityViews--; + _entityViews[entityView.QueueIndex] = null; if(wasSwapped) { - //Now bubble formerLastNode (which is no longer the last node) up or down as appropriate - OnNodeUpdated(formerLastNode); + //Now bubble formerLastEntityView (which is no longer the last entityView) up or down as appropriate + OnEntityViewUpdated(formerLastEntityView); } } public IEnumerator GetEnumerator() { - for(int i = 1; i <= _numNodes; i++) - yield return _nodes[i]; + for(int i = 1; i <= _numEntityViews; i++) + yield return _entityViews[i]; } IEnumerator IEnumerable.GetEnumerator() @@ -308,16 +306,16 @@ namespace Svelto.DataStructures /// public bool IsValidQueue() { - for(int i = 1; i < _nodes.Count; i++) + for(int i = 1; i < _entityViews.Count; i++) { - if(_nodes[i] != null) + if(_entityViews[i] != null) { int childLeftIndex = 2 * i; - if(childLeftIndex < _nodes.Count && _nodes[childLeftIndex] != null && HasHigherPriority(_nodes[childLeftIndex], _nodes[i])) + if(childLeftIndex < _entityViews.Count && _entityViews[childLeftIndex] != null && HasHigherPriority(_entityViews[childLeftIndex], _entityViews[i])) return false; int childRightIndex = childLeftIndex + 1; - if(childRightIndex < _nodes.Count && _nodes[childRightIndex] != null && HasHigherPriority(_nodes[childRightIndex], _nodes[i])) + if(childRightIndex < _entityViews.Count && _entityViews[childRightIndex] != null && HasHigherPriority(_entityViews[childRightIndex], _entityViews[i])) return false; } } diff --git a/DataStructures/PriorityQueue/IPriorityQueue.cs b/DataStructures/PriorityQueue/IPriorityQueue.cs index 632820e..58997ff 100644 --- a/DataStructures/PriorityQueue/IPriorityQueue.cs +++ b/DataStructures/PriorityQueue/IPriorityQueue.cs @@ -8,16 +8,16 @@ namespace Svelto.DataStructures /// (theoretically?) optimize method calls from concrete-types slightly better. /// public interface IPriorityQueue : IEnumerable - where T : PriorityQueueNode + where T : PriorityQueueEntityView { - void Remove(T node); - void UpdatePriority(T node, double priority); - void Enqueue(T node, double priority); + void Remove(T entityView); + void UpdatePriority(T entityView, double priority); + void Enqueue(T entityView, double priority); T Dequeue(); T First { get; } int Count { get; } int MaxSize { get; } void Clear(); - bool Contains(T node); + bool Contains(T entityView); } } diff --git a/DataStructures/PriorityQueue/PriorityQueueNode.cs b/DataStructures/PriorityQueue/PriorityQueueNode.cs index b09f3a4..48c5491 100644 --- a/DataStructures/PriorityQueue/PriorityQueueNode.cs +++ b/DataStructures/PriorityQueue/PriorityQueueNode.cs @@ -1,9 +1,9 @@ namespace Svelto.DataStructures { - public class PriorityQueueNode + public class PriorityQueueEntityView { /// - /// The Priority to insert this node at. Must be set BEFORE adding a node to the queue + /// The Priority to insert this entityView at. Must be set BEFORE adding a entityView to the queue /// public double Priority { get; set; @@ -11,7 +11,7 @@ /// /// Used by the priority queue - do not edit this value. - /// Represents the order the node was inserted in + /// Represents the order the entityView was inserted in /// public long InsertionIndex { get; set; } diff --git a/ECS/DataStructures/TypeSafeDictionary.cs b/ECS/DataStructures/TypeSafeDictionary.cs index e399ba1..c7cdc14 100644 --- a/ECS/DataStructures/TypeSafeDictionary.cs +++ b/ECS/DataStructures/TypeSafeDictionary.cs @@ -1,6 +1,5 @@ using Svelto.DataStructures; using System.Collections.Generic; -using Svelto.ECS.Internal; namespace Svelto.ECS.Internal { @@ -14,35 +13,37 @@ namespace Svelto.ECS.Internal public interface ITypeSafeDictionary { - void FillWithIndexedNodes(ITypeSafeList nodes); - void Remove(int entityId); - NodeWithID GetIndexedNode(int entityID); + void FillWithIndexedEntityViews(ITypeSafeList entityViews); + bool Remove(int entityId); + IEntityView GetIndexedEntityView(int entityID); } - class TypeSafeDictionary : Dictionary, ITypeSafeDictionary where TValue:NodeWithID + class TypeSafeDictionary : Dictionary, ITypeSafeDictionary where TValue:IEntityView { internal static readonly ReadOnlyDictionary Default = new ReadOnlyDictionary(new Dictionary()); - public void FillWithIndexedNodes(ITypeSafeList nodes) + public void FillWithIndexedEntityViews(ITypeSafeList entityViews) { int count; - var buffer = FasterList.NoVirt.ToArrayFast((FasterList) nodes, out count); + var buffer = FasterList.NoVirt.ToArrayFast((FasterList) entityViews, out count); for (int i = 0; i < count; i++) { - var node = buffer[i]; + var entityView = buffer[i]; - Add(node.ID, node); + Add(entityView.ID, entityView); } } - public void Remove(int entityId) + new public bool Remove(int entityId) { - throw new System.NotImplementedException(); + base.Remove(entityId); + + return this.Count > 0; } - public NodeWithID GetIndexedNode(int entityID) + public IEntityView GetIndexedEntityView(int entityID) { return this[entityID]; } diff --git a/ECS/DataStructures/TypeSafeFasterListForECS.cs b/ECS/DataStructures/TypeSafeFasterListForECS.cs index e6e47a3..6241937 100644 --- a/ECS/DataStructures/TypeSafeFasterListForECS.cs +++ b/ECS/DataStructures/TypeSafeFasterListForECS.cs @@ -7,51 +7,57 @@ namespace Svelto.ECS.Internal { public interface ITypeSafeList: IEnumerable { - void AddRange(ITypeSafeList nodeListValue); + void AddRange(ITypeSafeList entityViewListValue); ITypeSafeList Create(); - bool isQueryiableNode { get; } - void UnorderedRemove(int index); + bool isQueryiableEntityView { get; } + bool UnorderedRemove(int entityID); ITypeSafeDictionary CreateIndexedDictionary(); + IEntityView[] ToArrayFast(out int count); } - class TypeSafeFasterListForECS: FasterList where T:INode + class TypeSafeFasterListForECS: FasterList where T:IEntityView { protected TypeSafeFasterListForECS() { _mappedIndices = new Dictionary(); } - public void UnorderedRemove(int mappedIndex) + public bool UnorderedRemove(int entityID) { - var index = _mappedIndices[mappedIndex]; - _mappedIndices.Remove(mappedIndex); + var index = _mappedIndices[entityID]; + + DesignByContract.Check.Assert(entityID == this[index].ID, "Something went wrong with the Svelto.ECS code, please contact the author"); + + _mappedIndices.Remove(entityID); if (UnorderedRemoveAt(index)) _mappedIndices[this[index].ID] = index; + + return this.Count > 0; } - public void AddRange(ITypeSafeList nodeListValue) + public void AddRange(ITypeSafeList entityViewListValue) { var index = this.Count; - AddRange(nodeListValue as FasterList); + AddRange(entityViewListValue as FasterList); for (int i = index; i < Count; ++i) - _mappedIndices[this[i].ID] = this.Count; + _mappedIndices[this[i].ID] = i; } readonly Dictionary _mappedIndices; } - class TypeSafeFasterListForECSForStructs : TypeSafeFasterListForECS, ITypeSafeList where T:struct, INode + class TypeSafeFasterListForECSForStructs : TypeSafeFasterListForECS, ITypeSafeList where T:struct, IEntityStruct { public ITypeSafeList Create() { return new TypeSafeFasterListForECSForStructs(); } - public bool isQueryiableNode + public bool isQueryiableEntityView { get { return false; } } @@ -60,16 +66,21 @@ namespace Svelto.ECS.Internal { throw new Exception("Not Allowed"); } + + public IEntityView[] ToArrayFast(out int count) + { + throw new Exception("Not Allowed"); + } } - class TypeSafeFasterListForECSForClasses : TypeSafeFasterListForECS, ITypeSafeList where T:NodeWithID + class TypeSafeFasterListForECSForClasses : TypeSafeFasterListForECS, ITypeSafeList where T:EntityView, new() { public ITypeSafeList Create() { return new TypeSafeFasterListForECSForClasses(); } - public bool isQueryiableNode + public bool isQueryiableEntityView { get { return true; } } @@ -78,5 +89,12 @@ namespace Svelto.ECS.Internal { return new TypeSafeDictionary(); } + + public IEntityView[] ToArrayFast(out int count) + { + count = this.Count; + + return this.ToArrayFast(); + } } } diff --git a/ECS/EngineNodeDB.cs b/ECS/EngineNodeDB.cs index 126dd46..103275f 100644 --- a/ECS/EngineNodeDB.cs +++ b/ECS/EngineNodeDB.cs @@ -5,137 +5,164 @@ using Svelto.ECS.Internal; namespace Svelto.ECS { - public class EngineNodeDB : IEngineNodeDB + public class EngineEntityViewDB : IEngineEntityViewDB { - internal EngineNodeDB( Dictionary nodesDB, - Dictionary nodesDBdic, - Dictionary metaNodesDB, - Dictionary> groupNodesDB) + internal EngineEntityViewDB( Dictionary entityViewsDB, + Dictionary entityViewsDBdic, + Dictionary metaEntityViewsDB, + Dictionary> groupEntityViewsDB) { - _nodesDB = nodesDB; - _nodesDBdic = nodesDBdic; - _metaNodesDB = metaNodesDB; - _groupNodesDB = groupNodesDB; + _entityViewsDB = entityViewsDB; + _entityViewsDBdic = entityViewsDBdic; + _metaEntityViewsDB = metaEntityViewsDB; + _groupEntityViewsDB = groupEntityViewsDB; } - public FasterReadOnlyList QueryNodes() + public FasterReadOnlyList QueryEntityViews() where T:EntityView, new() { var type = typeof(T); - ITypeSafeList nodes; + ITypeSafeList entityViews; - if (_nodesDB.TryGetValue(type, out nodes) == false) - return RetrieveEmptyNodeList(); + if (_entityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewList(); - return new FasterReadOnlyList((FasterList)nodes); + return new FasterReadOnlyList((FasterList)entityViews); } - public FasterReadOnlyList QueryGroupedNodes(int @group) + public FasterReadOnlyList QueryGroupedEntityViews(int @group) where T:EntityView, new() { - return new FasterReadOnlyList(_groupNodesDB[group] as FasterList); + Dictionary entityViews; + + if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) + return RetrieveEmptyEntityViewList(); + + return new FasterReadOnlyList(entityViews as FasterList); } - public T[] QueryNodesAsArray(out int count) where T : struct + public T[] QueryEntityViewsAsArray(out int count) where T : IEntityView { var type = typeof(T); count = 0; - ITypeSafeList nodes; + ITypeSafeList entityViews; - if (_nodesDB.TryGetValue(type, out nodes) == false) - return null; + if (_entityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewArray(); - var castedNodes = (FasterList)nodes; + var castedEntityViews = (FasterList)entityViews; - count = castedNodes.Count; + count = castedEntityViews.Count; - return castedNodes.ToArrayFast(); + return castedEntityViews.ToArrayFast(); } - - public ReadOnlyDictionary QueryIndexableNodes() where T:NodeWithID + + public T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T : IEntityView { var type = typeof(T); + count = 0; + + Dictionary entityViews; + + if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) + return RetrieveEmptyEntityViewArray(); + + var castedEntityViews = (FasterList)entityViews[type]; - ITypeSafeDictionary nodes; - - if (_nodesDBdic.TryGetValue(type, out nodes) == false) - return TypeSafeDictionary.Default; - - return new ReadOnlyDictionary(nodes as Dictionary); - } - - public T QueryMetaNode(int metaEntityID) where T:NodeWithID - { - return QueryNode(metaEntityID); - } + count = castedEntityViews.Count; - public bool TryQueryMetaNode(int metaEntityID, out T node) where T:NodeWithID - { - return TryQueryNode(metaEntityID, out node); + return castedEntityViews.ToArrayFast(); } - public FasterReadOnlyList QueryMetaNodes() + public ReadOnlyDictionary QueryIndexableEntityViews() where T:IEntityView { var type = typeof(T); - ITypeSafeList nodes; + ITypeSafeDictionary entityViews; - if (_metaNodesDB.TryGetValue(type, out nodes) == false) - return RetrieveEmptyNodeList(); + if (_entityViewsDBdic.TryGetValue(type, out entityViews) == false) + return TypeSafeDictionary.Default; - return new FasterReadOnlyList((FasterList)nodes); + return new ReadOnlyDictionary(entityViews as Dictionary); } - public bool TryQueryNode(int ID, out T node) where T:NodeWithID + public bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView { var type = typeof(T); - T internalNode; + T internalEntityView; - ITypeSafeDictionary nodes; + ITypeSafeDictionary entityViews; TypeSafeDictionary casted; - _nodesDBdic.TryGetValue(type, out nodes); - casted = nodes as TypeSafeDictionary; + _entityViewsDBdic.TryGetValue(type, out entityViews); + casted = entityViews as TypeSafeDictionary; if (casted != null && - casted.TryGetValue(ID, out internalNode)) + casted.TryGetValue(ID, out internalEntityView)) { - node = (T) internalNode; + entityView = (T)internalEntityView; return true; } - - node = default(T); + + entityView = default(T); return false; } - public T QueryNode(int ID) where T:NodeWithID + public T QueryEntityView(int ID) where T : IEntityView { var type = typeof(T); - T internalNode; ITypeSafeDictionary nodes; + T internalEntityView; ITypeSafeDictionary entityViews; TypeSafeDictionary casted; - _nodesDBdic.TryGetValue(type, out nodes); - casted = nodes as TypeSafeDictionary; + _entityViewsDBdic.TryGetValue(type, out entityViews); + casted = entityViews as TypeSafeDictionary; if (casted != null && - casted.TryGetValue(ID, out internalNode)) - return (T)internalNode; + casted.TryGetValue(ID, out internalEntityView)) + return (T)internalEntityView; - throw new Exception("Node Not Found"); + throw new Exception("EntityView Not Found"); } - static FasterReadOnlyList RetrieveEmptyNodeList() + public T QueryMetaEntityView(int metaEntityID) where T:EntityView, new() + { + return QueryEntityView(metaEntityID); + } + + public bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T:EntityView, new() + { + return TryQueryEntityView(metaEntityID, out entityView); + } + + public FasterReadOnlyList QueryMetaEntityViews() where T:EntityView, new() + { + var type = typeof(T); + + ITypeSafeList entityViews; + + if (_metaEntityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewList(); + + return new FasterReadOnlyList((FasterList)entityViews); + } + + static FasterReadOnlyList RetrieveEmptyEntityViewList() { return FasterReadOnlyList.DefaultList; } - readonly Dictionary _nodesDB; - readonly Dictionary _nodesDBdic; - readonly Dictionary _metaNodesDB; - readonly Dictionary> _groupNodesDB; + static T[] RetrieveEmptyEntityViewArray() + { + return FasterList.DefaultList.ToArrayFast(); + } + + readonly Dictionary _entityViewsDB; + readonly Dictionary _entityViewsDBdic; + readonly Dictionary _metaEntityViewsDB; + readonly Dictionary> _groupEntityViewsDB; } } diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs index 7602238..882e57b 100644 --- a/ECS/EnginesRoot.cs +++ b/ECS/EnginesRoot.cs @@ -1,167 +1,200 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; using Svelto.DataStructures; using Svelto.ECS.Internal; -using Svelto.ECS.Legacy; -using Svelto.ECS.NodeSchedulers; -using Svelto.ECS.Profiler; +using Svelto.ECS.Schedulers; using Svelto.Utilities; +using Svelto.WeakEvents; + +#if EXPERIMENTAL +using Svelto.ECS.Experimental; +using Svelto.ECS.Experimental.Internal; +#endif #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR using Svelto.ECS.Profiler; #endif -namespace Svelto.ECS.Internal -{ - struct BuildNodeCallbackStruct - { - public Action, int> internalRemove; - public Action, int> internalEnable; - public Action, int> internalDisable; - } -} - namespace Svelto.ECS { - public sealed class EnginesRoot : IEnginesRoot, IEntityFactory + public sealed class EnginesRoot : IEntityFunctions, IEntityFactory, IDisposable { - public EnginesRoot(NodeSubmissionScheduler nodeScheduler) + public EnginesRoot(EntityViewSubmissionScheduler entityViewScheduler) { - _nodeEngines = new Dictionary>(); - _activableEngines = new Dictionary>(); + _entityViewEngines = new Dictionary>(); _otherEngines = new FasterList(); - _engineRootWeakReference = new DataStructures.WeakReference(this); - - _nodesDB = new Dictionary(); - _metaNodesDB = new Dictionary(); - _groupNodesDB = new Dictionary>(); - _nodesDBdic = new Dictionary(); - - _sharedStructNodeLists = new SharedStructNodeLists(); - _sharedGroupedStructNodeLists = new SharedGroupedStructNodesLists(); - - _nodesToAdd = new DoubleBufferedNodes>(); - _metaNodesToAdd = new DoubleBufferedNodes>(); - _groupedNodesToAdd = new DoubleBufferedNodes>>(); - - _callBackStructForBuiltGroupedNodes = new BuildNodeCallbackStruct(); - - _callBackStructForBuiltGroupedNodes.internalRemove = InternalRemove; - _callBackStructForBuiltGroupedNodes.internalDisable = InternalDisable; - _callBackStructForBuiltGroupedNodes.internalEnable = InternalEnable; + _entityViewsDB = new Dictionary(); + _metaEntityViewsDB = new Dictionary(); + _groupEntityViewsDB = new Dictionary>(); + _entityViewsDBdic = new Dictionary(); - _callBackStructForBuiltNodes = new BuildNodeCallbackStruct(); - - _callBackStructForBuiltNodes.internalRemove = InternalGroupedRemove; - _callBackStructForBuiltNodes.internalDisable = InternalDisable; - _callBackStructForBuiltNodes.internalEnable = InternalEnable; - - _callBackStructForBuiltMetaNodes = new BuildNodeCallbackStruct(); - - _callBackStructForBuiltMetaNodes.internalRemove = InternalMetaRemove; - _callBackStructForBuiltMetaNodes.internalDisable = InternalDisable; - _callBackStructForBuiltMetaNodes.internalEnable = InternalEnable; - - _scheduler = nodeScheduler; - _scheduler.Schedule(SubmitNodes); - - _structNodeEngineType = typeof(IStructNodeEngine<>); - _groupedStructNodesEngineType = typeof(IGroupedStructNodesEngine<>); - _activableNodeEngineType = typeof(IActivableNodeEngine<>); + _entityViewsToAdd = new DoubleBufferedEntityViews>(); + _metaEntityViewsToAdd = new DoubleBufferedEntityViews>(); + _groupedEntityViewsToAdd = new DoubleBufferedEntityViews>>(); +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + _addEntityViewToEngine = AddEntityViewToEngine; + _removeEntityViewFromEngine = RemoveEntityViewFromEngine; +#endif + _engineEntityViewDB = new EngineEntityViewDB(_entityViewsDB, _entityViewsDBdic, _metaEntityViewsDB, _groupEntityViewsDB); + + _scheduler = entityViewScheduler; + _scheduler.Schedule(new WeakAction(SubmitEntityViews)); +#if EXPERIMENTAL + _sharedStructEntityViewLists = new SharedStructEntityViewLists(); + _sharedGroupedStructEntityViewLists = new SharedGroupedStructEntityViewsLists(); + + _structEntityViewEngineType = typeof(IStructEntityViewEngine<>); + _groupedStructEntityViewsEngineType = typeof(IGroupedStructEntityViewsEngine<>); _implementedInterfaceTypes = new Dictionary(); - -#if UNITY_EDITOR +#endif +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); debugEngineObject.gameObject.AddComponent(); #endif } - public void BuildEntity(int ID, EntityDescriptor ed) + public IEntityFactory GenerateEntityFactory() + { + return new GenericEntityFactory(new DataStructures.WeakReference(this)); + } + + public IEntityFunctions GenerateEntityFunctions() { - ed.BuildNodes(ID, _nodesToAdd.other, ref _callBackStructForBuiltNodes); + return new GenericEntityFunctions(new DataStructures.WeakReference(this)); + } + + public void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new() + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, EntityDescriptorTemplate.Default, implementors); + } + + public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, entityDescriptor, implementors); } /// /// A meta entity is a way to manage a set of entitites that are not easily /// queriable otherwise. For example you may want to group existing entities - /// by size and type and then use the meta entity node to manage the data + /// by size and type and then use the meta entity entityView to manage the data /// shared among the single entities of the same type and size. This will /// prevent the scenario where the coder is forced to parse all the entities to /// find the ones of the same size and type. - /// Since the entities are managed through the shared node, the same - /// shared node must be found on the single entities of the same type and size. - /// The shared node of the meta entity is then used by engines that are meant - /// to manage a group of entities through a single node. - /// The same engine can manage several meta entities nodes too. - /// The Engine manages the logic of the Meta Node data and other engines - /// can read back this data through the normal entity as the shared node + /// Since the entities are managed through the shared entityView, the same + /// shared entityView must be found on the single entities of the same type and size. + /// The shared entityView of the meta entity is then used by engines that are meant + /// to manage a group of entities through a single entityView. + /// The same engine can manage several meta entities entityViews too. + /// The Engine manages the logic of the Meta EntityView data and other engines + /// can read back this data through the normal entity as the shared entityView /// will be present in their descriptor too. - /// It's a way to control a group of Entities through a node only. - /// This set of entities can share exactly the same node reference if + /// It's a way to control a group of Entities through a entityView only. + /// This set of entities can share exactly the same entityView reference if /// built through this function. In this way, if you need to set a variable - /// on a group of entities, instead to inject N nodes and iterate over - /// them to set the same value, you can inject just one node, set the value + /// on a group of entities, instead to inject N entityViews and iterate over + /// them to set the same value, you can inject just one entityView, set the value /// and be sure that the value is shared between entities. /// /// /// - public void BuildMetaEntity(int metaEntityID, EntityDescriptor ed) + /// + public void BuildMetaEntity(int metaEntityID, object[] implementors) where T:IEntityDescriptor, new() { - ed.BuildNodes(metaEntityID, _metaNodesToAdd.other, ref _callBackStructForBuiltMetaNodes); + EntityFactory.BuildEntityViews(metaEntityID, _entityViewsToAdd.current, + EntityDescriptorTemplate.Default, implementors); } /// - /// Using this function is like building a normal entity, but the nodes + /// Using this function is like building a normal entity, but the entityViews /// are grouped by groupID to be better processed inside engines and - /// improve cache locality. Only IGroupStructNodeWithID nodes are grouped - /// other nodes are managed as usual. + /// improve cache locality. Only IGroupStructEntityViewWithID entityViews are grouped + /// other entityViews are managed as usual. /// /// /// /// - public void BuildEntityInGroup(int entityID, int groupID, - EntityDescriptor ed) + /// + public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new() { - ed.BuildGroupedNodes(entityID, groupID, _groupedNodesToAdd.other, ref _callBackStructForBuiltGroupedNodes); + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + EntityDescriptorTemplate.Default, + implementors); } - public void AddEngine(IEngine engine) + public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) { -#if UNITY_EDITOR - EngineProfiler.AddEngine(engine); -#endif - var queryableNodeEngine = engine as IQueryableNodeEngine; - if (queryableNodeEngine != null) - queryableNodeEngine.nodesDB = - new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB, _groupNodesDB); + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + entityDescriptor, implementors); + } - var engineType = engine.GetType(); - var implementedInterfaces = engineType.GetInterfaces(); + public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) + { + var removeEntityImplementor = removeInfo as RemoveEntityImplementor; - CollectImplementedInterfaces(implementedInterfaces); + if (removeEntityImplementor.removeEntityInfo.isInAGroup) + InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, removeEntityImplementor.removeEntityInfo.groupID, _entityViewsDB); + else + InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, _entityViewsDB); + } - var engineAdded = CheckGenericEngines(engine); + public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, entityID, _entityViewsDB); + } - if (CheckLegacyNodesEngine(engine, ref engineAdded) == false) - CheckNodesEngine(engine, engineType, ref engineAdded); + public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, metaEntityID, _metaEntityViewsDB); + } - if (engineAdded == false) + public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); + } + + public void AddEngine(IEngine engine) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + Profiler.EngineProfiler.AddEngine(engine); +#endif + var engineType = engine.GetType(); +#if EXPERIMENTAL + bool engineAdded; + + var implementedInterfaces = engineType.GetInterfaces(); + + CollectImplementedInterfaces(implementedInterfaces); + + engineAdded = CheckSpecialEngine(engine); +#endif + var viewEngine = engine as IHandleEntityViewEngine; + + if (viewEngine != null) + CheckEntityViewsEngine(viewEngine, engineType); + else _otherEngines.Add(engine); - - var callBackOnAddEngine = engine as ICallBackOnAddEngine; - if (callBackOnAddEngine != null) - callBackOnAddEngine.Ready(); + + var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; + if (queryableEntityViewEngine != null) + { + queryableEntityViewEngine.entityViewsDB = _engineEntityViewDB; + queryableEntityViewEngine.Ready(); + } } - - void CollectImplementedInterfaces(Type[] implementedInterfaces) + +#if EXPERIMENTAL + void CollectImplementedInterfaces(Type[] implementedInterfaces) { _implementedInterfaceTypes.Clear(); - var type = typeof(IEngine); + var type = typeof(IHandleEntityViewEngine); for (int index = 0; index < implementedInterfaces.Length; index++) { @@ -180,81 +213,60 @@ namespace Svelto.ECS _implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); } } - - bool CheckGenericEngines(IEngine engine) + + bool CheckSpecialEngine(IEngine engine) { if (_implementedInterfaceTypes.Count == 0) return false; bool engineAdded = false; - if (_implementedInterfaceTypes.ContainsKey(_structNodeEngineType)) - { - ((IStructNodeEngine)engine).CreateStructNodes - (_sharedStructNodeLists); - } - - if (_implementedInterfaceTypes.ContainsKey(_groupedStructNodesEngineType)) + if (_implementedInterfaceTypes.ContainsKey(_structEntityViewEngineType)) { - ((IGroupedStructNodesEngine)engine).CreateStructNodes - (_sharedGroupedStructNodeLists); + ((IStructEntityViewEngine)engine).CreateStructEntityViews + (_sharedStructEntityViewLists); } - Type[] arguments; - if (_implementedInterfaceTypes.TryGetValue(_activableNodeEngineType, - out arguments)) + if (_implementedInterfaceTypes.ContainsKey(_groupedStructEntityViewsEngineType)) { - AddEngine(engine, arguments, _activableEngines); - - engineAdded = true; + ((IGroupedStructEntityViewsEngine)engine).CreateStructEntityViews + (_sharedGroupedStructEntityViewLists); } return engineAdded; } - - bool CheckLegacyNodesEngine(IEngine engine, ref bool engineAdded) - { - var nodesEngine = engine as INodesEngine; - if (nodesEngine != null) - { - AddEngine(nodesEngine, nodesEngine.AcceptedNodes(), _nodeEngines); - - engineAdded = true; - - return true; - } - - return false; - } - - bool CheckNodesEngine(IEngine engine, Type engineType, ref bool engineAdded) +#endif + void CheckEntityViewsEngine(IEngine engine, Type engineType) { var baseType = engineType.GetBaseType(); - - if (baseType.IsGenericTypeEx() - && engine is INodeEngine) - { - AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines); - engineAdded = true; + if (baseType.IsGenericTypeEx()) + { + var genericArguments = baseType.GetGenericArguments(); + AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); +#if EXPERIMENTAL + var activableEngine = engine as IHandleActivableEntityEngine; + if (activableEngine != null) + AddEngine(activableEngine, genericArguments, _activableViewEntitiesEngines); +#endif - return true; + return; } - return false; + throw new Exception("Not Supported Engine"); } - static void AddEngine(IEngine engine, Type[] types, - Dictionary> engines) + static void AddEngine(T engine, Type[] types, + Dictionary> engines) { for (int i = 0; i < types.Length; i++) { - FasterList list; + FasterList list; var type = types[i]; if (engines.TryGetValue(type, out list) == false) { - list = new FasterList(); + list = new FasterList(); engines.Add(type, list); } @@ -263,309 +275,362 @@ namespace Svelto.ECS } } - static void AddNodesToTheDBAndSuitableEngines(Dictionary nodesToAdd, - Dictionary> nodeEngines, - Dictionary nodesDBdic, - Dictionary nodesDB) + void AddEntityViewsToTheDBAndSuitableEngines(Dictionary entityViewsToAdd, + Dictionary entityViewsDB) { - foreach (var nodeList in nodesToAdd) + foreach (var entityViewList in entityViewsToAdd) { - AddNodeToDB(nodesDB, nodeList); + AddEntityViewToDB(entityViewsDB, entityViewList); + + if (entityViewList.Value.isQueryiableEntityView) + { + AddEntityViewToEntityViewsDictionary(_entityViewsDBdic, entityViewList.Value, entityViewList.Key); + } + } - if (nodeList.Value.isQueryiableNode) + foreach (var entityViewList in entityViewsToAdd) + { + if (entityViewList.Value.isQueryiableEntityView) { - AddNodeToNodesDictionary(nodesDBdic, nodeList.Value, nodeList.Key); - - foreach (var node in nodeList.Value) - AddNodeToTheSuitableEngines(nodeEngines, node as NodeWithID, nodeList.Key); + AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, + entityViewList.Key); } } } - static void AddGroupNodesToTheDBAndSuitableEngines(Dictionary> groupedNodesToAdd, - Dictionary> nodeEngines, - Dictionary nodesDBdic, - Dictionary> groupNodesDB, - Dictionary nodesDB) + void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary> groupedEntityViewsToAdd, + Dictionary> groupEntityViewsDB, + Dictionary entityViewsDB) { - foreach (var group in groupedNodesToAdd) + foreach (var group in groupedEntityViewsToAdd) { - AddNodesToTheDBAndSuitableEngines(group.Value, nodeEngines, nodesDBdic, nodesDB); + AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); - AddNodesToGroupDB(groupNodesDB, @group); + AddEntityViewsToGroupDB(groupEntityViewsDB, @group); } } - static void AddNodesToGroupDB(Dictionary> groupNodesDB, + static void AddEntityViewsToGroupDB(Dictionary> groupEntityViewsDB, KeyValuePair> @group) { - Dictionary groupedNodesByType; + Dictionary groupedEntityViewsByType; - if (groupNodesDB.TryGetValue(@group.Key, out groupedNodesByType) == false) - groupedNodesByType = groupNodesDB[@group.Key] = new Dictionary(); + if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) + groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary(); - foreach (var node in @group.Value) + foreach (var entityView in @group.Value) { - groupedNodesByType.Add(node.Key, node.Value); + groupedEntityViewsByType.Add(entityView.Key, entityView.Value); } } - static void AddNodeToDB(Dictionary nodesDB, KeyValuePair nodeList) + static void AddEntityViewToDB(Dictionary entityViewsDB, KeyValuePair entityViewList) { ITypeSafeList dbList; - if (nodesDB.TryGetValue(nodeList.Key, out dbList) == false) - dbList = nodesDB[nodeList.Key] = nodeList.Value.Create(); + if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) + dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); - dbList.AddRange(nodeList.Value); + dbList.AddRange(entityViewList.Value); } - static void AddNodeToNodesDictionary(Dictionary nodesDBdic, - ITypeSafeList nodes, Type nodeType) + static void AddEntityViewToEntityViewsDictionary(Dictionary entityViewsDBdic, + ITypeSafeList entityViews, Type entityViewType) { - ITypeSafeDictionary nodesDic; + ITypeSafeDictionary entityViewsDic; - if (nodesDBdic.TryGetValue(nodeType, out nodesDic) == false) - nodesDic = nodesDBdic[nodeType] = nodes.CreateIndexedDictionary(); + if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) + entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); - nodesDic.FillWithIndexedNodes(nodes); + entityViewsDic.FillWithIndexedEntityViews(entityViews); } - static void AddNodeToTheSuitableEngines(Dictionary> nodeEngines, NodeWithID node, Type nodeType) + static void AddEntityViewToTheSuitableEngines(Dictionary> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) { - FasterList enginesForNode; + FasterList enginesForEntityView; - if (nodeEngines.TryGetValue(nodeType, out enginesForNode)) + if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) { - for (int j = 0; j < enginesForNode.Count; j++) + int viewsCount; + + var entityViews = entityViewsList.ToArrayFast(out viewsCount); + + for (int i = 0; i < viewsCount; i++) { + int count; + var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); + IEntityView entityView = entityViews[i]; + for (int j = 0; j < count; j++) + { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); + EngineProfiler.MonitorAddDuration(_addEntityViewToEngine, fastList[j], entityView); #else - (enginesForNode[j] as INodeEngine).Add(node); + fastList[j].Add(entityView); #endif + } } } } -/* - void DisableNodeFromEngines(INode node, Type nodeType) - { - ITypeSafeList enginesForNode; - if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) + void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, + Dictionary entityViewsDB) + { + int entityViewBuildersCount = entityViewBuilders.Length; + + for (int i = 0; i < entityViewBuildersCount; i++) { - for (int j = 0; j < enginesForNode.Count; j++) - { - (enginesForNode[j] as IActivableNodeEngine).Disable(node); - } - } - } + Type entityViewType = entityViewBuilders[i].GetEntityViewType(); - void EnableNodeFromEngines(INode node, Type nodeType) - { - ITypeSafeList enginesForNode; + ITypeSafeList entityViews = entityViewsDB[entityViewType]; + if (entityViews.UnorderedRemove(entityID) == false) + entityViewsDB.Remove(entityViewType); - if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) + if (entityViews.isQueryiableEntityView) { - (enginesForNode[j] as IActivableNodeEngine).Enable(node); + var typeSafeDictionary = _entityViewsDBdic[entityViewType]; + var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); + + if (typeSafeDictionary.Remove(entityID) == false) + _entityViewsDBdic.Remove(entityViewType); + + RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType); } } - }*/ -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - void AddNodeToEngine(IEngine engine, INode node) - { - (engine as INodeEngine).Add(node); - } - - void RemoveNodeFromEngine(IEngine engine, INode node) - { - (engine as INodeEngine).Remove(node); } -#endif - void InternalDisable(FasterList nodeBuilders, int entityID) + void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, + Dictionary entityViewsDB) { -/* if (_engineRootWeakReference.IsValid == false) - return; + int entityViewBuildersCount = entityViewBuilders.Length; - for (int i = 0; i < nodes.Count; i++) + for (int i = 0; i < entityViewBuildersCount; i++) { - var node = nodes[i]; - Type nodeType = node.GetType(); - - DisableNodeFromEngines(node, nodeType); - }*/ - } + Type entityViewType = entityViewBuilders[i].GetEntityViewType(); + Dictionary dictionary = _groupEntityViewsDB[groupID]; - void InternalEnable(FasterList nodeBuilders, int entityID) - {/* - if (_engineRootWeakReference.IsValid == false) - return; + if (dictionary[entityViewType].UnorderedRemove(entityID) == false) + dictionary.Remove(entityViewType); - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); - EnableNodeFromEngines(node, nodeType); - }*/ + if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); + } + + InternalRemove(entityViewBuilders, entityID, entityViewsDB); } - void InternalRemove(FasterList nodeBuilders, int entityID) + static void RemoveEntityViewFromEngines(Dictionary> entityViewEngines, + IEntityView entityView, Type entityViewType) { - if (_engineRootWeakReference.IsValid == false) - return; + FasterList enginesForEntityView; - int nodeBuildersCount = nodeBuilders.Count; - for (int i = 0; i < nodeBuildersCount; i++) + if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) { - Type nodeType = nodeBuilders[i].GetType(); - - ITypeSafeList nodes; - if (_nodesDB.TryGetValue(nodeType, out nodes) == true) - nodes.UnorderedRemove(entityID); - - if (nodes.isQueryiableNode) + int count; + var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); + + for (int j = 0; j < count; j++) { - var node = _nodesDBdic[nodeType].GetIndexedNode(entityID); - - _nodesDBdic[nodeType].Remove(entityID); - - RemoveNodeFromEngines(_nodeEngines, node, nodeType); +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + EngineProfiler.MonitorRemoveDuration(_removeEntityViewFromEngine, fastList[j], entityView); +#else + fastList[j].Remove(entityView); +#endif } } } - - void InternalGroupedRemove(FasterList nodeBuilders, int entityID) + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + static void AddEntityViewToEngine(IHandleEntityViewEngine engine, IEntityView entityView) { + engine.Add(entityView); } - void InternalMetaRemove(FasterList nodeBuilders, int entityID) + static void RemoveEntityViewFromEngine(IHandleEntityViewEngine engine, IEntityView entityView) { + engine.Remove(entityView); } - - static void RemoveNodeFromEngines(Dictionary> nodeEngines, NodeWithID node, Type nodeType) - { - FasterList enginesForNode; - - if (nodeEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); -#else - (enginesForNode[j] as INodeEngine).Remove(node); #endif - } - } - } - void SubmitNodes() + void SubmitEntityViews() { - _nodesToAdd.Swap(); - _metaNodesToAdd.Swap(); - _groupedNodesToAdd.Swap(); - - bool newNodesHaveBeenAddedWhileIterating = - _metaNodesToAdd.Count > 0 - || _nodesToAdd.Count > 0 - || _groupedNodesToAdd.Count > 0; + bool newEntityViewsHaveBeenAddedWhileIterating = + _metaEntityViewsToAdd.current.Count > 0 + || _entityViewsToAdd.current.Count > 0 + || _groupedEntityViewsToAdd.current.Count > 0; int numberOfReenteringLoops = 0; - while (newNodesHaveBeenAddedWhileIterating) + while (newEntityViewsHaveBeenAddedWhileIterating) { - if ( _nodesToAdd.Count > 0) - AddNodesToTheDBAndSuitableEngines(_nodesToAdd.current, _nodeEngines, _nodesDBdic, _nodesDB); + //use other as source from now on + //current will be use to write new entityViews + _entityViewsToAdd.Swap(); + _metaEntityViewsToAdd.Swap(); + _groupedEntityViewsToAdd.Swap(); + + if ( _entityViewsToAdd.other.Count > 0) + AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB); - if ( _metaNodesToAdd.Count > 0) - AddNodesToTheDBAndSuitableEngines(_metaNodesToAdd.current, _nodeEngines, _nodesDBdic, _metaNodesDB); + if ( _metaEntityViewsToAdd.other.Count > 0) + AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); - if (_groupedNodesToAdd.Count > 0) - AddGroupNodesToTheDBAndSuitableEngines(_groupedNodesToAdd.current, _nodeEngines, _nodesDBdic, _groupNodesDB, _nodesDB); + if (_groupedEntityViewsToAdd.other.Count > 0) + AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); - _nodesToAdd.Clear(); - _metaNodesToAdd.Clear(); - _groupedNodesToAdd.Clear(); + //other can be cleared now + _entityViewsToAdd.other.Clear(); + _metaEntityViewsToAdd.other.Clear(); + _groupedEntityViewsToAdd.other.Clear(); - _nodesToAdd.Swap(); - _metaNodesToAdd.Swap(); - _groupedNodesToAdd.Swap(); - - newNodesHaveBeenAddedWhileIterating = - _metaNodesToAdd.Count > 0 - || _nodesToAdd.Count > 0 - || _groupedNodesToAdd.Count > 0; + //has current new entityViews? + newEntityViewsHaveBeenAddedWhileIterating = + _metaEntityViewsToAdd.current.Count > 0 + || _entityViewsToAdd.current.Count > 0 + || _groupedEntityViewsToAdd.current.Count > 0; if (numberOfReenteringLoops > 5) - throw new Exception("possible infinite loop found creating Entities inside INodesEngine Add method, please consider building entities outside INodesEngine Add method"); + throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); numberOfReenteringLoops++; } } - readonly Dictionary> _nodeEngines; - readonly Dictionary> _activableEngines; + readonly Dictionary> _entityViewEngines; readonly FasterList _otherEngines; - readonly Dictionary _nodesDB; - readonly Dictionary _metaNodesDB; - readonly Dictionary> _groupNodesDB; + readonly Dictionary _entityViewsDB; + readonly Dictionary _metaEntityViewsDB; + readonly Dictionary> _groupEntityViewsDB; - readonly Dictionary _nodesDBdic; + readonly Dictionary _entityViewsDBdic; - readonly DoubleBufferedNodes> _nodesToAdd; - readonly DoubleBufferedNodes> _metaNodesToAdd; - readonly DoubleBufferedNodes>> _groupedNodesToAdd; + readonly DoubleBufferedEntityViews> _entityViewsToAdd; + readonly DoubleBufferedEntityViews> _metaEntityViewsToAdd; + readonly DoubleBufferedEntityViews>> _groupedEntityViewsToAdd; - readonly NodeSubmissionScheduler _scheduler; - - readonly Type _structNodeEngineType; - readonly Type _groupedStructNodesEngineType; - readonly Type _activableNodeEngineType; + readonly EntityViewSubmissionScheduler _scheduler; +#if EXPERIMENTAL + readonly Type _structEntityViewEngineType; + readonly Type _groupedStructEntityViewsEngineType; - readonly SharedStructNodeLists _sharedStructNodeLists; - readonly SharedGroupedStructNodesLists _sharedGroupedStructNodeLists; - - readonly Dictionary _implementedInterfaceTypes; - readonly DataStructures.WeakReference _engineRootWeakReference; - - BuildNodeCallbackStruct _callBackStructForBuiltNodes; - BuildNodeCallbackStruct _callBackStructForBuiltGroupedNodes; - BuildNodeCallbackStruct _callBackStructForBuiltMetaNodes; + readonly SharedStructEntityViewLists _sharedStructEntityViewLists; + readonly SharedGroupedStructEntityViewsLists _sharedGroupedStructEntityViewLists; + + readonly Dictionary _implementedInterfaceTypes; +#endif + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + static Action _addEntityViewToEngine; + static Action _removeEntityViewFromEngine; +#endif + readonly EngineEntityViewDB _engineEntityViewDB; - class DoubleBufferedNodes where T : class, IDictionary, new() + class DoubleBufferedEntityViews where T : class, IDictionary, new() { - readonly T _nodesToAddBufferA = new T(); - readonly T _nodesToAddBufferB = new T(); + readonly T _entityViewsToAddBufferA = new T(); + readonly T _entityViewsToAddBufferB = new T(); - public DoubleBufferedNodes() + public DoubleBufferedEntityViews() { - this.other = _nodesToAddBufferA; - this.current = _nodesToAddBufferB; + this.other = _entityViewsToAddBufferA; + this.current = _entityViewsToAddBufferB; } public T other { get; private set; } public T current { get; private set; } + + public void Swap() + { + var toSwap = other; + other = current; + current = toSwap; + } + } + + class GenericEntityFactory : IEntityFactory + { + DataStructures.WeakReference _weakEngine; - public int Count + public GenericEntityFactory(DataStructures.WeakReference weakReference) { - get { return current.Count; } + _weakEngine = weakReference; } - - public void Clear() + + public void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() { - current.Clear(); + _weakEngine.Target.BuildEntity(entityID, implementors); } - public void Swap() + public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) { - var toSwap = other; - other = current; - current = toSwap; + _weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); + } + + public void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildMetaEntity(metaEntityID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); + } + } + + class GenericEntityFunctions : IEntityFunctions + { + public GenericEntityFunctions(DataStructures.WeakReference weakReference) + { + _weakReference = weakReference; + } + + public void RemoveEntity(int entityID, IRemoveEntityComponent entityTemplate) + { + _weakReference.Target.RemoveEntity(entityID, entityTemplate); + } + + public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(metaEntityID); + } + + public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + readonly DataStructures.WeakReference _weakReference; + } + + public void Dispose() + { + foreach (var entity in _entityViewsDB) + { + if (entity.Value.isQueryiableEntityView == true) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } + } + } + + foreach (var entity in _metaEntityViewsDB) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } } } } diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs deleted file mode 100644 index 6202eac..0000000 --- a/ECS/EntityDescriptor.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using Svelto.DataStructures; -using Svelto.ECS.Internal; - -namespace Svelto.ECS -{ - public class EntityDescriptor - { - public void AddImplementors(params object[] componentsImplementor) - { - ProcessImplementors(componentsImplementor); - } - - public void AddNodes(params INodeBuilder[] nodesWithID) - { - _nodesToBuild.AddRange(nodesWithID); - } - - internal void BuildGroupedNodes - (int entityID, int groupID, - Dictionary> groupNodesByType, - ref BuildNodeCallbackStruct callBackstruct) - { - for (int index = 0; index < _nodesToBuild.Count; index++) - { - var nodeBuilder = _nodesToBuild[index]; - var nodeType = nodeBuilder.GetNodeType(); - - Dictionary groupedNodesTyped; - - if (groupNodesByType.TryGetValue(groupID, out groupedNodesTyped) == false) - { - groupedNodesTyped = new Dictionary(); - - groupNodesByType.Add(groupID, groupedNodesTyped); - }; - - BuildAndFillNode(entityID, groupedNodesTyped, nodeType, nodeBuilder); - } - - SetupImplementors(ref callBackstruct, entityID); - } - - internal void BuildNodes(int entityID, - Dictionary nodesByType, - ref BuildNodeCallbackStruct callBackstruct) - { - int count = _nodesToBuild.Count; - - for (int index = 0; index < count; index++) - { - var nodeBuilder = _nodesToBuild[index]; - var nodeType = nodeBuilder.GetNodeType(); - - BuildAndFillNode(entityID, nodesByType, nodeType, nodeBuilder); - } - - SetupImplementors(ref callBackstruct, entityID); - } - - void BuildAndFillNode(int entityID, Dictionary groupedNodesTyped, Type nodeType, INodeBuilder nodeBuilder) - { - ITypeSafeList nodes; - - var nodesPoolWillBeCreated = groupedNodesTyped.TryGetValue(nodeType, out nodes) == false; - var nodeObjectToFill = nodeBuilder.BuildNodeAndAddToList(ref nodes, entityID); - - if (nodesPoolWillBeCreated) - groupedNodesTyped.Add(nodeType, nodes); - - //the semantic of this code must still be improved - //but only classes can be filled, so I am aware - //it's a NodeWithID - if (nodeObjectToFill != null) - FillNode(nodeObjectToFill as NodeWithID); - } - - /// - /// if you want to avoid allocation in run-time, you can prebuild - /// EntityDescriptors and use them to build entities at different - /// times - /// - protected EntityDescriptor(INodeBuilder[] nodesToBuild) - { - _nodesToBuild = new FasterList(nodesToBuild); - } - protected EntityDescriptor(INodeBuilder[] nodesToBuild, - params object[] componentsImplementor):this(nodesToBuild) - { - ProcessImplementors(componentsImplementor); - } - - void ProcessImplementors(object[] implementors) - { - for (int index = 0; index < implementors.Length; index++) - { - var implementor = implementors[index]; - - if (implementor != null) - { - if (implementor is IRemoveEntityComponent) - _removingImplementors.Add(new DataStructures.WeakReference(implementor as IRemoveEntityComponent)); - if (implementor is IDisableEntityComponent) - _disablingImplementors.Add(new DataStructures.WeakReference(implementor as IDisableEntityComponent)); - if (implementor is IEnableEntityComponent) - _enablingImplementors.Add(new DataStructures.WeakReference(implementor as IEnableEntityComponent)); - - var interfaces = implementor.GetType().GetInterfaces(); - var weakReference = new DataStructures.WeakReference(implementor); - - for (int iindex = 0; iindex < interfaces.Length; iindex++) - { - var componentType = interfaces[iindex]; - - _implementorsByType[componentType] = weakReference; -#if DEBUG && !PROFILER - if (_implementorCounterByType.ContainsKey(componentType) == false) - _implementorCounterByType[componentType] = 1; - else - _implementorCounterByType[componentType]++; -#endif - } - } -#if DEBUG && !PROFILER - else - Utility.Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat(ToString())); -#endif - } - } - - void SetupImplementors( - ref BuildNodeCallbackStruct callBackstruct, - int entityID) - { - var RemoveEntity = callBackstruct.internalRemove; - var DisableEntity = callBackstruct.internalDisable; - var EnableEntity = callBackstruct.internalEnable; - - int removingImplementorsCount = _removingImplementors.Count; - if (removingImplementorsCount > 0) - { - Action removeEntityAction = () => RemoveEntity(_nodesToBuild, entityID); - - for (int index = 0; index < removingImplementorsCount; index++) - _removingImplementors[index].Target.removeEntity = removeEntityAction; - } - - int disablingImplementorsCount = _disablingImplementors.Count; - if (disablingImplementorsCount > 0) - { - Action disableEntityAction = () => DisableEntity(_nodesToBuild, entityID); - - for (int index = 0; index < disablingImplementorsCount; index++) - _disablingImplementors[index].Target.disableEntity = disableEntityAction; - } - - int enablingImplementorsCount = _enablingImplementors.Count; - if (enablingImplementorsCount > 0) - { - Action enableEntityAction = () => EnableEntity(_nodesToBuild, entityID); - - for (int index = 0; index < enablingImplementorsCount; index++) - _enablingImplementors[index].Target.enableEntity = enableEntityAction; - } - } - - void FillNode(TNode node) where TNode : NodeWithID - { - var fields = node.GetType().GetFields(BindingFlags.Public | - BindingFlags.Instance); - - for (int i = fields.Length - 1; i >= 0; --i) - { - var field = fields[i]; - Type fieldType = field.FieldType; - DataStructures.WeakReference component; - - if (_implementorsByType.TryGetValue(fieldType, out component) == false) - { - Exception e = - new Exception(NOT_FOUND_EXCEPTION + - field.FieldType.Name + " - Node: " + node.GetType().Name + - " - EntityDescriptor " + this); - - throw e; - } - else - field.SetValue(node, component.Target); - -#if DEBUG && !PROFILER - { - if (_implementorCounterByType[fieldType] != 1) - { - Utility.Console.LogError( - DUPLICATE_IMPLEMENTOR_ERROR.FastConcat("component: ", fieldType.ToString(), - " implementor: ", component.Target.ToString())); - } - } -#endif - - } - } - - readonly FasterList> _disablingImplementors = new FasterList>(); - readonly FasterList> _removingImplementors = new FasterList>(); - readonly FasterList> _enablingImplementors = new FasterList>(); - - readonly Dictionary> _implementorsByType = new Dictionary>(); -#if DEBUG && !PROFILER - readonly Dictionary _implementorCounterByType = new Dictionary(); -#endif - readonly FasterList _nodesToBuild; - - const string DUPLICATE_IMPLEMENTOR_ERROR = "the same component is implemented with more than one implementor. This is considered an error and MUST be fixed. "; - const string NULL_IMPLEMENTOR_ERROR = "Null implementor, are you using a wild GetComponents to fetch it? "; - const string NOT_FOUND_EXCEPTION = "Svelto.ECS: Implementor not found for a Node. Implementor Type: "; - } -} diff --git a/ECS/EntityDescriptorTemplate.cs b/ECS/EntityDescriptorTemplate.cs new file mode 100644 index 0000000..cceb87d --- /dev/null +++ b/ECS/EntityDescriptorTemplate.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; + +namespace Svelto.ECS +{ + public interface IEntityDescriptor + { + IEntityViewBuilder[] entityViewsToBuild { get; } + } + + static class EntityDescriptorTemplate where TType : IEntityDescriptor, new() + { + public static readonly EntityDescriptorInfo Default = new EntityDescriptorInfo(new TType()); + } + + public class EntityDescriptorInfo + { + public readonly IEntityDescriptor descriptor; + public readonly string name; + + public EntityDescriptorInfo(IEntityDescriptor entityDescriptor) + { + descriptor = entityDescriptor; + name = descriptor.ToString(); + } + } +} + +namespace Svelto.ECS.Internal +{ + static class EntityFactory + { + internal static void BuildGroupedEntityViews(int entityID, int groupID, + Dictionary> groupEntityViewsByType, + EntityDescriptorInfo entityViewsToBuildDescriptor, + object[] implementors) + { + var entityViewsToBuild = entityViewsToBuildDescriptor.descriptor.entityViewsToBuild; + int count = entityViewsToBuild.Length; + + RemoveEntityImplementor removeEntityImplementor = null; + + for (int index = 0; index < count; index++) + { + var entityViewBuilder = entityViewsToBuild[index]; + var entityViewType = entityViewBuilder.GetEntityViewType(); + + Dictionary groupedEntityViewsTyped; + + if (groupEntityViewsByType.TryGetValue(groupID, out groupedEntityViewsTyped) == false) + { + groupedEntityViewsTyped = new Dictionary(); + groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); + } + + var entityViewObjectToFill = + BuildEntityView(entityID, groupedEntityViewsTyped, entityViewType, entityViewBuilder); + + //the semantic of this code must still be improved + //but only classes can be filled, so I am aware + //it's a EntityViewWithID + if (entityViewObjectToFill != null) + { + if (removeEntityImplementor == null) + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.descriptor, groupID); + + FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, + entityViewsToBuildDescriptor.name); + } + } + } + + internal static void BuildEntityViews(int entityID, Dictionary entityViewsByType, + EntityDescriptorInfo entityViewsToBuildDescriptor, + object[] implementors) + { + var entityViewsToBuild = entityViewsToBuildDescriptor.descriptor.entityViewsToBuild; + int count = entityViewsToBuild.Length; + + RemoveEntityImplementor removeEntityImplementor = null; + + for (int index = 0; index < count; index++) + { + var entityViewBuilder = entityViewsToBuild[index]; + var entityViewType = entityViewBuilder.GetEntityViewType(); + + var entityViewObjectToFill = + BuildEntityView(entityID, entityViewsByType, entityViewType, entityViewBuilder); + + //the semantic of this code must still be improved + //but only classes can be filled, so I am aware + //it's a EntityView + if (entityViewObjectToFill != null) + { + if (removeEntityImplementor == null) + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.descriptor); + + FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, + entityViewsToBuildDescriptor.name); + } + } + } + + static IEntityView BuildEntityView(int entityID, Dictionary groupedEntityViewsTyped, + Type entityViewType, IEntityViewBuilder entityViewBuilderId) + { + ITypeSafeList entityViews; + + var entityViewsPoolWillBeCreated = + groupedEntityViewsTyped.TryGetValue(entityViewType, out entityViews) == false; + var entityViewObjectToFill = entityViewBuilderId.BuildEntityViewAndAddToList(ref entityViews, entityID); + + if (entityViewsPoolWillBeCreated) + groupedEntityViewsTyped.Add(entityViewType, entityViews); + + return entityViewObjectToFill as IEntityView; + } + + static void FillEntityView(EntityView entityView, object[] implementors, RemoveEntityImplementor removeEntity, + string entityDescriptorName) + { + for (int index = 0; index < implementors.Length; index++) + { + var implementor = implementors[index]; + + if (implementor != null) + { + var type = implementor.GetType(); + + Type[] interfaces; + if (_cachedTypes.TryGetValue(type, out interfaces) == false) + interfaces = _cachedTypes[type] = type.GetInterfaces(); + + for (int iindex = 0; iindex < interfaces.Length; iindex++) + { + var componentType = interfaces[iindex]; +#if DEBUG && !PROFILER + Tuple implementorHolder; + if (implementorsByType.TryGetValue(componentType, out implementorHolder) == true) + implementorHolder.item2++; + else +#endif + + implementorsByType[componentType] = new Tuple(implementor, 0); + } + } +#if DEBUG && !PROFILER + else + Utility.Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat(entityView.ToString())); +#endif + } + + int count; + + //Very efficent way to collect the fields of every EntityViewType + KeyValuePair>[] setters = + entityView.EntityViewBlazingFastReflection(out count); + + var removeEntityComponentType = typeof(IRemoveEntityComponent); + + for (int i = 0; i < count; i++) + { + var keyValuePair = setters[i]; + Type fieldType = keyValuePair.Key; + + if (fieldType == removeEntityComponentType) + { + keyValuePair.Value(entityView, removeEntity); + } + else + { + Tuple component; + + if (implementorsByType.TryGetValue(fieldType, out component) == false) + { + Exception e = new Exception(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name + " - EntityView: " + + entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); + + throw e; + } + + if (component.item2 > 1) + Utility.Console.LogError(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat( + "Component Type: ", fieldType.Name, " implementor: ", + component.item1.ToString()) + " - EntityView: " + + entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); + + keyValuePair.Value(entityView, component.item1); + } + + } + + implementorsByType.Clear(); + } + + struct Tuple + { + public T1 item1; + public T2 item2; + + public Tuple(T1 implementor, T2 v) + { + item1 = implementor; + item2 = v; + } + } + + //this is used to avoid newing a dictionary every time, but it's used locally only + static readonly Dictionary> implementorsByType = new Dictionary>(); + static Dictionary _cachedTypes = new Dictionary(); + + const string DUPLICATE_IMPLEMENTOR_ERROR = + "Svelto.ECS the same component is implemented with more than one implementor. This is considered an error and MUST be fixed."; + + const string NULL_IMPLEMENTOR_ERROR = + "Svelto.ECS Null implementor, please be careful about the implementors passed to avoid performance loss"; + + const string NOT_FOUND_EXCEPTION = "Svelto.ECS Implementor not found for an EntityView."; + } +} + diff --git a/ECS/Experimental/StructNodeCollections.cs b/ECS/Experimental/StructNodeCollections.cs new file mode 100644 index 0000000..e9e76e2 --- /dev/null +++ b/ECS/Experimental/StructNodeCollections.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Experimental.Internal; + +namespace Svelto.ECS.Experimental.Internal +{ + public interface IStructEntityViewEngine : IEngine + { + void CreateStructEntityViews(SharedStructEntityViewLists sharedStructEntityViewLists); + } + + public interface IGroupedStructEntityViewsEngine : IEngine + { + void CreateStructEntityViews(SharedGroupedStructEntityViewsLists sharedStructEntityViewLists); + } +} + +namespace Svelto.ECS.Experimental +{ + public interface IGroupedEntityView + { + int groupID { get; set; } + } + + /// + /// The engines can receive and store IEntityViews structs + /// Unboxing will happen during the Add, but the + /// data will then be stored and processed as stucts + /// + public interface IStructEntityViewEngine : IStructEntityViewEngine where T:struct, IEntityStruct + { } + + /// + /// same as above, but the entityViews are grouped by ID + /// usually the ID is the owner of the entityViews of that + /// group + /// + public interface IGroupedStructEntityViewsEngine : IGroupedStructEntityViewsEngine where T : struct, IGroupedEntityView + { + void Add(ref T entityView); + void Remove(ref T entityView); + } + + public sealed class StructEntityViews where T:struct, IEntityStruct + { + public T[] GetList(out int numberOfItems) + { + numberOfItems = _internalList.Count; + return _internalList.ToArrayFast(); + } + + public StructEntityViews(SharedStructEntityViewLists container) + { + _internalList = SharedStructEntityViewLists.NoVirt.GetList(container); + } + + public void Add(T entityView) + { + T convert = (T)entityView; + + _internalList.Add(convert); + } + + readonly FasterList _internalList; + } + + public struct StructGroupEntityViews + where T : struct, IEntityView + { + public StructGroupEntityViews(SharedGroupedStructEntityViewsLists container) + { + _container = container; + indices = new Dictionary(); + } + + public void Add(int groupID, T entityView) + { + T convert = (T)entityView; + + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + indices[entityView.ID] = fasterList.Count; + + fasterList.Add(convert); + } + + public void Remove(int groupID, T entityView) + { + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + var index = indices[entityView.ID]; + indices.Remove(entityView.ID); + + if (fasterList.UnorderedRemoveAt(index)) + indices[fasterList[index].ID] = index; + } + + public T[] GetList(int groupID, out int numberOfItems) + { + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + + return FasterList.NoVirt.ToArrayFast(fasterList, out numberOfItems); + } + + readonly SharedGroupedStructEntityViewsLists _container; + readonly Dictionary indices; + } + + public class SharedStructEntityViewLists + { + internal SharedStructEntityViewLists() + { + _collection = new Dictionary(); + } + + internal static class NoVirt + { + internal static FasterList GetList(SharedStructEntityViewLists obj) where T : struct + { + IFasterList list; + if (obj._collection.TryGetValue(typeof(T), out list)) + { + return list as FasterList; + } + + list = new FasterList(); + + obj._collection.Add(typeof(T), list); + + return (FasterList)list; + } + } + + readonly Dictionary _collection; + } + + public class SharedGroupedStructEntityViewsLists + { + internal SharedGroupedStructEntityViewsLists() + { + _collection = new Dictionary>(); + } + + internal static class NoVirt + { + internal static IFasterList GetList(SharedGroupedStructEntityViewsLists list, int groupID) where T : struct + { + Dictionary dic = GetGroup(list); + IFasterList localList; + + if (dic.TryGetValue(groupID, out localList)) + return localList; + + localList = new FasterList(); + dic.Add(groupID, localList); + + return localList; + } + + internal static Dictionary GetGroup(SharedGroupedStructEntityViewsLists list) where T : struct + { + Dictionary dic; + + if (list._collection.TryGetValue(typeof(T), out dic)) + { + return dic; + } + + dic = new Dictionary(); + + list._collection.Add(typeof(T), dic); + + return dic; + } + } + + readonly Dictionary> _collection; + } +} \ No newline at end of file diff --git a/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs b/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs new file mode 100644 index 0000000..9a21176 --- /dev/null +++ b/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs @@ -0,0 +1,14 @@ +#if UNITY_5 || UNITY_5_3_OR_NEWER +namespace Svelto.ECS +{ + public class GenericEntityDescriptorHolder: + UnityEngine.MonoBehaviour, IEntityDescriptorHolder + where T: class, IEntityDescriptor, new() + { + public EntityDescriptorInfo RetrieveDescriptor() + { + return EntityDescriptorTemplate.Default; + } + } +} +#endif \ No newline at end of file diff --git a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs b/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs index 5e0d363..8a6c173 100644 --- a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs +++ b/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs @@ -1,30 +1,30 @@ #if UNITY_5 || UNITY_5_3_OR_NEWER -using System; using System.Collections; +using Svelto.WeakEvents; using UnityEngine; -namespace Svelto.ECS.NodeSchedulers +namespace Svelto.ECS.Schedulers { - //The NodeSubmissionScheduler has been introduced to make - //the node submission logic platform indipendent. + //The EntityViewSubmissionScheduler has been introduced to make + //the entityView submission logic platform indipendent. //Please don't be tempted to create your own submission to //adapt to your game level code design. For example, //you may be tempted to write a submission logic to submit - //the nodes immediatly just because convenient for your game + //the entityViews immediatly just because convenient for your game //logic. This is not how it works. - public class UnitySumbmissionNodeScheduler : NodeSubmissionScheduler + public class UnitySumbmissionEntityViewScheduler : EntityViewSubmissionScheduler { - public UnitySumbmissionNodeScheduler() + public UnitySumbmissionEntityViewScheduler() { GameObject go = new GameObject("ECSScheduler"); _scheduler = go.AddComponent(); } - public override void Schedule(Action submitNodes) + public override void Schedule(WeakAction submitEntityViews) { - _scheduler.OnTick += submitNodes; + _scheduler.OnTick = submitEntityViews; } class Scheduler : MonoBehaviour @@ -35,11 +35,15 @@ namespace Svelto.ECS.NodeSchedulers { yield return _wait; - OnTick(); + if (OnTick.IsValid) + OnTick.Invoke(); + else + yield break; } } - internal Action OnTick; + internal WeakAction OnTick; + WaitForEndOfFrame _wait = new WaitForEndOfFrame(); } diff --git a/ECS/GenericEntityDescriptor.cs b/ECS/GenericEntityDescriptor.cs index f0c87ff..da643e9 100644 --- a/ECS/GenericEntityDescriptor.cs +++ b/ECS/GenericEntityDescriptor.cs @@ -1,258 +1,110 @@ +using System.Runtime.InteropServices; + namespace Svelto.ECS { - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() + public class GenericEntityDescriptor:IEntityDescriptor where T : EntityView, new() { static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] { new NodeBuilder() }; + entityViewBuilders = new IEntityViewBuilder[] { new EntityViewBuilder() }; } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - { - static GenericEntityDescriptor() + + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder() - }; + get { return entityViewBuilders; } } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; + public static readonly IEntityViewBuilder[] entityViewBuilders; + } - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() { static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder()}; } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; - } - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() - where W : NodeWithID, new() - { - static GenericEntityDescriptor() + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; + get { return entityViewBuilders; } } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; + + public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() - where W : NodeWithID, new() - where X : NodeWithID, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() { static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() - where W : NodeWithID, new() - where X : NodeWithID, new() - where Y : NodeWithID, new() - { - static GenericEntityDescriptor() + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; + get { return entityViewBuilders; } } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; + + public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() { - static GenericMixedEntityDescriptor() + static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] - { - new T(), - }; + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - { - static GenericMixedEntityDescriptor() + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - }; + get { return entityViewBuilders; } } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; + + public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() + where X : EntityView, new() { - static GenericMixedEntityDescriptor() + static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V() - }; + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; - } - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() - where W : INodeBuilder, new() - { - static GenericMixedEntityDescriptor() + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V(), - new W() - }; + get { return entityViewBuilders; } } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; + + public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() - where W : INodeBuilder, new() - where X : INodeBuilder, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() + where X : EntityView, new() + where Y : EntityView, new() { - static GenericMixedEntityDescriptor() + static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V(), - new W(), - new X() - }; + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() - where W : INodeBuilder, new() - where X : INodeBuilder, new() - where Y : INodeBuilder, new() - { - static GenericMixedEntityDescriptor() + public IEntityViewBuilder[] entityViewsToBuild { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V(), - new W(), - new X(), - new Y() - }; + get { return entityViewBuilders; } } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; + + public static readonly IEntityViewBuilder[] entityViewBuilders; } } diff --git a/ECS/GenericEntityDescriptorHolder.cs b/ECS/GenericEntityDescriptorHolder.cs deleted file mode 100644 index 05c8ac5..0000000 --- a/ECS/GenericEntityDescriptorHolder.cs +++ /dev/null @@ -1,31 +0,0 @@ -#if UNITY_5 || UNITY_5_3_OR_NEWER -using System; - -namespace Svelto.ECS -{ - public class GenericEntityDescriptorHolder: - UnityEngine.MonoBehaviour, IEntityDescriptorHolder where T:EntityDescriptor - { - public EntityDescriptor BuildDescriptorType(object[] externalImplentors) - { - I[] implementors; - - if (externalImplentors != null) - { - I[] baseImplentors = gameObject.GetComponents(); - - implementors = new I[externalImplentors.Length + baseImplentors.Length]; - - Array.Copy(baseImplentors, implementors, baseImplentors.Length); - Array.Copy(externalImplentors, 0, implementors, baseImplentors.Length, externalImplentors.Length); - } - else - { - implementors = gameObject.GetComponents(); - } - - return (T)Activator.CreateInstance(typeof(T), implementors); - } - } -} -#endif \ No newline at end of file diff --git a/ECS/ICallBackOnAddEngine.cs b/ECS/ICallBackOnAddEngine.cs deleted file mode 100644 index e77bf6a..0000000 --- a/ECS/ICallBackOnAddEngine.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Svelto.ECS -{ - public interface ICallBackOnAddEngine - { - void Ready(); - } -} diff --git a/ECS/IEngine.cs b/ECS/IEngine.cs index bb4c012..9fb5bec 100644 --- a/ECS/IEngine.cs +++ b/ECS/IEngine.cs @@ -1,36 +1,9 @@ -using Rewired.Utils; -using Svelto.ECS.Internal; - namespace Svelto.ECS.Internal { - public interface IStructNodeEngine : IEngine - { - void CreateStructNodes(SharedStructNodeLists sharedStructNodeLists); - } - - public interface IGroupedStructNodesEngine : IEngine + public interface IHandleEntityViewEngine : IEngine { - void CreateStructNodes(SharedGroupedStructNodesLists sharedStructNodeLists); - } - - public interface IActivableNodeEngine : IEngine - { - void Enable(NodeWithID node); - void Disable(NodeWithID node); - } - - public interface INodeEngine : IEngine - { - void Add(NodeWithID node); - void Remove(NodeWithID node); - } -} - -namespace Svelto.ECS.Legacy -{ - public interface INodesEngine : INodeEngine - { - System.Type[] AcceptedNodes(); + void Add(IEntityView entityView); + void Remove(IEntityView entityView); } } @@ -38,32 +11,17 @@ namespace Svelto.ECS { public interface IEngine {} - - public interface IActivableNodeEngine : IActivableNodeEngine where TNodeType : INode - { } - - public interface IQueryableNodeEngine:IEngine +#if EXPERIMENTAL + public interface IHandleActivableEntityEngine : IEngine { - IEngineNodeDB nodesDB { set; } + void Enable(EntityView entityView); + void Disable(EntityView entityView); } - - /// - /// The engines can receive and store INodes structs - /// Unboxing will happen during the Add, but the - /// data will then be stored and processed as stucts - /// - public interface IStructNodeEngine : IStructNodeEngine where T:struct, IStructNodeWithID - { } - - /// - /// same as above, but the nodes are grouped by ID - /// usually the ID is the owner of the nodes of that - /// group - /// - public interface IGroupedStructNodesEngine : IGroupedStructNodesEngine where T : struct, IGroupedNode +#endif + public interface IQueryingEntityViewEngine : IEngine { - void Add(ref T node); - void Remove(ref T node); + IEngineEntityViewDB entityViewsDB { set; } + + void Ready(); } } - diff --git a/ECS/IEngineNodeDB.cs b/ECS/IEngineNodeDB.cs index 05a2c6f..ddbf011 100644 --- a/ECS/IEngineNodeDB.cs +++ b/ECS/IEngineNodeDB.cs @@ -2,21 +2,21 @@ using Svelto.DataStructures; namespace Svelto.ECS { - public interface IEngineNodeDB + public interface IEngineEntityViewDB { - FasterReadOnlyList QueryNodes(); - FasterReadOnlyList QueryMetaNodes(); - FasterReadOnlyList QueryGroupedNodes(int group); + FasterReadOnlyList QueryEntityViews() where T:EntityView, new(); + FasterReadOnlyList QueryMetaEntityViews() where T: EntityView, new(); + FasterReadOnlyList QueryGroupedEntityViews(int group) where T: EntityView, new(); - T[] QueryNodesAsArray(out int count) where T:struct; + T[] QueryEntityViewsAsArray(out int count) where T: IEntityView; + T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T: IEntityView; - ReadOnlyDictionary QueryIndexableNodes() where T:NodeWithID; - - bool TryQueryNode(int ID, out T node) where T:NodeWithID; - T QueryNode(int ID) where T:NodeWithID; + ReadOnlyDictionary QueryIndexableEntityViews() where T: IEntityView; + bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView; + T QueryEntityView(int ID) where T: IEntityView; - bool TryQueryMetaNode(int metaEntityID, out T node) where T:NodeWithID; - T QueryMetaNode(int metaEntityID) where T:NodeWithID; + bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T: EntityView, new(); + T QueryMetaEntityView(int metaEntityID) where T: EntityView, new(); } } diff --git a/ECS/IEnginesInterfaces.cs b/ECS/IEnginesInterfaces.cs new file mode 100644 index 0000000..05ed50c --- /dev/null +++ b/ECS/IEnginesInterfaces.cs @@ -0,0 +1,31 @@ +namespace Svelto.ECS +{ + public interface IEntityFactory + { + void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new(); + void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null); + + void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T:IEntityDescriptor, new(); + + void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new(); + void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null); + } + + public interface IEntityFunctions + { + void RemoveEntity(int entityID, IRemoveEntityComponent template); + + void RemoveEntity(int entityID) where T:IEntityDescriptor, new(); + + void RemoveMetaEntity(int metaEntityID) where T:IEntityDescriptor, new(); + + void RemoveEntityFromGroup(int entityID, int groupID) where T:IEntityDescriptor, new(); +#if EXPERIMENTAL + void SetEntityActiveState(int entityID, bool state) where T:IEntityDescriptor, new(); + + void SetMetaEntityActiveState(int metaEntityID, bool state) where T:IEntityDescriptor, new(); + + void SetEntityInGroupActiveState(int entityID, int group, bool state) where T:IEntityDescriptor, new(); +#endif + } +} diff --git a/ECS/IEnginesRoot.cs b/ECS/IEnginesRoot.cs deleted file mode 100644 index 14f5957..0000000 --- a/ECS/IEnginesRoot.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Svelto.ECS -{ - public interface IEnginesRoot - { - void AddEngine(IEngine engine); - } - - public interface IEntityFactory - { - void BuildEntity(int ID, EntityDescriptor ED); - - void BuildMetaEntity(int metaEntityID, EntityDescriptor ED); - - void BuildEntityInGroup(int entityID, int groupID, EntityDescriptor ED); - } -} diff --git a/ECS/IEntityDescriptorHolder.cs b/ECS/IEntityDescriptorHolder.cs index 2c70278..c2a7515 100644 --- a/ECS/IEntityDescriptorHolder.cs +++ b/ECS/IEntityDescriptorHolder.cs @@ -1,11 +1,7 @@ namespace Svelto.ECS { - /// - /// please use [DisallowMultipleComponent] in your monobehaviours that implement IEntityDescriptorHolder - /// public interface IEntityDescriptorHolder { - //I must find a nicer solution for the extraImplentors - EntityDescriptor BuildDescriptorType(object[] extraImplentors = null); + EntityDescriptorInfo RetrieveDescriptor(); } } diff --git a/ECS/INode.cs b/ECS/INode.cs index 4876a86..445781c 100644 --- a/ECS/INode.cs +++ b/ECS/INode.cs @@ -1,29 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Svelto.DataStructures; +using Svelto.Utilities; + namespace Svelto.ECS -{ - public interface INode +{ + public interface IEntityView { int ID { get; } } - public interface IGroupedNode + public interface IEntityStruct:IEntityView { - int groupID { get; set; } + new int ID { set; } } - - public interface IStructNodeWithID : INode + + public abstract class EntityView : IEntityView { - new int ID { get; set; } + public int ID { get { return _ID; } } + + abstract internal KeyValuePair>[] + EntityViewBlazingFastReflection(out int count); + + protected int _ID; } - public class NodeWithID: INode + public class EntityView: EntityView where T: EntityView { - public static TNodeType BuildNode(int ID) where TNodeType: NodeWithID, new() + internal static TEntityViewType BuildEntityView(int ID) where TEntityViewType: EntityView, new() { - return new TNodeType { _ID = ID }; + if (FieldCache.list.Count == 0) + { + var type = typeof(TEntityViewType); + + var fields = type.GetFields(BindingFlags.Public | + BindingFlags.Instance); + + for (int i = fields.Length - 1; i >= 0; --i) + { + var field = fields[i]; + + Action setter = FastInvoke.MakeSetter(field); + + FieldCache.Add(new KeyValuePair>(field.FieldType, setter)); + } + } + + return new TEntityViewType { _ID = ID }; } - public int ID { get { return _ID; } } + override internal KeyValuePair>[] + EntityViewBlazingFastReflection(out int count) + { + return FasterList>>.NoVirt.ToArrayFast(FieldCache.list, out count); + } - protected int _ID; + static class FieldCache + { + internal static void Add(KeyValuePair> setter) + { + list.Add(setter); + } + + internal static readonly FasterList>> list = new FasterList>>(); + } } } + diff --git a/ECS/IRemoveEntityComponent.cs b/ECS/IRemoveEntityComponent.cs deleted file mode 100644 index 5a3ee3b..0000000 --- a/ECS/IRemoveEntityComponent.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace Svelto.ECS -{ - public interface IRemoveEntityComponent - { - Action removeEntity { get; set; } - } - - public interface IDisableEntityComponent - { - Action disableEntity { get; set; } - } - - public interface IEnableEntityComponent - { - Action enableEntity { get; set; } - } -} diff --git a/ECS/MixedEntityDescriptor.cs b/ECS/MixedEntityDescriptor.cs new file mode 100644 index 0000000..f91ad54 --- /dev/null +++ b/ECS/MixedEntityDescriptor.cs @@ -0,0 +1,107 @@ +namespace Svelto.ECS +{ + public class MixedEntityDescriptor:IEntityDescriptor where T : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + where X : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + where X : class, IEntityViewBuilder, new() + where Y : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X(), new Y()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } +} diff --git a/ECS/MultiNodesEngine.cs b/ECS/MultiNodesEngine.cs index 3559310..2ba4856 100644 --- a/ECS/MultiNodesEngine.cs +++ b/ECS/MultiNodesEngine.cs @@ -1,85 +1,87 @@ -using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS.Internal { - public abstract class MultiNodesEngine:INodeEngine where T:NodeWithID + public abstract class MultiEntityViewsEngine:IHandleEntityViewEngine where T:EntityView, new() { - protected abstract void Add(T node); - protected abstract void Remove(T node); + protected abstract void Add(T entityView); + protected abstract void Remove(T entityView); - public virtual void Add(NodeWithID node) + public virtual void Add(IEntityView entityView) { - Add((T) node); + Add((T) entityView); } - public virtual void Remove(NodeWithID node) + public virtual void Remove(IEntityView entityView) { - Remove((T) node); + Remove((T) entityView); } } } namespace Svelto.ECS { - public abstract class MultiNodesEngine : MultiNodesEngine - where T:NodeWithID where U:NodeWithID + public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine + where T:EntityView, new() + where U:EntityView, new() { - protected abstract void Add(U node); - protected abstract void Remove(U node); + protected abstract void Add(U entityView); + protected abstract void Remove(U entityView); - public override void Add(NodeWithID node) + public override void Add(IEntityView entityView) { - var castedNode = node as U; - if (castedNode != null) + var castedEntityView = entityView as U; + if (castedEntityView != null) { - Add(castedNode); + Add(castedEntityView); } else { - base.Add(node); + base.Add(entityView); } } - public override void Remove(NodeWithID node) + public override void Remove(IEntityView entityView) { - if (node is U) + if (entityView is U) { - Remove((U) node); + Remove((U) entityView); } else { - base.Remove(node); + base.Remove(entityView); } } } - public abstract class MultiNodesEngine : MultiNodesEngine - where T: NodeWithID where U : NodeWithID where V:NodeWithID + public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine + where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() { - protected abstract void Add(V node); - protected abstract void Remove(V node); + protected abstract void Add(V entityView); + protected abstract void Remove(V entityView); - public override void Add(NodeWithID node) + public override void Add(IEntityView entityView) { - var castedNode = node as V; - if (castedNode != null) + var castedEntityView = entityView as V; + if (castedEntityView != null) { - Add(castedNode); + Add(castedEntityView); } else - base.Add(node); + base.Add(entityView); } - public override void Remove(NodeWithID node) + public override void Remove(IEntityView entityView) { - var castedNode = node as V; - if (castedNode != null) + var castedEntityView = entityView as V; + if (castedEntityView != null) { - Remove(castedNode); + Remove(castedEntityView); } else - base.Remove(node); + base.Remove(entityView); } } } \ No newline at end of file diff --git a/ECS/NodeBuilder.cs b/ECS/NodeBuilder.cs index 70deb96..7b4db4b 100644 --- a/ECS/NodeBuilder.cs +++ b/ECS/NodeBuilder.cs @@ -1,58 +1,61 @@ using System; -using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS { - public interface INodeBuilder + public interface IEntityViewBuilder { - INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID); + IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID); - Type GetNodeType(); + Type GetEntityViewType(); } - public class NodeBuilder : INodeBuilder where NodeType : NodeWithID, new() + public class EntityViewBuilder : IEntityViewBuilder where EntityViewType : EntityView, new() { - public INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID) + public IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID) { if (list == null) - list = new TypeSafeFasterListForECSForClasses(); + list = new TypeSafeFasterListForECSForClasses(); - var castedList = list as TypeSafeFasterListForECSForClasses; + var castedList = list as TypeSafeFasterListForECSForClasses; - var node = NodeWithID.BuildNode(entityID); + var entityView = EntityView.BuildEntityView(entityID); - castedList.Add(node); + castedList.Add(entityView); - return node; + return entityView; } - public Type GetNodeType() + public Type GetEntityViewType() { - return typeof(NodeType); + return _entityViewType; } + + readonly Type _entityViewType = typeof(EntityViewType); } - public class StructNodeBuilder : INodeBuilder where NodeType : struct, IStructNodeWithID + public class EntityStructBuilder : IEntityViewBuilder where EntityViewType : struct, IEntityStruct { - public INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID) + public IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID) { - var node = default(NodeType); - node.ID = entityID; + var entityView = default(EntityViewType); + entityView.ID = entityID; if (list == null) - list = new TypeSafeFasterListForECSForStructs(); + list = new TypeSafeFasterListForECSForStructs(); - var castedList = list as TypeSafeFasterListForECSForStructs; + var castedList = list as TypeSafeFasterListForECSForStructs; - castedList.Add(node); + castedList.Add(entityView); return null; } - public Type GetNodeType() + public Type GetEntityViewType() { - return typeof(NodeType); + return _entityViewType; } - } + + readonly Type _entityViewType = typeof(EntityViewType); + } } \ No newline at end of file diff --git a/ECS/NodeSubmissionScheduler.cs b/ECS/NodeSubmissionScheduler.cs index dc86bf2..bc62758 100644 --- a/ECS/NodeSubmissionScheduler.cs +++ b/ECS/NodeSubmissionScheduler.cs @@ -1,9 +1,9 @@ -using System; +using Svelto.WeakEvents; -namespace Svelto.ECS.NodeSchedulers +namespace Svelto.ECS.Schedulers { - public abstract class NodeSubmissionScheduler + public abstract class EntityViewSubmissionScheduler { - abstract public void Schedule(Action submitNodes); + abstract public void Schedule(WeakAction submitEntityViews); } } \ No newline at end of file diff --git a/ECS/Profiler/EngineInfo.cs b/ECS/Profiler/EngineInfo.cs index ceffef9..c8fd453 100644 --- a/ECS/Profiler/EngineInfo.cs +++ b/ECS/Profiler/EngineInfo.cs @@ -33,12 +33,12 @@ namespace Svelto.ECS.Profiler double _accumulatedAddDuration; double _minAddDuration; double _maxAddDuration; - int _nodesAddedCount; + int _entityViewsAddedCount; double _accumulatedRemoveDuration; double _minRemoveDuration; double _maxRemoveDuration; - int _nodesRemovedCount; + int _entityViewsRemovedCount; public IEngine engine { get { return _engine; } } public string engineName { get { return _engineName; } } @@ -56,8 +56,8 @@ namespace Svelto.ECS.Profiler public double maxRemoveDuration { get { return _maxRemoveDuration; } } public double maxUpdateDuration { get { return _maxUpdateDuration[(int)UpdateType.Update]; } } - public double averageAddDuration { get { return _nodesAddedCount == 0 ? 0 : _accumulatedAddDuration / _nodesAddedCount; } } - public double averageRemoveDuration { get { return _nodesRemovedCount == 0 ? 0 : _accumulatedRemoveDuration / _nodesRemovedCount; } } + public double averageAddDuration { get { return _entityViewsAddedCount == 0 ? 0 : _accumulatedAddDuration / _entityViewsAddedCount; } } + public double averageRemoveDuration { get { return _entityViewsRemovedCount == 0 ? 0 : _accumulatedRemoveDuration / _entityViewsRemovedCount; } } public double averageUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.Update].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.Update] / _updateFrameTimes[(int)UpdateType.Update].Count; } } public double averageLateUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.LateUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.LateUpdate] / _updateFrameTimes[(int)UpdateType.LateUpdate].Count; } } public double averageFixedUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.FixedUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.FixedUpdate] / _updateFrameTimes[(int)UpdateType.FixedUpdate].Count; } } @@ -126,7 +126,7 @@ namespace Svelto.ECS.Profiler _maxAddDuration = duration; } _accumulatedAddDuration += duration; - _nodesAddedCount += 1; + _entityViewsAddedCount += 1; } public void AddRemoveDuration(double duration) @@ -140,7 +140,7 @@ namespace Svelto.ECS.Profiler _maxRemoveDuration = duration; } _accumulatedRemoveDuration += duration; - _nodesRemovedCount += 1; + _entityViewsRemovedCount += 1; } public void ResetDurations() @@ -156,12 +156,12 @@ namespace Svelto.ECS.Profiler _accumulatedAddDuration = 0; _minAddDuration = 0; _maxAddDuration = 0; - _nodesAddedCount = 0; + _entityViewsAddedCount = 0; _accumulatedRemoveDuration = 0; _minRemoveDuration = 0; _maxRemoveDuration = 0; - _nodesRemovedCount = 0; + _entityViewsRemovedCount = 0; } } } diff --git a/ECS/Profiler/EngineProfiler.cs b/ECS/Profiler/EngineProfiler.cs index 14ed4c7..5f0765d 100644 --- a/ECS/Profiler/EngineProfiler.cs +++ b/ECS/Profiler/EngineProfiler.cs @@ -12,27 +12,27 @@ namespace Svelto.ECS.Profiler { static readonly Stopwatch _stopwatch = new Stopwatch(); - public static void MonitorAddDuration(Action addingFunc, INodeEngine engine, INode node) + public static void MonitorAddDuration(Action addingFunc, IHandleEntityViewEngine engine, IEntityView entityView) { EngineInfo info; if (engineInfos.TryGetValue(engine.GetType(), out info)) { _stopwatch.Start(); - addingFunc(engine, node); + addingFunc(engine, entityView); _stopwatch.Reset(); info.AddAddDuration(_stopwatch.Elapsed.TotalMilliseconds); } } - public static void MonitorRemoveDuration(Action removeFunc, INodeEngine engine, NodeWithID node) + public static void MonitorRemoveDuration(Action removeFunc, IHandleEntityViewEngine engine, IEntityView entityView) { EngineInfo info; if (engineInfos.TryGetValue(engine.GetType(), out info)) { _stopwatch.Start(); - removeFunc(engine, node); - engine.Remove(node); + removeFunc(engine, entityView); + engine.Remove(entityView); _stopwatch.Reset(); info.AddRemoveDuration(_stopwatch.Elapsed.TotalMilliseconds); diff --git a/ECS/RemoveEntityImplementor.cs b/ECS/RemoveEntityImplementor.cs new file mode 100644 index 0000000..30f74c5 --- /dev/null +++ b/ECS/RemoveEntityImplementor.cs @@ -0,0 +1,42 @@ +namespace Svelto.ECS.Internal +{ + sealed class RemoveEntityImplementor : IRemoveEntityComponent + { + public RemoveEntityImplementor(IEntityDescriptor descriptor, int groupID) : this(descriptor) + { + removeEntityInfo = new RemoveEntityInfo(descriptor, groupID); + } + + internal RemoveEntityImplementor(IEntityDescriptor descriptor) + { + removeEntityInfo = new RemoveEntityInfo(descriptor); + } + + internal RemoveEntityInfo removeEntityInfo; + } +} + +namespace Svelto.ECS +{ + public interface IRemoveEntityComponent + {} + + public struct RemoveEntityInfo + { + readonly public IEntityDescriptor descriptor; + readonly public int groupID; + readonly public bool isInAGroup; + + public RemoveEntityInfo(IEntityDescriptor descriptor) : this() + { + this.descriptor = descriptor; + } + + public RemoveEntityInfo(IEntityDescriptor descriptor, int groupID) + { + this.descriptor = descriptor; + this.groupID = groupID; + isInAGroup = true; + } + } +} diff --git a/ECS/SingleNodeEngine.cs b/ECS/SingleNodeEngine.cs index 82b6727..a3ac1ad 100644 --- a/ECS/SingleNodeEngine.cs +++ b/ECS/SingleNodeEngine.cs @@ -2,19 +2,19 @@ using Svelto.ECS.Internal; namespace Svelto.ECS { - public abstract class SingleNodeEngine : INodeEngine where T:NodeWithID + public abstract class SingleEntityViewEngine : IHandleEntityViewEngine where T:EntityView, new() { - public void Add(NodeWithID node) + public void Add(IEntityView entityView) { - Add((T)node); //when byref returns will be vailable, this should be passed by reference, not copy! + Add((T)entityView); //when byref returns will be vailable, this should be passed by reference, not copy! } - public void Remove(NodeWithID node) + public void Remove(IEntityView entityView) { - Remove((T)node); + Remove((T)entityView); } - protected abstract void Add(T node); - protected abstract void Remove(T node); + protected abstract void Add(T entityView); + protected abstract void Remove(T entityView); } } diff --git a/ECS/StructNodes.cs b/ECS/StructNodes.cs deleted file mode 100644 index 0ccaf94..0000000 --- a/ECS/StructNodes.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System; -using System.Collections.Generic; -using Svelto.DataStructures; -using Svelto.ECS.Internal; - -namespace Svelto.ECS -{ - public sealed class StructNodes where T:struct, IStructNodeWithID - { - public T[] GetList(out int numberOfItems) - { - numberOfItems = _internalList.Count; - return _internalList.ToArrayFast(); - } - - public StructNodes(SharedStructNodeLists container) - { - _internalList = SharedStructNodeLists.NoVirt.GetList(container); - } - - public void Add(T node) - { - T convert = (T)node; - - _internalList.Add(convert); - } - - readonly FasterList _internalList; - } - - public struct StructGroupNodes - where T : struct, IStructNodeWithID - { - public StructGroupNodes(SharedGroupedStructNodesLists container) - { - _container = container; - indices = new Dictionary(); - } - - public void Add(int groupID, T node) - { - T convert = (T)node; - - var fasterList = (SharedGroupedStructNodesLists.NoVirt.GetList(_container, groupID) as FasterList); - indices[node.ID] = fasterList.Count; - - fasterList.Add(convert); - } - - public void Remove(int groupID, T node) - { - var fasterList = (SharedGroupedStructNodesLists.NoVirt.GetList(_container, groupID) as FasterList); - var index = indices[node.ID]; - indices.Remove(node.ID); - - if (fasterList.UnorderedRemoveAt(index)) - indices[fasterList[index].ID] = index; - } - - public T[] GetList(int groupID, out int numberOfItems) - { - var fasterList = (SharedGroupedStructNodesLists.NoVirt.GetList(_container, groupID) as FasterList); - - return FasterList.NoVirt.ToArrayFast(fasterList, out numberOfItems); - } - - readonly SharedGroupedStructNodesLists _container; - readonly Dictionary indices; - } - - public class SharedStructNodeLists - { - internal SharedStructNodeLists() - { - _collection = new Dictionary(); - } - - internal static class NoVirt - { - internal static FasterList GetList(SharedStructNodeLists obj) where T : struct - { - IFasterList list; - if (obj._collection.TryGetValue(typeof(T), out list)) - { - return list as FasterList; - } - - list = new FasterList(); - - obj._collection.Add(typeof(T), list); - - return (FasterList)list; - } - } - - readonly Dictionary _collection; - } - - public class SharedGroupedStructNodesLists - { - internal SharedGroupedStructNodesLists() - { - _collection = new Dictionary>(); - } - - internal static class NoVirt - { - internal static IFasterList GetList(SharedGroupedStructNodesLists list, int groupID) where T : struct - { - Dictionary dic = GetGroup(list); - IFasterList localList; - - if (dic.TryGetValue(groupID, out localList)) - return localList; - - localList = new FasterList(); - dic.Add(groupID, localList); - - return localList; - } - - internal static Dictionary GetGroup(SharedGroupedStructNodesLists list) where T : struct - { - Dictionary dic; - - if (list._collection.TryGetValue(typeof(T), out dic)) - { - return dic; - } - - dic = new Dictionary(); - - list._collection.Add(typeof(T), dic); - - return dic; - } - } - - readonly Dictionary> _collection; - } -} \ No newline at end of file diff --git a/ECS/note.txt b/ECS/note.txt index c041193..33ca04c 100644 --- a/ECS/note.txt +++ b/ECS/note.txt @@ -27,7 +27,7 @@ producer/consumer has the inconvienent to force check the number of jobs availab Engine can't be removed, they can only be disabled, but the logic of disabling must be handled by the engine itself -Should components have just one element? Should engines use just nodes? Components are ditacted by the entities and Nodes by the engines +Should components have just one element? Should engines use just entityViews? Components are ditacted by the entities and EntityViews by the engines http://thelinuxlich.github.io/artemis_CSharp/ @@ -42,7 +42,7 @@ http://entity-systems.wikidot.com/es-articles http://www.ashframework.org/ -it's very important to give a namespace to the engines. In this way it's impossible to create semantically wrong nodes (PlayerNode Vs TargetNode) +it's very important to give a namespace to the engines. In this way it's impossible to create semantically wrong entityViews (PlayerEntityView Vs TargetEntityView) ToDo: diff --git a/Utilities/FastInvoke.cs b/Utilities/FastInvoke.cs new file mode 100644 index 0000000..48e72f5 --- /dev/null +++ b/Utilities/FastInvoke.cs @@ -0,0 +1,24 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace Svelto.Utilities +{ + //https://stackoverflow.com/questions/321650/how-do-i-set-a-field-value-in-an-c-sharp-expression-tree/321686#321686 + public static class FastInvoke where T : class + { + public static Action MakeSetter(FieldInfo field) + { + DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] {typeof(T), typeof(object)}); + ILGenerator cg = m.GetILGenerator(); + + // arg0. = arg1 + cg.Emit(OpCodes.Ldarg_0); + cg.Emit(OpCodes.Ldarg_1); + cg.Emit(OpCodes.Stfld, field); + cg.Emit(OpCodes.Ret); + + return (Action) m.CreateDelegate(typeof(Action));; + } + } +} \ No newline at end of file diff --git a/Utilities/Murmur3.cs b/Utilities/Murmur3.cs index 6e83e68..9a0d5d7 100644 --- a/Utilities/Murmur3.cs +++ b/Utilities/Murmur3.cs @@ -1,5 +1,4 @@ using System; -using System.IO; /// /// Murmur hash. diff --git a/Utilities/NetFXCoreWrappers.cs b/Utilities/NetFXCoreWrappers.cs index b172b0b..cde69f8 100644 --- a/Utilities/NetFXCoreWrappers.cs +++ b/Utilities/NetFXCoreWrappers.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; -using System.Threading; using Svelto.DataStructures; namespace Svelto.Utilities diff --git a/WeakEvents/WeakAction.cs b/WeakEvents/WeakAction.cs index 042bf62..e7b6470 100644 --- a/WeakEvents/WeakAction.cs +++ b/WeakEvents/WeakAction.cs @@ -1,6 +1,5 @@ using System; using System.Reflection; -using System.Runtime.CompilerServices; using Svelto.Utilities; namespace Svelto.WeakEvents diff --git a/WeakEvents/WeakActionStruct.cs b/WeakEvents/WeakActionStruct.cs index a073cea..0df2e54 100644 --- a/WeakEvents/WeakActionStruct.cs +++ b/WeakEvents/WeakActionStruct.cs @@ -1,6 +1,5 @@ using System; using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Svelto.Utilities; diff --git a/WeakEvents/WeakEvent.cs b/WeakEvents/WeakEvent.cs index 814f68b..bcef44f 100644 --- a/WeakEvents/WeakEvent.cs +++ b/WeakEvents/WeakEvent.cs @@ -1,7 +1,6 @@ using Svelto.DataStructures; using System; using System.Reflection; -using Svelto.Utilities; namespace Svelto.WeakEvents { From c8f57253fc2c0c34b96a2426cab5f3a6ee6b9a81 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Sat, 23 Dec 2017 11:15:31 +0000 Subject: [PATCH 05/22] - optimize even more - some renaming --- DataStructures/FasterList.cs | 2 +- DataStructures/LockFreeQueue.cs | 65 +++--- .../PriorityQueue/HeapPriorityQueue.cs | 200 +++++++++--------- .../PriorityQueue/IPriorityQueue.cs | 10 +- .../PriorityQueue/PriorityQueueNode.cs | 6 +- .../TypeSafeFasterListForECS.cs | 35 +++ ...{EngineNodeDB.cs => EngineEntityViewDB.cs} | 0 ECS/EnginesRoot.cs | 56 +++-- ECS/EntityDescriptorTemplate.cs | 41 ++-- ...eduler.cs => EntitySubmissionScheduler.cs} | 2 +- ECS/{INode.cs => EntityView.cs} | 0 ECS/{NodeBuilder.cs => EntityViewBuilder.cs} | 21 ++ ...EngineNodeDB.cs => IEngineEntityViewDB.cs} | 0 ECS/IEnginesInterfaces.cs | 9 +- ...desEngine.cs => MultiEntityViewsEngine.cs} | 0 ...odeEngine.cs => SingleEntityViewEngine.cs} | 0 Utilities/FastInvoke.cs | 22 +- 17 files changed, 284 insertions(+), 185 deletions(-) rename ECS/{EngineNodeDB.cs => EngineEntityViewDB.cs} (100%) rename ECS/{NodeSubmissionScheduler.cs => EntitySubmissionScheduler.cs} (71%) rename ECS/{INode.cs => EntityView.cs} (100%) rename ECS/{NodeBuilder.cs => EntityViewBuilder.cs} (73%) rename ECS/{IEngineNodeDB.cs => IEngineEntityViewDB.cs} (100%) rename ECS/{MultiNodesEngine.cs => MultiEntityViewsEngine.cs} (100%) rename ECS/{SingleNodeEngine.cs => SingleEntityViewEngine.cs} (100%) diff --git a/DataStructures/FasterList.cs b/DataStructures/FasterList.cs index bc4c4f1..eed13af 100644 --- a/DataStructures/FasterList.cs +++ b/DataStructures/FasterList.cs @@ -788,7 +788,7 @@ namespace Svelto.DataStructures _buffer = newList; } - public void Trim() + public void Trim() { if (_count < _buffer.Length) Resize(_count); diff --git a/DataStructures/LockFreeQueue.cs b/DataStructures/LockFreeQueue.cs index 4b936be..4c55f39 100644 --- a/DataStructures/LockFreeQueue.cs +++ b/DataStructures/LockFreeQueue.cs @@ -1,13 +1,14 @@ +using System.Collections.Generic; using System.Threading; //from unify wiki namespace Svelto.DataStructures { - public class SingleLinkEntityView + public class SingleLinkNode { // Note; the Next member cannot be a property since // it participates in many CAS operations - public SingleLinkEntityView Next; + public SingleLinkNode Next; public T Item; } @@ -23,33 +24,33 @@ namespace Svelto.DataStructures public class LockFreeLinkPool { - private SingleLinkEntityView head; + private SingleLinkNode head; public LockFreeLinkPool() { - head = new SingleLinkEntityView(); + head = new SingleLinkNode(); } - public void Push(SingleLinkEntityView newEntityView) + public void Push(SingleLinkNode newNode) { - newEntityView.Item = default(T); + newNode.Item = default(T); do { - newEntityView.Next = head.Next; - } while (!SyncMethods.CAS>(ref head.Next, newEntityView.Next, newEntityView)); + newNode.Next = head.Next; + } while (!SyncMethods.CAS>(ref head.Next, newNode.Next, newNode)); return; } - public bool Pop(out SingleLinkEntityView entityView) + public bool Pop(out SingleLinkNode node) { do { - entityView = head.Next; - if (entityView == null) + node = head.Next; + if (node == null) { return false; } - } while (!SyncMethods.CAS>(ref head.Next, entityView, entityView.Next)); + } while (!SyncMethods.CAS>(ref head.Next, node, node.Next)); return true; } } @@ -57,35 +58,35 @@ namespace Svelto.DataStructures public class LockFreeQueue { - SingleLinkEntityView head; - SingleLinkEntityView tail; + SingleLinkNode head; + SingleLinkNode tail; LockFreeLinkPool trash; public LockFreeQueue() { - head = new SingleLinkEntityView(); + head = new SingleLinkNode(); tail = head; trash = new LockFreeLinkPool(); } public void Enqueue(T item) { - SingleLinkEntityView oldTail = null; - SingleLinkEntityView oldTailNext; + SingleLinkNode oldTail = null; + SingleLinkNode oldTailNext; - SingleLinkEntityView newEntityView; - if (!trash.Pop(out newEntityView)) + SingleLinkNode newNode; + if (!trash.Pop(out newNode)) { - newEntityView = new SingleLinkEntityView(); + newNode = new SingleLinkNode(); } else { - newEntityView.Next = null; + newNode.Next = null; } - newEntityView.Item = item; + newNode.Item = item; - bool newEntityViewWasAdded = false; - while (!newEntityViewWasAdded) + bool newNodeWasAdded = false; + while (!newNodeWasAdded) { oldTail = tail; oldTailNext = oldTail.Next; @@ -93,26 +94,26 @@ namespace Svelto.DataStructures if (tail == oldTail) { if (oldTailNext == null) - newEntityViewWasAdded = SyncMethods.CAS>(ref tail.Next, null, newEntityView); + newNodeWasAdded = SyncMethods.CAS>(ref tail.Next, null, newNode); else - SyncMethods.CAS>(ref tail, oldTail, oldTailNext); + SyncMethods.CAS>(ref tail, oldTail, oldTailNext); } } - SyncMethods.CAS>(ref tail, oldTail, newEntityView); + SyncMethods.CAS>(ref tail, oldTail, newNode); } public bool Dequeue(out T item) { item = default(T); - SingleLinkEntityView oldHead = null; + SingleLinkNode oldHead = null; bool haveAdvancedHead = false; while (!haveAdvancedHead) { oldHead = head; - SingleLinkEntityView oldTail = tail; - SingleLinkEntityView oldHeadNext = oldHead.Next; + SingleLinkNode oldTail = tail; + SingleLinkNode oldHeadNext = oldHead.Next; if (oldHead == head) { @@ -122,12 +123,12 @@ namespace Svelto.DataStructures { return false; } - SyncMethods.CAS>(ref tail, oldTail, oldHeadNext); + SyncMethods.CAS>(ref tail, oldTail, oldHeadNext); } else { item = oldHeadNext.Item; - haveAdvancedHead = SyncMethods.CAS>(ref head, oldHead, oldHeadNext); + haveAdvancedHead = SyncMethods.CAS>(ref head, oldHead, oldHeadNext); if (haveAdvancedHead) { trash.Push(oldHead); diff --git a/DataStructures/PriorityQueue/HeapPriorityQueue.cs b/DataStructures/PriorityQueue/HeapPriorityQueue.cs index bd8764b..606acd5 100644 --- a/DataStructures/PriorityQueue/HeapPriorityQueue.cs +++ b/DataStructures/PriorityQueue/HeapPriorityQueue.cs @@ -1,5 +1,7 @@ using System.Collections; using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Svelto.DataStructures; namespace Svelto.DataStructures { @@ -7,40 +9,40 @@ namespace Svelto.DataStructures /// An implementation of a min-Priority Queue using a heap. Has O(1) .Contains()! /// See https://bitbucket.org/BlueRaja/high-speed-priority-queue-for-c/wiki/Getting%20Started for more information /// - /// The values in the queue. Must implement the PriorityQueueEntityView interface + /// The values in the queue. Must implement the PriorityQueueNode interface public sealed class HeapPriorityQueue : IPriorityQueue - where T : PriorityQueueEntityView + where T : PriorityQueueNode { - private int _numEntityViews; - private readonly FasterList _entityViews; - private long _numEntityViewsEverEnqueued; + private int _numNodes; + private readonly FasterList _nodes; + private long _numNodesEverEnqueued; /// /// Instantiate a new Priority Queue /// - /// The max entityViews ever allowed to be enqueued (going over this will cause an exception) + /// The max nodes ever allowed to be enqueued (going over this will cause an exception) public HeapPriorityQueue() { - _numEntityViews = 0; - _entityViews = new FasterList(); - _numEntityViewsEverEnqueued = 0; + _numNodes = 0; + _nodes = new FasterList(); + _numNodesEverEnqueued = 0; } public HeapPriorityQueue(int initialSize) { - _numEntityViews = 0; - _entityViews = new FasterList(initialSize); - _numEntityViewsEverEnqueued = 0; + _numNodes = 0; + _nodes = new FasterList(initialSize); + _numNodesEverEnqueued = 0; } /// - /// Returns the number of entityViews in the queue. O(1) + /// Returns the number of nodes in the queue. O(1) /// public int Count { get { - return _numEntityViews; + return _numNodes; } } @@ -52,119 +54,119 @@ namespace Svelto.DataStructures { get { - return _entityViews.Count - 1; + return _nodes.Count - 1; } } /// - /// Removes every entityView from the queue. O(n) (So, don't do this often!) + /// Removes every node from the queue. O(n) (So, don't do this often!) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif public void Clear() { - _entityViews.FastClear(); + _nodes.FastClear(); - _numEntityViews = 0; + _numNodes = 0; } /// - /// Returns (in O(1)!) whether the given entityView is in the queue. O(1) + /// Returns (in O(1)!) whether the given node is in the queue. O(1) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public bool Contains(T entityView) + public bool Contains(T node) { - return (_entityViews[entityView.QueueIndex] == entityView); + return (_nodes[node.QueueIndex] == node); } /// - /// Enqueue a entityView - .Priority must be set beforehand! O(log n) + /// Enqueue a node - .Priority must be set beforehand! O(log n) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public void Enqueue(T entityView, double priority) + public void Enqueue(T node, double priority) { - entityView.Priority = priority; - _numEntityViews++; - if (_entityViews.Count < _numEntityViews) - _entityViews.Resize(_numEntityViews + 1); - - _entityViews[_numEntityViews] = entityView; - entityView.QueueIndex = _numEntityViews; - entityView.InsertionIndex = _numEntityViewsEverEnqueued++; - CascadeUp(_entityViews[_numEntityViews]); + node.Priority = priority; + _numNodes++; + if (_nodes.Count < _numNodes) + _nodes.Resize(_numNodes + 1); + + _nodes[_numNodes] = node; + node.QueueIndex = _numNodes; + node.InsertionIndex = _numNodesEverEnqueued++; + CascadeUp(_nodes[_numNodes]); } #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - private void Swap(T entityView1, T entityView2) + private void Swap(T node1, T node2) { - //Swap the entityViews - _entityViews[entityView1.QueueIndex] = entityView2; - _entityViews[entityView2.QueueIndex] = entityView1; + //Swap the nodes + _nodes[node1.QueueIndex] = node2; + _nodes[node2.QueueIndex] = node1; //Swap their indicies - int temp = entityView1.QueueIndex; - entityView1.QueueIndex = entityView2.QueueIndex; - entityView2.QueueIndex = temp; + int temp = node1.QueueIndex; + node1.QueueIndex = node2.QueueIndex; + node2.QueueIndex = temp; } //Performance appears to be slightly better when this is NOT inlined o_O - private void CascadeUp(T entityView) + private void CascadeUp(T node) { //aka Heapify-up - int parent = entityView.QueueIndex / 2; + int parent = node.QueueIndex / 2; while(parent >= 1) { - T parentEntityView = _entityViews[parent]; - if(HasHigherPriority(parentEntityView, entityView)) + T parentNode = _nodes[parent]; + if(HasHigherPriority(parentNode, node)) break; - //EntityView has lower priority value, so move it up the heap - Swap(entityView, parentEntityView); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() + //Node has lower priority value, so move it up the heap + Swap(node, parentNode); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() - parent = entityView.QueueIndex / 2; + parent = node.QueueIndex / 2; } } #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - private void CascadeDown(T entityView) + private void CascadeDown(T node) { //aka Heapify-down T newParent; - int finalQueueIndex = entityView.QueueIndex; + int finalQueueIndex = node.QueueIndex; while(true) { - newParent = entityView; + newParent = node; int childLeftIndex = 2 * finalQueueIndex; - //Check if the left-child is higher-priority than the current entityView - if(childLeftIndex > _numEntityViews) + //Check if the left-child is higher-priority than the current node + if(childLeftIndex > _numNodes) { - //This could be placed outside the loop, but then we'd have to check newParent != entityView twice - entityView.QueueIndex = finalQueueIndex; - _entityViews[finalQueueIndex] = entityView; + //This could be placed outside the loop, but then we'd have to check newParent != node twice + node.QueueIndex = finalQueueIndex; + _nodes[finalQueueIndex] = node; break; } - T childLeft = _entityViews[childLeftIndex]; + T childLeft = _nodes[childLeftIndex]; if(HasHigherPriority(childLeft, newParent)) { newParent = childLeft; } - //Check if the right-child is higher-priority than either the current entityView or the left child + //Check if the right-child is higher-priority than either the current node or the left child int childRightIndex = childLeftIndex + 1; - if(childRightIndex <= _numEntityViews) + if(childRightIndex <= _numNodes) { - T childRight = _entityViews[childRightIndex]; + T childRight = _nodes[childRightIndex]; if(HasHigherPriority(childRight, newParent)) { newParent = childRight; @@ -172,11 +174,11 @@ namespace Svelto.DataStructures } //If either of the children has higher (smaller) priority, swap and continue cascading - if(newParent != entityView) + if(newParent != node) { - //Move new parent to its new index. entityView will be moved once, at the end + //Move new parent to its new index. node will be moved once, at the end //Doing it this way is one less assignment operation than calling Swap() - _entityViews[finalQueueIndex] = newParent; + _nodes[finalQueueIndex] = newParent; int temp = newParent.QueueIndex; newParent.QueueIndex = finalQueueIndex; @@ -185,8 +187,8 @@ namespace Svelto.DataStructures else { //See note above - entityView.QueueIndex = finalQueueIndex; - _entityViews[finalQueueIndex] = entityView; + node.QueueIndex = finalQueueIndex; + _nodes[finalQueueIndex] = node; break; } } @@ -194,7 +196,7 @@ namespace Svelto.DataStructures /// /// Returns true if 'higher' has higher priority than 'lower', false otherwise. - /// Note that calling HasHigherPriority(entityView, entityView) (ie. both arguments the same entityView) will return false + /// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -206,11 +208,11 @@ namespace Svelto.DataStructures } /// - /// Removes the head of the queue (entityView with highest priority; ties are broken by order of insertion), and returns it. O(log n) + /// Removes the head of the queue (node with highest priority; ties are broken by order of insertion), and returns it. O(log n) /// public T Dequeue() { - T returnMe = _entityViews[1]; + T returnMe = _nodes[1]; Remove(returnMe); return returnMe; } @@ -222,77 +224,77 @@ namespace Svelto.DataStructures { get { - return _entityViews[1]; + return _nodes[1]; } } /// - /// This method must be called on a entityView every time its priority changes while it is in the queue. + /// This method must be called on a node every time its priority changes while it is in the queue. /// Forgetting to call this method will result in a corrupted queue! /// O(log n) /// #if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] #endif - public void UpdatePriority(T entityView, double priority) + public void UpdatePriority(T node, double priority) { - entityView.Priority = priority; - OnEntityViewUpdated(entityView); + node.Priority = priority; + OnNodeUpdated(node); } - private void OnEntityViewUpdated(T entityView) + private void OnNodeUpdated(T node) { - //Bubble the updated entityView up or down as appropriate - int parentIndex = entityView.QueueIndex / 2; - T parentEntityView = _entityViews[parentIndex]; + //Bubble the updated node up or down as appropriate + int parentIndex = node.QueueIndex / 2; + T parentNode = _nodes[parentIndex]; - if(parentIndex > 0 && HasHigherPriority(entityView, parentEntityView)) + if(parentIndex > 0 && HasHigherPriority(node, parentNode)) { - CascadeUp(entityView); + CascadeUp(node); } else { - //Note that CascadeDown will be called if parentEntityView == entityView (that is, entityView is the root) - CascadeDown(entityView); + //Note that CascadeDown will be called if parentNode == node (that is, node is the root) + CascadeDown(node); } } /// - /// Removes a entityView from the queue. Note that the entityView does not need to be the head of the queue. O(log n) + /// Removes a node from the queue. Note that the node does not need to be the head of the queue. O(log n) /// - public void Remove(T entityView) + public void Remove(T node) { - if(_numEntityViews <= 1) + if(_numNodes <= 1) { - _entityViews[1] = null; - _numEntityViews = 0; + _nodes[1] = null; + _numNodes = 0; return; } - //Make sure the entityView is the last entityView in the queue + //Make sure the node is the last node in the queue bool wasSwapped = false; - T formerLastEntityView = _entityViews[_numEntityViews]; - if(entityView.QueueIndex != _numEntityViews) + T formerLastNode = _nodes[_numNodes]; + if(node.QueueIndex != _numNodes) { - //Swap the entityView with the last entityView - Swap(entityView, formerLastEntityView); + //Swap the node with the last node + Swap(node, formerLastNode); wasSwapped = true; } - _numEntityViews--; - _entityViews[entityView.QueueIndex] = null; + _numNodes--; + _nodes[node.QueueIndex] = null; if(wasSwapped) { - //Now bubble formerLastEntityView (which is no longer the last entityView) up or down as appropriate - OnEntityViewUpdated(formerLastEntityView); + //Now bubble formerLastNode (which is no longer the last node) up or down as appropriate + OnNodeUpdated(formerLastNode); } } public IEnumerator GetEnumerator() { - for(int i = 1; i <= _numEntityViews; i++) - yield return _entityViews[i]; + for(int i = 1; i <= _numNodes; i++) + yield return _nodes[i]; } IEnumerator IEnumerable.GetEnumerator() @@ -306,16 +308,16 @@ namespace Svelto.DataStructures /// public bool IsValidQueue() { - for(int i = 1; i < _entityViews.Count; i++) + for(int i = 1; i < _nodes.Count; i++) { - if(_entityViews[i] != null) + if(_nodes[i] != null) { int childLeftIndex = 2 * i; - if(childLeftIndex < _entityViews.Count && _entityViews[childLeftIndex] != null && HasHigherPriority(_entityViews[childLeftIndex], _entityViews[i])) + if(childLeftIndex < _nodes.Count && _nodes[childLeftIndex] != null && HasHigherPriority(_nodes[childLeftIndex], _nodes[i])) return false; int childRightIndex = childLeftIndex + 1; - if(childRightIndex < _entityViews.Count && _entityViews[childRightIndex] != null && HasHigherPriority(_entityViews[childRightIndex], _entityViews[i])) + if(childRightIndex < _nodes.Count && _nodes[childRightIndex] != null && HasHigherPriority(_nodes[childRightIndex], _nodes[i])) return false; } } diff --git a/DataStructures/PriorityQueue/IPriorityQueue.cs b/DataStructures/PriorityQueue/IPriorityQueue.cs index 58997ff..632820e 100644 --- a/DataStructures/PriorityQueue/IPriorityQueue.cs +++ b/DataStructures/PriorityQueue/IPriorityQueue.cs @@ -8,16 +8,16 @@ namespace Svelto.DataStructures /// (theoretically?) optimize method calls from concrete-types slightly better. /// public interface IPriorityQueue : IEnumerable - where T : PriorityQueueEntityView + where T : PriorityQueueNode { - void Remove(T entityView); - void UpdatePriority(T entityView, double priority); - void Enqueue(T entityView, double priority); + void Remove(T node); + void UpdatePriority(T node, double priority); + void Enqueue(T node, double priority); T Dequeue(); T First { get; } int Count { get; } int MaxSize { get; } void Clear(); - bool Contains(T entityView); + bool Contains(T node); } } diff --git a/DataStructures/PriorityQueue/PriorityQueueNode.cs b/DataStructures/PriorityQueue/PriorityQueueNode.cs index 48c5491..b09f3a4 100644 --- a/DataStructures/PriorityQueue/PriorityQueueNode.cs +++ b/DataStructures/PriorityQueue/PriorityQueueNode.cs @@ -1,9 +1,9 @@ namespace Svelto.DataStructures { - public class PriorityQueueEntityView + public class PriorityQueueNode { /// - /// The Priority to insert this entityView at. Must be set BEFORE adding a entityView to the queue + /// The Priority to insert this node at. Must be set BEFORE adding a node to the queue /// public double Priority { get; set; @@ -11,7 +11,7 @@ /// /// Used by the priority queue - do not edit this value. - /// Represents the order the entityView was inserted in + /// Represents the order the node was inserted in /// public long InsertionIndex { get; set; } diff --git a/ECS/DataStructures/TypeSafeFasterListForECS.cs b/ECS/DataStructures/TypeSafeFasterListForECS.cs index 6241937..161ecf4 100644 --- a/ECS/DataStructures/TypeSafeFasterListForECS.cs +++ b/ECS/DataStructures/TypeSafeFasterListForECS.cs @@ -10,10 +10,12 @@ namespace Svelto.ECS.Internal void AddRange(ITypeSafeList entityViewListValue); ITypeSafeList Create(); + ITypeSafeList Create(int size); bool isQueryiableEntityView { get; } bool UnorderedRemove(int entityID); ITypeSafeDictionary CreateIndexedDictionary(); IEntityView[] ToArrayFast(out int count); + void ReserveCapacity(int capacity); } class TypeSafeFasterListForECS: FasterList where T:IEntityView @@ -22,6 +24,11 @@ namespace Svelto.ECS.Internal { _mappedIndices = new Dictionary(); } + + protected TypeSafeFasterListForECS(int size):base(size) + { + _mappedIndices = new Dictionary(); + } public bool UnorderedRemove(int entityID) { @@ -47,11 +54,23 @@ namespace Svelto.ECS.Internal _mappedIndices[this[i].ID] = i; } + public void ReserveCapacity(int capacity) + { + if (this.ToArrayFast().Length < capacity) + Resize(capacity); + } + readonly Dictionary _mappedIndices; } class TypeSafeFasterListForECSForStructs : TypeSafeFasterListForECS, ITypeSafeList where T:struct, IEntityStruct { + public TypeSafeFasterListForECSForStructs(int size):base(size) + {} + + public TypeSafeFasterListForECSForStructs() + {} + public ITypeSafeList Create() { return new TypeSafeFasterListForECSForStructs(); @@ -71,10 +90,21 @@ namespace Svelto.ECS.Internal { throw new Exception("Not Allowed"); } + + public ITypeSafeList Create(int size) + { + return new TypeSafeFasterListForECSForStructs(size); + } } class TypeSafeFasterListForECSForClasses : TypeSafeFasterListForECS, ITypeSafeList where T:EntityView, new() { + public TypeSafeFasterListForECSForClasses(int size):base(size) + {} + + public TypeSafeFasterListForECSForClasses() + {} + public ITypeSafeList Create() { return new TypeSafeFasterListForECSForClasses(); @@ -96,5 +126,10 @@ namespace Svelto.ECS.Internal return this.ToArrayFast(); } + + public ITypeSafeList Create(int size) + { + return new TypeSafeFasterListForECSForClasses(size); + } } } diff --git a/ECS/EngineNodeDB.cs b/ECS/EngineEntityViewDB.cs similarity index 100% rename from ECS/EngineNodeDB.cs rename to ECS/EngineEntityViewDB.cs diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs index 882e57b..5443753 100644 --- a/ECS/EnginesRoot.cs +++ b/ECS/EnginesRoot.cs @@ -18,9 +18,9 @@ using Svelto.ECS.Profiler; namespace Svelto.ECS { - public sealed class EnginesRoot : IEntityFunctions, IEntityFactory, IDisposable + public sealed class EnginesRoot : IDisposable { - public EnginesRoot(EntityViewSubmissionScheduler entityViewScheduler) + public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) { _entityViewEngines = new Dictionary>(); _otherEngines = new FasterList(); @@ -66,13 +66,13 @@ namespace Svelto.ECS return new GenericEntityFunctions(new DataStructures.WeakReference(this)); } - public void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new() + void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new() { EntityFactory.BuildEntityViews (entityID, _entityViewsToAdd.current, EntityDescriptorTemplate.Default, implementors); } - public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) { EntityFactory.BuildEntityViews (entityID, _entityViewsToAdd.current, entityDescriptor, implementors); @@ -103,7 +103,7 @@ namespace Svelto.ECS /// /// /// - public void BuildMetaEntity(int metaEntityID, object[] implementors) where T:IEntityDescriptor, new() + void BuildMetaEntity(int metaEntityID, object[] implementors) where T:IEntityDescriptor, new() { EntityFactory.BuildEntityViews(metaEntityID, _entityViewsToAdd.current, EntityDescriptorTemplate.Default, implementors); @@ -119,7 +119,7 @@ namespace Svelto.ECS /// /// /// - public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new() + void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new() { EntityFactory.BuildGroupedEntityViews(entityID, groupID, _groupedEntityViewsToAdd.current, @@ -127,14 +127,14 @@ namespace Svelto.ECS implementors); } - public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) { EntityFactory.BuildGroupedEntityViews(entityID, groupID, _groupedEntityViewsToAdd.current, entityDescriptor, implementors); } - public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) + void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) { var removeEntityImplementor = removeInfo as RemoveEntityImplementor; @@ -144,21 +144,44 @@ namespace Svelto.ECS InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, _entityViewsDB); } - public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + void RemoveEntity(int entityID) where T : IEntityDescriptor, new() { InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, entityID, _entityViewsDB); } - public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() { InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, metaEntityID, _metaEntityViewsDB); } - public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() { InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); } - + + void Preallocate(int size) where T : IEntityDescriptor, new() + { + var entityViewsToBuild = EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild; + int count = entityViewsToBuild.Length; + + for (int index = 0; index < count; index++) + { + var entityViewBuilder = entityViewsToBuild[index]; + var entityViewType = entityViewBuilder.GetEntityViewType(); + + ITypeSafeList dbList; + if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) + _entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); + else + dbList.ReserveCapacity(size); + + if (_entityViewsToAdd.current.TryGetValue(entityViewType, out dbList) == false) + _entityViewsToAdd.current[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); + else + dbList.ReserveCapacity(size); + } + } + public void AddEngine(IEngine engine) { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR @@ -323,7 +346,7 @@ namespace Svelto.ECS groupedEntityViewsByType.Add(entityView.Key, entityView.Value); } } - + static void AddEntityViewToDB(Dictionary entityViewsDB, KeyValuePair entityViewList) { ITypeSafeList dbList; @@ -508,7 +531,7 @@ namespace Svelto.ECS readonly DoubleBufferedEntityViews> _metaEntityViewsToAdd; readonly DoubleBufferedEntityViews>> _groupedEntityViewsToAdd; - readonly EntityViewSubmissionScheduler _scheduler; + readonly EntitySubmissionScheduler _scheduler; #if EXPERIMENTAL readonly Type _structEntityViewEngineType; readonly Type _groupedStructEntityViewsEngineType; @@ -580,6 +603,11 @@ namespace Svelto.ECS { _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); } + + public void Preallocate(int size) where T : IEntityDescriptor, new() + { + _weakEngine.Target.Preallocate(size); + } } class GenericEntityFunctions : IEntityFunctions diff --git a/ECS/EntityDescriptorTemplate.cs b/ECS/EntityDescriptorTemplate.cs index cceb87d..3c20589 100644 --- a/ECS/EntityDescriptorTemplate.cs +++ b/ECS/EntityDescriptorTemplate.cs @@ -101,17 +101,17 @@ namespace Svelto.ECS.Internal } } - static IEntityView BuildEntityView(int entityID, Dictionary groupedEntityViewsTyped, + static IEntityView BuildEntityView(int entityID, Dictionary entityViewsByType, Type entityViewType, IEntityViewBuilder entityViewBuilderId) { - ITypeSafeList entityViews; + ITypeSafeList entityViewsList; var entityViewsPoolWillBeCreated = - groupedEntityViewsTyped.TryGetValue(entityViewType, out entityViews) == false; - var entityViewObjectToFill = entityViewBuilderId.BuildEntityViewAndAddToList(ref entityViews, entityID); + entityViewsByType.TryGetValue(entityViewType, out entityViewsList) == false; + var entityViewObjectToFill = entityViewBuilderId.BuildEntityViewAndAddToList(ref entityViewsList, entityID); if (entityViewsPoolWillBeCreated) - groupedEntityViewsTyped.Add(entityViewType, entityViews); + entityViewsByType.Add(entityViewType, entityViewsList); return entityViewObjectToFill as IEntityView; } @@ -163,13 +163,13 @@ namespace Svelto.ECS.Internal var keyValuePair = setters[i]; Type fieldType = keyValuePair.Key; - if (fieldType == removeEntityComponentType) - { - keyValuePair.Value(entityView, removeEntity); - } - else + if (fieldType != removeEntityComponentType) { +#if DEBUG && !PROFILER Tuple component; +#else + object component; +#endif if (implementorsByType.TryGetValue(fieldType, out component) == false) { @@ -178,21 +178,28 @@ namespace Svelto.ECS.Internal throw e; } - +#if DEBUG && !PROFILER if (component.item2 > 1) Utility.Console.LogError(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat( "Component Type: ", fieldType.Name, " implementor: ", component.item1.ToString()) + " - EntityView: " + entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); - +#endif +#if DEBUG && !PROFILER keyValuePair.Value(entityView, component.item1); +#else + keyValuePair.Value(entityView, component); +#endif + } + else + { + keyValuePair.Value(entityView, removeEntity); } - } implementorsByType.Clear(); } - +#if DEBUG && !PROFILER struct Tuple { public T1 item1; @@ -204,9 +211,13 @@ namespace Svelto.ECS.Internal item2 = v; } } - +#endif //this is used to avoid newing a dictionary every time, but it's used locally only +#if DEBUG && !PROFILER static readonly Dictionary> implementorsByType = new Dictionary>(); +#else + static readonly Dictionary implementorsByType = new Dictionary(); +#endif static Dictionary _cachedTypes = new Dictionary(); const string DUPLICATE_IMPLEMENTOR_ERROR = diff --git a/ECS/NodeSubmissionScheduler.cs b/ECS/EntitySubmissionScheduler.cs similarity index 71% rename from ECS/NodeSubmissionScheduler.cs rename to ECS/EntitySubmissionScheduler.cs index bc62758..cfa8168 100644 --- a/ECS/NodeSubmissionScheduler.cs +++ b/ECS/EntitySubmissionScheduler.cs @@ -2,7 +2,7 @@ using Svelto.WeakEvents; namespace Svelto.ECS.Schedulers { - public abstract class EntityViewSubmissionScheduler + public abstract class EntitySubmissionScheduler { abstract public void Schedule(WeakAction submitEntityViews); } diff --git a/ECS/INode.cs b/ECS/EntityView.cs similarity index 100% rename from ECS/INode.cs rename to ECS/EntityView.cs diff --git a/ECS/NodeBuilder.cs b/ECS/EntityViewBuilder.cs similarity index 73% rename from ECS/NodeBuilder.cs rename to ECS/EntityViewBuilder.cs index 7b4db4b..48ce2dd 100644 --- a/ECS/NodeBuilder.cs +++ b/ECS/EntityViewBuilder.cs @@ -6,6 +6,7 @@ namespace Svelto.ECS public interface IEntityViewBuilder { IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID); + ITypeSafeList Preallocate(ref ITypeSafeList list, int size); Type GetEntityViewType(); } @@ -26,6 +27,16 @@ namespace Svelto.ECS return entityView; } + public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) + { + if (list == null) + list = new TypeSafeFasterListForECSForClasses(size); + else + list.ReserveCapacity(size); + + return list; + } + public Type GetEntityViewType() { return _entityViewType; @@ -51,6 +62,16 @@ namespace Svelto.ECS return null; } + public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) + { + if (list == null) + list = new TypeSafeFasterListForECSForStructs(size); + else + list.ReserveCapacity(size); + + return list; + } + public Type GetEntityViewType() { return _entityViewType; diff --git a/ECS/IEngineNodeDB.cs b/ECS/IEngineEntityViewDB.cs similarity index 100% rename from ECS/IEngineNodeDB.cs rename to ECS/IEngineEntityViewDB.cs diff --git a/ECS/IEnginesInterfaces.cs b/ECS/IEnginesInterfaces.cs index 05ed50c..6c8945c 100644 --- a/ECS/IEnginesInterfaces.cs +++ b/ECS/IEnginesInterfaces.cs @@ -2,6 +2,8 @@ namespace Svelto.ECS { public interface IEntityFactory { + void Preallocate(int size) where T : IEntityDescriptor, new(); + void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new(); void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null); @@ -20,12 +22,5 @@ namespace Svelto.ECS void RemoveMetaEntity(int metaEntityID) where T:IEntityDescriptor, new(); void RemoveEntityFromGroup(int entityID, int groupID) where T:IEntityDescriptor, new(); -#if EXPERIMENTAL - void SetEntityActiveState(int entityID, bool state) where T:IEntityDescriptor, new(); - - void SetMetaEntityActiveState(int metaEntityID, bool state) where T:IEntityDescriptor, new(); - - void SetEntityInGroupActiveState(int entityID, int group, bool state) where T:IEntityDescriptor, new(); -#endif } } diff --git a/ECS/MultiNodesEngine.cs b/ECS/MultiEntityViewsEngine.cs similarity index 100% rename from ECS/MultiNodesEngine.cs rename to ECS/MultiEntityViewsEngine.cs diff --git a/ECS/SingleNodeEngine.cs b/ECS/SingleEntityViewEngine.cs similarity index 100% rename from ECS/SingleNodeEngine.cs rename to ECS/SingleEntityViewEngine.cs diff --git a/Utilities/FastInvoke.cs b/Utilities/FastInvoke.cs index 48e72f5..c749c1d 100644 --- a/Utilities/FastInvoke.cs +++ b/Utilities/FastInvoke.cs @@ -5,20 +5,26 @@ using System.Reflection.Emit; namespace Svelto.Utilities { //https://stackoverflow.com/questions/321650/how-do-i-set-a-field-value-in-an-c-sharp-expression-tree/321686#321686 + public static class FastInvoke where T : class { public static Action MakeSetter(FieldInfo field) { - DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] {typeof(T), typeof(object)}); - ILGenerator cg = m.GetILGenerator(); + if (field.FieldType.IsInterface == true && field.FieldType.IsValueType == false) + { + DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] { typeof(T), typeof(object) }); + ILGenerator cg = m.GetILGenerator(); + + // arg0. = arg1 + cg.Emit(OpCodes.Ldarg_0); + cg.Emit(OpCodes.Ldarg_1); + cg.Emit(OpCodes.Stfld, field); + cg.Emit(OpCodes.Ret); - // arg0. = arg1 - cg.Emit(OpCodes.Ldarg_0); - cg.Emit(OpCodes.Ldarg_1); - cg.Emit(OpCodes.Stfld, field); - cg.Emit(OpCodes.Ret); + return (Action)m.CreateDelegate(typeof(Action)); + } - return (Action) m.CreateDelegate(typeof(Action));; + throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); } } } \ No newline at end of file From 4ea83ddce3818250a30d31b734a1cd1968dc01df Mon Sep 17 00:00:00 2001 From: sebas77 Date: Sat, 23 Dec 2017 11:17:28 +0000 Subject: [PATCH 06/22] add csproj for svelto framework --- .gitignore | 3 +++ Svelto.ECS.csproj | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 Svelto.ECS.csproj diff --git a/.gitignore b/.gitignore index ac529bb..a41426d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ /EntitySystem/note.txt.meta /*.meta *.meta +/obj +/bin/Release/netstandard2.0 +/bin/Debug/netstandard2.0 diff --git a/Svelto.ECS.csproj b/Svelto.ECS.csproj new file mode 100644 index 0000000..c06df04 --- /dev/null +++ b/Svelto.ECS.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + + C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.0.0\ref\netcoreapp2.0\System.Reflection.Emit.Lightweight.dll + + + + From ba2e592eda6e0d6588ebc6bb5bb7713971dd417e Mon Sep 17 00:00:00 2001 From: sebas77 Date: Sun, 24 Dec 2017 00:48:43 +0000 Subject: [PATCH 07/22] found a way to avoid some awkward breaking changes from 1.0 split EngineRoot for better readability and add comments --- ECS/EngineEntityViewDB.cs | 10 +- ECS/EnginesRoot.cs | 665 ------------------ ECS/EnginesRootEngines.cs | 238 +++++++ ECS/EnginesRootEntities.cs | 337 +++++++++ ECS/EnginesRootSubmission.cs | 160 +++++ ECS/EntityDescriptorTemplate.cs | 71 +- ECS/EntityView.cs | 31 +- ECS/EntityViewBuilder.cs | 22 +- .../Unity/UnitySumbmissionNodeScheduler.cs | 2 +- ECS/GenericEntityDescriptor.cs | 42 +- ECS/IEngineEntityViewDB.cs | 10 +- ECS/IEnginesInterfaces.cs | 2 +- ECS/MultiEntityViewsEngine.cs | 12 +- ECS/RemoveEntityImplementor.cs | 30 +- ECS/SingleEntityViewEngine.cs | 2 +- 15 files changed, 850 insertions(+), 784 deletions(-) delete mode 100644 ECS/EnginesRoot.cs create mode 100644 ECS/EnginesRootEngines.cs create mode 100644 ECS/EnginesRootEntities.cs create mode 100644 ECS/EnginesRootSubmission.cs diff --git a/ECS/EngineEntityViewDB.cs b/ECS/EngineEntityViewDB.cs index 103275f..495073f 100644 --- a/ECS/EngineEntityViewDB.cs +++ b/ECS/EngineEntityViewDB.cs @@ -18,7 +18,7 @@ namespace Svelto.ECS _groupEntityViewsDB = groupEntityViewsDB; } - public FasterReadOnlyList QueryEntityViews() where T:EntityView, new() + public FasterReadOnlyList QueryEntityViews() where T:EntityView, new() { var type = typeof(T); @@ -30,7 +30,7 @@ namespace Svelto.ECS return new FasterReadOnlyList((FasterList)entityViews); } - public FasterReadOnlyList QueryGroupedEntityViews(int @group) where T:EntityView, new() + public FasterReadOnlyList QueryGroupedEntityViews(int @group) where T:EntityView, new() { Dictionary entityViews; @@ -128,17 +128,17 @@ namespace Svelto.ECS throw new Exception("EntityView Not Found"); } - public T QueryMetaEntityView(int metaEntityID) where T:EntityView, new() + public T QueryMetaEntityView(int metaEntityID) where T:EntityView, new() { return QueryEntityView(metaEntityID); } - public bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T:EntityView, new() + public bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T:EntityView, new() { return TryQueryEntityView(metaEntityID, out entityView); } - public FasterReadOnlyList QueryMetaEntityViews() where T:EntityView, new() + public FasterReadOnlyList QueryMetaEntityViews() where T:EntityView, new() { var type = typeof(T); diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs deleted file mode 100644 index 5443753..0000000 --- a/ECS/EnginesRoot.cs +++ /dev/null @@ -1,665 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using Svelto.DataStructures; -using Svelto.ECS.Internal; -using Svelto.ECS.Schedulers; -using Svelto.Utilities; -using Svelto.WeakEvents; - -#if EXPERIMENTAL -using Svelto.ECS.Experimental; -using Svelto.ECS.Experimental.Internal; -#endif - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR -using Svelto.ECS.Profiler; -#endif - -namespace Svelto.ECS -{ - public sealed class EnginesRoot : IDisposable - { - public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) - { - _entityViewEngines = new Dictionary>(); - _otherEngines = new FasterList(); - - _entityViewsDB = new Dictionary(); - _metaEntityViewsDB = new Dictionary(); - _groupEntityViewsDB = new Dictionary>(); - _entityViewsDBdic = new Dictionary(); - - _entityViewsToAdd = new DoubleBufferedEntityViews>(); - _metaEntityViewsToAdd = new DoubleBufferedEntityViews>(); - _groupedEntityViewsToAdd = new DoubleBufferedEntityViews>>(); -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - _addEntityViewToEngine = AddEntityViewToEngine; - _removeEntityViewFromEngine = RemoveEntityViewFromEngine; -#endif - _engineEntityViewDB = new EngineEntityViewDB(_entityViewsDB, _entityViewsDBdic, _metaEntityViewsDB, _groupEntityViewsDB); - - _scheduler = entityViewScheduler; - _scheduler.Schedule(new WeakAction(SubmitEntityViews)); -#if EXPERIMENTAL - _sharedStructEntityViewLists = new SharedStructEntityViewLists(); - _sharedGroupedStructEntityViewLists = new SharedGroupedStructEntityViewsLists(); - - _structEntityViewEngineType = typeof(IStructEntityViewEngine<>); - _groupedStructEntityViewsEngineType = typeof(IGroupedStructEntityViewsEngine<>); - - _implementedInterfaceTypes = new Dictionary(); -#endif -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); - debugEngineObject.gameObject.AddComponent(); -#endif - } - - public IEntityFactory GenerateEntityFactory() - { - return new GenericEntityFactory(new DataStructures.WeakReference(this)); - } - - public IEntityFunctions GenerateEntityFunctions() - { - return new GenericEntityFunctions(new DataStructures.WeakReference(this)); - } - - void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new() - { - EntityFactory.BuildEntityViews - (entityID, _entityViewsToAdd.current, EntityDescriptorTemplate.Default, implementors); - } - - void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - EntityFactory.BuildEntityViews - (entityID, _entityViewsToAdd.current, entityDescriptor, implementors); - } - - /// - /// A meta entity is a way to manage a set of entitites that are not easily - /// queriable otherwise. For example you may want to group existing entities - /// by size and type and then use the meta entity entityView to manage the data - /// shared among the single entities of the same type and size. This will - /// prevent the scenario where the coder is forced to parse all the entities to - /// find the ones of the same size and type. - /// Since the entities are managed through the shared entityView, the same - /// shared entityView must be found on the single entities of the same type and size. - /// The shared entityView of the meta entity is then used by engines that are meant - /// to manage a group of entities through a single entityView. - /// The same engine can manage several meta entities entityViews too. - /// The Engine manages the logic of the Meta EntityView data and other engines - /// can read back this data through the normal entity as the shared entityView - /// will be present in their descriptor too. - /// It's a way to control a group of Entities through a entityView only. - /// This set of entities can share exactly the same entityView reference if - /// built through this function. In this way, if you need to set a variable - /// on a group of entities, instead to inject N entityViews and iterate over - /// them to set the same value, you can inject just one entityView, set the value - /// and be sure that the value is shared between entities. - /// - /// - /// - /// - void BuildMetaEntity(int metaEntityID, object[] implementors) where T:IEntityDescriptor, new() - { - EntityFactory.BuildEntityViews(metaEntityID, _entityViewsToAdd.current, - EntityDescriptorTemplate.Default, implementors); - } - - /// - /// Using this function is like building a normal entity, but the entityViews - /// are grouped by groupID to be better processed inside engines and - /// improve cache locality. Only IGroupStructEntityViewWithID entityViews are grouped - /// other entityViews are managed as usual. - /// - /// - /// - /// - /// - void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new() - { - EntityFactory.BuildGroupedEntityViews(entityID, groupID, - _groupedEntityViewsToAdd.current, - EntityDescriptorTemplate.Default, - implementors); - } - - void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - EntityFactory.BuildGroupedEntityViews(entityID, groupID, - _groupedEntityViewsToAdd.current, - entityDescriptor, implementors); - } - - void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) - { - var removeEntityImplementor = removeInfo as RemoveEntityImplementor; - - if (removeEntityImplementor.removeEntityInfo.isInAGroup) - InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, removeEntityImplementor.removeEntityInfo.groupID, _entityViewsDB); - else - InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, _entityViewsDB); - } - - void RemoveEntity(int entityID) where T : IEntityDescriptor, new() - { - InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, entityID, _entityViewsDB); - } - - void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() - { - InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, metaEntityID, _metaEntityViewsDB); - } - - void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() - { - InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); - } - - void Preallocate(int size) where T : IEntityDescriptor, new() - { - var entityViewsToBuild = EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild; - int count = entityViewsToBuild.Length; - - for (int index = 0; index < count; index++) - { - var entityViewBuilder = entityViewsToBuild[index]; - var entityViewType = entityViewBuilder.GetEntityViewType(); - - ITypeSafeList dbList; - if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) - _entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); - else - dbList.ReserveCapacity(size); - - if (_entityViewsToAdd.current.TryGetValue(entityViewType, out dbList) == false) - _entityViewsToAdd.current[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); - else - dbList.ReserveCapacity(size); - } - } - - public void AddEngine(IEngine engine) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - Profiler.EngineProfiler.AddEngine(engine); -#endif - var engineType = engine.GetType(); -#if EXPERIMENTAL - bool engineAdded; - - var implementedInterfaces = engineType.GetInterfaces(); - - CollectImplementedInterfaces(implementedInterfaces); - - engineAdded = CheckSpecialEngine(engine); -#endif - var viewEngine = engine as IHandleEntityViewEngine; - - if (viewEngine != null) - CheckEntityViewsEngine(viewEngine, engineType); - else - _otherEngines.Add(engine); - - var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; - if (queryableEntityViewEngine != null) - { - queryableEntityViewEngine.entityViewsDB = _engineEntityViewDB; - queryableEntityViewEngine.Ready(); - } - } - -#if EXPERIMENTAL - void CollectImplementedInterfaces(Type[] implementedInterfaces) - { - _implementedInterfaceTypes.Clear(); - - var type = typeof(IHandleEntityViewEngine); - - for (int index = 0; index < implementedInterfaces.Length; index++) - { - var interfaceType = implementedInterfaces[index]; - - if (type.IsAssignableFrom(interfaceType) == false) - continue; - - if (false == interfaceType.IsGenericTypeEx()) - { - continue; - } - - var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); - - _implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); - } - } - - bool CheckSpecialEngine(IEngine engine) - { - if (_implementedInterfaceTypes.Count == 0) return false; - - bool engineAdded = false; - - if (_implementedInterfaceTypes.ContainsKey(_structEntityViewEngineType)) - { - ((IStructEntityViewEngine)engine).CreateStructEntityViews - (_sharedStructEntityViewLists); - } - - if (_implementedInterfaceTypes.ContainsKey(_groupedStructEntityViewsEngineType)) - { - ((IGroupedStructEntityViewsEngine)engine).CreateStructEntityViews - (_sharedGroupedStructEntityViewLists); - } - - return engineAdded; - } -#endif - void CheckEntityViewsEngine(IEngine engine, Type engineType) - { - var baseType = engineType.GetBaseType(); - - if (baseType.IsGenericTypeEx()) - { - var genericArguments = baseType.GetGenericArguments(); - AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); -#if EXPERIMENTAL - var activableEngine = engine as IHandleActivableEntityEngine; - if (activableEngine != null) - AddEngine(activableEngine, genericArguments, _activableViewEntitiesEngines); -#endif - - return; - } - - throw new Exception("Not Supported Engine"); - } - - static void AddEngine(T engine, Type[] types, - Dictionary> engines) - { - for (int i = 0; i < types.Length; i++) - { - FasterList list; - - var type = types[i]; - - if (engines.TryGetValue(type, out list) == false) - { - list = new FasterList(); - - engines.Add(type, list); - } - - list.Add(engine); - } - } - - void AddEntityViewsToTheDBAndSuitableEngines(Dictionary entityViewsToAdd, - Dictionary entityViewsDB) - { - foreach (var entityViewList in entityViewsToAdd) - { - AddEntityViewToDB(entityViewsDB, entityViewList); - - if (entityViewList.Value.isQueryiableEntityView) - { - AddEntityViewToEntityViewsDictionary(_entityViewsDBdic, entityViewList.Value, entityViewList.Key); - } - } - - foreach (var entityViewList in entityViewsToAdd) - { - if (entityViewList.Value.isQueryiableEntityView) - { - AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, - entityViewList.Key); - } - } - } - - void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary> groupedEntityViewsToAdd, - Dictionary> groupEntityViewsDB, - Dictionary entityViewsDB) - { - foreach (var group in groupedEntityViewsToAdd) - { - AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); - - AddEntityViewsToGroupDB(groupEntityViewsDB, @group); - } - } - - static void AddEntityViewsToGroupDB(Dictionary> groupEntityViewsDB, - KeyValuePair> @group) - { - Dictionary groupedEntityViewsByType; - - if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) - groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary(); - - foreach (var entityView in @group.Value) - { - groupedEntityViewsByType.Add(entityView.Key, entityView.Value); - } - } - - static void AddEntityViewToDB(Dictionary entityViewsDB, KeyValuePair entityViewList) - { - ITypeSafeList dbList; - - if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) - dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); - - dbList.AddRange(entityViewList.Value); - } - - static void AddEntityViewToEntityViewsDictionary(Dictionary entityViewsDBdic, - ITypeSafeList entityViews, Type entityViewType) - { - ITypeSafeDictionary entityViewsDic; - - if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) - entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); - - entityViewsDic.FillWithIndexedEntityViews(entityViews); - } - - static void AddEntityViewToTheSuitableEngines(Dictionary> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) - { - FasterList enginesForEntityView; - - if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) - { - int viewsCount; - - var entityViews = entityViewsList.ToArrayFast(out viewsCount); - - for (int i = 0; i < viewsCount; i++) - { - int count; - var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); - IEntityView entityView = entityViews[i]; - for (int j = 0; j < count; j++) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorAddDuration(_addEntityViewToEngine, fastList[j], entityView); -#else - fastList[j].Add(entityView); -#endif - } - } - } - } - - void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, - Dictionary entityViewsDB) - { - int entityViewBuildersCount = entityViewBuilders.Length; - - for (int i = 0; i < entityViewBuildersCount; i++) - { - Type entityViewType = entityViewBuilders[i].GetEntityViewType(); - - ITypeSafeList entityViews = entityViewsDB[entityViewType]; - if (entityViews.UnorderedRemove(entityID) == false) - entityViewsDB.Remove(entityViewType); - - if (entityViews.isQueryiableEntityView) - { - var typeSafeDictionary = _entityViewsDBdic[entityViewType]; - var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); - - if (typeSafeDictionary.Remove(entityID) == false) - _entityViewsDBdic.Remove(entityViewType); - - RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType); - } - } - } - - void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, - Dictionary entityViewsDB) - { - int entityViewBuildersCount = entityViewBuilders.Length; - - for (int i = 0; i < entityViewBuildersCount; i++) - { - Type entityViewType = entityViewBuilders[i].GetEntityViewType(); - Dictionary dictionary = _groupEntityViewsDB[groupID]; - - if (dictionary[entityViewType].UnorderedRemove(entityID) == false) - dictionary.Remove(entityViewType); - - if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); - } - - InternalRemove(entityViewBuilders, entityID, entityViewsDB); - } - - static void RemoveEntityViewFromEngines(Dictionary> entityViewEngines, - IEntityView entityView, Type entityViewType) - { - FasterList enginesForEntityView; - - if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) - { - int count; - var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); - - for (int j = 0; j < count; j++) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(_removeEntityViewFromEngine, fastList[j], entityView); -#else - fastList[j].Remove(entityView); -#endif - } - } - } - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - static void AddEntityViewToEngine(IHandleEntityViewEngine engine, IEntityView entityView) - { - engine.Add(entityView); - } - - static void RemoveEntityViewFromEngine(IHandleEntityViewEngine engine, IEntityView entityView) - { - engine.Remove(entityView); - } -#endif - - void SubmitEntityViews() - { - bool newEntityViewsHaveBeenAddedWhileIterating = - _metaEntityViewsToAdd.current.Count > 0 - || _entityViewsToAdd.current.Count > 0 - || _groupedEntityViewsToAdd.current.Count > 0; - - int numberOfReenteringLoops = 0; - - while (newEntityViewsHaveBeenAddedWhileIterating) - { - //use other as source from now on - //current will be use to write new entityViews - _entityViewsToAdd.Swap(); - _metaEntityViewsToAdd.Swap(); - _groupedEntityViewsToAdd.Swap(); - - if ( _entityViewsToAdd.other.Count > 0) - AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB); - - if ( _metaEntityViewsToAdd.other.Count > 0) - AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); - - if (_groupedEntityViewsToAdd.other.Count > 0) - AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); - - //other can be cleared now - _entityViewsToAdd.other.Clear(); - _metaEntityViewsToAdd.other.Clear(); - _groupedEntityViewsToAdd.other.Clear(); - - //has current new entityViews? - newEntityViewsHaveBeenAddedWhileIterating = - _metaEntityViewsToAdd.current.Count > 0 - || _entityViewsToAdd.current.Count > 0 - || _groupedEntityViewsToAdd.current.Count > 0; - - if (numberOfReenteringLoops > 5) - throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); - - numberOfReenteringLoops++; - } - } - - readonly Dictionary> _entityViewEngines; - - readonly FasterList _otherEngines; - - readonly Dictionary _entityViewsDB; - readonly Dictionary _metaEntityViewsDB; - readonly Dictionary> _groupEntityViewsDB; - - readonly Dictionary _entityViewsDBdic; - - readonly DoubleBufferedEntityViews> _entityViewsToAdd; - readonly DoubleBufferedEntityViews> _metaEntityViewsToAdd; - readonly DoubleBufferedEntityViews>> _groupedEntityViewsToAdd; - - readonly EntitySubmissionScheduler _scheduler; -#if EXPERIMENTAL - readonly Type _structEntityViewEngineType; - readonly Type _groupedStructEntityViewsEngineType; - - readonly SharedStructEntityViewLists _sharedStructEntityViewLists; - readonly SharedGroupedStructEntityViewsLists _sharedGroupedStructEntityViewLists; - - readonly Dictionary _implementedInterfaceTypes; -#endif - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - static Action _addEntityViewToEngine; - static Action _removeEntityViewFromEngine; -#endif - readonly EngineEntityViewDB _engineEntityViewDB; - - class DoubleBufferedEntityViews where T : class, IDictionary, new() - { - readonly T _entityViewsToAddBufferA = new T(); - readonly T _entityViewsToAddBufferB = new T(); - - public DoubleBufferedEntityViews() - { - this.other = _entityViewsToAddBufferA; - this.current = _entityViewsToAddBufferB; - } - - public T other { get; private set; } - public T current { get; private set; } - - public void Swap() - { - var toSwap = other; - other = current; - current = toSwap; - } - } - - class GenericEntityFactory : IEntityFactory - { - DataStructures.WeakReference _weakEngine; - - public GenericEntityFactory(DataStructures.WeakReference weakReference) - { - _weakEngine = weakReference; - } - - public void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() - { - _weakEngine.Target.BuildEntity(entityID, implementors); - } - - public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - _weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); - } - - public void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() - { - _weakEngine.Target.BuildMetaEntity(metaEntityID, implementors); - } - - public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() - { - _weakEngine.Target.BuildEntityInGroup(entityID, groupID, implementors); - } - - public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); - } - - public void Preallocate(int size) where T : IEntityDescriptor, new() - { - _weakEngine.Target.Preallocate(size); - } - } - - class GenericEntityFunctions : IEntityFunctions - { - public GenericEntityFunctions(DataStructures.WeakReference weakReference) - { - _weakReference = weakReference; - } - - public void RemoveEntity(int entityID, IRemoveEntityComponent entityTemplate) - { - _weakReference.Target.RemoveEntity(entityID, entityTemplate); - } - - public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() - { - _weakReference.Target.RemoveEntity(entityID); - } - - public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() - { - _weakReference.Target.RemoveEntity(metaEntityID); - } - - public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() - { - _weakReference.Target.RemoveEntity(entityID); - } - - readonly DataStructures.WeakReference _weakReference; - } - - public void Dispose() - { - foreach (var entity in _entityViewsDB) - { - if (entity.Value.isQueryiableEntityView == true) - { - foreach (var entityView in entity.Value) - { - RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); - } - } - } - - foreach (var entity in _metaEntityViewsDB) - { - foreach (var entityView in entity.Value) - { - RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); - } - } - } - } -} \ No newline at end of file diff --git a/ECS/EnginesRootEngines.cs b/ECS/EnginesRootEngines.cs new file mode 100644 index 0000000..fb47ffe --- /dev/null +++ b/ECS/EnginesRootEngines.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; +using Svelto.ECS.Schedulers; +using Svelto.Utilities; +using Svelto.WeakEvents; + +#if EXPERIMENTAL +using Svelto.ECS.Experimental; +using Svelto.ECS.Experimental.Internal; +#endif + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +using Svelto.ECS.Profiler; +#endif + +namespace Svelto.ECS +{ + public partial class EnginesRoot : IDisposable + { + /// + /// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot + /// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks + /// periodically if new entity must be submited to the database and the engines. It's an external + /// dependencies to be indipendent by the running platform as the user can define it. + /// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why + /// it must receive a weak reference of the EnginesRoot callback. + /// + public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) + { + _entityViewEngines = new Dictionary>(); + _otherEngines = new FasterList(); + + _entityViewsDB = new Dictionary(); + _metaEntityViewsDB = new Dictionary(); + _groupEntityViewsDB = new Dictionary>(); + _entityViewsDBdic = new Dictionary(); + + _entityViewsToAdd = new DoubleBufferedEntityViews>(); + _metaEntityViewsToAdd = new DoubleBufferedEntityViews>(); + _groupedEntityViewsToAdd = new DoubleBufferedEntityViews>>(); + + _engineEntityViewDB = new EngineEntityViewDB(_entityViewsDB, _entityViewsDBdic, _metaEntityViewsDB, _groupEntityViewsDB); + + _scheduler = entityViewScheduler; + _scheduler.Schedule(new WeakAction(SubmitEntityViews)); +#if EXPERIMENTAL + _sharedStructEntityViewLists = new SharedStructEntityViewLists(); + _sharedGroupedStructEntityViewLists = new SharedGroupedStructEntityViewsLists(); + + _structEntityViewEngineType = typeof(IStructEntityViewEngine<>); + _groupedStructEntityViewsEngineType = typeof(IGroupedStructEntityViewsEngine<>); + + _implementedInterfaceTypes = new Dictionary(); +#endif +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + _addEntityViewToEngine = AddEntityViewToEngine; + _removeEntityViewFromEngine = RemoveEntityViewFromEngine; + + UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); + debugEngineObject.gameObject.AddComponent(); +#endif + } + + public void AddEngine(IEngine engine) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + Profiler.EngineProfiler.AddEngine(engine); +#endif + var engineType = engine.GetType(); +#if EXPERIMENTAL + bool engineAdded; + + var implementedInterfaces = engineType.GetInterfaces(); + + CollectImplementedInterfaces(implementedInterfaces); + + engineAdded = CheckSpecialEngine(engine); +#endif + var viewEngine = engine as IHandleEntityViewEngine; + + if (viewEngine != null) + CheckEntityViewsEngine(viewEngine, engineType); + else + _otherEngines.Add(engine); + + var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; + if (queryableEntityViewEngine != null) + { + queryableEntityViewEngine.entityViewsDB = _engineEntityViewDB; + queryableEntityViewEngine.Ready(); + } + } + +#if EXPERIMENTAL + void CollectImplementedInterfaces(Type[] implementedInterfaces) + { + _implementedInterfaceTypes.Clear(); + + var type = typeof(IHandleEntityViewEngine); + + for (int index = 0; index < implementedInterfaces.Length; index++) + { + var interfaceType = implementedInterfaces[index]; + + if (type.IsAssignableFrom(interfaceType) == false) + continue; + + if (false == interfaceType.IsGenericTypeEx()) + { + continue; + } + + var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); + + _implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); + } + } + + bool CheckSpecialEngine(IEngine engine) + { + if (_implementedInterfaceTypes.Count == 0) return false; + + bool engineAdded = false; + + if (_implementedInterfaceTypes.ContainsKey(_structEntityViewEngineType)) + { + ((IStructEntityViewEngine)engine).CreateStructEntityViews + (_sharedStructEntityViewLists); + } + + if (_implementedInterfaceTypes.ContainsKey(_groupedStructEntityViewsEngineType)) + { + ((IGroupedStructEntityViewsEngine)engine).CreateStructEntityViews + (_sharedGroupedStructEntityViewLists); + } + + return engineAdded; + } +#endif + void CheckEntityViewsEngine(IEngine engine, Type engineType) + { + var baseType = engineType.GetBaseType(); + + if (baseType.IsGenericTypeEx()) + { + var genericArguments = baseType.GetGenericArguments(); + AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); +#if EXPERIMENTAL + var activableEngine = engine as IHandleActivableEntityEngine; + if (activableEngine != null) + AddEngine(activableEngine, genericArguments, _activableViewEntitiesEngines); +#endif + + return; + } + + throw new Exception("Not Supported Engine"); + } + + //The T parameter allows to pass datastructure sthat not necessarly are + //defined with IEngine, but must be defined with IEngine implementations + static void AddEngine(T engine, Type[] types, + Dictionary> engines) where T:IEngine + { + for (int i = 0; i < types.Length; i++) + { + FasterList list; + + var type = types[i]; + + if (engines.TryGetValue(type, out list) == false) + { + list = new FasterList(); + + engines.Add(type, list); + } + + list.Add(engine); + } + } + + readonly Dictionary> _entityViewEngines; + + readonly FasterList _otherEngines; + + readonly Dictionary _entityViewsDB; + readonly Dictionary _metaEntityViewsDB; + readonly Dictionary> _groupEntityViewsDB; + + readonly Dictionary _entityViewsDBdic; + + readonly DoubleBufferedEntityViews> _entityViewsToAdd; + readonly DoubleBufferedEntityViews> _metaEntityViewsToAdd; + readonly DoubleBufferedEntityViews>> _groupedEntityViewsToAdd; + + readonly EntitySubmissionScheduler _scheduler; +#if EXPERIMENTAL + readonly Type _structEntityViewEngineType; + readonly Type _groupedStructEntityViewsEngineType; + + readonly SharedStructEntityViewLists _sharedStructEntityViewLists; + readonly SharedGroupedStructEntityViewsLists _sharedGroupedStructEntityViewLists; + + readonly Dictionary _implementedInterfaceTypes; +#endif + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + static Action _addEntityViewToEngine; + static Action _removeEntityViewFromEngine; +#endif + readonly EngineEntityViewDB _engineEntityViewDB; + + class DoubleBufferedEntityViews where T : class, IDictionary, new() + { + readonly T _entityViewsToAddBufferA = new T(); + readonly T _entityViewsToAddBufferB = new T(); + + internal DoubleBufferedEntityViews() + { + this.other = _entityViewsToAddBufferA; + this.current = _entityViewsToAddBufferB; + } + + internal T other; + internal T current; + + internal void Swap() + { + var toSwap = other; + other = current; + current = toSwap; + } + } + } +} \ No newline at end of file diff --git a/ECS/EnginesRootEntities.cs b/ECS/EnginesRootEntities.cs new file mode 100644 index 0000000..7d258ab --- /dev/null +++ b/ECS/EnginesRootEntities.cs @@ -0,0 +1,337 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; + +#if EXPERIMENTAL +using Svelto.ECS.Experimental; +using Svelto.ECS.Experimental.Internal; +#endif + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +using Svelto.ECS.Profiler; +#endif + +namespace Svelto.ECS +{ + public partial class EnginesRoot : IDisposable + { + /// + /// an EnginesRoot reference cannot be held by anything else than the Composition Root + /// where it has been created. IEntityFactory and IEntityFunctions allow a weakreference + /// of the EnginesRoot to be passed around. + /// + /// + public IEntityFactory GenerateEntityFactory() + { + return new GenericEntityFactory(new DataStructures.WeakReference(this)); + } + + public IEntityFunctions GenerateEntityFunctions() + { + return new GenericEntityFunctions(new DataStructures.WeakReference(this)); + } + + /// + /// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity + /// itself in terms of EntityViews to build. The Implementors are passed to fill the + /// references of the EntityViews components. Please read the articles on my blog + /// to understand better the terminologies + /// + /// + /// + /// + void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, EntityDescriptorTemplate.Default, implementors); + } + + /// + /// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo + /// can be built in place of the generic parameter T. + /// + /// + /// + /// + void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, entityDescriptor, implementors); + } + + /// + /// A meta entity is a way to manage a set of entitites that are not easily + /// queriable otherwise. For example you may want to group existing entities + /// by size and type and then use the meta entity entityView to manage the data + /// shared among the single entities of the same type and size. This will + /// prevent the scenario where the coder is forced to parse all the entities to + /// find the ones of the same size and type. + /// Since the entities are managed through the shared entityView, the same + /// shared entityView must be found on the single entities of the same type and size. + /// The shared entityView of the meta entity is then used by engines that are meant + /// to manage a group of entities through a single entityView. + /// The same engine can manage several meta entities entityViews too. + /// The Engine manages the logic of the Meta EntityView data and other engines + /// can read back this data through the normal entity as the shared entityView + /// will be present in their descriptor too. + /// It's a way to control a group of Entities through a entityView only. + /// This set of entities can share exactly the same entityView reference if + /// built through this function. In this way, if you need to set a variable + /// on a group of entities, instead to inject N entityViews and iterate over + /// them to set the same value, you can inject just one entityView, set the value + /// and be sure that the value is shared between entities. + /// + /// + /// + /// + void BuildMetaEntity(int metaEntityID, object[] implementors) where T : IEntityDescriptor, new() + { + EntityFactory.BuildEntityViews(metaEntityID, _entityViewsToAdd.current, + EntityDescriptorTemplate.Default, implementors); + } + + /// + /// Using this function is like building a normal entity, but the entityViews + /// are grouped by groupID to be more efficently processed inside engines and + /// improve cache locality. Either class entityViews and struct entityViews can be + /// grouped. + /// + /// + /// + /// + /// + void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() + { + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + EntityDescriptorTemplate.Default, + implementors); + } + + void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + entityDescriptor, implementors); + } + + void Preallocate(int size) where T : IEntityDescriptor, new() + { + var entityViewsToBuild = EntityDescriptorTemplate.Default.entityViewsToBuild; + int count = entityViewsToBuild.Length; + + for (int index = 0; index < count; index++) + { + var entityViewBuilder = entityViewsToBuild[index]; + var entityViewType = entityViewBuilder.GetEntityViewType(); + + ITypeSafeList dbList; + if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) + _entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); + else + dbList.ReserveCapacity(size); + + if (_entityViewsToAdd.current.TryGetValue(entityViewType, out dbList) == false) + _entityViewsToAdd.current[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); + else + dbList.ReserveCapacity(size); + } + } + + void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) + { + var removeEntityImplementor = removeInfo as RemoveEntityImplementor; + + if (removeEntityImplementor.isInAGroup) + InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, removeEntityImplementor.groupID, _entityViewsDB); + else + InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, _entityViewsDB); + } + + void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.entityViewsToBuild, entityID, _entityViewsDB); + } + + void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.entityViewsToBuild, metaEntityID, _metaEntityViewsDB); + } + + void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); + } + + void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, + Dictionary entityViewsDB) + { + int entityViewBuildersCount = entityViewBuilders.Length; + + for (int i = 0; i < entityViewBuildersCount; i++) + { + Type entityViewType = entityViewBuilders[i].GetEntityViewType(); + + ITypeSafeList entityViews = entityViewsDB[entityViewType]; + if (entityViews.UnorderedRemove(entityID) == false) + entityViewsDB.Remove(entityViewType); + + if (entityViews.isQueryiableEntityView) + { + var typeSafeDictionary = _entityViewsDBdic[entityViewType]; + var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); + + if (typeSafeDictionary.Remove(entityID) == false) + _entityViewsDBdic.Remove(entityViewType); + + RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType); + } + } + } + + void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, + Dictionary entityViewsDB) + { + int entityViewBuildersCount = entityViewBuilders.Length; + + for (int i = 0; i < entityViewBuildersCount; i++) + { + Type entityViewType = entityViewBuilders[i].GetEntityViewType(); + Dictionary dictionary = _groupEntityViewsDB[groupID]; + + if (dictionary[entityViewType].UnorderedRemove(entityID) == false) + dictionary.Remove(entityViewType); + + if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); + } + + InternalRemove(entityViewBuilders, entityID, entityViewsDB); + } + + static void RemoveEntityViewFromEngines(Dictionary> entityViewEngines, + IEntityView entityView, Type entityViewType) + { + FasterList enginesForEntityView; + + if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) + { + int count; + var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); + + for (int j = 0; j < count; j++) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + EngineProfiler.MonitorRemoveDuration(_removeEntityViewFromEngine, fastList[j], entityView); +#else + fastList[j].Remove(entityView); +#endif + } + } + } + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + static void AddEntityViewToEngine(IHandleEntityViewEngine engine, IEntityView entityView) + { + engine.Add(entityView); + } + + static void RemoveEntityViewFromEngine(IHandleEntityViewEngine engine, IEntityView entityView) + { + engine.Remove(entityView); + } +#endif + + class GenericEntityFactory : IEntityFactory + { + DataStructures.WeakReference _weakEngine; + + public GenericEntityFactory(DataStructures.WeakReference weakReference) + { + _weakEngine = weakReference; + } + + public void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildEntity(entityID, implementors); + } + + public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + _weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); + } + + public void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildMetaEntity(metaEntityID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); + } + + public void Preallocate(int size) where T : IEntityDescriptor, new() + { + _weakEngine.Target.Preallocate(size); + } + } + + class GenericEntityFunctions : IEntityFunctions + { + public GenericEntityFunctions(DataStructures.WeakReference weakReference) + { + _weakReference = weakReference; + } + + public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) + { + _weakReference.Target.RemoveEntity(entityID, removeInfo); + } + + public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(metaEntityID); + } + + public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + readonly DataStructures.WeakReference _weakReference; + } + + public void Dispose() + { + foreach (var entity in _entityViewsDB) + { + if (entity.Value.isQueryiableEntityView == true) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } + } + } + + foreach (var entity in _metaEntityViewsDB) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } + } + } + } +} \ No newline at end of file diff --git a/ECS/EnginesRootSubmission.cs b/ECS/EnginesRootSubmission.cs new file mode 100644 index 0000000..c0c7641 --- /dev/null +++ b/ECS/EnginesRootSubmission.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; + +#if EXPERIMENTAL +using Svelto.ECS.Experimental; +using Svelto.ECS.Experimental.Internal; +#endif + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +using Svelto.ECS.Profiler; +#endif + +namespace Svelto.ECS +{ + public partial class EnginesRoot : IDisposable + { + void SubmitEntityViews() + { + bool newEntityViewsHaveBeenAddedWhileIterating = + _metaEntityViewsToAdd.current.Count > 0 + || _entityViewsToAdd.current.Count > 0 + || _groupedEntityViewsToAdd.current.Count > 0; + + int numberOfReenteringLoops = 0; + + while (newEntityViewsHaveBeenAddedWhileIterating) + { + //use other as source from now on + //current will be use to write new entityViews + _entityViewsToAdd.Swap(); + _metaEntityViewsToAdd.Swap(); + _groupedEntityViewsToAdd.Swap(); + + if (_entityViewsToAdd.other.Count > 0) + AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB); + + if (_metaEntityViewsToAdd.other.Count > 0) + AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); + + if (_groupedEntityViewsToAdd.other.Count > 0) + AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); + + //other can be cleared now + _entityViewsToAdd.other.Clear(); + _metaEntityViewsToAdd.other.Clear(); + _groupedEntityViewsToAdd.other.Clear(); + + //has current new entityViews? + newEntityViewsHaveBeenAddedWhileIterating = + _metaEntityViewsToAdd.current.Count > 0 + || _entityViewsToAdd.current.Count > 0 + || _groupedEntityViewsToAdd.current.Count > 0; + + if (numberOfReenteringLoops > 5) + throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); + + numberOfReenteringLoops++; + } + } + + void AddEntityViewsToTheDBAndSuitableEngines(Dictionary entityViewsToAdd, + Dictionary entityViewsDB) + { + foreach (var entityViewList in entityViewsToAdd) + { + AddEntityViewToDB(entityViewsDB, entityViewList); + + if (entityViewList.Value.isQueryiableEntityView) + { + AddEntityViewToEntityViewsDictionary(_entityViewsDBdic, entityViewList.Value, entityViewList.Key); + } + } + + foreach (var entityViewList in entityViewsToAdd) + { + if (entityViewList.Value.isQueryiableEntityView) + { + AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, + entityViewList.Key); + } + } + } + + void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary> groupedEntityViewsToAdd, + Dictionary> groupEntityViewsDB, + Dictionary entityViewsDB) + { + foreach (var group in groupedEntityViewsToAdd) + { + AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); + + AddEntityViewsToGroupDB(groupEntityViewsDB, @group); + } + } + + static void AddEntityViewsToGroupDB(Dictionary> groupEntityViewsDB, + KeyValuePair> @group) + { + Dictionary groupedEntityViewsByType; + + if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) + groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary(); + + foreach (var entityView in @group.Value) + { + groupedEntityViewsByType.Add(entityView.Key, entityView.Value); + } + } + + static void AddEntityViewToDB(Dictionary entityViewsDB, KeyValuePair entityViewList) + { + ITypeSafeList dbList; + + if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) + dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); + + dbList.AddRange(entityViewList.Value); + } + + static void AddEntityViewToEntityViewsDictionary(Dictionary entityViewsDBdic, + ITypeSafeList entityViews, Type entityViewType) + { + ITypeSafeDictionary entityViewsDic; + + if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) + entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); + + entityViewsDic.FillWithIndexedEntityViews(entityViews); + } + + static void AddEntityViewToTheSuitableEngines(Dictionary> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) + { + FasterList enginesForEntityView; + + if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) + { + int viewsCount; + + var entityViews = entityViewsList.ToArrayFast(out viewsCount); + + for (int i = 0; i < viewsCount; i++) + { + int count; + var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); + IEntityView entityView = entityViews[i]; + for (int j = 0; j < count; j++) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + EngineProfiler.MonitorAddDuration(_addEntityViewToEngine, fastList[j], entityView); +#else + fastList[j].Add(entityView); +#endif + } + } + } + } + } +} \ No newline at end of file diff --git a/ECS/EntityDescriptorTemplate.cs b/ECS/EntityDescriptorTemplate.cs index 3c20589..d917577 100644 --- a/ECS/EntityDescriptorTemplate.cs +++ b/ECS/EntityDescriptorTemplate.cs @@ -1,3 +1,5 @@ +using Svelto.DataStructures; +using Svelto.ECS.Internal; using System; using System.Collections.Generic; @@ -8,20 +10,22 @@ namespace Svelto.ECS IEntityViewBuilder[] entityViewsToBuild { get; } } - static class EntityDescriptorTemplate where TType : IEntityDescriptor, new() + internal static class EntityDescriptorTemplate where TType : IEntityDescriptor, new() { public static readonly EntityDescriptorInfo Default = new EntityDescriptorInfo(new TType()); } public class EntityDescriptorInfo { - public readonly IEntityDescriptor descriptor; - public readonly string name; + readonly internal IEntityViewBuilder[] entityViewsToBuild; + readonly internal RemoveEntityImplementor removeEntityImplementor; + internal readonly string name; - public EntityDescriptorInfo(IEntityDescriptor entityDescriptor) + internal EntityDescriptorInfo(IEntityDescriptor descriptor) { - descriptor = entityDescriptor; name = descriptor.ToString(); + entityViewsToBuild = descriptor.entityViewsToBuild; + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuild); } } } @@ -31,11 +35,11 @@ namespace Svelto.ECS.Internal static class EntityFactory { internal static void BuildGroupedEntityViews(int entityID, int groupID, - Dictionary> groupEntityViewsByType, + Dictionary> groupEntityViewsByType, EntityDescriptorInfo entityViewsToBuildDescriptor, object[] implementors) { - var entityViewsToBuild = entityViewsToBuildDescriptor.descriptor.entityViewsToBuild; + var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; int count = entityViewsToBuild.Length; RemoveEntityImplementor removeEntityImplementor = null; @@ -53,6 +57,8 @@ namespace Svelto.ECS.Internal groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); } + //only class EntityView will be returned + //struct EntityView cannot be filled so it will be null. var entityViewObjectToFill = BuildEntityView(entityID, groupedEntityViewsTyped, entityViewType, entityViewBuilder); @@ -62,7 +68,7 @@ namespace Svelto.ECS.Internal if (entityViewObjectToFill != null) { if (removeEntityImplementor == null) - removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.descriptor, groupID); + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.entityViewsToBuild, groupID); FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, entityViewsToBuildDescriptor.name); @@ -70,20 +76,21 @@ namespace Svelto.ECS.Internal } } - internal static void BuildEntityViews(int entityID, Dictionary entityViewsByType, + internal static void BuildEntityViews(int entityID, + Dictionary entityViewsByType, EntityDescriptorInfo entityViewsToBuildDescriptor, object[] implementors) { - var entityViewsToBuild = entityViewsToBuildDescriptor.descriptor.entityViewsToBuild; + var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; int count = entityViewsToBuild.Length; - RemoveEntityImplementor removeEntityImplementor = null; - for (int index = 0; index < count; index++) { var entityViewBuilder = entityViewsToBuild[index]; var entityViewType = entityViewBuilder.GetEntityViewType(); + //only class EntityView will be returned + //struct EntityView cannot be filled so it will be null. var entityViewObjectToFill = BuildEntityView(entityID, entityViewsByType, entityViewType, entityViewBuilder); @@ -92,23 +99,26 @@ namespace Svelto.ECS.Internal //it's a EntityView if (entityViewObjectToFill != null) { - if (removeEntityImplementor == null) - removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.descriptor); - - FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, + FillEntityView(entityViewObjectToFill as EntityView, implementors, entityViewsToBuildDescriptor.removeEntityImplementor, entityViewsToBuildDescriptor.name); } } } static IEntityView BuildEntityView(int entityID, Dictionary entityViewsByType, - Type entityViewType, IEntityViewBuilder entityViewBuilderId) + Type entityViewType, IEntityViewBuilder entityViewBuilder) { ITypeSafeList entityViewsList; var entityViewsPoolWillBeCreated = entityViewsByType.TryGetValue(entityViewType, out entityViewsList) == false; - var entityViewObjectToFill = entityViewBuilderId.BuildEntityViewAndAddToList(ref entityViewsList, entityID); + + IEntityView entityViewObjectToFill; + + //passing the undefined entityViewsByType inside the entityViewBuilder will allow + //it to be created with the correct type and casted back to the undefined list. + //that's how the list will be eventually of the target type. + entityViewBuilder.BuildEntityViewAndAddToList(ref entityViewsList, entityID, out entityViewObjectToFill); if (entityViewsPoolWillBeCreated) entityViewsByType.Add(entityViewType, entityViewsList); @@ -116,6 +126,13 @@ namespace Svelto.ECS.Internal return entityViewObjectToFill as IEntityView; } + //this is used to avoid newing a dictionary every time, but it's used locally only and it's clearead for each use +#if DEBUG && !PROFILER + static readonly Dictionary> implementorsByType = new Dictionary>(); +#else + static readonly Dictionary implementorsByType = new Dictionary(); +#endif + static void FillEntityView(EntityView entityView, object[] implementors, RemoveEntityImplementor removeEntity, string entityDescriptorName) { @@ -136,12 +153,16 @@ namespace Svelto.ECS.Internal var componentType = interfaces[iindex]; #if DEBUG && !PROFILER Tuple implementorHolder; + if (implementorsByType.TryGetValue(componentType, out implementorHolder) == true) implementorHolder.item2++; else + implementorsByType[componentType] = new Tuple(implementor, 1); +#else + implementorsByType[componentType] = implementor; #endif - implementorsByType[componentType] = new Tuple(implementor, 0); + } } #if DEBUG && !PROFILER @@ -153,8 +174,8 @@ namespace Svelto.ECS.Internal int count; //Very efficent way to collect the fields of every EntityViewType - KeyValuePair>[] setters = - entityView.EntityViewBlazingFastReflection(out count); + KeyValuePair>[] setters = + FasterList>>.NoVirt.ToArrayFast(entityView.EntityViewBlazingFastReflection, out count); var removeEntityComponentType = typeof(IRemoveEntityComponent); @@ -211,13 +232,7 @@ namespace Svelto.ECS.Internal item2 = v; } } -#endif - //this is used to avoid newing a dictionary every time, but it's used locally only -#if DEBUG && !PROFILER - static readonly Dictionary> implementorsByType = new Dictionary>(); -#else - static readonly Dictionary implementorsByType = new Dictionary(); -#endif +#endif static Dictionary _cachedTypes = new Dictionary(); const string DUPLICATE_IMPLEMENTOR_ERROR = diff --git a/ECS/EntityView.cs b/ECS/EntityView.cs index 445781c..5891198 100644 --- a/ECS/EntityView.cs +++ b/ECS/EntityView.cs @@ -20,19 +20,17 @@ namespace Svelto.ECS { public int ID { get { return _ID; } } - abstract internal KeyValuePair>[] - EntityViewBlazingFastReflection(out int count); - - protected int _ID; + internal FasterList>> EntityViewBlazingFastReflection; + internal int _ID; } - public class EntityView: EntityView where T: EntityView + internal static class EntityView where T: EntityView, new() { - internal static TEntityViewType BuildEntityView(int ID) where TEntityViewType: EntityView, new() + internal static T BuildEntityView(int ID) { - if (FieldCache.list.Count == 0) + if (FieldCache.list.Count == 0) { - var type = typeof(TEntityViewType); + var type = typeof(T); var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); @@ -43,26 +41,15 @@ namespace Svelto.ECS Action setter = FastInvoke.MakeSetter(field); - FieldCache.Add(new KeyValuePair>(field.FieldType, setter)); + FieldCache.list.Add(new KeyValuePair>(field.FieldType, setter)); } } - return new TEntityViewType { _ID = ID }; - } - - override internal KeyValuePair>[] - EntityViewBlazingFastReflection(out int count) - { - return FasterList>>.NoVirt.ToArrayFast(FieldCache.list, out count); + return new T { _ID = ID, EntityViewBlazingFastReflection = FieldCache.list }; } - static class FieldCache + static class FieldCache where W:T { - internal static void Add(KeyValuePair> setter) - { - list.Add(setter); - } - internal static readonly FasterList>> list = new FasterList>>(); } } diff --git a/ECS/EntityViewBuilder.cs b/ECS/EntityViewBuilder.cs index 48ce2dd..6b02a66 100644 --- a/ECS/EntityViewBuilder.cs +++ b/ECS/EntityViewBuilder.cs @@ -5,26 +5,26 @@ namespace Svelto.ECS { public interface IEntityViewBuilder { - IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID); + void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView); ITypeSafeList Preallocate(ref ITypeSafeList list, int size); Type GetEntityViewType(); } - public class EntityViewBuilder : IEntityViewBuilder where EntityViewType : EntityView, new() + public class EntityViewBuilder : IEntityViewBuilder where EntityViewType : EntityView, new() { - public IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID) + public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) { if (list == null) list = new TypeSafeFasterListForECSForClasses(); var castedList = list as TypeSafeFasterListForECSForClasses; - var entityView = EntityView.BuildEntityView(entityID); + var lentityView = EntityView.BuildEntityView(entityID); - castedList.Add(entityView); + castedList.Add(lentityView); - return entityView; + entityView = lentityView; } public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) @@ -47,19 +47,19 @@ namespace Svelto.ECS public class EntityStructBuilder : IEntityViewBuilder where EntityViewType : struct, IEntityStruct { - public IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID) + public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) { - var entityView = default(EntityViewType); - entityView.ID = entityID; + var lentityView = default(EntityViewType); + lentityView.ID = entityID; if (list == null) list = new TypeSafeFasterListForECSForStructs(); var castedList = list as TypeSafeFasterListForECSForStructs; - castedList.Add(entityView); + castedList.Add(lentityView); - return null; + entityView = null; } public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) diff --git a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs b/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs index 8a6c173..a2dcf89 100644 --- a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs +++ b/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs @@ -13,7 +13,7 @@ namespace Svelto.ECS.Schedulers //the entityViews immediatly just because convenient for your game //logic. This is not how it works. - public class UnitySumbmissionEntityViewScheduler : EntityViewSubmissionScheduler + public class UnitySumbmissionEntityViewScheduler : EntitySubmissionScheduler { public UnitySumbmissionEntityViewScheduler() { diff --git a/ECS/GenericEntityDescriptor.cs b/ECS/GenericEntityDescriptor.cs index da643e9..a717870 100644 --- a/ECS/GenericEntityDescriptor.cs +++ b/ECS/GenericEntityDescriptor.cs @@ -2,7 +2,7 @@ namespace Svelto.ECS { - public class GenericEntityDescriptor:IEntityDescriptor where T : EntityView, new() + public class GenericEntityDescriptor:IEntityDescriptor where T : EntityView, new() { static GenericEntityDescriptor() { @@ -18,8 +18,8 @@ namespace Svelto.ECS } - public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() - where U : EntityView, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() { static GenericEntityDescriptor() { @@ -34,9 +34,9 @@ namespace Svelto.ECS public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() - where U : EntityView, new() - where V : EntityView, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() { static GenericEntityDescriptor() { @@ -51,10 +51,10 @@ namespace Svelto.ECS public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() - where U : EntityView, new() - where V : EntityView, new() - where W : EntityView, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() { static GenericEntityDescriptor() { @@ -69,11 +69,11 @@ namespace Svelto.ECS public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() - where U : EntityView, new() - where V : EntityView, new() - where W : EntityView, new() - where X : EntityView, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() + where X : EntityView, new() { static GenericEntityDescriptor() { @@ -88,12 +88,12 @@ namespace Svelto.ECS public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() - where U : EntityView, new() - where V : EntityView, new() - where W : EntityView, new() - where X : EntityView, new() - where Y : EntityView, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() + where X : EntityView, new() + where Y : EntityView, new() { static GenericEntityDescriptor() { diff --git a/ECS/IEngineEntityViewDB.cs b/ECS/IEngineEntityViewDB.cs index ddbf011..571f3f8 100644 --- a/ECS/IEngineEntityViewDB.cs +++ b/ECS/IEngineEntityViewDB.cs @@ -4,9 +4,9 @@ namespace Svelto.ECS { public interface IEngineEntityViewDB { - FasterReadOnlyList QueryEntityViews() where T:EntityView, new(); - FasterReadOnlyList QueryMetaEntityViews() where T: EntityView, new(); - FasterReadOnlyList QueryGroupedEntityViews(int group) where T: EntityView, new(); + FasterReadOnlyList QueryEntityViews() where T:EntityView, new(); + FasterReadOnlyList QueryMetaEntityViews() where T: EntityView, new(); + FasterReadOnlyList QueryGroupedEntityViews(int group) where T: EntityView, new(); T[] QueryEntityViewsAsArray(out int count) where T: IEntityView; T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T: IEntityView; @@ -15,8 +15,8 @@ namespace Svelto.ECS bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView; T QueryEntityView(int ID) where T: IEntityView; - bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T: EntityView, new(); - T QueryMetaEntityView(int metaEntityID) where T: EntityView, new(); + bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T: EntityView, new(); + T QueryMetaEntityView(int metaEntityID) where T: EntityView, new(); } } diff --git a/ECS/IEnginesInterfaces.cs b/ECS/IEnginesInterfaces.cs index 6c8945c..1929ca9 100644 --- a/ECS/IEnginesInterfaces.cs +++ b/ECS/IEnginesInterfaces.cs @@ -15,7 +15,7 @@ namespace Svelto.ECS public interface IEntityFunctions { - void RemoveEntity(int entityID, IRemoveEntityComponent template); + void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo); void RemoveEntity(int entityID) where T:IEntityDescriptor, new(); diff --git a/ECS/MultiEntityViewsEngine.cs b/ECS/MultiEntityViewsEngine.cs index 2ba4856..895a48b 100644 --- a/ECS/MultiEntityViewsEngine.cs +++ b/ECS/MultiEntityViewsEngine.cs @@ -2,7 +2,7 @@ using Svelto.ECS.Internal; namespace Svelto.ECS.Internal { - public abstract class MultiEntityViewsEngine:IHandleEntityViewEngine where T:EntityView, new() + public abstract class MultiEntityViewsEngine:IHandleEntityViewEngine where T:EntityView, new() { protected abstract void Add(T entityView); protected abstract void Remove(T entityView); @@ -22,8 +22,8 @@ namespace Svelto.ECS.Internal namespace Svelto.ECS { public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine - where T:EntityView, new() - where U:EntityView, new() + where T:EntityView, new() + where U:EntityView, new() { protected abstract void Add(U entityView); protected abstract void Remove(U entityView); @@ -55,9 +55,9 @@ namespace Svelto.ECS } public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine - where T : EntityView, new() - where U : EntityView, new() - where V : EntityView, new() + where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() { protected abstract void Add(V entityView); protected abstract void Remove(V entityView); diff --git a/ECS/RemoveEntityImplementor.cs b/ECS/RemoveEntityImplementor.cs index 30f74c5..7bd03b3 100644 --- a/ECS/RemoveEntityImplementor.cs +++ b/ECS/RemoveEntityImplementor.cs @@ -2,17 +2,20 @@ { sealed class RemoveEntityImplementor : IRemoveEntityComponent { - public RemoveEntityImplementor(IEntityDescriptor descriptor, int groupID) : this(descriptor) + public RemoveEntityImplementor(IEntityViewBuilder[] entityViews, int groupID):this(entityViews) { - removeEntityInfo = new RemoveEntityInfo(descriptor, groupID); + this.groupID = groupID; + isInAGroup = true; } - internal RemoveEntityImplementor(IEntityDescriptor descriptor) + internal RemoveEntityImplementor(IEntityViewBuilder[] entityViews) { - removeEntityInfo = new RemoveEntityInfo(descriptor); + removeEntityInfo = new RemoveEntityInfo(entityViews); } - internal RemoveEntityInfo removeEntityInfo; + readonly internal RemoveEntityInfo removeEntityInfo; + readonly internal int groupID; + readonly internal bool isInAGroup; } } @@ -23,20 +26,11 @@ namespace Svelto.ECS public struct RemoveEntityInfo { - readonly public IEntityDescriptor descriptor; - readonly public int groupID; - readonly public bool isInAGroup; - - public RemoveEntityInfo(IEntityDescriptor descriptor) : this() - { - this.descriptor = descriptor; - } - - public RemoveEntityInfo(IEntityDescriptor descriptor, int groupID) + readonly internal IEntityViewBuilder[] entityViewsToBuild; + + public RemoveEntityInfo(IEntityViewBuilder[] entityViews) : this() { - this.descriptor = descriptor; - this.groupID = groupID; - isInAGroup = true; + this.entityViewsToBuild = entityViews; } } } diff --git a/ECS/SingleEntityViewEngine.cs b/ECS/SingleEntityViewEngine.cs index a3ac1ad..605f775 100644 --- a/ECS/SingleEntityViewEngine.cs +++ b/ECS/SingleEntityViewEngine.cs @@ -2,7 +2,7 @@ using Svelto.ECS.Internal; namespace Svelto.ECS { - public abstract class SingleEntityViewEngine : IHandleEntityViewEngine where T:EntityView, new() + public abstract class SingleEntityViewEngine : IHandleEntityViewEngine where T:EntityView, new() { public void Add(IEntityView entityView) { From 6b14cdac139ca8c985ae25b6c91d769e06cdc97f Mon Sep 17 00:00:00 2001 From: sebas77 Date: Mon, 25 Dec 2017 00:22:04 +0000 Subject: [PATCH 08/22] Fix some bugs with the EntityProfiler and remove redundant code. --- ECS/EnginesRootEngines.cs | 9 +-------- ECS/EnginesRootEntities.cs | 14 +------------- ECS/EnginesRootSubmission.cs | 2 +- ECS/Profiler/EngineProfiler.cs | 7 +++---- 4 files changed, 6 insertions(+), 26 deletions(-) diff --git a/ECS/EnginesRootEngines.cs b/ECS/EnginesRootEngines.cs index fb47ffe..a74e26c 100644 --- a/ECS/EnginesRootEngines.cs +++ b/ECS/EnginesRootEngines.cs @@ -56,9 +56,6 @@ namespace Svelto.ECS _implementedInterfaceTypes = new Dictionary(); #endif #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - _addEntityViewToEngine = AddEntityViewToEngine; - _removeEntityViewFromEngine = RemoveEntityViewFromEngine; - UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); debugEngineObject.gameObject.AddComponent(); #endif @@ -206,11 +203,7 @@ namespace Svelto.ECS readonly Dictionary _implementedInterfaceTypes; #endif - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - static Action _addEntityViewToEngine; - static Action _removeEntityViewFromEngine; -#endif + readonly EngineEntityViewDB _engineEntityViewDB; class DoubleBufferedEntityViews where T : class, IDictionary, new() diff --git a/ECS/EnginesRootEntities.cs b/ECS/EnginesRootEntities.cs index 7d258ab..923c2bb 100644 --- a/ECS/EnginesRootEntities.cs +++ b/ECS/EnginesRootEntities.cs @@ -222,7 +222,7 @@ namespace Svelto.ECS for (int j = 0; j < count; j++) { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(_removeEntityViewFromEngine, fastList[j], entityView); + EngineProfiler.MonitorRemoveDuration(fastList[j], entityView); #else fastList[j].Remove(entityView); #endif @@ -230,18 +230,6 @@ namespace Svelto.ECS } } -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - static void AddEntityViewToEngine(IHandleEntityViewEngine engine, IEntityView entityView) - { - engine.Add(entityView); - } - - static void RemoveEntityViewFromEngine(IHandleEntityViewEngine engine, IEntityView entityView) - { - engine.Remove(entityView); - } -#endif - class GenericEntityFactory : IEntityFactory { DataStructures.WeakReference _weakEngine; diff --git a/ECS/EnginesRootSubmission.cs b/ECS/EnginesRootSubmission.cs index c0c7641..b51f3f2 100644 --- a/ECS/EnginesRootSubmission.cs +++ b/ECS/EnginesRootSubmission.cs @@ -148,7 +148,7 @@ namespace Svelto.ECS for (int j = 0; j < count; j++) { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorAddDuration(_addEntityViewToEngine, fastList[j], entityView); + EngineProfiler.MonitorAddDuration(fastList[j], entityView); #else fastList[j].Add(entityView); #endif diff --git a/ECS/Profiler/EngineProfiler.cs b/ECS/Profiler/EngineProfiler.cs index 5f0765d..3e10786 100644 --- a/ECS/Profiler/EngineProfiler.cs +++ b/ECS/Profiler/EngineProfiler.cs @@ -12,26 +12,25 @@ namespace Svelto.ECS.Profiler { static readonly Stopwatch _stopwatch = new Stopwatch(); - public static void MonitorAddDuration(Action addingFunc, IHandleEntityViewEngine engine, IEntityView entityView) + public static void MonitorAddDuration(IHandleEntityViewEngine engine, IEntityView entityView) { EngineInfo info; if (engineInfos.TryGetValue(engine.GetType(), out info)) { _stopwatch.Start(); - addingFunc(engine, entityView); + engine.Add(entityView); _stopwatch.Reset(); info.AddAddDuration(_stopwatch.Elapsed.TotalMilliseconds); } } - public static void MonitorRemoveDuration(Action removeFunc, IHandleEntityViewEngine engine, IEntityView entityView) + public static void MonitorRemoveDuration(IHandleEntityViewEngine engine, IEntityView entityView) { EngineInfo info; if (engineInfos.TryGetValue(engine.GetType(), out info)) { _stopwatch.Start(); - removeFunc(engine, entityView); engine.Remove(entityView); _stopwatch.Reset(); From d1805974587c719a5ef558e8c78b7249713a22ff Mon Sep 17 00:00:00 2001 From: sebas77 Date: Tue, 26 Dec 2017 13:07:58 +0000 Subject: [PATCH 09/22] rename file added the new function SwapEntityGroup to be able to easily move entities between groups --- .../TypeSafeFasterListForECS.cs | 11 +++- ECS/EnginesRootEntities.cs | 53 ++++++++++++++++++- ECS/EnginesRootSubmission.cs | 4 +- ...criptorTemplate.cs => EntityDescriptor.cs} | 2 +- ECS/EntityViewBuilder.cs | 17 ++++++ ECS/IEnginesInterfaces.cs | 5 +- 6 files changed, 84 insertions(+), 8 deletions(-) rename ECS/{EntityDescriptorTemplate.cs => EntityDescriptor.cs} (98%) diff --git a/ECS/DataStructures/TypeSafeFasterListForECS.cs b/ECS/DataStructures/TypeSafeFasterListForECS.cs index 161ecf4..4bca085 100644 --- a/ECS/DataStructures/TypeSafeFasterListForECS.cs +++ b/ECS/DataStructures/TypeSafeFasterListForECS.cs @@ -48,12 +48,21 @@ namespace Svelto.ECS.Internal { var index = this.Count; - AddRange(entityViewListValue as FasterList); + base.AddRange(entityViewListValue as FasterList); for (int i = index; i < Count; ++i) _mappedIndices[this[i].ID] = i; } + new public void Add(T entityView) + { + var index = this.Count; + + base.Add(entityView); + + _mappedIndices[entityView.ID] = index; + } + public void ReserveCapacity(int capacity) { if (this.ToArrayFast().Length < capacity) diff --git a/ECS/EnginesRootEntities.cs b/ECS/EnginesRootEntities.cs index 923c2bb..f9c3896 100644 --- a/ECS/EnginesRootEntities.cs +++ b/ECS/EnginesRootEntities.cs @@ -164,6 +164,45 @@ namespace Svelto.ECS InternalRemove(EntityDescriptorTemplate.Default.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); } + void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() + { + DesignByContract.Check.Require(fromGroupID != toGroupID, "can't move an entity to the same group where it already belongs to"); + + var entityViewBuilders = EntityDescriptorTemplate.Default.entityViewsToBuild; + int entityViewBuildersCount = entityViewBuilders.Length; + + for (int i = 0; i < entityViewBuildersCount; i++) + { + IEntityViewBuilder entityViewBuilder = entityViewBuilders[i]; + Type entityViewType = entityViewBuilder.GetEntityViewType(); + Dictionary dictionary = _groupEntityViewsDB[fromGroupID]; + + ITypeSafeList fromSafeList = dictionary[entityViewType]; + + Dictionary groupedEntityViewsTyped; + if (_groupEntityViewsDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) + { + groupedEntityViewsTyped = new Dictionary(); + + _groupEntityViewsDB.Add(toGroupID, groupedEntityViewsTyped); + } + + ITypeSafeList toSafeList; + + if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) + { + toSafeList = fromSafeList.Create(); + } + + entityViewBuilder.MoveEntityView(entityID, fromSafeList, toSafeList); + + if (fromSafeList.UnorderedRemove(entityID) == false) + dictionary.Remove(entityViewType); + + if (dictionary.Count == 0) _groupEntityViewsDB.Remove(fromGroupID); + } + } + void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, Dictionary entityViewsDB) { @@ -192,6 +231,13 @@ namespace Svelto.ECS void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, Dictionary entityViewsDB) + { + InternalRemoveFromDB(entityViewBuilders, entityID, groupID); + + InternalRemove(entityViewBuilders, entityID, entityViewsDB); + } + + void InternalRemoveFromDB(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID) { int entityViewBuildersCount = entityViewBuilders.Length; @@ -205,8 +251,6 @@ namespace Svelto.ECS if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); } - - InternalRemove(entityViewBuilders, entityID, entityViewsDB); } static void RemoveEntityViewFromEngines(Dictionary> entityViewEngines, @@ -297,6 +341,11 @@ namespace Svelto.ECS _weakReference.Target.RemoveEntity(entityID); } + public void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() + { + _weakReference.Target.SwapEntityGroup(entityID, fromGroupID, toGroupID); + } + readonly DataStructures.WeakReference _weakReference; } diff --git a/ECS/EnginesRootSubmission.cs b/ECS/EnginesRootSubmission.cs index b51f3f2..894881a 100644 --- a/ECS/EnginesRootSubmission.cs +++ b/ECS/EnginesRootSubmission.cs @@ -89,9 +89,9 @@ namespace Svelto.ECS { foreach (var group in groupedEntityViewsToAdd) { - AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); - AddEntityViewsToGroupDB(groupEntityViewsDB, @group); + + AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); } } diff --git a/ECS/EntityDescriptorTemplate.cs b/ECS/EntityDescriptor.cs similarity index 98% rename from ECS/EntityDescriptorTemplate.cs rename to ECS/EntityDescriptor.cs index d917577..91e09aa 100644 --- a/ECS/EntityDescriptorTemplate.cs +++ b/ECS/EntityDescriptor.cs @@ -105,7 +105,7 @@ namespace Svelto.ECS.Internal } } - static IEntityView BuildEntityView(int entityID, Dictionary entityViewsByType, + internal static IEntityView BuildEntityView(int entityID, Dictionary entityViewsByType, Type entityViewType, IEntityViewBuilder entityViewBuilder) { ITypeSafeList entityViewsList; diff --git a/ECS/EntityViewBuilder.cs b/ECS/EntityViewBuilder.cs index 6b02a66..b512cf9 100644 --- a/ECS/EntityViewBuilder.cs +++ b/ECS/EntityViewBuilder.cs @@ -9,6 +9,7 @@ namespace Svelto.ECS ITypeSafeList Preallocate(ref ITypeSafeList list, int size); Type GetEntityViewType(); + void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList); } public class EntityViewBuilder : IEntityViewBuilder where EntityViewType : EntityView, new() @@ -42,6 +43,14 @@ namespace Svelto.ECS return _entityViewType; } + public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) + { + var fromCastedList = fromSafeList as TypeSafeFasterListForECSForClasses; + var toCastedList = toSafeList as TypeSafeFasterListForECSForClasses; + + toCastedList.Add(fromCastedList[entityID]); + } + readonly Type _entityViewType = typeof(EntityViewType); } @@ -77,6 +86,14 @@ namespace Svelto.ECS return _entityViewType; } + public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) + { + var fromCastedList = fromSafeList as TypeSafeFasterListForECSForStructs; + var toCastedList = toSafeList as TypeSafeFasterListForECSForStructs; + + toCastedList.Add(fromCastedList[entityID]); + } + readonly Type _entityViewType = typeof(EntityViewType); } } \ No newline at end of file diff --git a/ECS/IEnginesInterfaces.cs b/ECS/IEnginesInterfaces.cs index 1929ca9..fe0494b 100644 --- a/ECS/IEnginesInterfaces.cs +++ b/ECS/IEnginesInterfaces.cs @@ -16,11 +16,12 @@ namespace Svelto.ECS public interface IEntityFunctions { void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo); - void RemoveEntity(int entityID) where T:IEntityDescriptor, new(); - + void RemoveMetaEntity(int metaEntityID) where T:IEntityDescriptor, new(); void RemoveEntityFromGroup(int entityID, int groupID) where T:IEntityDescriptor, new(); + + void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new(); } } From a9e20edd1ba12d03295d3e764ec1285e5caa8fb6 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Tue, 26 Dec 2017 19:55:57 +0000 Subject: [PATCH 10/22] improve code and fix a bug with the SwapEntityGroup function --- .../TypeSafeFasterListForECS.cs | 6 +++ ECS/EnginesRootEntities.cs | 31 +++++------ ECS/EntityDescriptor.cs | 52 +++++++------------ ECS/EntityViewBuilder.cs | 4 +- 4 files changed, 43 insertions(+), 50 deletions(-) diff --git a/ECS/DataStructures/TypeSafeFasterListForECS.cs b/ECS/DataStructures/TypeSafeFasterListForECS.cs index 4bca085..4f15c15 100644 --- a/ECS/DataStructures/TypeSafeFasterListForECS.cs +++ b/ECS/DataStructures/TypeSafeFasterListForECS.cs @@ -16,6 +16,7 @@ namespace Svelto.ECS.Internal ITypeSafeDictionary CreateIndexedDictionary(); IEntityView[] ToArrayFast(out int count); void ReserveCapacity(int capacity); + int GetIndexFromID(int entityID); } class TypeSafeFasterListForECS: FasterList where T:IEntityView @@ -69,6 +70,11 @@ namespace Svelto.ECS.Internal Resize(capacity); } + public int GetIndexFromID(int entityID) + { + return _mappedIndices[entityID]; + } + readonly Dictionary _mappedIndices; } diff --git a/ECS/EnginesRootEntities.cs b/ECS/EnginesRootEntities.cs index f9c3896..6b58966 100644 --- a/ECS/EnginesRootEntities.cs +++ b/ECS/EnginesRootEntities.cs @@ -171,22 +171,22 @@ namespace Svelto.ECS var entityViewBuilders = EntityDescriptorTemplate.Default.entityViewsToBuild; int entityViewBuildersCount = entityViewBuilders.Length; + Dictionary dictionary = _groupEntityViewsDB[fromGroupID]; + + Dictionary groupedEntityViewsTyped; + if (_groupEntityViewsDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) + { + groupedEntityViewsTyped = new Dictionary(); + + _groupEntityViewsDB.Add(toGroupID, groupedEntityViewsTyped); + } + for (int i = 0; i < entityViewBuildersCount; i++) { IEntityViewBuilder entityViewBuilder = entityViewBuilders[i]; Type entityViewType = entityViewBuilder.GetEntityViewType(); - Dictionary dictionary = _groupEntityViewsDB[fromGroupID]; ITypeSafeList fromSafeList = dictionary[entityViewType]; - - Dictionary groupedEntityViewsTyped; - if (_groupEntityViewsDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) - { - groupedEntityViewsTyped = new Dictionary(); - - _groupEntityViewsDB.Add(toGroupID, groupedEntityViewsTyped); - } - ITypeSafeList toSafeList; if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) @@ -198,9 +198,9 @@ namespace Svelto.ECS if (fromSafeList.UnorderedRemove(entityID) == false) dictionary.Remove(entityViewType); - - if (dictionary.Count == 0) _groupEntityViewsDB.Remove(fromGroupID); } + + if (dictionary.Count == 0) _groupEntityViewsDB.Remove(fromGroupID); } void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, @@ -241,16 +241,17 @@ namespace Svelto.ECS { int entityViewBuildersCount = entityViewBuilders.Length; + Dictionary dictionary = _groupEntityViewsDB[groupID]; + for (int i = 0; i < entityViewBuildersCount; i++) { Type entityViewType = entityViewBuilders[i].GetEntityViewType(); - Dictionary dictionary = _groupEntityViewsDB[groupID]; if (dictionary[entityViewType].UnorderedRemove(entityID) == false) dictionary.Remove(entityViewType); - - if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); } + + if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); } static void RemoveEntityViewFromEngines(Dictionary> entityViewEngines, diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs index 91e09aa..9f3a46f 100644 --- a/ECS/EntityDescriptor.cs +++ b/ECS/EntityDescriptor.cs @@ -39,51 +39,37 @@ namespace Svelto.ECS.Internal EntityDescriptorInfo entityViewsToBuildDescriptor, object[] implementors) { - var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; - int count = entityViewsToBuild.Length; + Dictionary groupedEntityViewsTyped; - RemoveEntityImplementor removeEntityImplementor = null; - - for (int index = 0; index < count; index++) + if (groupEntityViewsByType.TryGetValue(groupID, out groupedEntityViewsTyped) == false) { - var entityViewBuilder = entityViewsToBuild[index]; - var entityViewType = entityViewBuilder.GetEntityViewType(); - - Dictionary groupedEntityViewsTyped; - - if (groupEntityViewsByType.TryGetValue(groupID, out groupedEntityViewsTyped) == false) - { - groupedEntityViewsTyped = new Dictionary(); - groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); - } - - //only class EntityView will be returned - //struct EntityView cannot be filled so it will be null. - var entityViewObjectToFill = - BuildEntityView(entityID, groupedEntityViewsTyped, entityViewType, entityViewBuilder); + groupedEntityViewsTyped = new Dictionary(); + groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); + } - //the semantic of this code must still be improved - //but only classes can be filled, so I am aware - //it's a EntityViewWithID - if (entityViewObjectToFill != null) - { - if (removeEntityImplementor == null) - removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.entityViewsToBuild, groupID); + var removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.entityViewsToBuild, groupID); - FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, - entityViewsToBuildDescriptor.name); - } - } + InternalBuildEntityViews(entityID, groupedEntityViewsTyped, entityViewsToBuildDescriptor, implementors, removeEntityImplementor); } internal static void BuildEntityViews(int entityID, Dictionary entityViewsByType, EntityDescriptorInfo entityViewsToBuildDescriptor, object[] implementors) + { + var removeEntityImplementor = entityViewsToBuildDescriptor.removeEntityImplementor; + + InternalBuildEntityViews(entityID, entityViewsByType, entityViewsToBuildDescriptor, implementors, removeEntityImplementor); + } + + private static void InternalBuildEntityViews(int entityID, + Dictionary entityViewsByType, + EntityDescriptorInfo entityViewsToBuildDescriptor, + object[] implementors, RemoveEntityImplementor removeEntityImplementor) { var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; int count = entityViewsToBuild.Length; - + for (int index = 0; index < count; index++) { var entityViewBuilder = entityViewsToBuild[index]; @@ -99,7 +85,7 @@ namespace Svelto.ECS.Internal //it's a EntityView if (entityViewObjectToFill != null) { - FillEntityView(entityViewObjectToFill as EntityView, implementors, entityViewsToBuildDescriptor.removeEntityImplementor, + FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, entityViewsToBuildDescriptor.name); } } diff --git a/ECS/EntityViewBuilder.cs b/ECS/EntityViewBuilder.cs index b512cf9..73606af 100644 --- a/ECS/EntityViewBuilder.cs +++ b/ECS/EntityViewBuilder.cs @@ -48,7 +48,7 @@ namespace Svelto.ECS var fromCastedList = fromSafeList as TypeSafeFasterListForECSForClasses; var toCastedList = toSafeList as TypeSafeFasterListForECSForClasses; - toCastedList.Add(fromCastedList[entityID]); + toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); } readonly Type _entityViewType = typeof(EntityViewType); @@ -91,7 +91,7 @@ namespace Svelto.ECS var fromCastedList = fromSafeList as TypeSafeFasterListForECSForStructs; var toCastedList = toSafeList as TypeSafeFasterListForECSForStructs; - toCastedList.Add(fromCastedList[entityID]); + toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); } readonly Type _entityViewType = typeof(EntityViewType); From 6a4d702ea28829487554c25837e19ebd91db0db9 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Wed, 27 Dec 2017 03:01:08 +0000 Subject: [PATCH 11/22] Improve compatibility across platforms --- ECS/EnginesRootEngines.cs | 2 +- ECS/EntityDescriptor.cs | 4 +- ECS/EntityView.cs | 10 ++--- Utilities/FastInvoke.cs | 35 ++++++++++++++++- Utilities/NetFXCoreWrappers.cs | 58 ++++++++++++++++++++++++++--- Utilities/PropertyInfoExtensions.cs | 24 ------------ 6 files changed, 93 insertions(+), 40 deletions(-) delete mode 100644 Utilities/PropertyInfoExtensions.cs diff --git a/ECS/EnginesRootEngines.cs b/ECS/EnginesRootEngines.cs index a74e26c..940c5b5 100644 --- a/ECS/EnginesRootEngines.cs +++ b/ECS/EnginesRootEngines.cs @@ -143,7 +143,7 @@ namespace Svelto.ECS if (baseType.IsGenericTypeEx()) { - var genericArguments = baseType.GetGenericArguments(); + var genericArguments = baseType.GetGenericArgumentsEx(); AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); #if EXPERIMENTAL var activableEngine = engine as IHandleActivableEntityEngine; diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs index 9f3a46f..880c2c2 100644 --- a/ECS/EntityDescriptor.cs +++ b/ECS/EntityDescriptor.cs @@ -132,7 +132,7 @@ namespace Svelto.ECS.Internal Type[] interfaces; if (_cachedTypes.TryGetValue(type, out interfaces) == false) - interfaces = _cachedTypes[type] = type.GetInterfaces(); + interfaces = _cachedTypes[type] = type.GetInterfacesEx(); for (int iindex = 0; iindex < interfaces.Length; iindex++) { @@ -161,7 +161,7 @@ namespace Svelto.ECS.Internal //Very efficent way to collect the fields of every EntityViewType KeyValuePair>[] setters = - FasterList>>.NoVirt.ToArrayFast(entityView.EntityViewBlazingFastReflection, out count); + FasterList>>.NoVirt.ToArrayFast(entityView.entityViewBlazingFastReflection, out count); var removeEntityComponentType = typeof(IRemoveEntityComponent); diff --git a/ECS/EntityView.cs b/ECS/EntityView.cs index 5891198..8add72c 100644 --- a/ECS/EntityView.cs +++ b/ECS/EntityView.cs @@ -16,11 +16,11 @@ namespace Svelto.ECS new int ID { set; } } - public abstract class EntityView : IEntityView + public class EntityView : IEntityView { public int ID { get { return _ID; } } - internal FasterList>> EntityViewBlazingFastReflection; + internal FasterList>> entityViewBlazingFastReflection; internal int _ID; } @@ -39,13 +39,13 @@ namespace Svelto.ECS { var field = fields[i]; - Action setter = FastInvoke.MakeSetter(field); - + Action setter = FastInvoke.MakeSetter(field); + FieldCache.list.Add(new KeyValuePair>(field.FieldType, setter)); } } - return new T { _ID = ID, EntityViewBlazingFastReflection = FieldCache.list }; + return new T { _ID = ID, entityViewBlazingFastReflection = FieldCache.list }; } static class FieldCache where W:T diff --git a/Utilities/FastInvoke.cs b/Utilities/FastInvoke.cs index c749c1d..b9a1aab 100644 --- a/Utilities/FastInvoke.cs +++ b/Utilities/FastInvoke.cs @@ -1,6 +1,7 @@ using System; using System.Reflection; using System.Reflection.Emit; +using System.Linq.Expressions; namespace Svelto.Utilities { @@ -8,9 +9,20 @@ namespace Svelto.Utilities public static class FastInvoke where T : class { - public static Action MakeSetter(FieldInfo field) +#if ENABLE_IL2CPP + public static Action MakeSetter(FieldInfo field) { if (field.FieldType.IsInterface == true && field.FieldType.IsValueType == false) + { + return new Action((target, value) => field.SetValue(target, value)); + } + + throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); + } +#elif !NETFX_CORE + public static Action MakeSetter(FieldInfo field) + { + if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) { DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] { typeof(T), typeof(object) }); ILGenerator cg = m.GetILGenerator(); @@ -21,10 +33,29 @@ namespace Svelto.Utilities cg.Emit(OpCodes.Stfld, field); cg.Emit(OpCodes.Ret); - return (Action)m.CreateDelegate(typeof(Action)); + return new Action((target, value) => m.CreateDelegate(typeof(Action)).DynamicInvoke(target, value)); + } + + throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); + } +#else + public static Action MakeSetter(FieldInfo field) + { + if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) + { + ParameterExpression targetExp = Expression.Parameter(typeof(T), "target"); + ParameterExpression valueExp = Expression.Parameter(field.FieldType, "value"); + + MemberExpression fieldExp = Expression.Field(targetExp, field); + BinaryExpression assignExp = Expression.Assign(fieldExp, valueExp); + + var setter = Expression.Lambda(assignExp, targetExp, valueExp).Compile(); + + return new Action((target, value) => setter.DynamicInvoke(target, value)); } throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); } +#endif } } \ No newline at end of file diff --git a/Utilities/NetFXCoreWrappers.cs b/Utilities/NetFXCoreWrappers.cs index cde69f8..1fa798a 100644 --- a/Utilities/NetFXCoreWrappers.cs +++ b/Utilities/NetFXCoreWrappers.cs @@ -4,11 +4,18 @@ using System.Reflection; using System.Runtime.CompilerServices; using Svelto.DataStructures; -namespace Svelto.Utilities -{ public static class NetFXCoreWrappers { - public static MethodInfo GetMethodInfoEx(this Delegate delegateEx) + public static Type GetDeclaringType(this MethodInfo methodInfo) + { +#if NETFX_CORE + return methodInfo.DeclaringType; +#else + return methodInfo.ReflectedType; +#endif + } + + public static MethodInfo GetMethodInfoEx(this Delegate delegateEx) { #if NETFX_CORE var method = delegateEx.GetMethodInfo(); @@ -18,6 +25,33 @@ namespace Svelto.Utilities return method; } + public static Type[] GetInterfacesEx(this Type type) + { +#if NETFX_CORE + return type.GetInterfaces(); +#else + return type.GetInterfaces(); +#endif + } + + public static bool IsInterfaceEx(this Type type) + { +#if NETFX_CORE + return type.GetTypeInfo().IsInterface; +#else + return type.IsInterface; +#endif + } + + public static bool IsValueTypeEx(this Type type) + { +#if NETFX_CORE + return type.GetTypeInfo().IsValueType; +#else + return type.IsValueType; +#endif + } + public static Type GetDeclaringType(this MemberInfo memberInfo) { #if NETFX_CORE @@ -30,7 +64,7 @@ namespace Svelto.Utilities public static Type GetBaseType(this Type type) { #if NETFX_CORE - return type.BaseType(); + return type.GetTypeInfo().BaseType; #else return type.BaseType; #endif @@ -63,7 +97,19 @@ namespace Svelto.Utilities #endif } - public static MemberInfo[] FindWritablePropertiesWithCustomAttribute(this Type contract, + public static Type[] GetGenericArgumentsEx(this Type type) + { +#if !NETFX_CORE + return type.GetGenericArguments(); +#else + var typeinfo = type.GetTypeInfo(); + return typeinfo.IsGenericTypeDefinition + ? typeinfo.GenericTypeParameters + : typeinfo.GenericTypeArguments; +#endif + } + + public static MemberInfo[] FindWritablePropertiesWithCustomAttribute(this Type contract, Type customAttributeType) { FasterList propertyList = new FasterList(8); @@ -121,4 +167,4 @@ namespace Svelto.Utilities static readonly Type _compilerType = typeof(CompilerGeneratedAttribute); } -} + diff --git a/Utilities/PropertyInfoExtensions.cs b/Utilities/PropertyInfoExtensions.cs deleted file mode 100644 index 87b18d8..0000000 --- a/Utilities/PropertyInfoExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Reflection; - -public static class NetFXCoreWrappers -{ - public static MethodInfo GetMethodInfoEx(this Delegate delegateEx) - { -#if NETFX_CORE - var method = delegateEx.GetMethodInfo(); -#else - var method = delegateEx.Method; -#endif - return method; - } - - public static Type GetDeclaringType(this MethodInfo methodInfo) - { -#if NETFX_CORE - return methodInfo.DeclaringType; -#else - return methodInfo.ReflectedType; -#endif - } -} From 6b81c57d46bd41d4cc40c443527c73645a5244da Mon Sep 17 00:00:00 2001 From: sebas77 Date: Wed, 27 Dec 2017 12:13:19 +0000 Subject: [PATCH 12/22] DynamicInvokes are super slow, so I luckily found an alternative. --- ECS/EntityDescriptor.cs | 11 ++++++----- ECS/EntityView.cs | 8 ++++---- Utilities/FastInvoke.cs | 41 +++++++++++++++++++++++++++++++++-------- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs index 880c2c2..9b2de27 100644 --- a/ECS/EntityDescriptor.cs +++ b/ECS/EntityDescriptor.cs @@ -1,5 +1,6 @@ using Svelto.DataStructures; using Svelto.ECS.Internal; +using Svelto.Utilities; using System; using System.Collections.Generic; @@ -160,8 +161,8 @@ namespace Svelto.ECS.Internal int count; //Very efficent way to collect the fields of every EntityViewType - KeyValuePair>[] setters = - FasterList>>.NoVirt.ToArrayFast(entityView.entityViewBlazingFastReflection, out count); + KeyValuePair>[] setters = + FasterList>>.NoVirt.ToArrayFast(entityView.entityViewBlazingFastReflection, out count); var removeEntityComponentType = typeof(IRemoveEntityComponent); @@ -193,14 +194,14 @@ namespace Svelto.ECS.Internal entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); #endif #if DEBUG && !PROFILER - keyValuePair.Value(entityView, component.item1); + keyValuePair.Value.Call(entityView, component.item1); #else - keyValuePair.Value(entityView, component); + keyValuePair.Value.Call(entityView, component); #endif } else { - keyValuePair.Value(entityView, removeEntity); + keyValuePair.Value.Call(entityView, removeEntity); } } diff --git a/ECS/EntityView.cs b/ECS/EntityView.cs index 8add72c..4846935 100644 --- a/ECS/EntityView.cs +++ b/ECS/EntityView.cs @@ -20,7 +20,7 @@ namespace Svelto.ECS { public int ID { get { return _ID; } } - internal FasterList>> entityViewBlazingFastReflection; + internal FasterList>> entityViewBlazingFastReflection; internal int _ID; } @@ -39,9 +39,9 @@ namespace Svelto.ECS { var field = fields[i]; - Action setter = FastInvoke.MakeSetter(field); + CastedAction setter = FastInvoke.MakeSetter(field); - FieldCache.list.Add(new KeyValuePair>(field.FieldType, setter)); + FieldCache.list.Add(new KeyValuePair>(field.FieldType, setter)); } } @@ -50,7 +50,7 @@ namespace Svelto.ECS static class FieldCache where W:T { - internal static readonly FasterList>> list = new FasterList>>(); + internal static readonly FasterList>> list = new FasterList>>(); } } } diff --git a/Utilities/FastInvoke.cs b/Utilities/FastInvoke.cs index b9a1aab..8cd208c 100644 --- a/Utilities/FastInvoke.cs +++ b/Utilities/FastInvoke.cs @@ -10,7 +10,7 @@ namespace Svelto.Utilities public static class FastInvoke where T : class { #if ENABLE_IL2CPP - public static Action MakeSetter(FieldInfo field) + public static Action MakeSetter(FieldInfo field) where CastedType:class { if (field.FieldType.IsInterface == true && field.FieldType.IsValueType == false) { @@ -20,7 +20,7 @@ namespace Svelto.Utilities throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); } #elif !NETFX_CORE - public static Action MakeSetter(FieldInfo field) + public static CastedAction MakeSetter(FieldInfo field) where CastedType:class { if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) { @@ -33,29 +33,54 @@ namespace Svelto.Utilities cg.Emit(OpCodes.Stfld, field); cg.Emit(OpCodes.Ret); - return new Action((target, value) => m.CreateDelegate(typeof(Action)).DynamicInvoke(target, value)); + var del = m.CreateDelegate(typeof(Action)); + + return new CastedAction(del); } throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); } #else - public static Action MakeSetter(FieldInfo field) + public static CastedAction MakeSetter(FieldInfo field) where CastedType:class { if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) { ParameterExpression targetExp = Expression.Parameter(typeof(T), "target"); - ParameterExpression valueExp = Expression.Parameter(field.FieldType, "value"); + ParameterExpression valueExp = Expression.Parameter(typeof(object), "value"); MemberExpression fieldExp = Expression.Field(targetExp, field); - BinaryExpression assignExp = Expression.Assign(fieldExp, valueExp); + UnaryExpression convertedExp = Expression.TypeAs(valueExp, field.FieldType); + BinaryExpression assignExp = Expression.Assign(fieldExp, convertedExp); + + Type type = typeof(Action<,>).MakeGenericType(new Type[] { typeof(T), typeof(object) }); - var setter = Expression.Lambda(assignExp, targetExp, valueExp).Compile(); + var setter = Expression.Lambda(type, assignExp, targetExp, valueExp).Compile(); - return new Action((target, value) => setter.DynamicInvoke(target, value)); + return new CastedAction(setter); } throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); } #endif } + + public abstract class CastedAction + { + abstract public void Call(W target, object value); + } + + public class CastedAction : CastedAction where W : class where T:class + { + Action setter; + + public CastedAction(Delegate setter) + { + this.setter = (Action)setter; + } + + override public void Call(W target, object value) + { + setter(target as T, value); + } + } } \ No newline at end of file From 80ac93215ba44b9898a06d0ef9885b709ea2f762 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Wed, 27 Dec 2017 14:07:46 +0000 Subject: [PATCH 13/22] fix the FastInvoke.cs for all the platforms --- Utilities/FastInvoke.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Utilities/FastInvoke.cs b/Utilities/FastInvoke.cs index 8cd208c..c989b28 100644 --- a/Utilities/FastInvoke.cs +++ b/Utilities/FastInvoke.cs @@ -10,14 +10,14 @@ namespace Svelto.Utilities public static class FastInvoke where T : class { #if ENABLE_IL2CPP - public static Action MakeSetter(FieldInfo field) where CastedType:class + public static CastedAction MakeSetter(FieldInfo field) where CastedType:class { - if (field.FieldType.IsInterface == true && field.FieldType.IsValueType == false) + if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) { - return new Action((target, value) => field.SetValue(target, value)); + return new CastedAction(field.SetValue); } - throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); + throw new ArgumentException("Svelto.ECS unsupported field (must be an interface and a class)"); } #elif !NETFX_CORE public static CastedAction MakeSetter(FieldInfo field) where CastedType:class @@ -38,7 +38,7 @@ namespace Svelto.Utilities return new CastedAction(del); } - throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); + throw new ArgumentException("Svelto.ECS unsupported field (must be an interface and a class)"); } #else public static CastedAction MakeSetter(FieldInfo field) where CastedType:class @@ -59,7 +59,7 @@ namespace Svelto.Utilities return new CastedAction(setter); } - throw new ArgumentException("Svelto.ECS unsupported EntityView field (must be an interface and a class)"); + throw new ArgumentException("Svelto.ECS unsupported field (must be an interface and a class)"); } #endif } @@ -78,6 +78,11 @@ namespace Svelto.Utilities this.setter = (Action)setter; } + public CastedAction(Action setter) + { + this.setter = setter; + } + override public void Call(W target, object value) { setter(target as T, value); From ebe5f0f221538ec84d979e85fc00ecd2727f3967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastiano=20Mandal=C3=A0?= Date: Wed, 27 Dec 2017 17:13:55 +0000 Subject: [PATCH 14/22] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2030e27..dac0880 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,18 @@ Svelto Entity Component System for Unity Real Entity-Component-System for c# and Unity (it can be adapted for other c# platforms too). Enables to write encapsulated, uncoupled, highly efficient, data oriented, cache friendly, multi-threaded, code without pain. -you can find a working example to learn how to use the framework here: +you can find working examples to learn how to use the framework here: -https://github.com/sebas77/Svelto-ECS-Example +https://github.com/sebas77/Svelto-ECS-Example (unity) + +https://github.com/sebas77/Svelto.ECS.Vanilla.Example (.net core and standard) I advise to clone the example repositories separately from the framework one, both under the same Unity project Assets folder. relative article: +http://www.sebaslab.com/svelto-ecs-2-0-almost-production-ready/ + http://www.sebaslab.com/ecs-1-0/ If you want to know more about the theory and rationale behind this framework: From 2c8e956a82fd7ee80c9317fdbca1ef280838fefd Mon Sep 17 00:00:00 2001 From: sebas77 Date: Tue, 9 Jan 2018 11:11:35 +0000 Subject: [PATCH 15/22] working on a better folder structure --- .gitignore | 3 - DataStructures/CircularBufferIndexer.cs | 183 ---- DataStructures/FasterList.cs | 807 ------------------ DataStructures/HashableWeakReference.cs | 56 -- DataStructures/LockFreeQueue.cs | 142 --- .../PriorityQueue/HeapPriorityQueue.cs | 327 ------- .../PriorityQueue/IPriorityQueue.cs | 23 - .../PriorityQueue/PriorityQueueNode.cs | 24 - DataStructures/ReadOnlyDictionary.cs | 544 ------------ DataStructures/ThreadSafeDictionary.cs | 290 ------- DataStructures/ThreadSafeQueue.cs | 233 ----- DataStructures/WeakReference.cs | 79 -- ECS/EngineNodeDB.cs | 109 --- ECS/EnginesRoot.cs | 544 ------------ ECS/EntityDescriptor.cs | 196 ----- .../Unity/UnitySumbmissionNodeScheduler.cs | 41 - ECS/GenericEntityDescriptor.cs | 239 ------ ECS/GenericEntityDescriptorHolder.cs | 30 - ECS/ICallBackOnAddEngine.cs | 7 - ECS/IEngine.cs | 62 -- ECS/IEngineNodeDB.cs | 19 - ECS/IEnginesRoot.cs | 16 - ECS/IEntityDescriptorHolder.cs | 11 - ECS/INode.cs | 32 - ECS/IRemoveEntityComponent.cs | 19 - ECS/MultiNodesEngine.cs | 47 - ECS/NodeSubmissionScheduler.cs | 9 - ECS/SingleNodeEngine.cs | 21 - ECS/StructNodes.cs | 134 --- ECS/note.txt | 111 --- Svelto.Common | 1 + Svelto.ECS/.gitignore | 4 + .../Context}/ContextNotifier.cs | 0 .../Context}/Factories/GameObjectFactory.cs | 0 .../Factories/MonoBehaviourFactory.cs | 1 - .../Context}/ICompositionRoot.cs | 0 .../Context}/IContextNotifer.cs | 0 Svelto.ECS/Context/IUnityCompositionRoot.cs | 11 + .../Context}/IWaitForFrameworkDestruction.cs | 2 - .../IWaitForFrameworkInitialization.cs | 2 - .../Context}/UnityContext.cs | 5 + .../ECS/DataStructures/TypeSafeDictionary.cs | 51 ++ .../TypeSafeFasterListForECS.cs | 148 ++++ .../ECS}/Dispatcher/DispatchOnChange.cs | 0 .../ECS}/Dispatcher/DispatcherOnSet.cs | 0 Svelto.ECS/ECS/EnginesRootEngines.cs | 143 ++++ Svelto.ECS/ECS/EnginesRootEntities.cs | 411 +++++++++ Svelto.ECS/ECS/EnginesRootSubmission.cs | 165 ++++ Svelto.ECS/ECS/EntityDescriptor.cs | 272 ++++++ Svelto.ECS/ECS/EntitySubmissionScheduler.cs | 9 + Svelto.ECS/ECS/EntityView.cs | 59 ++ Svelto.ECS/ECS/EntityViewBuilder.cs | 99 +++ Svelto.ECS/ECS/EntityViewsDB.cs | 165 ++++ .../ECS/Experimental/StructNodeCollections.cs | 180 ++++ .../Unity/GenericEntityDescriptorHolder.cs | 14 + .../UnitySumbmissionEntityViewScheduler .cs | 53 ++ Svelto.ECS/ECS/GenericEntityDescriptor.cs | 110 +++ Svelto.ECS/ECS/IEngine.cs | 21 + Svelto.ECS/ECS/IEngineEntityViewDB.cs | 22 + Svelto.ECS/ECS/IEnginesInterfaces.cs | 29 + Svelto.ECS/ECS/IEntityDescriptorHolder.cs | 7 + Svelto.ECS/ECS/IEntityViewsDB.cs | 22 + Svelto.ECS/ECS/MixedEntityDescriptor.cs | 107 +++ Svelto.ECS/ECS/MultiEntityViewsEngine.cs | 118 +++ .../EngineProfiler/EngineProfilerInspector.cs | 2 +- .../EngineProfiler/EngineProfilerMenuItem.cs | 0 .../Editor/EngineProfiler/EnginesMonitor.cs | 0 .../EngineProfiler/ProfilerEditorLayout.cs | 0 .../ECS}/Profiler/EngineInfo.cs | 16 +- .../ECS}/Profiler/EngineProfiler.cs | 16 +- .../ECS}/Profiler/EngineProfilerBehaviour.cs | 0 Svelto.ECS/ECS/RemoveEntityImplementor.cs | 36 + {ECS => Svelto.ECS/ECS}/Sequencer.cs | 0 Svelto.ECS/ECS/SingleEntityViewEngine.cs | 20 + .../Factories}/IGameObjectFactory.cs | 2 + .../Factories}/IMonoBehaviourFactory.cs | 3 + LICENSE => Svelto.ECS/LICENSE | 0 README.md => Svelto.ECS/README.md | 0 Utilities/Console.cs | 152 ---- Utilities/DesignByContract.cs | 459 ---------- Utilities/FastConcatUtility.cs | 99 --- Utilities/ILogger.cs | 14 - Utilities/Murmur3.cs | 120 --- Utilities/PropertyInfoExtensions.cs | 24 - Utilities/SimpleLogger.cs | 24 - Utilities/SlowLoggerUnity.cs | 26 - WeakEvents/SafeEvent.cs | 47 - WeakEvents/WeakAction.cs | 92 -- WeakEvents/WeakActionStruct.cs | 154 ---- WeakEvents/WeakEvent.cs | 163 ---- 90 files changed, 2303 insertions(+), 5755 deletions(-) delete mode 100644 DataStructures/CircularBufferIndexer.cs delete mode 100644 DataStructures/FasterList.cs delete mode 100644 DataStructures/HashableWeakReference.cs delete mode 100644 DataStructures/LockFreeQueue.cs delete mode 100644 DataStructures/PriorityQueue/HeapPriorityQueue.cs delete mode 100644 DataStructures/PriorityQueue/IPriorityQueue.cs delete mode 100644 DataStructures/PriorityQueue/PriorityQueueNode.cs delete mode 100644 DataStructures/ReadOnlyDictionary.cs delete mode 100644 DataStructures/ThreadSafeDictionary.cs delete mode 100644 DataStructures/ThreadSafeQueue.cs delete mode 100644 DataStructures/WeakReference.cs delete mode 100644 ECS/EngineNodeDB.cs delete mode 100644 ECS/EnginesRoot.cs delete mode 100644 ECS/EntityDescriptor.cs delete mode 100644 ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs delete mode 100644 ECS/GenericEntityDescriptor.cs delete mode 100644 ECS/GenericEntityDescriptorHolder.cs delete mode 100644 ECS/ICallBackOnAddEngine.cs delete mode 100644 ECS/IEngine.cs delete mode 100644 ECS/IEngineNodeDB.cs delete mode 100644 ECS/IEnginesRoot.cs delete mode 100644 ECS/IEntityDescriptorHolder.cs delete mode 100644 ECS/INode.cs delete mode 100644 ECS/IRemoveEntityComponent.cs delete mode 100644 ECS/MultiNodesEngine.cs delete mode 100644 ECS/NodeSubmissionScheduler.cs delete mode 100644 ECS/SingleNodeEngine.cs delete mode 100644 ECS/StructNodes.cs delete mode 100644 ECS/note.txt create mode 160000 Svelto.Common create mode 100644 Svelto.ECS/.gitignore rename {Context => Svelto.ECS/Context}/ContextNotifier.cs (100%) rename {Context => Svelto.ECS/Context}/Factories/GameObjectFactory.cs (100%) rename {Context => Svelto.ECS/Context}/Factories/MonoBehaviourFactory.cs (91%) rename {Context => Svelto.ECS/Context}/ICompositionRoot.cs (100%) rename {Context => Svelto.ECS/Context}/IContextNotifer.cs (100%) create mode 100644 Svelto.ECS/Context/IUnityCompositionRoot.cs rename {Context => Svelto.ECS/Context}/IWaitForFrameworkDestruction.cs (88%) rename {Context => Svelto.ECS/Context}/IWaitForFrameworkInitialization.cs (88%) rename {Context => Svelto.ECS/Context}/UnityContext.cs (76%) create mode 100644 Svelto.ECS/ECS/DataStructures/TypeSafeDictionary.cs create mode 100644 Svelto.ECS/ECS/DataStructures/TypeSafeFasterListForECS.cs rename {ECS => Svelto.ECS/ECS}/Dispatcher/DispatchOnChange.cs (100%) rename {ECS => Svelto.ECS/ECS}/Dispatcher/DispatcherOnSet.cs (100%) create mode 100644 Svelto.ECS/ECS/EnginesRootEngines.cs create mode 100644 Svelto.ECS/ECS/EnginesRootEntities.cs create mode 100644 Svelto.ECS/ECS/EnginesRootSubmission.cs create mode 100644 Svelto.ECS/ECS/EntityDescriptor.cs create mode 100644 Svelto.ECS/ECS/EntitySubmissionScheduler.cs create mode 100644 Svelto.ECS/ECS/EntityView.cs create mode 100644 Svelto.ECS/ECS/EntityViewBuilder.cs create mode 100644 Svelto.ECS/ECS/EntityViewsDB.cs create mode 100644 Svelto.ECS/ECS/Experimental/StructNodeCollections.cs create mode 100644 Svelto.ECS/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs create mode 100644 Svelto.ECS/ECS/Extensions/Unity/UnitySumbmissionEntityViewScheduler .cs create mode 100644 Svelto.ECS/ECS/GenericEntityDescriptor.cs create mode 100644 Svelto.ECS/ECS/IEngine.cs create mode 100644 Svelto.ECS/ECS/IEngineEntityViewDB.cs create mode 100644 Svelto.ECS/ECS/IEnginesInterfaces.cs create mode 100644 Svelto.ECS/ECS/IEntityDescriptorHolder.cs create mode 100644 Svelto.ECS/ECS/IEntityViewsDB.cs create mode 100644 Svelto.ECS/ECS/MixedEntityDescriptor.cs create mode 100644 Svelto.ECS/ECS/MultiEntityViewsEngine.cs rename {ECS => Svelto.ECS/ECS}/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs (99%) rename {ECS => Svelto.ECS/ECS}/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs (100%) rename {ECS => Svelto.ECS/ECS}/Profiler/Editor/EngineProfiler/EnginesMonitor.cs (100%) rename {ECS => Svelto.ECS/ECS}/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs (100%) rename {ECS => Svelto.ECS/ECS}/Profiler/EngineInfo.cs (91%) rename {ECS => Svelto.ECS/ECS}/Profiler/EngineProfiler.cs (82%) rename {ECS => Svelto.ECS/ECS}/Profiler/EngineProfilerBehaviour.cs (100%) create mode 100644 Svelto.ECS/ECS/RemoveEntityImplementor.cs rename {ECS => Svelto.ECS/ECS}/Sequencer.cs (100%) create mode 100644 Svelto.ECS/ECS/SingleEntityViewEngine.cs rename {Factories => Svelto.ECS/Factories}/IGameObjectFactory.cs (87%) rename {Factories => Svelto.ECS/Factories}/IMonoBehaviourFactory.cs (80%) rename LICENSE => Svelto.ECS/LICENSE (100%) rename README.md => Svelto.ECS/README.md (100%) delete mode 100644 Utilities/Console.cs delete mode 100644 Utilities/DesignByContract.cs delete mode 100644 Utilities/FastConcatUtility.cs delete mode 100644 Utilities/ILogger.cs delete mode 100644 Utilities/Murmur3.cs delete mode 100644 Utilities/PropertyInfoExtensions.cs delete mode 100644 Utilities/SimpleLogger.cs delete mode 100644 Utilities/SlowLoggerUnity.cs delete mode 100644 WeakEvents/SafeEvent.cs delete mode 100644 WeakEvents/WeakAction.cs delete mode 100644 WeakEvents/WeakActionStruct.cs delete mode 100644 WeakEvents/WeakEvent.cs diff --git a/.gitignore b/.gitignore index ac529bb..c6bb293 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ -/EntitySystem/note.txt -/EntitySystem/note.txt.meta -/*.meta *.meta diff --git a/DataStructures/CircularBufferIndexer.cs b/DataStructures/CircularBufferIndexer.cs deleted file mode 100644 index 6d86441..0000000 --- a/DataStructures/CircularBufferIndexer.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Svelto.DataStructures -{ - // Serves as simple circular buffer dictionary, first in, first out - // Main drawback: it is the oldest in the list that is removed and the fact that we might re access a key - // isn't taken into account (we would have to do a shift in both arrays) - // Could be added as an option? - - public class CircularBufferIndexer : IDictionary - { - public ICollection Keys - { - get { return _keys; } - } - - public ICollection Values - { - get { return _values; } - } - - public int Count - { - get { throw new NotImplementedException(); } - } - - public bool IsReadOnly - { - get { throw new NotImplementedException(); } - } - - public CircularBufferIndexer(int size) - { - _keys = new TKey[size]; - _values = new TVal[size]; - _length = _startIndex = _nextIndex = 0; - } - - public TVal this[TKey key] - { - get - { - int index = _startIndex; - for (int i = 0; i < _length; ++i) - { - if (_keys[index].Equals(key)) - { - return _values[index]; - } - - index = NextPosition(index); - } - throw new KeyNotFoundException(); - } - set - { - int index = _startIndex; - for (int i = 0; i < _length; ++i) - { - if (_keys[index].Equals(key)) - { - _values[index] = value; - return; - } - - index = NextPosition(index); - } - throw new KeyNotFoundException(); - } - } - - public void Add(TKey key, TVal value) - { - if (ContainsKey(key)) - { - this[key] = value; - return; - } - - _keys[_nextIndex] = key; - _values[_nextIndex] = value; - _nextIndex = NextPosition(_nextIndex); - if (IsFull()) - { - _startIndex = NextPosition(_startIndex); - } - else - { - ++_length; - } - } - - public bool ContainsKey(TKey key) - { - int index = _startIndex; - for (int i = 0; i < _length; ++i) - { - if (_keys[index].Equals(key)) - { - return true; - } - - index = NextPosition(index); - } - return false; - } - - public bool Remove(TKey key) - { - throw new NotImplementedException(); - } - - public bool TryGetValue(TKey key, out TVal value) - { - value = default(TVal); - int index = _startIndex; - for (int i = 0; i < _length; ++i) - { - if (_keys[index].Equals(key)) - { - value = _values[index]; - return true; - } - - index = NextPosition(index); - } - return false; - } - - public IEnumerator GetEnumerator() - { - throw new NotImplementedException(); - } - - public void Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } - - public void Clear() - { - throw new NotImplementedException(); - } - - public bool Contains(KeyValuePair item) - { - throw new NotImplementedException(); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - throw new NotImplementedException(); - } - - public bool Remove(KeyValuePair item) - { - throw new NotImplementedException(); - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - throw new NotImplementedException(); - } - - int NextPosition(int position) - { - return (position + 1) % _keys.Length; - } - - bool IsFull() - { - return _length == _values.Length; - } - - TKey[] _keys; - TVal[] _values; - int _startIndex; - int _nextIndex; - int _length; - } -} diff --git a/DataStructures/FasterList.cs b/DataStructures/FasterList.cs deleted file mode 100644 index d87c13b..0000000 --- a/DataStructures/FasterList.cs +++ /dev/null @@ -1,807 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Threading; - -namespace Svelto.DataStructures -{ - public struct FasterListEnumerator : IEnumerator - { - public T Current - { - get { return _current; } - } - - public FasterListEnumerator(T[] buffer, int size) - { - _size = size; - _counter = 0; - _buffer = buffer; - _current = default(T); - } - - object IEnumerator.Current - { - get { return _current; } - } - - T IEnumerator.Current - { - get { return _current; } - } - - public void Dispose() - { - _buffer = null; - } - - public bool MoveNext() - { - if (_counter < _size) - { - _current = _buffer[_counter++]; - - return true; - } - - _current = default(T); - - return false; - } - - public void Reset() - { - _counter = 0; - } - - bool IEnumerator.MoveNext() - { - return MoveNext(); - } - - void IEnumerator.Reset() - { - Reset(); - } - - T[] _buffer; - int _counter; - int _size; - T _current; - } - - public struct FasterListEnumeratorCast : IEnumerator where T:U - { - public T Current - { - get { return (T)_buffer.Current; } - } - - public FasterListEnumeratorCast(FasterListEnumerator buffer) - { - _buffer = buffer; - } - - object IEnumerator.Current - { - get { return (T)_buffer.Current; } - } - - T IEnumerator.Current - { - get { return (T)_buffer.Current; } - } - - public void Dispose() - {} - - public bool MoveNext() - { - return _buffer.MoveNext(); - } - - public void Reset() - { - _buffer.Reset(); - } - - bool IEnumerator.MoveNext() - { - return MoveNext(); - } - - void IEnumerator.Reset() - { - Reset(); - } - - FasterListEnumerator _buffer; - } - - public struct FasterReadOnlyList : IList - { - public static FasterReadOnlyList DefaultList = new FasterReadOnlyList(new FasterList()); - - public int Count { get { return _list.Count; } } - public bool IsReadOnly { get { return true; } } - - public FasterReadOnlyList(FasterList list) - { - _list = list; - } - - public T this[int index] { get { return _list[index]; } set { throw new NotImplementedException(); } } - - public FasterListEnumerator GetEnumerator() - { - return _list.GetEnumerator(); - } - - public void Add(T item) - { - throw new NotImplementedException(); - } - - public void Clear() - { - throw new NotImplementedException(); - } - - public bool Contains(T item) - { - return _list.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - _list.CopyTo(array, arrayIndex); - } - - public bool Remove(T item) - { - throw new NotImplementedException(); - } - - public int IndexOf(T item) - { - return _list.IndexOf(item); - } - - public void Insert(int index, T item) - { - throw new NotImplementedException(); - } - - public void RemoveAt(int index) - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - readonly FasterList _list; - } - - public struct FasterListThreadSafe : IList - { - public FasterListThreadSafe(FasterList list) - { - if (list == null) throw new ArgumentException("invalid list"); - _list = list; - _lockQ = new ReaderWriterLockSlim(); - } - - public int Count - { - get - { - _lockQ.EnterReadLock(); - try - { - return _list.Count; - } - finally - { - _lockQ.ExitReadLock(); - } - } - } - public bool IsReadOnly { get { return false; } } - - public T this[int index] - { - get - { - _lockQ.EnterReadLock(); - try - { - return _list[index]; - } - finally - { - _lockQ.ExitReadLock(); - } - } - set - { - _lockQ.EnterWriteLock(); - try - { - _list[index] = value; - } - finally - { - _lockQ.ExitWriteLock(); - } - } - } - - public FasterListEnumerator GetEnumerator() - { - throw new NotImplementedException(); - } - - public void Add(T item) - { - _lockQ.EnterWriteLock(); - try - { - _list.Add(item); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public void Clear() - { - _lockQ.EnterWriteLock(); - try - { - _list.Clear(); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public void FastClear() - { - _lockQ.EnterWriteLock(); - try - { - _list.FastClear(); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public bool Contains(T item) - { - _lockQ.EnterReadLock(); - try - { - return _list.Contains(item); - } - finally - { - _lockQ.ExitReadLock(); - } - } - - public void CopyTo(T[] array, int arrayIndex) - { - _lockQ.EnterReadLock(); - try - { - _list.CopyTo(array, arrayIndex); - } - finally - { - _lockQ.ExitReadLock(); - } - } - - public bool Remove(T item) - { - _lockQ.EnterWriteLock(); - try - { - return _list.Remove(item); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public int IndexOf(T item) - { - _lockQ.EnterReadLock(); - try - { - return _list.IndexOf(item); - } - finally - { - _lockQ.ExitReadLock(); - } - } - - public void Insert(int index, T item) - { - _lockQ.EnterWriteLock(); - try - { - _list.Insert(index, item); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public void RemoveAt(int index) - { - _lockQ.EnterWriteLock(); - try - { - _list.RemoveAt(index); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - public void UnorderedRemoveAt(int index) - { - _lockQ.EnterWriteLock(); - try - { - _list.UnorderedRemoveAt(index); - } - finally - { - _lockQ.ExitWriteLock(); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - throw new NotImplementedException(); - } - - readonly FasterList _list; - - readonly ReaderWriterLockSlim _lockQ; - } - - public struct FasterReadOnlyListCast : IList where U:T - { - public static FasterReadOnlyListCast DefaultList = new FasterReadOnlyListCast(new FasterList()); - - public int Count { get { return _list.Count; } } - public bool IsReadOnly { get { return true; } } - - public FasterReadOnlyListCast(FasterList list) - { - _list = list; - } - - public U this[int index] { get { return (U)_list[index]; } set { throw new NotImplementedException(); } } - - public FasterListEnumeratorCast GetEnumerator() - { - return new FasterListEnumeratorCast(_list.GetEnumerator()); - } - - public void Add(U item) - { - throw new NotImplementedException(); - } - - public void Clear() - { - throw new NotImplementedException(); - } - - public bool Contains(U item) - { - return _list.Contains(item); - } - - public void CopyTo(U[] array, int arrayIndex) - { - Array.Copy(_list.ToArrayFast(), 0, array, arrayIndex, _list.Count); - } - - public bool Remove(U item) - { - throw new NotImplementedException(); - } - - public int IndexOf(U item) - { - return _list.IndexOf(item); - } - - public void Insert(int index, U item) - { - throw new NotImplementedException(); - } - - public void RemoveAt(int index) - { - throw new NotImplementedException(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - readonly FasterList _list; - } - - public interface IFasterList - {} - - public class FasterList : IList, IFasterList - { - const int MIN_SIZE = 4; - - public int Count - { - get { return _count; } - } - - public bool IsReadOnly - { - get { return false; } - } - - public FasterList() - { - _count = 0; - - _buffer = new T[MIN_SIZE]; - } - - public FasterList(int initialSize) - { - _count = 0; - - _buffer = new T[initialSize]; - } - - public FasterList(ICollection collection) - { - _buffer = new T[collection.Count]; - - collection.CopyTo(_buffer, 0); - - _count = _buffer.Length; - } - - public FasterList(FasterList listCopy) - { - _buffer = new T[listCopy.Count]; - - listCopy.CopyTo(_buffer, 0); - - _count = listCopy.Count; - } - - public T this[int i] - { - get { DesignByContract.Check.Require(i < _count, "out of bound index"); return _buffer[i]; } - set { DesignByContract.Check.Require(i < _count, "out of bound index"); _buffer[i] = value; } - } - - public void Add(T item) - { - if (_count == _buffer.Length) - AllocateMore(); - - _buffer[_count++] = item; - } - - - /// - /// this is a dirtish trick to be able to use the index operastor - /// before adding the elements through the Add functions - /// - /// - /// - /// - public static FasterList PreFill(int initialSize) where U:T, new() - { - var list = new FasterList(initialSize); - - for (int i = 0; i < initialSize; i++) - list.Add(new U()); - - list._count = 0; - - return list; - } - - public void AddRange(IEnumerable items, int count) - { - AddRange(items.GetEnumerator(), count); - } - - public void AddRange(IEnumerator items, int count) - { - if (_count + count >= _buffer.Length) - AllocateMore(_count + count); - - while (items.MoveNext()) - _buffer[_count++] = items.Current; - } - - public void AddRange(ICollection items) - { - AddRange(items.GetEnumerator(), items.Count); - } - - public void AddRange(FasterList items) - { - AddRange(items.ToArrayFast(), items.Count); - } - - public void AddRange(T[] items, int count) - { - if (count == 0) return; - - if (_count + count >= _buffer.Length) - AllocateMore(_count + count); - - Array.Copy(items, 0, _buffer, _count, count); - _count += count; - } - - public void AddRange(T[] items) - { - AddRange(items, items.Length); - } - - public FasterReadOnlyList AsReadOnly() - { - return new FasterReadOnlyList(this); - } - - /// - /// Careful, you could keep on holding references you don't want to hold to anymore - /// Use DeepClear in case. - /// - public void FastClear() - { - _count = 0; - } - - public void Clear() - { - Array.Clear(_buffer, 0, _buffer.Length); - - _count = 0; - } - - public bool Contains(T item) - { - var index = IndexOf(item); - - return index != -1; - } - - public void CopyTo(T[] array, int arrayIndex) - { - Array.Copy(_buffer, 0, array, arrayIndex, Count); - } - - public FasterListEnumerator GetEnumerator() - { - return new FasterListEnumerator(_buffer, Count); - } - - public int IndexOf(T item) - { - var comp = EqualityComparer.Default; - - for (var index = _count - 1; index >= 0; --index) - if (comp.Equals(_buffer[index], item)) - return index; - - return -1; - } - - public void Insert(int index, T item) - { - DesignByContract.Check.Require(index < _count, "out of bound index"); - - if (_count == _buffer.Length) AllocateMore(); - - Array.Copy(_buffer, index, _buffer, index + 1, _count - index); - - _buffer[index] = item; - ++_count; - } - - public void Release() - { - _count = 0; - _buffer = null; - } - - public bool Remove(T item) - { - var index = IndexOf(item); - - if (index == -1) - return false; - - RemoveAt(index); - - return true; - } - - public void RemoveAt(int index) - { - DesignByContract.Check.Require(index < _count, "out of bound index"); - - if (index == --_count) - return; - - Array.Copy(_buffer, index + 1, _buffer, index, _count - index); - - _buffer[_count] = default(T); - } - - public void Resize(int newSize) - { - if (newSize < MIN_SIZE) - newSize = MIN_SIZE; - - Array.Resize(ref _buffer, newSize); - - _count = newSize; - } - - public void SetAt(int index, T value) - { - if (index >= _buffer.Length) - AllocateMore(index + 1); - - if (_count <= index) - _count = index + 1; - - this[index] = value; - } - - public void Sort(IComparer comparer) - { - Array.Sort(_buffer, 0, _count, comparer); - } - - public T[] ToArray() - { - T[] destinationArray = new T[_count]; - - Array.Copy(_buffer, 0, destinationArray, 0, _count); - - return destinationArray; - } - - /// - /// This function exists to allow fast iterations. The size of the array returned cannot be - /// used. The list count must be used instead. - /// - /// - public T[] ToArrayFast() - { - return _buffer; - } - - public bool UnorderedRemove(T item) - { - var index = IndexOf(item); - - if (index == -1) - return false; - - UnorderedRemoveAt(index); - - return true; - } - - public bool UnorderedRemoveAt(int index) - { - DesignByContract.Check.Require(index < _count && _count > 0, "out of bound index"); - - if (index == --_count) - { - _buffer[_count] = default(T); - return false; - } - - _buffer[index] = _buffer[_count]; - _buffer[_count] = default(T); - - return true; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - void AllocateMore() - { - var newList = new T[Math.Max(_buffer.Length << 1, MIN_SIZE)]; - if (_count > 0) _buffer.CopyTo(newList, 0); - _buffer = newList; - } - - void AllocateMore(int newSize) - { - var oldLength = Math.Max(_buffer.Length, MIN_SIZE); - - while (oldLength < newSize) - oldLength <<= 1; - - var newList = new T[oldLength]; - if (_count > 0) Array.Copy(_buffer, newList, _count); - _buffer = newList; - } - - public void Trim() - { - if (_count < _buffer.Length) - Resize(_count); - } - - public bool Reuse(int index, out U result) - where U:class, T - { - result = default(U); - - if (index >= _buffer.Length) - return false; - - result = (U)_buffer[index]; - - return result != null; - } - - T[] _buffer; - int _count; - } -} diff --git a/DataStructures/HashableWeakReference.cs b/DataStructures/HashableWeakReference.cs deleted file mode 100644 index 62edfa6..0000000 --- a/DataStructures/HashableWeakReference.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; - -namespace Svelto.DataStructures -{ - class HashableWeakRef : IEquatable> where T : class - { - public bool isAlive { get { return _weakRef.IsAlive; } } - public T Target { get { return (T)_weakRef.Target; } } - - public HashableWeakRef(T target) - { - _weakRef = new WeakReference(target); - _hash = target.GetHashCode(); - } - - public static bool operator !=(HashableWeakRef a, HashableWeakRef b) - { - return !(a == b); - } - - public static bool operator ==(HashableWeakRef a, HashableWeakRef b) - { - if (a._hash != b._hash) - return false; - - var tmpTargetA = (T) a._weakRef.Target; - var tmpTargetB = (T) b._weakRef.Target; - - if (tmpTargetA == null || tmpTargetB == null) - return false; - - return tmpTargetA == tmpTargetB; - } - - public override bool Equals(object other) - { - if (other is HashableWeakRef) - return this.Equals((HashableWeakRef)other); - - return false; - } - - public bool Equals(HashableWeakRef other) - { - return (this == other); - } - - public override int GetHashCode() - { - return _hash; - } - - int _hash; - WeakReference _weakRef; - } -} diff --git a/DataStructures/LockFreeQueue.cs b/DataStructures/LockFreeQueue.cs deleted file mode 100644 index 4c55f39..0000000 --- a/DataStructures/LockFreeQueue.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System.Collections.Generic; -using System.Threading; - -//from unify wiki -namespace Svelto.DataStructures -{ - public class SingleLinkNode - { - // Note; the Next member cannot be a property since - // it participates in many CAS operations - public SingleLinkNode Next; - public T Item; - } - - public static class SyncMethods - { - public static bool CAS(ref T location, T comparand, T newValue) where T : class - { - return - (object)comparand == - (object)Interlocked.CompareExchange(ref location, newValue, comparand); - } - } - - public class LockFreeLinkPool - { - private SingleLinkNode head; - - public LockFreeLinkPool() - { - head = new SingleLinkNode(); - } - - public void Push(SingleLinkNode newNode) - { - newNode.Item = default(T); - do - { - newNode.Next = head.Next; - } while (!SyncMethods.CAS>(ref head.Next, newNode.Next, newNode)); - return; - } - - public bool Pop(out SingleLinkNode node) - { - do - { - node = head.Next; - if (node == null) - { - return false; - } - } while (!SyncMethods.CAS>(ref head.Next, node, node.Next)); - return true; - } - } - - public class LockFreeQueue - { - - SingleLinkNode head; - SingleLinkNode tail; - LockFreeLinkPool trash; - - public LockFreeQueue() - { - head = new SingleLinkNode(); - tail = head; - trash = new LockFreeLinkPool(); - } - - public void Enqueue(T item) - { - SingleLinkNode oldTail = null; - SingleLinkNode oldTailNext; - - SingleLinkNode newNode; - if (!trash.Pop(out newNode)) - { - newNode = new SingleLinkNode(); - } - else - { - newNode.Next = null; - } - newNode.Item = item; - - bool newNodeWasAdded = false; - while (!newNodeWasAdded) - { - oldTail = tail; - oldTailNext = oldTail.Next; - - if (tail == oldTail) - { - if (oldTailNext == null) - newNodeWasAdded = SyncMethods.CAS>(ref tail.Next, null, newNode); - else - SyncMethods.CAS>(ref tail, oldTail, oldTailNext); - } - } - SyncMethods.CAS>(ref tail, oldTail, newNode); - } - - public bool Dequeue(out T item) - { - item = default(T); - SingleLinkNode oldHead = null; - - bool haveAdvancedHead = false; - while (!haveAdvancedHead) - { - - oldHead = head; - SingleLinkNode oldTail = tail; - SingleLinkNode oldHeadNext = oldHead.Next; - - if (oldHead == head) - { - if (oldHead == oldTail) - { - if (oldHeadNext == null) - { - return false; - } - SyncMethods.CAS>(ref tail, oldTail, oldHeadNext); - } - else - { - item = oldHeadNext.Item; - haveAdvancedHead = SyncMethods.CAS>(ref head, oldHead, oldHeadNext); - if (haveAdvancedHead) - { - trash.Push(oldHead); - } - } - } - } - return true; - } - } -} \ No newline at end of file diff --git a/DataStructures/PriorityQueue/HeapPriorityQueue.cs b/DataStructures/PriorityQueue/HeapPriorityQueue.cs deleted file mode 100644 index 606acd5..0000000 --- a/DataStructures/PriorityQueue/HeapPriorityQueue.cs +++ /dev/null @@ -1,327 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using Svelto.DataStructures; - -namespace Svelto.DataStructures -{ - /// - /// An implementation of a min-Priority Queue using a heap. Has O(1) .Contains()! - /// See https://bitbucket.org/BlueRaja/high-speed-priority-queue-for-c/wiki/Getting%20Started for more information - /// - /// The values in the queue. Must implement the PriorityQueueNode interface - public sealed class HeapPriorityQueue : IPriorityQueue - where T : PriorityQueueNode - { - private int _numNodes; - private readonly FasterList _nodes; - private long _numNodesEverEnqueued; - - /// - /// Instantiate a new Priority Queue - /// - /// The max nodes ever allowed to be enqueued (going over this will cause an exception) - public HeapPriorityQueue() - { - _numNodes = 0; - _nodes = new FasterList(); - _numNodesEverEnqueued = 0; - } - - public HeapPriorityQueue(int initialSize) - { - _numNodes = 0; - _nodes = new FasterList(initialSize); - _numNodesEverEnqueued = 0; - } - - /// - /// Returns the number of nodes in the queue. O(1) - /// - public int Count - { - get - { - return _numNodes; - } - } - - /// - /// Returns the maximum number of items that can be enqueued at once in this queue. Once you hit this number (ie. once Count == MaxSize), - /// attempting to enqueue another item will throw an exception. O(1) - /// - public int MaxSize - { - get - { - return _nodes.Count - 1; - } - } - - /// - /// Removes every node from the queue. O(n) (So, don't do this often!) - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - public void Clear() - { - _nodes.FastClear(); - - _numNodes = 0; - } - - /// - /// Returns (in O(1)!) whether the given node is in the queue. O(1) - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - public bool Contains(T node) - { - return (_nodes[node.QueueIndex] == node); - } - - /// - /// Enqueue a node - .Priority must be set beforehand! O(log n) - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - public void Enqueue(T node, double priority) - { - node.Priority = priority; - _numNodes++; - if (_nodes.Count < _numNodes) - _nodes.Resize(_numNodes + 1); - - _nodes[_numNodes] = node; - node.QueueIndex = _numNodes; - node.InsertionIndex = _numNodesEverEnqueued++; - CascadeUp(_nodes[_numNodes]); - } - - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - private void Swap(T node1, T node2) - { - //Swap the nodes - _nodes[node1.QueueIndex] = node2; - _nodes[node2.QueueIndex] = node1; - - //Swap their indicies - int temp = node1.QueueIndex; - node1.QueueIndex = node2.QueueIndex; - node2.QueueIndex = temp; - } - - //Performance appears to be slightly better when this is NOT inlined o_O - private void CascadeUp(T node) - { - //aka Heapify-up - int parent = node.QueueIndex / 2; - while(parent >= 1) - { - T parentNode = _nodes[parent]; - if(HasHigherPriority(parentNode, node)) - break; - - //Node has lower priority value, so move it up the heap - Swap(node, parentNode); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown() - - parent = node.QueueIndex / 2; - } - } - - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - private void CascadeDown(T node) - { - //aka Heapify-down - T newParent; - int finalQueueIndex = node.QueueIndex; - while(true) - { - newParent = node; - int childLeftIndex = 2 * finalQueueIndex; - - //Check if the left-child is higher-priority than the current node - if(childLeftIndex > _numNodes) - { - //This could be placed outside the loop, but then we'd have to check newParent != node twice - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; - break; - } - - T childLeft = _nodes[childLeftIndex]; - if(HasHigherPriority(childLeft, newParent)) - { - newParent = childLeft; - } - - //Check if the right-child is higher-priority than either the current node or the left child - int childRightIndex = childLeftIndex + 1; - if(childRightIndex <= _numNodes) - { - T childRight = _nodes[childRightIndex]; - if(HasHigherPriority(childRight, newParent)) - { - newParent = childRight; - } - } - - //If either of the children has higher (smaller) priority, swap and continue cascading - if(newParent != node) - { - //Move new parent to its new index. node will be moved once, at the end - //Doing it this way is one less assignment operation than calling Swap() - _nodes[finalQueueIndex] = newParent; - - int temp = newParent.QueueIndex; - newParent.QueueIndex = finalQueueIndex; - finalQueueIndex = temp; - } - else - { - //See note above - node.QueueIndex = finalQueueIndex; - _nodes[finalQueueIndex] = node; - break; - } - } - } - - /// - /// Returns true if 'higher' has higher priority than 'lower', false otherwise. - /// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - private bool HasHigherPriority(T higher, T lower) - { - return (higher.Priority < lower.Priority || - (higher.Priority == lower.Priority && higher.InsertionIndex < lower.InsertionIndex)); - } - - /// - /// Removes the head of the queue (node with highest priority; ties are broken by order of insertion), and returns it. O(log n) - /// - public T Dequeue() - { - T returnMe = _nodes[1]; - Remove(returnMe); - return returnMe; - } - - /// - /// Returns the head of the queue, without removing it (use Dequeue() for that). O(1) - /// - public T First - { - get - { - return _nodes[1]; - } - } - - /// - /// This method must be called on a node every time its priority changes while it is in the queue. - /// Forgetting to call this method will result in a corrupted queue! - /// O(log n) - /// - #if NET_VERSION_4_5 - [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - public void UpdatePriority(T node, double priority) - { - node.Priority = priority; - OnNodeUpdated(node); - } - - private void OnNodeUpdated(T node) - { - //Bubble the updated node up or down as appropriate - int parentIndex = node.QueueIndex / 2; - T parentNode = _nodes[parentIndex]; - - if(parentIndex > 0 && HasHigherPriority(node, parentNode)) - { - CascadeUp(node); - } - else - { - //Note that CascadeDown will be called if parentNode == node (that is, node is the root) - CascadeDown(node); - } - } - - /// - /// Removes a node from the queue. Note that the node does not need to be the head of the queue. O(log n) - /// - public void Remove(T node) - { - if(_numNodes <= 1) - { - _nodes[1] = null; - _numNodes = 0; - return; - } - - //Make sure the node is the last node in the queue - bool wasSwapped = false; - T formerLastNode = _nodes[_numNodes]; - if(node.QueueIndex != _numNodes) - { - //Swap the node with the last node - Swap(node, formerLastNode); - wasSwapped = true; - } - - _numNodes--; - _nodes[node.QueueIndex] = null; - - if(wasSwapped) - { - //Now bubble formerLastNode (which is no longer the last node) up or down as appropriate - OnNodeUpdated(formerLastNode); - } - } - - public IEnumerator GetEnumerator() - { - for(int i = 1; i <= _numNodes; i++) - yield return _nodes[i]; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Should not be called in production code. - /// Checks to make sure the queue is still in a valid state. Used for testing/debugging the queue. - /// - public bool IsValidQueue() - { - for(int i = 1; i < _nodes.Count; i++) - { - if(_nodes[i] != null) - { - int childLeftIndex = 2 * i; - if(childLeftIndex < _nodes.Count && _nodes[childLeftIndex] != null && HasHigherPriority(_nodes[childLeftIndex], _nodes[i])) - return false; - - int childRightIndex = childLeftIndex + 1; - if(childRightIndex < _nodes.Count && _nodes[childRightIndex] != null && HasHigherPriority(_nodes[childRightIndex], _nodes[i])) - return false; - } - } - return true; - } - } -} \ No newline at end of file diff --git a/DataStructures/PriorityQueue/IPriorityQueue.cs b/DataStructures/PriorityQueue/IPriorityQueue.cs deleted file mode 100644 index 632820e..0000000 --- a/DataStructures/PriorityQueue/IPriorityQueue.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; - -namespace Svelto.DataStructures -{ - /// - /// The IPriorityQueue interface. This is mainly here for purists, and in case I decide to add more implementations later. - /// For speed purposes, it is actually recommended that you *don't* access the priority queue through this interface, since the JIT can - /// (theoretically?) optimize method calls from concrete-types slightly better. - /// - public interface IPriorityQueue : IEnumerable - where T : PriorityQueueNode - { - void Remove(T node); - void UpdatePriority(T node, double priority); - void Enqueue(T node, double priority); - T Dequeue(); - T First { get; } - int Count { get; } - int MaxSize { get; } - void Clear(); - bool Contains(T node); - } -} diff --git a/DataStructures/PriorityQueue/PriorityQueueNode.cs b/DataStructures/PriorityQueue/PriorityQueueNode.cs deleted file mode 100644 index b09f3a4..0000000 --- a/DataStructures/PriorityQueue/PriorityQueueNode.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Svelto.DataStructures -{ - public class PriorityQueueNode - { - /// - /// The Priority to insert this node at. Must be set BEFORE adding a node to the queue - /// - public double Priority { get; - set; - } - - /// - /// Used by the priority queue - do not edit this value. - /// Represents the order the node was inserted in - /// - public long InsertionIndex { get; set; } - - /// - /// Used by the priority queue - do not edit this value. - /// Represents the current position in the queue - /// - public int QueueIndex { get; set; } - } -} diff --git a/DataStructures/ReadOnlyDictionary.cs b/DataStructures/ReadOnlyDictionary.cs deleted file mode 100644 index 8b09f3a..0000000 --- a/DataStructures/ReadOnlyDictionary.cs +++ /dev/null @@ -1,544 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace Svelto.DataStructures -{ - public struct ReadOnlyDictionary : IDictionary - { - public bool isInitialized { get { return _dictionary != null; } } - - /// - /// Gets the element that has the specified key. - /// - /// The key of the element to get. - /// The element that has the specified key. - /// If is . - /// If property is retrieved and is not found. - public TValue this[TKey key] - { - get - { - return _dictionary[key]; - } - } - - /// - /// Gets the number of items in the dictionary. - /// - /// - /// The number of items in the dictionary. - /// - public int Count - { - get - { - return _dictionary.Count; - } - } - - /// - /// Gets a key collection that contains the keys of the dictionary. - /// - /// - /// A key collection that contains the keys of the dictionary. - /// - public KeyCollection Keys - { - get - { - return new KeyCollection(_dictionary.Keys); - } - } - - /// - /// Gets a collection that contains the values in the dictionary. - /// - /// - /// A collection that contains the values in the object that implements . - /// - public ValueCollection Values - { - get - { - return new ValueCollection(_dictionary.Values); - } - } - - /// - /// Initializes a new instance of the class - /// that is a wrapper around the specified dictionary. - /// - /// The dictionary to wrap. - public ReadOnlyDictionary(Dictionary dictionary) - { - if (dictionary == null) - throw new ArgumentNullException("dictionary"); - - _dictionary = dictionary; - } - - /// - /// - /// Gets the element that has the specified key. - /// - /// If the property is set. - TValue IDictionary.this[TKey key] - { - get - { - return this[key]; - } - - set - { - throw new NotSupportedException(); - } - } - - /// - ICollection IDictionary.Keys - { - get - { - return Keys; - } - } - - /// - ICollection IDictionary.Values - { - get - { - return Values; - } - } - - /// - bool ICollection>.IsReadOnly - { - get - { - return true; - } - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - void IDictionary.Add(TKey key, TValue value) - { - throw new NotSupportedException(); - } - - /// - bool IDictionary.Remove(TKey key) - { - throw new NotSupportedException(); - } - - /// - void ICollection>.Add(KeyValuePair item) - { - throw new NotSupportedException(); - } - - /// - void ICollection>.Clear() - { - throw new NotSupportedException(); - } - - /// - bool ICollection>.Contains(KeyValuePair item) - { - throw new NotImplementedException(); - } - - /// - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - { - throw new NotImplementedException(); - } - - /// - bool ICollection>.Remove(KeyValuePair item) - { - throw new NotSupportedException(); - } - - bool IDictionary.ContainsKey(TKey key) - { - return _dictionary.ContainsKey(key); - } - - bool IDictionary.TryGetValue(TKey key, out TValue value) - { - return _dictionary.TryGetValue(key, out value); - } - - int ICollection>.Count - { - get { return _dictionary.Count; } - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - return _dictionary.GetEnumerator(); - } - - /// - /// Determines whether the dictionary contains an element that has the specified key. - /// - /// The key to locate in the dictionary. - /// if the dictionary contains an element that has the specified key; otherwise, . - public bool ContainsKey(TKey key) - { - return _dictionary.ContainsKey(key); - } - - public DictionaryEnumerator GetEnumerator() - { - return new DictionaryEnumerator(_dictionary); - } - - /// - /// Retrieves the value that is associated with the specified key. - /// - /// The key whose value will be retrieved. - /// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. - /// if the object that implements contains an element with the specified key; otherwise, . - public bool TryGetValue(TKey key, out TValue value) - { - return _dictionary.TryGetValue(key, out value); - } - - readonly Dictionary _dictionary; - - /// - /// Represents a read-only collection of the keys of a object. - /// - public struct KeyCollection : ICollection, ICollection - { - /// - /// Initializes a new instance of the class - /// as a wrapper around the specified collection of keys. - /// - /// The collection of keys to wrap. - /// If is . - internal KeyCollection(ICollection keys) - { - if (keys == null) - throw new ArgumentNullException("keys"); - - _keys = keys; - } - - /// - bool ICollection.IsSynchronized - { - get - { - return false; - } - } - - /// - object ICollection.SyncRoot - { - get - { - throw new NotImplementedException(); - } - } - - /// - void ICollection.CopyTo(Array array, int index) - { - throw new NotImplementedException(); - } - - /// - /// Gets the number of elements in the collection. - /// - /// - /// The number of elements in the collection. - /// - public int Count - { - get - { - return _keys.Count; - } - } - - /// - bool ICollection.IsReadOnly - { - get - { - return true; - } - } - - /// - /// Copies the elements of the collection to an array, starting at a specific array index. - /// - /// The one-dimensional array that is the destination of the elements copied from the collection. The array must have zero-based indexing. - /// The zero-based index in at which copying begins. - /// If is . - /// If is less than 0. - /// - /// If is multidimensional. - /// -or- - /// If the number of elements in the source collection is greater than the available space from to the end of the destination . - /// -or- - /// If the type cannot be cast automatically to the type of the destination . - /// - public void CopyTo(TKey[] array, int arrayIndex) - { - _keys.CopyTo(array, arrayIndex); - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator GetEnumerator() - { - return _keys.GetEnumerator(); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - bool ICollection.Contains(TKey item) - { - return _keys.Contains(item); - } - - /// - void ICollection.Add(TKey item) - { - throw new NotSupportedException(); - } - - /// - bool ICollection.Remove(TKey item) - { - throw new NotSupportedException(); - } - - /// - void ICollection.Clear() - { - throw new NotSupportedException(); - } - - /// - /// The wrapped collection of keys. - /// - readonly ICollection _keys; - } - - /// - /// Represents a read-only collection of the values of a object. - /// - public struct ValueCollection : ICollection, ICollection - { - /// - /// Initializes a new instance of the class - /// as a wrapper around the specified collection of values. - /// - /// The collection of values to wrap. - /// If is . - internal ValueCollection(ICollection values) - { - if (values == null) - throw new ArgumentNullException("values"); - - _values = values; - } - - /// - bool ICollection.IsSynchronized - { - get - { - return false; - } - } - - /// - object ICollection.SyncRoot - { - get - { - throw new NotImplementedException(); - } - } - - /// - void ICollection.CopyTo(Array array, int index) - { - throw new NotImplementedException(); - } - - /// - /// Gets the number of elements in the collection. - /// - /// - /// The number of elements in the collection. - /// - public int Count - { - get - { - return _values.Count; - } - } - - /// - bool ICollection.IsReadOnly - { - get - { - return true; - } - } - - /// - /// Copies the elements of the collection to an array, starting at a specific array index. - /// - /// The one-dimensional array that is the destination of the elements copied from the collection. The array must have zero-based indexing. - /// The zero-based index in at which copying begins. - /// If is . - /// If is less than 0. - /// - /// If is multidimensional. - /// -or- - /// If the number of elements in the source collection is greater than the available space from to the end of the destination . - /// -or- - /// If the type cannot be cast automatically to the type of the destination . - /// - public void CopyTo(TValue[] array, int arrayIndex) - { - _values.CopyTo(array, arrayIndex); - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// An enumerator that can be used to iterate through the collection. - public IEnumerator GetEnumerator() - { - return _values.GetEnumerator(); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - bool ICollection.Contains(TValue item) - { - return _values.Contains(item); - } - - /// - void ICollection.Add(TValue item) - { - throw new NotSupportedException(); - } - - /// - bool ICollection.Remove(TValue item) - { - throw new NotSupportedException(); - } - - /// - void ICollection.Clear() - { - throw new NotSupportedException(); - } - - /// - /// The wrapped collection of values. - /// - readonly ICollection _values; - } - - public struct DictionaryEnumerator:IEnumerator> - { - /// - public TKey Key - { - get - { - return _enumerator.Current.Key; - } - } - - /// - public TValue Value - { - get - { - return _enumerator.Current.Value; - } - } - - public DictionaryEnumerator(IDictionary dictionary) - { - if (dictionary == null) - throw new ArgumentNullException("dictionary"); - - _enumerator = dictionary.GetEnumerator(); - } - - /// - public KeyValuePair Current - { - get - { - return _enumerator.Current; - } - } - - /// - public bool MoveNext() - { - return _enumerator.MoveNext(); - } - - /// - public void Reset() - { - _enumerator.Reset(); - } - - object IEnumerator.Current - { - get { return _enumerator.Current; } - } - - public void Dispose() - { - _enumerator.Dispose(); - } - - readonly IEnumerator> _enumerator; - } - } -} diff --git a/DataStructures/ThreadSafeDictionary.cs b/DataStructures/ThreadSafeDictionary.cs deleted file mode 100644 index 4a4a71f..0000000 --- a/DataStructures/ThreadSafeDictionary.cs +++ /dev/null @@ -1,290 +0,0 @@ - -using System.Collections.Generic; -using System.Threading; - -namespace Svelto.DataStructures -{ - /// - /// original code: http://devplanet.com/blogs/brianr/archive/2008/09/29/thread-safe-dictionary-update.aspx - /// simplified (not an IDictionary) and apdated (uses FasterList) - /// - /// - /// - - public class ThreadSafeDictionary - { - public ThreadSafeDictionary(int v) - { - dict = new Dictionary(v); - } - - public ThreadSafeDictionary() - { - dict = new Dictionary(); - } - - // setup the lock; - public virtual int Count - { - get - { - LockQ.EnterReadLock(); - try - { - return dict.Count; - } - finally - { - LockQ.ExitReadLock(); - } - } - } - - public virtual bool IsReadOnly - { - get - { - LockQ.EnterReadLock(); - try - { - return dict.IsReadOnly; - } - finally - { - LockQ.ExitReadLock(); - } - } - } - - public virtual FasterList Keys - { - get - { - LockQ.EnterReadLock(); - try - { - return new FasterList(dict.Keys); - } - finally - { - LockQ.ExitReadLock(); - } - } - } - - public virtual FasterList Values - { - get - { - LockQ.EnterReadLock(); - try - { - return new FasterList(dict.Values); - } - finally - { - LockQ.ExitReadLock(); - } - } - } - - public virtual TValue this[TKey key] - { - get - { - LockQ.EnterReadLock(); - try - { - return dict[key]; - } - finally - { - LockQ.ExitReadLock(); - } - } - - set - { - LockQ.EnterWriteLock(); - try - { - dict[key] = value; - } - finally - { - LockQ.ExitWriteLock(); - } - } - } - - public virtual void Add(KeyValuePair item) - { - LockQ.EnterWriteLock(); - try - { - dict.Add(item); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - public virtual void Clear() - { - LockQ.EnterWriteLock(); - try - { - dict.Clear(); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - public virtual bool Contains(KeyValuePair item) - { - LockQ.EnterReadLock(); - try - { - return dict.Contains(item); - } - finally - { - LockQ.ExitReadLock(); - } - } - - public virtual void CopyTo(KeyValuePair[] array, int arrayIndex) - { - LockQ.EnterReadLock(); - try - { - dict.CopyTo(array, arrayIndex); - } - finally - { - LockQ.ExitReadLock(); - } - } - - public virtual bool Remove(KeyValuePair item) - { - LockQ.EnterWriteLock(); - try - { - return dict.Remove(item); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - public virtual void Add(TKey key, TValue value) - { - LockQ.EnterWriteLock(); - try - { - dict.Add(key, value); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - public virtual bool ContainsKey(TKey key) - { - LockQ.EnterReadLock(); - try - { - return dict.ContainsKey(key); - } - finally - { - LockQ.ExitReadLock(); - } - } - - public virtual bool Remove(TKey key) - { - LockQ.EnterWriteLock(); - try - { - return dict.Remove(key); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - public virtual bool TryGetValue(TKey key, out TValue value) - { - LockQ.EnterReadLock(); - try - { - return dict.TryGetValue(key, out value); - } - finally - { - LockQ.ExitReadLock(); - } - } - - /// - /// Merge does a blind remove, and then add. Basically a blind Upsert. - /// - /// Key to lookup - /// New Value - public void MergeSafe(TKey key, TValue newValue) - { - LockQ.EnterWriteLock(); - try - { - // take a writelock immediately since we will always be writing - if (dict.ContainsKey(key)) - dict.Remove(key); - - dict.Add(key, newValue); - } - finally - { - LockQ.ExitWriteLock(); - } - } - - /// - /// This is a blind remove. Prevents the need to check for existence first. - /// - /// Key to remove - public void RemoveSafe(TKey key) - { - LockQ.EnterReadLock(); - try - { - if (dict.ContainsKey(key)) - LockQ.EnterWriteLock(); - try - { - dict.Remove(key); - } - finally - { - LockQ.ExitWriteLock(); - } - } - finally - { - LockQ.ExitReadLock(); - } - } - - // This is the internal dictionary that we are wrapping - readonly IDictionary dict; - - readonly ReaderWriterLockSlim LockQ = new ReaderWriterLockSlim(); - } -} diff --git a/DataStructures/ThreadSafeQueue.cs b/DataStructures/ThreadSafeQueue.cs deleted file mode 100644 index d9197f0..0000000 --- a/DataStructures/ThreadSafeQueue.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System.Collections.Generic; -using System.Threading; - -namespace Svelto.DataStructures -{ - public class ThreadSafeQueue - { - readonly Queue m_Queue; - - readonly ReaderWriterLockSlim LockQ = new ReaderWriterLockSlim(); - - public ThreadSafeQueue() - { - m_Queue = new Queue(); - } - - public ThreadSafeQueue(int capacity) - { - m_Queue = new Queue(capacity); - } - - public ThreadSafeQueue(IEnumerable collection) - { - m_Queue = new Queue(collection); - } - - public IEnumerator GetEnumerator() - { - Queue localQ; - - LockQ.EnterReadLock(); - try - { - localQ = new Queue(m_Queue); - } - - finally - { - LockQ.ExitReadLock(); - } - - foreach (T item in localQ) - yield return item; - } - - public void Enqueue(T item) - { - LockQ.EnterWriteLock(); - try - { - m_Queue.Enqueue(item); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public T Dequeue() - { - LockQ.EnterWriteLock(); - try - { - return m_Queue.Dequeue(); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public void EnqueueAll(IEnumerable ItemsToQueue) - { - LockQ.EnterWriteLock(); - try - { - foreach (T item in ItemsToQueue) - m_Queue.Enqueue(item); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public FasterList DequeueAll() - { - LockQ.EnterWriteLock(); - try - { - FasterList returnList = new FasterList(); - - while (m_Queue.Count > 0) - returnList.Add(m_Queue.Dequeue()); - - return returnList; - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public void DequeueAllInto(FasterList list) - { - LockQ.EnterWriteLock(); - try - { - while (m_Queue.Count > 0) - list.Add(m_Queue.Dequeue()); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public void DequeueInto(FasterList list, int count) - { - LockQ.EnterWriteLock(); - try - { - int originalSize = m_Queue.Count; - while (m_Queue.Count > 0 && originalSize - m_Queue.Count < count) - list.Add(m_Queue.Dequeue()); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public FasterList DequeueAllAs() where U:class - { - LockQ.EnterWriteLock(); - try - { - FasterList returnList = new FasterList(); - - while (m_Queue.Count > 0) - returnList.Add(m_Queue.Dequeue() as U); - - return returnList; - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public T Peek() - { - LockQ.EnterWriteLock(); - try - { - T item = default(T); - - if (m_Queue.Count > 0) - item = m_Queue.Peek(); - - return item; - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public void Clear() - { - LockQ.EnterWriteLock(); - try - { - m_Queue.Clear(); - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public bool TryDequeue(out T item) - { - LockQ.EnterWriteLock(); - try - { - if (m_Queue.Count > 0) - { - item = m_Queue.Dequeue(); - - return true; - } - else - { - item = default(T); - - return false; - } - } - - finally - { - LockQ.ExitWriteLock(); - } - } - - public int Count - { - get - { - LockQ.EnterWriteLock(); - try - { - return m_Queue.Count; - } - - finally - { - LockQ.ExitWriteLock(); - } - } - } - } -} diff --git a/DataStructures/WeakReference.cs b/DataStructures/WeakReference.cs deleted file mode 100644 index 0f14cca..0000000 --- a/DataStructures/WeakReference.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -/// -/// Represents a weak reference, which references an object while still allowing -/// that object to be reclaimed by garbage collection. -/// -/// The type of the object that is referenced. - -namespace Svelto.DataStructures -{ -#if !NETFX_CORE - public class WeakReference - : WeakReference where T : class - { - public bool IsValid { get { return Target != null && IsAlive == true; } } - - /// - /// Gets or sets the object (the target) referenced by the - /// current WeakReference{T} object. - /// - public new T Target - { - get - { - return (T)base.Target; - } - set - { - base.Target = value; - } - } - /// - /// Initializes a new instance of the WeakReference{T} class, referencing - /// the specified object. - /// - /// The object to reference. - public WeakReference(T target) - : base(target) - { } - - /// - /// Initializes a new instance of the WeakReference{T} class, referencing - /// the specified object and using the specified resurrection tracking. - /// - /// An object to track. - /// Indicates when to stop tracking the object. - /// If true, the object is tracked - /// after finalization; if false, the object is only tracked - /// until finalization. - public WeakReference(T target, bool trackResurrection) - : base(target, trackResurrection) - { } - } -#else - public class WeakReference : System.WeakReference where T : class - { - public bool IsValid { get { return Target != null && IsAlive == true; } } - - public new T Target - { - get - { - return (T)base.Target; - } - set - { - base.Target = value; - } - } - - public WeakReference(T target) - : base(target) - { } - - public WeakReference(T target, bool trackResurrection) - : base(target, trackResurrection) - { } - } -#endif -} diff --git a/ECS/EngineNodeDB.cs b/ECS/EngineNodeDB.cs deleted file mode 100644 index 0bb5bb8..0000000 --- a/ECS/EngineNodeDB.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Generic; -using Svelto.DataStructures; - -namespace Svelto.ECS -{ - public class EngineNodeDB : IEngineNodeDB - { - internal EngineNodeDB( Dictionary> nodesDB, - Dictionary> nodesDBdic, - Dictionary> metaNodesDB) - { - _nodesDB = nodesDB; - _nodesDBdic = nodesDBdic; - _metaNodesDB = metaNodesDB; - } - - public FasterReadOnlyListCast QueryNodes() where T:INode - { - var type = typeof(T); - - FasterList nodes; - - if (_nodesDB.TryGetValue(type, out nodes) == false) - return RetrieveEmptyNodeList(); - - return new FasterReadOnlyListCast(nodes); - } - - public ReadOnlyDictionary QueryIndexableNodes() where T:INode - { - var type = typeof(T); - - Dictionary nodes; - - if (_nodesDBdic.TryGetValue(type, out nodes) == false) - return _defaultEmptyNodeDict; - - return new ReadOnlyDictionary(nodes); - } - - public T QueryMetaNode(int metaEntityID) where T : INode - { - return QueryNode(metaEntityID); - } - - public bool TryQueryMetaNode(int metaEntityID, out T node) where T : INode - { - return TryQueryNode(metaEntityID, out node); - } - - public FasterReadOnlyListCast QueryMetaNodes() where T : INode - { - var type = typeof(T); - - FasterList nodes; - - if (_metaNodesDB.TryGetValue(type, out nodes) == false) - return RetrieveEmptyNodeList(); - - return new FasterReadOnlyListCast(nodes); - } - - public bool TryQueryNode(int ID, out T node) where T:INode - { - var type = typeof(T); - - INode internalNode; - - Dictionary nodes; - - if (_nodesDBdic.TryGetValue(type, out nodes) && - nodes.TryGetValue(ID, out internalNode)) - { - node = (T)internalNode; - - return true; - } - - node = default(T); - - return false; - } - - public T QueryNode(int ID) where T:INode - { - var type = typeof(T); - - INode internalNode; Dictionary nodes; - - if (_nodesDBdic.TryGetValue(type, out nodes) && - nodes.TryGetValue(ID, out internalNode)) - return (T)internalNode; - - throw new Exception("Node Not Found"); - } - - static FasterReadOnlyListCast RetrieveEmptyNodeList() where T : INode - { - return FasterReadOnlyListCast.DefaultList; - } - - readonly Dictionary> _nodesDB; - readonly Dictionary> _nodesDBdic; - readonly Dictionary> _metaNodesDB; - - readonly ReadOnlyDictionary _defaultEmptyNodeDict = new ReadOnlyDictionary(new Dictionary()); - } -} diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs deleted file mode 100644 index 404b187..0000000 --- a/ECS/EnginesRoot.cs +++ /dev/null @@ -1,544 +0,0 @@ -using System; -using System.Collections.Generic; -using Svelto.DataStructures; -using Svelto.ECS.Internal; -using Svelto.ECS.NodeSchedulers; -using WeakReference = Svelto.DataStructures.WeakReference; - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR -using Svelto.ECS.Profiler; -#endif -#if NETFX_CORE -using System.Reflection; -#endif - -namespace Svelto.ECS -{ - public sealed class EnginesRoot : IEnginesRoot, IEntityFactory - { - public EnginesRoot(NodeSubmissionScheduler nodeScheduler) - { - _nodeEngines = new Dictionary>(); - _activableEngines = new Dictionary>(); - _otherEngines = new FasterList(); - - _engineRootWeakReference = new WeakReference(this); - - _nodesDB = new Dictionary>(); - _nodesDBdic = new Dictionary>(); - - _nodesToAdd = new FasterList(); - _metaNodesToAdd = new FasterList(); - - _metaNodesDB = new Dictionary>(); - _sharedStructNodeLists = new SharedStructNodeLists(); - _sharedGroupedStructNodeLists = new SharedGroupedStructNodesLists(); - - _internalRemove = InternalRemove; - _internalDisable = InternalDisable; - _internalEnable = InternalEnable; - _internalMetaRemove = InternalMetaRemove; - - _scheduler = nodeScheduler; - _scheduler.Schedule(SubmitNodes); - - _structNodeEngineType = typeof(IStructNodeEngine<>); - _groupedStructNodesEngineType = typeof(IGroupedStructNodesEngine<>); - _activableNodeEngineType = typeof(IActivableNodeEngine<>); - - _implementedInterfaceTypes = new Dictionary(); - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); - debugEngineObject.gameObject.AddComponent(); -#endif - } - - void SubmitNodes() - { - int metaNodesCount = _metaNodesToAdd.Count; - int nodesCount = _nodesToAdd.Count; - - if (metaNodesCount + nodesCount == 0) return; - - bool newNodesHaveBeenAddedWhileIterating; - int startNodes = 0; - int startMetaNodes = 0; - int numberOfReenteringLoops = 0; - - do - { - var nodesToAdd = _nodesToAdd.ToArrayFast(); - - for (int i = startNodes; i < nodesCount; i++) - { - var node = nodesToAdd[i]; - var nodeType = node.GetType(); - - AddNodeToTheDB(node, nodeType); - var nodeWithId = node as INodeWithID; - if (nodeWithId != null) - AddNodeToNodesDictionary(nodeWithId, nodeType); - } - - var metaNodesToAdd = _metaNodesToAdd.ToArrayFast(); - - for (int i = startMetaNodes; i < metaNodesCount; i++) - { - var node = metaNodesToAdd[i]; - var nodeType = node.GetType(); - - AddNodeToMetaDB(node, nodeType); - var nodeWithId = node as INodeWithID; - if (nodeWithId != null) - AddNodeToNodesDictionary(nodeWithId, nodeType); - } - - for (int i = startNodes; i < nodesCount; i++) - { - var node = nodesToAdd[i]; - AddNodeToTheSuitableEngines(node, node.GetType()); - } - - for (int i = startMetaNodes; i < metaNodesCount; i++) - { - var node = metaNodesToAdd[i]; - AddNodeToTheSuitableEngines(node, node.GetType()); - } - - newNodesHaveBeenAddedWhileIterating = - _metaNodesToAdd.Count > metaNodesCount || - _nodesToAdd.Count > nodesCount; - - startNodes = nodesCount; - startMetaNodes = metaNodesCount; - - if (numberOfReenteringLoops > 5) - throw new Exception("possible infinite loop found creating Entities inside INodesEngine Add method, please consider building entities outside INodesEngine Add method"); - - numberOfReenteringLoops++; - - metaNodesCount = _metaNodesToAdd.Count; - nodesCount = _nodesToAdd.Count; - - } while (newNodesHaveBeenAddedWhileIterating); - - _nodesToAdd.Clear(); - _metaNodesToAdd.Clear(); - } - - public void AddEngine(IEngine engine) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.AddEngine(engine); -#endif - var queryableNodeEngine = engine as IQueryableNodeEngine; - if (queryableNodeEngine != null) - queryableNodeEngine.nodesDB = - new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB); - - var engineType = engine.GetType(); - var implementedInterfaces = engineType.GetInterfaces(); - - CollectImplementedInterfaces(implementedInterfaces); - - var engineAdded = CheckGenericEngines(engine); - - if (CheckLegacyNodesEngine(engine, ref engineAdded) == false) - CheckNodesEngine(engine, engineType, ref engineAdded); - - if (engineAdded == false) - _otherEngines.Add(engine); - - var callBackOnAddEngine = engine as ICallBackOnAddEngine; - if (callBackOnAddEngine != null) - callBackOnAddEngine.Ready(); - } - - void CollectImplementedInterfaces(Type[] implementedInterfaces) - { - _implementedInterfaceTypes.Clear(); - - var type = typeof(IEngine); - - for (int index = 0; index < implementedInterfaces.Length; index++) - { - var interfaceType = implementedInterfaces[index]; - - if (type.IsAssignableFrom(interfaceType) == false) - continue; -#if !NETFX_CORE - - if (false == interfaceType.IsGenericType) -#else - if (false == interfaceType.IsConstructedGenericType) -#endif - { - continue; - } - - var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); - - _implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); - } - } - - bool CheckGenericEngines(IEngine engine) - { - if (_implementedInterfaceTypes.Count == 0) return false; - - bool engineAdded = false; - - if (_implementedInterfaceTypes.ContainsKey(_structNodeEngineType)) - { - ((IStructNodeEngine)engine).CreateStructNodes - (_sharedStructNodeLists); - } - - if (_implementedInterfaceTypes.ContainsKey(_groupedStructNodesEngineType)) - { - ((IGroupedStructNodesEngine)engine).CreateStructNodes - (_sharedGroupedStructNodeLists); - } - - Type[] arguments; - if (_implementedInterfaceTypes.TryGetValue(_activableNodeEngineType, - out arguments)) - { - AddEngine(engine, arguments, _activableEngines); - - engineAdded = true; - } - - return engineAdded; - } - - bool CheckLegacyNodesEngine(IEngine engine, ref bool engineAdded) - { - var nodesEngine = engine as INodesEngine; - if (nodesEngine != null) - { - AddEngine(nodesEngine, nodesEngine.AcceptedNodes(), _nodeEngines); - - engineAdded = true; - - return true; - } - - return false; - } - - bool CheckNodesEngine(IEngine engine, Type engineType, ref bool engineAdded) - { -#if !NETFX_CORE - var baseType = engineType.BaseType; - - if (baseType.IsGenericType -#else - var baseType = engineType.GetTypeInfo().BaseType; - - if (baseType.IsConstructedGenericType -#endif - && engine is INodeEngine) - { - AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines); - - engineAdded = true; - - return true; - } - - return false; - } - - public void BuildEntity(int ID, EntityDescriptor ed) - { - var entityNodes = ed.BuildNodes(ID, - _internalRemove, - _internalEnable, - _internalDisable - ); - - _nodesToAdd.AddRange(entityNodes); - } - - /// - /// A meta entity is a way to manage a set of entitites that are not easily - /// queriable otherwise. For example you may want to group existing entities - /// by size and type and then use the meta entity node to manage the data - /// shared among the single entities of the same type and size. This will - /// prevent the scenario where the coder is forced to parse all the entities to - /// find the ones of the same size and type. - /// Since the entities are managed through the shared node, the same - /// shared node must be found on the single entities of the same type and size. - /// The shared node of the meta entity is then used by engines that are meant - /// to manage a group of entities through a single node. - /// The same engine can manage several meta entities nodes too. - /// The Engine manages the logic of the Meta Node data and other engines - /// can read back this data through the normal entity as the shared node - /// will be present in their descriptor too. - /// - /// - /// - public void BuildMetaEntity(int metaEntityID, EntityDescriptor ed) - { - var entityNodes = ed.BuildNodes(metaEntityID, - _internalMetaRemove, - _internalEnable, - _internalDisable - ); - - _metaNodesToAdd.AddRange(entityNodes); - } - - /// - /// Using this function is like building a normal entity, but the nodes - /// are grouped by groupID to be better processed inside engines and - /// improve cache locality. Only IGroupStructNodeWithID nodes are grouped - /// other nodes are managed as usual. - /// - /// - /// - /// - public void BuildEntityInGroup(int entityID, int groupID, - EntityDescriptor ed) - { - var entityNodes = ed.BuildNodes(entityID, - _internalRemove, - _internalEnable, - _internalDisable - ); - - _nodesToAdd.AddRange(entityNodes); - - for (int i = 0; i < entityNodes.Count; i++) - { - var groupNode = entityNodes[i] as IGroupedStructNodeWithID; - if (groupNode != null) - groupNode.groupID = groupID; - } - } - - static void AddEngine(IEngine engine, Type[] types, - Dictionary> engines) - { - for (int i = 0; i < types.Length; i++) - { - FasterList list; - - var type = types[i]; - - if (engines.TryGetValue(type, out list) == false) - { - list = new FasterList(); - - engines.Add(type, list); - } - - list.Add(engine); - } - } - - void AddNodeToMetaDB(INode node, Type nodeType) - { - FasterList nodes; - if (_metaNodesDB.TryGetValue(nodeType, out nodes) == false) - nodes = _metaNodesDB[nodeType] = new FasterList(); - - nodes.Add(node); - } - - void AddNodeToTheDB(T node, Type nodeType) where T : INode - { - FasterList nodes; - if (_nodesDB.TryGetValue(nodeType, out nodes) == false) - nodes = _nodesDB[nodeType] = new FasterList(); - - nodes.Add(node); - } - - void AddNodeToNodesDictionary(T node, Type nodeType) where T : INodeWithID - { - Dictionary nodesDic; - - if (_nodesDBdic.TryGetValue(nodeType, out nodesDic) == false) - nodesDic = _nodesDBdic[nodeType] = new Dictionary(); - - nodesDic.Add(node.ID, node); - } - - void AddNodeToTheSuitableEngines(INode node, Type nodeType) - { - FasterList enginesForNode; - - if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorAddDuration(enginesForNode[j] as INodeEngine, node); -#else - (enginesForNode[j] as INodeEngine).Add(node); -#endif - } - } - } - - void RemoveNodeFromTheDB(T node, Type nodeType) where T : INode - { - FasterList nodes; - if (_nodesDB.TryGetValue(nodeType, out nodes) == true) - nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? - } - - void RemoveNodeFromMetaDB(T node, Type nodeType) where T : INode - { - FasterList nodes; - if (_metaNodesDB.TryGetValue(nodeType, out nodes) == true) - nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? - } - - void RemoveNodeFromNodesDictionary(T node, Type nodeType) where T : INodeWithID - { - Dictionary nodesDic; - - if (_nodesDBdic.TryGetValue(nodeType, out nodesDic)) - nodesDic.Remove(node.ID); - } - - void RemoveNodeFromEngines(T node, Type nodeType) where T : INode - { - FasterList enginesForNode; - - if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration((enginesForNode[j] as INodeEngine), node); -#else - (enginesForNode[j] as INodeEngine).Remove(node); -#endif - } - } - } - - void DisableNodeFromEngines(INode node, Type nodeType) - { - FasterList enginesForNode; - - if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) - { - (enginesForNode[j] as IActivableNodeEngine).Disable(node); - } - } - } - - void EnableNodeFromEngines(INode node, Type nodeType) - { - FasterList enginesForNode; - - if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) - { - for (int j = 0; j < enginesForNode.Count; j++) - { - (enginesForNode[j] as IActivableNodeEngine).Enable(node); - } - } - } - - void InternalDisable(FasterList nodes) - { - if (_engineRootWeakReference.IsValid == false) - return; - - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); - DisableNodeFromEngines(node, nodeType); - } - } - - void InternalEnable(FasterList nodes) - { - if (_engineRootWeakReference.IsValid == false) - return; - - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); - EnableNodeFromEngines(node, nodeType); - } - } - - void InternalRemove(FasterList nodes) - { - if (_engineRootWeakReference.IsValid == false) - return; - - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); - - RemoveNodeFromEngines(node, nodeType); - RemoveNodeFromTheDB(node, node.GetType()); - - var nodeWithId = node as INodeWithID; - if (nodeWithId != null) - RemoveNodeFromNodesDictionary(nodeWithId, nodeType); - } - } - - void InternalMetaRemove(FasterList nodes) - { - for (int i = 0; i < nodes.Count; i++) - { - var node = nodes[i]; - Type nodeType = node.GetType(); - - RemoveNodeFromEngines(node, nodeType); - RemoveNodeFromMetaDB(node, nodeType); - - var nodeWithId = node as INodeWithID; - if (nodeWithId != null) - RemoveNodeFromNodesDictionary(nodeWithId, nodeType); - } - } - - readonly Dictionary> _nodeEngines; - readonly Dictionary> _activableEngines; - - readonly FasterList _otherEngines; - - readonly Dictionary> _nodesDB; - readonly Dictionary> _metaNodesDB; - - readonly Dictionary> _nodesDBdic; - - readonly FasterList _nodesToAdd; - readonly FasterList _metaNodesToAdd; - - readonly WeakReference _engineRootWeakReference; - readonly SharedStructNodeLists _sharedStructNodeLists; - readonly SharedGroupedStructNodesLists _sharedGroupedStructNodeLists; - - readonly NodeSubmissionScheduler _scheduler; - - readonly Action> _internalRemove; - readonly Action> _internalEnable; - readonly Action> _internalDisable; - readonly Action> _internalMetaRemove; - - readonly Type _structNodeEngineType; - readonly Type _groupedStructNodesEngineType; - readonly Type _activableNodeEngineType; - - readonly Dictionary _implementedInterfaceTypes; - } -} - diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs deleted file mode 100644 index cf459b2..0000000 --- a/ECS/EntityDescriptor.cs +++ /dev/null @@ -1,196 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using Svelto.DataStructures; -#if NETFX_CORE -using BindingFlags = System.Reflection.BindingFlags; -#endif - -namespace Svelto.ECS -{ - public class EntityDescriptor - { - protected EntityDescriptor() - { - } - protected EntityDescriptor(INodeBuilder[] nodesToBuild) - { - _nodesToBuild = new FasterList(nodesToBuild); - } - protected EntityDescriptor(INodeBuilder[] nodesToBuild, params object[] componentsImplementor):this(nodesToBuild) - { - ProcessImplementors(componentsImplementor); - } - - public void AddImplementors(params object[] componentsImplementor) - { - ProcessImplementors(componentsImplementor); - } - - void ProcessImplementors(object[] implementors) - { - for (int index = 0; index < implementors.Length; index++) - { - var implementor = implementors[index]; - if (implementor == null) - { - Utility.Console.LogWarning( - "Null implementor, are you using a wild GetComponents to fetch it? " - .FastConcat(ToString())); - } - else - { - if (implementor is IRemoveEntityComponent) - _removingImplementors.Add(implementor as IRemoveEntityComponent); - if (implementor is IDisableEntityComponent) - _disablingImplementors.Add(implementor as IDisableEntityComponent); - if (implementor is IEnableEntityComponent) - _enablingImplementors.Add(implementor as IEnableEntityComponent); - - var interfaces = implementor.GetType().GetInterfaces(); - for (int iindex = 0; iindex < interfaces.Length; iindex++) - { - _implementorsByType[interfaces[iindex]] = implementor; - } - } - } - } - - public void AddNodes(params INodeBuilder[] nodesWithID) - { - _nodesToBuild.AddRange(nodesWithID); - } - - public virtual FasterList BuildNodes(int ID) - { - var nodes = new FasterList(); - - for (int index = 0; index < _nodesToBuild.Count; index++) - { - var nodeBuilder = _nodesToBuild[index]; - var node = nodeBuilder.Build(ID); - - if (nodeBuilder.reflects != FillNodeMode.None) - node = FillNode(node, nodeBuilder.reflects); - - nodes.Add(node); - } - - return nodes; - } - - internal FasterList BuildNodes(int ID, - Action> removeEntity, - Action> enableEntity, - Action> disableEntity) - { - var nodes = BuildNodes(ID); - - SetupImplementors(removeEntity, enableEntity, disableEntity, nodes); - - return nodes; - } - - void SetupImplementors( - Action> removeEntity, - Action> enableEntity, - Action> disableEntity, - FasterList nodes) - { - Action removeEntityAction = () => { removeEntity(nodes); nodes.Clear(); }; - Action disableEntityAction = () => disableEntity(nodes); - Action enableEntityAction = () => enableEntity(nodes); - - for (int index = 0; index < _removingImplementors.Count; index++) - _removingImplementors[index].removeEntity = removeEntityAction; - for (int index = 0; index < _disablingImplementors.Count; index++) - _disablingImplementors[index].disableEntity = disableEntityAction; - for (int index = 0; index < _enablingImplementors.Count; index++) - _enablingImplementors[index].enableEntity = enableEntityAction; - } - - TNode FillNode(TNode node, FillNodeMode mode) where TNode : INode - { - var fields = node.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); - - for (int i = fields.Length - 1; i >= 0; --i) - { - var field = fields[i]; - Type fieldType = field.FieldType; - object component; - - if ((_implementorsByType.TryGetValue(fieldType, out component)) == false) - { - if (mode == FillNodeMode.Strict) - { - Exception e = - new Exception("Svelto.ECS: Implementor not found for a Node. " + "Implementor Type: " + - field.FieldType.Name + " - Node: " + node.GetType().Name + - " - EntityDescriptor " + this); - - throw e; - } - } - else - field.SetValue(node, component); - } - - return node; - } - - readonly FasterList _disablingImplementors = new FasterList(); - readonly FasterList _removingImplementors = new FasterList(); - readonly FasterList _enablingImplementors = new FasterList(); - readonly Dictionary _implementorsByType = new Dictionary(); - - readonly FasterList _nodesToBuild; - } - - public interface INodeBuilder - { - INode Build(int ID); - - FillNodeMode reflects { get; } - } - - public class NodeBuilder : INodeBuilder where NodeType : NodeWithID, new() - { - public INode Build(int ID) - { - NodeWithID node = NodeWithID.BuildNode(ID); - - return (NodeType)node; - } - - public FillNodeMode reflects { get { return FillNodeMode.Strict; } } - } - - public class StructNodeBuilder : INodeBuilder - where NodeType : struct, IStructNodeWithID - { - public INode Build(int ID) - { - var shortID = (short)ID; - IStructNodeWithID node = default(NodeType); - node.ID = shortID; - - return node; - } - - public virtual FillNodeMode reflects { get { return FillNodeMode.Relaxed; } } - } - - public class FastStructNodeBuilder : StructNodeBuilder - where NodeType : struct, IStructNodeWithID - { - public override FillNodeMode reflects { get { return FillNodeMode.None; } } - } - - public enum FillNodeMode - { - Strict, - Relaxed, - - None - } -} diff --git a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs b/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs deleted file mode 100644 index 9241fdf..0000000 --- a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs +++ /dev/null @@ -1,41 +0,0 @@ -#if UNITY_5 || UNITY_5_3_OR_NEWER -using System; -using System.Collections; -using UnityEngine; - -namespace Svelto.ECS.NodeSchedulers -{ - public class UnitySumbmissionNodeScheduler : NodeSubmissionScheduler - { - public UnitySumbmissionNodeScheduler() - { - GameObject go = new GameObject("ECSScheduler"); - - _scheduler = go.AddComponent(); - } - - public override void Schedule(Action submitNodes) - { - _scheduler.OnTick += submitNodes; - } - - class Scheduler : MonoBehaviour - { - IEnumerator Start() - { - while (true) - { - yield return _wait; - - OnTick(); - } - } - - internal Action OnTick; - WaitForEndOfFrame _wait = new WaitForEndOfFrame(); - } - - Scheduler _scheduler; - } -} -#endif \ No newline at end of file diff --git a/ECS/GenericEntityDescriptor.cs b/ECS/GenericEntityDescriptor.cs deleted file mode 100644 index 472cdff..0000000 --- a/ECS/GenericEntityDescriptor.cs +++ /dev/null @@ -1,239 +0,0 @@ -namespace Svelto.ECS -{ - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - { - static GenericEntityDescriptor() - { - _nodesToBuild = new INodeBuilder[] { new NodeBuilder() }; - } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - { - static GenericEntityDescriptor() - { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder() - }; - } - - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() - { - static GenericEntityDescriptor() - { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; - } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() - where W : NodeWithID, new() - { - static GenericEntityDescriptor() - { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; - } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() - where W : NodeWithID, new() - where X : NodeWithID, new() - { - static GenericEntityDescriptor() - { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; - } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericEntityDescriptor : EntityDescriptor - where T : NodeWithID, new() - where U : NodeWithID, new() - where V : NodeWithID, new() - where W : NodeWithID, new() - where X : NodeWithID, new() - where Y : NodeWithID, new() - { - static GenericEntityDescriptor() - { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder(), - new NodeBuilder() - }; - } - public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - {} - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - { - static GenericMixedEntityDescriptor() - { - _nodesToBuild = new INodeBuilder[] - { - new T(), - }; - } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() - { - static GenericMixedEntityDescriptor() - { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V() - }; - } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() - where W : INodeBuilder, new() - { - static GenericMixedEntityDescriptor() - { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V(), - new W() - }; - } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() - where W : INodeBuilder, new() - where X : INodeBuilder, new() - { - static GenericMixedEntityDescriptor() - { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V(), - new W(), - new X() - }; - } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; - } - - public class GenericMixedEntityDescriptor : EntityDescriptor - where T : INodeBuilder, new() - where U : INodeBuilder, new() - where V : INodeBuilder, new() - where W : INodeBuilder, new() - where X : INodeBuilder, new() - where Y : INodeBuilder, new() - { - static GenericMixedEntityDescriptor() - { - _nodesToBuild = new INodeBuilder[] - { - new T(), - new U(), - new V(), - new W(), - new X(), - new Y() - }; - } - public GenericMixedEntityDescriptor(params object[] componentsImplementor) : - base(_nodesToBuild, componentsImplementor) - { } - - static readonly INodeBuilder[] _nodesToBuild; - } -} diff --git a/ECS/GenericEntityDescriptorHolder.cs b/ECS/GenericEntityDescriptorHolder.cs deleted file mode 100644 index 4e51570..0000000 --- a/ECS/GenericEntityDescriptorHolder.cs +++ /dev/null @@ -1,30 +0,0 @@ -#if UNITY_5 || UNITY_5_3_OR_NEWER -using System; - -namespace Svelto.ECS -{ - public class GenericEntityDescriptorHolder: UnityEngine.MonoBehaviour, IEntityDescriptorHolder where T:EntityDescriptor - { - public EntityDescriptor BuildDescriptorType(object[] externalImplentors) - { - I[] implementors; - - if (externalImplentors != null) - { - I[] baseImplentors = gameObject.GetComponents(); - - implementors = new I[externalImplentors.Length + baseImplentors.Length]; - - Array.Copy(baseImplentors, implementors, baseImplentors.Length); - Array.Copy(externalImplentors, 0, implementors, baseImplentors.Length, externalImplentors.Length); - } - else - { - implementors = gameObject.GetComponents(); - } - - return (T)Activator.CreateInstance(typeof(T), implementors); - } - } -} -#endif \ No newline at end of file diff --git a/ECS/ICallBackOnAddEngine.cs b/ECS/ICallBackOnAddEngine.cs deleted file mode 100644 index e77bf6a..0000000 --- a/ECS/ICallBackOnAddEngine.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Svelto.ECS -{ - public interface ICallBackOnAddEngine - { - void Ready(); - } -} diff --git a/ECS/IEngine.cs b/ECS/IEngine.cs deleted file mode 100644 index d811e9a..0000000 --- a/ECS/IEngine.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Svelto.ECS.Internal; - -namespace Svelto.ECS.Internal -{ - public interface IStructNodeEngine : IEngine - { - void CreateStructNodes(SharedStructNodeLists sharedStructNodeLists); - } - - public interface IGroupedStructNodesEngine : IEngine - { - void CreateStructNodes(SharedGroupedStructNodesLists sharedStructNodeLists); - } - - public interface IActivableNodeEngine : IEngine - { - void Enable(INode obj); - void Disable(INode obj); - } - - public interface INodeEngine : IEngine - { - void Add(INode obj); - void Remove(INode obj); - } - - public interface INodesEngine : INodeEngine - { - System.Type[] AcceptedNodes(); - } -} - -namespace Svelto.ECS -{ - public interface IEngine - {} - - public interface IActivableNodeEngine : IActivableNodeEngine where TNodeType : INode - { } - - public interface IQueryableNodeEngine:IEngine - { - IEngineNodeDB nodesDB { set; } - } - - /// - /// The engines can receive and store INodes structs - /// Unboxing will happen during the Add, but the - /// data will then be stored and processed as stucts - /// - public interface IStructNodeEngine : IStructNodeEngine where T:struct, IStructNodeWithID - { } - - /// - /// same as above, but the nodes are grouped by ID - /// usually the ID is the owner of the nodes of that - /// group - /// - public interface IGroupedStructNodesEngine : IGroupedStructNodesEngine where T:struct, IGroupedStructNodeWithID - { } -} - diff --git a/ECS/IEngineNodeDB.cs b/ECS/IEngineNodeDB.cs deleted file mode 100644 index e2ee74f..0000000 --- a/ECS/IEngineNodeDB.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Svelto.DataStructures; - -namespace Svelto.ECS -{ - public interface IEngineNodeDB - { - ReadOnlyDictionary QueryIndexableNodes() where T:INode; - - bool TryQueryNode(int ID, out T node) where T:INode; - T QueryNode(int ID) where T:INode; - - FasterReadOnlyListCast QueryNodes() where T:INode; - - bool TryQueryMetaNode(int metaEntityID, out T node) where T : INode; - T QueryMetaNode(int metaEntityID) where T : INode; - FasterReadOnlyListCast QueryMetaNodes() where T : INode; - } -} - diff --git a/ECS/IEnginesRoot.cs b/ECS/IEnginesRoot.cs deleted file mode 100644 index 14f5957..0000000 --- a/ECS/IEnginesRoot.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Svelto.ECS -{ - public interface IEnginesRoot - { - void AddEngine(IEngine engine); - } - - public interface IEntityFactory - { - void BuildEntity(int ID, EntityDescriptor ED); - - void BuildMetaEntity(int metaEntityID, EntityDescriptor ED); - - void BuildEntityInGroup(int entityID, int groupID, EntityDescriptor ED); - } -} diff --git a/ECS/IEntityDescriptorHolder.cs b/ECS/IEntityDescriptorHolder.cs deleted file mode 100644 index 2c70278..0000000 --- a/ECS/IEntityDescriptorHolder.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Svelto.ECS -{ - /// - /// please use [DisallowMultipleComponent] in your monobehaviours that implement IEntityDescriptorHolder - /// - public interface IEntityDescriptorHolder - { - //I must find a nicer solution for the extraImplentors - EntityDescriptor BuildDescriptorType(object[] extraImplentors = null); - } -} diff --git a/ECS/INode.cs b/ECS/INode.cs deleted file mode 100644 index f9b0c81..0000000 --- a/ECS/INode.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Svelto.ECS -{ - public interface INode - {} - - public interface INodeWithID:INode - { - int ID { get; } - } - - public interface IStructNodeWithID : INode - { - int ID { get; set; } - } - - public interface IGroupedStructNodeWithID : IStructNodeWithID - { - int groupID { get; set; } - } - - public class NodeWithID: INodeWithID - { - public static TNodeType BuildNode(int ID) where TNodeType: NodeWithID, new() - { - return new TNodeType { _ID = ID }; - } - - public int ID { get { return _ID; } } - - protected int _ID; - } -} diff --git a/ECS/IRemoveEntityComponent.cs b/ECS/IRemoveEntityComponent.cs deleted file mode 100644 index 5a3ee3b..0000000 --- a/ECS/IRemoveEntityComponent.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace Svelto.ECS -{ - public interface IRemoveEntityComponent - { - Action removeEntity { get; set; } - } - - public interface IDisableEntityComponent - { - Action disableEntity { get; set; } - } - - public interface IEnableEntityComponent - { - Action enableEntity { get; set; } - } -} diff --git a/ECS/MultiNodesEngine.cs b/ECS/MultiNodesEngine.cs deleted file mode 100644 index 2907917..0000000 --- a/ECS/MultiNodesEngine.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Svelto.ECS.Internal; - -namespace Svelto.ECS.Internal -{ - public abstract class MultiNodesEngine - where T : INode - { - protected abstract void AddNode(T node); - protected abstract void RemoveNode(T node); - } -} - -namespace Svelto.ECS -{ - public abstract class MultiNodesEngine : INodesEngine - { - public abstract System.Type[] AcceptedNodes(); - - public abstract void Add(INode node); - public abstract void Remove(INode node); - } - - public abstract class MultiNodesEngine : MultiNodesEngine, - INodeEngine - where T : INode - where U : INode - { - protected abstract void AddNode(U node); - protected abstract void RemoveNode(U node); - - public void Add(INode node) - { - if (node is T) - AddNode((T)node); - else - AddNode((U)node); - } - - public void Remove(INode node) - { - if (node is T) - RemoveNode((T)node); - else - RemoveNode((U)node); - } - } -} \ No newline at end of file diff --git a/ECS/NodeSubmissionScheduler.cs b/ECS/NodeSubmissionScheduler.cs deleted file mode 100644 index dc86bf2..0000000 --- a/ECS/NodeSubmissionScheduler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Svelto.ECS.NodeSchedulers -{ - public abstract class NodeSubmissionScheduler - { - abstract public void Schedule(Action submitNodes); - } -} \ No newline at end of file diff --git a/ECS/SingleNodeEngine.cs b/ECS/SingleNodeEngine.cs deleted file mode 100644 index f4c58a1..0000000 --- a/ECS/SingleNodeEngine.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Svelto.ECS.Internal; - -namespace Svelto.ECS -{ - public abstract class SingleNodeEngine : INodeEngine - where TNodeType : INode - { - public void Add(INode obj) - { - Add((TNodeType) obj); - } - - public void Remove(INode obj) - { - Remove((TNodeType) obj); - } - - protected abstract void Add(TNodeType node); - protected abstract void Remove(TNodeType node); - } -} diff --git a/ECS/StructNodes.cs b/ECS/StructNodes.cs deleted file mode 100644 index 85ca30d..0000000 --- a/ECS/StructNodes.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Collections.Generic; -using Svelto.DataStructures; -using Svelto.ECS.Internal; - -namespace Svelto.ECS -{ - public class StructNodes where T:struct, IStructNodeWithID - { - public T[] GetList(out int numberOfItems) - { - numberOfItems = _internalList.Count; - return _internalList.ToArrayFast(); - } - - public StructNodes(SharedStructNodeLists container) - { - _internalList = container.GetList(); - } - - public void Add(T node) - { - T convert = (T)node; - - _internalList.Add(convert); - } - - readonly FasterList _internalList; - } - - public class StructGroupNodes - where T : struct, IGroupedStructNodeWithID - { - public StructGroupNodes(SharedGroupedStructNodesLists container) - { - _container = container; - } - - public void Add(int groupID, T node) - { - T convert = (T)node; - - var fasterList = (_container.GetList(groupID) as FasterList); - indices[node.ID] = fasterList.Count; - - fasterList.Add(convert); - } - - public void Remove(int groupID, T node) - { - var fasterList = (_container.GetList(groupID) as FasterList); - var index = indices[node.ID]; - indices.Remove(node.ID); - - if (fasterList.UnorderedRemoveAt(index)) - indices[fasterList[index].ID] = index; - } - - public T[] GetList(int groupID, out int numberOfItems) - { - var fasterList = (_container.GetList(groupID) as FasterList); - numberOfItems = fasterList.Count; - return fasterList.ToArrayFast(); - } - - readonly SharedGroupedStructNodesLists _container; - readonly Dictionary indices = new Dictionary(); - } - - public class SharedStructNodeLists - { - readonly Dictionary _collection; - - internal SharedStructNodeLists() - { - _collection = new Dictionary(); - } - - internal FasterList GetList() where T:struct - { - IFasterList list; - if (_collection.TryGetValue(typeof (T), out list)) - { - return list as FasterList; - } - - list = new FasterList(); - - _collection.Add(typeof (T), list); - - return (FasterList) list; - } - } - - public class SharedGroupedStructNodesLists - { - internal SharedGroupedStructNodesLists() - { - _collection = new Dictionary>(); - } - - internal IFasterList GetList(int groupID) where T : struct - { - Dictionary dic = GetGroup(); - IFasterList localList; - - if (dic.TryGetValue(groupID, out localList)) - return localList; - - localList = new FasterList(); - dic.Add(groupID, localList); - - return localList; - } - - internal Dictionary GetGroup() where T : struct - { - Dictionary dic; - - if (_collection.TryGetValue(typeof(T), out dic)) - { - return dic; - } - - dic = new Dictionary(); - - _collection.Add(typeof(T), dic); - - return dic; - } - - readonly Dictionary> _collection; - } -} \ No newline at end of file diff --git a/ECS/note.txt b/ECS/note.txt deleted file mode 100644 index c041193..0000000 --- a/ECS/note.txt +++ /dev/null @@ -1,111 +0,0 @@ -systems do not hold component data, but only system states -systems cannot be injected -systems are SRP and OCP -systems communicates between component, mediators, producer/consumer, observers. producer/consumer and observers must be defined in the layer of the engine. -systems can have injected dependencies - -components don't have logic -components can have only getter and setter -components cannot define patterns that requires logic. -components cannot issues commands - -High Cohesion[edit] -Main article: Cohesion (computer science) -High Cohesion is an evaluative pattern that attempts to keep objects appropriately focused, manageable and understandable. High cohesion is generally used in support of Low Coupling. High cohesion means that the responsibilities of a given element are strongly related and highly focused. Breaking programs into classes and subsystems is an example of activities that increase the cohesive properties of a system. Alternatively, low cohesion is a situation in which a given element has too many unrelated responsibilities. Elements with low cohesion often suffer from being hard to comprehend, hard to reuse, hard to maintain and averse to change.[3] - -Low Coupling[edit] -Main article: Loose coupling -Low Coupling is an evaluative pattern, which dictates how to assign responsibilities to support: - -lower dependency between the classes, -change in one class having lower impact on other classes, -higher reuse potential. - -events, observers and mediators have the inconvience to hold the reference to the engine, which forces to use cleanup if the engine must be removed. -Observers are easy to clean up from the engine. Mediators needs to be integrated to the framework to be simple to clean up. Component events need the clean up function. -producer/consumer has the inconvienent to force check the number of jobs available everyframe - -Engine can't be removed, they can only be disabled, but the logic of disabling must be handled by the engine itself - -Should components have just one element? Should engines use just nodes? Components are ditacted by the entities and Nodes by the engines - -http://thelinuxlich.github.io/artemis_CSharp/ - -differences: components no events, everthing must be update -give more responsabiltiy to the user, semplicity - -https://github.com/sschmid/Entitas-CSharp/wiki/Overview - -no groups, no queries - -http://entity-systems.wikidot.com/es-articles - -http://www.ashframework.org/ - -it's very important to give a namespace to the engines. In this way it's impossible to create semantically wrong nodes (PlayerNode Vs TargetNode) - -ToDo: - -it's not safe to remove an engine without having called being denitialised internal states. A special ClearOnRemove function must be added for each engine - -namespace GameFramework.RayCast -{ - public class RayCastEngineEngine - { - public RayCastEngine(RayCastEmployer jobList) - { - jobList.onJobassigned += OnRaycastRequested; - } - - public void Add(IComponent obj) - {} - - public void Remove(IComponent obj) - {} - - void OnRaycastRequested(RayCastJob job) - { - RaycastHit shootHit; - - Physics.Raycast(job.rayVector, out shootHit, job.range, _enemyMask); - - job.Done(shootHit); - } - - RayCastEmployer _employer; - - int _enemyMask; - } - - public struct RayCastJob - { - readonly public Ray rayVector; - readonly public float range; - readonly public Action Done; - - public RayCastJob(Ray direction, float distance, Action OnDone) - { - rayVector = direction; - range = distance; - Done = OnDone; - } - } - - public class RayCastEmployer - { - public event Action onJobassigned; - - public void AssignJob(RayCastJob data, Action onJobdone) - { - onJobassigned(data); - } - } -} - -if your code can be read as - -A tells B to do something is direct -A register B event is indirect -althoggh if B tells A something through event is direct again. B must say something like I don't know who you are, but this just happened. you say B.SomethingHappenedToMe() not B.YouMustDoThis(); - -un engine non deve mai avere concetti di un altro engine. dire all'engine sonoro suona morte � sbagliato. � l'engine death che triggera l'evento e l'engine sound ad ascoltarlo. diff --git a/Svelto.Common b/Svelto.Common new file mode 160000 index 0000000..9fd29ea --- /dev/null +++ b/Svelto.Common @@ -0,0 +1 @@ +Subproject commit 9fd29eaa5a2dd50a248112c045ae7691cab20a44 diff --git a/Svelto.ECS/.gitignore b/Svelto.ECS/.gitignore new file mode 100644 index 0000000..ac529bb --- /dev/null +++ b/Svelto.ECS/.gitignore @@ -0,0 +1,4 @@ +/EntitySystem/note.txt +/EntitySystem/note.txt.meta +/*.meta +*.meta diff --git a/Context/ContextNotifier.cs b/Svelto.ECS/Context/ContextNotifier.cs similarity index 100% rename from Context/ContextNotifier.cs rename to Svelto.ECS/Context/ContextNotifier.cs diff --git a/Context/Factories/GameObjectFactory.cs b/Svelto.ECS/Context/Factories/GameObjectFactory.cs similarity index 100% rename from Context/Factories/GameObjectFactory.cs rename to Svelto.ECS/Context/Factories/GameObjectFactory.cs diff --git a/Context/Factories/MonoBehaviourFactory.cs b/Svelto.ECS/Context/Factories/MonoBehaviourFactory.cs similarity index 91% rename from Context/Factories/MonoBehaviourFactory.cs rename to Svelto.ECS/Context/Factories/MonoBehaviourFactory.cs index 7f862ab..bd376b6 100644 --- a/Context/Factories/MonoBehaviourFactory.cs +++ b/Svelto.ECS/Context/Factories/MonoBehaviourFactory.cs @@ -2,7 +2,6 @@ #region using System; -using Svelto.DataStructures; using UnityEngine; #endregion diff --git a/Context/ICompositionRoot.cs b/Svelto.ECS/Context/ICompositionRoot.cs similarity index 100% rename from Context/ICompositionRoot.cs rename to Svelto.ECS/Context/ICompositionRoot.cs diff --git a/Context/IContextNotifer.cs b/Svelto.ECS/Context/IContextNotifer.cs similarity index 100% rename from Context/IContextNotifer.cs rename to Svelto.ECS/Context/IContextNotifer.cs diff --git a/Svelto.ECS/Context/IUnityCompositionRoot.cs b/Svelto.ECS/Context/IUnityCompositionRoot.cs new file mode 100644 index 0000000..c4db99a --- /dev/null +++ b/Svelto.ECS/Context/IUnityCompositionRoot.cs @@ -0,0 +1,11 @@ +#if UNITY_5 || UNITY_5_3_OR_NEWER +namespace Svelto.Context +{ + public interface IUnityCompositionRoot + { + void OnContextCreated(UnityContext contextHolder); + void OnContextInitialized(); + void OnContextDestroyed(); + } +} +#endif \ No newline at end of file diff --git a/Context/IWaitForFrameworkDestruction.cs b/Svelto.ECS/Context/IWaitForFrameworkDestruction.cs similarity index 88% rename from Context/IWaitForFrameworkDestruction.cs rename to Svelto.ECS/Context/IWaitForFrameworkDestruction.cs index 622fa3e..e830787 100644 --- a/Context/IWaitForFrameworkDestruction.cs +++ b/Svelto.ECS/Context/IWaitForFrameworkDestruction.cs @@ -1,5 +1,3 @@ -using System; - namespace Svelto.Context { public interface IWaitForFrameworkDestruction diff --git a/Context/IWaitForFrameworkInitialization.cs b/Svelto.ECS/Context/IWaitForFrameworkInitialization.cs similarity index 88% rename from Context/IWaitForFrameworkInitialization.cs rename to Svelto.ECS/Context/IWaitForFrameworkInitialization.cs index 937cbbc..f1b8dfb 100644 --- a/Context/IWaitForFrameworkInitialization.cs +++ b/Svelto.ECS/Context/IWaitForFrameworkInitialization.cs @@ -1,5 +1,3 @@ -using System; - namespace Svelto.Context { public interface IWaitForFrameworkInitialization diff --git a/Context/UnityContext.cs b/Svelto.ECS/Context/UnityContext.cs similarity index 76% rename from Context/UnityContext.cs rename to Svelto.ECS/Context/UnityContext.cs index 9591861..925a147 100644 --- a/Context/UnityContext.cs +++ b/Svelto.ECS/Context/UnityContext.cs @@ -13,6 +13,11 @@ public abstract class UnityContext:MonoBehaviour } } +//a Unity context is a platform specific context wrapper. +//Unity will drive the ICompositionRoot interface. +//OnContextCreated is called during the Awake of this MB +//OnContextInitialized is called one frame after the MB started +//OnContextDestroyed is called when the MB is destroyed public class UnityContext: UnityContext where T:class, ICompositionRoot, new() { protected override void OnAwake() diff --git a/Svelto.ECS/ECS/DataStructures/TypeSafeDictionary.cs b/Svelto.ECS/ECS/DataStructures/TypeSafeDictionary.cs new file mode 100644 index 0000000..c7cdc14 --- /dev/null +++ b/Svelto.ECS/ECS/DataStructures/TypeSafeDictionary.cs @@ -0,0 +1,51 @@ +using Svelto.DataStructures; +using System.Collections.Generic; + +namespace Svelto.ECS.Internal +{ + /// + /// This is just a place holder at the moment + /// I always wanted to create my own Dictionary + /// data structure as excercise, but never had the + /// time to. At the moment I need the custom interface + /// wrapped though. + /// + + public interface ITypeSafeDictionary + { + void FillWithIndexedEntityViews(ITypeSafeList entityViews); + bool Remove(int entityId); + IEntityView GetIndexedEntityView(int entityID); + } + + class TypeSafeDictionary : Dictionary, ITypeSafeDictionary where TValue:IEntityView + { + internal static readonly ReadOnlyDictionary Default = + new ReadOnlyDictionary(new Dictionary()); + + public void FillWithIndexedEntityViews(ITypeSafeList entityViews) + { + int count; + var buffer = FasterList.NoVirt.ToArrayFast((FasterList) entityViews, out count); + + for (int i = 0; i < count; i++) + { + var entityView = buffer[i]; + + Add(entityView.ID, entityView); + } + } + + new public bool Remove(int entityId) + { + base.Remove(entityId); + + return this.Count > 0; + } + + public IEntityView GetIndexedEntityView(int entityID) + { + return this[entityID]; + } + } +} diff --git a/Svelto.ECS/ECS/DataStructures/TypeSafeFasterListForECS.cs b/Svelto.ECS/ECS/DataStructures/TypeSafeFasterListForECS.cs new file mode 100644 index 0000000..17235f2 --- /dev/null +++ b/Svelto.ECS/ECS/DataStructures/TypeSafeFasterListForECS.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Svelto.DataStructures; + +namespace Svelto.ECS.Internal +{ + public interface ITypeSafeList: IEnumerable + { + void AddRange(ITypeSafeList entityViewListValue); + + ITypeSafeList Create(); + bool isQueryiableEntityView { get; } + bool UnorderedRemove(int entityID); + ITypeSafeDictionary CreateIndexedDictionary(); + IEntityView[] ToArrayFast(out int count); + void ReserveCapacity(int capacity); + } + + class TypeSafeFasterListForECS: FasterList where T:IEntityView + { + protected TypeSafeFasterListForECS() + { + _mappedIndices = new Dictionary(); + } + + protected TypeSafeFasterListForECS(int size):base(size) + { + _mappedIndices = new Dictionary(); + } + + public bool UnorderedRemove(int entityID) + { + var index = _mappedIndices[entityID]; + + DesignByContract.Check.Assert(entityID == this[index].ID, "Something went wrong with the Svelto.ECS code, please contact the author"); + + _mappedIndices.Remove(entityID); + + if (UnorderedRemoveAt(index)) + _mappedIndices[this[index].ID] = index; + + return this.Count > 0; + } + + public void AddRange(ITypeSafeList entityViewListValue) + { + var index = this.Count; + + base.AddRange(entityViewListValue as FasterList); + + for (int i = index; i < Count; ++i) + _mappedIndices[this[i].ID] = i; + } + + new public void Add(T entityView) + { + var index = this.Count; + + base.Add(entityView); + + _mappedIndices[entityView.ID] = index; + } + + public void ReserveCapacity(int capacity) + { + if (this.ToArrayFast().Length < capacity) + Resize(capacity); + } + + public int GetIndexFromID(int entityID) + { + return _mappedIndices[entityID]; + } + + readonly Dictionary _mappedIndices; + } + + class TypeSafeFasterListForECSForStructs : TypeSafeFasterListForECS, ITypeSafeList where T:struct, IEntityStruct + { + public TypeSafeFasterListForECSForStructs(int size):base(size) + {} + + public TypeSafeFasterListForECSForStructs() + {} + + public ITypeSafeList Create() + { + return new TypeSafeFasterListForECSForStructs(); + } + + public bool isQueryiableEntityView + { + get { return false; } + } + + public ITypeSafeDictionary CreateIndexedDictionary() + { + throw new Exception("Not Allowed"); + } + + public IEntityView[] ToArrayFast(out int count) + { + throw new Exception("Not Allowed"); + } + + public ITypeSafeList Create(int size) + { + return new TypeSafeFasterListForECSForStructs(size); + } + } + + class TypeSafeFasterListForECSForClasses : TypeSafeFasterListForECS, ITypeSafeList where T:EntityView, new() + { + public TypeSafeFasterListForECSForClasses(int size):base(size) + {} + + public TypeSafeFasterListForECSForClasses() + {} + + public ITypeSafeList Create() + { + return new TypeSafeFasterListForECSForClasses(); + } + + public bool isQueryiableEntityView + { + get { return true; } + } + + public ITypeSafeDictionary CreateIndexedDictionary() + { + return new TypeSafeDictionary(); + } + + public IEntityView[] ToArrayFast(out int count) + { + count = this.Count; + + return this.ToArrayFast(); + } + + public ITypeSafeList Create(int size) + { + return new TypeSafeFasterListForECSForClasses(size); + } + } +} diff --git a/ECS/Dispatcher/DispatchOnChange.cs b/Svelto.ECS/ECS/Dispatcher/DispatchOnChange.cs similarity index 100% rename from ECS/Dispatcher/DispatchOnChange.cs rename to Svelto.ECS/ECS/Dispatcher/DispatchOnChange.cs diff --git a/ECS/Dispatcher/DispatcherOnSet.cs b/Svelto.ECS/ECS/Dispatcher/DispatcherOnSet.cs similarity index 100% rename from ECS/Dispatcher/DispatcherOnSet.cs rename to Svelto.ECS/ECS/Dispatcher/DispatcherOnSet.cs diff --git a/Svelto.ECS/ECS/EnginesRootEngines.cs b/Svelto.ECS/ECS/EnginesRootEngines.cs new file mode 100644 index 0000000..e2ebfaa --- /dev/null +++ b/Svelto.ECS/ECS/EnginesRootEngines.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; +using Svelto.ECS.Schedulers; +using Svelto.WeakEvents; + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +using Svelto.ECS.Profiler; +#endif + +namespace Svelto.ECS +{ + public partial class EnginesRoot : IDisposable + { + /// + /// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot + /// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks + /// periodically if new entity must be submited to the database and the engines. It's an external + /// dependencies to be indipendent by the running platform as the user can define it. + /// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why + /// it must receive a weak reference of the EnginesRoot callback. + /// + public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) + { + _entityViewEngines = new Dictionary>(); + _otherEngines = new FasterList(); + + _entityViewsDB = new Dictionary(); + _metaEntityViewsDB = new Dictionary(); + _groupEntityViewsDB = new Dictionary>(); + _entityViewsDBDic = new Dictionary(); + + _entityViewsToAdd = new DoubleBufferedEntityViews>(); + _metaEntityViewsToAdd = new DoubleBufferedEntityViews>(); + _groupedEntityViewsToAdd = new DoubleBufferedEntityViews>>(); + + _DB = new EntityViewsDB(_entityViewsDB, _entityViewsDBDic, _metaEntityViewsDB, _groupEntityViewsDB); + + _scheduler = entityViewScheduler; + _scheduler.Schedule(new WeakAction(SubmitEntityViews)); +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); + debugEngineObject.gameObject.AddComponent(); +#endif + } + + public void AddEngine(IEngine engine) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + Profiler.EngineProfiler.AddEngine(engine); +#endif + var viewEngine = engine as IHandleEntityViewEngine; + + if (viewEngine != null) + CheckEntityViewsEngine(viewEngine); + else + _otherEngines.Add(engine); + + var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; + if (queryableEntityViewEngine != null) + { + queryableEntityViewEngine.entityViewsDB = _DB; + queryableEntityViewEngine.Ready(); + } + } + + void CheckEntityViewsEngine(IEngine engine) + { + var baseType = engine.GetType().GetBaseType(); + + while (baseType != _object) + { + if (baseType.IsGenericTypeEx()) + { + var genericArguments = baseType.GetGenericArgumentsEx(); + AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); + + return; + } + + baseType = baseType.GetBaseType(); + } + + throw new ArgumentException("Not Supported Engine " + engine.ToString()); + } + + //The T parameter allows to pass datastructure sthat not necessarly are + //defined with IEngine, but must be defined with IEngine implementations + static void AddEngine(T engine, Type[] entityViewTypes, + Dictionary> engines) where T:IEngine + { + for (int i = 0; i < entityViewTypes.Length; i++) + { + var type = entityViewTypes[i]; + + AddEngine(engine, engines, type); + } + } + + static void AddEngine(T engine, Dictionary> engines, Type type) where T : IEngine + { + FasterList list; + if (engines.TryGetValue(type, out list) == false) + { + list = new FasterList(); + + engines.Add(type, list); + } + + list.Add(engine); + } + + readonly Dictionary> _entityViewEngines; + readonly FasterList _otherEngines; + + static readonly Type _entityViewType= typeof(EntityView); + static readonly Type _object = typeof(object); + + class DoubleBufferedEntityViews where T : class, IDictionary, new() + { + readonly T _entityViewsToAddBufferA = new T(); + readonly T _entityViewsToAddBufferB = new T(); + + internal DoubleBufferedEntityViews() + { + this.other = _entityViewsToAddBufferA; + this.current = _entityViewsToAddBufferB; + } + + internal T other; + internal T current; + + internal void Swap() + { + var toSwap = other; + other = current; + current = toSwap; + } + } + } +} \ No newline at end of file diff --git a/Svelto.ECS/ECS/EnginesRootEntities.cs b/Svelto.ECS/ECS/EnginesRootEntities.cs new file mode 100644 index 0000000..fea2823 --- /dev/null +++ b/Svelto.ECS/ECS/EnginesRootEntities.cs @@ -0,0 +1,411 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +using Svelto.ECS.Profiler; +#endif + +namespace Svelto.ECS +{ + public partial class EnginesRoot : IDisposable + { + /// + /// an EnginesRoot reference cannot be held by anything else than the Composition Root + /// where it has been created. IEntityFactory and IEntityFunctions allow a weakreference + /// of the EnginesRoot to be passed around. + /// + /// + public IEntityFactory GenerateEntityFactory() + { + return new GenericEntityFactory(new DataStructures.WeakReference(this)); + } + + public IEntityFunctions GenerateEntityFunctions() + { + return new GenericEntityFunctions(new DataStructures.WeakReference(this)); + } + + /// + /// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity + /// itself in terms of EntityViews to build. The Implementors are passed to fill the + /// references of the EntityViews components. Please read the articles on my blog + /// to understand better the terminologies + /// + /// + /// + /// + void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, EntityDescriptorTemplate.Default, implementors); + } + + /// + /// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo + /// can be built in place of the generic parameter T. + /// + /// + /// + /// + void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptor, object[] implementors) + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, entityDescriptor, implementors); + } + + /// + /// A meta entity is a way to manage a set of entitites that are not easily + /// queriable otherwise. For example you may want to group existing entities + /// by size and type and then use the meta entity entityView to manage the data + /// shared among the single entities of the same type and size. This will + /// prevent the scenario where the coder is forced to parse all the entities to + /// find the ones of the same size and type. + /// Since the entities are managed through the shared entityView, the same + /// shared entityView must be found on the single entities of the same type and size. + /// The shared entityView of the meta entity is then used by engines that are meant + /// to manage a group of entities through a single entityView. + /// The same engine can manage several meta entities entityViews too. + /// The Engine manages the logic of the Meta EntityView data and other engines + /// can read back this data through the normal entity as the shared entityView + /// will be present in their descriptor too. + /// It's a way to control a group of Entities through a entityView only. + /// This set of entities can share exactly the same entityView reference if + /// built through this function. In this way, if you need to set a variable + /// on a group of entities, instead to inject N entityViews and iterate over + /// them to set the same value, you can inject just one entityView, set the value + /// and be sure that the value is shared between entities. + /// + /// + /// + /// + void BuildMetaEntity(int metaEntityID, object[] implementors) where T : IEntityDescriptor, new() + { + EntityFactory.BuildEntityViews(metaEntityID, _metaEntityViewsToAdd.current, + EntityDescriptorTemplate.Default, implementors); + } + + /// + /// Using this function is like building a normal entity, but the entityViews + /// are grouped by groupID to be more efficently processed inside engines and + /// improve cache locality. Either class entityViews and struct entityViews can be + /// grouped. + /// + /// + /// + /// + /// + void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() + { + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + EntityDescriptorTemplate.Default, + implementors); + } + + void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + entityDescriptor, implementors); + } + + void Preallocate(int size) where T : IEntityDescriptor, new() + { + var entityViewsToBuild = ((EntityDescriptorInfo) EntityDescriptorTemplate.Default).entityViewsToBuild; + int count = entityViewsToBuild.Length; + + for (int index = 0; index < count; index++) + { + var entityViewBuilder = entityViewsToBuild[index]; + var entityViewType = entityViewBuilder.GetEntityViewType(); + + ITypeSafeList dbList; + if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) + _entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); + else + dbList.ReserveCapacity(size); + + if (_entityViewsToAdd.current.TryGetValue(entityViewType, out dbList) == false) + _entityViewsToAdd.current[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); + else + dbList.ReserveCapacity(size); + } + } + + void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) + { + var removeEntityImplementor = removeInfo as RemoveEntityImplementor; + + if (removeEntityImplementor.isInAGroup) + InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, removeEntityImplementor.groupID, _entityViewsDB); + else + InternalRemoveFromDBAndEngines(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, _entityViewsDB); + } + + void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + InternalRemoveFromDBAndEngines( ((EntityDescriptorInfo) EntityDescriptorTemplate.Default).entityViewsToBuild, entityID, _entityViewsDB); + } + + void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + InternalRemoveFromDBAndEngines(((EntityDescriptorInfo) EntityDescriptorTemplate.Default).entityViewsToBuild, metaEntityID, _metaEntityViewsDB); + } + + void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + InternalRemoveFromDBAndEngines(((EntityDescriptorInfo) EntityDescriptorTemplate.Default).entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); + } + + void RemoveEntitiesGroup(int groupID) + { + foreach (var group in _groupEntityViewsDB[groupID]) + { + var entityViewType = group.Key; + + int count; + var entities = group.Value.ToArrayFast(out count); + + for (int i = 0; i < count; i++) + { + var entityID = entities[i].ID; + + InternalRemoveEntityViewFromDBAndEngines(_entityViewsDB, entityViewType, entityID); + } + } + + _groupEntityViewsDB.Remove(groupID); + } + + void InternalRemoveEntityViewFromDBAndEngines(Dictionary entityViewsDB, + Type entityViewType, int entityID) + { + var entityViews = entityViewsDB[entityViewType]; + if (entityViews.UnorderedRemove(entityID) == false) + entityViewsDB.Remove(entityViewType); + + if (entityViews.isQueryiableEntityView) + { + var typeSafeDictionary = _entityViewsDBDic[entityViewType]; + var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); + + if (typeSafeDictionary.Remove(entityID) == false) + _entityViewsDBDic.Remove(entityViewType); + + for (var current = entityViewType; current != _entityViewType; current = current.BaseType) + RemoveEntityViewFromEngines(_entityViewEngines, entityView, current); + } + } + + void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() + { + DesignByContract.Check.Require(fromGroupID != toGroupID, "can't move an entity to the same group where it already belongs to"); + + var entityViewBuilders = ((EntityDescriptorInfo) EntityDescriptorTemplate.Default).entityViewsToBuild; + int entityViewBuildersCount = entityViewBuilders.Length; + + var dictionary = _groupEntityViewsDB[fromGroupID]; + + Dictionary groupedEntityViewsTyped; + if (_groupEntityViewsDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) + { + groupedEntityViewsTyped = new Dictionary(); + + _groupEntityViewsDB.Add(toGroupID, groupedEntityViewsTyped); + } + + for (int i = 0; i < entityViewBuildersCount; i++) + { + IEntityViewBuilder entityViewBuilder = entityViewBuilders[i]; + Type entityViewType = entityViewBuilder.GetEntityViewType(); + + ITypeSafeList fromSafeList = dictionary[entityViewType]; + ITypeSafeList toSafeList; + + if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) + { + toSafeList = fromSafeList.Create(); + } + + entityViewBuilder.MoveEntityView(entityID, fromSafeList, toSafeList); + + if (fromSafeList.UnorderedRemove(entityID) == false) + dictionary.Remove(entityViewType); + } + + if (dictionary.Count == 0) _groupEntityViewsDB.Remove(fromGroupID); + } + + void InternalRemoveFromDBAndEngines(IEntityViewBuilder[] entityViewBuilders, int entityID, + Dictionary entityViewsDB) + { + int entityViewBuildersCount = entityViewBuilders.Length; + + for (int i = 0; i < entityViewBuildersCount; i++) + { + Type entityViewType = entityViewBuilders[i].GetEntityViewType(); + + InternalRemoveEntityViewFromDBAndEngines(entityViewsDB, entityViewType, entityID); + } + } + + void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, + Dictionary entityViewsDB) + { + InternalRemoveFromGroupDB(entityViewBuilders, entityID, groupID); + + InternalRemoveFromDBAndEngines(entityViewBuilders, entityID, entityViewsDB); + } + + void InternalRemoveFromGroupDB(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID) + { + int entityViewBuildersCount = entityViewBuilders.Length; + + Dictionary dictionary = _groupEntityViewsDB[groupID]; + + for (int i = 0; i < entityViewBuildersCount; i++) + { + Type entityViewType = entityViewBuilders[i].GetEntityViewType(); + + if (dictionary[entityViewType].UnorderedRemove(entityID) == false) + dictionary.Remove(entityViewType); + } + + if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); + } + + static void RemoveEntityViewFromEngines(Dictionary> entityViewEngines, + IEntityView entityView, Type entityViewType) + { + FasterList enginesForEntityView; + + if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) + { + int count; + var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); + + for (int j = 0; j < count; j++) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + EngineProfiler.MonitorRemoveDuration(fastList[j], entityView); +#else + fastList[j].Remove(entityView); +#endif + } + } + } + + class GenericEntityFactory : IEntityFactory + { + DataStructures.WeakReference _weakEngine; + + public GenericEntityFactory(DataStructures.WeakReference weakReference) + { + _weakEngine = weakReference; + } + + public void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildEntity(entityID, implementors); + } + + public void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + _weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); + } + + public void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildMetaEntity(metaEntityID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); + } + + public void Preallocate(int size) where T : IEntityDescriptor, new() + { + _weakEngine.Target.Preallocate(size); + } + } + + class GenericEntityFunctions : IEntityFunctions + { + public GenericEntityFunctions(DataStructures.WeakReference weakReference) + { + _weakReference = weakReference; + } + + public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) + { + _weakReference.Target.RemoveEntity(entityID, removeInfo); + } + + public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(metaEntityID); + } + + public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + public void RemoveGroupedEntities(int groupID) + { + _weakReference.Target.RemoveEntitiesGroup(groupID); + } + + public void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() + { + _weakReference.Target.SwapEntityGroup(entityID, fromGroupID, toGroupID); + } + + readonly DataStructures.WeakReference _weakReference; + } + + public void Dispose() + { + foreach (var entity in _entityViewsDB) + { + if (entity.Value.isQueryiableEntityView == true) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } + } + } + + foreach (var entity in _metaEntityViewsDB) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } + } + } + + readonly EntityViewsDB _DB; + + readonly Dictionary _entityViewsDB; + readonly Dictionary _metaEntityViewsDB; + readonly Dictionary> _groupEntityViewsDB; + + readonly Dictionary _entityViewsDBDic; + + } +} \ No newline at end of file diff --git a/Svelto.ECS/ECS/EnginesRootSubmission.cs b/Svelto.ECS/ECS/EnginesRootSubmission.cs new file mode 100644 index 0000000..c2343b9 --- /dev/null +++ b/Svelto.ECS/ECS/EnginesRootSubmission.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; +using Svelto.ECS.Schedulers; + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +using Svelto.ECS.Profiler; +#endif + +namespace Svelto.ECS +{ + public partial class EnginesRoot : IDisposable + { + void SubmitEntityViews() + { + bool newEntityViewsHaveBeenAddedWhileIterating = + _metaEntityViewsToAdd.current.Count > 0 + || _entityViewsToAdd.current.Count > 0 + || _groupedEntityViewsToAdd.current.Count > 0; + + int numberOfReenteringLoops = 0; + + while (newEntityViewsHaveBeenAddedWhileIterating) + { + //use other as source from now on + //current will be use to write new entityViews + _entityViewsToAdd.Swap(); + _metaEntityViewsToAdd.Swap(); + _groupedEntityViewsToAdd.Swap(); + + if (_entityViewsToAdd.other.Count > 0) + AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB); + + if (_metaEntityViewsToAdd.other.Count > 0) + AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); + + if (_groupedEntityViewsToAdd.other.Count > 0) + AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); + + //other can be cleared now + _entityViewsToAdd.other.Clear(); + _metaEntityViewsToAdd.other.Clear(); + _groupedEntityViewsToAdd.other.Clear(); + + //has current new entityViews? + newEntityViewsHaveBeenAddedWhileIterating = + _metaEntityViewsToAdd.current.Count > 0 + || _entityViewsToAdd.current.Count > 0 + || _groupedEntityViewsToAdd.current.Count > 0; + + if (numberOfReenteringLoops > 5) + throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); + + numberOfReenteringLoops++; + } + } + + void AddEntityViewsToTheDBAndSuitableEngines(Dictionary entityViewsToAdd, + Dictionary entityViewsDB) + { + foreach (var entityViewList in entityViewsToAdd) + { + AddEntityViewToDB(entityViewsDB, entityViewList); + + if (entityViewList.Value.isQueryiableEntityView) + { + AddEntityViewToEntityViewsDictionary(_entityViewsDBDic, entityViewList.Value, entityViewList.Key); + } + } + + foreach (var entityViewList in entityViewsToAdd) + { + if (entityViewList.Value.isQueryiableEntityView) + { + var type = entityViewList.Key; + for (var current = type; current != _entityViewType; current = current.BaseType) + AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, + current); + } + } + } + + void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary> groupedEntityViewsToAdd, + Dictionary> groupEntityViewsDB, + Dictionary entityViewsDB) + { + foreach (var group in groupedEntityViewsToAdd) + { + AddEntityViewsToGroupDB(groupEntityViewsDB, @group); + + AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); + } + } + + static void AddEntityViewsToGroupDB(Dictionary> groupEntityViewsDB, + KeyValuePair> @group) + { + Dictionary groupedEntityViewsByType; + + if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) + groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary(); + + foreach (var entityView in @group.Value) + { + groupedEntityViewsByType.Add(entityView.Key, entityView.Value); + } + } + + static void AddEntityViewToDB(Dictionary entityViewsDB, KeyValuePair entityViewList) + { + ITypeSafeList dbList; + + if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) + dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); + + dbList.AddRange(entityViewList.Value); + } + + static void AddEntityViewToEntityViewsDictionary(Dictionary entityViewsDBdic, + ITypeSafeList entityViews, Type entityViewType) + { + ITypeSafeDictionary entityViewsDic; + + if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) + entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); + + entityViewsDic.FillWithIndexedEntityViews(entityViews); + } + + static void AddEntityViewToTheSuitableEngines(Dictionary> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) + { + FasterList enginesForEntityView; + + if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) + { + int viewsCount; + + var entityViews = entityViewsList.ToArrayFast(out viewsCount); + + for (int i = 0; i < viewsCount; i++) + { + int count; + var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); + IEntityView entityView = entityViews[i]; + for (int j = 0; j < count; j++) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + EngineProfiler.MonitorAddDuration(fastList[j], entityView); +#else + fastList[j].Add(entityView); +#endif + } + } + } + } + + readonly DoubleBufferedEntityViews> _entityViewsToAdd; + readonly DoubleBufferedEntityViews> _metaEntityViewsToAdd; + readonly DoubleBufferedEntityViews>> _groupedEntityViewsToAdd; + + readonly EntitySubmissionScheduler _scheduler; + + } +} \ No newline at end of file diff --git a/Svelto.ECS/ECS/EntityDescriptor.cs b/Svelto.ECS/ECS/EntityDescriptor.cs new file mode 100644 index 0000000..d6c5aa3 --- /dev/null +++ b/Svelto.ECS/ECS/EntityDescriptor.cs @@ -0,0 +1,272 @@ +using Svelto.DataStructures; +using Svelto.ECS.Internal; +using Svelto.Utilities; +using System; +using System.Collections.Generic; + +namespace Svelto.ECS +{ + public interface IEntityDescriptor + { + IEntityViewBuilder[] entityViewsToBuild { get; } + } + + public class EntityDescriptor:IEntityDescriptor + { + protected EntityDescriptor(IEntityViewBuilder[] entityViewsToBuild) + { + this.entityViewsToBuild = entityViewsToBuild; + } + + public IEntityViewBuilder[] entityViewsToBuild { get; private set; } + } + + public interface IEntityDescriptorInfo + {} + + public static class EntityDescriptorTemplate where TType : IEntityDescriptor, new() + { + public static readonly IEntityDescriptorInfo Default = new EntityDescriptorInfo(new TType()); + } + + public class DynamicEntityDescriptorInfo : EntityDescriptorInfo where TType : IEntityDescriptor, new() + { + public DynamicEntityDescriptorInfo(FasterList extraEntityViews) + { + DesignByContract.Check.Require(extraEntityViews.Count > 0, "don't use a DynamicEntityDescriptorInfo if you don't need to use extra EntityViews"); + + var descriptor = new TType(); + int length = descriptor.entityViewsToBuild.Length; + + entityViewsToBuild = new IEntityViewBuilder[length + extraEntityViews.Count]; + + Array.Copy(descriptor.entityViewsToBuild, 0, entityViewsToBuild, 0, length); + Array.Copy(extraEntityViews.ToArrayFast(), 0, entityViewsToBuild, length, extraEntityViews.Count); + + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuild); + name = descriptor.ToString(); + } + } +} + +namespace Svelto.ECS.Internal +{ + public class EntityDescriptorInfo:IEntityDescriptorInfo + { + internal IEntityViewBuilder[] entityViewsToBuild; + internal RemoveEntityImplementor removeEntityImplementor; + internal string name; + + internal EntityDescriptorInfo(IEntityDescriptor descriptor) + { + name = descriptor.ToString(); + entityViewsToBuild = descriptor.entityViewsToBuild; + + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuild); + } + + protected EntityDescriptorInfo() + {} + } + + static class EntityFactory + { + internal static void BuildGroupedEntityViews(int entityID, int groupID, + Dictionary> groupEntityViewsByType, + IEntityDescriptorInfo eentityViewsToBuildDescriptor, + object[] implementors) + { + var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; + Dictionary groupedEntityViewsTyped; + + if (groupEntityViewsByType.TryGetValue(groupID, out groupedEntityViewsTyped) == false) + { + groupedEntityViewsTyped = new Dictionary(); + groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); + } + + //I would like to find a better solution for this + var removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.entityViewsToBuild, groupID); + + InternalBuildEntityViews(entityID, groupedEntityViewsTyped, entityViewsToBuildDescriptor, implementors, removeEntityImplementor); + } + + internal static void BuildEntityViews(int entityID, + Dictionary entityViewsByType, + IEntityDescriptorInfo eentityViewsToBuildDescriptor, + object[] implementors) + { + var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; + var removeEntityImplementor = entityViewsToBuildDescriptor.removeEntityImplementor; + + InternalBuildEntityViews(entityID, entityViewsByType, entityViewsToBuildDescriptor, implementors, removeEntityImplementor); + } + + static void InternalBuildEntityViews(int entityID, + Dictionary entityViewsByType, + IEntityDescriptorInfo eentityViewsToBuildDescriptor, + object[] implementors, RemoveEntityImplementor removeEntityImplementor) + { + var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; + var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; + int count = entityViewsToBuild.Length; + + for (int index = 0; index < count; index++) + { + var entityViewBuilder = entityViewsToBuild[index]; + var entityViewType = entityViewBuilder.GetEntityViewType(); + + //only class EntityView will be returned + //struct EntityView cannot be filled so it will be null. + var entityViewObjectToFill = + BuildEntityView(entityID, entityViewsByType, entityViewType, entityViewBuilder); + + //the semantic of this code must still be improved + //but only classes can be filled, so I am aware + //it's a EntityView + if (entityViewObjectToFill != null) + { + FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, + entityViewsToBuildDescriptor.name); + } + } + } + + static IEntityView BuildEntityView(int entityID, Dictionary entityViewsByType, + Type entityViewType, IEntityViewBuilder entityViewBuilder) + { + ITypeSafeList entityViewsList; + + var entityViewsPoolWillBeCreated = + entityViewsByType.TryGetValue(entityViewType, out entityViewsList) == false; + + IEntityView entityViewObjectToFill; + + //passing the undefined entityViewsByType inside the entityViewBuilder will allow + //it to be created with the correct type and casted back to the undefined list. + //that's how the list will be eventually of the target type. + entityViewBuilder.BuildEntityViewAndAddToList(ref entityViewsList, entityID, out entityViewObjectToFill); + + if (entityViewsPoolWillBeCreated) + entityViewsByType.Add(entityViewType, entityViewsList); + + return entityViewObjectToFill as IEntityView; + } + + //this is used to avoid newing a dictionary every time, but it's used locally only and it's clearead for each use +#if DEBUG && !PROFILER + static readonly Dictionary> implementorsByType = new Dictionary>(); +#else + static readonly Dictionary implementorsByType = new Dictionary(); +#endif + + static void FillEntityView(EntityView entityView, object[] implementors, RemoveEntityImplementor removeEntity, + string entityDescriptorName) + { + for (int index = 0; index < implementors.Length; index++) + { + var implementor = implementors[index]; + + if (implementor != null) + { + var type = implementor.GetType(); + + Type[] interfaces; + if (_cachedTypes.TryGetValue(type, out interfaces) == false) + interfaces = _cachedTypes[type] = type.GetInterfacesEx(); + + for (int iindex = 0; iindex < interfaces.Length; iindex++) + { + var componentType = interfaces[iindex]; +#if DEBUG && !PROFILER + Tuple implementorHolder; + + if (implementorsByType.TryGetValue(componentType, out implementorHolder) == true) + implementorHolder.item2++; + else + implementorsByType[componentType] = new Tuple(implementor, 1); +#else + implementorsByType[componentType] = implementor; +#endif + } + } +#if DEBUG && !PROFILER + else + Utility.Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat(entityView.ToString())); +#endif + } + + int count; + + //Very efficent way to collect the fields of every EntityViewType + KeyValuePair>[] setters = + FasterList>>.NoVirt.ToArrayFast(entityView.entityViewBlazingFastReflection, out count); + + var removeEntityComponentType = typeof(IRemoveEntityComponent); + + for (int i = 0; i < count; i++) + { + var keyValuePair = setters[i]; + Type fieldType = keyValuePair.Key; + + if (fieldType != removeEntityComponentType) + { +#if DEBUG && !PROFILER + Tuple component; +#else + object component; +#endif + + if (implementorsByType.TryGetValue(fieldType, out component) == false) + { + Exception e = new Exception(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name + " - EntityView: " + + entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); + + throw e; + } +#if DEBUG && !PROFILER + if (component.item2 > 1) + Utility.Console.LogError(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat( + "Component Type: ", fieldType.Name, " implementor: ", + component.item1.ToString()) + " - EntityView: " + + entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); +#endif +#if DEBUG && !PROFILER + keyValuePair.Value.Call(entityView, component.item1); +#else + keyValuePair.Value.Call(entityView, component); +#endif + } + else + { + keyValuePair.Value.Call(entityView, removeEntity); + } + } + + implementorsByType.Clear(); + } +#if DEBUG && !PROFILER + struct Tuple + { + public T1 item1; + public T2 item2; + + public Tuple(T1 implementor, T2 v) + { + item1 = implementor; + item2 = v; + } + } +#endif + static Dictionary _cachedTypes = new Dictionary(); + + const string DUPLICATE_IMPLEMENTOR_ERROR = + "Svelto.ECS the same component is implemented with more than one implementor. This is considered an error and MUST be fixed. "; + + const string NULL_IMPLEMENTOR_ERROR = + "Svelto.ECS Null implementor, please be careful about the implementors passed to avoid performance loss "; + + const string NOT_FOUND_EXCEPTION = "Svelto.ECS Implementor not found for an EntityView. "; + } +} + diff --git a/Svelto.ECS/ECS/EntitySubmissionScheduler.cs b/Svelto.ECS/ECS/EntitySubmissionScheduler.cs new file mode 100644 index 0000000..cfa8168 --- /dev/null +++ b/Svelto.ECS/ECS/EntitySubmissionScheduler.cs @@ -0,0 +1,9 @@ +using Svelto.WeakEvents; + +namespace Svelto.ECS.Schedulers +{ + public abstract class EntitySubmissionScheduler + { + abstract public void Schedule(WeakAction submitEntityViews); + } +} \ No newline at end of file diff --git a/Svelto.ECS/ECS/EntityView.cs b/Svelto.ECS/ECS/EntityView.cs new file mode 100644 index 0000000..b8e56fa --- /dev/null +++ b/Svelto.ECS/ECS/EntityView.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Svelto.DataStructures; +using Svelto.Utilities; + +namespace Svelto.ECS +{ + public interface IEntityView + { + int ID { get; } + } + + public interface IEntityStruct:IEntityView + { + new int ID { set; } + } + + public class EntityView : IEntityView + { + public int ID { get { return _ID; } } + + internal FasterList>> entityViewBlazingFastReflection; + internal int _ID; + } + + static class EntityView where T: EntityView, new() + { + internal static T BuildEntityView(int ID) + { + if (FieldCache.list.Count == 0) + { + var type = typeof(T); + + var fields = type.GetFields(BindingFlags.Public | + BindingFlags.Instance); + + for (int i = fields.Length - 1; i >= 0; --i) + { + var field = fields[i]; + + CastedAction setter = FastInvoke.MakeSetter(field); + + FieldCache.list.Add(new KeyValuePair>(field.FieldType, setter)); + } + } + + return new T { _ID = ID, entityViewBlazingFastReflection = FieldCache.list }; + } + + //check if I can remove W + static class FieldCache where W:T + { + internal static readonly FasterList>> list + = new FasterList>>(); + } + } +} + diff --git a/Svelto.ECS/ECS/EntityViewBuilder.cs b/Svelto.ECS/ECS/EntityViewBuilder.cs new file mode 100644 index 0000000..73606af --- /dev/null +++ b/Svelto.ECS/ECS/EntityViewBuilder.cs @@ -0,0 +1,99 @@ +using System; +using Svelto.ECS.Internal; + +namespace Svelto.ECS +{ + public interface IEntityViewBuilder + { + void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView); + ITypeSafeList Preallocate(ref ITypeSafeList list, int size); + + Type GetEntityViewType(); + void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList); + } + + public class EntityViewBuilder : IEntityViewBuilder where EntityViewType : EntityView, new() + { + public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) + { + if (list == null) + list = new TypeSafeFasterListForECSForClasses(); + + var castedList = list as TypeSafeFasterListForECSForClasses; + + var lentityView = EntityView.BuildEntityView(entityID); + + castedList.Add(lentityView); + + entityView = lentityView; + } + + public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) + { + if (list == null) + list = new TypeSafeFasterListForECSForClasses(size); + else + list.ReserveCapacity(size); + + return list; + } + + public Type GetEntityViewType() + { + return _entityViewType; + } + + public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) + { + var fromCastedList = fromSafeList as TypeSafeFasterListForECSForClasses; + var toCastedList = toSafeList as TypeSafeFasterListForECSForClasses; + + toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); + } + + readonly Type _entityViewType = typeof(EntityViewType); + } + + public class EntityStructBuilder : IEntityViewBuilder where EntityViewType : struct, IEntityStruct + { + public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) + { + var lentityView = default(EntityViewType); + lentityView.ID = entityID; + + if (list == null) + list = new TypeSafeFasterListForECSForStructs(); + + var castedList = list as TypeSafeFasterListForECSForStructs; + + castedList.Add(lentityView); + + entityView = null; + } + + public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) + { + if (list == null) + list = new TypeSafeFasterListForECSForStructs(size); + else + list.ReserveCapacity(size); + + return list; + } + + public Type GetEntityViewType() + { + return _entityViewType; + } + + public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) + { + var fromCastedList = fromSafeList as TypeSafeFasterListForECSForStructs; + var toCastedList = toSafeList as TypeSafeFasterListForECSForStructs; + + toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); + } + + readonly Type _entityViewType = typeof(EntityViewType); + } +} \ No newline at end of file diff --git a/Svelto.ECS/ECS/EntityViewsDB.cs b/Svelto.ECS/ECS/EntityViewsDB.cs new file mode 100644 index 0000000..b92c5ed --- /dev/null +++ b/Svelto.ECS/ECS/EntityViewsDB.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; + +namespace Svelto.ECS.Internal +{ + class EntityViewsDB : IEntityViewsDB + { + internal EntityViewsDB( Dictionary entityViewsDB, + Dictionary entityViewsDBdic, + Dictionary metaEntityViewsDB, + Dictionary> groupEntityViewsDB) + { + _entityViewsDB = entityViewsDB; + _entityViewsDBdic = entityViewsDBdic; + _metaEntityViewsDB = metaEntityViewsDB; + _groupEntityViewsDB = groupEntityViewsDB; + } + + public FasterReadOnlyList QueryEntityViews() where T:EntityView, new() + { + var type = typeof(T); + + ITypeSafeList entityViews; + + if (_entityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewList(); + + return new FasterReadOnlyList((FasterList)entityViews); + } + + public FasterReadOnlyList QueryGroupedEntityViews(int @group) where T:EntityView, new() + { + Dictionary entityViews; + + if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) + return RetrieveEmptyEntityViewList(); + + return new FasterReadOnlyList(entityViews as FasterList); + } + + public T[] QueryEntityViewsAsArray(out int count) where T : IEntityView + { + var type = typeof(T); + count = 0; + + ITypeSafeList entityViews; + + if (_entityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewArray(); + + var castedEntityViews = (FasterList)entityViews; + + return FasterList < T > .NoVirt.ToArrayFast(castedEntityViews, out count); + } + + public T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T : IEntityView + { + var type = typeof(T); + count = 0; + + Dictionary entityViews; + + if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) + return RetrieveEmptyEntityViewArray(); + + var castedEntityViews = (FasterList)entityViews[type]; + + count = castedEntityViews.Count; + + return FasterList.NoVirt.ToArrayFast(castedEntityViews, out count); + } + + public ReadOnlyDictionary QueryIndexableEntityViews() where T:IEntityView + { + var type = typeof(T); + + ITypeSafeDictionary entityViews; + + if (_entityViewsDBdic.TryGetValue(type, out entityViews) == false) + return TypeSafeDictionary.Default; + + return new ReadOnlyDictionary(entityViews as Dictionary); + } + + public bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView + { + var type = typeof(T); + + T internalEntityView; + + ITypeSafeDictionary entityViews; + TypeSafeDictionary casted; + + _entityViewsDBdic.TryGetValue(type, out entityViews); + casted = entityViews as TypeSafeDictionary; + + if (casted != null && + casted.TryGetValue(ID, out internalEntityView)) + { + entityView = internalEntityView; + + return true; + } + + entityView = default(T); + + return false; + } + + public T QueryEntityView(int ID) where T : IEntityView + { + var type = typeof(T); + + T internalEntityView; ITypeSafeDictionary entityViews; + TypeSafeDictionary casted; + + _entityViewsDBdic.TryGetValue(type, out entityViews); + casted = entityViews as TypeSafeDictionary; + + if (casted != null && + casted.TryGetValue(ID, out internalEntityView)) + return (T)internalEntityView; + + throw new Exception("EntityView Not Found"); + } + + public T QueryMetaEntityView(int metaEntityID) where T:EntityView, new() + { + return QueryEntityView(metaEntityID); + } + + public bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T:EntityView, new() + { + return TryQueryEntityView(metaEntityID, out entityView); + } + + public FasterReadOnlyList QueryMetaEntityViews() where T:EntityView, new() + { + var type = typeof(T); + + ITypeSafeList entityViews; + + if (_metaEntityViewsDB.TryGetValue(type, out entityViews) == false) + return RetrieveEmptyEntityViewList(); + + return new FasterReadOnlyList((FasterList)entityViews); + } + + static FasterReadOnlyList RetrieveEmptyEntityViewList() + { + return FasterReadOnlyList.DefaultList; + } + + static T[] RetrieveEmptyEntityViewArray() + { + return FasterList.DefaultList.ToArrayFast(); + } + + readonly Dictionary _entityViewsDB; + readonly Dictionary _entityViewsDBdic; + readonly Dictionary _metaEntityViewsDB; + readonly Dictionary> _groupEntityViewsDB; + } +} diff --git a/Svelto.ECS/ECS/Experimental/StructNodeCollections.cs b/Svelto.ECS/ECS/Experimental/StructNodeCollections.cs new file mode 100644 index 0000000..1b81938 --- /dev/null +++ b/Svelto.ECS/ECS/Experimental/StructNodeCollections.cs @@ -0,0 +1,180 @@ +#if EXPERIMENTAL +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Experimental.Internal; + +namespace Svelto.ECS.Experimental.Internal +{ + public interface IStructEntityViewEngine : IEngine + { + void CreateStructEntityViews(SharedStructEntityViewLists sharedStructEntityViewLists); + } + + public interface IGroupedStructEntityViewsEngine : IEngine + { + void CreateStructEntityViews(SharedGroupedStructEntityViewsLists sharedStructEntityViewLists); + } +} + +namespace Svelto.ECS.Experimental +{ + public interface IGroupedEntityView + { + int groupID { get; set; } + } + + /// + /// The engines can receive and store IEntityViews structs + /// Unboxing will happen during the Add, but the + /// data will then be stored and processed as stucts + /// + public interface IStructEntityViewEngine : IStructEntityViewEngine where T:struct, IEntityStruct + { } + + /// + /// same as above, but the entityViews are grouped by ID + /// usually the ID is the owner of the entityViews of that + /// group + /// + public interface IGroupedStructEntityViewsEngine : IGroupedStructEntityViewsEngine where T : struct, IGroupedEntityView + { + void Add(ref T entityView); + void Remove(ref T entityView); + } + + public sealed class StructEntityViews where T:struct, IEntityStruct + { + public T[] GetList(out int numberOfItems) + { + numberOfItems = _internalList.Count; + return _internalList.ToArrayFast(); + } + + public StructEntityViews(SharedStructEntityViewLists container) + { + _internalList = SharedStructEntityViewLists.NoVirt.GetList(container); + } + + public void Add(T entityView) + { + T convert = (T)entityView; + + _internalList.Add(convert); + } + + readonly FasterList _internalList; + } + + public struct StructGroupEntityViews + where T : struct, IEntityView + { + public StructGroupEntityViews(SharedGroupedStructEntityViewsLists container) + { + _container = container; + indices = new Dictionary(); + } + + public void Add(int groupID, T entityView) + { + T convert = (T)entityView; + + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + indices[entityView.ID] = fasterList.Count; + + fasterList.Add(convert); + } + + public void Remove(int groupID, T entityView) + { + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + var index = indices[entityView.ID]; + indices.Remove(entityView.ID); + + if (fasterList.UnorderedRemoveAt(index)) + indices[fasterList[index].ID] = index; + } + + public T[] GetList(int groupID, out int numberOfItems) + { + var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); + + return FasterList.NoVirt.ToArrayFast(fasterList, out numberOfItems); + } + + readonly SharedGroupedStructEntityViewsLists _container; + readonly Dictionary indices; + } + + public class SharedStructEntityViewLists + { + internal SharedStructEntityViewLists() + { + _collection = new Dictionary(); + } + + internal static class NoVirt + { + internal static FasterList GetList(SharedStructEntityViewLists obj) where T : struct + { + IFasterList list; + if (obj._collection.TryGetValue(typeof(T), out list)) + { + return list as FasterList; + } + + list = new FasterList(); + + obj._collection.Add(typeof(T), list); + + return (FasterList)list; + } + } + + readonly Dictionary _collection; + } + + public class SharedGroupedStructEntityViewsLists + { + internal SharedGroupedStructEntityViewsLists() + { + _collection = new Dictionary>(); + } + + internal static class NoVirt + { + internal static IFasterList GetList(SharedGroupedStructEntityViewsLists list, int groupID) where T : struct + { + Dictionary dic = GetGroup(list); + IFasterList localList; + + if (dic.TryGetValue(groupID, out localList)) + return localList; + + localList = new FasterList(); + dic.Add(groupID, localList); + + return localList; + } + + internal static Dictionary GetGroup(SharedGroupedStructEntityViewsLists list) where T : struct + { + Dictionary dic; + + if (list._collection.TryGetValue(typeof(T), out dic)) + { + return dic; + } + + dic = new Dictionary(); + + list._collection.Add(typeof(T), dic); + + return dic; + } + } + + readonly Dictionary> _collection; + } +} +#endif \ No newline at end of file diff --git a/Svelto.ECS/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs b/Svelto.ECS/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs new file mode 100644 index 0000000..fb672cb --- /dev/null +++ b/Svelto.ECS/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs @@ -0,0 +1,14 @@ +#if UNITY_5 || UNITY_5_3_OR_NEWER +namespace Svelto.ECS +{ + public class GenericEntityDescriptorHolder: + UnityEngine.MonoBehaviour , IEntityDescriptorHolder + where T: class, IEntityDescriptor, new() + { + public IEntityDescriptorInfo RetrieveDescriptor() + { + return EntityDescriptorTemplate.Default; + } + } +} +#endif \ No newline at end of file diff --git a/Svelto.ECS/ECS/Extensions/Unity/UnitySumbmissionEntityViewScheduler .cs b/Svelto.ECS/ECS/Extensions/Unity/UnitySumbmissionEntityViewScheduler .cs new file mode 100644 index 0000000..4eab8cd --- /dev/null +++ b/Svelto.ECS/ECS/Extensions/Unity/UnitySumbmissionEntityViewScheduler .cs @@ -0,0 +1,53 @@ +#if UNITY_5 || UNITY_5_3_OR_NEWER +using System.Collections; +using Svelto.WeakEvents; +using UnityEngine; + +namespace Svelto.ECS.Schedulers.Unity +{ + //The EntityViewSubmissionScheduler has been introduced to make + //the entityView submission logic platform indipendent. + //Please don't be tempted to create your own submission to + //adapt to your game level code design. For example, + //you may be tempted to write a submission logic to submit + //the entityViews immediatly just because convenient for your game + //logic. This is not how it works. + + public class UnitySumbmissionEntityViewScheduler : EntitySubmissionScheduler + { + public UnitySumbmissionEntityViewScheduler() + { + GameObject go = new GameObject("ECSScheduler"); + + _scheduler = go.AddComponent(); + } + + public override void Schedule(WeakAction submitEntityViews) + { + _scheduler.OnTick = submitEntityViews; + } + + class Scheduler : MonoBehaviour + { + IEnumerator Start() + { + while (true) + { + yield return _wait; + + if (OnTick.IsValid) + OnTick.Invoke(); + else + yield break; + } + } + + internal WeakAction OnTick; + + WaitForEndOfFrame _wait = new WaitForEndOfFrame(); + } + + Scheduler _scheduler; + } +} +#endif \ No newline at end of file diff --git a/Svelto.ECS/ECS/GenericEntityDescriptor.cs b/Svelto.ECS/ECS/GenericEntityDescriptor.cs new file mode 100644 index 0000000..a717870 --- /dev/null +++ b/Svelto.ECS/ECS/GenericEntityDescriptor.cs @@ -0,0 +1,110 @@ +using System.Runtime.InteropServices; + +namespace Svelto.ECS +{ + public class GenericEntityDescriptor:IEntityDescriptor where T : EntityView, new() + { + static GenericEntityDescriptor() + { + entityViewBuilders = new IEntityViewBuilder[] { new EntityViewBuilder() }; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return entityViewBuilders; } + } + + public static readonly IEntityViewBuilder[] entityViewBuilders; + + } + + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + { + static GenericEntityDescriptor() + { + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return entityViewBuilders; } + } + + public static readonly IEntityViewBuilder[] entityViewBuilders; + } + + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + { + static GenericEntityDescriptor() + { + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return entityViewBuilders; } + } + + public static readonly IEntityViewBuilder[] entityViewBuilders; + } + + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() + { + static GenericEntityDescriptor() + { + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return entityViewBuilders; } + } + + public static readonly IEntityViewBuilder[] entityViewBuilders; + } + + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() + where X : EntityView, new() + { + static GenericEntityDescriptor() + { + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return entityViewBuilders; } + } + + public static readonly IEntityViewBuilder[] entityViewBuilders; + } + + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() + where X : EntityView, new() + where Y : EntityView, new() + { + static GenericEntityDescriptor() + { + entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder(), new EntityViewBuilder()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return entityViewBuilders; } + } + + public static readonly IEntityViewBuilder[] entityViewBuilders; + } +} diff --git a/Svelto.ECS/ECS/IEngine.cs b/Svelto.ECS/ECS/IEngine.cs new file mode 100644 index 0000000..98597d5 --- /dev/null +++ b/Svelto.ECS/ECS/IEngine.cs @@ -0,0 +1,21 @@ +namespace Svelto.ECS.Internal +{ + public interface IHandleEntityViewEngine : IEngine + { + void Add(IEntityView entityView); + void Remove(IEntityView entityView); + } +} + +namespace Svelto.ECS +{ + public interface IEngine + {} + + public interface IQueryingEntityViewEngine : IEngine + { + IEntityViewsDB entityViewsDB { set; } + + void Ready(); + } +} diff --git a/Svelto.ECS/ECS/IEngineEntityViewDB.cs b/Svelto.ECS/ECS/IEngineEntityViewDB.cs new file mode 100644 index 0000000..571f3f8 --- /dev/null +++ b/Svelto.ECS/ECS/IEngineEntityViewDB.cs @@ -0,0 +1,22 @@ +using Svelto.DataStructures; + +namespace Svelto.ECS +{ + public interface IEngineEntityViewDB + { + FasterReadOnlyList QueryEntityViews() where T:EntityView, new(); + FasterReadOnlyList QueryMetaEntityViews() where T: EntityView, new(); + FasterReadOnlyList QueryGroupedEntityViews(int group) where T: EntityView, new(); + + T[] QueryEntityViewsAsArray(out int count) where T: IEntityView; + T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T: IEntityView; + + ReadOnlyDictionary QueryIndexableEntityViews() where T: IEntityView; + bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView; + T QueryEntityView(int ID) where T: IEntityView; + + bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T: EntityView, new(); + T QueryMetaEntityView(int metaEntityID) where T: EntityView, new(); + } +} + diff --git a/Svelto.ECS/ECS/IEnginesInterfaces.cs b/Svelto.ECS/ECS/IEnginesInterfaces.cs new file mode 100644 index 0000000..36f9aab --- /dev/null +++ b/Svelto.ECS/ECS/IEnginesInterfaces.cs @@ -0,0 +1,29 @@ +namespace Svelto.ECS +{ + public interface IEntityFactory + { + void Preallocate(int size) where T : IEntityDescriptor, new(); + + void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new(); + void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptorInfo, object[] implementors); + + void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T:IEntityDescriptor, new(); + + void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new(); + void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, object[] implementors); + } + + public interface IEntityFunctions + { + void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo); + void RemoveEntity(int entityID) where T:IEntityDescriptor, new(); + + void RemoveMetaEntity(int metaEntityID) where T:IEntityDescriptor, new(); + + void RemoveEntityFromGroup(int entityID, int groupID) where T:IEntityDescriptor, new(); + + void RemoveGroupedEntities(int groupID); + + void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new(); + } +} diff --git a/Svelto.ECS/ECS/IEntityDescriptorHolder.cs b/Svelto.ECS/ECS/IEntityDescriptorHolder.cs new file mode 100644 index 0000000..c144811 --- /dev/null +++ b/Svelto.ECS/ECS/IEntityDescriptorHolder.cs @@ -0,0 +1,7 @@ +namespace Svelto.ECS +{ + public interface IEntityDescriptorHolder + { + IEntityDescriptorInfo RetrieveDescriptor(); + } +} diff --git a/Svelto.ECS/ECS/IEntityViewsDB.cs b/Svelto.ECS/ECS/IEntityViewsDB.cs new file mode 100644 index 0000000..a6eb0c6 --- /dev/null +++ b/Svelto.ECS/ECS/IEntityViewsDB.cs @@ -0,0 +1,22 @@ +using Svelto.DataStructures; + +namespace Svelto.ECS +{ + public interface IEntityViewsDB + { + FasterReadOnlyList QueryEntityViews() where T:EntityView, new(); + FasterReadOnlyList QueryMetaEntityViews() where T: EntityView, new(); + FasterReadOnlyList QueryGroupedEntityViews(int group) where T: EntityView, new(); + + T[] QueryEntityViewsAsArray(out int count) where T: IEntityView; + T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T: IEntityView; + + ReadOnlyDictionary QueryIndexableEntityViews() where T: IEntityView; + bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView; + T QueryEntityView(int ID) where T: IEntityView; + + bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T: EntityView, new(); + T QueryMetaEntityView(int metaEntityID) where T: EntityView, new(); + } +} + diff --git a/Svelto.ECS/ECS/MixedEntityDescriptor.cs b/Svelto.ECS/ECS/MixedEntityDescriptor.cs new file mode 100644 index 0000000..f91ad54 --- /dev/null +++ b/Svelto.ECS/ECS/MixedEntityDescriptor.cs @@ -0,0 +1,107 @@ +namespace Svelto.ECS +{ + public class MixedEntityDescriptor:IEntityDescriptor where T : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + where X : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } + + public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() + where U : class, IEntityViewBuilder, new() + where V : class, IEntityViewBuilder, new() + where W : class, IEntityViewBuilder, new() + where X : class, IEntityViewBuilder, new() + where Y : class, IEntityViewBuilder, new() + { + static MixedEntityDescriptor() + { + _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X(), new Y()}; + } + + public IEntityViewBuilder[] entityViewsToBuild + { + get { return _entityViewsToBuild; } + } + + static readonly IEntityViewBuilder[] _entityViewsToBuild; + } +} diff --git a/Svelto.ECS/ECS/MultiEntityViewsEngine.cs b/Svelto.ECS/ECS/MultiEntityViewsEngine.cs new file mode 100644 index 0000000..324bc36 --- /dev/null +++ b/Svelto.ECS/ECS/MultiEntityViewsEngine.cs @@ -0,0 +1,118 @@ +using Svelto.ECS.Internal; + +namespace Svelto.ECS.Internal +{ + public abstract class MultiEntityViewsEngine:IHandleEntityViewEngine where T:EntityView, new() + { + protected abstract void Add(T entityView); + protected abstract void Remove(T entityView); + + public virtual void Add(IEntityView entityView) + { + Add((T) entityView); + } + + public virtual void Remove(IEntityView entityView) + { + Remove((T) entityView); + } + } +} + +namespace Svelto.ECS +{ + public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine + where U:EntityView, new() where T : EntityView, new() + { + protected abstract void Add(U entityView); + protected abstract void Remove(U entityView); + + public override void Add(IEntityView entityView) + { + var castedEntityView = entityView as U; + if (castedEntityView != null) + { + Add(castedEntityView); + } + else + { + base.Add(entityView); + } + } + + public override void Remove(IEntityView entityView) + { + if (entityView is U) + { + Remove((U) entityView); + } + else + { + base.Remove(entityView); + } + } + } + + public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine + where V : EntityView, new() where U : EntityView, new() where T : EntityView, new() + { + protected abstract void Add(V entityView); + protected abstract void Remove(V entityView); + + public override void Add(IEntityView entityView) + { + var castedEntityView = entityView as V; + if (castedEntityView != null) + { + Add(castedEntityView); + } + else + base.Add(entityView); + } + + public override void Remove(IEntityView entityView) + { + var castedEntityView = entityView as V; + if (castedEntityView != null) + { + Remove(castedEntityView); + } + else + base.Remove(entityView); + } + } + + /// + /// Please do not add more MultiEntityViewsEngine + /// if you use more than 4 nodes, your engine has + /// already too many responsabilities. + /// + public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine + where W : EntityView, new() where V : EntityView, new() where U : EntityView, new() where T : EntityView, new() + { + protected abstract void Add(W entityView); + protected abstract void Remove(W entityView); + + public override void Add(IEntityView entityView) + { + var castedEntityView = entityView as W; + if (castedEntityView != null) + { + Add(castedEntityView); + } + else + base.Add(entityView); + } + + public override void Remove(IEntityView entityView) + { + var castedEntityView = entityView as W; + if (castedEntityView != null) + { + Remove(castedEntityView); + } + else + base.Remove(entityView); + } + } +} \ No newline at end of file diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs b/Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs similarity index 99% rename from ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs rename to Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs index b1fb2da..0947e8a 100644 --- a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs +++ b/Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs @@ -1,6 +1,6 @@ #if UNITY_EDITOR + using System; -using System.Collections.Generic; using UnityEditor; using UnityEngine; diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs b/Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs similarity index 100% rename from ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs rename to Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs diff --git a/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs b/Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs similarity index 100% rename from ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs rename to Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs diff --git a/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs b/Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs similarity index 100% rename from ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs rename to Svelto.ECS/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs diff --git a/ECS/Profiler/EngineInfo.cs b/Svelto.ECS/ECS/Profiler/EngineInfo.cs similarity index 91% rename from ECS/Profiler/EngineInfo.cs rename to Svelto.ECS/ECS/Profiler/EngineInfo.cs index ceffef9..c8fd453 100644 --- a/ECS/Profiler/EngineInfo.cs +++ b/Svelto.ECS/ECS/Profiler/EngineInfo.cs @@ -33,12 +33,12 @@ namespace Svelto.ECS.Profiler double _accumulatedAddDuration; double _minAddDuration; double _maxAddDuration; - int _nodesAddedCount; + int _entityViewsAddedCount; double _accumulatedRemoveDuration; double _minRemoveDuration; double _maxRemoveDuration; - int _nodesRemovedCount; + int _entityViewsRemovedCount; public IEngine engine { get { return _engine; } } public string engineName { get { return _engineName; } } @@ -56,8 +56,8 @@ namespace Svelto.ECS.Profiler public double maxRemoveDuration { get { return _maxRemoveDuration; } } public double maxUpdateDuration { get { return _maxUpdateDuration[(int)UpdateType.Update]; } } - public double averageAddDuration { get { return _nodesAddedCount == 0 ? 0 : _accumulatedAddDuration / _nodesAddedCount; } } - public double averageRemoveDuration { get { return _nodesRemovedCount == 0 ? 0 : _accumulatedRemoveDuration / _nodesRemovedCount; } } + public double averageAddDuration { get { return _entityViewsAddedCount == 0 ? 0 : _accumulatedAddDuration / _entityViewsAddedCount; } } + public double averageRemoveDuration { get { return _entityViewsRemovedCount == 0 ? 0 : _accumulatedRemoveDuration / _entityViewsRemovedCount; } } public double averageUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.Update].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.Update] / _updateFrameTimes[(int)UpdateType.Update].Count; } } public double averageLateUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.LateUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.LateUpdate] / _updateFrameTimes[(int)UpdateType.LateUpdate].Count; } } public double averageFixedUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.FixedUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.FixedUpdate] / _updateFrameTimes[(int)UpdateType.FixedUpdate].Count; } } @@ -126,7 +126,7 @@ namespace Svelto.ECS.Profiler _maxAddDuration = duration; } _accumulatedAddDuration += duration; - _nodesAddedCount += 1; + _entityViewsAddedCount += 1; } public void AddRemoveDuration(double duration) @@ -140,7 +140,7 @@ namespace Svelto.ECS.Profiler _maxRemoveDuration = duration; } _accumulatedRemoveDuration += duration; - _nodesRemovedCount += 1; + _entityViewsRemovedCount += 1; } public void ResetDurations() @@ -156,12 +156,12 @@ namespace Svelto.ECS.Profiler _accumulatedAddDuration = 0; _minAddDuration = 0; _maxAddDuration = 0; - _nodesAddedCount = 0; + _entityViewsAddedCount = 0; _accumulatedRemoveDuration = 0; _minRemoveDuration = 0; _maxRemoveDuration = 0; - _nodesRemovedCount = 0; + _entityViewsRemovedCount = 0; } } } diff --git a/ECS/Profiler/EngineProfiler.cs b/Svelto.ECS/ECS/Profiler/EngineProfiler.cs similarity index 82% rename from ECS/Profiler/EngineProfiler.cs rename to Svelto.ECS/ECS/Profiler/EngineProfiler.cs index 2b07067..3e10786 100644 --- a/ECS/Profiler/EngineProfiler.cs +++ b/Svelto.ECS/ECS/Profiler/EngineProfiler.cs @@ -12,30 +12,28 @@ namespace Svelto.ECS.Profiler { static readonly Stopwatch _stopwatch = new Stopwatch(); - public static void MonitorAddDuration(INodeEngine engine, INode node) + public static void MonitorAddDuration(IHandleEntityViewEngine engine, IEntityView entityView) { EngineInfo info; if (engineInfos.TryGetValue(engine.GetType(), out info)) { - _stopwatch.Reset(); _stopwatch.Start(); - engine.Add(node); - _stopwatch.Stop(); + engine.Add(entityView); + _stopwatch.Reset(); info.AddAddDuration(_stopwatch.Elapsed.TotalMilliseconds); } } - public static void MonitorRemoveDuration(INodeEngine engine, INode node) + public static void MonitorRemoveDuration(IHandleEntityViewEngine engine, IEntityView entityView) { EngineInfo info; if (engineInfos.TryGetValue(engine.GetType(), out info)) { - _stopwatch.Reset(); _stopwatch.Start(); - engine.Remove(node); - _stopwatch.Stop(); - + engine.Remove(entityView); + _stopwatch.Reset(); + info.AddRemoveDuration(_stopwatch.Elapsed.TotalMilliseconds); } } diff --git a/ECS/Profiler/EngineProfilerBehaviour.cs b/Svelto.ECS/ECS/Profiler/EngineProfilerBehaviour.cs similarity index 100% rename from ECS/Profiler/EngineProfilerBehaviour.cs rename to Svelto.ECS/ECS/Profiler/EngineProfilerBehaviour.cs diff --git a/Svelto.ECS/ECS/RemoveEntityImplementor.cs b/Svelto.ECS/ECS/RemoveEntityImplementor.cs new file mode 100644 index 0000000..0ad6a93 --- /dev/null +++ b/Svelto.ECS/ECS/RemoveEntityImplementor.cs @@ -0,0 +1,36 @@ +namespace Svelto.ECS.Internal +{ + sealed class RemoveEntityImplementor : IRemoveEntityComponent + { + public RemoveEntityImplementor(IEntityViewBuilder[] entityViews, int groupID):this(entityViews) + { + this.groupID = groupID; + isInAGroup = true; + } + + internal RemoveEntityImplementor(IEntityViewBuilder[] entityViews) + { + removeEntityInfo = new RemoveEntityInfo(entityViews); + } + + internal readonly RemoveEntityInfo removeEntityInfo; + internal readonly int groupID; + internal readonly bool isInAGroup; + } +} + +namespace Svelto.ECS +{ + public interface IRemoveEntityComponent + {} + + public struct RemoveEntityInfo + { + internal readonly IEntityViewBuilder[] entityViewsToBuild; + + public RemoveEntityInfo(IEntityViewBuilder[] entityViews) : this() + { + this.entityViewsToBuild = entityViews; + } + } +} diff --git a/ECS/Sequencer.cs b/Svelto.ECS/ECS/Sequencer.cs similarity index 100% rename from ECS/Sequencer.cs rename to Svelto.ECS/ECS/Sequencer.cs diff --git a/Svelto.ECS/ECS/SingleEntityViewEngine.cs b/Svelto.ECS/ECS/SingleEntityViewEngine.cs new file mode 100644 index 0000000..605f775 --- /dev/null +++ b/Svelto.ECS/ECS/SingleEntityViewEngine.cs @@ -0,0 +1,20 @@ +using Svelto.ECS.Internal; + +namespace Svelto.ECS +{ + public abstract class SingleEntityViewEngine : IHandleEntityViewEngine where T:EntityView, new() + { + public void Add(IEntityView entityView) + { + Add((T)entityView); //when byref returns will be vailable, this should be passed by reference, not copy! + } + + public void Remove(IEntityView entityView) + { + Remove((T)entityView); + } + + protected abstract void Add(T entityView); + protected abstract void Remove(T entityView); + } +} diff --git a/Factories/IGameObjectFactory.cs b/Svelto.ECS/Factories/IGameObjectFactory.cs similarity index 87% rename from Factories/IGameObjectFactory.cs rename to Svelto.ECS/Factories/IGameObjectFactory.cs index 7879bf3..03f35ce 100644 --- a/Factories/IGameObjectFactory.cs +++ b/Svelto.ECS/Factories/IGameObjectFactory.cs @@ -1,3 +1,4 @@ +#if UNITY_5_3_OR_NEWER || UNITY_5 using UnityEngine; namespace Svelto.Factories @@ -10,3 +11,4 @@ namespace Svelto.Factories GameObject Build(GameObject prefab); } } +#endif \ No newline at end of file diff --git a/Factories/IMonoBehaviourFactory.cs b/Svelto.ECS/Factories/IMonoBehaviourFactory.cs similarity index 80% rename from Factories/IMonoBehaviourFactory.cs rename to Svelto.ECS/Factories/IMonoBehaviourFactory.cs index cbf5e05..f32a349 100644 --- a/Factories/IMonoBehaviourFactory.cs +++ b/Svelto.ECS/Factories/IMonoBehaviourFactory.cs @@ -1,3 +1,5 @@ +#if UNITY_5_3_OR_NEWER || UNITY_5 + using System; using UnityEngine; @@ -9,3 +11,4 @@ namespace Svelto.Factories } } +#endif \ No newline at end of file diff --git a/LICENSE b/Svelto.ECS/LICENSE similarity index 100% rename from LICENSE rename to Svelto.ECS/LICENSE diff --git a/README.md b/Svelto.ECS/README.md similarity index 100% rename from README.md rename to Svelto.ECS/README.md diff --git a/Utilities/Console.cs b/Utilities/Console.cs deleted file mode 100644 index cf11720..0000000 --- a/Utilities/Console.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -#if NETFX_CORE -using Windows.System.Diagnostics; -#else -using System.Diagnostics; -#endif -using System.Text; - -namespace Utility -{ - public static class Console - { - static StringBuilder _stringBuilder = new StringBuilder(256); -#if UNITY_5_3_OR_NEWER || UNITY_5 - public static ILogger logger = new SlowLoggerUnity(); -#else - public static ILogger logger = new SimpleLogger(); -#endif - public static volatile bool BatchLog = false; - - //Hack, have to find the right solution - public static Action onException; - - static Console() - { - onException = (e, obj, message, stack) => - { - UnityEngine.Debug.LogException(e, (UnityEngine.Object)obj); - }; - } - - public static void Log(string txt) - { - logger.Log(txt); - } - - public static void LogError(string txt) - { - string toPrint; - - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - _stringBuilder.Append("-!!!!!!-> "); - _stringBuilder.Append(txt); - - toPrint = _stringBuilder.ToString(); - } - - logger.Log(toPrint, null, LogType.Error); - } - - public static void LogError(string txt, string stack) - { - string toPrint; - - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - _stringBuilder.Append("-!!!!!!-> "); - _stringBuilder.Append(txt); - - toPrint = _stringBuilder.ToString(); - } - - logger.Log(toPrint, stack, LogType.Error); - } - - public static void LogException(Exception e) - { - LogException(e, null); - } - - public static void LogException(Exception e, UnityEngine.Object obj) - { - string toPrint; - string stackTrace; - - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - _stringBuilder.Append("-!!!!!!-> ").Append(e.Message); - - stackTrace = e.StackTrace; - - if (e.InnerException != null) - { - e = e.InnerException; - - _stringBuilder.Append(" Inner Message: ").Append(e.Message).Append(" Inner Stacktrace:") - .Append(e.StackTrace); - - stackTrace = e.StackTrace; - } - - toPrint = _stringBuilder.ToString(); - } - - onException(e, obj, toPrint, stackTrace); - } - - public static void LogWarning(string txt) - { - string toPrint; - - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - _stringBuilder.Append("------> "); - _stringBuilder.Append(txt); - - toPrint = _stringBuilder.ToString(); - } - - logger.Log(toPrint, null, LogType.Warning); - } - - /// - /// Use this function if you don't want the message to be batched - /// - /// - public static void SystemLog(string txt) - { - string toPrint; - - lock (_stringBuilder) - { -#if NETFX_CORE - string currentTimeString = DateTime.UtcNow.ToString("dd/mm/yy hh:ii:ss"); - string processTimeString = (DateTime.UtcNow - ProcessDiagnosticInfo.GetForCurrentProcess().ProcessStartTime.DateTime).ToString(); -#else - string currentTimeString = DateTime.UtcNow.ToLongTimeString(); //ensure includes seconds - string processTimeString = (DateTime.Now - Process.GetCurrentProcess().StartTime).ToString(); -#endif - - _stringBuilder.Length = 0; - _stringBuilder.Append("[").Append(currentTimeString); - _stringBuilder.Append("][").Append(processTimeString); - _stringBuilder.Length = _stringBuilder.Length - 3; //remove some precision that we don't need - _stringBuilder.Append("] ").AppendLine(txt); - - toPrint = _stringBuilder.ToString(); - } - -#if !UNITY_EDITOR && !NETFX_CORE - System.Console.WriteLine(toPrint); -#else - UnityEngine.Debug.Log(toPrint); -#endif - } - } -} \ No newline at end of file diff --git a/Utilities/DesignByContract.cs b/Utilities/DesignByContract.cs deleted file mode 100644 index b6a22d7..0000000 --- a/Utilities/DesignByContract.cs +++ /dev/null @@ -1,459 +0,0 @@ -// from: http://www.codeproject.com/Articles/1863/Design-by-Contract-Framework -// Provides support for Design By Contract -// as described by Bertrand Meyer in his seminal book, -// Object-Oriented Software Construction (2nd Ed) Prentice Hall 1997 -// (See chapters 11 and 12). -// -// See also Building Bug-free O-O Software: An Introduction to Design by Contract -// http://www.eiffel.com/doc/manuals/technology/contract/ -// -// The following conditional compilation symbols are supported: -// -// These suggestions are based on Bertrand Meyer's Object-Oriented Software Construction (2nd Ed) p393 -// -// DBC_CHECK_ALL - Check assertions - implies checking preconditions, postconditions and invariants -// DBC_CHECK_INVARIANT - Check invariants - implies checking preconditions and postconditions -// DBC_CHECK_POSTCONDITION - Check postconditions - implies checking preconditions -// DBC_CHECK_PRECONDITION - Check preconditions only, e.g., in Release build -// -// A suggested default usage scenario is the following: -// -// #if DEBUG -// #define DBC_CHECK_ALL -// #else -// #define DBC_CHECK_PRECONDITION -// #endif -// -// Alternatively, you can define these in the project properties dialog. - -#if DEBUG && !PROFILER -#define DBC_CHECK_ALL -#endif - -using System; -using System.Diagnostics; - -namespace DesignByContract -{ - /// - /// Design By Contract Checks. - /// - /// Each method generates an exception or - /// a trace assertion statement if the contract is broken. - /// - /// - /// This example shows how to call the Require method. - /// Assume DBC_CHECK_PRECONDITION is defined. - /// - /// public void Test(int x) - /// { - /// try - /// { - /// Check.Require(x > 1, "x must be > 1"); - /// } - /// catch (System.Exception ex) - /// { - /// Console.WriteLine(ex.ToString()); - /// } - /// } - /// - /// If you wish to use trace assertion statements, intended for Debug scenarios, - /// rather than exception handling then set - /// - /// Check.UseAssertions = true - /// - /// You can specify this in your application entry point and maybe make it - /// dependent on conditional compilation flags or configuration file settings, e.g., - /// - /// #if DBC_USE_ASSERTIONS - /// Check.UseAssertions = true; - /// #endif - /// - /// You can direct output to a Trace listener. For example, you could insert - /// - /// Trace.Listeners.Clear(); - /// Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); - /// - /// - /// or direct output to a file or the Event Log. - /// - /// (Note: For ASP.NET clients use the Listeners collection - /// of the Debug, not the Trace, object and, for a Release build, only exception-handling - /// is possible.) - /// - /// - public sealed class Check - { - #region Interface - - /// - /// Precondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION"), - Conditional("DBC_CHECK_PRECONDITION")] - public static void Require(bool assertion, string message) - { - if (UseExceptions) - { - if (!assertion) - throw new PreconditionException(message); - } - else - { - Trace.Assert(assertion, "Precondition: " + message); - } - } - - /// - /// Precondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION"), - Conditional("DBC_CHECK_PRECONDITION")] - public static void Require(bool assertion, string message, Exception inner) - { - if (UseExceptions) - { - if (!assertion) - throw new PreconditionException(message, inner); - } - else - { - Trace.Assert(assertion, "Precondition: " + message); - } - } - - /// - /// Precondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION"), - Conditional("DBC_CHECK_PRECONDITION")] - public static void Require(bool assertion) - { - if (UseExceptions) - { - if (!assertion) - throw new PreconditionException("Precondition failed."); - } - else - { - Trace.Assert(assertion, "Precondition failed."); - } - } - - /// - /// Postcondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION")] - public static void Ensure(bool assertion, string message) - { - if (UseExceptions) - { - if (!assertion) - throw new PostconditionException(message); - } - else - { - Trace.Assert(assertion, "Postcondition: " + message); - } - } - - /// - /// Postcondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION")] - public static void Ensure(bool assertion, string message, Exception inner) - { - if (UseExceptions) - { - if (!assertion) - throw new PostconditionException(message, inner); - } - else - { - Trace.Assert(assertion, "Postcondition: " + message); - } - } - - /// - /// Postcondition check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT"), - Conditional("DBC_CHECK_POSTCONDITION")] - public static void Ensure(bool assertion) - { - if (UseExceptions) - { - if (!assertion) - throw new PostconditionException("Postcondition failed."); - } - else - { - Trace.Assert(assertion, "Postcondition failed."); - } - } - - /// - /// Invariant check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT")] - public static void Invariant(bool assertion, string message) - { - if (UseExceptions) - { - if (!assertion) - throw new InvariantException(message); - } - else - { - Trace.Assert(assertion, "Invariant: " + message); - } - } - - /// - /// Invariant check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT")] - public static void Invariant(bool assertion, string message, Exception inner) - { - if (UseExceptions) - { - if (!assertion) - throw new InvariantException(message, inner); - } - else - { - Trace.Assert(assertion, "Invariant: " + message); - } - } - - /// - /// Invariant check. - /// - [Conditional("DBC_CHECK_ALL"), - Conditional("DBC_CHECK_INVARIANT")] - public static void Invariant(bool assertion) - { - if (UseExceptions) - { - if (!assertion) - throw new InvariantException("Invariant failed."); - } - else - { - Trace.Assert(assertion, "Invariant failed."); - } - } - - /// - /// Assertion check. - /// - [Conditional("DBC_CHECK_ALL")] - public static void Assert(bool assertion, string message) - { - if (UseExceptions) - { - if (!assertion) - throw new AssertionException(message); - } - else - { - Trace.Assert(assertion, "Assertion: " + message); - } - } - - /// - /// Assertion check. - /// - [Conditional("DBC_CHECK_ALL")] - public static void Assert(bool assertion, string message, Exception inner) - { - if (UseExceptions) - { - if (!assertion) - throw new AssertionException(message, inner); - } - else - { - Trace.Assert(assertion, "Assertion: " + message); - } - } - - /// - /// Assertion check. - /// - [Conditional("DBC_CHECK_ALL")] - public static void Assert(bool assertion) - { - if (UseExceptions) - { - if (!assertion) - throw new AssertionException("Assertion failed."); - } - else - { - Trace.Assert(assertion, "Assertion failed."); - } - } - - /// - /// Set this if you wish to use Trace Assert statements - /// instead of exception handling. - /// (The Check class uses exception handling by default.) - /// - public static bool UseAssertions - { - get - { - return useAssertions; - } - set - { - useAssertions = value; - } - } - - #endregion // Interface - - #region Implementation - - // No creation - private Check() {} - - /// - /// Is exception handling being used? - /// - private static bool UseExceptions - { - get - { - return !useAssertions; - } - } - - // Are trace assertion statements being used? - // Default is to use exception handling. - private static bool useAssertions = false; - - #endregion // Implementation - - } // End Check - - internal class Trace - { - internal static void Assert(bool assertion, string v) - { -#if NETFX_CORE - System.Diagnostics.Contracts.Contract.Assert(assertion, v); -#else - System.Diagnostics.Trace.Assert(assertion, v); -#endif - } - } - - #region Exceptions - - /// - /// Exception raised when a contract is broken. - /// Catch this exception type if you wish to differentiate between - /// any DesignByContract exception and other runtime exceptions. - /// - /// - public class DesignByContractException : Exception - { - protected DesignByContractException() {} - protected DesignByContractException(string message) : base(message) {} - protected DesignByContractException(string message, Exception inner) : base(message, inner) {} - } - - /// - /// Exception raised when a precondition fails. - /// - public class PreconditionException : DesignByContractException - { - /// - /// Precondition Exception. - /// - public PreconditionException() {} - /// - /// Precondition Exception. - /// - public PreconditionException(string message) : base(message) {} - /// - /// Precondition Exception. - /// - public PreconditionException(string message, Exception inner) : base(message, inner) {} - } - - /// - /// Exception raised when a postcondition fails. - /// - public class PostconditionException : DesignByContractException - { - /// - /// Postcondition Exception. - /// - public PostconditionException() {} - /// - /// Postcondition Exception. - /// - public PostconditionException(string message) : base(message) {} - /// - /// Postcondition Exception. - /// - public PostconditionException(string message, Exception inner) : base(message, inner) {} - } - - /// - /// Exception raised when an invariant fails. - /// - public class InvariantException : DesignByContractException - { - /// - /// Invariant Exception. - /// - public InvariantException() {} - /// - /// Invariant Exception. - /// - public InvariantException(string message) : base(message) {} - /// - /// Invariant Exception. - /// - public InvariantException(string message, Exception inner) : base(message, inner) {} - } - - /// - /// Exception raised when an assertion fails. - /// - public class AssertionException : DesignByContractException - { - /// - /// Assertion Exception. - /// - public AssertionException() {} - /// - /// Assertion Exception. - /// - public AssertionException(string message) : base(message) {} - /// - /// Assertion Exception. - /// - public AssertionException(string message, Exception inner) : base(message, inner) {} - } - - #endregion // Exception classes - -} // End Design By Contract diff --git a/Utilities/FastConcatUtility.cs b/Utilities/FastConcatUtility.cs deleted file mode 100644 index db83efa..0000000 --- a/Utilities/FastConcatUtility.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System.Text; - -public static class FastConcatUtility -{ - static readonly StringBuilder _stringBuilder = new StringBuilder(256); - - public static string FastConcat(this string str1, T str2) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - - return _stringBuilder.ToString(); - } - } - - public static string FastConcat(this string str1, string str2, string str3) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - _stringBuilder.Append(str3); - - return _stringBuilder.ToString(); - } - } - - public static string FastConcat(this string str1, string str2, string str3, string str4) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - _stringBuilder.Append(str3); - _stringBuilder.Append(str4); - - - return _stringBuilder.ToString(); - } - } - - public static string FastConcat(this string str1, string str2, string str3, string str4, string str5) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - _stringBuilder.Append(str1); - _stringBuilder.Append(str2); - _stringBuilder.Append(str3); - _stringBuilder.Append(str4); - _stringBuilder.Append(str5); - - return _stringBuilder.ToString(); - } - } - - public static string FastJoin(this string[] str) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - for (int i = 0; i < str.Length; i++) - _stringBuilder.Append(str[i]); - - return _stringBuilder.ToString(); - } - } - - public static string FastJoin(this string[] str, string str1) - { - lock (_stringBuilder) - { - _stringBuilder.Length = 0; - - for (int i = 0; i < str.Length; i++) - _stringBuilder.Append(str[i]); - - _stringBuilder.Append(str1); - - return _stringBuilder.ToString(); - } - } -} - -namespace Utility -{ -#if UNITY_5 || UNITY_5_3_OR_NEWER -#endif -} diff --git a/Utilities/ILogger.cs b/Utilities/ILogger.cs deleted file mode 100644 index 20eaa23..0000000 --- a/Utilities/ILogger.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Utility -{ - public enum LogType - { - Log, - Exception, - Warning, - Error - } - public interface ILogger - { - void Log (string txt, string stack = null, LogType type = LogType.Log); - } -} \ No newline at end of file diff --git a/Utilities/Murmur3.cs b/Utilities/Murmur3.cs deleted file mode 100644 index 6e83e68..0000000 --- a/Utilities/Murmur3.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.IO; - -/// -/// Murmur hash. -/// -/// Creates an evenly destributed uint hash from a string. -/// Very fast and fairly unique -/// - -public class Murmur3 -{ - static public uint MurmurHash3_x86_32(byte[] data, uint length, uint seed) - { - uint nblocks = length >> 2; - - uint h1 = seed; - - const uint c1 = 0xcc9e2d51; - const uint c2 = 0x1b873593; - - //---------- - // body - - int i = 0 ; - - for (uint j = nblocks; j > 0 ; --j) - { - uint k1l = BitConverter.ToUInt32(data, i); - - k1l *= c1; - k1l = rotl32(k1l, 15); - k1l *= c2; - - h1 ^= k1l; - h1 = rotl32(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - - i+=4; - } - - //---------- - // tail - - nblocks <<= 2; - - uint k1 = 0; - - uint tailLength = length & 3; - - if (tailLength == 3) - k1 ^= (uint)data[2 + nblocks] << 16; - if (tailLength >= 2) - k1 ^= (uint)data[1 + nblocks] << 8; - if (tailLength >= 1) - { - k1 ^= data[nblocks]; - k1 *= c1; k1 = rotl32(k1, 15); k1 *= c2; h1 ^= k1; - } - - //---------- - // finalization - - h1 ^= length; - - h1 = fmix32(h1); - - return h1; - } - - static uint fmix32(uint h) - { - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - - return h; - } - - static uint rotl32(uint x, byte r) - { - return (x << r) | (x >> (32 - r)); - } - - static public bool VerificationTest() - { - byte[] key = new byte[256]; - byte[] hashes = new byte[1024]; - - for (uint i = 0; i < 256; i++) - { - key[i] = (byte)i; - - uint result = MurmurHash3_x86_32(key, i, 256 - i); - - Buffer.BlockCopy(BitConverter.GetBytes(result), 0, hashes, (int)i * 4, 4); - } - - // Then hash the result array - - uint finalr = MurmurHash3_x86_32(hashes, 1024, 0); - - uint verification = 0xB0F57EE3; - - //---------- - - if (verification != finalr) - { - return false; - } - else - { - System.Diagnostics.Debug.WriteLine("works"); - - return true; - } - } -} diff --git a/Utilities/PropertyInfoExtensions.cs b/Utilities/PropertyInfoExtensions.cs deleted file mode 100644 index 87b18d8..0000000 --- a/Utilities/PropertyInfoExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Reflection; - -public static class NetFXCoreWrappers -{ - public static MethodInfo GetMethodInfoEx(this Delegate delegateEx) - { -#if NETFX_CORE - var method = delegateEx.GetMethodInfo(); -#else - var method = delegateEx.Method; -#endif - return method; - } - - public static Type GetDeclaringType(this MethodInfo methodInfo) - { -#if NETFX_CORE - return methodInfo.DeclaringType; -#else - return methodInfo.ReflectedType; -#endif - } -} diff --git a/Utilities/SimpleLogger.cs b/Utilities/SimpleLogger.cs deleted file mode 100644 index 454e1dc..0000000 --- a/Utilities/SimpleLogger.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Utility -{ - public class SimpleLogger : ILogger - { - public void Log(string txt, string stack = null, LogType type = LogType.Log) - { - switch (type) - { - case LogType.Log: - Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Exception: - Console.SystemLog("Log of exceptions not supported"); - break; - case LogType.Warning: - Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Error: - Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); - break; - } - } - } -} \ No newline at end of file diff --git a/Utilities/SlowLoggerUnity.cs b/Utilities/SlowLoggerUnity.cs deleted file mode 100644 index 6d5a33d..0000000 --- a/Utilities/SlowLoggerUnity.cs +++ /dev/null @@ -1,26 +0,0 @@ -#if UNITY_5_3_OR_NEWER || UNITY_5 -namespace Utility -{ - public class SlowLoggerUnity : ILogger - { - public void Log(string txt, string stack = null, LogType type = LogType.Log) - { - switch (type) - { - case LogType.Log: - UnityEngine.Debug.Log(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Exception: - UnityEngine.Debug.LogError("Log of exceptions not supported"); - break; - case LogType.Warning: - UnityEngine.Debug.LogWarning(stack != null ? txt.FastConcat(stack) : txt); - break; - case LogType.Error: - UnityEngine.Debug.LogError(stack != null ? txt.FastConcat(stack) : txt); - break; - } - } - } -} -#endif \ No newline at end of file diff --git a/WeakEvents/SafeEvent.cs b/WeakEvents/SafeEvent.cs deleted file mode 100644 index 846e58c..0000000 --- a/WeakEvents/SafeEvent.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; - -public static class SafeEvent -{ - public static void SafeRaise(this Action onEvent, T val) - { - if (onEvent != null) - { - var length = onEvent.GetInvocationList().Length; - for (int index = 0; index < length; index++) - { - Action handler = (Action) onEvent.GetInvocationList()[index]; - - try - { - if (handler != null) handler.Invoke(val); - } - catch (Exception e) - { - Utility.Console.LogException(e); - } - } - } - } - - public static void SafeRaise(this Action onEvent) - { - if (onEvent != null) - { - var length = onEvent.GetInvocationList().Length; - for (int index = 0; index < length; index++) - { - Action handler = (Action)onEvent.GetInvocationList()[index]; - - try - { - if (handler != null) handler.Invoke(); - } - catch (Exception e) - { - Utility.Console.LogException(e); - } - } - } - } -} - diff --git a/WeakEvents/WeakAction.cs b/WeakEvents/WeakAction.cs deleted file mode 100644 index 8c5ece6..0000000 --- a/WeakEvents/WeakAction.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Svelto.WeakEvents -{ - public class WeakAction : WeakAction - { - public WeakAction(Action listener) - : base(listener.Target, listener.GetMethodInfoEx()) - {} - - public void Invoke(T1 data1, T2 data2) - { - _data[0] = data1; - _data[1] = data2; - - Invoke_Internal(_data); - } - - readonly object[] _data = new object[2]; - } - - public class WeakAction : WeakActionBase - { - public WeakAction(Action listener) - : base(listener.Target, listener.GetMethodInfoEx()) - {} - - public void Invoke(T data) - { - _data[0] = data; - - Invoke_Internal(_data); - } - - readonly object[] _data = new object[1]; - } - - public class WeakAction : WeakActionBase - { - public WeakAction(Action listener) : base(listener) - {} - - public WeakAction(object listener, MethodInfo method) : base(listener, method) - {} - - public void Invoke() - { - Invoke_Internal(null); - } - } - - public abstract class WeakActionBase - { - protected readonly DataStructures.WeakReference ObjectRef; - protected readonly MethodInfo Method; - - public bool IsValid - { - get { return ObjectRef.IsValid; } - } - - protected WeakActionBase(Action listener) - : this(listener.Target, listener.GetMethodInfoEx()) - {} - - protected WeakActionBase(object listener, MethodInfo method) - { - ObjectRef = new DataStructures.WeakReference(listener); - - Method = method; - -#if NETFX_CORE - var attributes = (CompilerGeneratedAttribute[])method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); - if (attributes.Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#else - if (method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#endif - } - - protected void Invoke_Internal(object[] data) - { - if (ObjectRef.IsValid) - Method.Invoke(ObjectRef.Target, data); - else - Utility.Console.LogWarning("Target of weak action has been garbage collected"); - } - } -} \ No newline at end of file diff --git a/WeakEvents/WeakActionStruct.cs b/WeakEvents/WeakActionStruct.cs deleted file mode 100644 index 7686934..0000000 --- a/WeakEvents/WeakActionStruct.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -//careful, you must handle the destruction of the GCHandles! -namespace Svelto.WeakEvents -{ - public struct WeakActionStruct : IEquatable>, IDisposable - { - public WeakActionStruct(Action listener) - { - WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), out _objectRef, out _method); - } - - public bool Invoke(object[] args) - { - return WeakActionStructUtility.Invoke(ref _objectRef, _method, args); - } - - public bool Equals(WeakActionStruct other) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - other._objectRef.Target, other._method); - } - - public void Dispose() - { - _objectRef.Free(); - } - - public bool IsMatch(object otherObject, MethodInfo otherMethod) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - otherObject, otherMethod); - } - - GCHandle _objectRef; - readonly MethodInfo _method; - } - - public struct WeakActionStruct : IEquatable>, IDisposable - { - public WeakActionStruct(Action listener) - { - WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), - out _objectRef, out _method); - } - - public bool Invoke(object[] args) - { - return WeakActionStructUtility.Invoke(ref _objectRef, _method, args); - } - - public bool Equals(WeakActionStruct other) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - other._objectRef.Target, other._method); - } - - public void Dispose() - { - _objectRef.Free(); - } - - public bool IsMatch(object otherObject, MethodInfo otherMethod) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - otherObject, otherMethod); - } - - GCHandle _objectRef; - readonly MethodInfo _method; - } - - public struct WeakActionStruct : IEquatable, IDisposable - { - public WeakActionStruct(Action listener) - { - WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), - out _objectRef, out _method); - } - - public bool Invoke() - { - return WeakActionStructUtility.Invoke(ref _objectRef, _method, null); - } - - public bool Equals(WeakActionStruct other) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - other._objectRef.Target, other._method); - } - - public void Dispose() - { - _objectRef.Free(); - } - - public bool IsMatch(object otherObject, MethodInfo otherMethod) - { - return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, - otherObject, otherMethod); - } - - GCHandle _objectRef; - readonly MethodInfo _method; - } - - static class WeakActionStructUtility - { - internal static void Init(object target, MethodInfo method, - out GCHandle objectRef, out MethodInfo methodOut) - { - objectRef = GCHandle.Alloc(target, GCHandleType.Weak); - methodOut = method; - -#if DEBUG && !PROFILER -#if NETFX_CORE - Method = listener.GetMethodInfo(); - var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); - if(attributes.Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#else - if (method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) - throw new ArgumentException("Cannot create weak event to anonymous method with closure."); -#endif -#endif - } - - public static bool Invoke(ref GCHandle objectRef, MethodInfo method, object[] args) - { - if (objectRef.IsAllocated && objectRef.Target != null) - { - method.Invoke(objectRef.Target, args); - return true; - } - - Dispose(ref objectRef); - return false; - } - - public static void Dispose(ref GCHandle objectRef) - { - objectRef.Free(); - } - - public static bool IsMatch(object objectRef, MethodInfo method, - object _objectRef, MethodInfo _method) - { - return _method.Equals(method) && objectRef.Equals(_objectRef); - } - } -} \ No newline at end of file diff --git a/WeakEvents/WeakEvent.cs b/WeakEvents/WeakEvent.cs deleted file mode 100644 index 485df35..0000000 --- a/WeakEvents/WeakEvent.cs +++ /dev/null @@ -1,163 +0,0 @@ -using Svelto.DataStructures; -using System; -using System.Reflection; - -namespace Svelto.WeakEvents -{ - public class WeakEvent - { - public static WeakEvent operator+(WeakEvent c1, Action x) - { - if (c1 == null) c1 = new WeakEvent(); - c1._subscribers.Add(new WeakActionStruct(x)); - - return c1; - } - - public static WeakEvent operator-(WeakEvent c1, Action x) - { - DesignByContract.Check.Require(x != null); - c1.Remove(x.Target, x.GetMethodInfoEx()); - - return c1; - } - - public void Invoke() - { - for (int i = 0; i < _subscribers.Count; i++) - if (_subscribers[i].Invoke() == false) - _subscribers.UnorderedRemoveAt(i--); - } - - void Remove(object thisObject, MethodInfo thisMethod) - { - for (int i = 0; i < _subscribers.Count; ++i) - { - var otherObject = _subscribers[i]; - - if (otherObject.IsMatch(thisObject, thisMethod)) - { - _subscribers.UnorderedRemoveAt(i); - break; - } - } - } - - ~WeakEvent() - { - for (int i = 0; i < _subscribers.Count; i++) - _subscribers[i].Dispose(); - } - - readonly FasterList - _subscribers = new FasterList(); - } - - public class WeakEvent - { - public static WeakEvent operator+(WeakEvent c1, Action x) - { - if (c1 == null) c1 = new WeakEvent(); - c1._subscribers.Add(new WeakActionStruct(x)); - - return c1; - } - - public static WeakEvent operator-(WeakEvent c1, Action x) - { - DesignByContract.Check.Require(x != null); - c1.Remove(x.Target, x.GetMethodInfoEx()); - - return c1; - } - - public void Invoke(T1 arg1) - { - args[0] = arg1; - - for (int i = 0; i < _subscribers.Count; i++) - if (_subscribers[i].Invoke(args) == false) - _subscribers.UnorderedRemoveAt(i--); - } - - void Remove(object thisObject, MethodInfo thisMethod) - { - for (int i = 0; i < _subscribers.Count; ++i) - { - var otherObject = _subscribers[i]; - - if (otherObject.IsMatch(thisObject, thisMethod)) - { - _subscribers.UnorderedRemoveAt(i); - break; - } - } - } - - ~WeakEvent() - { - for (int i = 0; i < _subscribers.Count; i++) - _subscribers[i].Dispose(); - } - - readonly object[] args = new object[1]; - - readonly FasterList> - _subscribers = new FasterList>(); - } - - public class WeakEvent - { - public static WeakEvent operator+(WeakEvent c1, Action x) - { - if (c1 == null) c1 = new WeakEvent(); - c1._subscribers.Add(new WeakActionStruct(x)); - - return c1; - } - - public static WeakEvent operator-(WeakEvent c1, Action x) - { - DesignByContract.Check.Require(x != null); - c1.Remove(x.Target, x.GetMethodInfoEx()); - - return c1; - } - - public void Invoke(T1 arg1, T2 arg2) - { - args[0] = arg1; - args[1] = arg2; - - for (int i = 0; i < _subscribers.Count; i++) - if (_subscribers[i].Invoke(args) == false) - _subscribers.UnorderedRemoveAt(i--); - } - - void Remove(object thisObject, MethodInfo thisMethod) - { - for (int i = 0; i < _subscribers.Count; ++i) - { - var otherObject = _subscribers[i]; - - if (otherObject.IsMatch(thisObject, thisMethod)) - { - _subscribers.UnorderedRemoveAt(i); - - break; - } - } - } - - ~WeakEvent() - { - for (int i = 0; i < _subscribers.Count; i++) - _subscribers[i].Dispose(); - } - - readonly object[] args = new object[2]; - - readonly FasterList> - _subscribers = new FasterList>(); - } -} From 298c80383187cf2065184f7451e88b8e0160ce9f Mon Sep 17 00:00:00 2001 From: sebas77 Date: Tue, 9 Jan 2018 12:46:52 +0000 Subject: [PATCH 16/22] delete folder --- Svelto.Common | 1 - 1 file changed, 1 deletion(-) delete mode 160000 Svelto.Common diff --git a/Svelto.Common b/Svelto.Common deleted file mode 160000 index 9fd29ea..0000000 --- a/Svelto.Common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9fd29eaa5a2dd50a248112c045ae7691cab20a44 From 365f4f404abb9276e8bdbf4d62b32a726753260e Mon Sep 17 00:00:00 2001 From: sebas77 Date: Tue, 9 Jan 2018 12:47:35 +0000 Subject: [PATCH 17/22] Update submodule --- .gitmodules | 3 +++ Svelto.Common | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 Svelto.Common diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..532d6f0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Svelto.Common"] + path = Svelto.Common + url = https://github.com/sebas77/Svelto.Common.git diff --git a/Svelto.Common b/Svelto.Common new file mode 160000 index 0000000..1d516b3 --- /dev/null +++ b/Svelto.Common @@ -0,0 +1 @@ +Subproject commit 1d516b3c1eae36e366f48dad4af5950828793835 From c8fac3a2d5744461231e339e340e82c3af4d4a27 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Tue, 9 Jan 2018 13:31:06 +0000 Subject: [PATCH 18/22] removing old file --- Svelto.ECS/ECS/IEngineEntityViewDB.cs | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 Svelto.ECS/ECS/IEngineEntityViewDB.cs diff --git a/Svelto.ECS/ECS/IEngineEntityViewDB.cs b/Svelto.ECS/ECS/IEngineEntityViewDB.cs deleted file mode 100644 index 571f3f8..0000000 --- a/Svelto.ECS/ECS/IEngineEntityViewDB.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Svelto.DataStructures; - -namespace Svelto.ECS -{ - public interface IEngineEntityViewDB - { - FasterReadOnlyList QueryEntityViews() where T:EntityView, new(); - FasterReadOnlyList QueryMetaEntityViews() where T: EntityView, new(); - FasterReadOnlyList QueryGroupedEntityViews(int group) where T: EntityView, new(); - - T[] QueryEntityViewsAsArray(out int count) where T: IEntityView; - T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T: IEntityView; - - ReadOnlyDictionary QueryIndexableEntityViews() where T: IEntityView; - bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView; - T QueryEntityView(int ID) where T: IEntityView; - - bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T: EntityView, new(); - T QueryMetaEntityView(int metaEntityID) where T: EntityView, new(); - } -} - From 29931c39376d4d100f68b5522aa2a3fab2f6a501 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Tue, 9 Jan 2018 13:35:06 +0000 Subject: [PATCH 19/22] remove unused files after merging from wip --- Context/IUnityCompositionRoot.cs | 11 - DataStructures/IGraphNode.cs | 16 - .../LeftLeaningKeyedRedBlackTree.cs | 627 -------------- DataStructures/LeftLeaningRedBlackTree.cs | 789 ------------------ DataStructures/PriorityQueue.cs | 108 --- ECS/DataStructures/TypeSafeDictionary.cs | 51 -- .../TypeSafeFasterListForECS.cs | 150 ---- ECS/EngineEntityViewDB.cs | 168 ---- ECS/EnginesRootEngines.cs | 231 ----- ECS/EnginesRootEntities.cs | 375 --------- ECS/EnginesRootSubmission.cs | 160 ---- ECS/EntitySubmissionScheduler.cs | 9 - ECS/EntityView.cs | 57 -- ECS/EntityViewBuilder.cs | 99 --- ECS/Experimental/StructNodeCollections.cs | 178 ---- .../Unity/GenericEntityDescriptorHolder.cs | 14 - ECS/IEngineEntityViewDB.cs | 22 - ECS/IEnginesInterfaces.cs | 27 - ECS/MixedEntityDescriptor.cs | 107 --- ECS/MultiEntityViewsEngine.cs | 87 -- ECS/RemoveEntityImplementor.cs | 36 - ECS/SingleEntityViewEngine.cs | 20 - Observer/Observable.cs | 42 - Observer/Observer.cs | 111 --- Utilities/FastInvoke.cs | 91 -- Utilities/NetFXCoreWrappers.cs | 170 ---- Utilities/ThreadUtility.cs | 16 - 27 files changed, 3772 deletions(-) delete mode 100644 Context/IUnityCompositionRoot.cs delete mode 100644 DataStructures/IGraphNode.cs delete mode 100644 DataStructures/LeftLeaningKeyedRedBlackTree.cs delete mode 100644 DataStructures/LeftLeaningRedBlackTree.cs delete mode 100644 DataStructures/PriorityQueue.cs delete mode 100644 ECS/DataStructures/TypeSafeDictionary.cs delete mode 100644 ECS/DataStructures/TypeSafeFasterListForECS.cs delete mode 100644 ECS/EngineEntityViewDB.cs delete mode 100644 ECS/EnginesRootEngines.cs delete mode 100644 ECS/EnginesRootEntities.cs delete mode 100644 ECS/EnginesRootSubmission.cs delete mode 100644 ECS/EntitySubmissionScheduler.cs delete mode 100644 ECS/EntityView.cs delete mode 100644 ECS/EntityViewBuilder.cs delete mode 100644 ECS/Experimental/StructNodeCollections.cs delete mode 100644 ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs delete mode 100644 ECS/IEngineEntityViewDB.cs delete mode 100644 ECS/IEnginesInterfaces.cs delete mode 100644 ECS/MixedEntityDescriptor.cs delete mode 100644 ECS/MultiEntityViewsEngine.cs delete mode 100644 ECS/RemoveEntityImplementor.cs delete mode 100644 ECS/SingleEntityViewEngine.cs delete mode 100644 Observer/Observable.cs delete mode 100644 Observer/Observer.cs delete mode 100644 Utilities/FastInvoke.cs delete mode 100644 Utilities/NetFXCoreWrappers.cs delete mode 100644 Utilities/ThreadUtility.cs diff --git a/Context/IUnityCompositionRoot.cs b/Context/IUnityCompositionRoot.cs deleted file mode 100644 index c4db99a..0000000 --- a/Context/IUnityCompositionRoot.cs +++ /dev/null @@ -1,11 +0,0 @@ -#if UNITY_5 || UNITY_5_3_OR_NEWER -namespace Svelto.Context -{ - public interface IUnityCompositionRoot - { - void OnContextCreated(UnityContext contextHolder); - void OnContextInitialized(); - void OnContextDestroyed(); - } -} -#endif \ No newline at end of file diff --git a/DataStructures/IGraphNode.cs b/DataStructures/IGraphNode.cs deleted file mode 100644 index e1fc894..0000000 --- a/DataStructures/IGraphNode.cs +++ /dev/null @@ -1,16 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18408 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ -using System; - -public interface IGraphEntityView -{ - void VisitNeighbours(System.Action onVisiting); -} - diff --git a/DataStructures/LeftLeaningKeyedRedBlackTree.cs b/DataStructures/LeftLeaningKeyedRedBlackTree.cs deleted file mode 100644 index 94f285b..0000000 --- a/DataStructures/LeftLeaningKeyedRedBlackTree.cs +++ /dev/null @@ -1,627 +0,0 @@ -// Uncomment this to enable the following debugging aids: -// LeftLeaningRedBlackTree.HtmlFragment -// LeftLeaningRedBlackTree.EntityView.HtmlFragment -// LeftLeaningRedBlackTree.AssertInvariants -// #define DEBUGGING - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -/// -/// Implements a left-leaning red-black tree. -/// -/// -/// Based on the research paper "Left-leaning Red-Black Trees" -/// by Robert Sedgewick. More information available at: -/// http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf -/// http://www.cs.princeton.edu/~rs/talks/LLRB/08Penn.pdf -/// -/// Type of keys. -public class LeftLeaningKeyedRedBlackTree where TKey: IComparable -{ - /// - /// Stores the root entityView of the tree. - /// - private EntityView _rootEntityView; - - /// - /// Represents a entityView of the tree. - /// - /// - /// Using fields instead of properties drops execution time by about 40%. - /// - [DebuggerDisplay("Key={Key}")] - private class EntityView - { - /// - /// Gets or sets the entityView's key. - /// - public TKey Key; - - /// - /// Gets or sets the left entityView. - /// - public EntityView Left; - - /// - /// Gets or sets the right entityView. - /// - public EntityView Right; - - /// - /// Gets or sets the color of the entityView. - /// - public bool IsBlack; - -#if DEBUGGING - /// - /// Gets an HTML fragment representing the entityView and its children. - /// - public string HtmlFragment - { - get - { - return - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "
" + Key + ", " + Value + " [" + Siblings + "]
" + (null != Left ? Left.HtmlFragment : "[null]") + "" + (null != Right ? Right.HtmlFragment : "[null]") + "
"; - } - } -#endif - } - - /// - /// Adds a key/value pair to the tree. - /// - /// Key to add. - public void Add(TKey key) - { - _rootEntityView = Add(_rootEntityView, key); - _rootEntityView.IsBlack = true; -#if DEBUGGING - AssertInvariants(); -#endif - } - - /// - /// Removes a key/value pair from the tree. - /// - /// Key to remove. - /// True if key/value present and removed. - public bool Remove(TKey key) - { - int initialCount = Count; - if (null != _rootEntityView) - { - _rootEntityView = Remove(_rootEntityView, key); - if (null != _rootEntityView) - { - _rootEntityView.IsBlack = true; - } - } -#if DEBUGGING - AssertInvariants(); -#endif - return initialCount != Count; - } - - /// - /// Removes all entityViews in the tree. - /// - public void Clear() - { - _rootEntityView = null; - Count = 0; -#if DEBUGGING - AssertInvariants(); -#endif - } - - /// - /// Gets a sorted list of keys in the tree. - /// - /// Sorted list of keys. - public IEnumerable GetKeys() - { - TKey lastKey = default(TKey); - bool lastKeyValid = false; - return Traverse( - _rootEntityView, - n => !lastKeyValid || !object.Equals(lastKey, n.Key), - n => - { - lastKey = n.Key; - lastKeyValid = true; - return lastKey; - }); - } - - /// - /// Gets the count of key/value pairs in the tree. - /// - public int Count { get; private set; } - - /// - /// Gets the minimum key in the tree. - /// - public TKey MinimumKey - { - get { return GetExtreme(_rootEntityView, n => n.Left, n => n.Key); } - } - - /// - /// Gets the maximum key in the tree. - /// - public TKey MaximumKey - { - get { return GetExtreme(_rootEntityView, n => n.Right, n => n.Key); } - } - - /// - /// Returns true if the specified entityView is red. - /// - /// Specified entityView. - /// True if specified entityView is red. - private static bool IsRed(EntityView entityView) - { - if (null == entityView) - { - // "Virtual" leaf entityViews are always black - return false; - } - return !entityView.IsBlack; - } - - /// - /// Adds the specified key/value pair below the specified root entityView. - /// - /// Specified entityView. - /// Key to add. - /// Value to add. - /// New root entityView. - private EntityView Add(EntityView entityView, TKey key) - { - if (null == entityView) - { - // Insert new entityView - Count++; - return new EntityView { Key = key }; - } - - if (IsRed(entityView.Left) && IsRed(entityView.Right)) - { - // Split entityView with two red children - FlipColor(entityView); - } - - // Find right place for new entityView - int comparisonResult = KeyComparison(key, entityView.Key); - if (comparisonResult < 0) - { - entityView.Left = Add(entityView.Left, key); - } - else if (0 < comparisonResult) - { - entityView.Right = Add(entityView.Right, key); - } - - if (IsRed(entityView.Right)) - { - // Rotate to prevent red entityView on right - entityView = RotateLeft(entityView); - } - - if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) - { - // Rotate to prevent consecutive red entityViews - entityView = RotateRight(entityView); - } - - return entityView; - } - - /// - /// Removes the specified key/value pair from below the specified entityView. - /// - /// Specified entityView. - /// Key to remove. - /// True if key/value present and removed. - private EntityView Remove(EntityView entityView, TKey key) - { - int comparisonResult = KeyComparison(key, entityView.Key); - if (comparisonResult < 0) - { - // * Continue search if left is present - if (null != entityView.Left) - { - if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) - { - // Move a red entityView over - entityView = MoveRedLeft(entityView); - } - - // Remove from left - entityView.Left = Remove(entityView.Left, key); - } - } - else - { - if (IsRed(entityView.Left)) - { - // Flip a 3 entityView or unbalance a 4 entityView - entityView = RotateRight(entityView); - } - if ((0 == KeyComparison(key, entityView.Key)) && (null == entityView.Right)) - { - // Remove leaf entityView - Debug.Assert(null == entityView.Left, "About to remove an extra entityView."); - Count--; - // Leaf entityView is gone - return null; - } - // * Continue search if right is present - if (null != entityView.Right) - { - if (!IsRed(entityView.Right) && !IsRed(entityView.Right.Left)) - { - // Move a red entityView over - entityView = MoveRedRight(entityView); - } - if (0 == KeyComparison(key, entityView.Key)) - { - // Remove leaf entityView - Count--; - // Find the smallest entityView on the right, swap, and remove it - EntityView m = GetExtreme(entityView.Right, n => n.Left, n => n); - entityView.Key = m.Key; - entityView.Right = DeleteMinimum(entityView.Right); - } - else - { - // Remove from right - entityView.Right = Remove(entityView.Right, key); - } - } - } - - // Maintain invariants - return FixUp(entityView); - } - - /// - /// Flip the colors of the specified entityView and its direct children. - /// - /// Specified entityView. - private static void FlipColor(EntityView entityView) - { - entityView.IsBlack = !entityView.IsBlack; - entityView.Left.IsBlack = !entityView.Left.IsBlack; - entityView.Right.IsBlack = !entityView.Right.IsBlack; - } - - /// - /// Rotate the specified entityView "left". - /// - /// Specified entityView. - /// New root entityView. - private static EntityView RotateLeft(EntityView entityView) - { - EntityView x = entityView.Right; - entityView.Right = x.Left; - x.Left = entityView; - x.IsBlack = entityView.IsBlack; - entityView.IsBlack = false; - return x; - } - - /// - /// Rotate the specified entityView "right". - /// - /// Specified entityView. - /// New root entityView. - private static EntityView RotateRight(EntityView entityView) - { - EntityView x = entityView.Left; - entityView.Left = x.Right; - x.Right = entityView; - x.IsBlack = entityView.IsBlack; - entityView.IsBlack = false; - return x; - } - - /// - /// Moves a red entityView from the right child to the left child. - /// - /// Parent entityView. - /// New root entityView. - private static EntityView MoveRedLeft(EntityView entityView) - { - FlipColor(entityView); - if (IsRed(entityView.Right.Left)) - { - entityView.Right = RotateRight(entityView.Right); - entityView = RotateLeft(entityView); - FlipColor(entityView); - - // * Avoid creating right-leaning entityViews - if (IsRed(entityView.Right.Right)) - { - entityView.Right = RotateLeft(entityView.Right); - } - } - return entityView; - } - - /// - /// Moves a red entityView from the left child to the right child. - /// - /// Parent entityView. - /// New root entityView. - private static EntityView MoveRedRight(EntityView entityView) - { - FlipColor(entityView); - if (IsRed(entityView.Left.Left)) - { - entityView = RotateRight(entityView); - FlipColor(entityView); - } - return entityView; - } - - /// - /// Deletes the minimum entityView under the specified entityView. - /// - /// Specified entityView. - /// New root entityView. - private EntityView DeleteMinimum(EntityView entityView) - { - if (null == entityView.Left) - { - // Nothing to do - return null; - } - - if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) - { - // Move red entityView left - entityView = MoveRedLeft(entityView); - } - - // Recursively delete - entityView.Left = DeleteMinimum(entityView.Left); - - // Maintain invariants - return FixUp(entityView); - } - - /// - /// Maintains invariants by adjusting the specified entityViews children. - /// - /// Specified entityView. - /// New root entityView. - private static EntityView FixUp(EntityView entityView) - { - if (IsRed(entityView.Right)) - { - // Avoid right-leaning entityView - entityView = RotateLeft(entityView); - } - - if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) - { - // Balance 4-entityView - entityView = RotateRight(entityView); - } - - if (IsRed(entityView.Left) && IsRed(entityView.Right)) - { - // Push red up - FlipColor(entityView); - } - - // * Avoid leaving behind right-leaning entityViews - if ((null != entityView.Left) && IsRed(entityView.Left.Right) && !IsRed(entityView.Left.Left)) - { - entityView.Left = RotateLeft(entityView.Left); - if (IsRed(entityView.Left)) - { - // Balance 4-entityView - entityView = RotateRight(entityView); - } - } - - return entityView; - } - - /// - /// Gets the (first) entityView corresponding to the specified key. - /// - /// Key to search for. - /// Corresponding entityView or null if none found. - private EntityView GetEntityViewForKey(TKey key) - { - // Initialize - EntityView entityView = _rootEntityView; - while (null != entityView) - { - // Compare keys and go left/right - int comparisonResult = key.CompareTo(entityView.Key); - if (comparisonResult < 0) - { - entityView = entityView.Left; - } - else if (0 < comparisonResult) - { - entityView = entityView.Right; - } - else - { - // Match; return entityView - return entityView; - } - } - - // No match found - return null; - } - - /// - /// Gets an extreme (ex: minimum/maximum) value. - /// - /// Type of value. - /// EntityView to start from. - /// Successor function. - /// Selector function. - /// Extreme value. - private static T GetExtreme(EntityView entityView, Func successor, Func selector) - { - // Initialize - T extreme = default(T); - EntityView current = entityView; - while (null != current) - { - // Go to extreme - extreme = selector(current); - current = successor(current); - } - return extreme; - } - - /// - /// Traverses a subset of the sequence of entityViews in order and selects the specified entityViews. - /// - /// Type of elements. - /// Starting entityView. - /// Condition method. - /// Selector method. - /// Sequence of selected entityViews. - private IEnumerable Traverse(EntityView entityView, Func condition, Func selector) - { - // Create a stack to avoid recursion - Stack stack = new Stack(); - EntityView current = entityView; - while (null != current) - { - if (null != current.Left) - { - // Save current state and go left - stack.Push(current); - current = current.Left; - } - else - { - do - { - // Select current entityView if relevant - if (condition(current)) - { - yield return selector(current); - } - // Go right - or up if nothing to the right - current = current.Right; - } - while ((null == current) && - (0 < stack.Count) && - (null != (current = stack.Pop()))); - } - } - } - - /// - /// Compares the specified keys (primary) and values (secondary). - /// - /// The left key. - /// The right key. - /// CompareTo-style results: -1 if left is less, 0 if equal, and 1 if greater than right. - private int KeyComparison(TKey leftKey, TKey rightKey) - { - return leftKey.CompareTo(rightKey); - } - -#if DEBUGGING - /// - /// Asserts that tree invariants are not violated. - /// - private void AssertInvariants() - { - // Root is black - Debug.Assert((null == _rootEntityView) || _rootEntityView.IsBlack, "Root is not black"); - // Every path contains the same number of black entityViews - Dictionary parents = new Dictionary.EntityView, LeftLeaningRedBlackTree.EntityView>(); - foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) - { - if (null != entityView.Left) - { - parents[entityView.Left] = entityView; - } - if (null != entityView.Right) - { - parents[entityView.Right] = entityView; - } - } - if (null != _rootEntityView) - { - parents[_rootEntityView] = null; - } - int treeCount = -1; - foreach (EntityView entityView in Traverse(_rootEntityView, n => (null == n.Left) || (null == n.Right), n => n)) - { - int pathCount = 0; - EntityView current = entityView; - while (null != current) - { - if (current.IsBlack) - { - pathCount++; - } - current = parents[current]; - } - Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black entityViews."); - treeCount = pathCount; - } - // Verify entityView properties... - foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) - { - // Left entityView is less - if (null != entityView.Left) - { - Debug.Assert(0 > KeyAndValueComparison(entityView.Left.Key, entityView.Left.Value, entityView.Key, entityView.Value), "Left entityView is greater than its parent."); - } - // Right entityView is greater - if (null != entityView.Right) - { - Debug.Assert(0 < KeyAndValueComparison(entityView.Right.Key, entityView.Right.Value, entityView.Key, entityView.Value), "Right entityView is less than its parent."); - } - // Both children of a red entityView are black - Debug.Assert(!IsRed(entityView) || (!IsRed(entityView.Left) && !IsRed(entityView.Right)), "Red entityView has a red child."); - // Always left-leaning - Debug.Assert(!IsRed(entityView.Right) || IsRed(entityView.Left), "EntityView is not left-leaning."); - // No consecutive reds (subset of previous rule) - //Debug.Assert(!(IsRed(entityView) && IsRed(entityView.Left))); - } - } - - /// - /// Gets an HTML fragment representing the tree. - /// - public string HtmlDocument - { - get - { - return - "" + - "" + - (null != _rootEntityView ? _rootEntityView.HtmlFragment : "[null]") + - "" + - ""; - } - } -#endif -} diff --git a/DataStructures/LeftLeaningRedBlackTree.cs b/DataStructures/LeftLeaningRedBlackTree.cs deleted file mode 100644 index f109135..0000000 --- a/DataStructures/LeftLeaningRedBlackTree.cs +++ /dev/null @@ -1,789 +0,0 @@ -// Uncomment this to enable the following debugging aids: -// LeftLeaningRedBlackTree.HtmlFragment -// LeftLeaningRedBlackTree.EntityView.HtmlFragment -// LeftLeaningRedBlackTree.AssertInvariants -// #define DEBUGGING - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -/// -/// Implements a left-leaning red-black tree. -/// -/// -/// Based on the research paper "Left-leaning Red-Black Trees" -/// by Robert Sedgewick. More information available at: -/// http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf -/// http://www.cs.princeton.edu/~rs/talks/LLRB/08Penn.pdf -/// -/// Type of keys. -/// Type of values. -public class LeftLeaningRedBlackTree -{ - /// - /// Stores the key comparison function. - /// - private Comparison _keyComparison; - - /// - /// Stores the value comparison function. - /// - private Comparison _valueComparison; - - /// - /// Stores the root entityView of the tree. - /// - private EntityView _rootEntityView; - - /// - /// Represents a entityView of the tree. - /// - /// - /// Using fields instead of properties drops execution time by about 40%. - /// - [DebuggerDisplay("Key={Key}, Value={Value}, Siblings={Siblings}")] - private class EntityView - { - /// - /// Gets or sets the entityView's key. - /// - public TKey Key; - - /// - /// Gets or sets the entityView's value. - /// - public TValue Value; - - /// - /// Gets or sets the left entityView. - /// - public EntityView Left; - - /// - /// Gets or sets the right entityView. - /// - public EntityView Right; - - /// - /// Gets or sets the color of the entityView. - /// - public bool IsBlack; - - /// - /// Gets or sets the number of "siblings" (entityViews with the same key/value). - /// - public int Siblings; - -#if DEBUGGING - /// - /// Gets an HTML fragment representing the entityView and its children. - /// - public string HtmlFragment - { - get - { - return - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "
" + Key + ", " + Value + " [" + Siblings + "]
" + (null != Left ? Left.HtmlFragment : "[null]") + "" + (null != Right ? Right.HtmlFragment : "[null]") + "
"; - } - } -#endif - } - - /// - /// Initializes a new instance of the LeftLeaningRedBlackTree class implementing a normal dictionary. - /// - /// The key comparison function. - public LeftLeaningRedBlackTree(Comparison keyComparison) - { - if (null == keyComparison) - { - throw new ArgumentNullException("keyComparison"); - } - _keyComparison = keyComparison; - } - - /// - /// Initializes a new instance of the LeftLeaningRedBlackTree class implementing an ordered multi-dictionary. - /// - /// The key comparison function. - /// The value comparison function. - public LeftLeaningRedBlackTree(Comparison keyComparison, Comparison valueComparison) - : this(keyComparison) - { - if (null == valueComparison) - { - throw new ArgumentNullException("valueComparison"); - } - _valueComparison = valueComparison; - } - - /// - /// Gets a value indicating whether the tree is acting as an ordered multi-dictionary. - /// - private bool IsMultiDictionary - { - get { return null != _valueComparison; } - } - - /// - /// Adds a key/value pair to the tree. - /// - /// Key to add. - /// Value to add. - public void Add(TKey key, TValue value) - { - _rootEntityView = Add(_rootEntityView, key, value); - _rootEntityView.IsBlack = true; -#if DEBUGGING - AssertInvariants(); -#endif - } - - /// - /// Removes a key (and its associated value) from a normal (non-multi) dictionary. - /// - /// Key to remove. - /// True if key present and removed. - public bool Remove(TKey key) - { - if (IsMultiDictionary) - { - throw new InvalidOperationException("Remove is only supported when acting as a normal (non-multi) dictionary."); - } - return Remove(key, default(TValue)); - } - - /// - /// Removes a key/value pair from the tree. - /// - /// Key to remove. - /// Value to remove. - /// True if key/value present and removed. - public bool Remove(TKey key, TValue value) - { - int initialCount = Count; - if (null != _rootEntityView) - { - _rootEntityView = Remove(_rootEntityView, key, value); - if (null != _rootEntityView) - { - _rootEntityView.IsBlack = true; - } - } -#if DEBUGGING - AssertInvariants(); -#endif - return initialCount != Count; - } - - /// - /// Removes all entityViews in the tree. - /// - public void Clear() - { - _rootEntityView = null; - Count = 0; -#if DEBUGGING - AssertInvariants(); -#endif - } - - /// - /// Gets a sorted list of keys in the tree. - /// - /// Sorted list of keys. - public IEnumerable GetKeys() - { - TKey lastKey = default(TKey); - bool lastKeyValid = false; - return Traverse( - _rootEntityView, - n => !lastKeyValid || !object.Equals(lastKey, n.Key), - n => - { - lastKey = n.Key; - lastKeyValid = true; - return lastKey; - }); - } - - /// - /// Gets the value associated with the specified key in a normal (non-multi) dictionary. - /// - /// Specified key. - /// Value associated with the specified key. - public TValue GetValueForKey(TKey key) - { - if (IsMultiDictionary) - { - throw new InvalidOperationException("GetValueForKey is only supported when acting as a normal (non-multi) dictionary."); - } - EntityView entityView = GetEntityViewForKey(key); - if (null != entityView) - { - return entityView.Value; - } - else - { - throw new KeyNotFoundException(); - } - } - - /// - /// Gets a sequence of the values associated with the specified key. - /// - /// Specified key. - /// Sequence of values. - public IEnumerable GetValuesForKey(TKey key) - { - return Traverse(GetEntityViewForKey(key), n => 0 == _keyComparison(n.Key, key), n => n.Value); - } - - /// - /// Gets a sequence of all the values in the tree. - /// - /// Sequence of all values. - public IEnumerable GetValuesForAllKeys() - { - return Traverse(_rootEntityView, n => true, n => n.Value); - } - - /// - /// Gets the count of key/value pairs in the tree. - /// - public int Count { get; private set; } - - /// - /// Gets the minimum key in the tree. - /// - public TKey MinimumKey - { - get { return GetExtreme(_rootEntityView, n => n.Left, n => n.Key); } - } - - /// - /// Gets the maximum key in the tree. - /// - public TKey MaximumKey - { - get { return GetExtreme(_rootEntityView, n => n.Right, n => n.Key); } - } - - /// - /// Returns true if the specified entityView is red. - /// - /// Specified entityView. - /// True if specified entityView is red. - private static bool IsRed(EntityView entityView) - { - if (null == entityView) - { - // "Virtual" leaf entityViews are always black - return false; - } - return !entityView.IsBlack; - } - - /// - /// Adds the specified key/value pair below the specified root entityView. - /// - /// Specified entityView. - /// Key to add. - /// Value to add. - /// New root entityView. - private EntityView Add(EntityView entityView, TKey key, TValue value) - { - if (null == entityView) - { - // Insert new entityView - Count++; - return new EntityView { Key = key, Value = value }; - } - - if (IsRed(entityView.Left) && IsRed(entityView.Right)) - { - // Split entityView with two red children - FlipColor(entityView); - } - - // Find right place for new entityView - int comparisonResult = KeyAndValueComparison(key, value, entityView.Key, entityView.Value); - if (comparisonResult < 0) - { - entityView.Left = Add(entityView.Left, key, value); - } - else if (0 < comparisonResult) - { - entityView.Right = Add(entityView.Right, key, value); - } - else - { - if (IsMultiDictionary) - { - // Store the presence of a "duplicate" entityView - entityView.Siblings++; - Count++; - } - else - { - // Replace the value of the existing entityView - entityView.Value = value; - } - } - - if (IsRed(entityView.Right)) - { - // Rotate to prevent red entityView on right - entityView = RotateLeft(entityView); - } - - if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) - { - // Rotate to prevent consecutive red entityViews - entityView = RotateRight(entityView); - } - - return entityView; - } - - /// - /// Removes the specified key/value pair from below the specified entityView. - /// - /// Specified entityView. - /// Key to remove. - /// Value to remove. - /// True if key/value present and removed. - private EntityView Remove(EntityView entityView, TKey key, TValue value) - { - int comparisonResult = KeyAndValueComparison(key, value, entityView.Key, entityView.Value); - if (comparisonResult < 0) - { - // * Continue search if left is present - if (null != entityView.Left) - { - if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) - { - // Move a red entityView over - entityView = MoveRedLeft(entityView); - } - - // Remove from left - entityView.Left = Remove(entityView.Left, key, value); - } - } - else - { - if (IsRed(entityView.Left)) - { - // Flip a 3 entityView or unbalance a 4 entityView - entityView = RotateRight(entityView); - } - if ((0 == KeyAndValueComparison(key, value, entityView.Key, entityView.Value)) && (null == entityView.Right)) - { - // Remove leaf entityView - Debug.Assert(null == entityView.Left, "About to remove an extra entityView."); - Count--; - if (0 < entityView.Siblings) - { - // Record the removal of the "duplicate" entityView - Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); - entityView.Siblings--; - return entityView; - } - else - { - // Leaf entityView is gone - return null; - } - } - // * Continue search if right is present - if (null != entityView.Right) - { - if (!IsRed(entityView.Right) && !IsRed(entityView.Right.Left)) - { - // Move a red entityView over - entityView = MoveRedRight(entityView); - } - if (0 == KeyAndValueComparison(key, value, entityView.Key, entityView.Value)) - { - // Remove leaf entityView - Count--; - if (0 < entityView.Siblings) - { - // Record the removal of the "duplicate" entityView - Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); - entityView.Siblings--; - } - else - { - // Find the smallest entityView on the right, swap, and remove it - EntityView m = GetExtreme(entityView.Right, n => n.Left, n => n); - entityView.Key = m.Key; - entityView.Value = m.Value; - entityView.Siblings = m.Siblings; - entityView.Right = DeleteMinimum(entityView.Right); - } - } - else - { - // Remove from right - entityView.Right = Remove(entityView.Right, key, value); - } - } - } - - // Maintain invariants - return FixUp(entityView); - } - - /// - /// Flip the colors of the specified entityView and its direct children. - /// - /// Specified entityView. - private static void FlipColor(EntityView entityView) - { - entityView.IsBlack = !entityView.IsBlack; - entityView.Left.IsBlack = !entityView.Left.IsBlack; - entityView.Right.IsBlack = !entityView.Right.IsBlack; - } - - /// - /// Rotate the specified entityView "left". - /// - /// Specified entityView. - /// New root entityView. - private static EntityView RotateLeft(EntityView entityView) - { - EntityView x = entityView.Right; - entityView.Right = x.Left; - x.Left = entityView; - x.IsBlack = entityView.IsBlack; - entityView.IsBlack = false; - return x; - } - - /// - /// Rotate the specified entityView "right". - /// - /// Specified entityView. - /// New root entityView. - private static EntityView RotateRight(EntityView entityView) - { - EntityView x = entityView.Left; - entityView.Left = x.Right; - x.Right = entityView; - x.IsBlack = entityView.IsBlack; - entityView.IsBlack = false; - return x; - } - - /// - /// Moves a red entityView from the right child to the left child. - /// - /// Parent entityView. - /// New root entityView. - private static EntityView MoveRedLeft(EntityView entityView) - { - FlipColor(entityView); - if (IsRed(entityView.Right.Left)) - { - entityView.Right = RotateRight(entityView.Right); - entityView = RotateLeft(entityView); - FlipColor(entityView); - - // * Avoid creating right-leaning entityViews - if (IsRed(entityView.Right.Right)) - { - entityView.Right = RotateLeft(entityView.Right); - } - } - return entityView; - } - - /// - /// Moves a red entityView from the left child to the right child. - /// - /// Parent entityView. - /// New root entityView. - private static EntityView MoveRedRight(EntityView entityView) - { - FlipColor(entityView); - if (IsRed(entityView.Left.Left)) - { - entityView = RotateRight(entityView); - FlipColor(entityView); - } - return entityView; - } - - /// - /// Deletes the minimum entityView under the specified entityView. - /// - /// Specified entityView. - /// New root entityView. - private EntityView DeleteMinimum(EntityView entityView) - { - if (null == entityView.Left) - { - // Nothing to do - return null; - } - - if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) - { - // Move red entityView left - entityView = MoveRedLeft(entityView); - } - - // Recursively delete - entityView.Left = DeleteMinimum(entityView.Left); - - // Maintain invariants - return FixUp(entityView); - } - - /// - /// Maintains invariants by adjusting the specified entityViews children. - /// - /// Specified entityView. - /// New root entityView. - private static EntityView FixUp(EntityView entityView) - { - if (IsRed(entityView.Right)) - { - // Avoid right-leaning entityView - entityView = RotateLeft(entityView); - } - - if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) - { - // Balance 4-entityView - entityView = RotateRight(entityView); - } - - if (IsRed(entityView.Left) && IsRed(entityView.Right)) - { - // Push red up - FlipColor(entityView); - } - - // * Avoid leaving behind right-leaning entityViews - if ((null != entityView.Left) && IsRed(entityView.Left.Right) && !IsRed(entityView.Left.Left)) - { - entityView.Left = RotateLeft(entityView.Left); - if (IsRed(entityView.Left)) - { - // Balance 4-entityView - entityView = RotateRight(entityView); - } - } - - return entityView; - } - - /// - /// Gets the (first) entityView corresponding to the specified key. - /// - /// Key to search for. - /// Corresponding entityView or null if none found. - private EntityView GetEntityViewForKey(TKey key) - { - // Initialize - EntityView entityView = _rootEntityView; - while (null != entityView) - { - // Compare keys and go left/right - int comparisonResult = _keyComparison(key, entityView.Key); - if (comparisonResult < 0) - { - entityView = entityView.Left; - } - else if (0 < comparisonResult) - { - entityView = entityView.Right; - } - else - { - // Match; return entityView - return entityView; - } - } - - // No match found - return null; - } - - /// - /// Gets an extreme (ex: minimum/maximum) value. - /// - /// Type of value. - /// EntityView to start from. - /// Successor function. - /// Selector function. - /// Extreme value. - private static T GetExtreme(EntityView entityView, Func successor, Func selector) - { - // Initialize - T extreme = default(T); - EntityView current = entityView; - while (null != current) - { - // Go to extreme - extreme = selector(current); - current = successor(current); - } - return extreme; - } - - /// - /// Traverses a subset of the sequence of entityViews in order and selects the specified entityViews. - /// - /// Type of elements. - /// Starting entityView. - /// Condition method. - /// Selector method. - /// Sequence of selected entityViews. - private IEnumerable Traverse(EntityView entityView, Func condition, Func selector) - { - // Create a stack to avoid recursion - Stack stack = new Stack(); - EntityView current = entityView; - while (null != current) - { - if (null != current.Left) - { - // Save current state and go left - stack.Push(current); - current = current.Left; - } - else - { - do - { - for (int i = 0; i <= current.Siblings; i++) - { - // Select current entityView if relevant - if (condition(current)) - { - yield return selector(current); - } - } - // Go right - or up if nothing to the right - current = current.Right; - } - while ((null == current) && - (0 < stack.Count) && - (null != (current = stack.Pop()))); - } - } - } - - /// - /// Compares the specified keys (primary) and values (secondary). - /// - /// The left key. - /// The left value. - /// The right key. - /// The right value. - /// CompareTo-style results: -1 if left is less, 0 if equal, and 1 if greater than right. - private int KeyAndValueComparison(TKey leftKey, TValue leftValue, TKey rightKey, TValue rightValue) - { - // Compare keys - int comparisonResult = _keyComparison(leftKey, rightKey); - if ((0 == comparisonResult) && (null != _valueComparison)) - { - // Keys match; compare values - comparisonResult = _valueComparison(leftValue, rightValue); - } - return comparisonResult; - } - -#if DEBUGGING - /// - /// Asserts that tree invariants are not violated. - /// - private void AssertInvariants() - { - // Root is black - Debug.Assert((null == _rootEntityView) || _rootEntityView.IsBlack, "Root is not black"); - // Every path contains the same number of black entityViews - Dictionary parents = new Dictionary.EntityView, LeftLeaningRedBlackTree.EntityView>(); - foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) - { - if (null != entityView.Left) - { - parents[entityView.Left] = entityView; - } - if (null != entityView.Right) - { - parents[entityView.Right] = entityView; - } - } - if (null != _rootEntityView) - { - parents[_rootEntityView] = null; - } - int treeCount = -1; - foreach (EntityView entityView in Traverse(_rootEntityView, n => (null == n.Left) || (null == n.Right), n => n)) - { - int pathCount = 0; - EntityView current = entityView; - while (null != current) - { - if (current.IsBlack) - { - pathCount++; - } - current = parents[current]; - } - Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black entityViews."); - treeCount = pathCount; - } - // Verify entityView properties... - foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) - { - // Left entityView is less - if (null != entityView.Left) - { - Debug.Assert(0 > KeyAndValueComparison(entityView.Left.Key, entityView.Left.Value, entityView.Key, entityView.Value), "Left entityView is greater than its parent."); - } - // Right entityView is greater - if (null != entityView.Right) - { - Debug.Assert(0 < KeyAndValueComparison(entityView.Right.Key, entityView.Right.Value, entityView.Key, entityView.Value), "Right entityView is less than its parent."); - } - // Both children of a red entityView are black - Debug.Assert(!IsRed(entityView) || (!IsRed(entityView.Left) && !IsRed(entityView.Right)), "Red entityView has a red child."); - // Always left-leaning - Debug.Assert(!IsRed(entityView.Right) || IsRed(entityView.Left), "EntityView is not left-leaning."); - // No consecutive reds (subset of previous rule) - //Debug.Assert(!(IsRed(entityView) && IsRed(entityView.Left))); - } - } - - /// - /// Gets an HTML fragment representing the tree. - /// - public string HtmlDocument - { - get - { - return - "" + - "" + - (null != _rootEntityView ? _rootEntityView.HtmlFragment : "[null]") + - "" + - ""; - } - } -#endif -} diff --git a/DataStructures/PriorityQueue.cs b/DataStructures/PriorityQueue.cs deleted file mode 100644 index f314d94..0000000 --- a/DataStructures/PriorityQueue.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections; - -// By James McCaffrey11/02/2012 - -sealed public class PriorityQueue:IEnumerable where T : IComparable -{ - private List data; - - public PriorityQueue () - { - this.data = new List (); - } - - IEnumerator System.Collections.IEnumerable.GetEnumerator () - { - // Lets call the generic version here - return this.GetEnumerator (); - } - - public IEnumerator GetEnumerator () - { - return data.GetEnumerator () as IEnumerator; - } - - public void Enqueue (T item) - { - data.Add (item); - int ci = data.Count - 1; // child index; start at end - while (ci > 0) { - int pi = (ci - 1) / 2; // parent index - if (data [ci].CompareTo (data [pi]) >= 0) - break; // child item is larger than (or equal) parent so we're done - T tmp = data [ci]; - data [ci] = data [pi]; - data [pi] = tmp; - ci = pi; - } - } - - public T Dequeue() - { - // assumes pq is not empty; up to calling code - int li = data.Count - 1; // last index (before removal) - T frontItem = data [0]; // fetch the front - data [0] = data [li]; - data.RemoveAt (li); - - --li; // last index (after removal) - int pi = 0; // parent index. start at front of pq - while (true) - { - int ci = pi * 2 + 1; // left child index of parent - if (ci > li) - break; // no children so done - int rc = ci + 1; // right child - if (rc <= li && data [rc].CompareTo (data [ci]) < 0) // if there is a rc (ci + 1), and it is smaller than left child, use the rc instead - ci = rc; - if (data [pi].CompareTo (data [ci]) <= 0) - break; // parent is smaller than (or equal to) smallest child so done - T tmp = data [pi]; - data [pi] = data [ci]; - data [ci] = tmp; // swap parent and child - pi = ci; - } - - return frontItem; - } - - public T Peek () - { - T frontItem = data [0]; - return frontItem; - } - - public int Count () - { - return data.Count; - } - - public override string ToString () - { - string s = ""; - for (int i = 0; i < data.Count; ++i) - s += data [i].ToString () + " "; - s += "count = " + data.Count; - return s; - } - - public bool IsConsistent () - { - // is the heap property true for all data? - if (data.Count == 0) - return true; - int li = data.Count - 1; // last index - for (int pi = 0; pi < data.Count; ++pi) { // each parent index - int lci = 2 * pi + 1; // left child index - int rci = 2 * pi + 2; // right child index - - if (lci <= li && data [pi].CompareTo (data [lci]) > 0) - return false; // if lc exists and it's greater than parent then bad. - if (rci <= li && data [pi].CompareTo (data [rci]) > 0) - return false; // check the right child too. - } - return true; // passed all checks - } // IsConsistent -} // PriorityQueue diff --git a/ECS/DataStructures/TypeSafeDictionary.cs b/ECS/DataStructures/TypeSafeDictionary.cs deleted file mode 100644 index c7cdc14..0000000 --- a/ECS/DataStructures/TypeSafeDictionary.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Svelto.DataStructures; -using System.Collections.Generic; - -namespace Svelto.ECS.Internal -{ - /// - /// This is just a place holder at the moment - /// I always wanted to create my own Dictionary - /// data structure as excercise, but never had the - /// time to. At the moment I need the custom interface - /// wrapped though. - /// - - public interface ITypeSafeDictionary - { - void FillWithIndexedEntityViews(ITypeSafeList entityViews); - bool Remove(int entityId); - IEntityView GetIndexedEntityView(int entityID); - } - - class TypeSafeDictionary : Dictionary, ITypeSafeDictionary where TValue:IEntityView - { - internal static readonly ReadOnlyDictionary Default = - new ReadOnlyDictionary(new Dictionary()); - - public void FillWithIndexedEntityViews(ITypeSafeList entityViews) - { - int count; - var buffer = FasterList.NoVirt.ToArrayFast((FasterList) entityViews, out count); - - for (int i = 0; i < count; i++) - { - var entityView = buffer[i]; - - Add(entityView.ID, entityView); - } - } - - new public bool Remove(int entityId) - { - base.Remove(entityId); - - return this.Count > 0; - } - - public IEntityView GetIndexedEntityView(int entityID) - { - return this[entityID]; - } - } -} diff --git a/ECS/DataStructures/TypeSafeFasterListForECS.cs b/ECS/DataStructures/TypeSafeFasterListForECS.cs deleted file mode 100644 index 4f15c15..0000000 --- a/ECS/DataStructures/TypeSafeFasterListForECS.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using Svelto.DataStructures; - -namespace Svelto.ECS.Internal -{ - public interface ITypeSafeList: IEnumerable - { - void AddRange(ITypeSafeList entityViewListValue); - - ITypeSafeList Create(); - ITypeSafeList Create(int size); - bool isQueryiableEntityView { get; } - bool UnorderedRemove(int entityID); - ITypeSafeDictionary CreateIndexedDictionary(); - IEntityView[] ToArrayFast(out int count); - void ReserveCapacity(int capacity); - int GetIndexFromID(int entityID); - } - - class TypeSafeFasterListForECS: FasterList where T:IEntityView - { - protected TypeSafeFasterListForECS() - { - _mappedIndices = new Dictionary(); - } - - protected TypeSafeFasterListForECS(int size):base(size) - { - _mappedIndices = new Dictionary(); - } - - public bool UnorderedRemove(int entityID) - { - var index = _mappedIndices[entityID]; - - DesignByContract.Check.Assert(entityID == this[index].ID, "Something went wrong with the Svelto.ECS code, please contact the author"); - - _mappedIndices.Remove(entityID); - - if (UnorderedRemoveAt(index)) - _mappedIndices[this[index].ID] = index; - - return this.Count > 0; - } - - public void AddRange(ITypeSafeList entityViewListValue) - { - var index = this.Count; - - base.AddRange(entityViewListValue as FasterList); - - for (int i = index; i < Count; ++i) - _mappedIndices[this[i].ID] = i; - } - - new public void Add(T entityView) - { - var index = this.Count; - - base.Add(entityView); - - _mappedIndices[entityView.ID] = index; - } - - public void ReserveCapacity(int capacity) - { - if (this.ToArrayFast().Length < capacity) - Resize(capacity); - } - - public int GetIndexFromID(int entityID) - { - return _mappedIndices[entityID]; - } - - readonly Dictionary _mappedIndices; - } - - class TypeSafeFasterListForECSForStructs : TypeSafeFasterListForECS, ITypeSafeList where T:struct, IEntityStruct - { - public TypeSafeFasterListForECSForStructs(int size):base(size) - {} - - public TypeSafeFasterListForECSForStructs() - {} - - public ITypeSafeList Create() - { - return new TypeSafeFasterListForECSForStructs(); - } - - public bool isQueryiableEntityView - { - get { return false; } - } - - public ITypeSafeDictionary CreateIndexedDictionary() - { - throw new Exception("Not Allowed"); - } - - public IEntityView[] ToArrayFast(out int count) - { - throw new Exception("Not Allowed"); - } - - public ITypeSafeList Create(int size) - { - return new TypeSafeFasterListForECSForStructs(size); - } - } - - class TypeSafeFasterListForECSForClasses : TypeSafeFasterListForECS, ITypeSafeList where T:EntityView, new() - { - public TypeSafeFasterListForECSForClasses(int size):base(size) - {} - - public TypeSafeFasterListForECSForClasses() - {} - - public ITypeSafeList Create() - { - return new TypeSafeFasterListForECSForClasses(); - } - - public bool isQueryiableEntityView - { - get { return true; } - } - - public ITypeSafeDictionary CreateIndexedDictionary() - { - return new TypeSafeDictionary(); - } - - public IEntityView[] ToArrayFast(out int count) - { - count = this.Count; - - return this.ToArrayFast(); - } - - public ITypeSafeList Create(int size) - { - return new TypeSafeFasterListForECSForClasses(size); - } - } -} diff --git a/ECS/EngineEntityViewDB.cs b/ECS/EngineEntityViewDB.cs deleted file mode 100644 index 495073f..0000000 --- a/ECS/EngineEntityViewDB.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Collections.Generic; -using Svelto.DataStructures; -using Svelto.ECS.Internal; - -namespace Svelto.ECS -{ - public class EngineEntityViewDB : IEngineEntityViewDB - { - internal EngineEntityViewDB( Dictionary entityViewsDB, - Dictionary entityViewsDBdic, - Dictionary metaEntityViewsDB, - Dictionary> groupEntityViewsDB) - { - _entityViewsDB = entityViewsDB; - _entityViewsDBdic = entityViewsDBdic; - _metaEntityViewsDB = metaEntityViewsDB; - _groupEntityViewsDB = groupEntityViewsDB; - } - - public FasterReadOnlyList QueryEntityViews() where T:EntityView, new() - { - var type = typeof(T); - - ITypeSafeList entityViews; - - if (_entityViewsDB.TryGetValue(type, out entityViews) == false) - return RetrieveEmptyEntityViewList(); - - return new FasterReadOnlyList((FasterList)entityViews); - } - - public FasterReadOnlyList QueryGroupedEntityViews(int @group) where T:EntityView, new() - { - Dictionary entityViews; - - if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) - return RetrieveEmptyEntityViewList(); - - return new FasterReadOnlyList(entityViews as FasterList); - } - - public T[] QueryEntityViewsAsArray(out int count) where T : IEntityView - { - var type = typeof(T); - count = 0; - - ITypeSafeList entityViews; - - if (_entityViewsDB.TryGetValue(type, out entityViews) == false) - return RetrieveEmptyEntityViewArray(); - - var castedEntityViews = (FasterList)entityViews; - - count = castedEntityViews.Count; - - return castedEntityViews.ToArrayFast(); - } - - public T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T : IEntityView - { - var type = typeof(T); - count = 0; - - Dictionary entityViews; - - if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) - return RetrieveEmptyEntityViewArray(); - - var castedEntityViews = (FasterList)entityViews[type]; - - count = castedEntityViews.Count; - - return castedEntityViews.ToArrayFast(); - } - - public ReadOnlyDictionary QueryIndexableEntityViews() where T:IEntityView - { - var type = typeof(T); - - ITypeSafeDictionary entityViews; - - if (_entityViewsDBdic.TryGetValue(type, out entityViews) == false) - return TypeSafeDictionary.Default; - - return new ReadOnlyDictionary(entityViews as Dictionary); - } - - public bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView - { - var type = typeof(T); - - T internalEntityView; - - ITypeSafeDictionary entityViews; - TypeSafeDictionary casted; - - _entityViewsDBdic.TryGetValue(type, out entityViews); - casted = entityViews as TypeSafeDictionary; - - if (casted != null && - casted.TryGetValue(ID, out internalEntityView)) - { - entityView = (T)internalEntityView; - - return true; - } - - entityView = default(T); - - return false; - } - - public T QueryEntityView(int ID) where T : IEntityView - { - var type = typeof(T); - - T internalEntityView; ITypeSafeDictionary entityViews; - TypeSafeDictionary casted; - - _entityViewsDBdic.TryGetValue(type, out entityViews); - casted = entityViews as TypeSafeDictionary; - - if (casted != null && - casted.TryGetValue(ID, out internalEntityView)) - return (T)internalEntityView; - - throw new Exception("EntityView Not Found"); - } - - public T QueryMetaEntityView(int metaEntityID) where T:EntityView, new() - { - return QueryEntityView(metaEntityID); - } - - public bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T:EntityView, new() - { - return TryQueryEntityView(metaEntityID, out entityView); - } - - public FasterReadOnlyList QueryMetaEntityViews() where T:EntityView, new() - { - var type = typeof(T); - - ITypeSafeList entityViews; - - if (_metaEntityViewsDB.TryGetValue(type, out entityViews) == false) - return RetrieveEmptyEntityViewList(); - - return new FasterReadOnlyList((FasterList)entityViews); - } - - static FasterReadOnlyList RetrieveEmptyEntityViewList() - { - return FasterReadOnlyList.DefaultList; - } - - static T[] RetrieveEmptyEntityViewArray() - { - return FasterList.DefaultList.ToArrayFast(); - } - - readonly Dictionary _entityViewsDB; - readonly Dictionary _entityViewsDBdic; - readonly Dictionary _metaEntityViewsDB; - readonly Dictionary> _groupEntityViewsDB; - } -} diff --git a/ECS/EnginesRootEngines.cs b/ECS/EnginesRootEngines.cs deleted file mode 100644 index 940c5b5..0000000 --- a/ECS/EnginesRootEngines.cs +++ /dev/null @@ -1,231 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using Svelto.DataStructures; -using Svelto.ECS.Internal; -using Svelto.ECS.Schedulers; -using Svelto.Utilities; -using Svelto.WeakEvents; - -#if EXPERIMENTAL -using Svelto.ECS.Experimental; -using Svelto.ECS.Experimental.Internal; -#endif - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR -using Svelto.ECS.Profiler; -#endif - -namespace Svelto.ECS -{ - public partial class EnginesRoot : IDisposable - { - /// - /// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot - /// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks - /// periodically if new entity must be submited to the database and the engines. It's an external - /// dependencies to be indipendent by the running platform as the user can define it. - /// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why - /// it must receive a weak reference of the EnginesRoot callback. - /// - public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) - { - _entityViewEngines = new Dictionary>(); - _otherEngines = new FasterList(); - - _entityViewsDB = new Dictionary(); - _metaEntityViewsDB = new Dictionary(); - _groupEntityViewsDB = new Dictionary>(); - _entityViewsDBdic = new Dictionary(); - - _entityViewsToAdd = new DoubleBufferedEntityViews>(); - _metaEntityViewsToAdd = new DoubleBufferedEntityViews>(); - _groupedEntityViewsToAdd = new DoubleBufferedEntityViews>>(); - - _engineEntityViewDB = new EngineEntityViewDB(_entityViewsDB, _entityViewsDBdic, _metaEntityViewsDB, _groupEntityViewsDB); - - _scheduler = entityViewScheduler; - _scheduler.Schedule(new WeakAction(SubmitEntityViews)); -#if EXPERIMENTAL - _sharedStructEntityViewLists = new SharedStructEntityViewLists(); - _sharedGroupedStructEntityViewLists = new SharedGroupedStructEntityViewsLists(); - - _structEntityViewEngineType = typeof(IStructEntityViewEngine<>); - _groupedStructEntityViewsEngineType = typeof(IGroupedStructEntityViewsEngine<>); - - _implementedInterfaceTypes = new Dictionary(); -#endif -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); - debugEngineObject.gameObject.AddComponent(); -#endif - } - - public void AddEngine(IEngine engine) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - Profiler.EngineProfiler.AddEngine(engine); -#endif - var engineType = engine.GetType(); -#if EXPERIMENTAL - bool engineAdded; - - var implementedInterfaces = engineType.GetInterfaces(); - - CollectImplementedInterfaces(implementedInterfaces); - - engineAdded = CheckSpecialEngine(engine); -#endif - var viewEngine = engine as IHandleEntityViewEngine; - - if (viewEngine != null) - CheckEntityViewsEngine(viewEngine, engineType); - else - _otherEngines.Add(engine); - - var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; - if (queryableEntityViewEngine != null) - { - queryableEntityViewEngine.entityViewsDB = _engineEntityViewDB; - queryableEntityViewEngine.Ready(); - } - } - -#if EXPERIMENTAL - void CollectImplementedInterfaces(Type[] implementedInterfaces) - { - _implementedInterfaceTypes.Clear(); - - var type = typeof(IHandleEntityViewEngine); - - for (int index = 0; index < implementedInterfaces.Length; index++) - { - var interfaceType = implementedInterfaces[index]; - - if (type.IsAssignableFrom(interfaceType) == false) - continue; - - if (false == interfaceType.IsGenericTypeEx()) - { - continue; - } - - var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); - - _implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); - } - } - - bool CheckSpecialEngine(IEngine engine) - { - if (_implementedInterfaceTypes.Count == 0) return false; - - bool engineAdded = false; - - if (_implementedInterfaceTypes.ContainsKey(_structEntityViewEngineType)) - { - ((IStructEntityViewEngine)engine).CreateStructEntityViews - (_sharedStructEntityViewLists); - } - - if (_implementedInterfaceTypes.ContainsKey(_groupedStructEntityViewsEngineType)) - { - ((IGroupedStructEntityViewsEngine)engine).CreateStructEntityViews - (_sharedGroupedStructEntityViewLists); - } - - return engineAdded; - } -#endif - void CheckEntityViewsEngine(IEngine engine, Type engineType) - { - var baseType = engineType.GetBaseType(); - - if (baseType.IsGenericTypeEx()) - { - var genericArguments = baseType.GetGenericArgumentsEx(); - AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); -#if EXPERIMENTAL - var activableEngine = engine as IHandleActivableEntityEngine; - if (activableEngine != null) - AddEngine(activableEngine, genericArguments, _activableViewEntitiesEngines); -#endif - - return; - } - - throw new Exception("Not Supported Engine"); - } - - //The T parameter allows to pass datastructure sthat not necessarly are - //defined with IEngine, but must be defined with IEngine implementations - static void AddEngine(T engine, Type[] types, - Dictionary> engines) where T:IEngine - { - for (int i = 0; i < types.Length; i++) - { - FasterList list; - - var type = types[i]; - - if (engines.TryGetValue(type, out list) == false) - { - list = new FasterList(); - - engines.Add(type, list); - } - - list.Add(engine); - } - } - - readonly Dictionary> _entityViewEngines; - - readonly FasterList _otherEngines; - - readonly Dictionary _entityViewsDB; - readonly Dictionary _metaEntityViewsDB; - readonly Dictionary> _groupEntityViewsDB; - - readonly Dictionary _entityViewsDBdic; - - readonly DoubleBufferedEntityViews> _entityViewsToAdd; - readonly DoubleBufferedEntityViews> _metaEntityViewsToAdd; - readonly DoubleBufferedEntityViews>> _groupedEntityViewsToAdd; - - readonly EntitySubmissionScheduler _scheduler; -#if EXPERIMENTAL - readonly Type _structEntityViewEngineType; - readonly Type _groupedStructEntityViewsEngineType; - - readonly SharedStructEntityViewLists _sharedStructEntityViewLists; - readonly SharedGroupedStructEntityViewsLists _sharedGroupedStructEntityViewLists; - - readonly Dictionary _implementedInterfaceTypes; -#endif - - readonly EngineEntityViewDB _engineEntityViewDB; - - class DoubleBufferedEntityViews where T : class, IDictionary, new() - { - readonly T _entityViewsToAddBufferA = new T(); - readonly T _entityViewsToAddBufferB = new T(); - - internal DoubleBufferedEntityViews() - { - this.other = _entityViewsToAddBufferA; - this.current = _entityViewsToAddBufferB; - } - - internal T other; - internal T current; - - internal void Swap() - { - var toSwap = other; - other = current; - current = toSwap; - } - } - } -} \ No newline at end of file diff --git a/ECS/EnginesRootEntities.cs b/ECS/EnginesRootEntities.cs deleted file mode 100644 index 6b58966..0000000 --- a/ECS/EnginesRootEntities.cs +++ /dev/null @@ -1,375 +0,0 @@ -using System; -using System.Collections.Generic; -using Svelto.DataStructures; -using Svelto.ECS.Internal; - -#if EXPERIMENTAL -using Svelto.ECS.Experimental; -using Svelto.ECS.Experimental.Internal; -#endif - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR -using Svelto.ECS.Profiler; -#endif - -namespace Svelto.ECS -{ - public partial class EnginesRoot : IDisposable - { - /// - /// an EnginesRoot reference cannot be held by anything else than the Composition Root - /// where it has been created. IEntityFactory and IEntityFunctions allow a weakreference - /// of the EnginesRoot to be passed around. - /// - /// - public IEntityFactory GenerateEntityFactory() - { - return new GenericEntityFactory(new DataStructures.WeakReference(this)); - } - - public IEntityFunctions GenerateEntityFunctions() - { - return new GenericEntityFunctions(new DataStructures.WeakReference(this)); - } - - /// - /// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity - /// itself in terms of EntityViews to build. The Implementors are passed to fill the - /// references of the EntityViews components. Please read the articles on my blog - /// to understand better the terminologies - /// - /// - /// - /// - void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() - { - EntityFactory.BuildEntityViews - (entityID, _entityViewsToAdd.current, EntityDescriptorTemplate.Default, implementors); - } - - /// - /// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo - /// can be built in place of the generic parameter T. - /// - /// - /// - /// - void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - EntityFactory.BuildEntityViews - (entityID, _entityViewsToAdd.current, entityDescriptor, implementors); - } - - /// - /// A meta entity is a way to manage a set of entitites that are not easily - /// queriable otherwise. For example you may want to group existing entities - /// by size and type and then use the meta entity entityView to manage the data - /// shared among the single entities of the same type and size. This will - /// prevent the scenario where the coder is forced to parse all the entities to - /// find the ones of the same size and type. - /// Since the entities are managed through the shared entityView, the same - /// shared entityView must be found on the single entities of the same type and size. - /// The shared entityView of the meta entity is then used by engines that are meant - /// to manage a group of entities through a single entityView. - /// The same engine can manage several meta entities entityViews too. - /// The Engine manages the logic of the Meta EntityView data and other engines - /// can read back this data through the normal entity as the shared entityView - /// will be present in their descriptor too. - /// It's a way to control a group of Entities through a entityView only. - /// This set of entities can share exactly the same entityView reference if - /// built through this function. In this way, if you need to set a variable - /// on a group of entities, instead to inject N entityViews and iterate over - /// them to set the same value, you can inject just one entityView, set the value - /// and be sure that the value is shared between entities. - /// - /// - /// - /// - void BuildMetaEntity(int metaEntityID, object[] implementors) where T : IEntityDescriptor, new() - { - EntityFactory.BuildEntityViews(metaEntityID, _entityViewsToAdd.current, - EntityDescriptorTemplate.Default, implementors); - } - - /// - /// Using this function is like building a normal entity, but the entityViews - /// are grouped by groupID to be more efficently processed inside engines and - /// improve cache locality. Either class entityViews and struct entityViews can be - /// grouped. - /// - /// - /// - /// - /// - void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() - { - EntityFactory.BuildGroupedEntityViews(entityID, groupID, - _groupedEntityViewsToAdd.current, - EntityDescriptorTemplate.Default, - implementors); - } - - void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - EntityFactory.BuildGroupedEntityViews(entityID, groupID, - _groupedEntityViewsToAdd.current, - entityDescriptor, implementors); - } - - void Preallocate(int size) where T : IEntityDescriptor, new() - { - var entityViewsToBuild = EntityDescriptorTemplate.Default.entityViewsToBuild; - int count = entityViewsToBuild.Length; - - for (int index = 0; index < count; index++) - { - var entityViewBuilder = entityViewsToBuild[index]; - var entityViewType = entityViewBuilder.GetEntityViewType(); - - ITypeSafeList dbList; - if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) - _entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); - else - dbList.ReserveCapacity(size); - - if (_entityViewsToAdd.current.TryGetValue(entityViewType, out dbList) == false) - _entityViewsToAdd.current[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); - else - dbList.ReserveCapacity(size); - } - } - - void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) - { - var removeEntityImplementor = removeInfo as RemoveEntityImplementor; - - if (removeEntityImplementor.isInAGroup) - InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, removeEntityImplementor.groupID, _entityViewsDB); - else - InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, _entityViewsDB); - } - - void RemoveEntity(int entityID) where T : IEntityDescriptor, new() - { - InternalRemove(EntityDescriptorTemplate.Default.entityViewsToBuild, entityID, _entityViewsDB); - } - - void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() - { - InternalRemove(EntityDescriptorTemplate.Default.entityViewsToBuild, metaEntityID, _metaEntityViewsDB); - } - - void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() - { - InternalRemove(EntityDescriptorTemplate.Default.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); - } - - void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() - { - DesignByContract.Check.Require(fromGroupID != toGroupID, "can't move an entity to the same group where it already belongs to"); - - var entityViewBuilders = EntityDescriptorTemplate.Default.entityViewsToBuild; - int entityViewBuildersCount = entityViewBuilders.Length; - - Dictionary dictionary = _groupEntityViewsDB[fromGroupID]; - - Dictionary groupedEntityViewsTyped; - if (_groupEntityViewsDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) - { - groupedEntityViewsTyped = new Dictionary(); - - _groupEntityViewsDB.Add(toGroupID, groupedEntityViewsTyped); - } - - for (int i = 0; i < entityViewBuildersCount; i++) - { - IEntityViewBuilder entityViewBuilder = entityViewBuilders[i]; - Type entityViewType = entityViewBuilder.GetEntityViewType(); - - ITypeSafeList fromSafeList = dictionary[entityViewType]; - ITypeSafeList toSafeList; - - if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) - { - toSafeList = fromSafeList.Create(); - } - - entityViewBuilder.MoveEntityView(entityID, fromSafeList, toSafeList); - - if (fromSafeList.UnorderedRemove(entityID) == false) - dictionary.Remove(entityViewType); - } - - if (dictionary.Count == 0) _groupEntityViewsDB.Remove(fromGroupID); - } - - void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, - Dictionary entityViewsDB) - { - int entityViewBuildersCount = entityViewBuilders.Length; - - for (int i = 0; i < entityViewBuildersCount; i++) - { - Type entityViewType = entityViewBuilders[i].GetEntityViewType(); - - ITypeSafeList entityViews = entityViewsDB[entityViewType]; - if (entityViews.UnorderedRemove(entityID) == false) - entityViewsDB.Remove(entityViewType); - - if (entityViews.isQueryiableEntityView) - { - var typeSafeDictionary = _entityViewsDBdic[entityViewType]; - var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); - - if (typeSafeDictionary.Remove(entityID) == false) - _entityViewsDBdic.Remove(entityViewType); - - RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType); - } - } - } - - void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, - Dictionary entityViewsDB) - { - InternalRemoveFromDB(entityViewBuilders, entityID, groupID); - - InternalRemove(entityViewBuilders, entityID, entityViewsDB); - } - - void InternalRemoveFromDB(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID) - { - int entityViewBuildersCount = entityViewBuilders.Length; - - Dictionary dictionary = _groupEntityViewsDB[groupID]; - - for (int i = 0; i < entityViewBuildersCount; i++) - { - Type entityViewType = entityViewBuilders[i].GetEntityViewType(); - - if (dictionary[entityViewType].UnorderedRemove(entityID) == false) - dictionary.Remove(entityViewType); - } - - if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); - } - - static void RemoveEntityViewFromEngines(Dictionary> entityViewEngines, - IEntityView entityView, Type entityViewType) - { - FasterList enginesForEntityView; - - if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) - { - int count; - var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); - - for (int j = 0; j < count; j++) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(fastList[j], entityView); -#else - fastList[j].Remove(entityView); -#endif - } - } - } - - class GenericEntityFactory : IEntityFactory - { - DataStructures.WeakReference _weakEngine; - - public GenericEntityFactory(DataStructures.WeakReference weakReference) - { - _weakEngine = weakReference; - } - - public void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() - { - _weakEngine.Target.BuildEntity(entityID, implementors); - } - - public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - _weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); - } - - public void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() - { - _weakEngine.Target.BuildMetaEntity(metaEntityID, implementors); - } - - public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() - { - _weakEngine.Target.BuildEntityInGroup(entityID, groupID, implementors); - } - - public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); - } - - public void Preallocate(int size) where T : IEntityDescriptor, new() - { - _weakEngine.Target.Preallocate(size); - } - } - - class GenericEntityFunctions : IEntityFunctions - { - public GenericEntityFunctions(DataStructures.WeakReference weakReference) - { - _weakReference = weakReference; - } - - public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) - { - _weakReference.Target.RemoveEntity(entityID, removeInfo); - } - - public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() - { - _weakReference.Target.RemoveEntity(entityID); - } - - public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() - { - _weakReference.Target.RemoveEntity(metaEntityID); - } - - public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() - { - _weakReference.Target.RemoveEntity(entityID); - } - - public void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() - { - _weakReference.Target.SwapEntityGroup(entityID, fromGroupID, toGroupID); - } - - readonly DataStructures.WeakReference _weakReference; - } - - public void Dispose() - { - foreach (var entity in _entityViewsDB) - { - if (entity.Value.isQueryiableEntityView == true) - { - foreach (var entityView in entity.Value) - { - RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); - } - } - } - - foreach (var entity in _metaEntityViewsDB) - { - foreach (var entityView in entity.Value) - { - RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); - } - } - } - } -} \ No newline at end of file diff --git a/ECS/EnginesRootSubmission.cs b/ECS/EnginesRootSubmission.cs deleted file mode 100644 index 894881a..0000000 --- a/ECS/EnginesRootSubmission.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Collections.Generic; -using Svelto.DataStructures; -using Svelto.ECS.Internal; - -#if EXPERIMENTAL -using Svelto.ECS.Experimental; -using Svelto.ECS.Experimental.Internal; -#endif - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR -using Svelto.ECS.Profiler; -#endif - -namespace Svelto.ECS -{ - public partial class EnginesRoot : IDisposable - { - void SubmitEntityViews() - { - bool newEntityViewsHaveBeenAddedWhileIterating = - _metaEntityViewsToAdd.current.Count > 0 - || _entityViewsToAdd.current.Count > 0 - || _groupedEntityViewsToAdd.current.Count > 0; - - int numberOfReenteringLoops = 0; - - while (newEntityViewsHaveBeenAddedWhileIterating) - { - //use other as source from now on - //current will be use to write new entityViews - _entityViewsToAdd.Swap(); - _metaEntityViewsToAdd.Swap(); - _groupedEntityViewsToAdd.Swap(); - - if (_entityViewsToAdd.other.Count > 0) - AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB); - - if (_metaEntityViewsToAdd.other.Count > 0) - AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); - - if (_groupedEntityViewsToAdd.other.Count > 0) - AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); - - //other can be cleared now - _entityViewsToAdd.other.Clear(); - _metaEntityViewsToAdd.other.Clear(); - _groupedEntityViewsToAdd.other.Clear(); - - //has current new entityViews? - newEntityViewsHaveBeenAddedWhileIterating = - _metaEntityViewsToAdd.current.Count > 0 - || _entityViewsToAdd.current.Count > 0 - || _groupedEntityViewsToAdd.current.Count > 0; - - if (numberOfReenteringLoops > 5) - throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); - - numberOfReenteringLoops++; - } - } - - void AddEntityViewsToTheDBAndSuitableEngines(Dictionary entityViewsToAdd, - Dictionary entityViewsDB) - { - foreach (var entityViewList in entityViewsToAdd) - { - AddEntityViewToDB(entityViewsDB, entityViewList); - - if (entityViewList.Value.isQueryiableEntityView) - { - AddEntityViewToEntityViewsDictionary(_entityViewsDBdic, entityViewList.Value, entityViewList.Key); - } - } - - foreach (var entityViewList in entityViewsToAdd) - { - if (entityViewList.Value.isQueryiableEntityView) - { - AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, - entityViewList.Key); - } - } - } - - void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary> groupedEntityViewsToAdd, - Dictionary> groupEntityViewsDB, - Dictionary entityViewsDB) - { - foreach (var group in groupedEntityViewsToAdd) - { - AddEntityViewsToGroupDB(groupEntityViewsDB, @group); - - AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); - } - } - - static void AddEntityViewsToGroupDB(Dictionary> groupEntityViewsDB, - KeyValuePair> @group) - { - Dictionary groupedEntityViewsByType; - - if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) - groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary(); - - foreach (var entityView in @group.Value) - { - groupedEntityViewsByType.Add(entityView.Key, entityView.Value); - } - } - - static void AddEntityViewToDB(Dictionary entityViewsDB, KeyValuePair entityViewList) - { - ITypeSafeList dbList; - - if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) - dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); - - dbList.AddRange(entityViewList.Value); - } - - static void AddEntityViewToEntityViewsDictionary(Dictionary entityViewsDBdic, - ITypeSafeList entityViews, Type entityViewType) - { - ITypeSafeDictionary entityViewsDic; - - if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) - entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); - - entityViewsDic.FillWithIndexedEntityViews(entityViews); - } - - static void AddEntityViewToTheSuitableEngines(Dictionary> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) - { - FasterList enginesForEntityView; - - if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) - { - int viewsCount; - - var entityViews = entityViewsList.ToArrayFast(out viewsCount); - - for (int i = 0; i < viewsCount; i++) - { - int count; - var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); - IEntityView entityView = entityViews[i]; - for (int j = 0; j < count; j++) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorAddDuration(fastList[j], entityView); -#else - fastList[j].Add(entityView); -#endif - } - } - } - } - } -} \ No newline at end of file diff --git a/ECS/EntitySubmissionScheduler.cs b/ECS/EntitySubmissionScheduler.cs deleted file mode 100644 index cfa8168..0000000 --- a/ECS/EntitySubmissionScheduler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Svelto.WeakEvents; - -namespace Svelto.ECS.Schedulers -{ - public abstract class EntitySubmissionScheduler - { - abstract public void Schedule(WeakAction submitEntityViews); - } -} \ No newline at end of file diff --git a/ECS/EntityView.cs b/ECS/EntityView.cs deleted file mode 100644 index 4846935..0000000 --- a/ECS/EntityView.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using Svelto.DataStructures; -using Svelto.Utilities; - -namespace Svelto.ECS -{ - public interface IEntityView - { - int ID { get; } - } - - public interface IEntityStruct:IEntityView - { - new int ID { set; } - } - - public class EntityView : IEntityView - { - public int ID { get { return _ID; } } - - internal FasterList>> entityViewBlazingFastReflection; - internal int _ID; - } - - internal static class EntityView where T: EntityView, new() - { - internal static T BuildEntityView(int ID) - { - if (FieldCache.list.Count == 0) - { - var type = typeof(T); - - var fields = type.GetFields(BindingFlags.Public | - BindingFlags.Instance); - - for (int i = fields.Length - 1; i >= 0; --i) - { - var field = fields[i]; - - CastedAction setter = FastInvoke.MakeSetter(field); - - FieldCache.list.Add(new KeyValuePair>(field.FieldType, setter)); - } - } - - return new T { _ID = ID, entityViewBlazingFastReflection = FieldCache.list }; - } - - static class FieldCache where W:T - { - internal static readonly FasterList>> list = new FasterList>>(); - } - } -} - diff --git a/ECS/EntityViewBuilder.cs b/ECS/EntityViewBuilder.cs deleted file mode 100644 index 73606af..0000000 --- a/ECS/EntityViewBuilder.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using Svelto.ECS.Internal; - -namespace Svelto.ECS -{ - public interface IEntityViewBuilder - { - void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView); - ITypeSafeList Preallocate(ref ITypeSafeList list, int size); - - Type GetEntityViewType(); - void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList); - } - - public class EntityViewBuilder : IEntityViewBuilder where EntityViewType : EntityView, new() - { - public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) - { - if (list == null) - list = new TypeSafeFasterListForECSForClasses(); - - var castedList = list as TypeSafeFasterListForECSForClasses; - - var lentityView = EntityView.BuildEntityView(entityID); - - castedList.Add(lentityView); - - entityView = lentityView; - } - - public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) - { - if (list == null) - list = new TypeSafeFasterListForECSForClasses(size); - else - list.ReserveCapacity(size); - - return list; - } - - public Type GetEntityViewType() - { - return _entityViewType; - } - - public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) - { - var fromCastedList = fromSafeList as TypeSafeFasterListForECSForClasses; - var toCastedList = toSafeList as TypeSafeFasterListForECSForClasses; - - toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); - } - - readonly Type _entityViewType = typeof(EntityViewType); - } - - public class EntityStructBuilder : IEntityViewBuilder where EntityViewType : struct, IEntityStruct - { - public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) - { - var lentityView = default(EntityViewType); - lentityView.ID = entityID; - - if (list == null) - list = new TypeSafeFasterListForECSForStructs(); - - var castedList = list as TypeSafeFasterListForECSForStructs; - - castedList.Add(lentityView); - - entityView = null; - } - - public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) - { - if (list == null) - list = new TypeSafeFasterListForECSForStructs(size); - else - list.ReserveCapacity(size); - - return list; - } - - public Type GetEntityViewType() - { - return _entityViewType; - } - - public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) - { - var fromCastedList = fromSafeList as TypeSafeFasterListForECSForStructs; - var toCastedList = toSafeList as TypeSafeFasterListForECSForStructs; - - toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); - } - - readonly Type _entityViewType = typeof(EntityViewType); - } -} \ No newline at end of file diff --git a/ECS/Experimental/StructNodeCollections.cs b/ECS/Experimental/StructNodeCollections.cs deleted file mode 100644 index e9e76e2..0000000 --- a/ECS/Experimental/StructNodeCollections.cs +++ /dev/null @@ -1,178 +0,0 @@ -using System; -using System.Collections.Generic; -using Svelto.DataStructures; -using Svelto.ECS.Experimental.Internal; - -namespace Svelto.ECS.Experimental.Internal -{ - public interface IStructEntityViewEngine : IEngine - { - void CreateStructEntityViews(SharedStructEntityViewLists sharedStructEntityViewLists); - } - - public interface IGroupedStructEntityViewsEngine : IEngine - { - void CreateStructEntityViews(SharedGroupedStructEntityViewsLists sharedStructEntityViewLists); - } -} - -namespace Svelto.ECS.Experimental -{ - public interface IGroupedEntityView - { - int groupID { get; set; } - } - - /// - /// The engines can receive and store IEntityViews structs - /// Unboxing will happen during the Add, but the - /// data will then be stored and processed as stucts - /// - public interface IStructEntityViewEngine : IStructEntityViewEngine where T:struct, IEntityStruct - { } - - /// - /// same as above, but the entityViews are grouped by ID - /// usually the ID is the owner of the entityViews of that - /// group - /// - public interface IGroupedStructEntityViewsEngine : IGroupedStructEntityViewsEngine where T : struct, IGroupedEntityView - { - void Add(ref T entityView); - void Remove(ref T entityView); - } - - public sealed class StructEntityViews where T:struct, IEntityStruct - { - public T[] GetList(out int numberOfItems) - { - numberOfItems = _internalList.Count; - return _internalList.ToArrayFast(); - } - - public StructEntityViews(SharedStructEntityViewLists container) - { - _internalList = SharedStructEntityViewLists.NoVirt.GetList(container); - } - - public void Add(T entityView) - { - T convert = (T)entityView; - - _internalList.Add(convert); - } - - readonly FasterList _internalList; - } - - public struct StructGroupEntityViews - where T : struct, IEntityView - { - public StructGroupEntityViews(SharedGroupedStructEntityViewsLists container) - { - _container = container; - indices = new Dictionary(); - } - - public void Add(int groupID, T entityView) - { - T convert = (T)entityView; - - var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); - indices[entityView.ID] = fasterList.Count; - - fasterList.Add(convert); - } - - public void Remove(int groupID, T entityView) - { - var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); - var index = indices[entityView.ID]; - indices.Remove(entityView.ID); - - if (fasterList.UnorderedRemoveAt(index)) - indices[fasterList[index].ID] = index; - } - - public T[] GetList(int groupID, out int numberOfItems) - { - var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList(_container, groupID) as FasterList); - - return FasterList.NoVirt.ToArrayFast(fasterList, out numberOfItems); - } - - readonly SharedGroupedStructEntityViewsLists _container; - readonly Dictionary indices; - } - - public class SharedStructEntityViewLists - { - internal SharedStructEntityViewLists() - { - _collection = new Dictionary(); - } - - internal static class NoVirt - { - internal static FasterList GetList(SharedStructEntityViewLists obj) where T : struct - { - IFasterList list; - if (obj._collection.TryGetValue(typeof(T), out list)) - { - return list as FasterList; - } - - list = new FasterList(); - - obj._collection.Add(typeof(T), list); - - return (FasterList)list; - } - } - - readonly Dictionary _collection; - } - - public class SharedGroupedStructEntityViewsLists - { - internal SharedGroupedStructEntityViewsLists() - { - _collection = new Dictionary>(); - } - - internal static class NoVirt - { - internal static IFasterList GetList(SharedGroupedStructEntityViewsLists list, int groupID) where T : struct - { - Dictionary dic = GetGroup(list); - IFasterList localList; - - if (dic.TryGetValue(groupID, out localList)) - return localList; - - localList = new FasterList(); - dic.Add(groupID, localList); - - return localList; - } - - internal static Dictionary GetGroup(SharedGroupedStructEntityViewsLists list) where T : struct - { - Dictionary dic; - - if (list._collection.TryGetValue(typeof(T), out dic)) - { - return dic; - } - - dic = new Dictionary(); - - list._collection.Add(typeof(T), dic); - - return dic; - } - } - - readonly Dictionary> _collection; - } -} \ No newline at end of file diff --git a/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs b/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs deleted file mode 100644 index 9a21176..0000000 --- a/ECS/Extensions/Unity/GenericEntityDescriptorHolder.cs +++ /dev/null @@ -1,14 +0,0 @@ -#if UNITY_5 || UNITY_5_3_OR_NEWER -namespace Svelto.ECS -{ - public class GenericEntityDescriptorHolder: - UnityEngine.MonoBehaviour, IEntityDescriptorHolder - where T: class, IEntityDescriptor, new() - { - public EntityDescriptorInfo RetrieveDescriptor() - { - return EntityDescriptorTemplate.Default; - } - } -} -#endif \ No newline at end of file diff --git a/ECS/IEngineEntityViewDB.cs b/ECS/IEngineEntityViewDB.cs deleted file mode 100644 index 571f3f8..0000000 --- a/ECS/IEngineEntityViewDB.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Svelto.DataStructures; - -namespace Svelto.ECS -{ - public interface IEngineEntityViewDB - { - FasterReadOnlyList QueryEntityViews() where T:EntityView, new(); - FasterReadOnlyList QueryMetaEntityViews() where T: EntityView, new(); - FasterReadOnlyList QueryGroupedEntityViews(int group) where T: EntityView, new(); - - T[] QueryEntityViewsAsArray(out int count) where T: IEntityView; - T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T: IEntityView; - - ReadOnlyDictionary QueryIndexableEntityViews() where T: IEntityView; - bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView; - T QueryEntityView(int ID) where T: IEntityView; - - bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T: EntityView, new(); - T QueryMetaEntityView(int metaEntityID) where T: EntityView, new(); - } -} - diff --git a/ECS/IEnginesInterfaces.cs b/ECS/IEnginesInterfaces.cs deleted file mode 100644 index fe0494b..0000000 --- a/ECS/IEnginesInterfaces.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Svelto.ECS -{ - public interface IEntityFactory - { - void Preallocate(int size) where T : IEntityDescriptor, new(); - - void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new(); - void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null); - - void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T:IEntityDescriptor, new(); - - void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new(); - void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null); - } - - public interface IEntityFunctions - { - void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo); - void RemoveEntity(int entityID) where T:IEntityDescriptor, new(); - - void RemoveMetaEntity(int metaEntityID) where T:IEntityDescriptor, new(); - - void RemoveEntityFromGroup(int entityID, int groupID) where T:IEntityDescriptor, new(); - - void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new(); - } -} diff --git a/ECS/MixedEntityDescriptor.cs b/ECS/MixedEntityDescriptor.cs deleted file mode 100644 index f91ad54..0000000 --- a/ECS/MixedEntityDescriptor.cs +++ /dev/null @@ -1,107 +0,0 @@ -namespace Svelto.ECS -{ - public class MixedEntityDescriptor:IEntityDescriptor where T : class, IEntityViewBuilder, new() - { - static MixedEntityDescriptor() - { - _entityViewsToBuild = new IEntityViewBuilder[] {new T()}; - } - - public IEntityViewBuilder[] entityViewsToBuild - { - get { return _entityViewsToBuild; } - } - - static readonly IEntityViewBuilder[] _entityViewsToBuild; - } - - public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() - where U : class, IEntityViewBuilder, new() - { - static MixedEntityDescriptor() - { - _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U()}; - } - - public IEntityViewBuilder[] entityViewsToBuild - { - get { return _entityViewsToBuild; } - } - - static readonly IEntityViewBuilder[] _entityViewsToBuild; - } - - public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() - where U : class, IEntityViewBuilder, new() - where V : class, IEntityViewBuilder, new() - { - static MixedEntityDescriptor() - { - _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V()}; - } - - public IEntityViewBuilder[] entityViewsToBuild - { - get { return _entityViewsToBuild; } - } - - static readonly IEntityViewBuilder[] _entityViewsToBuild; - } - - public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() - where U : class, IEntityViewBuilder, new() - where V : class, IEntityViewBuilder, new() - where W : class, IEntityViewBuilder, new() - { - static MixedEntityDescriptor() - { - _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W()}; - } - - public IEntityViewBuilder[] entityViewsToBuild - { - get { return _entityViewsToBuild; } - } - - static readonly IEntityViewBuilder[] _entityViewsToBuild; - } - - public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() - where U : class, IEntityViewBuilder, new() - where V : class, IEntityViewBuilder, new() - where W : class, IEntityViewBuilder, new() - where X : class, IEntityViewBuilder, new() - { - static MixedEntityDescriptor() - { - _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X()}; - } - - public IEntityViewBuilder[] entityViewsToBuild - { - get { return _entityViewsToBuild; } - } - - static readonly IEntityViewBuilder[] _entityViewsToBuild; - } - - public class MixedEntityDescriptor : IEntityDescriptor where T : class, IEntityViewBuilder, new() - where U : class, IEntityViewBuilder, new() - where V : class, IEntityViewBuilder, new() - where W : class, IEntityViewBuilder, new() - where X : class, IEntityViewBuilder, new() - where Y : class, IEntityViewBuilder, new() - { - static MixedEntityDescriptor() - { - _entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X(), new Y()}; - } - - public IEntityViewBuilder[] entityViewsToBuild - { - get { return _entityViewsToBuild; } - } - - static readonly IEntityViewBuilder[] _entityViewsToBuild; - } -} diff --git a/ECS/MultiEntityViewsEngine.cs b/ECS/MultiEntityViewsEngine.cs deleted file mode 100644 index 895a48b..0000000 --- a/ECS/MultiEntityViewsEngine.cs +++ /dev/null @@ -1,87 +0,0 @@ -using Svelto.ECS.Internal; - -namespace Svelto.ECS.Internal -{ - public abstract class MultiEntityViewsEngine:IHandleEntityViewEngine where T:EntityView, new() - { - protected abstract void Add(T entityView); - protected abstract void Remove(T entityView); - - public virtual void Add(IEntityView entityView) - { - Add((T) entityView); - } - - public virtual void Remove(IEntityView entityView) - { - Remove((T) entityView); - } - } -} - -namespace Svelto.ECS -{ - public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine - where T:EntityView, new() - where U:EntityView, new() - { - protected abstract void Add(U entityView); - protected abstract void Remove(U entityView); - - public override void Add(IEntityView entityView) - { - var castedEntityView = entityView as U; - if (castedEntityView != null) - { - Add(castedEntityView); - } - else - { - base.Add(entityView); - } - } - - public override void Remove(IEntityView entityView) - { - if (entityView is U) - { - Remove((U) entityView); - } - else - { - base.Remove(entityView); - } - } - } - - public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine - where T : EntityView, new() - where U : EntityView, new() - where V : EntityView, new() - { - protected abstract void Add(V entityView); - protected abstract void Remove(V entityView); - - public override void Add(IEntityView entityView) - { - var castedEntityView = entityView as V; - if (castedEntityView != null) - { - Add(castedEntityView); - } - else - base.Add(entityView); - } - - public override void Remove(IEntityView entityView) - { - var castedEntityView = entityView as V; - if (castedEntityView != null) - { - Remove(castedEntityView); - } - else - base.Remove(entityView); - } - } -} \ No newline at end of file diff --git a/ECS/RemoveEntityImplementor.cs b/ECS/RemoveEntityImplementor.cs deleted file mode 100644 index 7bd03b3..0000000 --- a/ECS/RemoveEntityImplementor.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Svelto.ECS.Internal -{ - sealed class RemoveEntityImplementor : IRemoveEntityComponent - { - public RemoveEntityImplementor(IEntityViewBuilder[] entityViews, int groupID):this(entityViews) - { - this.groupID = groupID; - isInAGroup = true; - } - - internal RemoveEntityImplementor(IEntityViewBuilder[] entityViews) - { - removeEntityInfo = new RemoveEntityInfo(entityViews); - } - - readonly internal RemoveEntityInfo removeEntityInfo; - readonly internal int groupID; - readonly internal bool isInAGroup; - } -} - -namespace Svelto.ECS -{ - public interface IRemoveEntityComponent - {} - - public struct RemoveEntityInfo - { - readonly internal IEntityViewBuilder[] entityViewsToBuild; - - public RemoveEntityInfo(IEntityViewBuilder[] entityViews) : this() - { - this.entityViewsToBuild = entityViews; - } - } -} diff --git a/ECS/SingleEntityViewEngine.cs b/ECS/SingleEntityViewEngine.cs deleted file mode 100644 index 605f775..0000000 --- a/ECS/SingleEntityViewEngine.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Svelto.ECS.Internal; - -namespace Svelto.ECS -{ - public abstract class SingleEntityViewEngine : IHandleEntityViewEngine where T:EntityView, new() - { - public void Add(IEntityView entityView) - { - Add((T)entityView); //when byref returns will be vailable, this should be passed by reference, not copy! - } - - public void Remove(IEntityView entityView) - { - Remove((T)entityView); - } - - protected abstract void Add(T entityView); - protected abstract void Remove(T entityView); - } -} diff --git a/Observer/Observable.cs b/Observer/Observable.cs deleted file mode 100644 index 0741b1b..0000000 --- a/Observer/Observable.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; - -namespace Svelto.Observer -{ - public delegate void ObserverAction(ref DispatchType parameter); - - public interface IObservable - { - event Action Notify; - - void Dispatch(); - } - - public interface IObservable - { - event ObserverAction Notify; - - void Dispatch(ref DispatchType parameter); - } - - public class Observable:IObservable - { - public event ObserverAction Notify; - - public void Dispatch(ref DispatchType parameter) - { - if (Notify != null) - Notify(ref parameter); - } - } - - public class Observable:IObservable - { - public event Action Notify; - - public void Dispatch() - { - if (Notify != null) - Notify(); - } - } -} diff --git a/Observer/Observer.cs b/Observer/Observer.cs deleted file mode 100644 index 7871f47..0000000 --- a/Observer/Observer.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; - -namespace Svelto.Observer.InterNamespace -{ - public abstract class Observer : IObserver - { - protected Observer(Observable observable) - { - observable.Notify += OnObservableDispatched; - - _unsubscribe = () => observable.Notify -= OnObservableDispatched; - } - - public void AddAction(ObserverAction action) - { - _actions += action; - } - - public void RemoveAction(ObserverAction action) - { - _actions -= action; - } - - public void Unsubscribe() - { - _unsubscribe(); - } - - void OnObservableDispatched(ref DispatchType dispatchNotification) - { - if (_actions != null) - { - var actionType = TypeMap(ref dispatchNotification); - - _actions(ref actionType); - } - } - - protected abstract ActionType TypeMap(ref DispatchType dispatchNotification); - - ObserverAction _actions; - Action _unsubscribe; - } -} - -namespace Svelto.Observer.IntraNamespace -{ - public class Observer : InterNamespace.Observer - { - public Observer(Observable observable) : base(observable) - { } - - protected override DispatchType TypeMap(ref DispatchType dispatchNotification) - { - return dispatchNotification; - } - } -} - -namespace Svelto.Observer -{ - public class Observer: IObserver - { - public Observer(Observable observable) - { - observable.Notify += OnObservableDispatched; - - _unsubscribe = () => observable.Notify -= OnObservableDispatched; - } - - public void AddAction(Action action) - { - _actions += action; - } - - public void RemoveAction(Action action) - { - _actions -= action; - } - - public void Unsubscribe() - { - _unsubscribe(); - } - - void OnObservableDispatched() - { - if (_actions != null) - _actions(); - } - - Action _actions; - readonly Action _unsubscribe; - } - - public interface IObserver - { - void AddAction(ObserverAction action); - void RemoveAction(ObserverAction action); - - void Unsubscribe(); - } - - public interface IObserver - { - void AddAction(Action action); - void RemoveAction(Action action); - - void Unsubscribe(); - } -} \ No newline at end of file diff --git a/Utilities/FastInvoke.cs b/Utilities/FastInvoke.cs deleted file mode 100644 index c989b28..0000000 --- a/Utilities/FastInvoke.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Reflection; -using System.Reflection.Emit; -using System.Linq.Expressions; - -namespace Svelto.Utilities -{ - //https://stackoverflow.com/questions/321650/how-do-i-set-a-field-value-in-an-c-sharp-expression-tree/321686#321686 - - public static class FastInvoke where T : class - { -#if ENABLE_IL2CPP - public static CastedAction MakeSetter(FieldInfo field) where CastedType:class - { - if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) - { - return new CastedAction(field.SetValue); - } - - throw new ArgumentException("Svelto.ECS unsupported field (must be an interface and a class)"); - } -#elif !NETFX_CORE - public static CastedAction MakeSetter(FieldInfo field) where CastedType:class - { - if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) - { - DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] { typeof(T), typeof(object) }); - ILGenerator cg = m.GetILGenerator(); - - // arg0. = arg1 - cg.Emit(OpCodes.Ldarg_0); - cg.Emit(OpCodes.Ldarg_1); - cg.Emit(OpCodes.Stfld, field); - cg.Emit(OpCodes.Ret); - - var del = m.CreateDelegate(typeof(Action)); - - return new CastedAction(del); - } - - throw new ArgumentException("Svelto.ECS unsupported field (must be an interface and a class)"); - } -#else - public static CastedAction MakeSetter(FieldInfo field) where CastedType:class - { - if (field.FieldType.IsInterfaceEx() == true && field.FieldType.IsValueTypeEx() == false) - { - ParameterExpression targetExp = Expression.Parameter(typeof(T), "target"); - ParameterExpression valueExp = Expression.Parameter(typeof(object), "value"); - - MemberExpression fieldExp = Expression.Field(targetExp, field); - UnaryExpression convertedExp = Expression.TypeAs(valueExp, field.FieldType); - BinaryExpression assignExp = Expression.Assign(fieldExp, convertedExp); - - Type type = typeof(Action<,>).MakeGenericType(new Type[] { typeof(T), typeof(object) }); - - var setter = Expression.Lambda(type, assignExp, targetExp, valueExp).Compile(); - - return new CastedAction(setter); - } - - throw new ArgumentException("Svelto.ECS unsupported field (must be an interface and a class)"); - } -#endif - } - - public abstract class CastedAction - { - abstract public void Call(W target, object value); - } - - public class CastedAction : CastedAction where W : class where T:class - { - Action setter; - - public CastedAction(Delegate setter) - { - this.setter = (Action)setter; - } - - public CastedAction(Action setter) - { - this.setter = setter; - } - - override public void Call(W target, object value) - { - setter(target as T, value); - } - } -} \ No newline at end of file diff --git a/Utilities/NetFXCoreWrappers.cs b/Utilities/NetFXCoreWrappers.cs deleted file mode 100644 index 1fa798a..0000000 --- a/Utilities/NetFXCoreWrappers.cs +++ /dev/null @@ -1,170 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.CompilerServices; -using Svelto.DataStructures; - - public static class NetFXCoreWrappers - { - public static Type GetDeclaringType(this MethodInfo methodInfo) - { -#if NETFX_CORE - return methodInfo.DeclaringType; -#else - return methodInfo.ReflectedType; -#endif - } - - public static MethodInfo GetMethodInfoEx(this Delegate delegateEx) - { -#if NETFX_CORE - var method = delegateEx.GetMethodInfo(); -#else - var method = delegateEx.Method; -#endif - return method; - } - - public static Type[] GetInterfacesEx(this Type type) - { -#if NETFX_CORE - return type.GetInterfaces(); -#else - return type.GetInterfaces(); -#endif - } - - public static bool IsInterfaceEx(this Type type) - { -#if NETFX_CORE - return type.GetTypeInfo().IsInterface; -#else - return type.IsInterface; -#endif - } - - public static bool IsValueTypeEx(this Type type) - { -#if NETFX_CORE - return type.GetTypeInfo().IsValueType; -#else - return type.IsValueType; -#endif - } - - public static Type GetDeclaringType(this MemberInfo memberInfo) - { -#if NETFX_CORE - return memberInfo.DeclaringType; -#else - return memberInfo.ReflectedType; -#endif - } - - public static Type GetBaseType(this Type type) - { -#if NETFX_CORE - return type.GetTypeInfo().BaseType; -#else - return type.BaseType; -#endif - } - - public static IEnumerable GetCustomAttributes(this Type type, bool inherit) - { -#if !NETFX_CORE - return Attribute.GetCustomAttributes(type, inherit); -#else - return type.GetTypeInfo().GetCustomAttributes(inherit); -#endif - } - - public static bool ContainsCustomAttribute(this MemberInfo memberInfo, Type customAttribute, bool inherit) - { -#if !NETFX_CORE - return Attribute.IsDefined(memberInfo, customAttribute, inherit); -#else - return memberInfo.GetCustomAttribute(customAttribute, inherit) != null; -#endif - } - - public static bool IsGenericTypeEx(this Type type) - { -#if !NETFX_CORE - return type.IsGenericType; -#else - return type.IsConstructedGenericType; -#endif - } - - public static Type[] GetGenericArgumentsEx(this Type type) - { -#if !NETFX_CORE - return type.GetGenericArguments(); -#else - var typeinfo = type.GetTypeInfo(); - return typeinfo.IsGenericTypeDefinition - ? typeinfo.GenericTypeParameters - : typeinfo.GenericTypeArguments; -#endif - } - - public static MemberInfo[] FindWritablePropertiesWithCustomAttribute(this Type contract, - Type customAttributeType) - { - FasterList propertyList = new FasterList(8); - - do - { - var propertyInfos = contract.GetProperties(System.Reflection.BindingFlags.Public | - System.Reflection.BindingFlags.NonPublic | - System.Reflection.BindingFlags.DeclaredOnly | - System.Reflection.BindingFlags.Instance); - - for (int i = 0; i < propertyInfos.Length; i++) - { - PropertyInfo propertyInfo = propertyInfos[i]; - - if (propertyInfo.CanWrite && - propertyInfo.ContainsCustomAttribute(customAttributeType, false) == true) - propertyList.Add(propertyInfo); - } - - contract = contract.GetBaseType(); - } while (contract != null); - - if (propertyList.Count > 0) - return propertyList.ToArray(); - - return null; - } - - public static bool IsCompilerGenerated(this Type t) - { -#if NETFX_CORE - var attr = t.GetTypeInfo().GetCustomAttribute(typeof(CompilerGeneratedAttribute)); - - return attr != null; -#else - var attr = Attribute.IsDefined(t, typeof(CompilerGeneratedAttribute)); - - return attr; -#endif - } - - public static bool IsCompilerGenerated(this MemberInfo memberInfo) - { -#if NETFX_CORE - var attr = memberInfo.DeclaringType.GetTypeInfo().GetCustomAttribute(_compilerType); - - return attr != null; -#else - var attr = Attribute.IsDefined(memberInfo, _compilerType); - - return attr; -#endif - } - - static readonly Type _compilerType = typeof(CompilerGeneratedAttribute); - } - diff --git a/Utilities/ThreadUtility.cs b/Utilities/ThreadUtility.cs deleted file mode 100644 index 9c87991..0000000 --- a/Utilities/ThreadUtility.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Threading; - -namespace Svelto.Utilities -{ - public static class ThreadUtility - { - public static void MemoryBarrier() - { -#if NETFX_CORE || NET_4_6 - Interlocked.MemoryBarrier(); -#else - Thread.MemoryBarrier(); -#endif - } - } -} \ No newline at end of file From f1262acc72f408eceea50d97582f9c0e2dc1bde7 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Tue, 9 Jan 2018 14:29:51 +0000 Subject: [PATCH 20/22] Update Svelto.Common to the latest version --- Svelto.Common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Svelto.Common b/Svelto.Common index 1d516b3..b8c8bff 160000 --- a/Svelto.Common +++ b/Svelto.Common @@ -1 +1 @@ -Subproject commit 1d516b3c1eae36e366f48dad4af5950828793835 +Subproject commit b8c8bffd9290adf39609d30865fd73567923bb54 From 2428d7dd1636c566fe1a849b1a5d634347db31b3 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Tue, 9 Jan 2018 17:20:00 +0000 Subject: [PATCH 21/22] Fix Engine Profiler --- Svelto.ECS/ECS/EnginesRootEngines.cs | 15 ++++-- Svelto.ECS/ECS/Profiler/EngineInfo.cs | 49 +------------------ Svelto.ECS/ECS/Profiler/EngineProfiler.cs | 7 +-- .../ECS/Profiler/EngineProfilerBehaviour.cs | 16 ++++++ 4 files changed, 32 insertions(+), 55 deletions(-) diff --git a/Svelto.ECS/ECS/EnginesRootEngines.cs b/Svelto.ECS/ECS/EnginesRootEngines.cs index e2ebfaa..e8b557d 100644 --- a/Svelto.ECS/ECS/EnginesRootEngines.cs +++ b/Svelto.ECS/ECS/EnginesRootEngines.cs @@ -14,6 +14,17 @@ namespace Svelto.ECS { public partial class EnginesRoot : IDisposable { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + /// + /// I still need to find a good solution for this. Need to move somewhere else + /// + static EnginesRoot() + { + UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Svelto.ECS.Profiler"); + debugEngineObject.gameObject.AddComponent(); + UnityEngine.GameObject.DontDestroyOnLoad(debugEngineObject); + } +#endif /// /// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot /// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks @@ -40,10 +51,6 @@ namespace Svelto.ECS _scheduler = entityViewScheduler; _scheduler.Schedule(new WeakAction(SubmitEntityViews)); -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); - debugEngineObject.gameObject.AddComponent(); -#endif } public void AddEngine(IEngine engine) diff --git a/Svelto.ECS/ECS/Profiler/EngineInfo.cs b/Svelto.ECS/ECS/Profiler/EngineInfo.cs index c8fd453..038af1c 100644 --- a/Svelto.ECS/ECS/Profiler/EngineInfo.cs +++ b/Svelto.ECS/ECS/Profiler/EngineInfo.cs @@ -40,27 +40,16 @@ namespace Svelto.ECS.Profiler double _maxRemoveDuration; int _entityViewsRemovedCount; - public IEngine engine { get { return _engine; } } public string engineName { get { return _engineName; } } - public Type engineType { get { return _engineType; } } - - public double lastUpdateDuration { get { return _lastUpdateDuration[(int) UpdateType.Update]; } } - public double lastFixedUpdateDuration { get { return _lastUpdateDuration[(int)UpdateType.LateUpdate]; } } - public double lastLateUpdateDuration { get { return _lastUpdateDuration[(int)UpdateType.FixedUpdate]; } } - + public double minAddDuration { get { return _minAddDuration; } } public double minRemoveDuration { get { return _minRemoveDuration; } } - public double minUpdateDuration { get { return _minUpdateDuration[(int)UpdateType.Update]; } } public double maxAddDuration { get { return _maxAddDuration; } } public double maxRemoveDuration { get { return _maxRemoveDuration; } } - public double maxUpdateDuration { get { return _maxUpdateDuration[(int)UpdateType.Update]; } } public double averageAddDuration { get { return _entityViewsAddedCount == 0 ? 0 : _accumulatedAddDuration / _entityViewsAddedCount; } } public double averageRemoveDuration { get { return _entityViewsRemovedCount == 0 ? 0 : _accumulatedRemoveDuration / _entityViewsRemovedCount; } } - public double averageUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.Update].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.Update] / _updateFrameTimes[(int)UpdateType.Update].Count; } } - public double averageLateUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.LateUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.LateUpdate] / _updateFrameTimes[(int)UpdateType.LateUpdate].Count; } } - public double averageFixedUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.FixedUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.FixedUpdate] / _updateFrameTimes[(int)UpdateType.FixedUpdate].Count; } } public EngineInfo(IEngine engine) { @@ -79,42 +68,6 @@ namespace Svelto.ECS.Profiler ResetDurations(); } - public void AddUpdateDuration(double updateDuration) - { - AddUpdateDurationForType(updateDuration, (int)UpdateType.Update); - } - - public void AddLateUpdateDuration(double updateDuration) - { - AddUpdateDurationForType(updateDuration, (int)UpdateType.LateUpdate); - } - - public void AddFixedUpdateDuration(double updateDuration) - { - AddUpdateDurationForType(updateDuration, (int)UpdateType.FixedUpdate); - } - - void AddUpdateDurationForType(double updateDuration, int updateType) - { - if (updateDuration < _minUpdateDuration[updateType] || _minUpdateDuration[updateType] == 0) - { - _minUpdateDuration[updateType] = updateDuration; - } - if (updateDuration > _maxUpdateDuration[updateType]) - { - _maxUpdateDuration[updateType] = updateDuration; - } - - if (_updateFrameTimes[updateType].Count == NUM_FRAMES_TO_AVERAGE) - { - _accumulatedUpdateDuration[updateType] -= _updateFrameTimes[updateType].Dequeue(); - } - - _accumulatedUpdateDuration[updateType] += updateDuration; - _updateFrameTimes[updateType].Enqueue(updateDuration); - _lastUpdateDuration[updateType] = updateDuration; - } - public void AddAddDuration(double duration) { if (duration < _minAddDuration || _minAddDuration == 0) diff --git a/Svelto.ECS/ECS/Profiler/EngineProfiler.cs b/Svelto.ECS/ECS/Profiler/EngineProfiler.cs index 3e10786..a74333b 100644 --- a/Svelto.ECS/ECS/Profiler/EngineProfiler.cs +++ b/Svelto.ECS/ECS/Profiler/EngineProfiler.cs @@ -19,9 +19,9 @@ namespace Svelto.ECS.Profiler { _stopwatch.Start(); engine.Add(entityView); - _stopwatch.Reset(); - + _stopwatch.Stop(); info.AddAddDuration(_stopwatch.Elapsed.TotalMilliseconds); + _stopwatch.Reset(); } } @@ -32,9 +32,10 @@ namespace Svelto.ECS.Profiler { _stopwatch.Start(); engine.Remove(entityView); - _stopwatch.Reset(); + _stopwatch.Stop(); info.AddRemoveDuration(_stopwatch.Elapsed.TotalMilliseconds); + _stopwatch.Reset(); } } diff --git a/Svelto.ECS/ECS/Profiler/EngineProfilerBehaviour.cs b/Svelto.ECS/ECS/Profiler/EngineProfilerBehaviour.cs index a350ae7..b9bd384 100644 --- a/Svelto.ECS/ECS/Profiler/EngineProfilerBehaviour.cs +++ b/Svelto.ECS/ECS/Profiler/EngineProfilerBehaviour.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using UnityEngine; +using UnityEngine.SceneManagement; //This profiler is based on the Entitas Visual Debugging tool //https://github.com/sschmid/Entitas-CSharp @@ -16,6 +17,21 @@ namespace Svelto.ECS.Profiler { EngineProfiler.ResetDurations(); } + + void OnEnable() + { + SceneManager.sceneLoaded += OnLevelFinishedLoading; + } + + void OnDisable() + { + SceneManager.sceneLoaded -= OnLevelFinishedLoading; + } + + void OnLevelFinishedLoading(Scene arg0, LoadSceneMode arg1) + { + ResetDurations(); + } } } #endif \ No newline at end of file From f8b7b5930717e12ec985eef371610ead1fec8456 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Wed, 10 Jan 2018 18:43:31 +0000 Subject: [PATCH 22/22] Rename EntityStructBuilder to EntityViewStructBuilder --- Svelto.ECS/ECS/EntityViewBuilder.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Svelto.ECS/ECS/EntityViewBuilder.cs b/Svelto.ECS/ECS/EntityViewBuilder.cs index 73606af..7b89bcd 100644 --- a/Svelto.ECS/ECS/EntityViewBuilder.cs +++ b/Svelto.ECS/ECS/EntityViewBuilder.cs @@ -54,19 +54,19 @@ namespace Svelto.ECS readonly Type _entityViewType = typeof(EntityViewType); } - public class EntityStructBuilder : IEntityViewBuilder where EntityViewType : struct, IEntityStruct + public class EntityViewStructBuilder : IEntityViewBuilder where EntityViewType : struct, IEntityStruct { public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) { - var lentityView = default(EntityViewType); - lentityView.ID = entityID; + var structEntityView = default(EntityViewType); + structEntityView.ID = entityID; if (list == null) list = new TypeSafeFasterListForECSForStructs(); var castedList = list as TypeSafeFasterListForECSForStructs; - castedList.Add(lentityView); + castedList.Add(structEntityView); entityView = null; }