diff --git a/OpenRA.FileFormats/MiniYaml.cs b/OpenRA.FileFormats/MiniYaml.cs index fd09ad4608..04d3a1b9f9 100755 --- a/OpenRA.FileFormats/MiniYaml.cs +++ b/OpenRA.FileFormats/MiniYaml.cs @@ -21,7 +21,8 @@ namespace OpenRA.FileFormats { public struct SourceLocation { - public string Filename; public int Line; + public string Filename; public int Line; + public override string ToString() { return "{0}:{1}".F(Filename, Line); } } public SourceLocation Location; @@ -52,7 +53,12 @@ namespace OpenRA.FileFormats public MiniYamlNode( string k, string v, List n, SourceLocation loc ) : this( k, new MiniYaml( v, n ), loc ) { - } + } + + public override string ToString() + { + return "{{YamlNode: {0} @ {1}}}".F(Key, Location); + } } public class MiniYaml @@ -95,7 +101,7 @@ namespace OpenRA.FileFormats var level = line.Length - t.Length; if (levels.Count <= level) - throw new InvalidOperationException("Bad indent in miniyaml"); + throw new YamlException("Bad indent in miniyaml"); while (levels.Count > level + 1) levels.RemoveAt(levels.Count - 1); @@ -169,9 +175,10 @@ namespace OpenRA.FileFormats var aDict = a.ToDictionary( x => x.Key ); var bDict = b.ToDictionary( x => x.Key ); - var keys = aDict.Keys.Union( bDict.Keys ).ToList(); - - var noInherit = keys.Where( x => x.Length > 0 && x[ 0 ] == '-' ).Select( x => x.Substring( 1 ) ).ToList(); + var keys = aDict.Keys.Union( bDict.Keys ).ToList(); + + var noInherit = keys.Where(x => x.Length > 0 && x[0] == '-') + .ToDictionary(x => x.Substring(1), x => false); foreach( var key in keys ) { @@ -179,10 +186,11 @@ namespace OpenRA.FileFormats aDict.TryGetValue( key, out aa ); bDict.TryGetValue( key, out bb ); - if( noInherit.Contains( key ) ) + if( noInherit.ContainsKey( key ) ) { - if( aa != null ) - ret.Add( aa ); + // if( aa != null ) + // ret.Add( aa ); + noInherit[key] = true; } else { @@ -190,7 +198,11 @@ namespace OpenRA.FileFormats var merged = ( aa == null || bb == null ) ? aa ?? bb : new MiniYamlNode( key, Merge( aa.Value, bb.Value ), loc ); ret.Add( merged ); } - } + } + + if (noInherit.ContainsValue(false)) + throw new YamlException("Bogus yaml removals: {0}".F( + string.Join(", ", noInherit.Where(x => !x.Value).Select(x => x.Key).ToArray()))); return ret; } @@ -236,5 +248,10 @@ namespace OpenRA.FileFormats yield return ""; } } - } + } + + public class YamlException : Exception + { + public YamlException(string s) : base(s) { } + } } diff --git a/OpenRA.Game/GameRules/ActorInfo.cs b/OpenRA.Game/GameRules/ActorInfo.cs index 39c0065c18..f421c34138 100644 --- a/OpenRA.Game/GameRules/ActorInfo.cs +++ b/OpenRA.Game/GameRules/ActorInfo.cs @@ -22,14 +22,30 @@ namespace OpenRA public readonly TypeDictionary Traits = new TypeDictionary(); public ActorInfo( string name, MiniYaml node, Dictionary allUnits ) - { - var mergedNode = MergeWithParent( node, allUnits ).NodesDict; - - Name = name; - foreach( var t in mergedNode ) - if( t.Key != "Inherits" && !t.Key.StartsWith("-") ) - Traits.Add( LoadTraitInfo( t.Key.Split('@')[0], t.Value ) ); - } + { + try + { + var mergedNode = MergeWithParent(node, allUnits).NodesDict; + + Name = name; + foreach (var t in mergedNode) + if (t.Key != "Inherits" && !t.Key.StartsWith("-")) + Traits.Add(LoadTraitInfo(t.Key.Split('@')[0], t.Value)); + } + catch (YamlException e) + { + throw new YamlException("Actor type {0}: {1}".F(name, e.Message)); + } + } + + static IEnumerable GetInheritanceChain(MiniYaml node, Dictionary allUnits) + { + while (node != null) + { + yield return node; + node = GetParent(node, allUnits); + } + } static MiniYaml GetParent( MiniYaml node, Dictionary allUnits ) { @@ -49,9 +65,15 @@ namespace OpenRA static MiniYaml MergeWithParent( MiniYaml node, Dictionary allUnits ) { - var parent = GetParent( node, allUnits ); - if( parent != null ) - return MiniYaml.Merge( node, MergeWithParent( parent, allUnits ) ); + var parent = GetParent( node, allUnits ); + if (parent != null) + { + var result = MiniYaml.Merge(node, MergeWithParent(parent, allUnits)); + + // strip the '-' + result.Nodes.RemoveAll(a => a.Key.StartsWith("-")); + return result; + } return node; }