Export CSV layers condensed

I use an obscure language called DM to code my game. The engine has it’s own map format “DMM” which is just a CSV.

I have written a script in DM to convert a Tiled CSV to a DMM and it works, but only for 1 layer. The only thing I’ve come up with to add multiple layers have to loop 10,000 times to add the second layer. That’s obviously not ideal.

So let’s say the Tiled CSV exports like this:
layer1:
0,0,0,0,0
0,1,0,2,1

layer2:
-1,-1,4,3,-1
-1,3,2,-1,-1

I need it to export like this for two layers:
0(2)-1),0(2)-1),0(2)4),0(2)3),0(2)-1)
0(2)-1),0(2)3),0(2)2),0(2)-1),0(2)-1)

Three layers?:
0(2)-1)(3)-1),0(2)-1)(3)-1),0(2)4)(3)-1),0(2)3)(3)-1),0(2)-1)(3)-1)
0(2)-1)(3)-1),0(2)3)(3)-1),0(2)2)(3)-1),0(2)-1)(3)-1),0(2)-1)(3)-1)

It doesn’t have to format like that specifically. Each layer just needs an identifier that I can separate from one another using regex. If I can get Tiled to export a CSV in a format like this my script can convert it to a DMM file.

I’ve done some looking, and maybe I don’t know exactly what to search for, but I can’t seem to find any example of editing the script for the CSV export. I’ve never used Javascript or Python, so this will definitely been a learning experience all around. I’m hoping someone can give me some resources to push me in the right direction.

You can’t edit the existing export, so you will need to use Tiled’s scripting feature to register a new map format (you could call it DMM if you want!). You will, at a minimum, need to write the write() function, which outputs the file, formatted as you like. You don’t have to write the read() function since you probably don’t need to parse these files in Tiled.

Documentation for scripting map formats:

The example is for JSON, but should still be useful. To simplify the output and layer data accesses, I recommend making an array of cells that’s mapWidth x mapHeight in size (in JavaScript, you don’t actually need to specify this, you can just declare var cellData = [] and then access it with the cell index like cellData[y*Math.floor(x/layer.width) + x]), then iterating over cells in the layers, and appending the data for each layer as you go. So, after the first pass, the first cell would be just 0, after the second pass it would be 0(2)-1), and after the third pass it would be 0(2)-1(3)-1).
Then, once you’re done, you’ll need to iterate over this data and output it as CSV (adding , and linebreaks where appropriate). Alternatively, you can make cellData a 2D array to begin with (remember to declare each new row in that case, cellData[row] = [], before you try to add data to it), and then you only need to do cellData[row].join(',') on each row and put linebreaks between them.

So, your whole thing, based on the JSON example from the documentation, should look like this (I used the 2D array approach):

var customMapFormat = {
	name: "DMM",
	extension: "dmm",

	write: function(map, fileName) {
		var cellData = []; //Holds the tile data
		var curLayer = 0; //Keeps track of how many tile layers we've looked at. Not every layer is a tile layer, so just the index is not enough!

		for (var i = 0; i < map.layerCount; ++i) {
			var layer = map.layerAt(i);
			if (layer.isTileLayer) {
				for (y = 0; y < layer.height; ++y) {
					if(curLayer == 0) cellData[y] = []; //Create the row arrays while on the first loop
					for (x = 0; x < layer.width; ++x) {
						tileID = layer.cellAt(x, y).tileId;
						tileID = tileID & ~(0x80000000 | 0x40000000 | 0x20000000); //Clear the flip flags, since the CSV format does not include these.
						tileID = tileID - 1; //CSV tiles are 0-indexed, but Tiled cells are 1-indexed. Empty cells become -1. (It's actually more complicated than this, but the CSV format is very limited)
						if(curLayer == 0) { //on the first layer, populate the initial data:
							cellData[y][x] = ""+tileID; //convert it to a string
						} else { //after the first layer, append to the existing string:
							cellData[y][x] += "("+curLayer+")"+tileID+")";
						}
					}
				}
				curLayer++; //Prepare for the next tile layer
			}
		}
		
		var output = "";
		//Iterate over cellData and add it all to the output string:
		for(curLayer = 0; curLayer < cellData.length; curLayer++) {
			output += cellData[curLayer].join(',') + "\n"; //convert the array to CSV (no spaces) and add a newline at the end of the row
		}

		//and finally, write the file:
		var file = new TextFile(fileName, TextFile.WriteOnly);
		file.write(output);
		file.commit();
	},
}

tiled.registerMapFormat("DMM", customMapFormat);

There are some comments in there to explain what’s going on.

1 Like