mirror of
https://github.com/OMGeeky/pytiled_parser.git
synced 2025-12-29 07:40:11 +01:00
I'm back!
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
[style]
|
||||
based_on_style = google
|
||||
column_limit = 78
|
||||
@@ -1,4 +1,5 @@
|
||||
-e .
|
||||
black
|
||||
pytest
|
||||
sphinx
|
||||
coverage
|
||||
|
||||
21
mypy.ini
Normal file
21
mypy.ini
Normal file
@@ -0,0 +1,21 @@
|
||||
# Global options:
|
||||
|
||||
[mypy]
|
||||
python_version = 3.6
|
||||
warn_unused_configs = False
|
||||
disallow_any_unimported = True
|
||||
disallow_any_expr = True
|
||||
disallow_any_decorated = True
|
||||
disallow_any_explicit = True
|
||||
disallow_any_generics = True
|
||||
disallow_subclassing_any = True
|
||||
disallow_untyped_calls = True
|
||||
disallow_untyped_defs = True
|
||||
disallow_incomplete_defs = True
|
||||
check_untyped_defs = True
|
||||
disallow_untyped_decorators = True
|
||||
warn_return_any = True
|
||||
|
||||
# Per-module options:
|
||||
[mypy-tests.*]
|
||||
ignore_errors = True
|
||||
@@ -2,16 +2,15 @@
|
||||
pytiled_parser objects for Tiled maps.
|
||||
"""
|
||||
|
||||
import dataclasses
|
||||
|
||||
import functools
|
||||
import re
|
||||
|
||||
import xml.etree.ElementTree as etree
|
||||
from collections import OrderedDict
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, NamedTuple, Optional, Union
|
||||
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
from typing import NamedTuple, Union, Optional, List, Dict
|
||||
import attr
|
||||
|
||||
|
||||
class Color(NamedTuple):
|
||||
@@ -60,7 +59,7 @@ class Template:
|
||||
"""
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s(auto_attribs=True)
|
||||
class Chunk:
|
||||
"""
|
||||
Chunk object for infinite maps.
|
||||
@@ -81,7 +80,7 @@ class Chunk:
|
||||
chunk_data: List[List[int]]
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s(auto_attribs=True)
|
||||
class Image:
|
||||
"""
|
||||
Image object.
|
||||
@@ -100,7 +99,7 @@ class Image:
|
||||
|
||||
source: str
|
||||
size: Optional[Size] = None
|
||||
trans: Optional[Color] = None
|
||||
trans: Optional[str] = None
|
||||
|
||||
|
||||
Properties = Dict[str, Union[int, float, Color, Path, str]]
|
||||
@@ -151,7 +150,7 @@ class Frame(NamedTuple):
|
||||
duration: int
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s(auto_attribs=True)
|
||||
class TileTerrain:
|
||||
"""
|
||||
Defines each corner of a tile by Terrain index in
|
||||
@@ -172,7 +171,7 @@ class TileTerrain:
|
||||
bottom_right: Optional[int] = None
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class Layer:
|
||||
"""Class that all layers inherret from.
|
||||
|
||||
@@ -212,7 +211,7 @@ Either a 2 dimensional array of integers representing the global tile IDs
|
||||
"""
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class TileLayer(Layer):
|
||||
"""Tile map layer containing tiles.
|
||||
|
||||
@@ -230,27 +229,8 @@ class TileLayer(Layer):
|
||||
data: LayerData
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class _TiledObjectBase:
|
||||
id: int
|
||||
location: OrderedPair
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class _TiledObjectDefaults:
|
||||
size: Size = Size(0, 0)
|
||||
rotation: int = 0
|
||||
opacity: float = 1
|
||||
|
||||
name: Optional[str] = None
|
||||
type: Optional[str] = None
|
||||
|
||||
properties: Optional[Properties] = None
|
||||
template: Optional[Template] = None
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class TiledObject(_TiledObjectDefaults, _TiledObjectBase):
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class TiledObject:
|
||||
"""
|
||||
TiledObject object.
|
||||
|
||||
@@ -274,8 +254,21 @@ class TiledObject(_TiledObjectDefaults, _TiledObjectBase):
|
||||
FIXME
|
||||
"""
|
||||
|
||||
id: int
|
||||
location: OrderedPair
|
||||
|
||||
@dataclasses.dataclass
|
||||
size: Size = Size(0, 0)
|
||||
rotation: int = 0
|
||||
opacity: float = 1
|
||||
|
||||
name: Optional[str] = None
|
||||
type: Optional[str] = None
|
||||
|
||||
properties: Optional[Properties] = None
|
||||
template: Optional[Template] = None
|
||||
|
||||
|
||||
@attr.s()
|
||||
class RectangleObject(TiledObject):
|
||||
"""
|
||||
Rectangle shape defined by a point, width, and height.
|
||||
@@ -286,7 +279,7 @@ class RectangleObject(TiledObject):
|
||||
"""
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s()
|
||||
class ElipseObject(TiledObject):
|
||||
"""
|
||||
Elipse shape defined by a point, width, and height.
|
||||
@@ -295,7 +288,7 @@ class ElipseObject(TiledObject):
|
||||
"""
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s()
|
||||
class PointObject(TiledObject):
|
||||
"""
|
||||
Point defined by a point (x,y).
|
||||
@@ -304,13 +297,8 @@ class PointObject(TiledObject):
|
||||
"""
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class _TileImageObjectBase(_TiledObjectBase):
|
||||
gid: int
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class TileImageObject(TiledObject, _TileImageObjectBase):
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class TileImageObject(TiledObject):
|
||||
"""
|
||||
Polygon shape defined by a set of connections between points.
|
||||
|
||||
@@ -320,14 +308,11 @@ class TileImageObject(TiledObject, _TileImageObjectBase):
|
||||
:gid (int): Refference to a global tile id.
|
||||
"""
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class _PointsObjectBase(_TiledObjectBase):
|
||||
points: List[OrderedPair]
|
||||
gid: int
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class PolygonObject(TiledObject, _PointsObjectBase):
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class PolygonObject(TiledObject):
|
||||
"""
|
||||
Polygon shape defined by a set of connections between points.
|
||||
|
||||
@@ -337,9 +322,11 @@ class PolygonObject(TiledObject, _PointsObjectBase):
|
||||
:points (List[OrderedPair])
|
||||
"""
|
||||
|
||||
points: List[OrderedPair]
|
||||
|
||||
@dataclasses.dataclass
|
||||
class PolylineObject(TiledObject, _PointsObjectBase):
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class PolylineObject(TiledObject):
|
||||
"""
|
||||
Polyline defined by a set of connections between points.
|
||||
|
||||
@@ -351,29 +338,11 @@ class PolylineObject(TiledObject, _PointsObjectBase):
|
||||
the location of the object.
|
||||
"""
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class _TextObjectBase(_TiledObjectBase):
|
||||
text: str
|
||||
points: List[OrderedPair]
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class _TextObjectDefaults(_TiledObjectDefaults):
|
||||
font_family: str = "sans-serif"
|
||||
font_size: int = 16
|
||||
wrap: bool = False
|
||||
color: str = "#000000"
|
||||
bold: bool = False
|
||||
italic: bool = False
|
||||
underline: bool = False
|
||||
strike_out: bool = False
|
||||
kerning: bool = False
|
||||
horizontal_align: str = "left"
|
||||
vertical_align: str = "top"
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class TextObject(TiledObject, _TextObjectDefaults, _TextObjectBase):
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class TextObject(TiledObject):
|
||||
"""
|
||||
Text object with associated settings.
|
||||
|
||||
@@ -396,8 +365,21 @@ class TextObject(TiledObject, _TextObjectDefaults, _TextObjectBase):
|
||||
:vertical_align (str): Vertical alignment of the text (defalt: "top")
|
||||
"""
|
||||
|
||||
text: str
|
||||
font_family: str = "sans-serif"
|
||||
font_size: int = 16
|
||||
wrap: bool = False
|
||||
color: str = "#000000"
|
||||
bold: bool = False
|
||||
italic: bool = False
|
||||
underline: bool = False
|
||||
strike_out: bool = False
|
||||
kerning: bool = False
|
||||
horizontal_align: str = "left"
|
||||
vertical_align: str = "top"
|
||||
|
||||
@dataclasses.dataclass
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class ObjectLayer(Layer):
|
||||
"""
|
||||
TiledObject Group Object.
|
||||
@@ -426,7 +408,7 @@ class ObjectLayer(Layer):
|
||||
draw_order: Optional[str] = "topdown"
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class LayerGroup(Layer):
|
||||
"""
|
||||
Layer Group.
|
||||
@@ -445,13 +427,13 @@ class LayerGroup(Layer):
|
||||
layers: Optional[List[Union["LayerGroup", Layer, ObjectLayer]]]
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s(auto_attribs=True)
|
||||
class Hitbox:
|
||||
"""Group of hitboxes for
|
||||
"""Group of hitboxes for FIXME
|
||||
"""
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s(auto_attribs=True)
|
||||
class Tile:
|
||||
"""
|
||||
Individual tile object.
|
||||
@@ -466,14 +448,15 @@ class Tile:
|
||||
"""
|
||||
|
||||
id: int
|
||||
type: Optional[str]
|
||||
terrain: Optional[TileTerrain]
|
||||
animation: Optional[List[Frame]]
|
||||
image: Optional[Image]
|
||||
hitboxes: Optional[List[TiledObject]]
|
||||
|
||||
type: Optional[str] = None
|
||||
terrain: Optional[TileTerrain] = None
|
||||
animation: Optional[List[Frame]] = None
|
||||
image: Optional[Image] = None
|
||||
hitboxes: Optional[List[TiledObject]] = None
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s(auto_attribs=True)
|
||||
class TileSet:
|
||||
"""
|
||||
Object for storing a TSX with all associated collision data.
|
||||
@@ -506,22 +489,23 @@ class TileSet:
|
||||
|
||||
name: str
|
||||
max_tile_size: Size
|
||||
spacing: Optional[int]
|
||||
margin: Optional[int]
|
||||
tile_count: Optional[int]
|
||||
columns: Optional[int]
|
||||
tile_offset: Optional[OrderedPair]
|
||||
grid: Optional[Grid]
|
||||
properties: Optional[Properties]
|
||||
image: Optional[Image]
|
||||
terrain_types: Optional[List[Terrain]]
|
||||
tiles: Optional[Dict[int, Tile]]
|
||||
|
||||
spacing: Optional[int] = None
|
||||
margin: Optional[int] = None
|
||||
tile_count: Optional[int] = None
|
||||
columns: Optional[int] = None
|
||||
tile_offset: Optional[OrderedPair] = None
|
||||
grid: Optional[Grid] = None
|
||||
properties: Optional[Properties] = None
|
||||
image: Optional[Image] = None
|
||||
terrain_types: Optional[List[Terrain]] = None
|
||||
tiles: Optional[Dict[int, Tile]] = None
|
||||
|
||||
|
||||
TileSetDict = Dict[int, TileSet]
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
@attr.s(auto_attribs=True)
|
||||
class TileMap:
|
||||
"""
|
||||
Object for storing a TMX with all associated layers and properties.
|
||||
@@ -569,7 +553,7 @@ class TileMap:
|
||||
map_size: Size
|
||||
tile_size: Size
|
||||
infinite: bool
|
||||
next_layer_id: int
|
||||
next_layer_id: Optional[int]
|
||||
next_object_id: int
|
||||
|
||||
tile_sets: TileSetDict
|
||||
@@ -581,22 +565,3 @@ class TileMap:
|
||||
background_color: Optional[str] = None
|
||||
|
||||
properties: Optional[Properties] = None
|
||||
|
||||
|
||||
"""
|
||||
[22:16] <__m4ch1n3__> i would "[i for i in int_list if i < littler_then_value]"
|
||||
[22:16] <__m4ch1n3__> it returns a list of integers below "littler_then_value"
|
||||
[22:17] <__m4ch1n3__> !py3 [i for i in [1,2,3,4,1,2,3,4] if i < 3]
|
||||
[22:17] <codebot> __m4ch1n3__: [1, 2, 1, 2]
|
||||
[22:17] <__m4ch1n3__> !py3 [i for i in [1,2,3,4,1,2,3,4] if i < 4]
|
||||
[22:17] <codebot> __m4ch1n3__: [1, 2, 3, 1, 2, 3]
|
||||
[22:22] <__m4ch1n3__> !py3 max([i for i in [1,2,3,4,1,2,3,4] if i < 4])
|
||||
[22:22] <codebot> __m4ch1n3__: 3
|
||||
[22:22] <__m4ch1n3__> max(...) would return the maximum of resulting list
|
||||
[22:23] <__m4ch1n3__> !py3 max([i for i in [1, 10, 100] if i < 20])
|
||||
[22:23] <codebot> __m4ch1n3__: 10
|
||||
[22:23] <__m4ch1n3__> !py3 max([i for i in [1, 10, 100] if i < 242])
|
||||
[22:23] <codebot> __m4ch1n3__: 100
|
||||
[22:23] == markb1 [~mbiggers@45.36.35.206] has quit [Ping timeout: 245 seconds]
|
||||
[22:23] <__m4ch1n3__> !py3 max(i for i in [1, 10, 100] if i < 242)
|
||||
"""
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import functools
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import pytiled_parser.objects as objects
|
||||
|
||||
|
||||
@@ -27,8 +30,24 @@ def parse_color(color: str) -> objects.Color:
|
||||
return objects.Color(red, green, blue, alpha)
|
||||
|
||||
|
||||
def get_tile_by_gid(tile_sets: objects.TileSetDict, gid: int) -> objects.Tile:
|
||||
"""Gets Tile from a global tile ID.
|
||||
def _get_tile_set_key(gid: int, tile_set_keys: List[int]) -> int:
|
||||
"""Gets tile set key given a tile GID.
|
||||
|
||||
Args:
|
||||
gid: Global ID of the tile.
|
||||
|
||||
Returns:
|
||||
int: The key of the tile set that contains the tile for the GID.
|
||||
"""
|
||||
|
||||
# credit to __m4ch1n3__ on ##learnpython for this idea
|
||||
return max([key for key in tile_set_keys if key <= gid])
|
||||
|
||||
|
||||
def get_tile_by_gid(
|
||||
gid: int, tile_sets: objects.TileSetDict
|
||||
) -> Optional[objects.Tile]:
|
||||
"""Gets correct Tile for a given global ID.
|
||||
|
||||
Args:
|
||||
tile_sets (objects.TileSetDict): TileSetDict from TileMap.
|
||||
@@ -36,10 +55,13 @@ def get_tile_by_gid(tile_sets: objects.TileSetDict, gid: int) -> objects.Tile:
|
||||
|
||||
Returns:
|
||||
objects.Tile: The Tile object reffered to by the global tile ID.
|
||||
None: If there is no objects.Tile object in the tile_set.tiles dict
|
||||
for the associated gid.
|
||||
"""
|
||||
for tileset_key, tileset in tile_sets.items():
|
||||
for tile_key, tile in tileset.tiles.items():
|
||||
tile_gid = tile.id + tileset_key
|
||||
if tile_gid == gid:
|
||||
return tile
|
||||
tile_set_key = _get_tile_set_key(gid, list(tile_sets.keys()))
|
||||
tile_set = tile_sets[tile_set_key]
|
||||
|
||||
if tile_set.tiles is not None:
|
||||
return tile_set.tiles.get(gid - tile_set_key)
|
||||
|
||||
return None
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import functools
|
||||
import base64
|
||||
import functools
|
||||
import gzip
|
||||
import re
|
||||
import zlib
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from typing import Callable, Dict, List, Optional, Tuple, Union
|
||||
import xml.etree.ElementTree as etree
|
||||
import zlib
|
||||
from pathlib import Path
|
||||
from typing import Callable, Dict, List, Optional, Tuple, Union
|
||||
|
||||
import pytiled_parser.objects as objects
|
||||
import pytiled_parser.utilities as utilities
|
||||
@@ -73,7 +71,7 @@ def _decode_data(
|
||||
element: etree.Element,
|
||||
layer_width: int,
|
||||
encoding: str,
|
||||
compression: Optional[str],
|
||||
compression: Optional[str] = None,
|
||||
) -> List[List[int]]:
|
||||
"""Decodes data or chunk data.
|
||||
|
||||
@@ -105,12 +103,10 @@ def _decode_data(
|
||||
if encoding == "csv":
|
||||
return _decode_csv_data(data_text)
|
||||
|
||||
return _decode_base64_data(data_text, compression, layer_width)
|
||||
return _decode_base64_data(data_text, layer_width, compression)
|
||||
|
||||
|
||||
def _parse_data(
|
||||
element: etree.Element, layer_width: int
|
||||
) -> objects.LayerData:
|
||||
def _parse_data(element: etree.Element, layer_width: int) -> objects.LayerData:
|
||||
"""Parses layer data.
|
||||
|
||||
Will parse CSV, base64, gzip-base64, or zlip-base64 encoded data.
|
||||
@@ -226,7 +222,13 @@ def _parse_tile_layer(element: etree.Element,) -> objects.TileLayer:
|
||||
raise ValueError(f"{element} has no child data element.")
|
||||
|
||||
return objects.TileLayer(
|
||||
id, name, offset, opacity, properties, size, data
|
||||
id=id,
|
||||
name=name,
|
||||
offset=offset,
|
||||
opacity=opacity,
|
||||
properties=properties,
|
||||
size=size,
|
||||
data=data,
|
||||
)
|
||||
|
||||
|
||||
@@ -249,7 +251,7 @@ def _parse_objects(
|
||||
location_y = float(object_element.attrib["y"])
|
||||
location = objects.OrderedPair(location_x, location_y)
|
||||
|
||||
tiled_object = objects.TiledObject(id, location)
|
||||
tiled_object = objects.TiledObject(id=id, location=location)
|
||||
|
||||
try:
|
||||
width = float(object_element.attrib["width"])
|
||||
@@ -323,14 +325,14 @@ def _parse_object_layer(element: etree.Element,) -> objects.ObjectLayer:
|
||||
pass
|
||||
|
||||
return objects.ObjectLayer(
|
||||
id,
|
||||
name,
|
||||
offset,
|
||||
opacity,
|
||||
properties,
|
||||
tiled_objects,
|
||||
color,
|
||||
draw_order,
|
||||
id=id,
|
||||
name=name,
|
||||
offset=offset,
|
||||
opacity=opacity,
|
||||
properties=properties,
|
||||
tiled_objects=tiled_objects,
|
||||
color=color,
|
||||
draw_order=draw_order,
|
||||
)
|
||||
|
||||
|
||||
@@ -352,7 +354,14 @@ def _parse_layer_group(element: etree.Element,) -> objects.LayerGroup:
|
||||
|
||||
layers = _get_layers(element)
|
||||
|
||||
return objects.LayerGroup(id, name, offset, opacity, properties, layers)
|
||||
return objects.LayerGroup(
|
||||
id=id,
|
||||
name=name,
|
||||
offset=offset,
|
||||
opacity=opacity,
|
||||
properties=properties,
|
||||
layers=layers,
|
||||
)
|
||||
|
||||
|
||||
def _get_layer_parser(
|
||||
@@ -648,6 +657,37 @@ def _parse_tile_set(tile_set_element: etree.Element) -> objects.TileSet:
|
||||
)
|
||||
|
||||
|
||||
def _get_tile_sets(
|
||||
map_element: etree.Element, parent_dir: Path
|
||||
) -> objects.TileSetDict:
|
||||
# parse all tilesets
|
||||
tile_sets: objects.TileSetDict = {}
|
||||
tile_set_element_list = map_element.findall("./tileset")
|
||||
for tile_set_element in tile_set_element_list:
|
||||
# tiled docs are ambiguous about the 'firstgid' attribute
|
||||
# current understanding is for the purposes of mapping the layer
|
||||
# data to the tile set data, add the 'firstgid' value to each
|
||||
# tile 'id'; this means that the 'firstgid' is specific to each,
|
||||
# tile set as they pertain to the map, not tile set specific as
|
||||
# the tiled docs can make it seem
|
||||
# 'firstgid' the key for each TileMap
|
||||
first_gid = int(tile_set_element.attrib["firstgid"])
|
||||
try:
|
||||
# check if is an external TSX
|
||||
source = tile_set_element.attrib["source"]
|
||||
except KeyError:
|
||||
# the tile set in embedded
|
||||
name = tile_set_element.attrib["name"]
|
||||
tile_sets[first_gid] = _parse_tile_set(tile_set_element)
|
||||
else:
|
||||
# tile set is external
|
||||
tile_sets[first_gid] = _parse_external_tile_set(
|
||||
parent_dir, tile_set_element
|
||||
)
|
||||
|
||||
return tile_sets
|
||||
|
||||
|
||||
def parse_tile_map(tmx_file: Union[str, Path]) -> objects.TileMap:
|
||||
# setting up XML parsing
|
||||
map_tree = etree.parse(str(tmx_file))
|
||||
@@ -660,9 +700,11 @@ def parse_tile_map(tmx_file: Union[str, Path]) -> objects.TileMap:
|
||||
tiled_version = map_element.attrib["tiledversion"]
|
||||
orientation = map_element.attrib["orientation"]
|
||||
render_order = map_element.attrib["renderorder"]
|
||||
|
||||
map_width = int(map_element.attrib["width"])
|
||||
map_height = int(map_element.attrib["height"])
|
||||
map_size = objects.Size(map_width, map_height)
|
||||
|
||||
tile_width = int(map_element.attrib["tilewidth"])
|
||||
tile_height = int(map_element.attrib["tileheight"])
|
||||
tile_size = objects.Size(tile_width, tile_height)
|
||||
@@ -673,30 +715,7 @@ def parse_tile_map(tmx_file: Union[str, Path]) -> objects.TileMap:
|
||||
next_layer_id = int(map_element.attrib["nextlayerid"])
|
||||
next_object_id = int(map_element.attrib["nextobjectid"])
|
||||
|
||||
# parse all tilesets
|
||||
tile_sets: Dict[int, objects.TileSet] = {}
|
||||
tile_set_element_list = map_element.findall("./tileset")
|
||||
for tile_set_element in tile_set_element_list:
|
||||
# tiled docs are ambiguous about the 'firstgid' attribute
|
||||
# current understanding is for the purposes of mapping the layer
|
||||
# data to the tile set data, add the 'firstgid' value to each
|
||||
# tile 'id'; this means that the 'firstgid' is specific to each,
|
||||
# tile set as they pertain to the map, not tile set specific as
|
||||
# the tiled docs can make it seem
|
||||
# 'firstgid' is saved beside each TileMap
|
||||
firstgid = int(tile_set_element.attrib["firstgid"])
|
||||
try:
|
||||
# check if is an external TSX
|
||||
source = tile_set_element.attrib["source"]
|
||||
except KeyError:
|
||||
# the tile set in embedded
|
||||
name = tile_set_element.attrib["name"]
|
||||
tile_sets[firstgid] = _parse_tile_set(tile_set_element)
|
||||
else:
|
||||
# tile set is external
|
||||
tile_sets[firstgid] = _parse_external_tile_set(
|
||||
parent_dir, tile_set_element
|
||||
)
|
||||
tile_sets = _get_tile_sets(map_element, parent_dir)
|
||||
|
||||
layers = _get_layers(map_element)
|
||||
|
||||
|
||||
7
setup.py
7
setup.py
@@ -1,6 +1,7 @@
|
||||
from os import path
|
||||
import sys
|
||||
from setuptools import setup
|
||||
from os import path
|
||||
|
||||
from setuptools import setup # type: ignore
|
||||
|
||||
BUILD = 0
|
||||
VERSION = "0.0.1"
|
||||
@@ -21,7 +22,7 @@ if __name__ == "__main__":
|
||||
license="MIT",
|
||||
url="https://github.com/Beefy-Swain/pytiled_parser",
|
||||
download_url="https://github.com/Beefy-Swain/pytiled_parser",
|
||||
install_requires=["dataclasses"],
|
||||
install_requires=["attrs"],
|
||||
packages=["pytiled_parser"],
|
||||
classifiers=[
|
||||
"Development Status :: 1 - Planning",
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
{ 'background_color': None,
|
||||
'hex_side_length': None,
|
||||
'infinite': False,
|
||||
'layers': [ TileLayer(id=1, name='Tile Layer 1', offset=None, opacity=None, properties=None, size=Size(width=10, height=10), data=[[1, 2, 3, 4, 5, 6, 7, 8, 30, 30], [9, 10, 11, 12, 13, 14, 15, 16, 30, 30], [17, 18, 19, 20, 21, 22, 23, 24, 30, 30], [25, 26, 27, 28, 29, 30, 31, 32, 30, 30], [33, 34, 35, 36, 37, 38, 39, 40, 30, 30], [41, 42, 43, 44, 45, 46, 47, 48, 30, 30], [30, 30, 30, 30, 30, 30, 30, 30, 30, 30], [30, 30, 30, 30, 30, 30, 30, 30, 30, 30], [30, 30, 30, 30, 30, 30, 30, 30, 30, 30], [30, 30, 30, 30, 30, 30, 30, 30, 30, 30]]),
|
||||
TileLayer(id=2, name='Tile Layer 2', offset=None, opacity=0.5, properties=None, size=Size(width=10, height=10), data=[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 46, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 6, 7, 7, 7, 7, 7, 8, 0], [0, 0, 14, 15, 15, 15, 15, 15, 16, 0], [0, 0, 22, 23, 23, 23, 23, 23, 24, 0]]),
|
||||
LayerGroup(id=3, name='Group 1', offset=None, opacity=None, properties={'bool property': True}, layers=[TileLayer(id=5, name='Tile Layer 4', offset=OrderedPair(x=49.0, y=-50.0), opacity=None, properties=None, size=Size(width=10, height=10), data=[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 31, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), TileLayer(id=4, name='Tile Layer 3', offset=None, opacity=None, properties=None, size=Size(width=10, height=10), data=[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 2, 3, 0, 0, 0, 0, 0, 0, 0], [9, 10, 11, 0, 0, 0, 0, 0, 0, 0], [17, 18, 19, 0, 0, 0, 0, 0, 0, 0]])]),
|
||||
ObjectLayer(id=6, name='Object Layer 1', offset=OrderedPair(x=4.66667, y=-4.33333), opacity=0.9, properties=None, tiled_objects=[TiledObject(id=1, location=OrderedPair(x=200.25, y=210.75), size=Size(width=47.25, height=25.0), rotation=15, opacity=1, name='rectangle 1', type='rectangle type', properties=None, template=None), TiledObject(id=2, location=OrderedPair(x=252.5, y=87.75), size=Size(width=0, height=0), rotation=-21, opacity=1, name='polygon 1', type='polygon type', properties=None, template=None), TiledObject(id=3, location=OrderedPair(x=198.75, y=102.5), size=Size(width=17.75, height=14.25), rotation=0, opacity=1, name='elipse 1', type='elipse type', properties=None, template=None), TiledObject(id=4, location=OrderedPair(x=174.25, y=186.0), size=Size(width=0, height=0), rotation=0, opacity=1, name='point 1', type='point type', properties=None, template=None), TiledObject(id=7, location=OrderedPair(x=11.3958, y=48.5833), size=Size(width=107.625, height=27.25), rotation=0, opacity=1, name='insert text 1', type='insert text type', properties=None, template=None), TiledObject(id=6, location=OrderedPair(x=47.25, y=72.5), size=Size(width=47.0, height=53.0), rotation=31, opacity=1, name='inserted tile 1', type='inserted tile type', properties={'tile property bool': True}, template=None), TiledObject(id=8, location=OrderedPair(x=144.667, y=112.0), size=Size(width=0, height=0), rotation=0, opacity=1, name='polyline 1', type='polyline type', properties=None, template=None), TiledObject(id=9, location=OrderedPair(x=69.8333, y=168.333), size=Size(width=0, height=0), rotation=0, opacity=1, name='polygon 2', type='polygon type', properties=None, template=None)], color=Color(red=0, green=0, blue=0, alpha=255), draw_order='index')],
|
||||
'map_size': Size(width=10, height=10),
|
||||
'next_layer_id': 16,
|
||||
'next_object_id': 10,
|
||||
'orientation': 'orthogonal',
|
||||
'parent_dir': PosixPath('/home/benk/Projects/pytiled_parser/venv/pytiled_parser/tests/test_data'),
|
||||
'properties': None,
|
||||
'render_order': 'right-down',
|
||||
'stagger_axis': None,
|
||||
'stagger_index': None,
|
||||
'tile_sets': { 1: TileSet(name='tile_set_image', max_tile_size=Size(width=32, height=32), spacing=1, margin=1, tile_count=48, columns=8, tile_offset=None, grid=None, properties=None, image=Image(source='images/tmw_desert_spacing.png', size=Size(width=265, height=199), trans=None), terrain_types=None, tiles={})},
|
||||
'tile_size': Size(width=32, height=32),
|
||||
'tiled_version': '1.2.3',
|
||||
'version': '1.2'}
|
||||
22
test/test_attr.py
Normal file
22
test/test_attr.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import attr
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class Foo:
|
||||
x: int
|
||||
y: int
|
||||
|
||||
a: int = 5
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class Bar(Foo):
|
||||
z: int
|
||||
|
||||
|
||||
foo = Foo(x=1, y=2)
|
||||
|
||||
bar = Bar(x=1, y=2, z=3)
|
||||
|
||||
print(foo)
|
||||
print(bar)
|
||||
178
test/test_output.py
Normal file
178
test/test_output.py
Normal file
@@ -0,0 +1,178 @@
|
||||
{
|
||||
"parent_dir": PosixPath(
|
||||
"/home/ben/Projects/pytiled_parser/pytiled_parser-venv/pytiled_parser/tests/test_data"
|
||||
),
|
||||
"version": "1.2",
|
||||
"tiled_version": "1.2.3",
|
||||
"orientation": "orthogonal",
|
||||
"render_order": "right-down",
|
||||
"map_size": Size(width=8, height=6),
|
||||
"tile_size": Size(width=32, height=32),
|
||||
"infinite": False,
|
||||
"next_layer_id": 2,
|
||||
"next_object_id": 1,
|
||||
"tile_sets": {
|
||||
1: TileSet(
|
||||
name="tile_set_image",
|
||||
max_tile_size=Size(width=32, height=32),
|
||||
spacing=1,
|
||||
margin=1,
|
||||
tile_count=48,
|
||||
columns=8,
|
||||
tile_offset=None,
|
||||
grid=None,
|
||||
properties=None,
|
||||
image=Image(
|
||||
source="images/tmw_desert_spacing.png",
|
||||
size=Size(width=265, height=199),
|
||||
trans=None,
|
||||
),
|
||||
terrain_types=None,
|
||||
tiles={
|
||||
9: Tile(
|
||||
id=9,
|
||||
type=None,
|
||||
terrain=None,
|
||||
animation=None,
|
||||
image=None,
|
||||
hitboxes=[
|
||||
TiledObject(
|
||||
id=2,
|
||||
location=OrderedPair(x=1.0, y=1.0),
|
||||
size=Size(width=32.0, height=32.0),
|
||||
rotation=1,
|
||||
opacity=1,
|
||||
name="wall",
|
||||
type="rectangle type",
|
||||
properties=None,
|
||||
template=None,
|
||||
)
|
||||
],
|
||||
),
|
||||
19: Tile(
|
||||
id=19,
|
||||
type=None,
|
||||
terrain=None,
|
||||
animation=None,
|
||||
image=None,
|
||||
hitboxes=[
|
||||
TiledObject(
|
||||
id=1,
|
||||
location=OrderedPair(x=32.0, y=1.0),
|
||||
size=Size(width=0, height=0),
|
||||
rotation=1,
|
||||
opacity=1,
|
||||
name="wall corner",
|
||||
type="polygon type",
|
||||
properties=None,
|
||||
template=None,
|
||||
)
|
||||
],
|
||||
),
|
||||
20: Tile(
|
||||
id=20,
|
||||
type=None,
|
||||
terrain=None,
|
||||
animation=None,
|
||||
image=None,
|
||||
hitboxes=[
|
||||
TiledObject(
|
||||
id=1,
|
||||
location=OrderedPair(x=1.45455, y=1.45455),
|
||||
size=Size(width=0, height=0),
|
||||
rotation=1,
|
||||
opacity=1,
|
||||
name="polyline",
|
||||
type="polyline type",
|
||||
properties=None,
|
||||
template=None,
|
||||
)
|
||||
],
|
||||
),
|
||||
31: Tile(
|
||||
id=31,
|
||||
type=None,
|
||||
terrain=None,
|
||||
animation=None,
|
||||
image=None,
|
||||
hitboxes=[
|
||||
TiledObject(
|
||||
id=1,
|
||||
location=OrderedPair(x=5.09091, y=2.54545),
|
||||
size=Size(width=19.6364, height=19.2727),
|
||||
rotation=1,
|
||||
opacity=1,
|
||||
name="rock 1",
|
||||
type="elipse type",
|
||||
properties=None,
|
||||
template=None,
|
||||
),
|
||||
TiledObject(
|
||||
id=2,
|
||||
location=OrderedPair(x=16.1818, y=22.0),
|
||||
size=Size(width=8.54545, height=8.36364),
|
||||
rotation=-1,
|
||||
opacity=1,
|
||||
name="rock 2",
|
||||
type="elipse type",
|
||||
properties=None,
|
||||
template=None,
|
||||
),
|
||||
],
|
||||
),
|
||||
45: Tile(
|
||||
id=45,
|
||||
type=None,
|
||||
terrain=None,
|
||||
animation=None,
|
||||
image=None,
|
||||
hitboxes=[
|
||||
TiledObject(
|
||||
id=1,
|
||||
location=OrderedPair(x=14.7273, y=26.3636),
|
||||
size=Size(width=0, height=0),
|
||||
rotation=0,
|
||||
opacity=1,
|
||||
name="sign",
|
||||
type="point type",
|
||||
properties=None,
|
||||
template=None,
|
||||
)
|
||||
],
|
||||
),
|
||||
},
|
||||
)
|
||||
},
|
||||
"layers": [
|
||||
TileLayer(
|
||||
id=1,
|
||||
name="Tile Layer 1",
|
||||
offset=None,
|
||||
opacity=None,
|
||||
properties=None,
|
||||
size=Size(width=8, height=6),
|
||||
data=[
|
||||
[1, 2, 3, 4, 5, 6, 7, 8],
|
||||
[9, 10, 11, 12, 13, 14, 15, 16],
|
||||
[17, 18, 19, 20, 21, 22, 23, 24],
|
||||
[25, 26, 27, 28, 29, 30, 31, 32],
|
||||
[33, 34, 35, 36, 37, 38, 39, 40],
|
||||
[41, 42, 43, 44, 45, 46, 47, 48],
|
||||
],
|
||||
)
|
||||
],
|
||||
"hex_side_length": None,
|
||||
"stagger_axis": None,
|
||||
"stagger_index": None,
|
||||
"background_color": None,
|
||||
"properties": {
|
||||
"bool property - false": False,
|
||||
"bool property - true": True,
|
||||
"color property": "#ff49fcff",
|
||||
"file property": PosixPath("../../../../../../../../var/log/syslog"),
|
||||
"float property": 1.23456789,
|
||||
"int property": 13,
|
||||
"string property": "Hello, World!!",
|
||||
},
|
||||
}
|
||||
e
|
||||
@@ -1,17 +1,11 @@
|
||||
import pprint
|
||||
import pickle
|
||||
|
||||
import pprint
|
||||
from io import StringIO
|
||||
|
||||
import pytiled_parser
|
||||
|
||||
|
||||
pp = pprint.PrettyPrinter(indent=4, compact=True, width=100)
|
||||
|
||||
pp = pp.pprint
|
||||
|
||||
MAP_NAME = "/home/benk/Projects/pytiled_parser/venv/pytiled_parser/tests/test_data/test_map_image_tile_set.tmx"
|
||||
MAP_NAME = "/home/ben/Projects/pytiled_parser/pytiled_parser-venv/pytiled_parser/tests/test_data/test_map_simple_hitboxes.tmx"
|
||||
|
||||
map = pytiled_parser.parse_tile_map(MAP_NAME)
|
||||
|
||||
pp(map.__dict__)
|
||||
print(map.__dict__)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import pytest
|
||||
|
||||
pytest.main(["-x", "tests/unit2"])
|
||||
pytest.main(["--tb=native", "-s", "tests"])
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import pytest
|
||||
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
from contextlib import contextmanager
|
||||
from typing import Callable, List, Optional, Tuple
|
||||
|
||||
from pytiled_parser import objects, xml_parser, utilities
|
||||
import pytest
|
||||
from pytiled_parser import objects, utilities, xml_parser
|
||||
|
||||
|
||||
@contextmanager
|
||||
@@ -19,8 +17,7 @@ def _get_root_element(xml: str) -> etree.Element:
|
||||
|
||||
layer_data = [
|
||||
(
|
||||
'<layer id="1" name="Tile Layer 1" width="10" height="10">'
|
||||
"</layer>",
|
||||
'<layer id="1" name="Tile Layer 1" width="10" height="10">' "</layer>",
|
||||
(int(1), "Tile Layer 1", None, None, None),
|
||||
),
|
||||
(
|
||||
@@ -46,7 +43,7 @@ layer_data = [
|
||||
|
||||
@pytest.mark.parametrize("xml,expected", layer_data)
|
||||
def test_parse_layer(xml, expected, monkeypatch):
|
||||
def mockreturn(properties):
|
||||
def mockreturn(*args):
|
||||
return "properties"
|
||||
|
||||
monkeypatch.setattr(xml_parser, "_parse_properties_element", mockreturn)
|
||||
@@ -160,11 +157,53 @@ data_base64 = [
|
||||
@pytest.mark.parametrize(
|
||||
"data_base64,width,compression,expected,raises", data_base64
|
||||
)
|
||||
def test_decode_base64_data(
|
||||
data_base64, width, compression, expected, raises
|
||||
):
|
||||
def test_decode_base64_data(data_base64, width, compression, expected, raises):
|
||||
with raises:
|
||||
assert (
|
||||
xml_parser._decode_base64_data(data_base64, width, compression)
|
||||
== expected
|
||||
)
|
||||
|
||||
|
||||
# FIXME: use hypothesis for this
|
||||
def create_tile_set(qty_of_tiles):
|
||||
tile_set = objects.TileSet(None, None)
|
||||
|
||||
if qty_of_tiles == 0:
|
||||
return tile_set
|
||||
|
||||
tiles = {}
|
||||
|
||||
for tile_id in range(qty_of_tiles):
|
||||
tiles[tile_id] = objects.Tile(tile_id)
|
||||
|
||||
tile_set.tiles = tiles
|
||||
|
||||
return tile_set
|
||||
|
||||
|
||||
tile_by_gid = [
|
||||
(1, {1: create_tile_set(0)}, None),
|
||||
(1, {1: create_tile_set(1)}, objects.Tile(0)),
|
||||
(1, {1: create_tile_set(2)}, objects.Tile(0)),
|
||||
(2, {1: create_tile_set(1)}, None),
|
||||
(10, {1: create_tile_set(10)}, objects.Tile(9)),
|
||||
(1, {1: create_tile_set(1), 2: create_tile_set(1)}, objects.Tile(0)),
|
||||
(2, {1: create_tile_set(1), 2: create_tile_set(1)}, objects.Tile(0)),
|
||||
(3, {1: create_tile_set(1), 2: create_tile_set(1)}, None),
|
||||
(15, {1: create_tile_set(5), 6: create_tile_set(10)}, objects.Tile(9)),
|
||||
(
|
||||
20,
|
||||
{
|
||||
1: create_tile_set(5),
|
||||
6: create_tile_set(10),
|
||||
16: create_tile_set(10),
|
||||
},
|
||||
objects.Tile(4),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("gid,tile_sets,expected", tile_by_gid)
|
||||
def test_get_tile_by_gid(gid, tile_sets, expected):
|
||||
assert utilities.get_tile_by_gid(gid, tile_sets) == expected
|
||||
@@ -1,9 +1,7 @@
|
||||
import os
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
import pytiled_parser
|
||||
|
||||
print(os.path.dirname(os.path.abspath(__file__)))
|
||||
@@ -15,13 +13,11 @@ def test_map_simple():
|
||||
"""
|
||||
TMX with a very simple spritesheet tile set and some properties.
|
||||
"""
|
||||
map = pytiled_parser.parse_tile_map(
|
||||
Path("../test_data/test_map_simple.tmx")
|
||||
)
|
||||
map = pytiled_parser.parse_tile_map(Path("test_data/test_map_simple.tmx"))
|
||||
|
||||
# map
|
||||
# unsure how to get paths to compare propperly
|
||||
assert str(map.parent_dir) == "../test_data"
|
||||
assert str(map.parent_dir) == "test_data"
|
||||
assert map.version == "1.2"
|
||||
assert map.tiled_version == "1.2.3"
|
||||
assert map.orientation == "orthogonal"
|
||||
@@ -41,7 +37,7 @@ def test_map_simple():
|
||||
assert map.properties == {
|
||||
"bool property - false": False,
|
||||
"bool property - true": True,
|
||||
"color property": (0x49, 0xFC, 0xFF, 0xFF),
|
||||
"color property": "#ff49fcff",
|
||||
"file property": Path("/var/log/syslog"),
|
||||
"float property": 1.23456789,
|
||||
"int property": 13,
|
||||
Reference in New Issue
Block a user