NodeCanvas Forums › Support › Diffability › Reply To: Diffability
Hey Gavalakis!
I’ve adjusted the JSON serialization for diffability. I noticed you turned it off a while ago and I have another hacky way around it. It might be able to be cleaned up and released if its reasonably stable.
It works by writing to a JSON file when a graph asset is imported (it uses a hacky path strategy). That gets the JSON out of the asset file. It also monitors TextAssets that use the same hacky path strategy. When those change the graph serializedGraph field is updated to reflect the JSON file.
—————————————————–
#if UNITY_EDITOR
using System.Collections.Generic;
using UnityEditor;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using System.IO;
using System.Text.RegularExpressions;
using UnityEngine;namespace NodeCanvas.Editor
{
///Handles post processing of graph assets
public class GraphAssetPostProcessor
{[InitializeOnLoadMethod]
static void PreInit() {
EditorApplication.delayCall -= Init;
EditorApplication.delayCall += Init;
}static void Init(){
#if UNITY_2019_3_OR_NEWER
ParadoxNotion.Design.AssetTracker.onAssetsImported -= OnAssetsImported;
ParadoxNotion.Design.AssetTracker.onAssetsImported += OnAssetsImported;
#endif
//we track graph assets so that we can access them on a diff thread
AssetTracker.BeginTrackingAssetsOfType(typeof(Graph));
AssetTracker.BeginTrackingAssetsOfType(typeof(TextAsset));
}private const string SERIALIZATION_START = “#—GRAPH_START—“;
private const string SERIALIZATION_END = “#—GRAPH_END—“;
private const string IS_YAML = “%YAML”;//Asset Tracker callback
static void OnAssetsImported(string[] paths) {
var willRefresh = false;
foreach ( var path in paths ) {
var asset = AssetDatabase.LoadAssetAtPath(path, typeof(Graph));
if ( asset is Graph graphAsset)
{
// If the graph has changed we should update the json text asset
var localPath = AssetDatabase.GetAssetPath(graphAsset) + “.json”;
var systemPath = EditorUtils.AssetToSystemPath(localPath);
var pretyJson = ParadoxNotion.Serialization.JSONSerializer.PrettifyJson(graphAsset.GetSerializedJsonData());// has the graph actually changed?
var writeJsonFile = File.Exists(systemPath) == false || File.ReadAllText(systemPath) != pretyJson;
if (writeJsonFile)
{
willRefresh = true;
File.WriteAllText(systemPath, pretyJson);
}
}asset = AssetDatabase.LoadAssetAtPath(path, typeof(TextAsset));
if ( asset is TextAsset textAsset) {// If the json has changed we should update the graph asset
var localPath = AssetDatabase.GetAssetPath(textAsset);
var match = Regex.Match(localPath, @”(?.*\.asset)\.json$”);
if (match.Success)
{
var graphPath = match.Groups[“graph”].Value;
var graph = (Graph)AssetDatabase.LoadAssetAtPath(graphPath, typeof(Graph));
if (graph != null)
{
willRefresh = true;
graph.OverwriteSerializedGraphString(textAsset.text);
EditorUtility.SetDirty(graph);
AssetDatabase.ImportAsset(graphPath); // Do I need to do this? I have no idea!
}
}
}
}
if ( willRefresh ) { EditorApplication.delayCall += () => AssetDatabase.Refresh(); }
}///Append prety json to yaml file as comments for version control diff purposes
static void AppendPrettyJSONComments(Graph graph, string path) {
var systemPath = EditorUtils.AssetToSystemPath(path);
var lines = File.ReadAllLines(systemPath);//not a yaml? bail out.
if ( lines.Length == 0 || !lines[0].StartsWith(IS_YAML) ) { return; }var result = new List(lines.Length);
//clear previous. Unity actually does not keep any changes made to the file, but I don’t trust this will always be the case.
var skip = false;
for ( var i = 0; i < lines.Length; i++ ) {
var line = lines;
if ( line.StartsWith(SERIALIZATION_START) ) { skip = true; }
if ( skip ) { continue; }
if ( line.StartsWith(SERIALIZATION_END) ) {
skip = false;
continue;
}
result.Add(line);
}//add new
result.Add(SERIALIZATION_START);
result.Add(“#The pretty formatted json serialization bellow is only a reference to help in version control diff. Other than that it is not used at all.”);
var pretyJson = ParadoxNotion.Serialization.JSONSerializer.PrettifyJson(graph.GetSerializedJsonData());
var split = pretyJson.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.None);
for ( var i = 0; i < split.Length; i++ ) {
var newLine = ‘#’ + split;
result.Add(newLine);
}
result.Add(SERIALIZATION_END);File.WriteAllLines(systemPath, result);
}}
}#endif
This allows changes to the JSON file that serialize into the main asset … or you can just ignore it because the original graph asset is the single source of truth in non-editor mode. It seems to generally work but I’m not a very experienced Editor scripter.
Anyways, I thought I would share.