Skip to content

Instantly share code, notes, and snippets.

@spacechase0
Created May 8, 2017 03:20
Show Gist options
  • Save spacechase0/c2966360e12425cf1702b7ce366f54db to your computer and use it in GitHub Desktop.
Save spacechase0/c2966360e12425cf1702b7ce366f54db to your computer and use it in GitHub Desktop.
Stardew Valley: Load a Tiled map file directly
// You will need "TiledNet" from NuGet. (Also found here: https://github.com/napen123/Tiled.Net)
using Tiled;
private class TileMapping
{
public TileSheet tileSheet = null;
public int tileId = 0;
public TileMapping() { }
public TileMapping( TileSheet ts, int id )
{
tileSheet = ts;
tileId = id;
}
}
public static Map loadMap(string mapName)
{
var tmap = new TiledMap(Path.Combine(Mod.instance.Helper.DirectoryPath, "locations/" + mapName + "/map.tmx"));
var xmap = new Map(mapName);
addTiledPropertiesToXTile(tmap.Properties, xmap.Properties);
var tileMapping = new Dictionary<int, TileMapping>();
foreach ( var ttileSheet in tmap.Tilesets )
{
// xTile wants things like "Mines/mine", not "Mines/mine.png"
string image = ttileSheet.Image.Source;
if (image.EndsWith(".png"))
image = image.Substring(0, image.Length - 4);
var xtileSheet = new TileSheet(xmap, image, new Size(ttileSheet.Columns, ttileSheet.TileCount / ttileSheet.Columns), new Size(tmap.TileWidth, tmap.TileHeight));
addTiledPropertiesToXTile(ttileSheet.Properties, xtileSheet.Properties);
xtileSheet.Id = ttileSheet.Name;
xtileSheet.Spacing = new Size( ttileSheet.Spacing, ttileSheet.Spacing);
xtileSheet.Margin = new Size(ttileSheet.Margin, ttileSheet.Margin);
for (int i = 0; i < ttileSheet.TileCount; ++i)
{
tileMapping.Add(ttileSheet.FirstGlobalId + i, new TileMapping(xtileSheet, i));
}
foreach (var ttile in ttileSheet.Tiles)
{
addTiledPropertiesToXTile(ttile.Properties, xtileSheet.TileIndexProperties[ttile.Id - ttileSheet.FirstGlobalId]);
}
xmap.AddTileSheet(xtileSheet);
}
var tobjectGroups = new List<TiledObjectGroup>();
foreach (var tlayer_ in tmap.Layers)
{
if (tlayer_ is TiledTileLayer)
{
var tlayer = tlayer_ as TiledTileLayer;
// Note that the tile size needs to be * 4. Otherwise, you will break collisions and many other things.
// Yes, even if you don't use the loaded map. Creating the layer is enough.
// For some reason vanilla has a tilesize of 16 for tilesheets, but 64 for the layers.
// I mean, I knew the game was scaled up, but that's kinda odd.
// Anyways, whenever you create a layer with a different tile size, it changes the tile size
// of EVERY OTHER LAYER IN EXISTANCE to match. And guess what, that breaks things.
// I spent hours figuring this out. I don't care about the underlying cause. I just want to mod.
var xlayer = new Layer(tlayer.Name, xmap, new Size(tmap.Width, tmap.Height), new Size(tmap.TileWidth * 4, tmap.TileHeight * 4));
addTiledPropertiesToXTile(tlayer.Properties, xlayer.Properties);
if (tlayer.Data.Compression != TiledData.CompressionType.NoCompression)
throw new InvalidDataException("Compressed tile data is not supported.");
if (tlayer.Data.Encoding == TiledData.EncodingType.NoEncoding || tlayer.Data.Encoding == TiledData.EncodingType.Xml)
{
for (int i = 0; i < tlayer.Data.Tiles.Count; ++i)
{
var ttile = tlayer.Data.Tiles[i];
int ix = i % tmap.Width;
int iy = i / tmap.Width;
var xtile = new StaticTile(xlayer, tileMapping[ttile.GlobalId].tileSheet, BlendMode.Alpha, tileMapping[ttile.GlobalId].tileId);
xlayer.Tiles[ix, iy] = xtile;
}
}
else if (tlayer.Data.Encoding == TiledData.EncodingType.Csv)
{
string[] ttiles = string.Join("", tlayer.Data.Data).Split(',');
for (int i = 0; i < ttiles.Length; ++i)
{
var ttile = int.Parse(ttiles[i]);
if (!tileMapping.ContainsKey(ttile))
continue;
int ix = i % tmap.Width;
int iy = i / tmap.Width;
var xtile = new StaticTile(xlayer, tileMapping[ttile].tileSheet, BlendMode.Alpha, tileMapping[ttile].tileId);
xlayer.Tiles[ix, iy] = xtile;
}
}
else throw new InvalidDataException("Tile data encoding type " + tlayer.Data.Encoding + " not supported.");
xmap.AddLayer(xlayer);
}
else if (tlayer_ is TiledObjectGroup)
{
tobjectGroups.Add(tlayer_ as TiledObjectGroup);
}
}
foreach ( var tobjectGroup in tobjectGroups )
{
var xlayer = xmap.GetLayer(tobjectGroup.Name);
if (xlayer == null)
continue;
foreach (var tobj in tobjectGroup.Objects)
{
if (tobj.Name != "TileData" || tobj.Width != tmap.TileWidth || tobj.Height != tmap.TileWidth || tobj.Properties.Count == 0)
continue;
int x = (int)tobj.X / tmap.TileWidth;
int y = (int)tobj.Y / tmap.TileWidth;
if (xlayer.Tiles[new Location(x, y)] == null)
{
Log.warn("Tile property for non-existant tile; skipping");
continue;
}
addTiledPropertiesToXTile(tobj.Properties, xlayer.Tiles[new Location(x, y)].Properties);
}
}
return xmap;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment