A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5
6namespace Unity.VisualScripting
7{
8 public abstract class GraphElement<TGraph> : IGraphElement where TGraph : class, IGraph
9 {
10 [Serialize]
11 public Guid guid { get; set; } = Guid.NewGuid();
12
13 // To minimize the amount of implementation needed, and simplify inversion of control,
14 // we provide instantiation routines that fit most types of elements in the right order and
15 // we provide implemented defaults for interfaces that the element could implement.
16 // Normally, an element shouldn't have to override instantiate or uninstantiate directly.
17
18 public virtual void Instantiate(GraphReference instance)
19 {
20 // Create the data for this graph, non-recursively, that is
21 // required for the nest instantiation, so we do it first.
22 if (this is IGraphElementWithData withData)
23 {
24 instance.data.CreateElementData(withData);
25 }
26
27 // Nest instantiation is a recursive operation that will
28 // call Instantiate on descendant graphs and elements.
29 // Because event listening will descend graph data recursively,
30 // we need to create it before.
31 if (this is IGraphNesterElement nester && nester.nest.graph != null)
32 {
33 GraphInstances.Instantiate(instance.ChildReference(nester, true));
34 }
35
36 // StartListening is a recursive operation that will
37 // descend graphs recursively. It must be called after
38 // instantiation of all child graphs because it will require
39 // their data. The drawback with this approach is that it will be
40 // called at each step bubbling up, whereas it will only
41 // effectively trigger once we reach the top level.
42 // Traversal is currently O(n!) where n is the number of descendants,
43 // ideally it would be O(n) if only triggered from the root.
44
45 // => Listening has to be implemented by Bolt classes, because Graphs isn't aware of the event system
46 }
47
48 public virtual void Uninstantiate(GraphReference instance)
49 {
50 // See above comments, in reverse order.
51
52 if (this is IGraphNesterElement nester && nester.nest.graph != null)
53 {
54 GraphInstances.Uninstantiate(instance.ChildReference(nester, true));
55 }
56
57 if (this is IGraphElementWithData withData)
58 {
59 instance.data.FreeElementData(withData);
60 }
61 }
62
63 public virtual void BeforeAdd() { }
64
65 public virtual void AfterAdd()
66 {
67 var instances = GraphInstances.OfPooled(graph);
68
69 foreach (var instance in instances)
70 {
71 Instantiate(instance);
72 }
73
74 instances.Free();
75 }
76
77 public virtual void BeforeRemove()
78 {
79 var instances = GraphInstances.OfPooled(graph);
80
81 foreach (var instance in instances)
82 {
83 Uninstantiate(instance);
84 }
85
86 instances.Free();
87
88 Dispose();
89 }
90
91 public virtual void AfterRemove() { }
92
93 public virtual void Dispose() { }
94
95 protected void InstantiateNest()
96 {
97 var nester = (IGraphNesterElement)this;
98
99 if (graph == null)
100 {
101 return;
102 }
103
104 var instances = GraphInstances.OfPooled(graph);
105
106 foreach (var instance in instances)
107 {
108 GraphInstances.Instantiate(instance.ChildReference(nester, true));
109 }
110
111 instances.Free();
112 }
113
114 protected void UninstantiateNest()
115 {
116 var nester = (IGraphNesterElement)this;
117
118 var instances = GraphInstances.ChildrenOfPooled(nester);
119
120 foreach (var instance in instances)
121 {
122 GraphInstances.Uninstantiate(instance);
123 }
124
125 instances.Free();
126 }
127
128 #region Graph
129
130 [DoNotSerialize]
131 public virtual int dependencyOrder => 0;
132
133 public virtual bool HandleDependencies() => true;
134
135 [DoNotSerialize]
136 public TGraph graph { get; set; }
137
138 [DoNotSerialize]
139 IGraph IGraphElement.graph
140 {
141 get => graph;
142 set
143 {
144 Ensure.That(nameof(value)).IsOfType<TGraph>(value);
145 graph = (TGraph)value;
146 }
147 }
148
149 [DoNotSerialize]
150 IGraph IGraphItem.graph => graph;
151
152 #endregion
153
154 #region Poutine
155
156 public virtual IEnumerable<ISerializationDependency> deserializationDependencies => Enumerable.Empty<ISerializationDependency>();
157
158 public virtual IEnumerable<object> GetAotStubs(HashSet<object> visited)
159 {
160 return Enumerable.Empty<object>();
161 }
162
163 public virtual void Prewarm() { }
164
165 protected void CopyFrom(GraphElement<TGraph> source) { }
166
167 public override string ToString()
168 {
169 var sb = new StringBuilder();
170 sb.Append(GetType().Name);
171 sb.Append("#");
172 sb.Append(guid.ToString().Substring(0, 5));
173 sb.Append("...");
174 return sb.ToString();
175 }
176
177 #endregion
178
179 public virtual AnalyticsIdentifier GetAnalyticsIdentifier()
180 {
181 throw new NotImplementedException();
182 }
183 }
184}