| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- using System;
- using System.Linq;
- using YamlDotNet.RepresentationModel;
- namespace Content.Tools
- {
- public static class YamlTools
- {
- public static YamlNode CopyYamlNodes(YamlNode other)
- {
- switch (other)
- {
- case YamlSequenceNode subSequence:
- var tmp1 = new YamlSequenceNode();
- MergeYamlSequences(tmp1, new YamlSequenceNode(), subSequence, "");
- return tmp1;
- case YamlMappingNode subMapping:
- var tmp2 = new YamlMappingNode();
- MergeYamlMappings(tmp2, new YamlMappingNode(), subMapping, "", Array.Empty<string>());
- return tmp2;
- case YamlScalarNode subScalar:
- var tmp3 = new YamlScalarNode();
- CopyYamlScalar(tmp3, subScalar);
- return tmp3;
- default:
- throw new ArgumentException($"Unrecognized YAML node type for copy: {other.GetType()}", nameof(other));
- }
- }
- public static bool TriTypeMatch(YamlNode ours, YamlNode based, YamlNode other)
- {
- var refType = other.GetType();
- if (refType != based.GetType())
- return false;
- if (refType != ours.GetType())
- return false;
- return true;
- }
- public static void MergeYamlNodes(YamlNode ours, YamlNode based, YamlNode other, string path)
- {
- if (!TriTypeMatch(ours, based, other))
- throw new ArgumentException($"Node type mismatch at {path}");
- switch (other)
- {
- case YamlSequenceNode subSequence:
- MergeYamlSequences((YamlSequenceNode) ours, (YamlSequenceNode) based, subSequence, path);
- break;
- case YamlMappingNode subMapping:
- MergeYamlMappings((YamlMappingNode) ours, (YamlMappingNode) based, subMapping, path, Array.Empty<string>());
- break;
- case YamlScalarNode subScalar:
- // Console.WriteLine(path + " - " + ours + " || " + based + " || " + other);
- var scalarA = (YamlScalarNode) ours;
- var scalarB = (YamlScalarNode) based;
- var scalarC = subScalar;
- var aeb = (scalarA.Value == scalarB.Value);
- var cneb = (scalarC.Value != scalarB.Value);
- if (aeb || cneb)
- CopyYamlScalar(scalarA, scalarC);
- // Console.WriteLine(path + " . " + ours + " || " + based + " || " + other);
- break;
- default:
- throw new ArgumentException($"Unrecognized YAML node type at {path}: {other.GetType()}", nameof(other));
- }
- }
- public static void MergeYamlSequences(YamlSequenceNode ours, YamlSequenceNode based, YamlSequenceNode other, string path)
- {
- if (ours.Children.Count == based.Children.Count && other.Children.Count == ours.Children.Count)
- {
- // this is terrible and doesn't do proper rearrange detection
- // but it looks as if vectors might be arrays
- // so rearrange detection might break more stuff...
- // nope, they aren't, but still good to have
- for (var i = 0; i < ours.Children.Count; i++)
- MergeYamlNodes(ours.Children[i], based.Children[i], other.Children[i], path + "/" + i);
- return;
- }
- // for now, just copy other -> ours
- // I am aware this is terrible
- ours.Children.Clear();
- foreach (var c in other.Children)
- ours.Add(CopyYamlNodes(c));
- }
- public static void MergeYamlMappings(YamlMappingNode ours, YamlMappingNode based, YamlMappingNode other, string path, string[] ignoreThese)
- {
- // Deletions/modifications
- foreach (var kvp in based)
- {
- if (ignoreThese.Contains(kvp.Key.ToString()))
- continue;
- var localPath = path + "/" + kvp.Key;
- var deletedByOurs = !ours.Children.ContainsKey(kvp.Key);
- var deletedByOther = !other.Children.ContainsKey(kvp.Key);
- if (deletedByOther && !deletedByOurs)
- {
- // Delete
- ours.Children.Remove(kvp.Key);
- }
- else if (!(deletedByOurs || deletedByOther))
- {
- // Modify
- var a = ours[kvp.Key];
- var b = kvp.Value; // based[kvp.Key]
- var c = other[kvp.Key];
- if (!TriTypeMatch(a, b, c))
- {
- Console.WriteLine("Warning: Type mismatch (defaulting to value C) at " + localPath);
- ours.Children[kvp.Key] = CopyYamlNodes(c);
- }
- else
- {
- MergeYamlNodes(a, b, c, localPath);
- }
- }
- }
- // Additions
- foreach (var kvp in other)
- {
- if (ignoreThese.Contains(kvp.Key.ToString()))
- continue;
- var localPath = path + "/" + kvp.Key;
- if (!based.Children.ContainsKey(kvp.Key))
- {
- if (ours.Children.ContainsKey(kvp.Key))
- {
- // Both sides added the same key. Try to merge.
- var a = ours[kvp.Key];
- var b = based[kvp.Key];
- var c = kvp.Value; // other[kvp.Key]
- if (!TriTypeMatch(a, b, c))
- {
- Console.WriteLine("Warning: Type mismatch (defaulting to value C) at " + localPath);
- ours.Children[kvp.Key] = CopyYamlNodes(c);
- }
- else
- {
- MergeYamlNodes(a, b, c, localPath);
- }
- }
- else
- {
- // Well that was easy
- ours.Children[kvp.Key] = CopyYamlNodes(kvp.Value);
- }
- }
- }
- }
- // NOTE: This is a heuristic ONLY! And is also not used at the moment because sequence matching isn't in place.
- // It could also be massively improved.
- public static float YamlNodesHeuristic(YamlNode a, YamlNode b)
- {
- if (a.GetType() != b.GetType())
- return 0.0f;
- return a switch
- {
- YamlSequenceNode x => YamlSequencesHeuristic(x, (YamlSequenceNode) b),
- YamlMappingNode y => YamlMappingsHeuristic(y, (YamlMappingNode) b),
- YamlScalarNode z => (z.Value == ((YamlScalarNode) b).Value) ? 1.0f : 0.0f,
- _ => throw new ArgumentException($"Unrecognized YAML node type: {a.GetType()}", nameof(a))
- };
- }
- public static float YamlSequencesHeuristic(YamlSequenceNode a, YamlSequenceNode b)
- {
- if (a.Children.Count != b.Children.Count)
- return 0.0f;
- if (a.Children.Count == 0)
- return 1.0f;
- var total = 0.0f;
- for (var i = 0; i < a.Children.Count; i++)
- total += YamlNodesHeuristic(a.Children[i], b.Children[i]);
- return total / a.Children.Count;
- }
- public static float YamlMappingsHeuristic(YamlMappingNode a, YamlMappingNode b)
- {
- return Equals(a, b) ? 1.0f : 0.0f;
- }
- public static void CopyYamlScalar(YamlScalarNode dst, YamlScalarNode src)
- {
- dst.Value = src.Value;
- dst.Style = src.Style;
- }
- }
- }
|