Merge pull request #10902 from pchote/inline-rules

Restore the ability for maps to include inline rules.
This commit is contained in:
abcdefg30
2016-03-11 21:33:52 +01:00
34 changed files with 191 additions and 203 deletions

View File

@@ -21,8 +21,6 @@ namespace OpenRA
{ {
public sealed class RulesetCache public sealed class RulesetCache
{ {
static readonly string[] NoMapRules = new string[0];
readonly ModData modData; readonly ModData modData;
readonly Dictionary<string, ActorInfo> actorCache = new Dictionary<string, ActorInfo>(); readonly Dictionary<string, ActorInfo> actorCache = new Dictionary<string, ActorInfo>();
@@ -44,11 +42,13 @@ namespace OpenRA
this.modData = modData; this.modData = modData;
} }
/// <summary> public Ruleset Load(IReadOnlyFileSystem fileSystem,
/// Cache and return the Ruleset for a given map. MiniYaml additionalRules,
/// If a map isn't specified then return the default mod Ruleset. MiniYaml additionalWeapons,
/// </summary> MiniYaml additionalVoices,
public Ruleset Load(IReadOnlyFileSystem fileSystem, Map map = null) MiniYaml additionalNotifications,
MiniYaml additionalMusic,
MiniYaml additionalSequences)
{ {
var m = modData.Manifest; var m = modData.Manifest;
@@ -60,46 +60,58 @@ namespace OpenRA
Dictionary<string, TileSet> tileSets; Dictionary<string, TileSet> tileSets;
using (new PerfTimer("Actors")) using (new PerfTimer("Actors"))
actors = LoadYamlRules(fileSystem, actorCache, m.Rules, actors = LoadYamlRules(fileSystem, actorCache, m.Rules, additionalRules,
map != null ? map.RuleDefinitions : NoMapRules,
k => new ActorInfo(Game.ModData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value)); k => new ActorInfo(Game.ModData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value));
using (new PerfTimer("Weapons")) using (new PerfTimer("Weapons"))
weapons = LoadYamlRules(fileSystem, weaponCache, m.Weapons, weapons = LoadYamlRules(fileSystem, weaponCache, m.Weapons, additionalWeapons,
map != null ? map.WeaponDefinitions : NoMapRules,
k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
using (new PerfTimer("Voices")) using (new PerfTimer("Voices"))
voices = LoadYamlRules(fileSystem, voiceCache, m.Voices, voices = LoadYamlRules(fileSystem, voiceCache, m.Voices, additionalVoices,
map != null ? map.VoiceDefinitions : NoMapRules,
k => new SoundInfo(k.Value)); k => new SoundInfo(k.Value));
using (new PerfTimer("Notifications")) using (new PerfTimer("Notifications"))
notifications = LoadYamlRules(fileSystem, notificationCache, m.Notifications, notifications = LoadYamlRules(fileSystem, notificationCache, m.Notifications, additionalNotifications,
map != null ? map.NotificationDefinitions : NoMapRules,
k => new SoundInfo(k.Value)); k => new SoundInfo(k.Value));
using (new PerfTimer("Music")) using (new PerfTimer("Music"))
music = LoadYamlRules(fileSystem, musicCache, m.Music, music = LoadYamlRules(fileSystem, musicCache, m.Music, additionalMusic,
map != null ? map.MusicDefinitions : NoMapRules,
k => new MusicInfo(k.Key, k.Value)); k => new MusicInfo(k.Key, k.Value));
using (new PerfTimer("TileSets")) using (new PerfTimer("TileSets"))
tileSets = LoadTileSets(fileSystem, tileSetCache, m.TileSets); tileSets = LoadTileSets(fileSystem, tileSetCache, m.TileSets);
// TODO: only initialize, and then cache, the provider for the given map // 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); return new Ruleset(actors, weapons, voices, notifications, music, tileSets, sequences);
} }
/// <summary>
/// Cache and return the Ruleset for a given map.
/// If a map isn't specified then return the default mod Ruleset.
/// </summary>
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<string, T> LoadYamlRules<T>(IReadOnlyFileSystem fileSystem, Dictionary<string, T> LoadYamlRules<T>(IReadOnlyFileSystem fileSystem,
Dictionary<string, T> itemCache, Dictionary<string, T> itemCache,
string[] files, string[] mapFiles, IEnumerable<string> files, MiniYaml mapRules,
Func<MiniYamlNode, T> f) Func<MiniYamlNode, T> f)
{ {
RaiseProgress(); RaiseProgress();
var inputKey = string.Concat(string.Join("|", files.Append(mapFiles)), "|"); if (mapRules != null && mapRules.Value != null)
files = files.Append(FieldLoader.GetValue<string[]>("value", mapRules.Value));
var inputKey = string.Join("|", files);
if (mapRules != null && mapRules.Nodes.Any())
inputKey += "|" + mapRules.Nodes.WriteToString();
Func<MiniYamlNode, T> wrap = wkv => Func<MiniYamlNode, T> wrap = wkv =>
{ {
var key = inputKey + wkv.Value.ToLines(wkv.Key).JoinWith("|"); var key = inputKey + wkv.Value.ToLines(wkv.Key).JoinWith("|");
@@ -114,8 +126,9 @@ namespace OpenRA
return t; return t;
}; };
var tree = MiniYaml.Merge(files.Append(mapFiles).Select(s => MiniYaml.FromStream(fileSystem.Open(s)))) var tree = MiniYaml.Load(fileSystem, files, mapRules).ToDictionaryWithConflictLog(
.ToDictionaryWithConflictLog(n => n.Key, n => n.Value, "LoadYamlRules", null, null); n => n.Key, n => n.Value, "LoadYamlRules", null, null);
RaiseProgress(); RaiseProgress();
var itemSet = tree.ToDictionary(kv => kv.Key.ToLowerInvariant(), kv => wrap(new MiniYamlNode(kv.Key, kv.Value))); var itemSet = tree.ToDictionary(kv => kv.Key.ToLowerInvariant(), kv => wrap(new MiniYamlNode(kv.Key, kv.Value)));

View File

@@ -53,11 +53,16 @@ namespace OpenRA.Graphics
readonly Dictionary<string, UnitSequences> sequenceCache = new Dictionary<string, UnitSequences>(); readonly Dictionary<string, UnitSequences> sequenceCache = new Dictionary<string, UnitSequences>();
public SequenceProvider(IReadOnlyFileSystem fileSystem, ModData modData, TileSet tileSet, Map map) public SequenceProvider(IReadOnlyFileSystem fileSystem, ModData modData, TileSet tileSet, MiniYaml additionalSequences)
{ {
this.modData = modData; this.modData = modData;
this.tileSet = tileSet; 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))); spriteCache = Exts.Lazy(() => new SpriteCache(fileSystem, modData.SpriteLoaders, new SheetBuilder(SheetType.Indexed)));
} }
@@ -97,17 +102,9 @@ namespace OpenRA.Graphics
return unitSeq.Value.Keys; return unitSeq.Value.Keys;
} }
public Sequences LoadSequences(IReadOnlyFileSystem fileSystem, Map map) Sequences Load(IReadOnlyFileSystem fileSystem, MiniYaml additionalSequences)
{ {
using (new Support.PerfTimer("LoadSequences")) var nodes = MiniYaml.Load(fileSystem, modData.Manifest.Sequences, additionalSequences);
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 items = new Dictionary<string, UnitSequences>(); var items = new Dictionary<string, UnitSequences>();
foreach (var n in nodes) foreach (var n in nodes)
{ {

View File

@@ -21,13 +21,9 @@ namespace OpenRA.Graphics
{ {
static Dictionary<string, Dictionary<string, Voxel>> units; static Dictionary<string, Dictionary<string, Voxel>> units;
public static void Initialize(VoxelLoader loader, IReadOnlyFileSystem fileSystem, IEnumerable<string> voxelFiles) public static void Initialize(VoxelLoader loader, IReadOnlyFileSystem fileSystem, List<MiniYamlNode> sequences)
{ {
units = new Dictionary<string, Dictionary<string, Voxel>>(); units = new Dictionary<string, Dictionary<string, Voxel>>();
var sequences = MiniYaml.Merge(voxelFiles.Select(
s => MiniYaml.FromStream(fileSystem.Open(s))));
foreach (var s in sequences) foreach (var s in sequences)
LoadVoxelsForUnit(loader, s.Key, s.Value); LoadVoxelsForUnit(loader, s.Key, s.Value);

View File

@@ -141,14 +141,14 @@ namespace OpenRA
public Lazy<CPos[]> SpawnPoints; public Lazy<CPos[]> SpawnPoints;
// Yaml map data // Yaml map data
[FieldLoader.Ignore] public readonly string[] RuleDefinitions = { }; [FieldLoader.Ignore] public readonly MiniYaml RuleDefinitions;
[FieldLoader.Ignore] public readonly string[] SequenceDefinitions = { }; [FieldLoader.Ignore] public readonly MiniYaml SequenceDefinitions;
[FieldLoader.Ignore] public readonly string[] VoxelSequenceDefinitions = { }; [FieldLoader.Ignore] public readonly MiniYaml VoxelSequenceDefinitions;
[FieldLoader.Ignore] public readonly string[] WeaponDefinitions = { }; [FieldLoader.Ignore] public readonly MiniYaml WeaponDefinitions;
[FieldLoader.Ignore] public readonly string[] VoiceDefinitions = { }; [FieldLoader.Ignore] public readonly MiniYaml VoiceDefinitions;
[FieldLoader.Ignore] public readonly string[] MusicDefinitions = { }; [FieldLoader.Ignore] public readonly MiniYaml MusicDefinitions;
[FieldLoader.Ignore] public readonly string[] NotificationDefinitions = { }; [FieldLoader.Ignore] public readonly MiniYaml NotificationDefinitions;
[FieldLoader.Ignore] public readonly string[] TranslationDefinitions = { }; [FieldLoader.Ignore] public readonly MiniYaml TranslationDefinitions;
[FieldLoader.Ignore] public List<MiniYamlNode> PlayerDefinitions = new List<MiniYamlNode>(); [FieldLoader.Ignore] public List<MiniYamlNode> PlayerDefinitions = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> ActorDefinitions = new List<MiniYamlNode>(); [FieldLoader.Ignore] public List<MiniYamlNode> ActorDefinitions = new List<MiniYamlNode>();
@@ -184,13 +184,6 @@ namespace OpenRA
throw new InvalidOperationException("Required file {0} not present in this map".F(filename)); 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<string[]>(section, node.Value.Value);
}
/// <summary> /// <summary>
/// Initializes a new map created by the editor or importer. /// 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. /// 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); MapSize = new int2(size);
Tileset = tileset.Id; 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<ResourceTile>(Grid.Type, size)); MapResources = Exts.Lazy(() => new CellLayer<ResourceTile>(Grid.Type, size));
MapTiles = Exts.Lazy(() => MapTiles = Exts.Lazy(() =>
@@ -260,14 +257,14 @@ namespace OpenRA
return spawns.ToArray(); return spawns.ToArray();
}); });
LoadFileList(yaml, "Rules", ref RuleDefinitions); RuleDefinitions = LoadRuleSection(yaml, "Rules");
LoadFileList(yaml, "Sequences", ref SequenceDefinitions); SequenceDefinitions = LoadRuleSection(yaml, "Sequences");
LoadFileList(yaml, "VoxelSequences", ref VoxelSequenceDefinitions); VoxelSequenceDefinitions = LoadRuleSection(yaml, "VoxelSequences");
LoadFileList(yaml, "Weapons", ref WeaponDefinitions); WeaponDefinitions = LoadRuleSection(yaml, "Weapons");
LoadFileList(yaml, "Voices", ref VoiceDefinitions); VoiceDefinitions = LoadRuleSection(yaml, "Voices");
LoadFileList(yaml, "Music", ref MusicDefinitions); MusicDefinitions = LoadRuleSection(yaml, "Music");
LoadFileList(yaml, "Notifications", ref NotificationDefinitions); NotificationDefinitions = LoadRuleSection(yaml, "Notifications");
LoadFileList(yaml, "Translations", ref TranslationDefinitions); TranslationDefinitions = LoadRuleSection(yaml, "Translations");
PlayerDefinitions = MiniYaml.NodesOrEmpty(yaml, "Players"); PlayerDefinitions = MiniYaml.NodesOrEmpty(yaml, "Players");
ActorDefinitions = MiniYaml.NodesOrEmpty(yaml, "Actors"); ActorDefinitions = MiniYaml.NodesOrEmpty(yaml, "Actors");
@@ -287,6 +284,12 @@ namespace OpenRA
Uid = ComputeUID(Package); 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() void PostInit()
{ {
rules = Exts.Lazy(() => rules = Exts.Lazy(() =>
@@ -448,21 +451,21 @@ namespace OpenRA
root.Add(new MiniYamlNode("Players", null, PlayerDefinitions)); root.Add(new MiniYamlNode("Players", null, PlayerDefinitions));
root.Add(new MiniYamlNode("Actors", null, ActorDefinitions)); root.Add(new MiniYamlNode("Actors", null, ActorDefinitions));
var fileFields = new[] var ruleSections = new[]
{ {
Pair.New("Rules", RuleDefinitions), new MiniYamlNode("Rules", RuleDefinitions),
Pair.New("Sequences", SequenceDefinitions), new MiniYamlNode("Sequences", SequenceDefinitions),
Pair.New("VoxelSequences", VoxelSequenceDefinitions), new MiniYamlNode("VoxelSequences", VoxelSequenceDefinitions),
Pair.New("Weapons", WeaponDefinitions), new MiniYamlNode("Weapons", WeaponDefinitions),
Pair.New("Voices", VoiceDefinitions), new MiniYamlNode("Voices", VoiceDefinitions),
Pair.New("Music", MusicDefinitions), new MiniYamlNode("Music", MusicDefinitions),
Pair.New("Notifications", NotificationDefinitions), new MiniYamlNode("Notifications", NotificationDefinitions),
Pair.New("Translations", TranslationDefinitions) new MiniYamlNode("Translations", TranslationDefinitions)
}; };
foreach (var kv in fileFields) foreach (var section in ruleSections)
if (kv.Second.Any()) if (section.Value != null && (section.Value.Value != null || section.Value.Nodes.Any()))
root.Add(new MiniYamlNode(kv.First, FieldSaver.FormatValue(kv.Second))); root.Add(section);
// Saving to a new package: copy over all the content from the map // Saving to a new package: copy over all the content from the map
if (Package != null && toPackage != Package) if (Package != null && toPackage != Package)

View File

@@ -13,6 +13,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using OpenRA.FileSystem;
namespace OpenRA namespace OpenRA
{ {
@@ -375,6 +376,21 @@ namespace OpenRA
foreach (var line in Nodes.ToLines(false)) foreach (var line in Nodes.ToLines(false))
yield return "\t" + line; yield return "\t" + line;
} }
public static List<MiniYamlNode> Load(IReadOnlyFileSystem fileSystem, IEnumerable<string> files, MiniYaml mapRules)
{
if (mapRules != null && mapRules.Value != null)
{
var mapFiles = FieldLoader.GetValue<string[]>("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] [Serializable]

View File

@@ -130,8 +130,7 @@ namespace OpenRA
return; return;
} }
var yaml = MiniYaml.Merge(Manifest.Translations.Append(map.TranslationDefinitions) var yaml = MiniYaml.Load(map, Manifest.Translations, map.TranslationDefinitions);
.Select(t => MiniYaml.FromStream(map.Open(t))));
Languages = yaml.Select(t => t.Key).ToArray(); Languages = yaml.Select(t => t.Key).ToArray();
foreach (var y in yaml) foreach (var y in yaml)
@@ -182,7 +181,7 @@ namespace OpenRA
foreach (var entry in map.Rules.Music) foreach (var entry in map.Rules.Music)
entry.Value.Load(map); 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(); VoxelLoader.Finish();
return map; return map;

View File

@@ -392,7 +392,7 @@ namespace OpenRA.Server
SendOrderTo(newConn, "Message", motd); 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."); SendOrderTo(newConn, "Message", "This map contains custom rules. Game experience may change.");
if (Settings.DisableSinglePlayer) if (Settings.DisableSinglePlayer)

View File

@@ -26,18 +26,17 @@ namespace OpenRA.Mods.Common.Lint
public void Run(Action<string> emitError, Action<string> emitWarning, Map map) public void Run(Action<string> emitError, Action<string> emitWarning, Map map)
{ {
if (map != null && !map.SequenceDefinitions.Any()) if (map.SequenceDefinitions == null)
return; return;
var modData = Game.ModData; var modData = Game.ModData;
this.emitError = emitError; this.emitError = emitError;
var mapSequences = map != null ? map.SequenceDefinitions : new string[0]; sequenceDefinitions = MiniYaml.Load(map, modData.Manifest.Sequences, map.SequenceDefinitions);
sequenceDefinitions = MiniYaml.Merge(modData.Manifest.Sequences.Append(mapSequences).Select(s => MiniYaml.FromStream(map.Open(s))));
var rules = map == null ? modData.DefaultRules : map.Rules; var rules = map.Rules;
var factions = rules.Actors["world"].TraitInfos<FactionInfo>().Select(f => f.InternalName).ToArray(); var factions = rules.Actors["world"].TraitInfos<FactionInfo>().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) foreach (var actorInfo in rules.Actors)
{ {

View File

@@ -387,7 +387,7 @@ namespace OpenRA.Mods.Common.Server
server.SendMessage("{0} changed the map to {1}.".F(client.Name, server.Map.Title)); 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."); server.SendMessage("This map contains custom rules. Game experience may change.");
if (server.Settings.DisableSinglePlayer) if (server.Settings.DisableSinglePlayer)

View File

@@ -90,7 +90,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
testMap.PreloadRules(); testMap.PreloadRules();
// Run all rule checks on the map if it defines custom rules. // 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); CheckRules(modData, testMap.Rules, testMap);
// Run all map-level checks here. // Run all map-level checks here.

View File

@@ -33,10 +33,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
public ModData ModData; public ModData ModData;
public Map Map; public Map Map;
public IReadWritePackage Package;
public List<string> Players = new List<string>(); public List<string> Players = new List<string>();
public MapPlayers MapPlayers; public MapPlayers MapPlayers;
public MiniYaml Rules = new MiniYaml("");
public bool ValidateArguments(string[] args) public bool ValidateArguments(string[] args)
{ {
@@ -52,8 +50,6 @@ namespace OpenRA.Mods.Common.UtilityCommands
Game.ModData = modData; Game.ModData = modData;
var filename = args[1]; 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)) using (var stream = modData.DefaultFileSystem.Open(filename))
{ {
var file = new IniFile(stream); var file = new IniFile(stream);
@@ -67,7 +63,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
Map = new Map(modData, modData.DefaultRules.TileSets[tileset], MapSize, MapSize) Map = new Map(modData, modData.DefaultRules.TileSets[tileset], MapSize, MapSize)
{ {
Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)), Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)),
Author = "Westwood Studios" Author = "Westwood Studios",
}; };
Map.RequiresMod = modData.Manifest.Mod.Id; Map.RequiresMod = modData.Manifest.Mod.Id;
@@ -96,16 +92,10 @@ namespace OpenRA.Mods.Common.UtilityCommands
Map.FixOpenAreas(); Map.FixOpenAreas();
if (Rules.Nodes.Any()) var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap";
{ var package = new ZipFile(modData.ModFiles, dest, true);
// 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 = Rules.Nodes.ToLines(false).JoinWith("\n"); Map.Save(package);
Package.Update("rules.yaml", System.Text.Encoding.ASCII.GetBytes(rulesText));
}
Map.Save(Package);
Console.WriteLine(dest + " saved."); Console.WriteLine(dest + " saved.");
} }
@@ -140,11 +130,11 @@ namespace OpenRA.Mods.Common.UtilityCommands
if (briefing.Length == 0) if (briefing.Length == 0)
return; return;
var worldNode = Rules.Nodes.FirstOrDefault(n => n.Key == "World"); var worldNode = Map.RuleDefinitions.Nodes.FirstOrDefault(n => n.Key == "World");
if (worldNode == null) if (worldNode == null)
{ {
worldNode = new MiniYamlNode("World", new MiniYaml("", new List<MiniYamlNode>())); worldNode = new MiniYamlNode("World", new MiniYaml("", new List<MiniYamlNode>()));
Rules.Nodes.Add(worldNode); Map.RuleDefinitions.Nodes.Add(worldNode);
} }
var missionData = worldNode.Value.Nodes.FirstOrDefault(n => n.Key == "MissionData"); var missionData = worldNode.Value.Nodes.FirstOrDefault(n => n.Key == "MissionData");
@@ -201,11 +191,11 @@ namespace OpenRA.Mods.Common.UtilityCommands
if (videos.Any()) 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) if (worldNode == null)
{ {
worldNode = new MiniYamlNode("World", new MiniYaml("", new List<MiniYamlNode>())); worldNode = new MiniYamlNode("World", new MiniYaml("", new List<MiniYamlNode>()));
Rules.Nodes.Add(worldNode); Map.RuleDefinitions.Nodes.Add(worldNode);
} }
var missionData = worldNode.Value.Nodes.FirstOrDefault(n => n.Key == "MissionData"); var missionData = worldNode.Value.Nodes.FirstOrDefault(n => n.Key == "MissionData");
@@ -298,7 +288,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
craters.Add(node); 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) if (worldNode == null)
worldNode = new MiniYamlNode("World", new MiniYaml("", new List<MiniYamlNode>())); worldNode = new MiniYamlNode("World", new MiniYaml("", new List<MiniYamlNode>()));
@@ -316,8 +306,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
worldNode.Value.Nodes.Add(smudgeLayer); worldNode.Value.Nodes.Add(smudgeLayer);
} }
if (worldNode.Value.Nodes.Any() && !Rules.Nodes.Contains(worldNode)) if (worldNode.Value.Nodes.Any() && !Map.RuleDefinitions.Nodes.Contains(worldNode))
Rules.Nodes.Add(worldNode); Map.RuleDefinitions.Nodes.Add(worldNode);
} }
// TODO: fix this -- will have bitrotted pretty badly. // TODO: fix this -- will have bitrotted pretty badly.

View File

@@ -27,17 +27,23 @@ namespace OpenRA.Mods.Common.UtilityCommands
delegate void UpgradeAction(int engineVersion, ref List<MiniYamlNode> nodes, MiniYamlNode parent, int depth); delegate void UpgradeAction(int engineVersion, ref List<MiniYamlNode> nodes, MiniYamlNode parent, int depth);
static void ProcessYaml(Map map, IEnumerable<string> files, int engineDate, UpgradeAction processFile) static void ProcessYaml(Map map, MiniYaml yaml, int engineDate, UpgradeAction processYaml)
{ {
foreach (var filename in files) if (yaml == null)
{ return;
if (!map.Package.Contains(filename))
continue;
var yaml = MiniYaml.FromStream(map.Package.GetStream(filename)); if (yaml.Value != null)
processFile(engineDate, ref yaml, null, 0); {
((IReadWritePackage)map.Package).Update(filename, Encoding.ASCII.GetBytes(yaml.WriteToString())); var files = FieldLoader.GetValue<string[]>("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) public static void UpgradeMap(ModData modData, IReadWritePackage package, int engineDate)

View File

@@ -948,20 +948,10 @@ namespace OpenRA.Mods.Common.UtilityCommands
rules.Value.Nodes.Add(playerNode); rules.Value.Nodes.Add(playerNode);
} }
// Format 9 -> 10 extracted map rules, sequences, voxelsequences, weapons, voices, music, notifications, // Format 9 -> 10 moved smudges to SmudgeLayer, and uses map.png for all maps
// and translations to external files, moved smudges to SmudgeLayer, and uses map.png for all maps
if (mapFormat < 10) if (mapFormat < 10)
{ {
ExtractSmudges(yaml); 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")) if (package.Contains("map.png"))
yaml.Nodes.Add(new MiniYamlNode("LockPreview", new MiniYaml("True"))); yaml.Nodes.Add(new MiniYamlNode("LockPreview", new MiniYaml("True")));
} }
@@ -1023,22 +1013,5 @@ namespace OpenRA.Mods.Common.UtilityCommands
worldNode.Value.Nodes.Add(smudgeLayer); 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);
}
} }
} }

