-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSystemDependencyResolver.cs
133 lines (116 loc) · 4.37 KB
/
SystemDependencyResolver.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using System;
using System.Collections.Generic;
using UnityEngine;
namespace MelonECS
{
internal class SystemDependencyResolver
{
class Node : IEquatable<Node>
{
public readonly System system;
public HashSet<Type> readEvents = new HashSet<Type>();
public HashSet<Type> writeEvents = new HashSet<Type>();
public List<Node> edges = new List<Node>();
public Node(System system)
{
this.system = system;
var attributes = system.GetType().GetCustomAttributes(true);
foreach (var attribute in attributes)
{
switch (attribute)
{
case ReadEventsAttribute read:
foreach (Type type in read.types)
readEvents.Add(type);
break;
case WriteEventsAttribute write:
foreach (Type type in write.types)
writeEvents.Add(type);
break;
}
}
}
public bool Equals(Node other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(system, other.system);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Node) obj);
}
public override int GetHashCode()
{
return (system != null ? system.GetHashCode() : 0);
}
}
public System[] ResolveDependencies(IEnumerable<System> systems)
{
var readSystems = new Dictionary<Type, List<Node>>();
var writeSystems = new Dictionary<Type, List<Node>>();
var nodes = new List<Node>();
foreach (var system in systems)
{
var node = new Node(system);
nodes.Add(node);
foreach (Type type in node.readEvents)
TryAdd(type, node, readSystems);
foreach (Type type in node.writeEvents)
TryAdd(type, node, writeSystems);
}
foreach (Node node in nodes)
{
foreach (Type type in node.readEvents)
{
if ( writeSystems.TryGetValue(type, out var list) )
node.edges.AddRange(list);
}
}
// var toResolve = new Stack<Node>();
// toResolve.Push(nodes[0]);
// while (toResolve.Count > 0)
// {
// var node = toResolve.Pop();
// for (int i = node.edges.Count - 1; i >= 0; i--)
// {
// var edge = node.edges[i];
// toResolve.Push(edge);
// }
// }
var resolved = new List<System>();
var seen = new HashSet<Node>();
Resolve(nodes[0], resolved, seen);
return resolved.ToArray();
}
private void Resolve(Node node, List<System> resolved, HashSet<Node> seen)
{
Debug.Log(node.system.GetType().Name);
seen.Add(node);
foreach (var edge in node.edges)
{
if (resolved.Contains(edge.system))
continue;
if (seen.Contains(edge))
{
Debug.LogError($"Circular dependency detected: {node.system.GetType().Name} -> {edge.system.GetType().Name}");
continue;
}
Resolve(edge, resolved, seen);
}
resolved.Add(node.system);
}
private void TryAdd(Type type, Node node, Dictionary<Type, List<Node>> dictionary)
{
if (!dictionary.TryGetValue(type, out var nodes))
{
nodes = new List<Node>();
dictionary.Add(type, nodes);
}
nodes.Add(node);
}
}
}