diff --git a/OpenRA.Game/MiniYaml.cs b/OpenRA.Game/MiniYaml.cs index 7245d52c22..3aff12f350 100644 --- a/OpenRA.Game/MiniYaml.cs +++ b/OpenRA.Game/MiniYaml.cs @@ -257,7 +257,9 @@ namespace OpenRA if (!sources.Any()) return new List(); - var tree = sources.Where(s => s != null).Aggregate(MergePartial) + var tree = sources.Where(s => s != null) + .Select(MergeSelfPartial) + .Aggregate(MergePartial) .ToDictionary(n => n.Key, n => n.Value); var resolved = new Dictionary(); @@ -325,6 +327,42 @@ namespace OpenRA return resolved; } + /// + /// Merges any duplicate keys that are defined within the same set of nodes. + /// Does not resolve inheritance or node removals. + /// + static MiniYaml MergeSelfPartial(MiniYaml existingNodes) + { + // Nothing to do + if (existingNodes.Nodes == null || existingNodes.Nodes.Count == 0) + return existingNodes; + + return new MiniYaml(existingNodes.Value, MergeSelfPartial(existingNodes.Nodes)); + } + + /// + /// Merges any duplicate keys that are defined within the same set of nodes. + /// Does not resolve inheritance or node removals. + /// + static List MergeSelfPartial(List existingNodes) + { + var keys = new HashSet(); + var ret = new List(); + foreach (var n in existingNodes) + { + if (keys.Add(n.Key)) + ret.Add(n); + else + { + // Node with the same key has already been added: merge new node over the existing one + var original = ret.First(r => r.Key == n.Key); + original.Value = MergePartial(original.Value, n.Value); + } + } + + return ret; + } + static MiniYaml MergePartial(MiniYaml existingNodes, MiniYaml overrideNodes) { if (existingNodes == null)