View File

@@ -165,8 +165,6 @@ namespace OpenRA.Mods.TS.UtilityCommands
var filename = args[1]; var filename = args[1];
var file = new IniFile(File.Open(args[1], FileMode.Open)); var file = new IniFile(File.Open(args[1], FileMode.Open));
var map = GenerateMapHeader(filename, file, modData); var map = GenerateMapHeader(filename, file, modData);
var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap";
var package = new ZipFile(modData.DefaultFileSystem, dest, true);
ReadTiles(map, file); ReadTiles(map, file);
ReadActors(map, file, "Structures"); ReadActors(map, file, "Structures");
@@ -175,11 +173,13 @@ namespace OpenRA.Mods.TS.UtilityCommands
ReadTerrainActors(map, file); ReadTerrainActors(map, file);
ReadWaypoints(map, file); ReadWaypoints(map, file);
ReadOverlay(map, file); ReadOverlay(map, file);
ReadLighting(map, package, file); ReadLighting(map, file);
var mapPlayers = new MapPlayers(map.Rules, spawnCount); var mapPlayers = new MapPlayers(map.Rules, spawnCount);
map.PlayerDefinitions = mapPlayers.ToMiniYaml(); map.PlayerDefinitions = mapPlayers.ToMiniYaml();
var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap";
var package = new ZipFile(modData.DefaultFileSystem, dest, true);
map.Save(package); map.Save(package);
Console.WriteLine(dest + " saved."); 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 lightingTypes = new[] { "Red", "Green", "Blue", "Ambient" };
var lightingSection = file.GetSection("Lighting"); var lightingSection = file.GetSection("Lighting");
var lightingNode = new MiniYamlNode("GlobalLightingPaletteEffect", new MiniYaml("", new List<MiniYamlNode>())); var lightingNodes = new List<MiniYamlNode>();
var worldNode = new MiniYamlNode("World", new MiniYaml("", new List<MiniYamlNode>() { lightingNode }));
foreach (var kv in lightingSection) foreach (var kv in lightingSection)
{ {
@@ -444,19 +443,18 @@ namespace OpenRA.Mods.TS.UtilityCommands
{ {
var val = FieldLoader.GetValue<float>(kv.Key, kv.Value); var val = FieldLoader.GetValue<float>(kv.Key, kv.Value);
if (val != 1.0f) 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 else
Console.WriteLine("Ignoring unknown lighting type: `{0}`".F(kv.Key)); 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 map.RuleDefinitions.Nodes.Add(new MiniYamlNode("World", new MiniYaml("", new List<MiniYamlNode>()
typeof(Map).GetField("RuleDefinitions").SetValue(map, new[] { "rules.yaml" }); {
new MiniYamlNode("GlobalLightingPaletteEffect", new MiniYaml("", lightingNodes))
var rulesText = new List<MiniYamlNode>() { worldNode }.ToLines(false).JoinWith("\n"); })));
package.Update("rules.yaml", System.Text.Encoding.ASCII.GetBytes(rulesText));
} }
} }
} }

