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}