Add support for pre-1.0 Tiled JSON formats

While attempting to parse Starbound dungeons in Tiled JSON format, I
encountered a number of parse errors. These errors appear to be due to
pre-1.0 differences in the Tiled JSON map and tileset formats. As far as
I can tell, most Starbound dungeon files were created and/or last edited
with Tiled 0.15.2.

* Map object `properties` were dictionaries rather than lists, with the
  key being the property name and the value always a string.
* Tileset `tiles` were dictionaries rather than lists, with the key
  being the tile id (integer cast as a string) and the value being a
  dictionary containing the remainder of the tile definition.
* Some map and tileset properties did not exist, or were optional.

This patch introduces minimal changes to the code to allow the Starbound
files to be parsed. There may be other legacy quirks, but these are the
only ones I've noticed in these files.
This commit is contained in:
rl-starbound
2023-01-16 09:37:35 -05:00
parent 5635f50146
commit 186ecd90d3
3 changed files with 29 additions and 15 deletions

View File

@@ -27,7 +27,7 @@ def parse(raw_properties: List[RawProperty]) -> Properties:
"""Parse a list of `RawProperty` objects into `Properties`.
Args:
raw_properties: The list of `RawProperty` objects to parse.
raw_properties: The list or dict of `RawProperty` objects to parse. The dict type is supported for parsing legacy Tiled dungeon files.
Returns:
Properties: The parsed `Property` objects.
@@ -36,13 +36,17 @@ def parse(raw_properties: List[RawProperty]) -> Properties:
final: Properties = {}
value: Property
for raw_property in raw_properties:
if raw_property["type"] == "file":
value = Path(cast(str, raw_property["value"]))
elif raw_property["type"] == "color":
value = parse_color(cast(str, raw_property["value"]))
else:
value = raw_property["value"]
final[raw_property["name"]] = value
if isinstance(raw_properties, dict):
for name, value in raw_properties.items():
final[name] = value
else:
for raw_property in raw_properties:
if raw_property["type"] == "file":
value = Path(cast(str, raw_property["value"]))
elif raw_property["type"] == "color":
value = parse_color(cast(str, raw_property["value"]))
else:
value = raw_property["value"]
final[raw_property["name"]] = value
return final

View File

@@ -112,14 +112,14 @@ def parse(file: Path) -> TiledMap:
# `map` is a built-in function
map_ = TiledMap(
map_file=file,
infinite=raw_tiled_map["infinite"],
infinite=raw_tiled_map.get("infinite", False),
layers=[parse_layer(layer_, parent_dir) for layer_ in raw_tiled_map["layers"]],
map_size=Size(raw_tiled_map["width"], raw_tiled_map["height"]),
next_layer_id=raw_tiled_map["nextlayerid"],
next_layer_id=raw_tiled_map.get("nextlayerid"),
next_object_id=raw_tiled_map["nextobjectid"],
orientation=raw_tiled_map["orientation"],
render_order=raw_tiled_map["renderorder"],
tiled_version=raw_tiled_map["tiledversion"],
tiled_version=raw_tiled_map.get("tiledversion", ""),
tile_size=Size(raw_tiled_map["tilewidth"], raw_tiled_map["tileheight"]),
tilesets=tilesets,
version=version,

View File

@@ -249,7 +249,7 @@ def parse(
tile_count=raw_tileset["tilecount"],
tile_width=raw_tileset["tilewidth"],
tile_height=raw_tileset["tileheight"],
columns=raw_tileset["columns"],
columns=raw_tileset.get("columns", 1),
spacing=raw_tileset["spacing"],
margin=raw_tileset["margin"],
firstgid=firstgid,
@@ -304,8 +304,18 @@ def parse(
if raw_tileset.get("tiles") is not None:
tiles = {}
for raw_tile in raw_tileset["tiles"]:
tiles[raw_tile["id"]] = _parse_tile(raw_tile, external_path=external_path)
if isinstance(raw_tileset["tiles"], dict):
for raw_tile_id, raw_tile in raw_tileset["tiles"].items():
assert raw_tile.get("id") is None
raw_tile["id"] = int(raw_tile_id)
tiles[raw_tile["id"]] = _parse_tile(
raw_tile, external_path=external_path
)
else:
for raw_tile in raw_tileset["tiles"]:
tiles[raw_tile["id"]] = _parse_tile(
raw_tile, external_path=external_path
)
tileset.tiles = tiles
if raw_tileset.get("wangsets") is not None: