Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
|
4538c0f3c9 | 2 years ago |
41 changed files with 784 additions and 841 deletions
@ -0,0 +1,7 @@
|
||||
- immutable component system? |
||||
|
||||
- method to remove all components of a type without destroying Entities |
||||
- method to remove a component of a type without destroying entity |
||||
|
||||
- look at test coverage |
||||
- docs |
@ -1,16 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace Encompass |
||||
{ |
||||
[AttributeUsage(AttributeTargets.Class)] |
||||
public class Adds : Attribute |
||||
{ |
||||
public readonly HashSet<Type> addTypes; |
||||
|
||||
public Adds(params Type[] addTypes) |
||||
{ |
||||
this.addTypes = new HashSet<Type>(addTypes); |
||||
} |
||||
} |
||||
} |
@ -1,156 +0,0 @@
|
||||
using System; |
||||
|
||||
namespace Encompass |
||||
{ |
||||
public static unsafe class MemoryHelper |
||||
{ |
||||
public static void Copy(uint* src, uint* dest, int count) |
||||
{ |
||||
for (; count != 0; count--) *dest++ = *src++; |
||||
} |
||||
|
||||
public static void Fill(uint* p, int count, uint value) |
||||
{ |
||||
for (; count != 0; count--) *p++ = value; |
||||
} |
||||
|
||||
public static void And(uint* p, uint* q, uint* result, int count) |
||||
{ |
||||
for (; count != 0; count--) *result++ = *p++ & *q++; |
||||
} |
||||
|
||||
public static void Or(uint* p, uint* q, uint* result, int count) |
||||
{ |
||||
for (; count != 0; count--) *result++ = *p++ | *q++; |
||||
} |
||||
|
||||
public static void Not(uint* p, uint* result, int count) |
||||
{ |
||||
for (; count != 0; count--) *result++ = ~*p++; |
||||
} |
||||
|
||||
public static bool Equal(uint* p, uint* q, int count) |
||||
{ |
||||
for (; count != 0; count--) if (*p++ != *q++) { return false; } |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
public unsafe struct BitSet512 : IEquatable<BitSet512> |
||||
{ |
||||
public static BitSet512 Zero { get; } = new BitSet512(0); |
||||
public static BitSet512 Ones { get; } = new BitSet512(uint.MaxValue); |
||||
|
||||
private const int _uintLength = 16; |
||||
|
||||
private fixed uint _buffer[_uintLength]; |
||||
|
||||
public BitSet512(uint value) |
||||
{ |
||||
fixed (uint* p = _buffer) MemoryHelper.Fill(p, _uintLength, value); |
||||
} |
||||
|
||||
public BitSet512(uint* src) |
||||
{ |
||||
fixed (uint* dest = _buffer) MemoryHelper.Copy(src, dest, _uintLength); |
||||
} |
||||
|
||||
public static BitSet512 operator &(BitSet512 a, BitSet512 b) |
||||
{ |
||||
var tmp = stackalloc uint[_uintLength]; |
||||
MemoryHelper.And(a._buffer, b._buffer, tmp, _uintLength); |
||||
return new BitSet512(tmp); |
||||
} |
||||
|
||||
public static BitSet512 operator |(BitSet512 a, BitSet512 b) |
||||
{ |
||||
var tmp = stackalloc uint[_uintLength]; |
||||
MemoryHelper.Or(a._buffer, b._buffer, tmp, _uintLength); |
||||
return new BitSet512(tmp); |
||||
} |
||||
|
||||
public static BitSet512 operator ~(BitSet512 a) |
||||
{ |
||||
var tmp = stackalloc uint[_uintLength]; |
||||
MemoryHelper.Not(a._buffer, tmp, _uintLength); |
||||
return new BitSet512(tmp); |
||||
} |
||||
|
||||
public static bool operator ==(BitSet512 left, BitSet512 right) |
||||
{ |
||||
return left.Equals(right); |
||||
} |
||||
|
||||
public static bool operator !=(BitSet512 left, BitSet512 right) |
||||
{ |
||||
return !(left == right); |
||||
} |
||||
|
||||
public BitSet512 Set(int index) |
||||
{ |
||||
var tmp = stackalloc uint[_uintLength]; |
||||
fixed (uint* p = _buffer) MemoryHelper.Copy(p, tmp, _uintLength); |
||||
tmp[index / 32] |= (uint)(1 << index % 32); |
||||
return new BitSet512(tmp); |
||||
} |
||||
|
||||
public BitSet512 UnSet(int index) |
||||
{ |
||||
var tmp = stackalloc uint[_uintLength]; |
||||
fixed (uint* p = _buffer) MemoryHelper.Copy(p, tmp, _uintLength); |
||||
tmp[index / 32] &= ~(uint)(1 << index % 32); |
||||
return new BitSet512(tmp); |
||||
} |
||||
|
||||
public bool Get(int bitIndex) |
||||
{ |
||||
var bitInt = (uint)(1 << bitIndex % 32); |
||||
return (_buffer[bitIndex / 32] & bitInt) == bitInt; |
||||
} |
||||
|
||||
public bool AllTrue() |
||||
{ |
||||
return this == Ones; |
||||
} |
||||
|
||||
public bool AllFalse() |
||||
{ |
||||
return this == Zero; |
||||
} |
||||
|
||||
public static BitSet512 BitwiseAnd(BitSet512 left, BitSet512 right) |
||||
{ |
||||
return left & right; |
||||
} |
||||
|
||||
public static BitSet512 BitwiseOr(BitSet512 left, BitSet512 right) |
||||
{ |
||||
return left | right; |
||||
} |
||||
|
||||
public static BitSet512 OnesComplement(BitSet512 bitSet) |
||||
{ |
||||
return ~bitSet; |
||||
} |
||||
|
||||
public override bool Equals(object obj) |
||||
{ |
||||
return obj is BitSet512 set && Equals(set); |
||||
} |
||||
|
||||
public bool Equals(BitSet512 other) |
||||
{ |
||||
fixed (uint* p = _buffer) return MemoryHelper.Equal(p, other._buffer, _uintLength); |
||||
} |
||||
|
||||
public override int GetHashCode() |
||||
{ |
||||
var hc = 0; |
||||
for (var i = 0; i < _uintLength; i++) |
||||
{ |
||||
hc ^= _buffer[i].GetHashCode(); |
||||
} |
||||
return hc; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,132 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using Encompass.Exceptions; |
||||
|
||||
namespace Encompass |
||||
{ |
||||
internal class DrawLayerManager |
||||
{ |
||||
private readonly SortedList<int, int> _layerOrder = new SortedList<int, int>(); |
||||
|
||||
private readonly Dictionary<int, Dictionary<Type, HashSet<int>>> _layerIndexToTypeToID = new Dictionary<int, Dictionary<Type, HashSet<int>>>(); |
||||
private readonly Dictionary<int, HashSet<GeneralRenderer>> _layerIndexToGeneralRenderers = new Dictionary<int, HashSet<GeneralRenderer>>(512); |
||||
|
||||
private readonly Dictionary<Type, Dictionary<int, int>> _typeToEntityToLayer = new Dictionary<Type, Dictionary<int, int>>(512); |
||||
public IEnumerable<int> LayerOrder { get { return _layerOrder.Values; } } |
||||
|
||||
public DrawLayerManager() |
||||
{ |
||||
RegisterDrawLayer(0); |
||||
} |
||||
|
||||
public void RegisterDrawLayer(int layer) |
||||
{ |
||||
if (!_layerIndexToTypeToID.ContainsKey(layer)) |
||||
{ |
||||
_layerOrder.Add(layer, layer); |
||||
_layerIndexToGeneralRenderers.Add(layer, new HashSet<GeneralRenderer>()); |
||||
_layerIndexToTypeToID.Add(layer, new Dictionary<Type, HashSet<int>>()); |
||||
} |
||||
} |
||||
|
||||
public void RegisterOrderedDrawable<TComponent>() where TComponent : struct
|
||||
{ |
||||
if (!_typeToEntityToLayer.ContainsKey(typeof(TComponent))) |
||||
{ |
||||
_typeToEntityToLayer.Add(typeof(TComponent), new Dictionary<int, int>(128)); |
||||
} |
||||
|
||||
foreach (var pair in _layerIndexToTypeToID) |
||||
{ |
||||
if (!pair.Value.ContainsKey(typeof(TComponent))) |
||||
{ |
||||
pair.Value.Add(typeof(TComponent), new HashSet<int>()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void RegisterGeneralRendererWithLayer(GeneralRenderer renderer, int layer) |
||||
{ |
||||
RegisterDrawLayer(layer); |
||||
var set = _layerIndexToGeneralRenderers[layer]; |
||||
set.Add(renderer); |
||||
} |
||||
|
||||
public void RegisterComponentWithLayer<TComponent>(int entityID, int layer) where TComponent : struct
|
||||
{ |
||||
if (!_layerIndexToTypeToID.ContainsKey(layer)) |
||||
{ |
||||
throw new UndefinedLayerException("Layer {0} is not defined. Use WorldBuilder.RegisterDrawLayer to register the layer.", layer); |
||||
} |
||||
|
||||
if (_typeToEntityToLayer[typeof(TComponent)].ContainsKey(entityID)) |
||||
{ |
||||
if (_typeToEntityToLayer[typeof(TComponent)][entityID] != layer) |
||||
{ |
||||
UnRegisterComponentWithLayer<TComponent>(entityID); |
||||
|
||||
var set = _layerIndexToTypeToID[layer][typeof(TComponent)]; |
||||
set.Add(entityID); |
||||
|
||||
_typeToEntityToLayer[typeof(TComponent)].Add(entityID, layer); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
var set = _layerIndexToTypeToID[layer][typeof(TComponent)]; |
||||
set.Add(entityID); |
||||
|
||||
_typeToEntityToLayer[typeof(TComponent)].Add(entityID, layer); |
||||
} |
||||
} |
||||
|
||||
public void UnRegisterComponentWithLayer<TComponent>(int entityID) where TComponent : struct
|
||||
{ |
||||
if (!_typeToEntityToLayer.ContainsKey(typeof(TComponent))) { return; } |
||||
|
||||
if (_typeToEntityToLayer[typeof(TComponent)].ContainsKey(entityID)) |
||||
{ |
||||
var layer = _typeToEntityToLayer[typeof(TComponent)][entityID]; |
||||
_layerIndexToTypeToID[layer][typeof(TComponent)].Remove(entityID); |
||||
} |
||||
_typeToEntityToLayer[typeof(TComponent)].Remove(entityID); |
||||
} |
||||
|
||||
public void UnRegisterEntityWithLayer(int entityID) |
||||
{ |
||||
foreach (var store in _layerIndexToTypeToID.Values) |
||||
{ |
||||
foreach (var typeToSet in store) |
||||
{ |
||||
var type = typeToSet.Key; |
||||
var set = typeToSet.Value; |
||||
|
||||
if (set.Contains(entityID)) |
||||
{ |
||||
_typeToEntityToLayer[type].Remove(entityID); |
||||
set.Remove(entityID); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public IEnumerable<GeneralRenderer> GeneralRenderersByLayer(int layer) |
||||
{ |
||||
return _layerIndexToGeneralRenderers.ContainsKey(layer) ? |
||||
_layerIndexToGeneralRenderers[layer] : |
||||
Enumerable.Empty<GeneralRenderer>(); |
||||
} |
||||
|
||||
public IEnumerable<(int, Type)> AllInLayer(int layer) |
||||
{ |
||||
foreach (var kvp in _layerIndexToTypeToID[layer]) |
||||
{ |
||||
foreach (var id in kvp.Value) |
||||
{ |
||||
yield return (id, kvp.Key); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,12 @@
|
||||
using System; |
||||
|
||||
namespace Encompass.Exceptions |
||||
{ |
||||
public class IllegalSendTypeException : Exception |
||||
{ |
||||
public IllegalSendTypeException( |
||||
string format, |
||||
params object[] args |
||||
) : base(string.Format(format, args)) { } |
||||
} |
||||
} |
@ -1,390 +0,0 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
namespace Encompass |
||||
{ |
||||
internal class DirectedGraph<TNode> where TNode : IEquatable<TNode> |
||||
{ |
||||
protected HashSet<TNode> nodes = new HashSet<TNode>(); |
||||
protected Dictionary<TNode, HashSet<TNode>> neighbors = new Dictionary<TNode, HashSet<TNode>>(); |
||||
|
||||
protected HashSet<(TNode, TNode)> edges = new HashSet<(TNode, TNode)>(); |
||||
|
||||
public IEnumerable<TNode> Nodes => nodes; |
||||
public IEnumerable<(TNode, TNode)> Edges => edges; |
||||
|
||||
public void AddNode(TNode node) |
||||
{ |
||||
if (!Exists(node)) |
||||
{ |
||||
nodes.Add(node); |
||||
neighbors.Add(node, new HashSet<TNode>()); |
||||
} |
||||
} |
||||
|
||||
public void AddNodes(params TNode[] nodes) |
||||
{ |
||||
foreach (var node in nodes) |
||||
{ |
||||
AddNode(node); |
||||
} |
||||
} |
||||
|
||||
public void RemoveNode(TNode node) |
||||
{ |
||||
CheckNodes(node); |
||||
|
||||
var edgesToRemove = new List<(TNode, TNode)>(); |
||||
|
||||
foreach (var entry in neighbors) |
||||
{ |
||||
if (entry.Value.Contains(node)) |
||||
{ |
||||
edgesToRemove.Add((entry.Key, node)); |
||||
} |
||||
} |
||||
|
||||
foreach (var edge in edgesToRemove) |
||||
{ |
||||
RemoveEdge(edge.Item1, edge.Item2); |
||||
} |
||||
|
||||
nodes.Remove(node); |
||||
neighbors.Remove(node); |
||||
} |
||||
|
||||
public void RemoveEdge(TNode v, TNode u) |
||||
{ |
||||
CheckEdge(v, u); |
||||
neighbors[v].Remove(u); |
||||
edges.Remove((v, u)); |
||||
} |
||||
|
||||
public void AddEdge(TNode v, TNode u) |
||||
{ |
||||
CheckNodes(v, u); |
||||
if (Exists(v, u)) { throw new ArgumentException($"Edge between {v} and {u} already exists in the graph"); } |
||||
|
||||
if (v.Equals(u)) { throw new ArgumentException("Self-edges are not allowed in a simple graph. Use a multigraph instead"); } |
||||
|
||||
neighbors[v].Add(u); |
||||
edges.Add((v, u)); |
||||
} |
||||
|
||||
public bool Exists(TNode node) |
||||
{ |
||||
return nodes.Contains(node); |
||||
} |
||||
|
||||
public bool Exists(TNode v, TNode u) |
||||
{ |
||||
CheckNodes(v, u); |
||||
return edges.Contains((v, u)); |
||||
} |
||||
|
||||
protected void CheckNodes(params TNode[] givenNodes) |
||||
{ |
||||
foreach (var node in givenNodes) |
||||
{ |
||||
if (!Exists(node)) |
||||
{ |
||||
throw new System.ArgumentException($"Vertex {node} does not exist in the graph"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected void CheckEdge(TNode v, TNode u) |
||||
{ |
||||
CheckNodes(v, u); |
||||
if (!Exists(v, u)) { throw new ArgumentException($"Edge between vertex {v} and vertex {u} does not exist in the graph"); } |
||||
} |
||||
|
||||
public IEnumerable<TNode> Neighbors(TNode node) |
||||
{ |
||||
CheckNodes(node); |
||||
return neighbors[node]; |
||||
} |
||||
|
||||
public DirectedGraph<TNode> Clone() |
||||
{ |
||||
var clone = new DirectedGraph<TNode>(); |
||||
clone.AddNodes(Nodes.ToArray()); |
||||
|
||||
foreach (var v in Nodes) |
||||
{ |
||||
foreach (var n in Neighbors(v)) |
||||
{ |
||||
clone.AddEdge(v, n); |
||||
} |
||||
} |
||||
|
||||
return clone; |
||||
} |
||||
|
||||
public DirectedGraph<TNode> SubGraph(params TNode[] subVertices) |
||||
{ |
||||
var subGraph = new DirectedGraph<TNode>(); |
||||
subGraph.AddNodes(subVertices.ToArray()); |
||||
|
||||
foreach (var n in Nodes) |
||||
{ |
||||
if (Nodes.Contains(n)) |
||||
{ |
||||
var neighbors = Neighbors(n); |
||||
foreach (var u in neighbors) |
||||
{ |
||||
if (subVertices.Contains(u)) |
||||
{ |
||||
subGraph.AddEdge(n, u); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
return subGraph; |
||||
} |
||||
|
||||
private IEnumerable<TNode> PostorderNodeDFSHelper(HashSet<TNode> discovered, TNode v) |
||||
{ |
||||
discovered.Add(v); |
||||
|
||||
foreach (var neighbor in Neighbors(v)) |
||||
{ |
||||
if (!discovered.Contains(neighbor)) |
||||
{ |
||||
foreach (var node in PostorderNodeDFSHelper(discovered, neighbor)) |
||||
{ |
||||
yield return node; |
||||
} |
||||
} |
||||
} |
||||
|
||||
yield return v; |
||||
} |
||||
|
||||
protected IEnumerable<TNode> PostorderNodeDFS() |
||||
{ |
||||
var dfsDiscovered = new HashSet<TNode>(); |
||||
|
||||
foreach (var node in Nodes) |
||||
{ |
||||
if (!dfsDiscovered.Contains(node)) |
||||
{ |
||||
foreach (var thing in PostorderNodeDFSHelper(dfsDiscovered, node)) |
||||
{ |
||||
yield return thing; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public IEnumerable<TNode> TopologicalSort() |
||||
{ |
||||
return PostorderNodeDFS().Reverse(); |
||||
} |
||||
|
||||
public bool Cyclic() |
||||
{ |
||||
return StronglyConnectedComponents().Any((scc) => scc.Count() > 1); |
||||
} |
||||
|
||||
public IEnumerable<IEnumerable<TNode>> SimpleCycles() |
||||
{ |
||||
void unblock(TNode thisnode, HashSet<TNode> blocked, Dictionary<TNode, HashSet<TNode>> B) //refactor to remove closure |
||||
{ |
||||
var stack = new Stack<TNode>(); |
||||
stack.Push(thisnode); |
||||
|
||||
while (stack.Count > 0) |
||||
{ |
||||
var node = stack.Pop(); |
||||
if (blocked.Contains(thisnode)) |
||||
{ |
||||
blocked.Remove(thisnode); |
||||
if (B.ContainsKey(node)) |
||||
{ |
||||
foreach (var n in B[node]) |
||||
{ |
||||
if (!stack.Contains(n)) |
||||
{ |
||||
stack.Push(n); |
||||
} |
||||
} |
||||
B[node].Clear(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
List<List<TNode>> result = new List<List<TNode>>(); |
||||
var subGraph = Clone(); |
||||
|
||||
var sccs = new Stack<IEnumerable<TNode>>(); |
||||
foreach (var scc in StronglyConnectedComponents()) |
||||
{ |
||||
sccs.Push(scc); |
||||
} |
||||
|
||||
while (sccs.Count > 0) |
||||
{ |
||||
var scc = new Stack<TNode>(sccs.Pop()); |
||||
var startNode = scc.Pop(); |
||||
var path = new Stack<TNode>(); |
||||
path.Push(startNode); |
||||
var blocked = new HashSet<TNode> |
||||
{ |
||||
startNode |
||||
}; |
||||
var closed = new HashSet<TNode>(); |
||||
var B = new Dictionary<TNode, HashSet<TNode>>(); |
||||
var stack = new Stack<(TNode, Stack<TNode>)>(); |
||||
stack.Push((startNode, new Stack<TNode>(subGraph.Neighbors(startNode)))); |
||||
|
||||
while (stack.Count > 0) |
||||
{ |
||||
var entry = stack.Peek(); |
||||
var thisnode = entry.Item1; |
||||
var neighbors = entry.Item2; |
||||
|
||||
if (neighbors.Count > 0) |
||||
{ |
||||
var nextNode = neighbors.Pop(); |
||||
|
||||
if (nextNode.Equals(startNode)) |
||||
{ |
||||
var resultPath = new List<TNode>(); |
||||
foreach (var v in path) |
||||
{ |
||||
resultPath.Add(v); |
||||
} |
||||
result.Add(resultPath); |
||||
foreach (var v in path) |
||||
{ |
||||
closed.Add(v); |
||||
} |
||||
} |
||||
else if (!blocked.Contains(nextNode)) |
||||
{ |
||||
path.Push(nextNode); |
||||
stack.Push((nextNode, new Stack<TNode>(subGraph.Neighbors(nextNode)))); |
||||
closed.Remove(nextNode); |
||||
blocked.Add(nextNode); |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
if (neighbors.Count == 0) |
||||
{ |
||||
if (closed.Contains(thisnode)) |
||||
{ |
||||
unblock(thisnode, blocked, B); |
||||
} |
||||
else |
||||
{ |
||||
foreach (var neighbor in subGraph.Neighbors(thisnode)) |
||||
{ |
||||
if (!B.ContainsKey(neighbor)) |
||||
{ |
||||
B[neighbor] = new HashSet<TNode>(); |
||||
} |
||||
B[neighbor].Add(thisnode); |
||||
} |
||||
} |
||||
|
||||
stack.Pop(); |
||||
path.Pop(); |
||||
} |
||||
} |
||||
|
||||
subGraph.RemoveNode(startNode); |
||||
var H = subGraph.SubGraph(scc.ToArray()); |
||||
var HSccs = H.StronglyConnectedComponents(); |
||||
foreach (var HScc in HSccs) |
||||
{ |
||||
sccs.Push(HScc); |
||||
} |
||||