Fix templates for tile objects. See #41

This commit is contained in:
Darren Eberly
2021-07-28 22:37:30 -04:00
parent 0ec7941491
commit 30f52fd7ce
4 changed files with 109 additions and 48 deletions

View File

@@ -11,10 +11,9 @@ See:
import base64 import base64
import gzip import gzip
import importlib.util import importlib.util
import sys
import zlib import zlib
from pathlib import Path from pathlib import Path
from typing import Any, Callable, List, Optional, Union from typing import Any, List, Optional, Union
from typing import cast as type_cast from typing import cast as type_cast
import attr import attr
@@ -284,7 +283,9 @@ def _decode_tile_layer_data(
def _cast_chunk( def _cast_chunk(
raw_chunk: RawChunk, encoding: Optional[str] = None, compression: str = None raw_chunk: RawChunk,
encoding: Optional[str] = None,
compression: Optional[str] = None,
) -> Chunk: ) -> Chunk:
"""Cast the raw_chunk to a Chunk. """Cast the raw_chunk to a Chunk.
@@ -403,7 +404,8 @@ def _cast_tile_layer(raw_layer: RawLayer) -> TileLayer:
def _cast_object_layer( def _cast_object_layer(
raw_layer: RawLayer, parent_dir: Optional[Path] = None raw_layer: RawLayer,
parent_dir: Optional[Path] = None,
) -> ObjectLayer: ) -> ObjectLayer:
"""Cast the raw_layer to an ObjectLayer. """Cast the raw_layer to an ObjectLayer.
@@ -458,46 +460,38 @@ def _cast_group_layer(
layers = [] layers = []
for layer in raw_layer["layers"]: for layer in raw_layer["layers"]:
layers.append(cast(layer, parent_dir)) layers.append(cast(layer, parent_dir=parent_dir))
return LayerGroup(layers=layers, **_get_common_attributes(raw_layer).__dict__) return LayerGroup(layers=layers, **_get_common_attributes(raw_layer).__dict__)
def _get_caster(type_: str) -> Callable[[RawLayer], Layer]: def cast(
"""Get the caster function for the raw layer. raw_layer: RawLayer,
parent_dir: Optional[Path] = None,
Args: ) -> Layer:
type_: the type of the layer
Returns:
Callable[[RawLayer], Layer]: The caster function.
"""
casters = {
"tilelayer": _cast_tile_layer,
"objectgroup": _cast_object_layer,
"imagelayer": _cast_image_layer,
"group": _cast_group_layer,
}
return casters[type_]
def cast(raw_layer: RawLayer, parent_dir: Optional[Path] = None) -> Layer:
"""Cast a raw Tiled layer into a pytiled_parser type. """Cast a raw Tiled layer into a pytiled_parser type.
This function will determine the type of layer and cast accordingly. This function will determine the type of layer and cast accordingly.
Args: Args:
raw_layer: Raw layer to be cast. raw_layer: Raw layer to be cast.
parent_dir: The parent directory that the map file is in.
Returns: Returns:
Layer: a properly typed Layer. Layer: a properly typed Layer.
"""
caster = _get_caster(raw_layer["type"])
if ( Raises:
caster.__name__ == "_cast_object_layer" RuntimeError: For an invalid layer type being provided
or caster.__name__ == "_cast_group_layer" """
): type_ = raw_layer["type"]
return caster(raw_layer, parent_dir)
else: if type_ == "objectgroup":
return caster(raw_layer) return _cast_object_layer(raw_layer, parent_dir)
elif type_ == "group":
return _cast_group_layer(raw_layer, parent_dir)
elif type_ == "imagelayer":
return _cast_image_layer(raw_layer)
elif type_ == "tilelayer":
return _cast_tile_layer(raw_layer)
raise RuntimeError(f"An invalid layer type of {type_} was supplied")

View File

@@ -132,12 +132,16 @@ def parse_map(file: Path) -> TiledMap:
tileset_path = Path(parent_dir / raw_tileset["source"]) tileset_path = Path(parent_dir / raw_tileset["source"])
with open(tileset_path) as raw_tileset_file: with open(tileset_path) as raw_tileset_file:
tilesets[raw_tileset["firstgid"]] = tileset.cast( tilesets[raw_tileset["firstgid"]] = tileset.cast(
json.load(raw_tileset_file), external_path=tileset_path.parent json.load(raw_tileset_file),
raw_tileset["firstgid"],
external_path=tileset_path.parent,
) )
else: else:
# Is an embedded Tileset # Is an embedded Tileset
raw_tileset = typing_cast(RawTileSet, raw_tileset) raw_tileset = typing_cast(RawTileSet, raw_tileset)
tilesets[raw_tileset["firstgid"]] = tileset.cast(raw_tileset) tilesets[raw_tileset["firstgid"]] = tileset.cast(
raw_tileset, raw_tileset["firstgid"]
)
if isinstance(raw_tiled_map["version"], float): if isinstance(raw_tiled_map["version"], float):
version = str(raw_tiled_map["version"]) version = str(raw_tiled_map["version"])
@@ -160,6 +164,37 @@ def parse_map(file: Path) -> TiledMap:
version=version, version=version,
) )
layers = [layer for layer in map_.layers if hasattr(layer, "tiled_objects")]
for my_layer in layers:
for tiled_object in my_layer.tiled_objects: # type: ignore
if hasattr(tiled_object, "new_tileset"):
if tiled_object.new_tileset:
already_loaded = None
for val in map_.tilesets.values():
if val.name == tiled_object.new_tileset["name"]:
already_loaded = val
break
if not already_loaded:
highest_firstgid = max(map_.tilesets.keys())
last_tileset_count = map_.tilesets[highest_firstgid].tile_count
new_firstgid = highest_firstgid + last_tileset_count
map_.tilesets[new_firstgid] = tileset.cast(
tiled_object.new_tileset,
new_firstgid,
tiled_object.new_tileset_path,
)
tiled_object.gid = tiled_object.gid + (new_firstgid - 1)
else:
tiled_object.gid = tiled_object.gid + (
already_loaded.firstgid - 1
)
tiled_object.new_tileset = None
tiled_object.new_tileset_path = None
if raw_tiled_map.get("backgroundcolor") is not None: if raw_tiled_map.get("backgroundcolor") is not None:
map_.background_color = parse_color(raw_tiled_map["backgroundcolor"]) map_.background_color = parse_color(raw_tiled_map["backgroundcolor"])

