A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using UnityEditor.Graphing;
5using UnityEngine;
6using UnityEditor.ShaderGraph;
7using UnityEditor.ShaderGraph.Internal;
8using UnityEditor.ShaderGraph.Serialization;
9
10namespace UnityEditor.ShaderGraph
11{
12 enum CopyPasteGraphSource
13 {
14 Default,
15 Duplicate
16 }
17
18 [Serializable]
19 sealed class CopyPasteGraph : JsonObject
20 {
21 CopyPasteGraphSource m_CopyPasteGraphSource;
22
23 [SerializeField]
24 List<Edge> m_Edges = new List<Edge>();
25
26 [SerializeField]
27 List<JsonData<AbstractMaterialNode>> m_Nodes = new List<JsonData<AbstractMaterialNode>>();
28
29 [SerializeField]
30 List<JsonData<GroupData>> m_Groups = new List<JsonData<GroupData>>();
31
32 [SerializeField]
33 List<JsonData<StickyNoteData>> m_StickyNotes = new List<JsonData<StickyNoteData>>();
34
35 [SerializeField]
36 List<JsonRef<ShaderInput>> m_Inputs = new List<JsonRef<ShaderInput>>();
37
38 [SerializeField]
39 List<JsonData<CategoryData>> m_Categories = new List<JsonData<CategoryData>>();
40
41 // The meta properties are properties that are not copied into the target graph
42 // but sent along to allow property nodes to still hvae the data from the original
43 // property present.
44 [SerializeField]
45 List<JsonData<AbstractShaderProperty>> m_MetaProperties = new List<JsonData<AbstractShaderProperty>>();
46
47 [SerializeField]
48 List<string> m_MetaPropertyIds = new List<string>();
49
50 // The meta keywords are keywords that are required by keyword nodes
51 // These are copied into the target graph when there is no collision
52 [SerializeField]
53 List<JsonData<ShaderKeyword>> m_MetaKeywords = new List<JsonData<ShaderKeyword>>();
54
55 [SerializeField]
56 List<string> m_MetaKeywordIds = new List<string>();
57
58 [SerializeField]
59 List<JsonData<ShaderDropdown>> m_MetaDropdowns = new List<JsonData<ShaderDropdown>>();
60
61 [SerializeField]
62 List<string> m_MetaDropdownIds = new List<string>();
63
64 public CopyPasteGraph() { }
65
66 public CopyPasteGraph(IEnumerable<GroupData> groups,
67 IEnumerable<AbstractMaterialNode> nodes,
68 IEnumerable<Edge> edges,
69 IEnumerable<ShaderInput> inputs,
70 IEnumerable<CategoryData> categories,
71 IEnumerable<AbstractShaderProperty> metaProperties,
72 IEnumerable<ShaderKeyword> metaKeywords,
73 IEnumerable<ShaderDropdown> metaDropdowns,
74 IEnumerable<StickyNoteData> notes,
75 bool keepOutputEdges = false,
76 bool removeOrphanEdges = true,
77 CopyPasteGraphSource copyPasteGraphSource = CopyPasteGraphSource.Default)
78 {
79 m_CopyPasteGraphSource = copyPasteGraphSource;
80 if (groups != null)
81 {
82 foreach (var groupData in groups)
83 AddGroup(groupData);
84 }
85
86 if (notes != null)
87 {
88 foreach (var stickyNote in notes)
89 AddNote(stickyNote);
90 }
91
92 var nodeSet = new HashSet<AbstractMaterialNode>();
93
94 if (nodes != null)
95 {
96 foreach (var node in nodes.Distinct())
97 {
98 if (!node.canCopyNode)
99 {
100 throw new InvalidOperationException($"Cannot copy node {node.name} ({node.objectId}).");
101 }
102
103 nodeSet.Add(node);
104 AddNode(node);
105 foreach (var edge in NodeUtils.GetAllEdges(node))
106 AddEdge((Edge)edge);
107 }
108 }
109
110 if (edges != null)
111 {
112 foreach (var edge in edges)
113 AddEdge(edge);
114 }
115
116 if (inputs != null)
117 {
118 foreach (var input in inputs)
119 AddInput(input);
120 }
121
122 if (categories != null)
123 {
124 foreach (var category in categories)
125 AddCategory(category);
126 }
127
128 if (metaProperties != null)
129 {
130 foreach (var metaProperty in metaProperties.Distinct())
131 AddMetaProperty(metaProperty);
132 }
133
134 if (metaKeywords != null)
135 {
136 foreach (var metaKeyword in metaKeywords.Distinct())
137 AddMetaKeyword(metaKeyword);
138 }
139
140 if (metaDropdowns != null)
141 {
142 foreach (var metaDropdown in metaDropdowns.Distinct())
143 AddMetaDropdown(metaDropdown);
144 }
145
146 var distinct = m_Edges.Distinct();
147 if (removeOrphanEdges)
148 {
149 distinct = distinct.Where(edge => nodeSet.Contains(edge.inputSlot.node) || (keepOutputEdges && nodeSet.Contains(edge.outputSlot.node)));
150 }
151 m_Edges = distinct.ToList();
152 }
153
154 public bool IsInputCategorized(ShaderInput shaderInput)
155 {
156 foreach (var category in categories)
157 {
158 if (category.IsItemInCategory(shaderInput))
159 return true;
160 }
161
162 return false;
163 }
164
165 // The only situation in which an input has an identical reference name to another input in a category, while not being the same instance, is if they are duplicates
166 public bool IsInputDuplicatedFromCategory(ShaderInput shaderInput, CategoryData inputCategory, GraphData targetGraphData)
167 {
168 foreach (var child in inputCategory.Children)
169 {
170 if (child.referenceName.Equals(shaderInput.referenceName, StringComparison.Ordinal) && child.objectId != shaderInput.objectId)
171 {
172 return true;
173 }
174 }
175
176 // Need to check if they share same graph owner as well, if not then we can early out
177 bool inputBelongsToTargetGraph = targetGraphData.ContainsInput(shaderInput);
178 if (inputBelongsToTargetGraph == false)
179 return false;
180
181 return false;
182 }
183
184 void AddGroup(GroupData group)
185 {
186 m_Groups.Add(group);
187 }
188
189 void AddNote(StickyNoteData stickyNote)
190 {
191 m_StickyNotes.Add(stickyNote);
192 }
193
194 void AddNode(AbstractMaterialNode node)
195 {
196 m_Nodes.Add(node);
197 }
198
199 void AddEdge(Edge edge)
200 {
201 m_Edges.Add(edge);
202 }
203
204 void AddInput(ShaderInput input)
205 {
206 m_Inputs.Add(input);
207 }
208
209 void AddCategory(CategoryData category)
210 {
211 m_Categories.Add(category);
212 }
213
214 void AddMetaProperty(AbstractShaderProperty metaProperty)
215 {
216 m_MetaProperties.Add(metaProperty);
217 m_MetaPropertyIds.Add(metaProperty.objectId);
218 }
219
220 void AddMetaKeyword(ShaderKeyword metaKeyword)
221 {
222 m_MetaKeywords.Add(metaKeyword);
223 m_MetaKeywordIds.Add(metaKeyword.objectId);
224 }
225
226 void AddMetaDropdown(ShaderDropdown metaDropdown)
227 {
228 m_MetaDropdowns.Add(metaDropdown);
229 m_MetaDropdownIds.Add(metaDropdown.objectId);
230 }
231
232 public IEnumerable<T> GetNodes<T>()
233 {
234 return m_Nodes.SelectValue().OfType<T>();
235 }
236
237 public DataValueEnumerable<GroupData> groups => m_Groups.SelectValue();
238
239 public DataValueEnumerable<StickyNoteData> stickyNotes => m_StickyNotes.SelectValue();
240
241 public IEnumerable<Edge> edges
242 {
243 get { return m_Edges; }
244 }
245
246 public RefValueEnumerable<ShaderInput> inputs
247 {
248 get { return m_Inputs.SelectValue(); }
249 }
250
251 public DataValueEnumerable<CategoryData> categories
252 {
253 get { return m_Categories.SelectValue(); }
254 }
255
256 public DataValueEnumerable<AbstractShaderProperty> metaProperties
257 {
258 get { return m_MetaProperties.SelectValue(); }
259 }
260
261 public DataValueEnumerable<ShaderKeyword> metaKeywords
262 {
263 get { return m_MetaKeywords.SelectValue(); }
264 }
265
266 public DataValueEnumerable<ShaderDropdown> metaDropdowns
267 {
268 get { return m_MetaDropdowns.SelectValue(); }
269 }
270
271 public IEnumerable<string> metaPropertyIds => m_MetaPropertyIds;
272
273 public IEnumerable<string> metaKeywordIds => m_MetaKeywordIds;
274
275 public CopyPasteGraphSource copyPasteGraphSource => m_CopyPasteGraphSource;
276
277 public override void OnAfterMultiDeserialize(string json)
278 {
279 // should we add support for versioning old CopyPasteGraphs from old versions of Unity?
280 // so you can copy from old paste to new
281
282 foreach (var node in m_Nodes.SelectValue())
283 {
284 node.UpdateNodeAfterDeserialization();
285 node.SetupSlots();
286 }
287 }
288
289 internal static CopyPasteGraph FromJson(string copyBuffer, GraphData targetGraph)
290 {
291 try
292 {
293 var graph = new CopyPasteGraph();
294 MultiJson.Deserialize(graph, copyBuffer, targetGraph, true);
295 return graph;
296 }
297 catch
298 {
299 // ignored. just means copy buffer was not a graph :(
300 return null;
301 }
302 }
303 }
304}