diff --git a/OpenRA.Game/Exts.cs b/OpenRA.Game/Exts.cs index 11a428e089..53de85d9c7 100644 --- a/OpenRA.Game/Exts.cs +++ b/OpenRA.Game/Exts.cs @@ -361,7 +361,7 @@ namespace OpenRA public static Dictionary ToDictionaryWithConflictLog( this IEnumerable source, Func keySelector, Func elementSelector, - string debugName, Func logKey, Func logValue) + string debugName, Func logKey = null, Func logValue = null) { // Fall back on ToString() if null functions are provided: logKey = logKey ?? (s => s.ToString()); diff --git a/OpenRA.Game/GameRules/Ruleset.cs b/OpenRA.Game/GameRules/Ruleset.cs index 01a2e5fa93..0f7e299076 100644 --- a/OpenRA.Game/GameRules/Ruleset.cs +++ b/OpenRA.Game/GameRules/Ruleset.cs @@ -9,8 +9,11 @@ */ #endregion +using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; +using OpenRA.FileSystem; using OpenRA.GameRules; using OpenRA.Graphics; using OpenRA.Traits; @@ -24,25 +27,25 @@ namespace OpenRA public readonly IReadOnlyDictionary Voices; public readonly IReadOnlyDictionary Notifications; public readonly IReadOnlyDictionary Music; - public readonly IReadOnlyDictionary TileSets; - public readonly IReadOnlyDictionary Sequences; + public readonly TileSet TileSet; + public readonly SequenceProvider Sequences; public Ruleset( - IDictionary actors, - IDictionary weapons, - IDictionary voices, - IDictionary notifications, - IDictionary music, - IDictionary tileSets, - IDictionary sequences) + IReadOnlyDictionary actors, + IReadOnlyDictionary weapons, + IReadOnlyDictionary voices, + IReadOnlyDictionary notifications, + IReadOnlyDictionary music, + TileSet tileSet, + SequenceProvider sequences) { - Actors = new ReadOnlyDictionary(actors); - Weapons = new ReadOnlyDictionary(weapons); - Voices = new ReadOnlyDictionary(voices); - Notifications = new ReadOnlyDictionary(notifications); - Music = new ReadOnlyDictionary(music); - TileSets = new ReadOnlyDictionary(tileSets); - Sequences = new ReadOnlyDictionary(sequences); + Actors = actors; + Weapons = weapons; + Voices = voices; + Notifications = notifications; + Music = music; + TileSet = tileSet; + Sequences = sequences; foreach (var a in Actors.Values) { @@ -80,5 +83,120 @@ namespace OpenRA } public IEnumerable> InstalledMusic { get { return Music.Where(m => m.Value.Exists); } } + + static IReadOnlyDictionary MergeOrDefault(string name, IReadOnlyFileSystem fileSystem, IEnumerable files, MiniYaml additional, + IReadOnlyDictionary defaults, Func makeObject) + { + if (additional == null && defaults != null) + return defaults; + + var result = MiniYaml.Load(fileSystem, files, additional) + .ToDictionaryWithConflictLog(k => k.Key.ToLowerInvariant(), makeObject, "LoadFromManifest<" + name + ">"); + + return new ReadOnlyDictionary(result); + } + + public static Ruleset LoadDefaults(ModData modData) + { + var m = modData.Manifest; + var fs = modData.DefaultFileSystem; + + Ruleset ruleset = null; + Action f = () => + { + var actors = MergeOrDefault("Manifest,Rules", fs, m.Rules, null, null, + k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value)); + + var weapons = MergeOrDefault("Manifest,Weapons", fs, m.Weapons, null, null, + k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); + + var voices = MergeOrDefault("Manifest,Voices", fs, m.Voices, null, null, + k => new SoundInfo(k.Value)); + + var notifications = MergeOrDefault("Manifest,Notifications", fs, m.Notifications, null, null, + k => new SoundInfo(k.Value)); + + var music = MergeOrDefault("Manifest,Music", fs, m.Music, null, null, + k => new MusicInfo(k.Key, k.Value)); + + // The default ruleset does not include a preferred tileset or sequence set + ruleset = new Ruleset(actors, weapons, voices, notifications, music, null, null); + }; + + if (modData.IsOnMainThread) + { + modData.HandleLoadingProgress(); + + var loader = new Task(f); + loader.Start(); + + // Animate the loadscreen while we wait + while (!loader.Wait(40)) + modData.HandleLoadingProgress(); + } + else + f(); + + return ruleset; + } + + public static Ruleset LoadDefaultsForTileSet(ModData modData, string tileSet) + { + var dr = modData.DefaultRules; + var ts = modData.DefaultTileSets[tileSet]; + var sequences = modData.DefaultSequences[tileSet]; + return new Ruleset(dr.Actors, dr.Weapons, dr.Voices, dr.Notifications, dr.Music, ts, sequences); + } + + public static Ruleset LoadFromMap(ModData modData, Map map) + { + var m = modData.Manifest; + var dr = modData.DefaultRules; + + Ruleset ruleset = null; + Action f = () => + { + var actors = MergeOrDefault("Manifest,Rules", map, m.Rules, map.RuleDefinitions, dr.Actors, + k => new ActorInfo(modData.ObjectCreator, k.Key.ToLowerInvariant(), k.Value)); + + var weapons = MergeOrDefault("Manifest,Weapons", map, m.Weapons, map.WeaponDefinitions, dr.Weapons, + k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); + + var voices = MergeOrDefault("Manifest,Voices", map, m.Voices, map.VoiceDefinitions, dr.Voices, + k => new SoundInfo(k.Value)); + + var notifications = MergeOrDefault("Manifest,Notifications", map, m.Notifications, map.NotificationDefinitions, dr.Notifications, + k => new SoundInfo(k.Value)); + + var music = MergeOrDefault("Manifest,Music", map, m.Music, map.NotificationDefinitions, dr.Music, + k => new MusicInfo(k.Key, k.Value)); + + // TODO: Add support for merging custom tileset modifications + var ts = modData.DefaultTileSets[map.Tileset]; + + // TODO: Top-level dictionary should be moved into the Ruleset instead of in its own object + var sequences = map.SequenceDefinitions == null ? modData.DefaultSequences[map.Tileset] : + new SequenceProvider(map, modData, ts, map.SequenceDefinitions); + + // TODO: Add support for custom voxel sequences + ruleset = new Ruleset(actors, weapons, voices, notifications, music, ts, sequences); + }; + + if (modData.IsOnMainThread) + { + modData.HandleLoadingProgress(); + + var loader = new Task(f); + loader.Start(); + + // Animate the loadscreen while we wait + while (!loader.Wait(40)) + modData.HandleLoadingProgress(); + } + else + f(); + + return ruleset; + } } } diff --git a/OpenRA.Game/GameRules/RulesetCache.cs b/OpenRA.Game/GameRules/RulesetCache.cs deleted file mode 100644 index b308b18a8e..0000000000 --- a/OpenRA.Game/GameRules/RulesetCache.cs +++ /dev/null @@ -1,159 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRA.FileSystem; -using OpenRA.GameRules; -using OpenRA.Graphics; -using OpenRA.Support; - -namespace OpenRA -{ - public sealed class RulesetCache - { - readonly ModData modData; - - readonly Dictionary actorCache = new Dictionary(); - readonly Dictionary weaponCache = new Dictionary(); - readonly Dictionary voiceCache = new Dictionary(); - readonly Dictionary notificationCache = new Dictionary(); - readonly Dictionary musicCache = new Dictionary(); - readonly Dictionary tileSetCache = new Dictionary(); - - public event EventHandler LoadingProgress; - void RaiseProgress() - { - if (LoadingProgress != null) - LoadingProgress(this, new EventArgs()); - } - - public RulesetCache(ModData modData) - { - this.modData = modData; - } - - public Ruleset Load(IReadOnlyFileSystem fileSystem, - MiniYaml additionalRules, - MiniYaml additionalWeapons, - MiniYaml additionalVoices, - MiniYaml additionalNotifications, - MiniYaml additionalMusic, - MiniYaml additionalSequences) - { - var m = modData.Manifest; - - Dictionary actors; - Dictionary weapons; - Dictionary voices; - Dictionary notifications; - Dictionary music; - Dictionary tileSets; - - using (new PerfTimer("Actors")) - 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, additionalWeapons, - k => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); - - using (new PerfTimer("Voices")) - voices = LoadYamlRules(fileSystem, voiceCache, m.Voices, additionalVoices, - k => new SoundInfo(k.Value)); - - using (new PerfTimer("Notifications")) - notifications = LoadYamlRules(fileSystem, notificationCache, m.Notifications, additionalNotifications, - k => new SoundInfo(k.Value)); - - using (new PerfTimer("Music")) - 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, 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, - IEnumerable files, MiniYaml mapRules, - Func f) - { - RaiseProgress(); - - 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("|"); - T t; - if (itemCache.TryGetValue(key, out t)) - return t; - - t = f(wkv); - itemCache.Add(key, t); - - RaiseProgress(); - return t; - }; - - 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))); - RaiseProgress(); - return itemSet; - } - - Dictionary LoadTileSets(IReadOnlyFileSystem fileSystem, Dictionary itemCache, string[] files) - { - var items = new Dictionary(); - - foreach (var file in files) - { - TileSet t; - if (itemCache.TryGetValue(file, out t)) - items.Add(t.Id, t); - else - { - t = new TileSet(fileSystem, file); - itemCache.Add(file, t); - items.Add(t.Id, t); - } - } - - return items; - } - } -} diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index a674b4c212..6fd195351e 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -169,10 +169,9 @@ namespace OpenRA [FieldLoader.Ignore] CellLayer cellProjection; [FieldLoader.Ignore] CellLayer> inverseCellProjection; - [FieldLoader.Ignore] Lazy cachedTileSet; [FieldLoader.Ignore] Lazy rules; public Ruleset Rules { get { return rules != null ? rules.Value : null; } } - public SequenceProvider SequenceProvider { get { return Rules.Sequences[Tileset]; } } + public SequenceProvider SequenceProvider { get { return Rules.Sequences; } } [FieldLoader.Ignore] public ProjectedCellRegion ProjectedCellBounds; [FieldLoader.Ignore] public CellRegion AllCells; @@ -297,7 +296,7 @@ namespace OpenRA { try { - return modData.RulesetCache.Load(this, this); + return Ruleset.LoadFromMap(modData, this); } catch (Exception e) { @@ -305,11 +304,9 @@ namespace OpenRA Log.Write("debug", "Failed to load rules for {0} with error {1}", Title, e.Message); } - return modData.DefaultRules; + return Ruleset.LoadDefaultsForTileSet(modData, Tileset); }); - cachedTileSet = Exts.Lazy(() => Rules.TileSets[Tileset]); - var tl = new MPos(0, 0).ToCPos(this); var br = new MPos(MapSize.X - 1, MapSize.Y - 1).ToCPos(this); AllCells = new CellRegion(Grid.Type, tl, br); @@ -391,7 +388,7 @@ namespace OpenRA // Odd-height ramps get bumped up a level to the next even height layer if ((height & 1) == 1) { - var ti = cachedTileSet.Value.GetTileInfo(MapTiles.Value[uv]); + var ti = Rules.TileSet.GetTileInfo(MapTiles.Value[uv]); if (ti != null && ti.RampType != 0) height += 1; } @@ -627,7 +624,7 @@ namespace OpenRA public byte[] SavePreview() { - var tileset = Rules.TileSets[Tileset]; + var tileset = Rules.TileSet; var resources = Rules.Actors["world"].TraitInfos() .ToDictionary(r => r.ResourceType, r => r.TerrainType); @@ -878,7 +875,7 @@ namespace OpenRA public void FixOpenAreas() { var r = new Random(); - var tileset = Rules.TileSets[Tileset]; + var tileset = Rules.TileSet; for (var j = Bounds.Top; j < Bounds.Bottom; j++) { @@ -926,7 +923,7 @@ namespace OpenRA { var custom = CustomTerrain[uv]; terrainIndex = cachedTerrainIndexes[uv] = - custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[uv]); + custom != byte.MaxValue ? custom : Rules.TileSet.GetTerrainIndex(MapTiles.Value[uv]); } return (byte)terrainIndex; @@ -934,7 +931,7 @@ namespace OpenRA public TerrainTypeInfo GetTerrainInfo(CPos cell) { - return cachedTileSet.Value[GetTerrainIndex(cell)]; + return Rules.TileSet[GetTerrainIndex(cell)]; } public CPos Clamp(CPos cell) diff --git a/OpenRA.Game/ModData.cs b/OpenRA.Game/ModData.cs index b20b31e25c..1792eaa620 100644 --- a/OpenRA.Game/ModData.cs +++ b/OpenRA.Game/ModData.cs @@ -30,15 +30,20 @@ namespace OpenRA public readonly ISoundLoader[] SoundLoaders; public readonly ISpriteLoader[] SpriteLoaders; public readonly ISpriteSequenceLoader SpriteSequenceLoader; - public readonly RulesetCache RulesetCache; public ILoadScreen LoadScreen { get; private set; } public VoxelLoader VoxelLoader { get; private set; } public CursorProvider CursorProvider { get; private set; } public FS ModFiles = new FS(); + public IReadOnlyFileSystem DefaultFileSystem { get { return ModFiles; } } readonly Lazy defaultRules; public Ruleset DefaultRules { get { return defaultRules.Value; } } - public IReadOnlyFileSystem DefaultFileSystem { get { return ModFiles; } } + + readonly Lazy> defaultTileSets; + public IReadOnlyDictionary DefaultTileSets { get { return defaultTileSets.Value; } } + + readonly Lazy> defaultSequences; + public IReadOnlyDictionary DefaultSequences { get { return defaultSequences.Value; } } public ModData(string mod, bool useLoadScreen = false) { @@ -57,8 +62,6 @@ namespace OpenRA } WidgetLoader = new WidgetLoader(this); - RulesetCache = new RulesetCache(this); - RulesetCache.LoadingProgress += HandleLoadingProgress; MapCache = new MapCache(this); SoundLoaders = GetLoaders(Manifest.SoundFormats, "sound"); @@ -73,19 +76,39 @@ namespace OpenRA SpriteSequenceLoader = (ISpriteSequenceLoader)ctor.Invoke(new[] { this }); SpriteSequenceLoader.OnMissingSpriteError = s => Log.Write("debug", s); - defaultRules = Exts.Lazy(() => RulesetCache.Load(DefaultFileSystem)); + defaultRules = Exts.Lazy(() => Ruleset.LoadDefaults(this)); + defaultTileSets = Exts.Lazy(() => + { + var items = new Dictionary(); + + foreach (var file in Manifest.TileSets) + { + var t = new TileSet(DefaultFileSystem, file); + items.Add(t.Id, t); + } + + return (IReadOnlyDictionary)(new ReadOnlyDictionary(items)); + }); + + defaultSequences = Exts.Lazy(() => + { + var items = DefaultTileSets.ToDictionary(t => t.Key, t => new SequenceProvider(DefaultFileSystem, this, t.Value, null)); + return (IReadOnlyDictionary)(new ReadOnlyDictionary(items)); + }); initialThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId; } // HACK: Only update the loading screen if we're in the main thread. int initialThreadId; - void HandleLoadingProgress(object sender, EventArgs e) + internal void HandleLoadingProgress() { - if (LoadScreen != null && System.Threading.Thread.CurrentThread.ManagedThreadId == initialThreadId) + if (LoadScreen != null && IsOnMainThread) LoadScreen.Display(); } + internal bool IsOnMainThread { get { return System.Threading.Thread.CurrentThread.ManagedThreadId == initialThreadId; } } + public void InitializeLoaders(IReadOnlyFileSystem fileSystem) { // all this manipulation of static crap here is nasty and breaks diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 983eeceb19..d75b30c3ee 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -215,7 +215,6 @@ - diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 98bffa816a..23ef101885 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -160,7 +160,7 @@ namespace OpenRA Map = map; Timestep = orderManager.LobbyInfo.GlobalSettings.Timestep; - TileSet = map.Rules.TileSets[Map.Tileset]; + TileSet = map.Rules.TileSet; SharedRandom = new MersenneTwister(orderManager.LobbyInfo.GlobalSettings.RandomSeed); var worldActorType = type == WorldType.Editor ? "EditorWorld" : "World"; diff --git a/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs b/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs index 47fdd2b85c..85f9a92f72 100644 --- a/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs +++ b/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs @@ -37,7 +37,7 @@ namespace OpenRA.Mods.Common.Widgets preview.IsVisible = () => editorWidget.CurrentBrush == this; var variant = resource.Variants.FirstOrDefault(); - var sequenceProvider = wr.World.Map.Rules.Sequences[world.TileSet.Id]; + var sequenceProvider = wr.World.Map.Rules.Sequences; var sequence = sequenceProvider.GetSequence("resources", variant); var sprite = sequence.GetSprite(resource.MaxDensity - 1); preview.GetSprite = () => sprite; diff --git a/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs b/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs index 1f1796d231..5c2ab6f272 100644 --- a/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs +++ b/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs @@ -100,8 +100,7 @@ namespace OpenRA.Mods.Common.Widgets var mapTiles = map.MapTiles.Value; var mapHeight = map.MapHeight.Value; - var rules = map.Rules; - var tileset = rules.TileSets[map.Tileset]; + var tileset = map.Rules.TileSet; var template = tileset.Templates[Template]; var baseHeight = mapHeight.Contains(cell) ? mapHeight[cell] : (byte)0; @@ -139,8 +138,7 @@ namespace OpenRA.Mods.Common.Widgets var queue = new Queue(); var touched = new CellLayer(map); - var rules = map.Rules; - var tileset = rules.TileSets[map.Tileset]; + var tileset = map.Rules.TileSet; var template = tileset.Templates[Template]; Action maybeEnqueue = newCell => diff --git a/OpenRA.Mods.Common/Lint/CheckSequences.cs b/OpenRA.Mods.Common/Lint/CheckSequences.cs index d1ed7d0e72..166d25c1e9 100644 --- a/OpenRA.Mods.Common/Lint/CheckSequences.cs +++ b/OpenRA.Mods.Common/Lint/CheckSequences.cs @@ -36,7 +36,7 @@ namespace OpenRA.Mods.Common.Lint var rules = map.Rules; var factions = rules.Actors["world"].TraitInfos().Select(f => f.InternalName).ToArray(); - var sequenceProviders = new[] { rules.Sequences[map.Tileset] }; + var sequenceProviders = new[] { rules.Sequences }; foreach (var actorInfo in rules.Actors) { diff --git a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs index 0285393c24..39ac629eb5 100644 --- a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs @@ -308,7 +308,7 @@ namespace OpenRA.Mods.Common.Server // Pick a random color for the bot var validator = server.ModData.Manifest.Get(); - var tileset = server.Map.Rules.TileSets[server.Map.Tileset]; + var tileset = server.Map.Rules.TileSet; var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color); var playerColors = server.LobbyInfo.Clients.Select(c => c.Color.RGB) .Concat(server.MapPlayers.Players.Values.Select(p => p.Color.RGB)); @@ -1064,7 +1064,7 @@ namespace OpenRA.Mods.Common.Server server.SendOrderTo(connectionToEcho, "Message", message); }; - var tileset = server.Map.Rules.TileSets[server.Map.Tileset]; + var tileset = server.Map.Rules.TileSet; var terrainColors = tileset.TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color).ToList(); var playerColors = server.LobbyInfo.Clients.Where(c => c.Index != playerIndex).Select(c => c.Color.RGB) .Concat(server.MapPlayers.Players.Values.Select(p => p.Color.RGB)).ToList(); diff --git a/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs b/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs index 943fb2edb2..ee47648cdb 100644 --- a/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs +++ b/OpenRA.Mods.Common/UtilityCommands/CheckYaml.cs @@ -127,7 +127,6 @@ namespace OpenRA.Mods.Common.UtilityCommands { try { - modData.RulesetCache.Load(map ?? modData.DefaultFileSystem, map); var customRulesPass = (ILintRulesPass)modData.ObjectCreator.CreateBasic(customRulesPassType); customRulesPass.Run(EmitError, EmitWarning, rules); } diff --git a/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs index 0534c7d6ba..712143d64b 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ExtractLanguageStringsCommand.cs @@ -30,7 +30,6 @@ namespace OpenRA.Mods.Common.UtilityCommands { // HACK: The engine code assumes that Game.modData is set. Game.ModData = modData; - modData.RulesetCache.Load(modData.DefaultFileSystem); var types = Game.ModData.ObjectCreator.GetTypes(); var translatableFields = types.SelectMany(t => t.GetFields()) diff --git a/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs index 28ee6125a2..2728cddcef 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs @@ -60,7 +60,7 @@ namespace OpenRA.Mods.Common.UtilityCommands ValidateMapFormat(format); var tileset = GetTileset(mapSection); - Map = new Map(modData, modData.DefaultRules.TileSets[tileset], MapSize, MapSize) + Map = new Map(modData, modData.DefaultTileSets[tileset], MapSize, MapSize) { Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)), Author = "Westwood Studios", diff --git a/OpenRA.Mods.Common/UtilityCommands/RemapShpCommand.cs b/OpenRA.Mods.Common/UtilityCommands/RemapShpCommand.cs index f18f0bc33d..9b892dc179 100644 --- a/OpenRA.Mods.Common/UtilityCommands/RemapShpCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/RemapShpCommand.cs @@ -42,15 +42,13 @@ namespace OpenRA.Mods.Common.UtilityCommands var srcModData = new ModData(srcMod); Game.ModData = srcModData; - var srcRules = srcModData.RulesetCache.Load(srcModData.DefaultFileSystem); - var srcPaletteInfo = srcRules.Actors["player"].TraitInfo(); + var srcPaletteInfo = srcModData.DefaultRules.Actors["player"].TraitInfo(); var srcRemapIndex = srcPaletteInfo.RemapIndex; var destMod = args[2].Split(':')[0]; var destModData = new ModData(destMod); Game.ModData = destModData; - var destRules = destModData.RulesetCache.Load(destModData.DefaultFileSystem); - var destPaletteInfo = destRules.Actors["player"].TraitInfo(); + var destPaletteInfo = destModData.DefaultRules.Actors["player"].TraitInfo(); var destRemapIndex = destPaletteInfo.RemapIndex; var shadowIndex = new int[] { }; diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs index 63c697dde6..985eb1fa77 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs @@ -19,7 +19,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic public class LayerSelectorLogic : ChromeLogic { readonly EditorViewportControllerWidget editor; - readonly World world; readonly WorldRenderer worldRenderer; readonly ScrollPanelWidget layerTemplateList; @@ -29,8 +28,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic public LayerSelectorLogic(Widget widget, WorldRenderer worldRenderer) { this.worldRenderer = worldRenderer; - world = worldRenderer.World; - editor = widget.Parent.Get("MAP_EDITOR"); layerTemplateList = widget.Get("LAYERTEMPLATE_LIST"); @@ -60,7 +57,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic layerPreview.GetPalette = () => resource.Palette; var variant = resource.Variants.FirstOrDefault(); - var sequenceProvider = rules.Sequences[world.TileSet.Id]; + var sequenceProvider = rules.Sequences; var sequence = sequenceProvider.GetSequence("resources", variant); var frame = sequence.Frames != null ? sequence.Frames.Last() : resource.MaxDensity - 1; layerPreview.GetSprite = () => sequence.GetSprite(frame); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/NewMapLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/NewMapLogic.cs index 45fe326b1e..00067aa452 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/NewMapLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/NewMapLogic.cs @@ -20,14 +20,14 @@ namespace OpenRA.Mods.Common.Widgets.Logic Widget panel; [ObjectCreator.UseCtor] - public NewMapLogic(Action onExit, Action onSelect, Widget widget, World world) + public NewMapLogic(Action onExit, Action onSelect, Widget widget, World world, ModData modData) { panel = widget; panel.Get("CANCEL_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; var tilesetDropDown = panel.Get("TILESET"); - var tilesets = world.Map.Rules.TileSets.Select(t => t.Key).ToList(); + var tilesets = modData.DefaultTileSets.Select(t => t.Key).ToList(); Func setupItem = (option, template) => { var item = ScrollItemWidget.Setup(template, @@ -55,7 +55,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic height = Math.Max(2, height); var maxTerrainHeight = world.Map.Grid.MaximumTerrainHeight; - var tileset = world.Map.Rules.TileSets[tilesetDropDown.Text]; + var tileset = modData.DefaultTileSets[tilesetDropDown.Text]; var map = new Map(Game.ModData, tileset, width + 2, height + maxTerrainHeight + 2); var tl = new PPos(1, 1); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs index 257e61aa8f..6ca7384cdd 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs @@ -26,7 +26,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic public TileSelectorLogic(Widget widget, WorldRenderer worldRenderer) { var rules = worldRenderer.World.Map.Rules; - var tileset = rules.TileSets[worldRenderer.World.Map.Tileset]; + var tileset = rules.TileSet; editor = widget.Parent.Get("MAP_EDITOR"); panel = widget.Get("TILETEMPLATE_LIST"); diff --git a/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs b/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs index 777f477171..b34764539f 100644 --- a/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs +++ b/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs @@ -48,14 +48,14 @@ namespace OpenRA.Mods.Common.Widgets public TerrainTemplatePreviewWidget(WorldRenderer worldRenderer, World world) { this.worldRenderer = worldRenderer; - tileset = world.Map.Rules.TileSets[world.Map.Tileset]; + tileset = world.Map.Rules.TileSet; } protected TerrainTemplatePreviewWidget(TerrainTemplatePreviewWidget other) : base(other) { worldRenderer = other.worldRenderer; - tileset = other.worldRenderer.World.Map.Rules.TileSets[other.worldRenderer.World.Map.Tileset]; + tileset = other.worldRenderer.World.Map.Rules.TileSet; Template = other.Template; GetScale = other.GetScale; } diff --git a/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs b/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs index d15333cc62..3656ad15fd 100644 --- a/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs +++ b/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs @@ -308,7 +308,7 @@ namespace OpenRA.Mods.D2k.UtilityCommands { mapSize = new Size(stream.ReadUInt16(), stream.ReadUInt16()); - tileSet = rules.TileSets["ARRAKIS"]; + tileSet = Game.ModData.DefaultTileSets["ARRAKIS"]; map = new Map(Game.ModData, tileSet, mapSize.Width + 2 * MapCordonWidth, mapSize.Height + 2 * MapCordonWidth) { diff --git a/OpenRA.Mods.D2k/UtilityCommands/ImportD2kMapCommand.cs b/OpenRA.Mods.D2k/UtilityCommands/ImportD2kMapCommand.cs index e57c34c162..b26530ba71 100644 --- a/OpenRA.Mods.D2k/UtilityCommands/ImportD2kMapCommand.cs +++ b/OpenRA.Mods.D2k/UtilityCommands/ImportD2kMapCommand.cs @@ -30,8 +30,7 @@ namespace OpenRA.Mods.D2k.UtilityCommands // HACK: The engine code assumes that Game.modData is set. Game.ModData = modData; - var rules = modData.RulesetCache.Load(modData.DefaultFileSystem); - + var rules = Ruleset.LoadDefaultsForTileSet(modData, "ARRAKIS"); var map = D2kMapImporter.Import(args[1], modData.Manifest.Mod.Id, args[2], rules); if (map == null) diff --git a/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs b/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs index 16d4477e55..c8f2c1f53b 100644 --- a/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs +++ b/OpenRA.Mods.TS/UtilityCommands/ImportTSMapCommand.cs @@ -228,7 +228,7 @@ namespace OpenRA.Mods.TS.UtilityCommands fullSize = new int2(iniSize[2], iniSize[3]); - var map = new Map(Game.ModData, modData.DefaultRules.TileSets[tileset], size.Width, size.Height); + var map = new Map(Game.ModData, modData.DefaultTileSets[tileset], size.Width, size.Height); map.Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)); map.Author = "Westwood Studios"; map.Bounds = new Rectangle(iniBounds[0], iniBounds[1], iniBounds[2], 2 * iniBounds[3] + 2 * iniBounds[1]); @@ -243,7 +243,7 @@ namespace OpenRA.Mods.TS.UtilityCommands void ReadTiles(Map map, IniFile file) { - var tileset = Game.ModData.DefaultRules.TileSets[map.Tileset]; + var tileset = Game.ModData.DefaultTileSets[map.Tileset]; var mapSection = file.GetSection("IsoMapPack5"); var data = Convert.FromBase64String(mapSection.Aggregate(string.Empty, (a, b) => a + b.Value));