View File

@@ -1,7 +1,7 @@
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
import json import json
from pathlib import Path from pathlib import Path
from typing import Callable, Dict, List, Optional, Union from typing import Any, Callable, Dict, List, Optional, Union
import attr import attr
from typing_extensions import TypedDict from typing_extensions import TypedDict
@@ -148,6 +148,8 @@ class Tile(TiledObject):
""" """
gid: int gid: int
new_tileset: Optional[Dict[str, Any]] = None
new_tileset_path: Optional[Path] = None
class RawTextDict(TypedDict): class RawTextDict(TypedDict):
@@ -257,7 +259,11 @@ def _cast_point(raw_tiled_object: RawTiledObject) -> Point:
return Point(**_get_common_attributes(raw_tiled_object).__dict__) return Point(**_get_common_attributes(raw_tiled_object).__dict__)
def _cast_tile(raw_tiled_object: RawTiledObject) -> Tile: def _cast_tile(
raw_tiled_object: RawTiledObject,
new_tileset: Optional[Dict[str, Any]] = None,
new_tileset_path: Optional[Path] = None,
) -> Tile:
"""Cast the raw_tiled_object to a Tile object. """Cast the raw_tiled_object to a Tile object.
Args: Args:
@@ -268,7 +274,12 @@ def _cast_tile(raw_tiled_object: RawTiledObject) -> Tile:
""" """
gid = raw_tiled_object["gid"] gid = raw_tiled_object["gid"]
return Tile(gid=gid, **_get_common_attributes(raw_tiled_object).__dict__) return Tile(
gid=gid,
new_tileset=new_tileset,
new_tileset_path=new_tileset_path,
**_get_common_attributes(raw_tiled_object).__dict__
)
def _cast_polygon(raw_tiled_object: RawTiledObject) -> Polygon: def _cast_polygon(raw_tiled_object: RawTiledObject) -> Polygon:
@@ -393,16 +404,24 @@ def _get_caster(
def cast( def cast(
raw_tiled_object: RawTiledObject, parent_dir: Optional[Path] = None raw_tiled_object: RawTiledObject,
parent_dir: Optional[Path] = None,
) -> TiledObject: ) -> TiledObject:
"""Cast the raw tiled object into a pytiled_parser type """Cast the raw tiled object into a pytiled_parser type
Args: Args:
raw_tiled_object: Raw Tiled object that is to be cast. raw_tiled_object: Raw Tiled object that is to be cast.
parent_dir: The parent directory that the map file is in.
Returns: Returns:
TiledObject: a properly typed Tiled object. TiledObject: a properly typed Tiled object.
Raises:
RuntimeError: When a required parameter was not sent based on a condition.
""" """
new_tileset = None
new_tileset_path = None
if raw_tiled_object.get("template"): if raw_tiled_object.get("template"):
if not parent_dir: if not parent_dir:
raise RuntimeError( raise RuntimeError(
@@ -410,12 +429,21 @@ def cast(
) )
template_path = Path(parent_dir / raw_tiled_object["template"]) template_path = Path(parent_dir / raw_tiled_object["template"])
with open(template_path) as raw_template_file: with open(template_path) as raw_template_file:
loaded_template = json.load(raw_template_file)["object"] template = json.load(raw_template_file)
if "tileset" in template:
tileset_path = Path(
template_path.parent / template["tileset"]["source"]
)
with open(tileset_path) as raw_tileset_file:
new_tileset = json.load(raw_tileset_file)
new_tileset_path = tileset_path.parent
loaded_template = template["object"]
for key in loaded_template: for key in loaded_template:
if key != "id": if key != "id":
raw_tiled_object[key] = loaded_template[key] # type: ignore raw_tiled_object[key] = loaded_template[key] # type: ignore
caster = _get_caster(raw_tiled_object) if raw_tiled_object.get("gid"):
return _cast_tile(raw_tiled_object, new_tileset, new_tileset_path)
tiled_object = caster(raw_tiled_object) return _get_caster(raw_tiled_object)(raw_tiled_object)
return tiled_object

View File

@@ -130,6 +130,8 @@ class Tileset:
tile_count: int tile_count: int
columns: int columns: int
firstgid: int
type: str = "tileset" type: str = "tileset"
spacing: int = 0 spacing: int = 0
@@ -144,7 +146,6 @@ class Tileset:
transformations: Optional[Transformations] = None transformations: Optional[Transformations] = None
firstgid: Optional[int] = None
background_color: Optional[Color] = None background_color: Optional[Color] = None
tile_offset: Optional[OrderedPair] = None tile_offset: Optional[OrderedPair] = None
transparent_color: Optional[Color] = None transparent_color: Optional[Color] = None
@@ -329,11 +330,16 @@ def _cast_grid(raw_grid: RawGrid) -> Grid:
) )
def cast(raw_tileset: RawTileSet, external_path: Optional[Path] = None) -> Tileset: def cast(
raw_tileset: RawTileSet,
firstgid: int,
external_path: Optional[Path] = None,
) -> Tileset:
"""Cast the raw tileset into a pytiled_parser type """Cast the raw tileset into a pytiled_parser type
Args: Args:
raw_tileset: Raw Tileset to be cast. raw_tileset: Raw Tileset to be cast.
firstgid: GID corresponding the first tile in the set.
external_path: The path to the tileset if it is not an embedded one. external_path: The path to the tileset if it is not an embedded one.
Returns: Returns:
@@ -348,6 +354,7 @@ def cast(raw_tileset: RawTileSet, external_path: Optional[Path] = None) -> Tiles
columns=raw_tileset["columns"], columns=raw_tileset["columns"],
spacing=raw_tileset["spacing"], spacing=raw_tileset["spacing"],
margin=raw_tileset["margin"], margin=raw_tileset["margin"],
firstgid=firstgid,
) )
if raw_tileset.get("version") is not None: if raw_tileset.get("version") is not None:
@@ -373,9 +380,6 @@ def cast(raw_tileset: RawTileSet, external_path: Optional[Path] = None) -> Tiles
if raw_tileset.get("imageheight") is not None: if raw_tileset.get("imageheight") is not None:
tileset.image_height = raw_tileset["imageheight"] tileset.image_height = raw_tileset["imageheight"]
if raw_tileset.get("firstgid") is not None:
tileset.firstgid = raw_tileset["firstgid"]
if raw_tileset.get("backgroundcolor") is not None: if raw_tileset.get("backgroundcolor") is not None:
tileset.background_color = parse_color(raw_tileset["backgroundcolor"]) tileset.background_color = parse_color(raw_tileset["backgroundcolor"])