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 mapX = x + b.Left;
var mapY = y + b.Top; var mapY = y + b.Top;
var type = tileset[tileset.GetTerrainIndex(mapTiles[new MPos(mapX, mapY)])]; var type = tileset.GetTileInfo(mapTiles[new MPos(mapX, mapY)]);
colors[y * stride + x] = type.Color.ToArgb(); 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.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using OpenRA.Primitives;
namespace OpenRA namespace OpenRA
{ {
@@ -24,11 +25,29 @@ namespace OpenRA
public readonly Color LeftColor; public readonly Color LeftColor;
public readonly Color RightColor; 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 public class TerrainTypeInfo
{ {
static readonly TerrainTypeInfo Default = new TerrainTypeInfo();
public readonly string Type; public readonly string Type;
public readonly string[] TargetTypes = { }; public readonly string[] TargetTypes = { };
public readonly string[] AcceptsSmudgeType = { }; public readonly string[] AcceptsSmudgeType = { };
@@ -36,15 +55,17 @@ namespace OpenRA
public readonly Color Color; public readonly Color Color;
public readonly string CustomCursor; public readonly string CustomCursor;
public TerrainTypeInfo() { } // Private default ctor for serialization comparison
TerrainTypeInfo() { }
public TerrainTypeInfo(MiniYaml my) { FieldLoader.Load(this, my); } 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 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 ushort Id;
public readonly string Image; public readonly string Image;
@@ -129,28 +150,22 @@ namespace OpenRA
public MiniYaml Save(TileSet tileSet) public MiniYaml Save(TileSet tileSet)
{ {
var root = new List<MiniYamlNode>(); var root = FieldSaver.SaveDifferences(this, Default);
foreach (var field in Fields)
{
var f = this.GetType().GetField(field);
if (f.GetValue(this) == null)
continue;
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, root.Nodes.Add(new MiniYamlNode("Tiles", null, tileYaml));
tileInfo.Select((terrainTypeIndex, templateIndex) => new MiniYamlNode(templateIndex.ToString(), terrainTypeIndex.Save())).ToList()));
return new MiniYaml(null, root); return root;
} }
} }
public class TileSet public class TileSet
{ {
static readonly string[] Fields = { "Name", "Id", "SheetSize", "Palette", "PlayerPalette", "Extensions", "WaterPaletteRotationBase",
"EditorTemplateOrder", "IgnoreTileSpriteOffsets", "MaximumHeight" };
public readonly string Name; public readonly string Name;
public readonly string Id; public readonly string Id;
public readonly int SheetSize = 512; public readonly int SheetSize = 512;
@@ -163,12 +178,17 @@ namespace OpenRA
public readonly string[] EditorTemplateOrder; public readonly string[] EditorTemplateOrder;
public readonly bool IgnoreTileSpriteOffsets; public readonly bool IgnoreTileSpriteOffsets;
[FieldLoader.Ignore]
public readonly Dictionary<ushort, TerrainTemplateInfo> Templates = new Dictionary<ushort, TerrainTemplateInfo>(); public readonly Dictionary<ushort, TerrainTemplateInfo> Templates = new Dictionary<ushort, TerrainTemplateInfo>();
[FieldLoader.Ignore]
public readonly TerrainTypeInfo[] TerrainInfo; public readonly TerrainTypeInfo[] TerrainInfo;
readonly Dictionary<string, byte> terrainIndexByType = new Dictionary<string, byte>(); readonly Dictionary<string, byte> terrainIndexByType = new Dictionary<string, byte>();
readonly byte defaultWalkableTerrainIndex; readonly byte defaultWalkableTerrainIndex;
// Private default ctor for serialization comparison
TileSet() { }
public TileSet(ModData modData, string filepath) public TileSet(ModData modData, string filepath)
{ {
var yaml = MiniYaml.DictFromFile(filepath); var yaml = MiniYaml.DictFromFile(filepath);
@@ -269,18 +289,7 @@ namespace OpenRA
public void Save(string filepath) public void Save(string filepath)
{ {
var root = new List<MiniYamlNode>(); var root = new List<MiniYamlNode>();
var gen = new List<MiniYamlNode>(); root.Add(new MiniYamlNode("General", FieldSaver.SaveDifferences(this, new TileSet())));
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("Terrain", null, root.Add(new MiniYamlNode("Terrain", null,
TerrainInfo.Select(t => new MiniYamlNode("TerrainType@{0}".F(t.Type), t.Save())).ToList())); 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="Widgets\VqaPlayerWidget.cs" />
<Compile Include="Traits\Render\WithInfantryBody.cs" /> <Compile Include="Traits\Render\WithInfantryBody.cs" />
<Compile Include="UtilityCommands\CheckSequenceSprites.cs" /> <Compile Include="UtilityCommands\CheckSequenceSprites.cs" />
<Compile Include="UtilityCommands\FixClassicTilesets.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <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