View File

@@ -1293,4 +1293,7 @@ Actors:
Owner: Neutral Owner: Neutral
Location: 115,-15 Location: 115,-15
Rules: rules.yaml Rules:
World:
GlobalLightingPaletteEffect:
Ambient: 0.72

View File

@@ -1,3 +0,0 @@
World:
GlobalLightingPaletteEffect:
Ambient: 0.72

View File

@@ -1499,4 +1499,7 @@ Actors:
Location: 123,87 Location: 123,87
Owner: Neutral Owner: Neutral
Rules: rules.yaml Rules:
World:
GlobalLightingPaletteEffect:
Ambient: 0.68

View File

@@ -1,3 +0,0 @@
World:
GlobalLightingPaletteEffect:
Ambient: 0.68

View File

@@ -1737,3 +1737,9 @@ Actors:
Location: 111,13 Location: 111,13
Rules: rules.yaml Rules: rules.yaml
World:
GlobalLightingPaletteEffect:
Red: 1.1
Green: 1.1
Blue: 1
Ambient: 0.55

View File

@@ -4,10 +4,5 @@ World:
-MPStartLocations: -MPStartLocations:
MusicPlaylist: MusicPlaylist:
BackgroundMusic: intro BackgroundMusic: intro
GlobalLightingPaletteEffect:
Red: 1.1
Green: 1.1
Blue: 1
Ambient: 0.55
LuaScript: LuaScript:
Scripts: map.lua Scripts: map.lua

