Merge pull request #7707 from pchote/tileset-fixes

Automated correctness fixes for tileset definitions.
This commit is contained in:
Taryn Hill
2015-03-24 09:03:34 -05:00
14 changed files with 5322 additions and 4211 deletions

View File

@@ -44,8 +44,10 @@ namespace OpenRA.Graphics
{
var mapX = x + b.Left;
var mapY = y + b.Top;
var type = tileset[tileset.GetTerrainIndex(mapTiles[new MPos(mapX, mapY)])];
colors[y * stride + x] = type.Color.ToArgb();
var type = tileset.GetTileInfo(mapTiles[new MPos(mapX, mapY)]);
var color = type != null ? type.LeftColor : Color.Black;
colors[y * stride + x] = color.ToArgb();
}
}
}

View File

@@ -12,6 +12,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using OpenRA.Primitives;
namespace OpenRA
{
@@ -24,11 +25,29 @@ namespace OpenRA
public readonly Color LeftColor;
public readonly Color RightColor;
public MiniYaml Save() { return FieldSaver.Save(this); }
public MiniYaml Save(TileSet tileSet)
{
var root = new List<MiniYamlNode>();
if (Height != 0)
root.Add(FieldSaver.SaveField(this, "Height"));
if (RampType != 0)
root.Add(FieldSaver.SaveField(this, "RampType"));
if (LeftColor != tileSet.TerrainInfo[TerrainType].Color)
root.Add(FieldSaver.SaveField(this, "LeftColor"));
if (RightColor != tileSet.TerrainInfo[TerrainType].Color)
root.Add(FieldSaver.SaveField(this, "RightColor"));
return new MiniYaml(tileSet.TerrainInfo[TerrainType].Type, root);
}
}
public class TerrainTypeInfo
{
static readonly TerrainTypeInfo Default = new TerrainTypeInfo();
public readonly string Type;
public readonly string[] TargetTypes = { };
public readonly string[] AcceptsSmudgeType = { };
@@ -36,15 +55,17 @@ namespace OpenRA
public readonly Color Color;
public readonly string CustomCursor;
public TerrainTypeInfo() { }
// Private default ctor for serialization comparison
TerrainTypeInfo() { }
public TerrainTypeInfo(MiniYaml my) { FieldLoader.Load(this, my); }
public MiniYaml Save() { return FieldSaver.Save(this); }
public MiniYaml Save() { return FieldSaver.SaveDifferences(this, Default); }
}
public class TerrainTemplateInfo
{
static readonly string[] Fields = { "Id", "Image", "Frames", "Size", "PickAny", "Category" };
static readonly TerrainTemplateInfo Default = new TerrainTemplateInfo(0, null, int2.Zero, null);
public readonly ushort Id;
public readonly string Image;
@@ -129,28 +150,22 @@ namespace OpenRA
public MiniYaml Save(TileSet tileSet)
{
var root = new List<MiniYamlNode>();
foreach (var field in Fields)
{
var f = this.GetType().GetField(field);
if (f.GetValue(this) == null)
continue;
var root = FieldSaver.SaveDifferences(this, Default);
root.Add(new MiniYamlNode(field, FieldSaver.FormatValue(this, f)));
}
var tileYaml = tileInfo
.Select((ti, i) => Pair.New(i.ToString(), ti))
.Where(t => t.Second != null)
.Select(t => new MiniYamlNode(t.First, t.Second.Save(tileSet)))
.ToList();
root.Add(new MiniYamlNode("Tiles", null,
tileInfo.Select((terrainTypeIndex, templateIndex) => new MiniYamlNode(templateIndex.ToString(), terrainTypeIndex.Save())).ToList()));
root.Nodes.Add(new MiniYamlNode("Tiles", null, tileYaml));
return new MiniYaml(null, root);
return root;
}
}
public class TileSet
{
static readonly string[] Fields = { "Name", "Id", "SheetSize", "Palette", "PlayerPalette", "Extensions", "WaterPaletteRotationBase",
"EditorTemplateOrder", "IgnoreTileSpriteOffsets", "MaximumHeight" };
public readonly string Name;
public readonly string Id;
public readonly int SheetSize = 512;
@@ -163,12 +178,17 @@ namespace OpenRA
public readonly string[] EditorTemplateOrder;
public readonly bool IgnoreTileSpriteOffsets;
[FieldLoader.Ignore]
public readonly Dictionary<ushort, TerrainTemplateInfo> Templates = new Dictionary<ushort, TerrainTemplateInfo>();
[FieldLoader.Ignore]
public readonly TerrainTypeInfo[] TerrainInfo;
readonly Dictionary<string, byte> terrainIndexByType = new Dictionary<string, byte>();
readonly byte defaultWalkableTerrainIndex;
// Private default ctor for serialization comparison
TileSet() { }
public TileSet(ModData modData, string filepath)
{
var yaml = MiniYaml.DictFromFile(filepath);
@@ -269,18 +289,7 @@ namespace OpenRA
public void Save(string filepath)
{
var root = new List<MiniYamlNode>();
var gen = new List<MiniYamlNode>();
foreach (var field in Fields)
{
var f = this.GetType().GetField(field);
if (f.GetValue(this) == null)
continue;
gen.Add(new MiniYamlNode(field, FieldSaver.FormatValue(this, f)));
}
root.Add(new MiniYamlNode("General", null, gen));
root.Add(new MiniYamlNode("General", FieldSaver.SaveDifferences(this, new TileSet())));
root.Add(new MiniYamlNode("Terrain", null,
TerrainInfo.Select(t => new MiniYamlNode("TerrainType@{0}".F(t.Type), t.Save())).ToList()));

View File

@@ -617,6 +617,7 @@
<Compile Include="Widgets\VqaPlayerWidget.cs" />
<Compile Include="Traits\Render\WithInfantryBody.cs" />
<Compile Include="UtilityCommands\CheckSequenceSprites.cs" />
<Compile Include="UtilityCommands\FixClassicTilesets.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>

View File

@@ -0,0 +1,104 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using OpenRA.FileSystem;
using OpenRA.Graphics;
using OpenRA.Traits;
using StyleCop;
namespace OpenRA.Mods.Common.UtilityCommands
{
class FixClassicTilesets : IUtilityCommand
{
public string Name { get { return "--fix-classic-tilesets"; } }
[Desc("Fixes missing template tile definitions and adds filename extensions.")]
public void Run(ModData modData, string[] args)
{
// HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData;
GlobalFileSystem.LoadFromManifest(Game.ModData.Manifest);
var imageField = typeof(TerrainTemplateInfo).GetField("Image");
var pickAnyField = typeof(TerrainTemplateInfo).GetField("PickAny");
var tileInfoField = typeof(TerrainTemplateInfo).GetField("tileInfo", BindingFlags.NonPublic | BindingFlags.Instance);
var terrainTypeField = typeof(TerrainTileInfo).GetField("TerrainType");
var terrainLeftColorField = typeof(TerrainTileInfo).GetField("LeftColor");
var terrainRightColorField = typeof(TerrainTileInfo).GetField("RightColor");
var empty = new Size(0, 0);
var single = new int2(1, 1);
foreach (var t in Game.ModData.Manifest.TileSets)
{
var ts = new TileSet(Game.ModData, t);
var exts = new[] { "" }.Concat(ts.Extensions);
var frameCache = new FrameCache(Game.ModData.SpriteLoaders, ts.Extensions);
Console.WriteLine("Tileset: " + ts.Name);
foreach (var template in ts.Templates.Values)
{
// Find the sprite associated with this template
foreach (var ext in exts)
{
Stream s;
if (!GlobalFileSystem.TryOpenWithExts(template.Image, new[] { ext }, out s))
continue;
// Rewrite the template image (normally readonly) using reflection
imageField.SetValue(template, template.Image + ext);
// Fetch the private tileInfo array so that we can write new entries
var tileInfo = (TerrainTileInfo[])tileInfoField.GetValue(template);
// Open the file and search for any implicit frames
var allFrames = frameCache[template.Image];
var frames = template.Frames != null ? template.Frames.Select(f => allFrames[f]).ToArray() : allFrames;
// Resize array for new entries
if (frames.Length > template.TilesCount)
{
var oldLength = template.TilesCount;
var ti = new TerrainTileInfo[frames.Length];
Array.Copy(tileInfo, ti, template.TilesCount);
tileInfoField.SetValue(template, ti);
tileInfo = ti;
}
for (var i = 0; i < template.TilesCount; i++)
{
if (template[i] == null && frames[i] != null && frames[i].Size != empty)
{
tileInfo[i] = new TerrainTileInfo();
var ti = ts.GetTerrainIndex("Clear");
terrainTypeField.SetValue(tileInfo[i], ti);
terrainLeftColorField.SetValue(tileInfo[i], ts[ti].Color);
terrainRightColorField.SetValue(tileInfo[i], ts[ti].Color);
Console.WriteLine("Fixing entry for {0}:{1}", template.Image, i);
}
}
if (template.TilesCount > 1 && template.Size == single)
pickAnyField.SetValue(template, true);
s.Dispose();
}
}
ts.Save(t);
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff