Reply To: Diffability

Forums 💬 NodeCanvas ⚙️ Support Diffability Reply To: Diffability

#16640
locutis
Participant

    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[i];
    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[i];
    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.