View File

@@ -1554,4 +1554,10 @@ Actors:
Location: 134,73 Location: 134,73
Owner: Neutral Owner: Neutral
Rules: rules.yaml Rules:
World:
GlobalLightingPaletteEffect:
Red: 0.5
Green: 0.7
Blue: 0.7
Ambient: 0.78

View File

@@ -1,6 +0,0 @@
World:
GlobalLightingPaletteEffect:
Red: 0.5
Blue: 0.7
Green: 0.7
Ambient: 0.78

View File

@@ -868,4 +868,7 @@ Actors:
Location: 254,39 Location: 254,39
Owner: Neutral Owner: Neutral
Rules: rules.yaml Rules:
World:
GlobalLightingPaletteEffect:
Ambient: 0.85

View File

@@ -1,3 +0,0 @@
World:
GlobalLightingPaletteEffect:
Ambient: 0.85

View File

@@ -853,4 +853,7 @@ Actors:
Owner: Neutral Owner: Neutral
Location: 95,3 Location: 95,3
Rules: rules.yaml Rules:
World:
GlobalLightingPaletteEffect:
Ambient: 0.62

View File

@@ -1,3 +0,0 @@
World:
GlobalLightingPaletteEffect:
Ambient: 0.62

View File

@@ -830,4 +830,7 @@ Actors:
Location: 99,74 Location: 99,74
Owner: Neutral Owner: Neutral
Rules: rules.yaml Rules:
World:
GlobalLightingPaletteEffect:
Ambient: 0.79

