A game about forced loneliness, made by TACStudios
1using System;
2using UnityEditor.Graphs;
3using UnityEditor.ShaderGraph;
4using UnityEditor.ShaderGraph.Serialization;
5using UnityEngine;
6
7namespace UnityEditor.Graphing
8{
9 class HandleUndoRedoAction : IGraphDataAction
10 {
11 void HandleGraphUndoRedo(GraphData graphData)
12 {
13 AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out HandleUndoRedoAction");
14 AssertHelpers.IsNotNull(newGraphData, "NewGraphData is null while carrying out HandleUndoRedoAction");
15 try
16 {
17 graphData?.ReplaceWith(newGraphData);
18 }
19 catch (Exception e)
20 {
21 if (graphData != null)
22 graphData.replaceInProgress = false;
23 throw e;
24 }
25 }
26
27 public Action<GraphData> modifyGraphDataAction => HandleGraphUndoRedo;
28
29 public GraphData newGraphData { get; set; }
30 }
31
32 class GraphObject : ScriptableObject, ISerializationCallbackReceiver
33 {
34 [SerializeField]
35 SerializationHelper.JSONSerializedElement m_SerializedGraph;
36
37 [SerializeField]
38 int m_SerializedVersion;
39
40 [SerializeField]
41 bool m_IsDirty;
42
43 [SerializeField]
44 bool m_IsSubGraph;
45
46 [SerializeField]
47 string m_AssetGuid;
48
49 internal string AssetGuid
50 {
51 get => m_AssetGuid;
52 }
53
54 [NonSerialized]
55 GraphData m_Graph;
56
57 [NonSerialized]
58 int m_DeserializedVersion;
59
60 public DataStore<GraphData> graphDataStore
61 {
62 get => m_DataStore;
63 private set
64 {
65 if (m_DataStore != value && value != null)
66 m_DataStore = value;
67 }
68 }
69
70 DataStore<GraphData> m_DataStore;
71
72 public GraphData graph
73 {
74 get { return m_Graph; }
75 set
76 {
77 if (m_Graph != null)
78 m_Graph.owner = null;
79 m_Graph = value;
80 graphDataStore = new DataStore<GraphData>(ReduceGraphDataAction, m_Graph);
81 if (m_Graph != null)
82 m_Graph.owner = this;
83 }
84 }
85
86 Material m_MaterialArtifact;
87
88 /// <summary>
89 /// The Material artifact generated by the import process.
90 /// Every modification to this material will be lost when the graph is saved.
91 /// for.
92 /// </summary>
93 public Material materialArtifact
94 {
95 get
96 {
97 if (m_MaterialArtifact == null)
98 m_MaterialArtifact = AssetDatabase.LoadAssetAtPath<Material>(AssetDatabase.GUIDToAssetPath(AssetGuid));
99 return m_MaterialArtifact;
100 }
101 }
102
103 // this value stores whether an undo operation has been registered (which indicates a change has been made to the graph)
104 // and is used to trigger the MaterialGraphEditWindow to update it's title
105 public bool isDirty
106 {
107 get { return m_IsDirty; }
108 set { m_IsDirty = value; }
109 }
110
111 public virtual void RegisterCompleteObjectUndo(string actionName)
112 {
113 Undo.RegisterCompleteObjectUndo(this, actionName);
114 if (materialArtifact)
115 Undo.RecordObject(m_MaterialArtifact, actionName);
116 m_SerializedVersion++;
117 m_DeserializedVersion++;
118 m_IsDirty = true;
119 }
120
121 public void OnBeforeSerialize()
122 {
123 if (graph != null)
124 {
125 var json = MultiJson.Serialize(graph);
126 m_SerializedGraph = new SerializationHelper.JSONSerializedElement { JSONnodeData = json };
127 m_IsSubGraph = graph.isSubGraph;
128 m_AssetGuid = graph.assetGuid;
129 }
130 }
131
132 public void OnAfterDeserialize()
133 {
134 }
135
136 public bool wasUndoRedoPerformed => m_DeserializedVersion != m_SerializedVersion;
137
138 public void HandleUndoRedo()
139 {
140 Debug.Assert(wasUndoRedoPerformed);
141 var deserializedGraph = DeserializeGraph();
142
143 var handleUndoRedoAction = new HandleUndoRedoAction();
144 handleUndoRedoAction.newGraphData = deserializedGraph;
145 graphDataStore.Dispatch(handleUndoRedoAction);
146 }
147
148 GraphData DeserializeGraph()
149 {
150 var json = m_SerializedGraph.JSONnodeData;
151 var deserializedGraph = new GraphData { isSubGraph = m_IsSubGraph, assetGuid = m_AssetGuid };
152 MultiJson.Deserialize(deserializedGraph, json);
153 m_DeserializedVersion = m_SerializedVersion;
154 m_SerializedGraph = default;
155 return deserializedGraph;
156 }
157
158 public void Validate()
159 {
160 if (graph != null)
161 {
162 graph.OnEnable();
163 graph.ValidateGraph();
164 }
165 }
166
167 // This is a very simple reducer, all it does is take the action and apply it to the graph data, which causes some mutation in state
168 // This isn't strictly redux anymore but its needed given that our state tree is quite large and we don't want to be creating copies of it everywhere by unboxing
169 void ReduceGraphDataAction(GraphData initialState, IGraphDataAction graphDataAction)
170 {
171 graphDataAction.modifyGraphDataAction(initialState);
172 }
173
174 void OnEnable()
175 {
176 if (graph == null && m_SerializedGraph.JSONnodeData != null)
177 {
178 graph = DeserializeGraph();
179 }
180 Validate();
181 }
182
183 void OnDestroy()
184 {
185 graph?.OnDisable();
186 }
187 }
188}