diff --git a/OpenRA.Game/GameRules/RulesetCache.cs b/OpenRA.Game/GameRules/RulesetCache.cs index e817689b3c..b308b18a8e 100644 --- a/OpenRA.Game/GameRules/RulesetCache.cs +++ b/OpenRA.Game/GameRules/RulesetCache.cs @@ -21,8 +21,6 @@ namespace OpenRA { public sealed class RulesetCache { - static readonly string[] NoMapRules = new string[0]; - readonly ModData modData; readonly Dictionary actorCache = new Dictionary(); @@ -44,11 +42,13 @@ namespace OpenRA this.modData = modData; } - /// - /// Cache and return the Ruleset for a given map. - /// If a map isn't specified then return the default mod Ruleset. - /// - public Ruleset Load(IReadOnlyFileSystem fileSystem, Map map = null) + public Ruleset Load(IReadOnlyFileSystem fileSystem, + MiniYaml additionalRules, + MiniYaml additionalWeapons, + MiniYaml additionalVoices, + MiniYaml additionalNotifications, + MiniYaml additionalMusic, + MiniYaml additionalSequences) { var m = modData.Manifest; @@ -60,46 +60,58 @@ namespace OpenRA Dictionary tileSets; using (new PerfTimer("Actors")) - actors = LoadYamlRules(fileSystem, actorCache, m.Rules, - map != null ? map.RuleDefinitions : NoMapRules, + actors = LoadYamlRules(fileSystem, actorCache, m.Rules, additionalRules, k => new ActorInfo(Game.ModData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value)); using (new PerfTimer("Weapons")) - weapons = LoadYamlRules(fileSystem, weaponCache, m.Weapons, - map != null ? map.WeaponDefinitions : NoMapRules, + weapons = LoadYamlRules(fileSystem, weaponCache, m.Weapons, additionalWeapons, k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); using (new PerfTimer("Voices")) - voices = LoadYamlRules(fileSystem, voiceCache, m.Voices, - map != null ? map.VoiceDefinitions : NoMapRules, + voices = LoadYamlRules(fileSystem, voiceCache, m.Voices, additionalVoices, k => new SoundInfo(k.Value)); using (new PerfTimer("Notifications")) - notifications = LoadYamlRules(fileSystem, notificationCache, m.Notifications, - map != null ? map.NotificationDefinitions : NoMapRules, + notifications = LoadYamlRules(fileSystem, notificationCache, m.Notifications, additionalNotifications, k => new SoundInfo(k.Value)); using (new PerfTimer("Music")) - music = LoadYamlRules(fileSystem, musicCache, m.Music, - map != null ? map.MusicDefinitions : NoMapRules, + music = LoadYamlRules(fileSystem, musicCache, m.Music, additionalMusic, k => new MusicInfo(k.Key, k.Value)); using (new PerfTimer("TileSets")) tileSets = LoadTileSets(fileSystem, tileSetCache, m.TileSets); // TODO: only initialize, and then cache, the provider for the given map - var sequences = tileSets.ToDictionary(t => t.Key, t => new SequenceProvider(fileSystem, modData, t.Value, map)); + var sequences = tileSets.ToDictionary(t => t.Key, t => new SequenceProvider(fileSystem, modData, t.Value, additionalSequences)); return new Ruleset(actors, weapons, voices, notifications, music, tileSets, sequences); } + /// + /// Cache and return the Ruleset for a given map. + /// If a map isn't specified then return the default mod Ruleset. + /// + public Ruleset Load(IReadOnlyFileSystem fileSystem, Map map = null) + { + return map != null ? Load(fileSystem, map.RuleDefinitions, map.WeaponDefinitions, + map.VoiceDefinitions, map.NotificationDefinitions, map.MusicDefinitions, + map.SequenceDefinitions) : Load(fileSystem, null, null, null, null, null, null); + } + Dictionary LoadYamlRules(IReadOnlyFileSystem fileSystem, Dictionary itemCache, - string[] files, string[] mapFiles, + IEnumerable files, MiniYaml mapRules, Func f) { RaiseProgress(); - var inputKey = string.Concat(string.Join("|", files.Append(mapFiles)), "|"); + if (mapRules != null && mapRules.Value != null) + files = files.Append(FieldLoader.GetValue("value", mapRules.Value)); + + var inputKey = string.Join("|", files); + if (mapRules != null && mapRules.Nodes.Any()) + inputKey += "|" + mapRules.Nodes.WriteToString(); + Func wrap = wkv => { var key = inputKey + wkv.Value.ToLines(wkv.Key).JoinWith("|"); @@ -114,8 +126,9 @@ namespace OpenRA return t; }; - var tree = MiniYaml.Merge(files.Append(mapFiles).Select(s => MiniYaml.FromStream(fileSystem.Open(s)))) - .ToDictionaryWithConflictLog(n => n.Key, n => n.Value, "LoadYamlRules", null, null); + var tree = MiniYaml.Load(fileSystem, files, mapRules).ToDictionaryWithConflictLog( + n => n.Key, n => n.Value, "LoadYamlRules", null, null); + RaiseProgress(); var itemSet = tree.ToDictionary(kv => kv.Key.ToLowerInvariant(), kv => wrap(new MiniYamlNode(kv.Key, kv.Value))); diff --git a/OpenRA.Game/Graphics/SequenceProvider.cs b/OpenRA.Game/Graphics/SequenceProvider.cs index 97a31f8899..654a4b411c 100644 --- a/OpenRA.Game/Graphics/SequenceProvider.cs +++ b/OpenRA.Game/Graphics/SequenceProvider.cs @@ -53,11 +53,16 @@ namespace OpenRA.Graphics readonly Dictionary sequenceCache = new Dictionary(); - public SequenceProvider(IReadOnlyFileSystem fileSystem, ModData modData, TileSet tileSet, Map map) + public SequenceProvider(IReadOnlyFileSystem fileSystem, ModData modData, TileSet tileSet, MiniYaml additionalSequences) { this.modData = modData; this.tileSet = tileSet; - sequences = Exts.Lazy(() => LoadSequences(fileSystem, map)); + sequences = Exts.Lazy(() => + { + using (new Support.PerfTimer("LoadSequences")) + return Load(fileSystem, additionalSequences); + }); + spriteCache = Exts.Lazy(() => new SpriteCache(fileSystem, modData.SpriteLoaders, new SheetBuilder(SheetType.Indexed))); } @@ -97,17 +102,9 @@ namespace OpenRA.Graphics return unitSeq.Value.Keys; } - public Sequences LoadSequences(IReadOnlyFileSystem fileSystem, Map map) + Sequences Load(IReadOnlyFileSystem fileSystem, MiniYaml additionalSequences) { - using (new Support.PerfTimer("LoadSequences")) - return Load(fileSystem, map != null ? map.SequenceDefinitions : new string[0]); - } - - Sequences Load(IReadOnlyFileSystem fileSystem, string[] mapSequences) - { - var nodes = MiniYaml.Merge(modData.Manifest.Sequences.Append(mapSequences) - .Select(s => MiniYaml.FromStream(fileSystem.Open(s)))); - + var nodes = MiniYaml.Load(fileSystem, modData.Manifest.Sequences, additionalSequences); var items = new Dictionary(); foreach (var n in nodes) { diff --git a/OpenRA.Game/Graphics/VoxelProvider.cs b/OpenRA.Game/Graphics/VoxelProvider.cs index 0f6aca848b..804fffbf2f 100644 --- a/OpenRA.Game/Graphics/VoxelProvider.cs +++ b/OpenRA.Game/Graphics/VoxelProvider.cs @@ -21,13 +21,9 @@ namespace OpenRA.Graphics { static Dictionary> units; - public static void Initialize(VoxelLoader loader, IReadOnlyFileSystem fileSystem, IEnumerable voxelFiles) + public static void Initialize(VoxelLoader loader, IReadOnlyFileSystem fileSystem, List sequences) { units = new Dictionary>(); - - var sequences = MiniYaml.Merge(voxelFiles.Select( - s => MiniYaml.FromStream(fileSystem.Open(s)))); - foreach (var s in sequences) LoadVoxelsForUnit(loader, s.Key, s.Value); diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 4add5c064d..a0bc1b02f3 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -141,14 +141,14 @@ namespace OpenRA public Lazy SpawnPoints; // Yaml map data - [FieldLoader.Ignore] public readonly string[] RuleDefinitions = { }; - [FieldLoader.Ignore] public readonly string[] SequenceDefinitions = { }; - [FieldLoader.Ignore] public readonly string[] VoxelSequenceDefinitions = { }; - [FieldLoader.Ignore] public readonly string[] WeaponDefinitions = { }; - [FieldLoader.Ignore] public readonly string[] VoiceDefinitions = { }; - [FieldLoader.Ignore] public readonly string[] MusicDefinitions = { }; - [FieldLoader.Ignore] public readonly string[] NotificationDefinitions = { }; - [FieldLoader.Ignore] public readonly string[] TranslationDefinitions = { }; + [FieldLoader.Ignore] public readonly MiniYaml RuleDefinitions; + [FieldLoader.Ignore] public readonly MiniYaml SequenceDefinitions; + [FieldLoader.Ignore] public readonly MiniYaml VoxelSequenceDefinitions; + [FieldLoader.Ignore] public readonly MiniYaml WeaponDefinitions; + [FieldLoader.Ignore] public readonly MiniYaml VoiceDefinitions; + [FieldLoader.Ignore] public readonly MiniYaml MusicDefinitions; + [FieldLoader.Ignore] public readonly MiniYaml NotificationDefinitions; + [FieldLoader.Ignore] public readonly MiniYaml TranslationDefinitions; [FieldLoader.Ignore] public List PlayerDefinitions = new List(); [FieldLoader.Ignore] public List ActorDefinitions = new List(); @@ -184,13 +184,6 @@ namespace OpenRA throw new InvalidOperationException("Required file {0} not present in this map".F(filename)); } - void LoadFileList(MiniYaml yaml, string section, ref string[] files) - { - MiniYamlNode node; - if ((node = yaml.Nodes.FirstOrDefault(n => n.Key == section)) != null) - files = FieldLoader.GetValue(section, node.Value.Value); - } - /// /// Initializes a new map created by the editor or importer. /// The map will not receive a valid UID until after it has been saved and reloaded. @@ -208,6 +201,10 @@ namespace OpenRA MapSize = new int2(size); Tileset = tileset.Id; + // Empty rules that can be added to by the importers. + // Will be dropped on save if nothing is added to it + RuleDefinitions = new MiniYaml(""); + MapResources = Exts.Lazy(() => new CellLayer(Grid.Type, size)); MapTiles = Exts.Lazy(() => @@ -260,14 +257,14 @@ namespace OpenRA return spawns.ToArray(); }); - LoadFileList(yaml, "Rules", ref RuleDefinitions); - LoadFileList(yaml, "Sequences", ref SequenceDefinitions); - LoadFileList(yaml, "VoxelSequences", ref VoxelSequenceDefinitions); - LoadFileList(yaml, "Weapons", ref WeaponDefinitions); - LoadFileList(yaml, "Voices", ref VoiceDefinitions); - LoadFileList(yaml, "Music", ref MusicDefinitions); - LoadFileList(yaml, "Notifications", ref NotificationDefinitions); - LoadFileList(yaml, "Translations", ref TranslationDefinitions); + RuleDefinitions = LoadRuleSection(yaml, "Rules"); + SequenceDefinitions = LoadRuleSection(yaml, "Sequences"); + VoxelSequenceDefinitions = LoadRuleSection(yaml, "VoxelSequences"); + WeaponDefinitions = LoadRuleSection(yaml, "Weapons"); + VoiceDefinitions = LoadRuleSection(yaml, "Voices"); + MusicDefinitions = LoadRuleSection(yaml, "Music"); + NotificationDefinitions = LoadRuleSection(yaml, "Notifications"); + TranslationDefinitions = LoadRuleSection(yaml, "Translations"); PlayerDefinitions = MiniYaml.NodesOrEmpty(yaml, "Players"); ActorDefinitions = MiniYaml.NodesOrEmpty(yaml, "Actors"); @@ -287,6 +284,12 @@ namespace OpenRA Uid = ComputeUID(Package); } + MiniYaml LoadRuleSection(MiniYaml yaml, string section) + { + var node = yaml.Nodes.FirstOrDefault(n => n.Key == section); + return node != null ? node.Value : null; + } + void PostInit() { rules = Exts.Lazy(() => @@ -448,21 +451,21 @@ namespace OpenRA root.Add(new MiniYamlNode("Players", null, PlayerDefinitions)); root.Add(new MiniYamlNode("Actors", null, ActorDefinitions)); - var fileFields = new[] + var ruleSections = new[] { - Pair.New("Rules", RuleDefinitions), - Pair.New("Sequences", SequenceDefinitions), - Pair.New("VoxelSequences", VoxelSequenceDefinitions), - Pair.New("Weapons", WeaponDefinitions), - Pair.New("Voices", VoiceDefinitions), - Pair.New("Music", MusicDefinitions), - Pair.New("Notifications", NotificationDefinitions), - Pair.New("Translations", TranslationDefinitions) + new MiniYamlNode("Rules", RuleDefinitions), + new MiniYamlNode("Sequences", SequenceDefinitions), + new MiniYamlNode("VoxelSequences", VoxelSequenceDefinitions), + new MiniYamlNode("Weapons", WeaponDefinitions), + new MiniYamlNode("Voices", VoiceDefinitions), + new MiniYamlNode("Music", MusicDefinitions), + new MiniYamlNode("Notifications", NotificationDefinitions), + new MiniYamlNode("Translations", TranslationDefinitions) }; - foreach (var kv in fileFields) - if (kv.Second.Any()) - root.Add(new MiniYamlNode(kv.First, FieldSaver.FormatValue(kv.Second))); + foreach (var section in ruleSections) + if (section.Value != null && (section.Value.Value != null || section.Value.Nodes.Any())) + root.Add(section); // Saving to a new package: copy over all the content from the map if (Package != null && toPackage != Package) diff --git a/OpenRA.Game/MiniYaml.cs b/OpenRA.Game/MiniYaml.cs index 17d205ae6f..bcc4fe5e60 100644 --- a/OpenRA.Game/MiniYaml.cs +++ b/OpenRA.Game/MiniYaml.cs @@ -13,6 +13,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using OpenRA.FileSystem; namespace OpenRA { @@ -375,6 +376,21 @@ namespace OpenRA foreach (var line in Nodes.ToLines(false)) yield return "\t" + line; } + + public static List Load(IReadOnlyFileSystem fileSystem, IEnumerable files, MiniYaml mapRules) + { + if (mapRules != null && mapRules.Value != null) + { + var mapFiles = FieldLoader.GetValue("value", mapRules.Value); + files = files.Append(mapFiles); + } + + var yaml = files.Select(s => MiniYaml.FromStream(fileSystem.Open(s))); + if (mapRules != null && mapRules.Nodes.Any()) + yaml = yaml.Append(mapRules.Nodes); + + return MiniYaml.Merge(yaml); + } } [Serializable] diff --git a/OpenRA.Game/ModData.cs b/OpenRA.Game/ModData.cs index 605a823847..b20b31e25c 100644 --- a/OpenRA.Game/ModData.cs +++ b/OpenRA.Game/ModData.cs @@ -130,8 +130,7 @@ namespace OpenRA return; } - var yaml = MiniYaml.Merge(Manifest.Translations.Append(map.TranslationDefinitions) - .Select(t => MiniYaml.FromStream(map.Open(t)))); + var yaml = MiniYaml.Load(map, Manifest.Translations, map.TranslationDefinitions); Languages = yaml.Select(t => t.Key).ToArray(); foreach (var y in yaml) @@ -182,7 +181,7 @@ namespace OpenRA foreach (var entry in map.Rules.Music) entry.Value.Load(map); - VoxelProvider.Initialize(VoxelLoader, map, Manifest.VoxelSequences.Append(map.VoxelSequenceDefinitions)); + VoxelProvider.Initialize(VoxelLoader, map, MiniYaml.Load(map, Manifest.VoxelSequences, map.VoxelSequenceDefinitions)); VoxelLoader.Finish(); return map; diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index 0d14b76022..d46e7b2522 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -392,7 +392,7 @@ namespace OpenRA.Server SendOrderTo(newConn, "Message", motd); } - if (Map.RuleDefinitions.Any() && !LobbyInfo.IsSinglePlayer) + if (Map.RuleDefinitions != null && !LobbyInfo.IsSinglePlayer) SendOrderTo(newConn, "Message", "This map contains custom rules. Game experience may change."); if (Settings.DisableSinglePlayer) diff --git a/OpenRA.Mods.Common/Lint/CheckSequences.cs b/OpenRA.Mods.Common/Lint/CheckSequences.cs index 55d3b1dabc..d1ed7d0e72 100644 --- a/OpenRA.Mods.Common/Lint/CheckSequences.cs +++ b/OpenRA.Mods.Common/Lint/CheckSequences.cs @@ -26,18 +26,17 @@ namespace OpenRA.Mods.Common.Lint public void Run(Action emitError, Action emitWarning, Map map) { - if (map != null && !map.SequenceDefinitions.Any()) + if (map.SequenceDefinitions == null) return; var modData = Game.ModData; this.emitError = emitError; - var mapSequences = map != null ? map.SequenceDefinitions : new string[0]; - sequenceDefinitions = MiniYaml.Merge(modData.Manifest.Sequences.Append(mapSequences).Select(s => MiniYaml.FromStream(map.Open(s)))); + sequenceDefinitions = MiniYaml.Load(map, modData.Manifest.Sequences, map.SequenceDefinitions); - var rules = map == null ? modData.DefaultRules : map.Rules; + var rules = map.Rules; var factions = rules.Actors["world"].TraitInfos().Select(f => f.InternalName).ToArray(); - var sequenceProviders = map == null ? rules.Sequences.Values : new[] { rules.Sequences[map.Tileset] }; + var sequenceProviders = new[] { rules.Sequences[map.Tileset] }; foreach (var actorInfo in rules.Actors) { diff --git a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs index 5089f8b7ca..0285393c24 100644 --- a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs @@ -387,7 +387,7 @@ namespace OpenRA.Mods.Common.Server server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title)); - if (server.Map.RuleDefinitions.Any()) + if (server.Map.RuleDefinitions != null) server.SendMessage("This map contains custom rules. Game experience may change."); if (server.Settings.DisableSinglePlayer) diff --git a/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs b/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs index 2a96940697..943fb2edb2 100644 --- a/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs +++ b/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs @@ -90,7 +90,7 @@ namespace OpenRA.Mods.Common.UtilityCommands testMap.PreloadRules(); // Run all rule checks on the map if it defines custom rules. - if (testMap.RuleDefinitions.Any() || testMap.VoiceDefinitions.Any() || testMap.WeaponDefinitions.Any()) + if (testMap.RuleDefinitions != null || testMap.VoiceDefinitions != null || testMap.WeaponDefinitions != null) CheckRules(modData, testMap.Rules, testMap); // Run all map-level checks here. diff --git a/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs index 9d469750b3..28ee6125a2 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs @@ -33,10 +33,8 @@ namespace OpenRA.Mods.Common.UtilityCommands public ModData ModData; public Map Map; - public IReadWritePackage Package; public List Players = new List(); public MapPlayers MapPlayers; - public MiniYaml Rules = new MiniYaml(""); public bool ValidateArguments(string[] args) { @@ -52,8 +50,6 @@ namespace OpenRA.Mods.Common.UtilityCommands Game.ModData = modData; var filename = args[1]; - var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap"; - Package = new ZipFile(modData.ModFiles, dest, true); using (var stream = modData.DefaultFileSystem.Open(filename)) { var file = new IniFile(stream); @@ -67,7 +63,7 @@ namespace OpenRA.Mods.Common.UtilityCommands Map = new Map(modData, modData.DefaultRules.TileSets[tileset], MapSize, MapSize) { Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)), - Author = "Westwood Studios" + Author = "Westwood Studios", }; Map.RequiresMod = modData.Manifest.Mod.Id; @@ -96,16 +92,10 @@ namespace OpenRA.Mods.Common.UtilityCommands Map.FixOpenAreas(); - if (Rules.Nodes.Any()) - { - // HACK: bypassing the readonly modifier here is still better than leaving this mutable by everyone - typeof(Map).GetField("RuleDefinitions").SetValue(Map, new[] { "rules.yaml" }); + var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap"; + var package = new ZipFile(modData.ModFiles, dest, true); - var rulesText = Rules.Nodes.ToLines(false).JoinWith("\n"); - Package.Update("rules.yaml", System.Text.Encoding.ASCII.GetBytes(rulesText)); - } - - Map.Save(Package); + Map.Save(package); Console.WriteLine(dest + " saved."); } @@ -140,11 +130,11 @@ namespace OpenRA.Mods.Common.UtilityCommands if (briefing.Length == 0) return; - var worldNode = Rules.Nodes.FirstOrDefault(n => n.Key == "World"); + var worldNode = Map.RuleDefinitions.Nodes.FirstOrDefault(n => n.Key == "World"); if (worldNode == null) { worldNode = new MiniYamlNode("World", new MiniYaml("", new List())); - Rules.Nodes.Add(worldNode); + Map.RuleDefinitions.Nodes.Add(worldNode); } var missionData = worldNode.Value.Nodes.FirstOrDefault(n => n.Key == "MissionData"); @@ -201,11 +191,11 @@ namespace OpenRA.Mods.Common.UtilityCommands if (videos.Any()) { - var worldNode = Rules.Nodes.FirstOrDefault(n => n.Key == "World"); + var worldNode = Map.RuleDefinitions.Nodes.FirstOrDefault(n => n.Key == "World"); if (worldNode == null) { worldNode = new MiniYamlNode("World", new MiniYaml("", new List())); - Rules.Nodes.Add(worldNode); + Map.RuleDefinitions.Nodes.Add(worldNode); } var missionData = worldNode.Value.Nodes.FirstOrDefault(n => n.Key == "MissionData"); @@ -298,7 +288,7 @@ namespace OpenRA.Mods.Common.UtilityCommands craters.Add(node); } - var worldNode = Rules.Nodes.FirstOrDefault(n => n.Key == "World"); + var worldNode = Map.RuleDefinitions.Nodes.FirstOrDefault(n => n.Key == "World"); if (worldNode == null) worldNode = new MiniYamlNode("World", new MiniYaml("", new List())); @@ -316,8 +306,8 @@ namespace OpenRA.Mods.Common.UtilityCommands worldNode.Value.Nodes.Add(smudgeLayer); } - if (worldNode.Value.Nodes.Any() && !Rules.Nodes.Contains(worldNode)) - Rules.Nodes.Add(worldNode); + if (worldNode.Value.Nodes.Any() && !Map.RuleDefinitions.Nodes.Contains(worldNode)) + Map.RuleDefinitions.Nodes.Add(worldNode); } // TODO: fix this -- will have bitrotted pretty badly. diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs index cc9da3aac3..6e608c58fc 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs @@ -27,17 +27,23 @@ namespace OpenRA.Mods.Common.UtilityCommands delegate void UpgradeAction(int engineVersion, ref List nodes, MiniYamlNode parent, int depth); - static void ProcessYaml(Map map, IEnumerable files, int engineDate, UpgradeAction processFile) + static void ProcessYaml(Map map, MiniYaml yaml, int engineDate, UpgradeAction processYaml) { - foreach (var filename in files) - { - if (!map.Package.Contains(filename)) - continue; + if (yaml == null) + return; - var yaml = MiniYaml.FromStream(map.Package.GetStream(filename)); - processFile(engineDate, ref yaml, null, 0); - ((IReadWritePackage)map.Package).Update(filename, Encoding.ASCII.GetBytes(yaml.WriteToString())); - } + if (yaml.Value != null) + { + var files = FieldLoader.GetValue("value", yaml.Value); + foreach (var filename in files) + { + var fileNodes = MiniYaml.FromStream(map.Package.GetStream(filename)); + processYaml(engineDate, ref fileNodes, null, 0); + ((IReadWritePackage)map.Package).Update(filename, Encoding.ASCII.GetBytes(fileNodes.WriteToString())); + } + } + + processYaml(engineDate, ref yaml.Nodes, null, 1); } public static void UpgradeMap(ModData modData, IReadWritePackage package, int engineDate) diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 153bbdf4e9..bbe3067d1d 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -948,20 +948,10 @@ namespace OpenRA.Mods.Common.UtilityCommands rules.Value.Nodes.Add(playerNode); } - // Format 9 -> 10 extracted map rules, sequences, voxelsequences, weapons, voices, music, notifications, - // and translations to external files, moved smudges to SmudgeLayer, and uses map.png for all maps + // Format 9 -> 10 moved smudges to SmudgeLayer, and uses map.png for all maps if (mapFormat < 10) { ExtractSmudges(yaml); - ExtractOrRemoveRules(package, yaml, "Rules", "rules.yaml"); - ExtractOrRemoveRules(package, yaml, "Sequences", "sequences.yaml"); - ExtractOrRemoveRules(package, yaml, "VoxelSequences", "voxels.yaml"); - ExtractOrRemoveRules(package, yaml, "Weapons", "weapons.yaml"); - ExtractOrRemoveRules(package, yaml, "Voices", "voices.yaml"); - ExtractOrRemoveRules(package, yaml, "Music", "music.yaml"); - ExtractOrRemoveRules(package, yaml, "Notifications", "notifications.yaml"); - ExtractOrRemoveRules(package, yaml, "Translations", "translations.yaml"); - if (package.Contains("map.png")) yaml.Nodes.Add(new MiniYamlNode("LockPreview", new MiniYaml("True"))); } @@ -1023,22 +1013,5 @@ namespace OpenRA.Mods.Common.UtilityCommands worldNode.Value.Nodes.Add(smudgeLayer); } } - - static void ExtractOrRemoveRules(IReadWritePackage package, MiniYaml yaml, string key, string filename) - { - var node = yaml.Nodes.FirstOrDefault(n => n.Key == key); - if (node == null) - return; - - if (node.Value.Nodes.Any()) - { - var rulesText = node.Value.Nodes.ToLines(false).JoinWith("\n"); - package.Update(filename, System.Text.Encoding.ASCII.GetBytes(rulesText)); - node.Value.Value = filename; - node.Value.Nodes.Clear(); - } - else - yaml.Nodes.Remove(node); - } } } diff --git a/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs b/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs index 48eda4f34c..16d4477e55 100644 --- a/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs +++ b/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs @@ -165,8 +165,6 @@ namespace OpenRA.Mods.TS.UtilityCommands var filename = args[1]; var file = new IniFile(File.Open(args[1], FileMode.Open)); var map = GenerateMapHeader(filename, file, modData); - var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap"; - var package = new ZipFile(modData.DefaultFileSystem, dest, true); ReadTiles(map, file); ReadActors(map, file, "Structures"); @@ -175,11 +173,13 @@ namespace OpenRA.Mods.TS.UtilityCommands ReadTerrainActors(map, file); ReadWaypoints(map, file); ReadOverlay(map, file); - ReadLighting(map, package, file); + ReadLighting(map, file); var mapPlayers = new MapPlayers(map.Rules, spawnCount); map.PlayerDefinitions = mapPlayers.ToMiniYaml(); + var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap"; + var package = new ZipFile(modData.DefaultFileSystem, dest, true); map.Save(package); Console.WriteLine(dest + " saved."); } @@ -431,12 +431,11 @@ namespace OpenRA.Mods.TS.UtilityCommands } } - void ReadLighting(Map map, IReadWritePackage package, IniFile file) + void ReadLighting(Map map, IniFile file) { var lightingTypes = new[] { "Red", "Green", "Blue", "Ambient" }; var lightingSection = file.GetSection("Lighting"); - var lightingNode = new MiniYamlNode("GlobalLightingPaletteEffect", new MiniYaml("", new List())); - var worldNode = new MiniYamlNode("World", new MiniYaml("", new List() { lightingNode })); + var lightingNodes = new List(); foreach (var kv in lightingSection) { @@ -444,19 +443,18 @@ namespace OpenRA.Mods.TS.UtilityCommands { var val = FieldLoader.GetValue(kv.Key, kv.Value); if (val != 1.0f) - lightingNode.Value.Nodes.Add(new MiniYamlNode(kv.Key, FieldSaver.FormatValue(val))); + lightingNodes.Add(new MiniYamlNode(kv.Key, FieldSaver.FormatValue(val))); } else Console.WriteLine("Ignoring unknown lighting type: `{0}`".F(kv.Key)); } - if (lightingNode.Value.Nodes.Any()) + if (lightingNodes.Any()) { - // HACK: bypassing the readonly modifier here is still better than leaving this mutable by everyone - typeof(Map).GetField("RuleDefinitions").SetValue(map, new[] { "rules.yaml" }); - - var rulesText = new List() { worldNode }.ToLines(false).JoinWith("\n"); - package.Update("rules.yaml", System.Text.Encoding.ASCII.GetBytes(rulesText)); + map.RuleDefinitions.Nodes.Add(new MiniYamlNode("World", new MiniYaml("", new List() + { + new MiniYamlNode("GlobalLightingPaletteEffect", new MiniYaml("", lightingNodes)) + }))); } } } diff --git a/mods/ts/maps/arivruns/map.yaml b/mods/ts/maps/arivruns/map.yaml index 6aac0348d3..e20d40fac8 100644 --- a/mods/ts/maps/arivruns/map.yaml +++ b/mods/ts/maps/arivruns/map.yaml @@ -1293,4 +1293,7 @@ Actors: Owner: Neutral Location: 115,-15 -Rules: rules.yaml +Rules: + World: + GlobalLightingPaletteEffect: + Ambient: 0.72 diff --git a/mods/ts/maps/arivruns/rules.yaml b/mods/ts/maps/arivruns/rules.yaml deleted file mode 100644 index f8fa63e382..0000000000 --- a/mods/ts/maps/arivruns/rules.yaml +++ /dev/null @@ -1,3 +0,0 @@ -World: - GlobalLightingPaletteEffect: - Ambient: 0.72 diff --git a/mods/ts/maps/cliffsin/map.yaml b/mods/ts/maps/cliffsin/map.yaml index 49aa13d7bd..c76b6cb8dc 100644 --- a/mods/ts/maps/cliffsin/map.yaml +++ b/mods/ts/maps/cliffsin/map.yaml @@ -1499,4 +1499,7 @@ Actors: Location: 123,87 Owner: Neutral -Rules: rules.yaml +Rules: + World: + GlobalLightingPaletteEffect: + Ambient: 0.68 diff --git a/mods/ts/maps/cliffsin/rules.yaml b/mods/ts/maps/cliffsin/rules.yaml deleted file mode 100644 index 60f2701725..0000000000 --- a/mods/ts/maps/cliffsin/rules.yaml +++ /dev/null @@ -1,3 +0,0 @@ -World: - GlobalLightingPaletteEffect: - Ambient: 0.68 diff --git a/mods/ts/maps/gdi4a/map.yaml b/mods/ts/maps/gdi4a/map.yaml index 6a02f07652..cf07cbe862 100644 --- a/mods/ts/maps/gdi4a/map.yaml +++ b/mods/ts/maps/gdi4a/map.yaml @@ -1737,3 +1737,9 @@ Actors: Location: 111,13 Rules: rules.yaml + World: + GlobalLightingPaletteEffect: + Red: 1.1 + Green: 1.1 + Blue: 1 + Ambient: 0.55 \ No newline at end of file diff --git a/mods/ts/maps/gdi4a/rules.yaml b/mods/ts/maps/gdi4a/rules.yaml index adfe77c8ab..eba63b3e66 100644 --- a/mods/ts/maps/gdi4a/rules.yaml +++ b/mods/ts/maps/gdi4a/rules.yaml @@ -4,10 +4,5 @@ World: -MPStartLocations: MusicPlaylist: BackgroundMusic: intro - GlobalLightingPaletteEffect: - Red: 1.1 - Green: 1.1 - Blue: 1 - Ambient: 0.55 LuaScript: Scripts: map.lua diff --git a/mods/ts/maps/karasjok/map.yaml b/mods/ts/maps/karasjok/map.yaml index 4969205cef..9cf66da2b9 100644 --- a/mods/ts/maps/karasjok/map.yaml +++ b/mods/ts/maps/karasjok/map.yaml @@ -1554,4 +1554,10 @@ Actors: Location: 134,73 Owner: Neutral -Rules: rules.yaml +Rules: + World: + GlobalLightingPaletteEffect: + Red: 0.5 + Green: 0.7 + Blue: 0.7 + Ambient: 0.78 \ No newline at end of file diff --git a/mods/ts/maps/karasjok/rules.yaml b/mods/ts/maps/karasjok/rules.yaml deleted file mode 100644 index de64efd8cd..0000000000 --- a/mods/ts/maps/karasjok/rules.yaml +++ /dev/null @@ -1,6 +0,0 @@ -World: - GlobalLightingPaletteEffect: - Red: 0.5 - Blue: 0.7 - Green: 0.7 - Ambient: 0.78 diff --git a/mods/ts/maps/rivrrad4/map.yaml b/mods/ts/maps/rivrrad4/map.yaml index 129d01f1f1..218b7acb15 100644 --- a/mods/ts/maps/rivrrad4/map.yaml +++ b/mods/ts/maps/rivrrad4/map.yaml @@ -868,4 +868,7 @@ Actors: Location: 254,39 Owner: Neutral -Rules: rules.yaml +Rules: + World: + GlobalLightingPaletteEffect: + Ambient: 0.85 diff --git a/mods/ts/maps/rivrrad4/rules.yaml b/mods/ts/maps/rivrrad4/rules.yaml deleted file mode 100644 index 7493f42ace..0000000000 --- a/mods/ts/maps/rivrrad4/rules.yaml +++ /dev/null @@ -1,3 +0,0 @@ -World: - GlobalLightingPaletteEffect: - Ambient: 0.85 diff --git a/mods/ts/maps/springs/map.yaml b/mods/ts/maps/springs/map.yaml index 13f41bb60e..6241f0ff5a 100644 --- a/mods/ts/maps/springs/map.yaml +++ b/mods/ts/maps/springs/map.yaml @@ -853,4 +853,7 @@ Actors: Owner: Neutral Location: 95,3 -Rules: rules.yaml +Rules: + World: + GlobalLightingPaletteEffect: + Ambient: 0.62 diff --git a/mods/ts/maps/springs/rules.yaml b/mods/ts/maps/springs/rules.yaml deleted file mode 100644 index 4ff8dd87ae..0000000000 --- a/mods/ts/maps/springs/rules.yaml +++ /dev/null @@ -1,3 +0,0 @@ -World: - GlobalLightingPaletteEffect: - Ambient: 0.62 diff --git a/mods/ts/maps/t_garden/map.yaml b/mods/ts/maps/t_garden/map.yaml index d632589d50..7b36079229 100644 --- a/mods/ts/maps/t_garden/map.yaml +++ b/mods/ts/maps/t_garden/map.yaml @@ -830,4 +830,7 @@ Actors: Location: 99,74 Owner: Neutral -Rules: rules.yaml +Rules: + World: + GlobalLightingPaletteEffect: + Ambient: 0.79 diff --git a/mods/ts/maps/t_garden/rules.yaml b/mods/ts/maps/t_garden/rules.yaml deleted file mode 100644 index 005365fd83..0000000000 --- a/mods/ts/maps/t_garden/rules.yaml +++ /dev/null @@ -1,6 +0,0 @@ -World: - GlobalLightingPaletteEffect: - Red: 1 - Blue: 1 - Green: 1 - Ambient: 0.79 diff --git a/mods/ts/maps/tactical/map.yaml b/mods/ts/maps/tactical/map.yaml index 96783707ed..65cf128c8c 100644 --- a/mods/ts/maps/tactical/map.yaml +++ b/mods/ts/maps/tactical/map.yaml @@ -800,4 +800,7 @@ Actors: Location: 167,83 Owner: Neutral -Rules: rules.yaml +Rules: + World: + GlobalLightingPaletteEffect: + Ambient: 0.85 diff --git a/mods/ts/maps/tactical/rules.yaml b/mods/ts/maps/tactical/rules.yaml deleted file mode 100644 index 7493f42ace..0000000000 --- a/mods/ts/maps/tactical/rules.yaml +++ /dev/null @@ -1,3 +0,0 @@ -World: - GlobalLightingPaletteEffect: - Ambient: 0.85 diff --git a/mods/ts/maps/terrace/map.yaml b/mods/ts/maps/terrace/map.yaml index 3263c9db70..ae12bad0a1 100644 --- a/mods/ts/maps/terrace/map.yaml +++ b/mods/ts/maps/terrace/map.yaml @@ -509,4 +509,7 @@ Actors: Location: 84,60 Owner: Neutral -Rules: rules.yaml +Rules: + World: + GlobalLightingPaletteEffect: + Ambient: 0.63 diff --git a/mods/ts/maps/terrace/rules.yaml b/mods/ts/maps/terrace/rules.yaml deleted file mode 100644 index 7bd64ec853..0000000000 --- a/mods/ts/maps/terrace/rules.yaml +++ /dev/null @@ -1,3 +0,0 @@ -World: - GlobalLightingPaletteEffect: - Ambient: 0.63 diff --git a/mods/ts/maps/tread_l/map.yaml b/mods/ts/maps/tread_l/map.yaml index a27cd3c2fc..095f365317 100644 --- a/mods/ts/maps/tread_l/map.yaml +++ b/mods/ts/maps/tread_l/map.yaml @@ -1213,4 +1213,7 @@ Actors: Location: 123,20 Owner: Neutral -Rules: rules.yaml +Rules: + World: + GlobalLightingPaletteEffect: + Ambient: 0.75 diff --git a/mods/ts/maps/tread_l/rules.yaml b/mods/ts/maps/tread_l/rules.yaml deleted file mode 100644 index 9fad12c1dc..0000000000 --- a/mods/ts/maps/tread_l/rules.yaml +++ /dev/null @@ -1,3 +0,0 @@ -World: - GlobalLightingPaletteEffect: - Ambient: 0.75