View File

@@ -1,6 +0,0 @@
World:
GlobalLightingPaletteEffect:
Red: 1
Blue: 1
Green: 1
Ambient: 0.79

View File

@@ -800,4 +800,7 @@ Actors:
Location: 167,83 Location: 167,83
Owner: Neutral Owner: Neutral
Rules: rules.yaml Rules:
World:
GlobalLightingPaletteEffect:
Ambient: 0.85

View File

@@ -1,3 +0,0 @@
World:
GlobalLightingPaletteEffect:
Ambient: 0.85

View File

@@ -509,4 +509,7 @@ Actors:
Location: 84,60 Location: 84,60
Owner: Neutral Owner: Neutral
Rules: rules.yaml Rules:
World:
GlobalLightingPaletteEffect:
Ambient: 0.63

View File

@@ -1,3 +0,0 @@
World:
GlobalLightingPaletteEffect:
Ambient: 0.63

View File

@@ -1213,4 +1213,7 @@ Actors:
Location: 123,20 Location: 123,20
Owner: Neutral Owner: Neutral
Rules: rules.yaml Rules:
World:
GlobalLightingPaletteEffect:
Ambient: 0.75

View File

@@ -1,3 +0,0 @@
World:
GlobalLightingPaletteEffect:
Ambient: 0.75