NodeCanvas Forums › General Discussion › [FEATURE REQUEST] Add an option to disable minified JSON graph serialization
Tagged: serialization git versioncontrol
When working with version control, the minified json used in graph assets can be a bit of a pain to work with, as any small change to the graph result in huge diffs that can be annoying to sift through. Using pretty print instead isn’t a perfect solution, as formatting is kind of ruined once written to the asset (and I’m not sure we have any control over this?), but I still believe it’s a more readable solution for version control.
I think it would be a good middle ground to keep the default minified, but allow us the option to enable pretty printed serialization. This would also have to be a project based setting that can be picked up by version control so the entire team uses the same setting for serialization.
Hello there,
This is something I’ve been struggling with in the past, but unfortunately serializing the json in a clean pretty format is not possible. A serialized pretty json string field in a Unity Asset, actually ends up looking worst than a minified one and not very helpful for diff purposes. 🙁 Here is an example of how it looks:
Join us on Discord: https://discord.gg/97q2Rjh
This is a pretty big issue for any project working with VCS – would it be possible to write out the serialized json as a companion file and load it in at runtime? Then maybe bake everything together at build time?
Hello there.
There is already a similar feature suggestion to automatically serialize the graph to an external pretty json file alongside the graph and load from that file in runtime. This is something that I will implement soon. With that said, there is already the possibility of manually exporting the graph serialization to a pretty json file and importing from json in runtime, but of course the goal above it to do this automatically.
Is this described feature above what you were suggesting as well?
Join us on Discord: https://discord.gg/97q2Rjh
Wait, so if I manually export the graph – it will load it from the file in runtime going forward?
I’m not seeing that functionality, but was hoping you could point me in the direction of the serialization so that I could hack a solution. We’re getting multiple daily conflicts and its just not an acceptable workflow
Here is a first start on reading/writing to disk. This is only editor atm, need to add build logic to bake it BACK in. This is a git patch. I name the resulting json files with a preceding “.” to ensure Unity ignores them. NOTE: this is super hacky. My recommendation would be to serialize into YAML. Mixing data formats is generally going to result in an inelegant solution
For Graph.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
diff --git a/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/Graph.cs b/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/Graph.cs index 49810cfd..8700ef67 100644 --- a/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/Graph.cs +++ b/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/Graph.cs @@ -8,6 +8,9 @@ using ParadoxNotion.Services; using UnityEngine; using Logger = ParadoxNotion.Services.Logger; using UndoUtility = ParadoxNotion.Design.UndoUtility; +using UnityEditor; +using System.IO; +using UnityEditor.SceneManagement; namespace NodeCanvas.Framework { @@ -29,6 +32,8 @@ namespace NodeCanvas.Framework //the json graph [SerializeField] private string _serializedGraph; + //the json graph file path + [SerializeField] private string _serializedGraphFile; //the unity references used for json graph [SerializeField] private List<UnityEngine.Object> _objectReferences; //the actual graph data. Mixed serialized by Unity/Json @@ -49,13 +54,72 @@ namespace NodeCanvas.Framework ///---------------------------------------------------------------------------------------------- ///---------------------------------------------------------------------------------------------- - protected void OnEnable() { Validate(); OnGraphObjectEnable(); } + protected void OnEnable() { getAssetPath(); Validate(); OnGraphObjectEnable(); } protected void OnDisable() { OnGraphObjectDisable(); } protected void OnDestroy() { Stop(); OnGraphObjectDestroy(); } protected void OnValidate() { /*we dont need this now*/ } protected void Reset() { OnGraphValidate(); } ///---------------------------------------------------------------------------------------------- + public void getAssetPath() => getAssetPath(false, ref _serializedGraphFile); + public void getAssetPath(bool isBoundGraph, ref string file) + { +#if UNITY_EDITOR + if (!string.IsNullOrEmpty(file)) return; + var path = AssetDatabase.GetAssetPath(this); + if (string.IsNullOrEmpty(path)) + { + // try to get owner for bound graphs + if (!isBoundGraph) + { + //Debug.Log($"getAssetPath failed for {(name)}"); + return; + } + path = PrefabStageUtility.GetCurrentPrefabStage()?.assetPath; + if (string.IsNullOrEmpty(path)) + { + //Debug.Log($"getAssetPath failed for owner {name}"); + return; + } + } + EditorUtility.SetDirty(this); + file = Path.Combine(Path.GetDirectoryName(path), "." + Path.GetFileNameWithoutExtension(path) + ".JSON"); + //Debug.Log($"getAssetPath set {_serializedGraphFile}"); + //AssetDatabase.SaveAssets(); + //AssetDatabase.Refresh(); +#endif + + } +#if UNITY_EDITOR + public void WriteToDisk() => WriteToDisk(_serializedGraphFile, ref _serializedGraph); + public void WriteToDisk(string file, ref string result) + { + if (string.IsNullOrEmpty(file)) + { + //Debug.Log($"WriteToDisk failed for \n {file} "); + return; + } + File.WriteAllText(file, this.Serialize(_objectReferences, pretyJson:true)); + result = file; + //Debug.Log($"WriteToDisk {file}"); + } + public void ReadFromDisk() => ReadFromDisk(_serializedGraphFile, ref _serializedGraph); + public void ReadFromDisk(string file, ref string result) + { + if (string.IsNullOrEmpty(file)) + { + //Debug.Log($"ReadFromDisk failed for \n {file} "); + return; + } + if (File.Exists(file)) + { + result = File.ReadAllText(file); + } + //Debug.Log($"ReadFromDisk {file}"); + } +#endif + + ///<summary>Serialize the Graph. Return if serialization changed</summary> public bool SelfSerialize() { @@ -93,6 +157,11 @@ namespace NodeCanvas.Framework onGraphSerialized(this); } + +#if UNITY_EDITOR + WriteToDisk(); +#endif + //purge cache and refs graphSource.PurgeRedundantReferences(); flatMetaGraph = null; @@ -108,6 +177,11 @@ namespace NodeCanvas.Framework ///<summary>Deserialize the Graph. Return if that succeed</summary> public bool SelfDeserialize() { + +#if UNITY_EDITOR + ReadFromDisk(); +#endif + if ( Deserialize(_serializedGraph, _objectReferences, false) ) { //raise event @@ -124,10 +198,10 @@ namespace NodeCanvas.Framework ///---------------------------------------------------------------------------------------------- ///<summary>Serialize the graph and returns the serialized json string. The provided objectReferences list will be cleared and populated with the found unity object references.</summary> - public string Serialize(List<UnityEngine.Object> references) { + public string Serialize(List<UnityEngine.Object> references, bool pretyJson = false) { if ( references == null ) { references = new List<Object>(); } UpdateNodeIDs(true); - var result = JSONSerializer.Serialize(typeof(GraphSource), graphSource.Pack(this), references); + var result = JSONSerializer.Serialize(typeof(GraphSource), graphSource.Pack(this), references, pretyJson: pretyJson); return result; } |
And for GraphOwner.cs (to also generate for bound prefabs):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
diff --git a/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/GraphOwner.cs b/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/GraphOwner.cs index 31e3ab64..45be7c5d 100644 --- a/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/GraphOwner.cs +++ b/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/GraphOwner.cs @@ -69,6 +69,8 @@ namespace NodeCanvas.Framework ///<summary>Raised only once when "Start" is called, then is set to null</summary> public event System.Action onMonoBehaviourStart; + [SerializeField, FormerlySerializedAs("boundGraphSerializationFile")] + private string _boundGraphSerializationFile; [SerializeField, FormerlySerializedAs("boundGraphSerialization")] private string _boundGraphSerialization; [SerializeField, FormerlySerializedAs("boundGraphObjectReferences")] @@ -443,6 +445,9 @@ namespace NodeCanvas.Framework boundGraphSerialization = serializedGraph.GetSerializedJsonData(); boundGraphObjectReferences = serializedGraph.GetSerializedReferencesData(); ParadoxNotion.Design.UndoUtility.SetDirty(this); + + serializedGraph.getAssetPath(isBoundGraph: true, ref _boundGraphSerializationFile); + serializedGraph.WriteToDisk(_boundGraphSerializationFile, ref _boundGraphSerialization); } } @@ -462,6 +467,10 @@ namespace NodeCanvas.Framework boundGraphInstance.name = graphType.Name; boundGraphInstance.SetGraphSourceMetaData(this.boundGraphSource); + + boundGraphInstance.getAssetPath(isBoundGraph:true, ref _boundGraphSerializationFile); + boundGraphInstance.ReadFromDisk(_boundGraphSerializationFile, ref _boundGraphSerialization); + boundGraphInstance.Deserialize(boundGraphSerialization, boundGraphObjectReferences, false); boundGraphInstance.UpdateReferencesFromOwner(this); boundGraphInstance.Validate(); |
And here is a git patch to resolve the viewport changes – way too many updates due to this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
diff --git a/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/Internal/GraphSource.cs b/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/Internal/GraphSource.cs index 70479553..a84f7b2c 100644 --- a/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/Internal/GraphSource.cs +++ b/Assets/ParadoxNotion/CanvasCore/Framework/Runtime/Graphs/Internal/GraphSource.cs @@ -36,9 +36,9 @@ namespace NodeCanvas.Framework.Internal private string _category; [SerializeField, fsSerializeAs("comments"), fsWriteOnly, fsIgnoreInBuild] private string _comments; - [SerializeField, fsSerializeAs("translation"), fsWriteOnly, fsIgnoreInBuild] + [System.NonSerialized] private Vector2 _translation; - [SerializeField, fsSerializeAs("zoomFactor"), fsWriteOnly, fsIgnoreInBuild] + [System.NonSerialized] private float _zoomFactor; [fsSerializeAs("type")] |
Hello again.
Thank you. I will look at the changes even though I have already worked on the external file serialization/deserialization 🙂
Regarding your last post changes, do you mean about serializing the translation and zoom factor and marking the asset as dirty?
Thank you.
Join us on Discord: https://discord.gg/97q2Rjh
Hey!
This is more of a hack for users who need a solution. Less of a suggestion for you. The second git patch is to disable serializing the translation. Way too many updates for just a view change.
Ultimately, though, it looks like node canvas might not meet the needs for our use case. The merge conflicts are just not viable.
The automatic serialisation of the graph to an external nice json file alongside the graph and runtime loading from that file is already a suggested feature. This is something I’ll start doing soon.
ciyapa
This is a big issue for any project working with VCS – would it be possible to write out the HCMI as a companion file and load it in at runtime? Then maybe bake everything together at build time?
Hello again.
Thank you. I will look at the changes even though I have already worked on the external file serialization/deserialization
Regarding your last post changes, do you mean about serializing the translation and zoom factor and marking the asset as dirty?
Thank you.
This would be for anyone else who needs a workaround until you have your external changes live (like me and the OP).
And yes – that is nuking the translation + zoom serializing changes. I saw some questions asking to disable that, and I did it for myself. Thought I would share the patch as well.
Its just a shame that Unity doesn’t support chomping indicator |, or this would be so much easier