diff --git a/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs b/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs index 34ac57b391..78ebe6adfb 100644 --- a/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs +++ b/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using System.Collections.Generic; using System.IO; using OpenRA.Graphics; @@ -19,6 +20,39 @@ namespace OpenRA.Mods.Common.Traits { public class TerrainRendererInfo : TraitInfo, ITiledTerrainRendererInfo { + bool ITiledTerrainRendererInfo.ValidateTileSprites(ITemplatedTerrainInfo terrainInfo, Action onError) + { + var missingImages = new HashSet(); + var failed = false; + Action onMissingImage = (id, f) => + { + onError("\tTemplate `{0}` references sprite `{1}` that does not exist.".F(id, f)); + missingImages.Add(f); + failed = true; + }; + + var tileCache = new Theater((TileSet)terrainInfo, onMissingImage); + foreach (var t in terrainInfo.Templates) + { + for (var v = 0; v < t.Value.Images.Length; v++) + { + if (!missingImages.Contains(t.Value.Images[v])) + { + for (var i = 0; i < t.Value.TilesCount; i++) + { + if (t.Value[i] == null || tileCache.HasTileSprite(new TerrainTile(t.Key, (byte)i), v)) + continue; + + onError("\tTemplate `{0}` references frame {1} that does not exist in sprite `{2}`.".F(t.Key, i, t.Value.Images[v])); + failed = true; + } + } + } + } + + return failed; + } + public override object Create(ActorInitializer init) { return new TerrainRenderer(init.World); } } @@ -27,15 +61,17 @@ namespace OpenRA.Mods.Common.Traits readonly Map map; readonly Dictionary spriteLayers = new Dictionary(); readonly TileSet terrainInfo; - readonly Theater theater; + readonly Theater tileCache; bool disposed; public TerrainRenderer(World world) { map = world.Map; + terrainInfo = map.Rules.TerrainInfo as TileSet; + if (terrainInfo == null) + throw new InvalidDataException("TerrainRenderer can only be used with the default TileSet"); - terrainInfo = map.Rules.TileSet; - theater = new Theater(terrainInfo); + tileCache = new Theater(terrainInfo); } void IWorldLoaded.WorldLoaded(World world, WorldRenderer wr) @@ -44,7 +80,7 @@ namespace OpenRA.Mods.Common.Traits { var palette = template.Value.Palette ?? TileSet.TerrainPaletteInternalName; spriteLayers.GetOrAdd(palette, pal => - new TerrainSpriteLayer(world, wr, theater.Sheet, BlendMode.Alpha, wr.Palette(palette), world.Type != WorldType.Editor)); + new TerrainSpriteLayer(world, wr, tileCache.Sheet, BlendMode.Alpha, wr.Palette(palette), world.Type != WorldType.Editor)); } foreach (var cell in map.AllCells) @@ -62,7 +98,7 @@ namespace OpenRA.Mods.Common.Traits palette = template.Palette ?? palette; foreach (var kv in spriteLayers) - kv.Value.Update(cell, palette == kv.Key ? theater.TileSprite(tile) : null, false); + kv.Value.Update(cell, palette == kv.Key ? tileCache.TileSprite(tile) : null, false); } void IRenderTerrain.RenderTerrain(WorldRenderer wr, Viewport viewport) @@ -85,15 +121,15 @@ namespace OpenRA.Mods.Common.Traits foreach (var kv in spriteLayers.Values) kv.Dispose(); - theater.Dispose(); + tileCache.Dispose(); disposed = true; } - Sheet ITiledTerrainRenderer.Sheet { get { return theater.Sheet; } } + Sheet ITiledTerrainRenderer.Sheet { get { return tileCache.Sheet; } } Sprite ITiledTerrainRenderer.TileSprite(TerrainTile r, int? variant) { - return theater.TileSprite(r, variant); + return tileCache.TileSprite(r, variant); } Rectangle ITiledTerrainRenderer.TemplateBounds(TerrainTemplateInfo template) @@ -110,7 +146,7 @@ namespace OpenRA.Mods.Common.Traits if (!terrainInfo.TryGetTileInfo(tile, out var tileInfo)) continue; - var sprite = theater.TileSprite(tile); + var sprite = tileCache.TileSprite(tile); var u = map.Grid.Type == MapGridType.Rectangular ? x : (x - y) / 2f; var v = map.Grid.Type == MapGridType.Rectangular ? y : (x + y) / 2f; diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 993a9823dd..7301a768ca 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -645,7 +645,10 @@ namespace OpenRA.Mods.Common.Traits } [RequireExplicitImplementation] - public interface ITiledTerrainRendererInfo : ITraitInfoInterface { } + public interface ITiledTerrainRendererInfo : ITraitInfoInterface + { + bool ValidateTileSprites(ITemplatedTerrainInfo terrainInfo, Action onError); + } [RequireExplicitImplementation] public interface ITiledTerrainRenderer diff --git a/OpenRA.Mods.Common/UtilityCommands/CheckMissingSprites.cs b/OpenRA.Mods.Common/UtilityCommands/CheckMissingSprites.cs index 7265c52687..8738d20ab4 100644 --- a/OpenRA.Mods.Common/UtilityCommands/CheckMissingSprites.cs +++ b/OpenRA.Mods.Common/UtilityCommands/CheckMissingSprites.cs @@ -13,6 +13,7 @@ using System; using System.Collections.Generic; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; +using OpenRA.Mods.Common.Traits; namespace OpenRA.Mods.Common.UtilityCommands { @@ -45,33 +46,11 @@ namespace OpenRA.Mods.Common.UtilityCommands try { Console.WriteLine("Tileset: " + kv.Key); - var tileset = modData.DefaultTileSets[kv.Key]; - var missingImages = new HashSet(); - Action onMissingImage = (id, f) => - { - Console.WriteLine("\tTemplate `{0}` references sprite `{1}` that does not exist.", id, f); - missingImages.Add(f); - failed = true; - }; + var terrainInfo = modData.DefaultTileSets[kv.Key]; - var theater = new Theater(tileset, onMissingImage); - foreach (var t in tileset.Templates) - { - for (var v = 0; v < t.Value.Images.Length; v++) - { - if (!missingImages.Contains(t.Value.Images[v])) - { - for (var i = 0; i < t.Value.TilesCount; i++) - { - if (t.Value[i] == null || theater.HasTileSprite(new TerrainTile(t.Key, (byte)i), v)) - continue; - - Console.WriteLine("\tTemplate `{0}` references frame {1} that does not exist in sprite `{2}`.", t.Key, i, t.Value.Images[v]); - failed = true; - } - } - } - } + if (terrainInfo is ITemplatedTerrainInfo templatedTerrainInfo) + foreach (var r in modData.DefaultRules.Actors["world"].TraitInfos()) + failed |= r.ValidateTileSprites(templatedTerrainInfo, Console.WriteLine); foreach (var image in kv.Value.Images) {