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); var exts = new[] { "" }.Concat(args[1].Split(',')); foreach (var t in Game.ModData.Manifest.TileSets) { var ts = new TileSet(Game.ModData, t); var frameCache = new FrameCache(Game.ModData.SpriteLoaders); 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.TryOpen(template.Images[0] + ext, out s)) { continue; } // Rewrite the template image (normally readonly) using reflection imageField.SetValue(template, template.Images[0] + 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.Images[0]]; var frames = template.Frames != null?template.Frames.Select(f => allFrames[f]).ToArray() : allFrames; // Resize array for new entries if (frames.Length > 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.Images[0], i); } } if (template.TilesCount > 1 && template.Size == single) { pickAnyField.SetValue(template, true); } s.Dispose(); } } ts.Save(t); } }