Skip to content

Merge development for v1.5.0 #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
May 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Tiled Session file from using a project file
*.tiled-session

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased]

## [1.5.0] - 2021-05-16

This release contains several new features. As of this release pytiled-parser supports 100% of Tiled's feature-set as of Tiled 1.6.

As of version 1.5.0 of pytiled-parser, we are supporting a minimum version of Tiled 1.5. Many features will still work with older versions, but we cannot guarantee functionality with those versions.

### Additions

- Added support for object template files
- Added `World` object to support loading Tiled `.world` files.
- Full support for Wang Sets/Terrains

### Changes

- The `version` attribute of `TiledMap` and `TileSet` is now a string with Tiled major/minor version. For example `"1.6"`. It used to be a float like `1.6`. This is due to Tiled changing that on their side. pytiled-parser will still load in the value regardless if it is a number or string in the JSON, but it will be converted to a string within pytiled-parser if it comes in as a float.

## [1.4.0] - 2021-04-25

- Fixes issues with image loading for external tilesets. Previously, if an external tileset was in a different directory than the map file, image paths for the tileset would be incorrect. This was due to all images being given relative paths to the map file, regardless of if they were for an external tileset. This has been solved by giving absolute paths for images from external tilesets. Relative paths for embedded tilesets is still fine as the tileset is part of the map file.
Expand Down
22 changes: 16 additions & 6 deletions pytiled_parser/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,9 @@ def _cast_tile_layer(raw_layer: RawLayer) -> TileLayer:
return tile_layer


def _cast_object_layer(raw_layer: RawLayer) -> ObjectLayer:
def _cast_object_layer(
raw_layer: RawLayer, parent_dir: Optional[Path] = None
) -> ObjectLayer:
"""Cast the raw_layer to an ObjectLayer.

Args:
Expand All @@ -413,7 +415,7 @@ def _cast_object_layer(raw_layer: RawLayer) -> ObjectLayer:

tiled_objects = []
for tiled_object_ in raw_layer["objects"]:
tiled_objects.append(tiled_object.cast(tiled_object_))
tiled_objects.append(tiled_object.cast(tiled_object_, parent_dir))

return ObjectLayer(
tiled_objects=tiled_objects,
Expand Down Expand Up @@ -441,7 +443,9 @@ def _cast_image_layer(raw_layer: RawLayer) -> ImageLayer:
return image_layer


def _cast_group_layer(raw_layer: RawLayer) -> LayerGroup:
def _cast_group_layer(
raw_layer: RawLayer, parent_dir: Optional[Path] = None
) -> LayerGroup:
"""Cast the raw_layer to a LayerGroup.

Args:
Expand All @@ -454,7 +458,7 @@ def _cast_group_layer(raw_layer: RawLayer) -> LayerGroup:
layers = []

for layer in raw_layer["layers"]:
layers.append(cast(layer))
layers.append(cast(layer, parent_dir))

return LayerGroup(layers=layers, **_get_common_attributes(raw_layer).__dict__)

Expand All @@ -477,7 +481,7 @@ def _get_caster(type_: str) -> Callable[[RawLayer], Layer]:
return casters[type_]


def cast(raw_layer: RawLayer) -> Layer:
def cast(raw_layer: RawLayer, parent_dir: Optional[Path] = None) -> Layer:
"""Cast a raw Tiled layer into a pytiled_parser type.

This function will determine the type of layer and cast accordingly.
Expand All @@ -490,4 +494,10 @@ def cast(raw_layer: RawLayer) -> Layer:
"""
caster = _get_caster(raw_layer["type"])

return caster(raw_layer)
if (
caster.__name__ == "_cast_object_layer"
or caster.__name__ == "_cast_group_layer"
):
return caster(raw_layer, parent_dir)
else:
return caster(raw_layer)
8 changes: 0 additions & 8 deletions pytiled_parser/template.py

This file was deleted.

13 changes: 9 additions & 4 deletions pytiled_parser/tiled_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class TiledMap:
tiled_version: str
tile_size: Size
tilesets: TilesetDict
version: float
version: str

map_file: Optional[Path] = None
background_color: Optional[Color] = None
Expand Down Expand Up @@ -102,7 +102,7 @@ class _RawTiledMap(TypedDict):
tilesets: List[_RawTilesetMapping]
tilewidth: int
type: str
version: float
version: Union[str, float]
width: int


Expand Down Expand Up @@ -139,11 +139,16 @@ def parse_map(file: Path) -> TiledMap:
raw_tileset = typing_cast(RawTileSet, raw_tileset)
tilesets[raw_tileset["firstgid"]] = tileset.cast(raw_tileset)

if isinstance(raw_tiled_map["version"], float):
version = str(raw_tiled_map["version"])
else:
version = raw_tiled_map["version"]

# `map` is a built-in function
map_ = TiledMap(
map_file=file,
infinite=raw_tiled_map["infinite"],
layers=[layer.cast(layer_) for layer_ in raw_tiled_map["layers"]],
layers=[layer.cast(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_object_id=raw_tiled_map["nextobjectid"],
Expand All @@ -152,7 +157,7 @@ def parse_map(file: Path) -> TiledMap:
tiled_version=raw_tiled_map["tiledversion"],
tile_size=Size(raw_tiled_map["tilewidth"], raw_tiled_map["tileheight"]),
tilesets=tilesets,
version=raw_tiled_map["version"],
version=version,
)

if raw_tiled_map.get("backgroundcolor") is not None:
Expand Down
20 changes: 18 additions & 2 deletions pytiled_parser/tiled_object.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# pylint: disable=too-few-public-methods

import json
from pathlib import Path
from typing import Callable, Dict, List, Optional, Union

import attr
Expand Down Expand Up @@ -174,6 +175,7 @@ class RawTiledObject(TypedDict):

id: int
gid: int
template: str
x: float
y: float
width: float
Expand Down Expand Up @@ -390,7 +392,9 @@ def _get_caster(
return _cast_rectangle


def cast(raw_tiled_object: RawTiledObject) -> TiledObject:
def cast(
raw_tiled_object: RawTiledObject, parent_dir: Optional[Path] = None
) -> TiledObject:
"""Cast the raw tiled object into a pytiled_parser type

Args:
Expand All @@ -399,6 +403,18 @@ def cast(raw_tiled_object: RawTiledObject) -> TiledObject:
Returns:
TiledObject: a properly typed Tiled object.
"""
if raw_tiled_object.get("template"):
if not parent_dir:
raise RuntimeError(
"A parent directory must be specified when using object templates"
)
template_path = Path(parent_dir / raw_tiled_object["template"])
with open(template_path) as raw_template_file:
loaded_template = json.load(raw_template_file)["object"]
for key in loaded_template:
if key != "id":
raw_tiled_object[key] = loaded_template[key] # type: ignore

caster = _get_caster(raw_tiled_object)

tiled_object = caster(raw_tiled_object)
Expand Down
Loading