diff --git a/OpenRA.Editor/Form1.cs b/OpenRA.Editor/Form1.cs index 5ad9aa333d..f7dbd2ca27 100644 --- a/OpenRA.Editor/Form1.cs +++ b/OpenRA.Editor/Form1.cs @@ -88,7 +88,11 @@ namespace OpenRA.Editor foreach (var init in Program.Rules.Actors[kv.Value.Type].GetInitKeys()) apd.AddRow(init.First, apd.MakeEditorControl(init.Second, - () => objSaved.NodesDict.ContainsKey(init.First) ? objSaved.NodesDict[init.First].Value : null, + () => + { + var nodesDict = objSaved.ToDictionary(); + return nodesDict.ContainsKey(init.First) ? nodesDict[init.First].Value : null; + }, _ => { })); apd.ShowDialog(); diff --git a/OpenRA.Game/GameRules/ActorInfo.cs b/OpenRA.Game/GameRules/ActorInfo.cs index 1151b7c18c..6274a9d6e1 100644 --- a/OpenRA.Game/GameRules/ActorInfo.cs +++ b/OpenRA.Game/GameRules/ActorInfo.cs @@ -33,7 +33,7 @@ namespace OpenRA { try { - var mergedNode = MergeWithParent(node, allUnits).NodesDict; + var mergedNode = MergeWithParent(node, allUnits).ToDictionary(); Name = name; foreach (var t in mergedNode) @@ -49,7 +49,7 @@ namespace OpenRA static MiniYaml GetParent( MiniYaml node, Dictionary allUnits ) { MiniYaml inherits; - node.NodesDict.TryGetValue( "Inherits", out inherits ); + node.ToDictionary().TryGetValue( "Inherits", out inherits ); if( inherits == null || string.IsNullOrEmpty( inherits.Value ) ) return null; diff --git a/OpenRA.Game/GameRules/MusicInfo.cs b/OpenRA.Game/GameRules/MusicInfo.cs index 59fca18bb1..133a1b9bff 100644 --- a/OpenRA.Game/GameRules/MusicInfo.cs +++ b/OpenRA.Game/GameRules/MusicInfo.cs @@ -24,7 +24,7 @@ namespace OpenRA.GameRules { Title = value.Value; - var nd = value.NodesDict; + var nd = value.ToDictionary(); var ext = nd.ContainsKey("Extension") ? nd["Extension"].Value : "aud"; Filename = (nd.ContainsKey("Filename") ? nd["Filename"].Value : key)+"."+ext; if (!GlobalFileSystem.Exists(Filename)) diff --git a/OpenRA.Game/GameRules/SoundInfo.cs b/OpenRA.Game/GameRules/SoundInfo.cs index 6f88c6f114..0eb8e66da7 100644 --- a/OpenRA.Game/GameRules/SoundInfo.cs +++ b/OpenRA.Game/GameRules/SoundInfo.cs @@ -28,10 +28,9 @@ namespace OpenRA.GameRules static Dictionary Load(MiniYaml y, string name) { - return y.NodesDict.ContainsKey(name) - ? y.NodesDict[name].NodesDict.ToDictionary( - a => a.Key, - a => FieldLoader.GetValue("(value)", a.Value.Value)) + var nd = y.ToDictionary(); + return nd.ContainsKey(name) + ? nd[name].ToDictionary(my => FieldLoader.GetValue("(value)", my.Value)) : new Dictionary(); } diff --git a/OpenRA.Game/GameRules/WeaponInfo.cs b/OpenRA.Game/GameRules/WeaponInfo.cs index 13d35fb9cf..f62abf5771 100644 --- a/OpenRA.Game/GameRules/WeaponInfo.cs +++ b/OpenRA.Game/GameRules/WeaponInfo.cs @@ -73,10 +73,9 @@ namespace OpenRA.GameRules static object LoadVersus(MiniYaml y) { - return y.NodesDict.ContainsKey("Versus") - ? y.NodesDict["Versus"].NodesDict.ToDictionary( - a => a.Key, - a => FieldLoader.GetValue("(value)", a.Value.Value)) + var nd = y.ToDictionary(); + return nd.ContainsKey("Versus") + ? nd["Versus"].ToDictionary(my => FieldLoader.GetValue("(value)", my.Value)) : new Dictionary(); } } @@ -126,7 +125,7 @@ namespace OpenRA.GameRules static object LoadProjectile(MiniYaml yaml) { MiniYaml proj; - if (!yaml.NodesDict.TryGetValue("Projectile", out proj)) + if (!yaml.ToDictionary().TryGetValue("Projectile", out proj)) return null; var ret = Game.CreateObject(proj.Value + "Info"); FieldLoader.Load(ret, proj); diff --git a/OpenRA.Game/Graphics/CursorProvider.cs b/OpenRA.Game/Graphics/CursorProvider.cs index 9c00994f49..abb792777d 100644 --- a/OpenRA.Game/Graphics/CursorProvider.cs +++ b/OpenRA.Game/Graphics/CursorProvider.cs @@ -31,20 +31,20 @@ namespace OpenRA.Graphics var sequences = new MiniYaml(null, sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(MiniYaml.MergeLiberal)); var shadowIndex = new int[] { }; - if (sequences.NodesDict.ContainsKey("ShadowIndex")) + var nodesDict = sequences.ToDictionary(); + if (nodesDict.ContainsKey("ShadowIndex")) { Array.Resize(ref shadowIndex, shadowIndex.Length + 1); - Exts.TryParseIntegerInvariant(sequences.NodesDict["ShadowIndex"].Value, + Exts.TryParseIntegerInvariant(nodesDict["ShadowIndex"].Value, out shadowIndex[shadowIndex.Length - 1]); } palette = new HardwarePalette(); - foreach (var p in sequences.NodesDict["Palettes"].Nodes) + foreach (var p in nodesDict["Palettes"].Nodes) palette.AddPalette(p.Key, new Palette(GlobalFileSystem.Open(p.Value.Value), shadowIndex), false); - var spriteLoader = new SpriteLoader(new string[0], new SheetBuilder(SheetType.Indexed)); - foreach (var s in sequences.NodesDict["Cursors"].Nodes) + foreach (var s in nodesDict["Cursors"].Nodes) LoadSequencesForCursor(spriteLoader, s.Key, s.Value); palette.Initialize(); diff --git a/OpenRA.Game/Graphics/CursorSequence.cs b/OpenRA.Game/Graphics/CursorSequence.cs index 22c0da8678..0ee6a0a4d0 100644 --- a/OpenRA.Game/Graphics/CursorSequence.cs +++ b/OpenRA.Game/Graphics/CursorSequence.cs @@ -28,7 +28,7 @@ namespace OpenRA.Graphics public CursorSequence(SpriteLoader loader, string cursorSrc, string palette, MiniYaml info) { sprites = loader.LoadAllSprites(cursorSrc); - var d = info.NodesDict; + var d = info.ToDictionary(); start = Exts.ParseIntegerInvariant(d["start"].Value); this.palette = palette; diff --git a/OpenRA.Game/Graphics/Sequence.cs b/OpenRA.Game/Graphics/Sequence.cs index 6f0d5802e3..936f8d1c6e 100644 --- a/OpenRA.Game/Graphics/Sequence.cs +++ b/OpenRA.Game/Graphics/Sequence.cs @@ -33,7 +33,7 @@ namespace OpenRA.Graphics { var srcOverride = info.Value; Name = name; - var d = info.NodesDict; + var d = info.ToDictionary(); var offset = float2.Zero; var blendMode = BlendMode.Alpha; diff --git a/OpenRA.Game/Graphics/SequenceProvider.cs b/OpenRA.Game/Graphics/SequenceProvider.cs index 340cc622d9..6b9b71223a 100644 --- a/OpenRA.Game/Graphics/SequenceProvider.cs +++ b/OpenRA.Game/Graphics/SequenceProvider.cs @@ -118,7 +118,7 @@ namespace OpenRA.Graphics else { t = Exts.Lazy(() => (IReadOnlyDictionary)new ReadOnlyDictionary( - node.Value.NodesDict.ToDictionary(x => x.Key, x => + node.Value.ToDictionary().ToDictionary(x => x.Key, x => { using (new Support.PerfTimer("new Sequence(\"{0}\")".F(node.Key), 20)) return new Sequence(spriteLoader.Value, node.Key, x.Key, x.Value); diff --git a/OpenRA.Game/Graphics/VoxelProvider.cs b/OpenRA.Game/Graphics/VoxelProvider.cs index 683f3b5fd8..ca30c8663f 100644 --- a/OpenRA.Game/Graphics/VoxelProvider.cs +++ b/OpenRA.Game/Graphics/VoxelProvider.cs @@ -33,7 +33,7 @@ namespace OpenRA.Graphics Game.modData.VoxelLoader.RefreshBuffer(); } - static Voxel LoadVoxel(string unit, string name, MiniYaml info) + static Voxel LoadVoxel(string unit, MiniYaml info) { var vxl = unit; var hva = unit; @@ -55,7 +55,7 @@ namespace OpenRA.Graphics Game.modData.LoadScreen.Display(); try { - var seq = sequences.NodesDict.ToDictionary(x => x.Key, x => LoadVoxel(unit,x.Key,x.Value)); + var seq = sequences.ToDictionary(my => LoadVoxel(unit, my)); units.Add(unit, seq); } catch (FileNotFoundException) {} // Do nothing; we can crash later if we actually wanted art diff --git a/OpenRA.Game/Manifest.cs b/OpenRA.Game/Manifest.cs index 6734adb179..194dadca8c 100644 --- a/OpenRA.Game/Manifest.cs +++ b/OpenRA.Game/Manifest.cs @@ -37,7 +37,7 @@ namespace OpenRA public Manifest(string mod) { var path = new[] { "mods", mod, "mod.yaml" }.Aggregate(Path.Combine); - var yaml = new MiniYaml(null, MiniYaml.FromFile(path)).NodesDict; + var yaml = new MiniYaml(null, MiniYaml.FromFile(path)).ToDictionary(); Mod = FieldLoader.Load(yaml["Metadata"]); Mod.Id = mod; @@ -68,9 +68,11 @@ namespace OpenRA LoadScreen = yaml["LoadScreen"]; LobbyDefaults = yaml["LobbyDefaults"]; - Fonts = yaml["Fonts"].NodesDict.ToDictionary(x => x.Key, - x => Pair.New(x.Value.NodesDict["Font"].Value, - Exts.ParseIntegerInvariant(x.Value.NodesDict["Size"].Value))); + Fonts = yaml["Fonts"].ToDictionary(my => + { + var nd = my.ToDictionary(); + return Pair.New(nd["Font"].Value, Exts.ParseIntegerInvariant(nd["Size"].Value)); + }); if (yaml.ContainsKey("TileSize")) TileSize = FieldLoader.GetValue("TileSize", yaml["TileSize"].Value); @@ -94,7 +96,7 @@ namespace OpenRA if (!yaml.ContainsKey(key)) return new string[] { }; - return yaml[key].NodesDict.Keys.ToArray(); + return yaml[key].ToDictionary().Keys.ToArray(); } static IReadOnlyDictionary YamlDictionary(Dictionary yaml, string key) @@ -102,7 +104,7 @@ namespace OpenRA if (!yaml.ContainsKey(key)) return new ReadOnlyDictionary(); - var inner = yaml[key].NodesDict.ToDictionary(x => x.Key, x => x.Value.Value); + var inner = yaml[key].ToDictionary(my => my.Value); return new ReadOnlyDictionary(inner); } } diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 946ad1c90d..8e0c982b07 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -80,8 +80,9 @@ namespace OpenRA static object LoadOptions(MiniYaml y) { var options = new MapOptions(); - if (y.NodesDict.ContainsKey("Options")) - FieldLoader.Load(options, y.NodesDict["Options"]); + var nodesDict = y.ToDictionary(); + if (nodesDict.ContainsKey("Options")) + FieldLoader.Load(options, nodesDict["Options"]); return options; } @@ -185,18 +186,20 @@ namespace OpenRA RequiresMod = upgradeForMod; } + var nd = yaml.ToDictionary(); + // Load players - foreach (var kv in yaml.NodesDict["Players"].NodesDict) + foreach (var my in nd["Players"].ToDictionary().Values) { - var player = new PlayerReference(kv.Value); + var player = new PlayerReference(my); Players.Add(player.Name, player); } Actors = Exts.Lazy(() => { var ret = new Dictionary(); - foreach (var kv in yaml.NodesDict["Actors"].NodesDict) - ret.Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.NodesDict)); + foreach (var kv in nd["Actors"].ToDictionary()) + ret.Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.ToDictionary())); return ret; }); @@ -204,9 +207,9 @@ namespace OpenRA Smudges = Exts.Lazy(() => { var ret = new List(); - foreach (var kv in yaml.NodesDict["Smudges"].NodesDict) + foreach (var name in nd["Smudges"].ToDictionary().Keys) { - var vals = kv.Key.Split(' '); + var vals = name.Split(' '); var loc = vals[1].Split(','); ret.Add(new SmudgeReference(vals[0], new int2( Exts.ParseIntegerInvariant(loc[0]), diff --git a/OpenRA.Game/Map/TileSet.cs b/OpenRA.Game/Map/TileSet.cs index 3dc386006b..082cd3d49b 100644 --- a/OpenRA.Game/Map/TileSet.cs +++ b/OpenRA.Game/Map/TileSet.cs @@ -56,9 +56,9 @@ namespace OpenRA static object LoadTiles(MiniYaml y) { - return y.NodesDict["Tiles"].NodesDict.ToDictionary( - t => byte.Parse(t.Key), - t => t.Value.Value); + return y.ToDictionary()["Tiles"].ToDictionary( + name => byte.Parse(name), + my => my.Value); } static readonly string[] Fields = { "Id", "Image", "Frames", "Size", "PickAny" }; @@ -105,11 +105,11 @@ namespace OpenRA FieldLoader.Load(this, yaml["General"]); // TerrainTypes - Terrain = yaml["Terrain"].NodesDict.Values + Terrain = yaml["Terrain"].ToDictionary().Values .Select(y => new TerrainTypeInfo(y)).ToDictionary(t => t.Type); // Templates - Templates = yaml["Templates"].NodesDict.Values + Templates = yaml["Templates"].ToDictionary().Values .Select(y => new TileTemplate(y)).ToDictionary(t => t.Id); } diff --git a/OpenRA.Game/MiniYaml.cs b/OpenRA.Game/MiniYaml.cs index 7b7274dd46..26cf634957 100755 --- a/OpenRA.Game/MiniYaml.cs +++ b/OpenRA.Game/MiniYaml.cs @@ -83,23 +83,39 @@ namespace OpenRA public class MiniYaml { + static Func StringIdentity = s => s; + static Func MiniYamlIdentity = my => my; public string Value; public List Nodes; - public Dictionary NodesDict + public Dictionary ToDictionary() { - get - { - var ret = new Dictionary(); - foreach (var y in Nodes) - { - if (ret.ContainsKey(y.Key)) - throw new InvalidDataException("Duplicate key `{0}' in {1}".F(y.Key, y.Location)); - ret.Add(y.Key, y.Value); - } + return ToDictionary(MiniYamlIdentity); + } - return ret; + public Dictionary ToDictionary(Func elementSelector) + { + return ToDictionary(StringIdentity, elementSelector); + } + + public Dictionary ToDictionary( + Func keySelector, Func elementSelector) + { + var ret = new Dictionary(); + foreach (var y in Nodes) + { + var key = keySelector(y.Key); + var element = elementSelector(y.Value); + try + { + ret.Add(key, element); + } + catch (ArgumentException ex) + { + throw new InvalidDataException("Duplicate key `{0}' in {1}".F(y.Key, y.Location), ex); + } } + return ret; } public MiniYaml(string value) : this(value, null) { } @@ -122,7 +138,8 @@ namespace OpenRA public static List NodesOrEmpty(MiniYaml y, string s) { - return y.NodesDict.ContainsKey(s) ? y.NodesDict[s].Nodes : new List(); + var nd = y.ToDictionary(); + return nd.ContainsKey(s) ? nd[s].Nodes : new List(); } static List FromLines(string[] lines, string filename) diff --git a/OpenRA.Game/ModData.cs b/OpenRA.Game/ModData.cs index 1716bcd1e5..4f8754ab7f 100644 --- a/OpenRA.Game/ModData.cs +++ b/OpenRA.Game/ModData.cs @@ -38,7 +38,7 @@ namespace OpenRA Manifest = new Manifest(mod); ObjectCreator = new ObjectCreator(Manifest); LoadScreen = ObjectCreator.CreateObject(Manifest.LoadScreen.Value); - LoadScreen.Init(Manifest, Manifest.LoadScreen.NodesDict.ToDictionary(x => x.Key, x => x.Value.Value)); + LoadScreen.Init(Manifest, Manifest.LoadScreen.ToDictionary(my => my.Value)); LoadScreen.Display(); WidgetLoader = new WidgetLoader(this); RulesetCache = new RulesetCache(this); @@ -96,9 +96,9 @@ namespace OpenRA foreach (var y in yaml) { if (y.Key == Game.Settings.Graphics.Language) - selectedTranslations = y.Value.NodesDict.ToDictionary(x => x.Key, x => x.Value.Value ?? ""); - if (y.Key == Game.Settings.Graphics.DefaultLanguage) - defaultTranslations = y.Value.NodesDict.ToDictionary(x => x.Key, x => x.Value.Value ?? ""); + selectedTranslations = y.Value.ToDictionary(my => my.Value ?? ""); + else if (y.Key == Game.Settings.Graphics.DefaultLanguage) + defaultTranslations = y.Value.ToDictionary(my => my.Value ?? ""); } var translations = new Dictionary(); diff --git a/OpenRA.Game/ModMetadata.cs b/OpenRA.Game/ModMetadata.cs index b37b9d16cd..005bf9cb11 100644 --- a/OpenRA.Game/ModMetadata.cs +++ b/OpenRA.Game/ModMetadata.cs @@ -34,10 +34,11 @@ namespace OpenRA continue; var yaml = new MiniYaml(null, MiniYaml.FromFile(yamlPath)); - if (!yaml.NodesDict.ContainsKey("Metadata")) + var nd = yaml.ToDictionary(); + if (!nd.ContainsKey("Metadata")) continue; - var mod = FieldLoader.Load(yaml.NodesDict["Metadata"]); + var mod = FieldLoader.Load(nd["Metadata"]); mod.Id = m; ret.Add(m, mod); diff --git a/OpenRA.Mods.RA/AI/HackyAI.cs b/OpenRA.Mods.RA/AI/HackyAI.cs index 2e97a8e149..a0a1f1f453 100644 --- a/OpenRA.Mods.RA/AI/HackyAI.cs +++ b/OpenRA.Mods.RA/AI/HackyAI.cs @@ -68,10 +68,9 @@ namespace OpenRA.Mods.RA.AI static object LoadList(MiniYaml y, string field) { - return y.NodesDict.ContainsKey(field) - ? y.NodesDict[field].NodesDict.ToDictionary( - a => a.Key, - a => FieldLoader.GetValue(field, a.Value.Value)) + var nd = y.ToDictionary(); + return nd.ContainsKey(field) + ? nd[field].ToDictionary(my => FieldLoader.GetValue(field, my.Value)) : new Dictionary(); } diff --git a/OpenRA.Mods.RA/Move/Mobile.cs b/OpenRA.Mods.RA/Move/Mobile.cs index 3766c103a9..62d14b1017 100755 --- a/OpenRA.Mods.RA/Move/Mobile.cs +++ b/OpenRA.Mods.RA/Move/Mobile.cs @@ -41,11 +41,12 @@ namespace OpenRA.Mods.RA.Move static object LoadSpeeds(MiniYaml y) { Dictionary ret = new Dictionary(); - foreach (var t in y.NodesDict["TerrainSpeeds"].Nodes) + foreach (var t in y.ToDictionary()["TerrainSpeeds"].Nodes) { var speed = FieldLoader.GetValue("speed", t.Value.Value); - var cost = t.Value.NodesDict.ContainsKey("PathingCost") - ? FieldLoader.GetValue("cost", t.Value.NodesDict["PathingCost"].Value) + var nodesDict = t.Value.ToDictionary(); + var cost = nodesDict.ContainsKey("PathingCost") + ? FieldLoader.GetValue("cost", nodesDict["PathingCost"].Value) : (int)(10000 / speed); ret.Add(t.Key, new TerrainInfo { Speed = speed, Cost = cost }); } diff --git a/OpenRA.Mods.RA/Widgets/Logic/MainMenuLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/MainMenuLogic.cs index 9c4368d7e9..ae32eaac49 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/MainMenuLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/MainMenuLogic.cs @@ -193,12 +193,17 @@ namespace OpenRA.Mods.RA.Widgets.Logic static IEnumerable ReadNews(byte[] bytes) { var str = Encoding.UTF8.GetString(bytes); - return MiniYaml.FromString(str).Select(node => new NewsItem + + return MiniYaml.FromString(str).Select(node => { - Title = node.Value.NodesDict["Title"].Value, - Author = node.Value.NodesDict["Author"].Value, - DateTime = FieldLoader.GetValue("DateTime", node.Key), - Content = node.Value.NodesDict["Content"].Value + var nodesDict = node.Value.ToDictionary(); + return new NewsItem + { + Title = nodesDict["Title"].Value, + Author = nodesDict["Author"].Value, + DateTime = FieldLoader.GetValue("DateTime", node.Key), + Content = nodesDict["Content"].Value + }; }); } diff --git a/OpenRA.Mods.RA/Widgets/Logic/MissionBrowserLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/MissionBrowserLogic.cs index b0d8e2598e..7c996f9df7 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/MissionBrowserLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/MissionBrowserLogic.cs @@ -45,7 +45,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic description = widget.Get("MISSION_DESCRIPTION"); descriptionFont = Game.Renderer.Fonts[description.Font]; - var yaml = new MiniYaml(null, Game.modData.Manifest.Missions.Select(MiniYaml.FromFile).Aggregate(MiniYaml.MergeLiberal)).NodesDict; + var yaml = new MiniYaml(null, Game.modData.Manifest.Missions.Select(MiniYaml.FromFile).Aggregate(MiniYaml.MergeLiberal)).ToDictionary(); var missionMapPaths = yaml["Missions"].Nodes.Select(n => Path.GetFullPath(n.Key)); diff --git a/OpenRA.TilesetBuilder/FormBuilder.cs b/OpenRA.TilesetBuilder/FormBuilder.cs index 9370d91a69..7dd6d68bd1 100644 --- a/OpenRA.TilesetBuilder/FormBuilder.cs +++ b/OpenRA.TilesetBuilder/FormBuilder.cs @@ -82,7 +82,7 @@ namespace OpenRA.TilesetBuilder int size = int.Parse(tsize); var yaml = MiniYaml.DictFromFile("OpenRA.TilesetBuilder/defaults.yaml"); - terrainDefinition = yaml["Terrain"].NodesDict.Values.Select(y => new TerrainTypeInfo(y)).ToDictionary(t => t.Type); + terrainDefinition = yaml["Terrain"].ToDictionary().Values.Select(y => new TerrainTypeInfo(y)).ToDictionary(t => t.Type); int i = 0; surface1.Icon = new Bitmap[terrainDefinition.Keys.Count]; TerrainType = new TerrainTypeInfo[terrainDefinition.Keys.Count];