Move tileset image validation to TerrainRendererInfo.

This commit is contained in:
Paul Chote
2020-10-14 10:47:12 +01:00
committed by reaperrr
parent 2782620081
commit 6d6efd5fe8
3 changed files with 54 additions and 36 deletions

View File

@@ -9,6 +9,7 @@
*/ */
#endregion #endregion
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using OpenRA.Graphics; using OpenRA.Graphics;
@@ -19,6 +20,39 @@ namespace OpenRA.Mods.Common.Traits
{ {
public class TerrainRendererInfo : TraitInfo, ITiledTerrainRendererInfo public class TerrainRendererInfo : TraitInfo, ITiledTerrainRendererInfo
{ {
bool ITiledTerrainRendererInfo.ValidateTileSprites(ITemplatedTerrainInfo terrainInfo, Action<string> onError)
{
var missingImages = new HashSet<string>();
var failed = false;
Action<uint, string> 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); } public override object Create(ActorInitializer init) { return new TerrainRenderer(init.World); }
} }
@@ -27,15 +61,17 @@ namespace OpenRA.Mods.Common.Traits
readonly Map map; readonly Map map;
readonly Dictionary<string, TerrainSpriteLayer> spriteLayers = new Dictionary<string, TerrainSpriteLayer>(); readonly Dictionary<string, TerrainSpriteLayer> spriteLayers = new Dictionary<string, TerrainSpriteLayer>();
readonly TileSet terrainInfo; readonly TileSet terrainInfo;
readonly Theater theater; readonly Theater tileCache;
bool disposed; bool disposed;
public TerrainRenderer(World world) public TerrainRenderer(World world)
{ {
map = world.Map; 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; tileCache = new Theater(terrainInfo);
theater = new Theater(terrainInfo);
} }
void IWorldLoaded.WorldLoaded(World world, WorldRenderer wr) void IWorldLoaded.WorldLoaded(World world, WorldRenderer wr)
@@ -44,7 +80,7 @@ namespace OpenRA.Mods.Common.Traits
{ {
var palette = template.Value.Palette ?? TileSet.TerrainPaletteInternalName; var palette = template.Value.Palette ?? TileSet.TerrainPaletteInternalName;
spriteLayers.GetOrAdd(palette, pal => 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) foreach (var cell in map.AllCells)
@@ -62,7 +98,7 @@ namespace OpenRA.Mods.Common.Traits
palette = template.Palette ?? palette; palette = template.Palette ?? palette;
foreach (var kv in spriteLayers) 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) void IRenderTerrain.RenderTerrain(WorldRenderer wr, Viewport viewport)
@@ -85,15 +121,15 @@ namespace OpenRA.Mods.Common.Traits
foreach (var kv in spriteLayers.Values) foreach (var kv in spriteLayers.Values)
kv.Dispose(); kv.Dispose();
theater.Dispose(); tileCache.Dispose();
disposed = true; disposed = true;
} }
Sheet ITiledTerrainRenderer.Sheet { get { return theater.Sheet; } } Sheet ITiledTerrainRenderer.Sheet { get { return tileCache.Sheet; } }
Sprite ITiledTerrainRenderer.TileSprite(TerrainTile r, int? variant) Sprite ITiledTerrainRenderer.TileSprite(TerrainTile r, int? variant)
{ {
return theater.TileSprite(r, variant); return tileCache.TileSprite(r, variant);
} }
Rectangle ITiledTerrainRenderer.TemplateBounds(TerrainTemplateInfo template) Rectangle ITiledTerrainRenderer.TemplateBounds(TerrainTemplateInfo template)
@@ -110,7 +146,7 @@ namespace OpenRA.Mods.Common.Traits
if (!terrainInfo.TryGetTileInfo(tile, out var tileInfo)) if (!terrainInfo.TryGetTileInfo(tile, out var tileInfo))
continue; continue;
var sprite = theater.TileSprite(tile); var sprite = tileCache.TileSprite(tile);
var u = map.Grid.Type == MapGridType.Rectangular ? x : (x - y) / 2f; var u = map.Grid.Type == MapGridType.Rectangular ? x : (x - y) / 2f;
var v = map.Grid.Type == MapGridType.Rectangular ? y : (x + y) / 2f; var v = map.Grid.Type == MapGridType.Rectangular ? y : (x + y) / 2f;

View File

@@ -645,7 +645,10 @@ namespace OpenRA.Mods.Common.Traits
} }
[RequireExplicitImplementation] [RequireExplicitImplementation]
public interface ITiledTerrainRendererInfo : ITraitInfoInterface { } public interface ITiledTerrainRendererInfo : ITraitInfoInterface
{
bool ValidateTileSprites(ITemplatedTerrainInfo terrainInfo, Action<string> onError);
}
[RequireExplicitImplementation] [RequireExplicitImplementation]
public interface ITiledTerrainRenderer public interface ITiledTerrainRenderer

View File

@@ -13,6 +13,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics; using OpenRA.Mods.Common.Graphics;
using OpenRA.Mods.Common.Traits;
namespace OpenRA.Mods.Common.UtilityCommands namespace OpenRA.Mods.Common.UtilityCommands
{ {
@@ -45,33 +46,11 @@ namespace OpenRA.Mods.Common.UtilityCommands
try try
{ {
Console.WriteLine("Tileset: " + kv.Key); Console.WriteLine("Tileset: " + kv.Key);
var tileset = modData.DefaultTileSets[kv.Key]; var terrainInfo = modData.DefaultTileSets[kv.Key];
var missingImages = new HashSet<string>();
Action<uint, string> onMissingImage = (id, f) =>
{
Console.WriteLine("\tTemplate `{0}` references sprite `{1}` that does not exist.", id, f);
missingImages.Add(f);
failed = true;
};
var theater = new Theater(tileset, onMissingImage); if (terrainInfo is ITemplatedTerrainInfo templatedTerrainInfo)
foreach (var t in tileset.Templates) foreach (var r in modData.DefaultRules.Actors["world"].TraitInfos<ITiledTerrainRendererInfo>())
{ failed |= r.ValidateTileSprites(templatedTerrainInfo, Console.WriteLine);
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;
}
}
}
}
foreach (var image in kv.Value.Images) foreach (var image in kv.Value.Images)
{ {