mirror of
https://github.com/OMGeeky/pytiled_parser.git
synced 2025-12-26 17:02:28 +01:00
Cleanup from re-write merge
This commit is contained in:
@@ -1,569 +0,0 @@
|
||||
"""pytiled_parser objects for Tiled maps.
|
||||
"""
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, NamedTuple, Optional, Union
|
||||
|
||||
import attr
|
||||
|
||||
# See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#data
|
||||
TileLayerGrid = List[List[int]]
|
||||
|
||||
|
||||
class Color(NamedTuple):
|
||||
"""Color object.
|
||||
|
||||
Attributes:
|
||||
red: Red, between 1 and 255.
|
||||
green: Green, between 1 and 255.
|
||||
blue: Blue, between 1 and 255.
|
||||
alpha: Alpha, between 1 and 255.
|
||||
"""
|
||||
|
||||
red: int
|
||||
green: int
|
||||
blue: int
|
||||
alpha: int
|
||||
|
||||
|
||||
class OrderedPair(NamedTuple):
|
||||
"""OrderedPair NamedTuple.
|
||||
|
||||
Attributes:
|
||||
x: X coordinate.
|
||||
y: Y coordinate.
|
||||
"""
|
||||
|
||||
x: Union[int, float]
|
||||
y: Union[int, float]
|
||||
|
||||
|
||||
class Property(NamedTuple):
|
||||
"""Property NamedTuple.
|
||||
|
||||
Attributes:
|
||||
name: Name of property
|
||||
value: Value of property
|
||||
"""
|
||||
|
||||
name: str
|
||||
value: str
|
||||
|
||||
|
||||
class Size(NamedTuple):
|
||||
"""Size NamedTuple.
|
||||
|
||||
Attributes:
|
||||
width: The width of the object.
|
||||
size: The height of the object.
|
||||
"""
|
||||
|
||||
width: Union[int, float]
|
||||
height: Union[int, float]
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True)
|
||||
class Template:
|
||||
"""FIXME TODO"""
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True)
|
||||
class Chunk:
|
||||
"""Chunk object for infinite maps.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#chunk
|
||||
|
||||
Attributes:
|
||||
location: Location of chunk in tiles.
|
||||
width: The width of the chunk in tiles.
|
||||
height: The height of the chunk in tiles.
|
||||
layer_data: The global tile IDs in chunky according to row.
|
||||
"""
|
||||
|
||||
location: OrderedPair
|
||||
width: int
|
||||
height: int
|
||||
chunk_data: TileLayerGrid
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True)
|
||||
class Image:
|
||||
"""Image object.
|
||||
|
||||
pytiled_parser does not support embedded data in image elements at this time,
|
||||
even though the TMX format technically does.
|
||||
|
||||
Attributes:
|
||||
source: The reference to the tileset image file. Note that this is a relative
|
||||
path compared to FIXME
|
||||
trans: Defines a specific color that is treated as transparent.
|
||||
width: The image width in pixels (optional, used for tile index correction when
|
||||
the image changes).
|
||||
height: The image height in pixels (optional).
|
||||
"""
|
||||
|
||||
source: str
|
||||
size: Optional[Size] = None
|
||||
trans: Optional[str] = None
|
||||
width: Optional[int] = None
|
||||
height: Optional[int] = None
|
||||
|
||||
|
||||
Properties = Dict[str, Union[int, float, Color, Path, str]]
|
||||
|
||||
|
||||
class Grid(NamedTuple):
|
||||
"""Contains info for isometric maps.
|
||||
|
||||
This element is only used in case of isometric orientation, and determines how tile
|
||||
overlays for terrain and collision information are rendered.
|
||||
|
||||
Args:
|
||||
orientation: Orientation of the grid for the tiles in this tileset (orthogonal
|
||||
or isometric).
|
||||
width: Width of a grid cell.
|
||||
height: Height of a grid cell.
|
||||
"""
|
||||
|
||||
orientation: str
|
||||
width: int
|
||||
height: int
|
||||
|
||||
|
||||
class Terrain(NamedTuple):
|
||||
"""Terrain object.
|
||||
|
||||
Args:
|
||||
name: The name of the terrain type.
|
||||
tile: The local tile-id of the tile that represents the terrain visually.
|
||||
"""
|
||||
|
||||
name: str
|
||||
tile: int
|
||||
|
||||
|
||||
class Frame(NamedTuple):
|
||||
"""Animation Frame object.
|
||||
|
||||
This is only used as a part of an animation for Tile objects.
|
||||
|
||||
Args:
|
||||
tile_id: The local ID of a tile within the parent tile set object.
|
||||
duration: How long in milliseconds this frame should be displayed before
|
||||
advancing to the next frame.
|
||||
"""
|
||||
|
||||
tile_id: int
|
||||
duration: int
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True)
|
||||
class TileTerrain:
|
||||
"""Defines each corner of a tile by Terrain index in
|
||||
'TileSet.terrain_types'.
|
||||
|
||||
Defaults to 'None'. 'None' means that corner has no terrain.
|
||||
|
||||
Attributes:
|
||||
top_left: Top left terrain type.
|
||||
top_right: Top right terrain type.
|
||||
bottom_left: Bottom left terrain type.
|
||||
bottom_right: Bottom right terrain type.
|
||||
"""
|
||||
|
||||
top_left: Optional[int] = None
|
||||
top_right: Optional[int] = None
|
||||
bottom_left: Optional[int] = None
|
||||
bottom_right: Optional[int] = None
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class Layer:
|
||||
# FIXME:this docstring appears to be innacurate
|
||||
"""Class that all layers inherit from.
|
||||
|
||||
Args:
|
||||
id: Unique ID of the layer. Each layer that added to a map gets a unique id.
|
||||
Even if a layer is deleted, no layer ever gets the same ID.
|
||||
name: The name of the layer object.
|
||||
tiled_objects: List of tiled_objects in the layer.
|
||||
offset: Rendering offset of the layer object in pixels.
|
||||
opacity: Decimal value between 0 and 1 to determine opacity. 1 is completely
|
||||
opaque, 0 is completely transparent.
|
||||
properties: Properties for the layer.
|
||||
color: The color used to display the objects in this group.
|
||||
draworder: Whether the objects are drawn according to the order of the object
|
||||
elements in the object group element ('manual'), or sorted by their
|
||||
y-coordinate ('topdown'). Defaults to 'topdown'.
|
||||
See:
|
||||
https://doc.mapeditor.org/en/stable/manual/objects/#changing-stacking-order
|
||||
for more info.
|
||||
|
||||
"""
|
||||
|
||||
id_: int
|
||||
name: str
|
||||
|
||||
offset: Optional[OrderedPair]
|
||||
opacity: Optional[float]
|
||||
properties: Optional[Properties]
|
||||
|
||||
|
||||
LayerData = Union[TileLayerGrid, List[Chunk]]
|
||||
"""The tile data for one layer.
|
||||
|
||||
Either a 2 dimensional array of integers representing the global tile IDs
|
||||
for a TileLayerGrid, or a list of chunks for an infinite map layer.
|
||||
"""
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class TileLayer(Layer):
|
||||
"""Tile map layer containing tiles.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#layer
|
||||
|
||||
Args:
|
||||
size: The width of the layer in tiles. The same as the map width unless map is
|
||||
infitite.
|
||||
data: Either an 2 dimensional array of integers representing the global tile
|
||||
IDs for the map layer, or a list of chunks for an infinite map.
|
||||
"""
|
||||
|
||||
size: Size
|
||||
layer_data: LayerData
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class TiledObject:
|
||||
"""TiledObject object.
|
||||
|
||||
See:
|
||||
https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#object
|
||||
|
||||
Args:
|
||||
id: Unique ID of the object. Each object that is placed on a map gets a unique
|
||||
id. Even if an object was deleted, no object gets the same ID.
|
||||
gid: Global tiled object ID.
|
||||
location: The location of the object in pixels.
|
||||
size: The width of the object in pixels (default: (0, 0)).
|
||||
rotation: The rotation of the object in degrees clockwise (default: 0).
|
||||
opacity: The opacity of the object. (default: 255)
|
||||
name: The name of the object.
|
||||
type: The type of the object.
|
||||
properties: The properties of the TiledObject.
|
||||
template: A reference to a Template object FIXME
|
||||
"""
|
||||
|
||||
id_: int
|
||||
gid: Optional[int] = None
|
||||
|
||||
location: OrderedPair
|
||||
size: Optional[Size] = None
|
||||
rotation: Optional[float] = None
|
||||
opacity: Optional[float] = None
|
||||
|
||||
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.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/manual/objects/#insert-rectangle
|
||||
(objects in tiled are rectangles by default, so there is no specific
|
||||
documentation on the tmx-map-format page for it.)
|
||||
"""
|
||||
|
||||
|
||||
@attr.s()
|
||||
class ElipseObject(TiledObject):
|
||||
"""Elipse shape defined by a point, width, and height.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#ellipse
|
||||
"""
|
||||
|
||||
|
||||
@attr.s()
|
||||
class PointObject(TiledObject):
|
||||
"""Point defined by a point (x,y).
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#point
|
||||
"""
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class TileImageObject(TiledObject):
|
||||
"""Polygon shape defined by a set of connections between points.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/manual/objects/#insert-tile
|
||||
|
||||
Attributes:
|
||||
gid: Refference to a global tile id.
|
||||
"""
|
||||
|
||||
gid: int
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class PolygonObject(TiledObject):
|
||||
"""Polygon shape defined by a set of connections between points.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#polygon
|
||||
|
||||
Attributes:
|
||||
points: FIXME
|
||||
"""
|
||||
|
||||
points: List[OrderedPair]
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class PolylineObject(TiledObject):
|
||||
"""Polyline defined by a set of connections between points.
|
||||
|
||||
See:
|
||||
https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#polyline
|
||||
|
||||
Attributes:
|
||||
points: List of coordinates relative to the location of the object.
|
||||
"""
|
||||
|
||||
points: List[OrderedPair]
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class TextObject(TiledObject):
|
||||
"""Text object with associated settings.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#text
|
||||
and https://doc.mapeditor.org/en/stable/manual/objects/#insert-text
|
||||
|
||||
Attributes:
|
||||
font_family: The font family used (default: "sans-serif")
|
||||
font_size: The size of the font in pixels. (default: 16)
|
||||
wrap: Whether word wrapping is enabled. (default: False)
|
||||
color: Color of the text. (default: #000000)
|
||||
bold: Whether the font is bold. (default: False)
|
||||
italic: Whether the font is italic. (default: False)
|
||||
underline: Whether the text is underlined. (default: False)
|
||||
strike_out: Whether the text is striked-out. (default: False)
|
||||
kerning: Whether kerning should be used while rendering the text. (default:
|
||||
False)
|
||||
horizontal_align: Horizontal alignment of the text (default: "left")
|
||||
vertical_align: 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"
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class ObjectLayer(Layer):
|
||||
"""
|
||||
TiledObject Group Object.
|
||||
|
||||
The object group is in fact a map layer, and is hence called "object layer" in
|
||||
Tiled.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#objectgroup
|
||||
|
||||
Args:
|
||||
tiled_objects: List of tiled_objects in the layer.
|
||||
offset: Rendering offset of the layer object in pixels.
|
||||
color: The color used to display the objects in this group. FIXME: editor only?
|
||||
draworder: Whether the objects are drawn according to the order of the object
|
||||
elements in the object group element ('manual'), or sorted by their
|
||||
y-coordinate ('topdown'). Defaults to 'topdown'. See:
|
||||
https://doc.mapeditor.org/en/stable/manual/objects/#changing-stacking-order
|
||||
for more info.
|
||||
|
||||
"""
|
||||
|
||||
tiled_objects: List[TiledObject]
|
||||
|
||||
color: Optional[str] = None
|
||||
draw_order: Optional[str] = "topdown"
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class LayerGroup(Layer):
|
||||
"""Layer Group.
|
||||
|
||||
A LayerGroup can be thought of as a layer that contains layers
|
||||
(potentially including other LayerGroups).
|
||||
|
||||
Offset and opacity recursively affect child layers.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#group
|
||||
|
||||
Attributes:
|
||||
Layers: Layers in group.
|
||||
"""
|
||||
|
||||
layers: Optional[List[Union["LayerGroup", Layer, ObjectLayer]]]
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class ImageLayer(Layer):
|
||||
"""Image Layer.
|
||||
|
||||
An image layer displays a single image.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#imagelayer
|
||||
|
||||
Attributes:
|
||||
image: the image to display for this layer.
|
||||
"""
|
||||
|
||||
image: Image
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True)
|
||||
class TileSet:
|
||||
"""Object for storing a TSX with all associated collision data.
|
||||
|
||||
Args:
|
||||
name: The name of this tileset.
|
||||
max_tile_size: The maximum size of a tile in this tile set in pixels.
|
||||
spacing: The spacing in pixels between the tiles in this tileset (applies to
|
||||
the tileset image).
|
||||
margin: The margin around the tiles in this tileset (applies to the tileset
|
||||
image).
|
||||
tile_count: The number of tiles in this tileset.
|
||||
columns: The number of tile columns in the tileset. For image collection
|
||||
tilesets it is editable and is used when displaying the tileset.
|
||||
grid: Only used in case of isometric orientation, and determines how tile
|
||||
overlays for terrain and collision information are rendered.
|
||||
tileoffset: Used to specify an offset in pixels when drawing a tile from the
|
||||
tileset. When not present, no offset is applied.
|
||||
image: Used for spritesheet tile sets.
|
||||
terrain_types: List of of terrain types which can be referenced from the
|
||||
terrain attribute of the tile object. Ordered according to the terrain
|
||||
element's appearance in the TSX file.
|
||||
tiles: Dict of Tile objects by Tile.id.
|
||||
tsx_file: Path of the file containing the tileset, None if loaded internally
|
||||
from a map
|
||||
parent_dir: Path of the parent directory of the file containing the tileset,
|
||||
None if loaded internally from a map
|
||||
"""
|
||||
|
||||
name: str
|
||||
max_tile_size: Size
|
||||
|
||||
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
|
||||
tsx_file: Path = None
|
||||
parent_dir: Path = None
|
||||
|
||||
|
||||
TileSetDict = Dict[int, TileSet]
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True, kw_only=True)
|
||||
class Tile:
|
||||
"""Individual tile object.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#tile
|
||||
|
||||
Args:
|
||||
id: The local tile ID within its tileset.
|
||||
type: The type of the tile. Refers to an object type and is used by tile
|
||||
objects.
|
||||
terrain: Defines the terrain type of each corner of the tile.
|
||||
animation: Each tile can have exactly one animation associated with it.
|
||||
"""
|
||||
|
||||
id_: int
|
||||
type_: Optional[str] = None
|
||||
terrain: Optional[TileTerrain] = None
|
||||
animation: Optional[List[Frame]] = None
|
||||
objectgroup: Optional[List[TiledObject]] = None
|
||||
image: Optional[Image] = None
|
||||
properties: Optional[List[Property]] = None
|
||||
tileset: Optional[TileSet] = None
|
||||
flipped_horizontally: bool = False
|
||||
flipped_diagonally: bool = False
|
||||
flipped_vertically: bool = False
|
||||
|
||||
|
||||
@attr.s(auto_attribs=True)
|
||||
class TileMap:
|
||||
"""Object for storing a TMX with all associated layers and properties.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#map
|
||||
|
||||
Attributes:
|
||||
parent_dir: The directory the TMX file is in. Used for finding relative paths
|
||||
to TSX files and other assets.
|
||||
version: The TMX format version.
|
||||
tiledversion: The Tiled version used to save the file. May be a date (for
|
||||
snapshot builds).
|
||||
orientation: Map orientation. Tiled supports "orthogonal", "isometric",
|
||||
"staggered" and "hexagonal"
|
||||
renderorder: The order in which tiles on tile layers are rendered. Valid values
|
||||
are right-down, right-up, left-down and left-up. In all cases, the map is
|
||||
drawn row-by-row. (only supported for orthogonal maps at the moment)
|
||||
map_size: The map width in tiles.
|
||||
tile_size: The width of a tile.
|
||||
infinite: If the map is infinite or not.
|
||||
hexsidelength: Only for hexagonal maps. Determines the width or height
|
||||
(depending on the staggered axis) of the tile's edge, in pixels.
|
||||
stagger_axis: For staggered and hexagonal maps, determines which axis ("x" or
|
||||
"y") is staggered.
|
||||
staggerindex: For staggered and hexagonal maps, determines whether the "even"
|
||||
or "odd" indexes along the staggered axis are shifted.
|
||||
backgroundcolor: The background color of the map.
|
||||
nextlayerid: Stores the next available ID for new layers.
|
||||
nextobjectid: Stores the next available ID for new objects.
|
||||
tile_sets: Dict of tile sets used in this map. Key is the first GID for the
|
||||
tile set. The value is a TileSet object.
|
||||
layers: List of layer objects by draw order.
|
||||
"""
|
||||
|
||||
parent_dir: Path
|
||||
tmx_file: Union[str, Path]
|
||||
|
||||
version: str
|
||||
tiled_version: str
|
||||
orientation: str
|
||||
render_order: str
|
||||
map_size: Size
|
||||
tile_size: Size
|
||||
infinite: bool
|
||||
next_layer_id: Optional[int]
|
||||
next_object_id: int
|
||||
|
||||
tile_sets: TileSetDict
|
||||
layers: List[Layer]
|
||||
|
||||
hex_side_length: Optional[int] = None
|
||||
stagger_axis: Optional[int] = None
|
||||
stagger_index: Optional[int] = None
|
||||
background_color: Optional[Color] = None
|
||||
|
||||
properties: Optional[Properties] = None
|
||||
@@ -1,6 +0,0 @@
|
||||
def is_float(string: str):
|
||||
try:
|
||||
float(string)
|
||||
return True
|
||||
except (ValueError, TypeError):
|
||||
return False
|
||||
@@ -1,69 +0,0 @@
|
||||
"""Helper unitilies for pytiled_parser."""
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
import pytiled_parser.objects as objects
|
||||
|
||||
|
||||
def parse_color(color: str) -> objects.Color:
|
||||
"""Convert Tiled color format into Arcade's.
|
||||
|
||||
Args:
|
||||
color (str): Tiled formatted color string.
|
||||
|
||||
Returns:
|
||||
:Color: Color object in the format that Arcade understands.
|
||||
"""
|
||||
# the actual part we care about is always an even number
|
||||
if len(color) % 2:
|
||||
# strip initial '#' character
|
||||
color = color[1:]
|
||||
|
||||
if len(color) == 6:
|
||||
# full opacity if no alpha specified
|
||||
alpha = 0xFF
|
||||
red = int(color[0:2], 16)
|
||||
green = int(color[2:4], 16)
|
||||
blue = int(color[4:6], 16)
|
||||
else:
|
||||
alpha = int(color[0:2], 16)
|
||||
red = int(color[2:4], 16)
|
||||
green = int(color[4:6], 16)
|
||||
blue = int(color[6:8], 16)
|
||||
|
||||
return objects.Color(red, green, blue, alpha)
|
||||
|
||||
|
||||
def _get_tile_set_key(gid: int, tile_set_keys: List[int]) -> int:
|
||||
"""Gets tile set key given a tile GID.
|
||||
|
||||
Args:
|
||||
gid (int): Global ID of the tile.
|
||||
tile_set_keys (List[int]): List of tile set keys.
|
||||
|
||||
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.
|
||||
gid (int): Global tile ID of the tile to be returned.
|
||||
|
||||
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.
|
||||
"""
|
||||
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,940 +0,0 @@
|
||||
"""Handle XML parsing for TMX files"""
|
||||
|
||||
import base64
|
||||
import functools
|
||||
import gzip
|
||||
import re
|
||||
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.typing_helpers as TH
|
||||
from pytiled_parser.utilities import parse_color
|
||||
|
||||
|
||||
def _decode_base64_data(
|
||||
data_text: str, layer_width: int, compression: Optional[str] = None
|
||||
) -> objects.TileLayerGrid:
|
||||
"""Decode base64 data.
|
||||
|
||||
Args:
|
||||
data_text: Data to be decoded.
|
||||
layer_width: Width of each layer in tiles.
|
||||
compression: The type of compression for the data.
|
||||
|
||||
Raises:
|
||||
ValueError: If compression type is unsupported.
|
||||
|
||||
Returns:
|
||||
objects.TileLayerGrid: Tile grid.
|
||||
"""
|
||||
tile_grid: objects.TileLayerGrid = [[]]
|
||||
|
||||
unencoded_data = base64.b64decode(data_text)
|
||||
if compression == "zlib":
|
||||
unzipped_data = zlib.decompress(unencoded_data)
|
||||
elif compression == "gzip":
|
||||
unzipped_data = gzip.decompress(unencoded_data)
|
||||
elif compression is None:
|
||||
unzipped_data = unencoded_data
|
||||
else:
|
||||
raise ValueError(f"Unsupported compression type: '{compression}'.")
|
||||
|
||||
# Turn bytes into 4-byte integers
|
||||
byte_count = 0
|
||||
int_count = 0
|
||||
int_value = 0
|
||||
row_count = 0
|
||||
for byte in unzipped_data:
|
||||
int_value += byte << (byte_count * 8)
|
||||
byte_count += 1
|
||||
if not byte_count % 4:
|
||||
byte_count = 0
|
||||
int_count += 1
|
||||
tile_grid[row_count].append(int_value)
|
||||
int_value = 0
|
||||
if not int_count % layer_width:
|
||||
row_count += 1
|
||||
tile_grid.append([])
|
||||
|
||||
tile_grid.pop()
|
||||
return tile_grid
|
||||
|
||||
|
||||
def _decode_csv_data(data_text: str) -> objects.TileLayerGrid:
|
||||
"""Decodes csv encoded layer data.
|
||||
|
||||
Args:
|
||||
data_text: Data to be decoded.
|
||||
|
||||
Returns:
|
||||
objects.TileLayerGrid: Tile grid.
|
||||
"""
|
||||
tile_grid = []
|
||||
lines: List[str] = data_text.split("\n")
|
||||
# remove erroneous empty lists due to a newline being on both ends of text
|
||||
lines = lines[1:-1]
|
||||
for line in lines:
|
||||
line_list = line.split(",")
|
||||
# FIXME: what is this for?
|
||||
while "" in line_list:
|
||||
line_list.remove("")
|
||||
line_list_int = [int(item) for item in line_list]
|
||||
tile_grid.append(line_list_int)
|
||||
|
||||
return tile_grid
|
||||
|
||||
|
||||
# I'm not sure if this is the best way to do this
|
||||
TileLayerDecoder = Union[
|
||||
Callable[[str], objects.TileLayerGrid],
|
||||
Callable[[str, int, Optional[str]], objects.TileLayerGrid],
|
||||
]
|
||||
|
||||
|
||||
def _decode_tile_layer_data(
|
||||
element: etree.Element,
|
||||
layer_width: int,
|
||||
encoding: str,
|
||||
compression: Optional[str] = None,
|
||||
) -> objects.TileLayerGrid:
|
||||
"""Decodes tile layer data or chunk data.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#tmx-data
|
||||
|
||||
Args:
|
||||
element: Element to have text decoded.
|
||||
layer_width: Number of tiles per column in this layer. Used for determining
|
||||
when to cut off a row when decoding base64 encoding layers.
|
||||
encoding: Encoding format of the layer data.
|
||||
compression: Compression format of the layer data.
|
||||
|
||||
Raises:
|
||||
ValueError: Encoding type is not supported.
|
||||
|
||||
Returns:
|
||||
objects.TileLayerGrid: Tile grid.
|
||||
"""
|
||||
|
||||
data_text: str = element.text # type: ignore
|
||||
|
||||
if encoding == "csv":
|
||||
return _decode_csv_data(data_text)
|
||||
if encoding == "base64":
|
||||
return _decode_base64_data(data_text, layer_width, compression)
|
||||
|
||||
raise ValueError(f"{encoding} is not a supported encoding")
|
||||
|
||||
|
||||
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.
|
||||
|
||||
Args:
|
||||
element: Data element to parse.
|
||||
layer_width: Layer width. Used for base64 decoding.
|
||||
|
||||
Returns:
|
||||
LayerData: Data object containing layer data or chunks of data.
|
||||
"""
|
||||
encoding = element.attrib["encoding"]
|
||||
|
||||
compression = None
|
||||
try:
|
||||
compression = element.attrib["compression"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
chunk_elements = element.findall("./chunk")
|
||||
if chunk_elements:
|
||||
chunks: List[objects.Chunk] = []
|
||||
for chunk_element in chunk_elements:
|
||||
x = int(chunk_element.attrib["x"])
|
||||
y = int(chunk_element.attrib["y"])
|
||||
location = objects.OrderedPair(x, y)
|
||||
width = int(chunk_element.attrib["width"])
|
||||
height = int(chunk_element.attrib["height"])
|
||||
layer_data = _decode_tile_layer_data(
|
||||
chunk_element, layer_width, encoding, compression
|
||||
)
|
||||
chunks.append(objects.Chunk(location, width, height, layer_data))
|
||||
return chunks
|
||||
|
||||
return _decode_tile_layer_data(element, layer_width, encoding, compression)
|
||||
|
||||
|
||||
def _parse_layer(
|
||||
layer_element: etree.Element,
|
||||
) -> Tuple[
|
||||
int,
|
||||
str,
|
||||
Optional[objects.OrderedPair],
|
||||
Optional[float],
|
||||
Optional[objects.Properties],
|
||||
]:
|
||||
"""Parses all of the attributes for a Layer object.
|
||||
|
||||
Args:
|
||||
layer_element: The layer element to be parsed.
|
||||
|
||||
Returns:
|
||||
FIXME
|
||||
"""
|
||||
id_ = int(layer_element.attrib["id"])
|
||||
|
||||
name = layer_element.attrib["name"]
|
||||
|
||||
offset: Optional[objects.OrderedPair]
|
||||
offset_x = layer_element.attrib.get("offsetx")
|
||||
offset_y = layer_element.attrib.get("offsety")
|
||||
if offset_x and offset_y:
|
||||
assert TH.is_float(offset_x)
|
||||
assert TH.is_float(offset_y)
|
||||
offset = objects.OrderedPair(float(offset_x), float(offset_y))
|
||||
else:
|
||||
offset = None
|
||||
|
||||
opacity: Optional[float]
|
||||
opacity_attrib = layer_element.attrib.get("opacity")
|
||||
if opacity_attrib:
|
||||
opacity = float(opacity_attrib)
|
||||
else:
|
||||
opacity = None
|
||||
|
||||
properties: Optional[objects.Properties]
|
||||
properties_element = layer_element.find("./properties")
|
||||
if properties_element is not None:
|
||||
properties = _parse_properties_element(properties_element)
|
||||
else:
|
||||
properties = None
|
||||
|
||||
return id_, name, offset, opacity, properties
|
||||
|
||||
|
||||
def _parse_tile_layer(element: etree.Element,) -> objects.TileLayer:
|
||||
"""Parses tile layer element.
|
||||
|
||||
Args:
|
||||
element: The layer element to be parsed.
|
||||
|
||||
Raises:
|
||||
ValueError: Element has no child data element.
|
||||
|
||||
Returns:
|
||||
TileLayer: The tile layer object.
|
||||
"""
|
||||
id_, name, offset, opacity, properties = _parse_layer(element)
|
||||
|
||||
width = int(element.attrib["width"])
|
||||
height = int(element.attrib["height"])
|
||||
size = objects.Size(width, height)
|
||||
|
||||
data_element = element.find("./data")
|
||||
assert data_element is not None
|
||||
layer_data: objects.LayerData = _parse_data(data_element, width)
|
||||
|
||||
return objects.TileLayer(
|
||||
id_=id_,
|
||||
name=name,
|
||||
offset=offset,
|
||||
opacity=opacity,
|
||||
properties=properties,
|
||||
size=size,
|
||||
layer_data=layer_data,
|
||||
)
|
||||
|
||||
|
||||
def _parse_tiled_objects(
|
||||
object_elements: List[etree.Element],
|
||||
) -> List[objects.TiledObject]:
|
||||
"""Parses objects found in a 'objectgroup' element.
|
||||
|
||||
Args:
|
||||
object_elements: List of object elements to be parsed.
|
||||
|
||||
Returns:
|
||||
list: List of parsed tiled objects.
|
||||
"""
|
||||
tiled_objects: List[objects.TiledObject] = []
|
||||
|
||||
for object_element in object_elements:
|
||||
my_object = _parse_object(object_element)
|
||||
if my_object is not None:
|
||||
tiled_objects.append(my_object)
|
||||
|
||||
return tiled_objects
|
||||
|
||||
|
||||
def _parse_object(obj):
|
||||
my_id = obj.attrib["id"]
|
||||
my_x = float(obj.attrib["x"])
|
||||
my_y = float(obj.attrib["y"])
|
||||
my_location = objects.OrderedPair(x=my_x, y=my_y)
|
||||
if "width" in obj.attrib:
|
||||
my_width = float(obj.attrib["width"])
|
||||
else:
|
||||
my_width = None
|
||||
if "height" in obj.attrib:
|
||||
my_height = float(obj.attrib["height"])
|
||||
else:
|
||||
my_height = None
|
||||
my_name = obj.attrib["name"]
|
||||
|
||||
properties: Optional[objects.Properties]
|
||||
properties_element = obj.find("./properties")
|
||||
if properties_element is not None:
|
||||
properties = _parse_properties_element(properties_element)
|
||||
else:
|
||||
properties = None
|
||||
|
||||
# This is where it would be nice if we could assume a walrus
|
||||
# operator was part of our Python distribution.
|
||||
|
||||
my_object = None
|
||||
|
||||
polygon = obj.findall("./polygon")
|
||||
|
||||
if polygon and len(polygon) > 0:
|
||||
points = _parse_points(polygon[0].attrib["points"])
|
||||
my_object = objects.PolygonObject(
|
||||
id_=my_id,
|
||||
name=my_name,
|
||||
location=my_location,
|
||||
size=(my_width, my_height),
|
||||
points=points,
|
||||
properties=properties,
|
||||
)
|
||||
|
||||
if my_object is None:
|
||||
polyline = obj.findall("./polyline")
|
||||
|
||||
if polyline and len(polyline) > 0:
|
||||
points = _parse_points(polyline[0].attrib["points"])
|
||||
my_object = objects.PolylineObject(
|
||||
id_=my_id,
|
||||
name=my_name,
|
||||
location=my_location,
|
||||
size=(my_width, my_height),
|
||||
points=points,
|
||||
properties=properties,
|
||||
)
|
||||
|
||||
if my_object is None:
|
||||
ellipse = obj.findall("./ellipse")
|
||||
|
||||
if ellipse and len(ellipse):
|
||||
my_object = objects.ElipseObject(
|
||||
id_=my_id,
|
||||
name=my_name,
|
||||
location=my_location,
|
||||
size=(my_width, my_height),
|
||||
properties=properties,
|
||||
)
|
||||
|
||||
if my_object is None:
|
||||
if "template" in obj.attrib:
|
||||
print(
|
||||
"Warning, this .tmx file is using an unsupported"
|
||||
"'template' attribute. Ignoring."
|
||||
)
|
||||
|
||||
if my_object is None:
|
||||
point = obj.findall("./point")
|
||||
if point:
|
||||
my_object = objects.PointObject(
|
||||
id_=my_id,
|
||||
name=my_name,
|
||||
location=my_location,
|
||||
properties=properties,
|
||||
)
|
||||
|
||||
if my_object is None:
|
||||
my_object = objects.RectangleObject(
|
||||
id_=my_id,
|
||||
name=my_name,
|
||||
location=my_location,
|
||||
size=(my_width, my_height),
|
||||
properties=properties,
|
||||
)
|
||||
|
||||
return my_object
|
||||
|
||||
|
||||
|
||||
def _parse_object_layer(element: etree.Element,) -> objects.ObjectLayer:
|
||||
"""Parse the objectgroup element given.
|
||||
|
||||
See: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#objectgroup
|
||||
|
||||
Args:
|
||||
element: Element to be parsed.
|
||||
|
||||
Returns:
|
||||
ObjectLayer: The object layer object.
|
||||
"""
|
||||
id_, name, offset, opacity, properties = _parse_layer(element)
|
||||
|
||||
color = None
|
||||
try:
|
||||
color = element.attrib["color"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
draw_order = None
|
||||
try:
|
||||
draw_order = element.attrib["draworder"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
tiled_objects = _parse_tiled_objects(element.findall("./object"))
|
||||
|
||||
return objects.ObjectLayer(
|
||||
id_=id_,
|
||||
name=name,
|
||||
offset=offset,
|
||||
opacity=opacity,
|
||||
properties=properties,
|
||||
color=color,
|
||||
draw_order=draw_order,
|
||||
tiled_objects=tiled_objects,
|
||||
)
|
||||
|
||||
|
||||
def _parse_image_layer(element: etree.Element,) -> objects.ImageLayer:
|
||||
"""Parse the imagelayer element given.
|
||||
|
||||
Args:
|
||||
element: Element to be parsed.
|
||||
|
||||
Returns:
|
||||
ImageLayer: The image layer object.
|
||||
"""
|
||||
id_, name, offset, opacity, properties = _parse_layer(element)
|
||||
|
||||
image = _parse_image_element(element.find("./image"))
|
||||
|
||||
return objects.ImageLayer(
|
||||
id_=id_,
|
||||
name=name,
|
||||
offset=offset,
|
||||
opacity=opacity,
|
||||
properties=properties,
|
||||
image=image,
|
||||
)
|
||||
|
||||
|
||||
def _parse_layer_group(element: etree.Element,) -> objects.LayerGroup:
|
||||
"""Parse the objectgroup element given.
|
||||
|
||||
Args:
|
||||
element: Element to be parsed.
|
||||
|
||||
Returns:
|
||||
LayerGroup: The layer group object.
|
||||
"""
|
||||
id_, name, offset, opacity, properties = _parse_layer(element)
|
||||
|
||||
layers = _get_layers(element)
|
||||
|
||||
return objects.LayerGroup(
|
||||
id_=id_,
|
||||
name=name,
|
||||
offset=offset,
|
||||
opacity=opacity,
|
||||
properties=properties,
|
||||
layers=layers,
|
||||
)
|
||||
|
||||
|
||||
def _get_layer_parser(
|
||||
layer_tag: str,
|
||||
) -> Optional[Callable[[etree.Element], objects.Layer]]:
|
||||
"""Gets a the parser for the layer type specified.
|
||||
|
||||
Layer tags are 'layer' for a tile layer, 'objectgroup' for an object layer, and
|
||||
'group' for a layer group. If anything else is passed, returns None.
|
||||
|
||||
Args:
|
||||
layer_tag: Specifies the layer type to be parsed based on the element tag.
|
||||
|
||||
Returns:
|
||||
Callable: the function to be used to parse the layer.
|
||||
None: The element is not a map layer.
|
||||
"""
|
||||
if layer_tag == "layer":
|
||||
return _parse_tile_layer
|
||||
if layer_tag == "objectgroup":
|
||||
return _parse_object_layer
|
||||
if layer_tag == "group":
|
||||
return _parse_layer_group
|
||||
if layer_tag == "imagelayer":
|
||||
return _parse_image_layer
|
||||
return None
|
||||
|
||||
|
||||
def _get_layers(map_element: etree.Element) -> List[objects.Layer]:
|
||||
"""Parse layer type element given.
|
||||
|
||||
Retains draw order based on the returned lists index FIXME: confirm
|
||||
|
||||
Args:
|
||||
map_element: The element containing the layer.
|
||||
|
||||
Returns:
|
||||
List[Layer]: A list of the layers, ordered by draw order. FIXME: confirm
|
||||
"""
|
||||
layers: List[objects.Layer] = []
|
||||
for element in map_element.findall("./"):
|
||||
layer_parser = _get_layer_parser(element.tag)
|
||||
if layer_parser:
|
||||
layers.append(layer_parser(element))
|
||||
|
||||
return layers
|
||||
|
||||
|
||||
@functools.lru_cache()
|
||||
def _parse_external_tile_set(
|
||||
parent_dir: Path, tile_set_element: etree.Element
|
||||
) -> objects.TileSet:
|
||||
"""Parses an external tile set.
|
||||
|
||||
Caches the results to speed up subsequent maps with identical tilesets.
|
||||
|
||||
Args:
|
||||
parent_dir: Directory that TMX is in.
|
||||
tile_set_element: Tile set element.
|
||||
|
||||
Returns:
|
||||
objects.Tileset: The tileset being parsed.
|
||||
"""
|
||||
source = Path(tile_set_element.attrib["source"])
|
||||
resolved_path = parent_dir / source
|
||||
tile_set_tree = etree.parse(str(parent_dir / Path(source))).getroot()
|
||||
|
||||
parsed_tile_set = _parse_tile_set(tile_set_tree)
|
||||
|
||||
parsed_tile_set.tsx_file = resolved_path
|
||||
parsed_tile_set.parent_dir = resolved_path.parent
|
||||
|
||||
return parsed_tile_set
|
||||
|
||||
|
||||
def _parse_points(point_string: str) -> List[objects.OrderedPair]:
|
||||
str_pairs = point_string.split(" ")
|
||||
|
||||
points = []
|
||||
for str_pair in str_pairs:
|
||||
xys = str_pair.split(",")
|
||||
x = float(xys[0])
|
||||
y = float(xys[1])
|
||||
points.append(objects.OrderedPair(x, y))
|
||||
|
||||
return points
|
||||
|
||||
|
||||
def _parse_tiles(tile_element_list: List[etree.Element]) -> Dict[int, objects.Tile]:
|
||||
"""Parse a list of tile elements.
|
||||
|
||||
Args:
|
||||
tile_element_list: List of tile elements.
|
||||
|
||||
Returns:
|
||||
Dict[int, objects.Tile]: Dictionary containing Tile objects by their ID.
|
||||
"""
|
||||
tiles: Dict[int, objects.Tile] = {}
|
||||
for tile_element in tile_element_list:
|
||||
# id is not optional
|
||||
id_ = int(tile_element.attrib["id"])
|
||||
|
||||
# optional attributes
|
||||
_type = None
|
||||
try:
|
||||
_type = tile_element.attrib["type"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
terrain = None
|
||||
try:
|
||||
tile_terrain_attrib = tile_element.attrib["terrain"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
# below is an attempt to explain how terrains are handled.
|
||||
# 'terrain' attribute is a comma seperated list of 4 values,
|
||||
# each is either an integer or blank
|
||||
|
||||
# convert to list of values
|
||||
terrain_list_attrib = re.split(",", tile_terrain_attrib)
|
||||
# terrain_list is list of indexes of Tileset.terrain_types
|
||||
terrain_list: List[Optional[int]] = []
|
||||
# each index in terrain_list_attrib refers to a corner
|
||||
for corner in terrain_list_attrib:
|
||||
if not corner:
|
||||
terrain_list.append(None)
|
||||
else:
|
||||
terrain_list.append(int(corner))
|
||||
terrain = objects.TileTerrain(*terrain_list)
|
||||
|
||||
# tile element optional sub-elements
|
||||
properties: Optional[List[objects.Property]] = None
|
||||
tile_properties_element = tile_element.find("./properties")
|
||||
if tile_properties_element:
|
||||
properties = []
|
||||
property_list = tile_properties_element.findall("./property")
|
||||
for property_ in property_list:
|
||||
name = property_.attrib["name"]
|
||||
value = property_.attrib["value"]
|
||||
obj = objects.Property(name, value)
|
||||
properties.append(obj)
|
||||
|
||||
# tile element optional sub-elements
|
||||
animation: Optional[List[objects.Frame]] = None
|
||||
tile_animation_element = tile_element.find("./animation")
|
||||
if tile_animation_element:
|
||||
animation = []
|
||||
frames = tile_animation_element.findall("./frame")
|
||||
for frame in frames:
|
||||
# tileid refers to the Tile.id of the animation frame
|
||||
animated_id = int(frame.attrib["tileid"])
|
||||
# duration is in MS. Should perhaps be converted to seconds.
|
||||
# FIXME: make decision
|
||||
duration = int(frame.attrib["duration"])
|
||||
animation.append(objects.Frame(animated_id, duration))
|
||||
|
||||
# tile element optional sub-elements
|
||||
objectgroup: Optional[List[objects.TiledObject]] = None
|
||||
objectgroup_element = tile_element.find("./objectgroup")
|
||||
if objectgroup_element:
|
||||
objectgroup = []
|
||||
object_list = objectgroup_element.findall("./object")
|
||||
for obj in object_list:
|
||||
my_object = _parse_object(obj)
|
||||
if my_object is not None:
|
||||
objectgroup.append(my_object)
|
||||
|
||||
# if this is None, then the Tile is part of a spritesheet
|
||||
image = None
|
||||
image_element = tile_element.find("./image")
|
||||
if image_element is not None:
|
||||
image = _parse_image_element(image_element)
|
||||
|
||||
# print(f"Adding '{id_}', {image}, {objectgroup}")
|
||||
|
||||
tiles[id_] = objects.Tile(
|
||||
id_=id_,
|
||||
type_=_type,
|
||||
terrain=terrain,
|
||||
animation=animation,
|
||||
image=image,
|
||||
properties=properties,
|
||||
tileset=None,
|
||||
objectgroup=objectgroup,
|
||||
)
|
||||
|
||||
return tiles
|
||||
|
||||
|
||||
def _parse_image_element(image_element: etree.Element) -> objects.Image:
|
||||
"""Parse image element given.
|
||||
|
||||
Args:
|
||||
image_element (etree.Element): Image element to be parsed.
|
||||
|
||||
Returns:
|
||||
objects.Image: FIXME what is this?
|
||||
"""
|
||||
# FIXME doc
|
||||
image = objects.Image(image_element.attrib["source"])
|
||||
|
||||
width_attrib = image_element.attrib.get("width")
|
||||
height_attrib = image_element.attrib.get("height")
|
||||
|
||||
if width_attrib and height_attrib:
|
||||
image.size = objects.Size(int(width_attrib), int(height_attrib))
|
||||
|
||||
try:
|
||||
image.trans = image_element.attrib["trans"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return image
|
||||
|
||||
|
||||
def _parse_properties_element(properties_element: etree.Element) -> objects.Properties:
|
||||
# FIXME: wtf is this pseudo 'attributes' section?
|
||||
"""Adds Tiled property to Properties dict.
|
||||
|
||||
Each property element has a number of attributes:
|
||||
name: Name of property.
|
||||
property_type: Type of property. Can be string, int, float, bool, color or
|
||||
file. Defaults to string.
|
||||
value: The value of the property.
|
||||
|
||||
Args:
|
||||
properties_element: Element to be parsed.
|
||||
|
||||
Returns:
|
||||
objects.Properties: Dict of the property values by property name.
|
||||
|
||||
|
||||
"""
|
||||
properties: objects.Properties = {}
|
||||
for property_element in properties_element.findall("./property"):
|
||||
name = property_element.attrib["name"]
|
||||
try:
|
||||
property_type = property_element.attrib["type"]
|
||||
except KeyError:
|
||||
# strings do not have an attribute in property elements
|
||||
property_type = "string"
|
||||
value = property_element.attrib["value"]
|
||||
|
||||
property_types = ["string", "int", "float", "bool", "color", "file"]
|
||||
assert property_type in property_types, f"Invalid type for property {name}"
|
||||
|
||||
if property_type == "int":
|
||||
properties[name] = int(value)
|
||||
elif property_type == "float":
|
||||
properties[name] = float(value)
|
||||
elif property_type == "color":
|
||||
properties[name] = value
|
||||
elif property_type == "file":
|
||||
properties[name] = Path(value)
|
||||
elif property_type == "bool":
|
||||
if value == "true":
|
||||
properties[name] = True
|
||||
else:
|
||||
properties[name] = False
|
||||
else:
|
||||
properties[name] = value
|
||||
|
||||
return properties
|
||||
|
||||
|
||||
def _parse_tile_set(tile_set_element: etree.Element) -> objects.TileSet:
|
||||
"""Parses a tile set that is embedded into a TMX.
|
||||
|
||||
Args:
|
||||
tile_set_element: Element to be parsed.
|
||||
|
||||
Returns:
|
||||
objects.TileSet: Tile Set from element.
|
||||
"""
|
||||
# get all basic attributes
|
||||
name = tile_set_element.attrib["name"]
|
||||
max_tile_width = int(tile_set_element.attrib["tilewidth"])
|
||||
max_tile_height = int(tile_set_element.attrib["tileheight"])
|
||||
max_tile_size = objects.Size(max_tile_width, max_tile_height)
|
||||
|
||||
spacing = None
|
||||
try:
|
||||
spacing = int(tile_set_element.attrib["spacing"])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
margin = None
|
||||
try:
|
||||
margin = int(tile_set_element.attrib["margin"])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
tile_count = None
|
||||
try:
|
||||
tile_count = int(tile_set_element.attrib["tilecount"])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
columns = None
|
||||
try:
|
||||
columns = int(tile_set_element.attrib["columns"])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
tile_offset = None
|
||||
tileoffset_element = tile_set_element.find("./tileoffset")
|
||||
if tileoffset_element is not None:
|
||||
tile_offset_x = int(tileoffset_element.attrib["x"])
|
||||
tile_offset_y = int(tileoffset_element.attrib["y"])
|
||||
tile_offset = objects.OrderedPair(tile_offset_x, tile_offset_y)
|
||||
|
||||
grid = None
|
||||
grid_element = tile_set_element.find("./grid")
|
||||
if grid_element is not None:
|
||||
grid_orientation = grid_element.attrib["orientation"]
|
||||
grid_width = int(grid_element.attrib["width"])
|
||||
grid_height = int(grid_element.attrib["height"])
|
||||
grid = objects.Grid(grid_orientation, grid_width, grid_height)
|
||||
|
||||
properties = None
|
||||
properties_element = tile_set_element.find("./properties")
|
||||
if properties_element is not None:
|
||||
properties = _parse_properties_element(properties_element)
|
||||
|
||||
terrain_types: Optional[List[objects.Terrain]] = None
|
||||
terrain_types_element = tile_set_element.find("./terraintypes")
|
||||
if terrain_types_element is not None:
|
||||
terrain_types = []
|
||||
for terrain in terrain_types_element.findall("./terrain"):
|
||||
name = terrain.attrib["name"]
|
||||
terrain_tile = int(terrain.attrib["tile"])
|
||||
terrain_types.append(objects.Terrain(name, terrain_tile))
|
||||
|
||||
image = None
|
||||
image_element = tile_set_element.find("./image")
|
||||
if image_element is not None:
|
||||
image = _parse_image_element(image_element)
|
||||
|
||||
tile_element_list = tile_set_element.findall("./tile")
|
||||
tiles = _parse_tiles(tile_element_list)
|
||||
|
||||
tileset = objects.TileSet(
|
||||
name,
|
||||
max_tile_size,
|
||||
spacing,
|
||||
margin,
|
||||
tile_count,
|
||||
columns,
|
||||
tile_offset,
|
||||
grid,
|
||||
properties,
|
||||
image,
|
||||
terrain_types,
|
||||
tiles,
|
||||
)
|
||||
|
||||
# Go back and create a circular link so tiles know what tileset they are
|
||||
# part of. Needed for animation.
|
||||
for id_, tile in tiles.items():
|
||||
tile.tileset = tileset
|
||||
|
||||
return tileset
|
||||
|
||||
|
||||
def _get_tile_sets(map_element: etree.Element, parent_dir: Path) -> objects.TileSetDict:
|
||||
"""Get tile sets.
|
||||
|
||||
Args:
|
||||
map_element: Element to be parsed.
|
||||
parent_dir: Directory that TMX is in.
|
||||
|
||||
Returns:
|
||||
objects.TileSetDict: Dict of tile sets in the TMX by first_gid
|
||||
"""
|
||||
# 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 is 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:
|
||||
"""Parse tile map.
|
||||
|
||||
Args:
|
||||
tmx_file: TMX file to be parsed.
|
||||
|
||||
Returns:
|
||||
objects.TileMap: TileMap object generated from the TMX file provided.
|
||||
"""
|
||||
# setting up XML parsing
|
||||
map_tree = etree.parse(str(tmx_file))
|
||||
map_element = map_tree.getroot()
|
||||
|
||||
# positional arguments for TileMap
|
||||
parent_dir = Path(tmx_file).parent
|
||||
|
||||
version = map_element.attrib["version"]
|
||||
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)
|
||||
|
||||
infinite_attribute = map_element.attrib["infinite"]
|
||||
infinite = bool(infinite_attribute == "1")
|
||||
|
||||
if "nextlayerid" in map_element.attrib:
|
||||
next_layer_id = int(map_element.attrib["nextlayerid"])
|
||||
else:
|
||||
next_layer_id = None
|
||||
|
||||
if "nextobjectid" in map_element.attrib:
|
||||
next_object_id = int(map_element.attrib["nextobjectid"])
|
||||
else:
|
||||
next_object_id = None
|
||||
|
||||
tile_sets = _get_tile_sets(map_element, parent_dir)
|
||||
|
||||
layers = _get_layers(map_element)
|
||||
|
||||
tile_map = objects.TileMap(
|
||||
parent_dir,
|
||||
tmx_file,
|
||||
version,
|
||||
tiled_version,
|
||||
orientation,
|
||||
render_order,
|
||||
map_size,
|
||||
tile_size,
|
||||
infinite,
|
||||
next_layer_id,
|
||||
next_object_id,
|
||||
tile_sets,
|
||||
layers,
|
||||
)
|
||||
|
||||
try:
|
||||
tile_map.hex_side_length = int(map_element.attrib["hexsidelength"])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
tile_map.stagger_axis = map_element.attrib["staggeraxis"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
tile_map.stagger_index = map_element.attrib["staggerindex"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
color = parse_color(map_element.attrib["backgroundcolor"])
|
||||
tile_map.background_color = (color.red, color.green, color.blue)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
properties_element = map_tree.find("./properties")
|
||||
if properties_element is not None:
|
||||
tile_map.properties = _parse_properties_element(properties_element)
|
||||
|
||||
return tile_map
|
||||
@@ -1,3 +0,0 @@
|
||||
import pytest
|
||||
|
||||
pytest.main(["--tb=native", "-s", "tests"])
|
||||
@@ -1,91 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="10" height="10" tilewidth="32" tileheight="32" infinite="0" nextlayerid="16" nextobjectid="10">
|
||||
<tileset firstgid="1" source="tile_set_image.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="10" height="10">
|
||||
<data encoding="csv">
|
||||
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
|
||||
</data>
|
||||
</layer>
|
||||
<layer id="2" name="Tile Layer 2" width="10" height="10" opacity="0.5">
|
||||
<data encoding="csv">
|
||||
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
|
||||
</data>
|
||||
</layer>
|
||||
<group id="3" name="Group 1">
|
||||
<properties>
|
||||
<property name="bool property" type="bool" value="true"/>
|
||||
</properties>
|
||||
<layer id="5" name="Tile Layer 4" width="10" height="10" offsetx="49" offsety="-50">
|
||||
<data encoding="csv">
|
||||
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
|
||||
</data>
|
||||
</layer>
|
||||
<layer id="4" name="Tile Layer 3" width="10" height="10">
|
||||
<data encoding="csv">
|
||||
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
|
||||
</data>
|
||||
</layer>
|
||||
</group>
|
||||
<objectgroup color="#000000" draworder="index" id="6" name="Object Layer 1" opacity="0.9" offsetx="4.66667" offsety="-4.33333">
|
||||
<object id="1" name="rectangle 1" type="rectangle type" x="200.25" y="210.75" width="47.25" height="25" rotation="15"/>
|
||||
<object id="2" name="polygon 1" type="polygon type" x="252.5" y="87.75" rotation="-21">
|
||||
<polygon points="0,0 -41.25,24.25 -11,67.25 25.75,39.75 -9,37.75"/>
|
||||
</object>
|
||||
<object id="3" name="elipse 1" type="elipse type" x="198.75" y="102.5" width="17.75" height="14.25">
|
||||
<ellipse/>
|
||||
</object>
|
||||
<object id="4" name="point 1" type="point type" x="174.25" y="186">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="7" name="insert text 1" type="insert text type" x="11.3958" y="48.5833" width="107.625" height="27.25">
|
||||
<text fontfamily="Sans Serif" pixelsize="17" wrap="1" color="#b40303" italic="1" underline="1" strikeout="1">Hello World</text>
|
||||
</object>
|
||||
<object id="6" name="inserted tile 1" type="inserted tile type" gid="3221225503" x="47.25" y="72.5" width="47" height="53" rotation="31">
|
||||
<properties>
|
||||
<property name="tile property bool" type="bool" value="true"/>
|
||||
</properties>
|
||||
</object>
|
||||
<object id="8" name="polyline 1" type="polyline type" x="144.667" y="112">
|
||||
<polyline points="0,0 -14.3333,35.6667 15.3333,18.3333"/>
|
||||
</object>
|
||||
<object id="9" name="polygon 2" type="polygon type" x="69.8333" y="168.333">
|
||||
<polygon points="-3.25,-17.25 -15,10.75 20.75,4.5"/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
||||
@@ -1,390 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="8" height="6" tilewidth="32" tileheight="32" infinite="1" nextlayerid="3" nextobjectid="1">
|
||||
<tileset firstgid="1" source="tile_set_image.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="8" height="6">
|
||||
<data encoding="csv">
|
||||
<chunk x="-32" y="-32" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="-16" y="-32" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="0" y="-32" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="16" y="-32" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="-32" y="-16" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="-16" y="-16" width="16" height="16">
|
||||
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,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,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,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,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,30,30,30,30,30,30,30,30,30,30,30,1,2,3,
|
||||
30,30,30,30,30,30,30,30,30,30,30,30,30,9,10,11,
|
||||
30,30,30,30,30,30,30,30,30,30,30,30,30,17,18,19
|
||||
</chunk>
|
||||
<chunk x="0" y="-16" width="16" height="16">
|
||||
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,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,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,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,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,
|
||||
4,5,6,7,8,30,30,30,30,30,30,30,30,30,30,30,
|
||||
12,13,14,15,16,30,30,30,30,30,30,30,30,30,30,30,
|
||||
20,21,22,23,24,30,30,30,30,30,30,30,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="16" y="-16" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="-32" y="0" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="-16" y="0" width="16" height="16">
|
||||
30,30,30,30,30,30,30,30,30,30,30,30,30,25,26,27,
|
||||
30,30,30,30,30,30,30,30,30,30,30,30,30,33,34,35,
|
||||
30,30,30,30,30,30,30,30,30,30,30,30,30,41,42,43,
|
||||
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,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,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,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,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
|
||||
</chunk>
|
||||
<chunk x="0" y="0" width="16" height="16">
|
||||
28,29,30,31,32,30,30,30,30,30,30,30,30,30,30,30,
|
||||
36,37,38,39,40,30,30,30,30,30,30,30,30,30,30,30,
|
||||
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,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,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,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,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,30,30,30,30,30,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="16" y="0" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="-32" y="16" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="-16" y="16" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="0" y="16" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
<chunk x="16" y="16" width="16" height="16">
|
||||
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,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,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,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,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,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,30,30,30,30
|
||||
</chunk>
|
||||
</data>
|
||||
</layer>
|
||||
<layer id="2" name="Tile Layer 2" width="8" height="6">
|
||||
<data encoding="csv">
|
||||
<chunk x="-32" y="-16" width="16" height="16">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,21,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,29,
|
||||
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,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,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
|
||||
</chunk>
|
||||
<chunk x="16" y="-16" width="16" height="16">
|
||||
0,0,20,21,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,28,29,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,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,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
|
||||
</chunk>
|
||||
<chunk x="-16" y="0" width="16" height="16">
|
||||
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,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,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,
|
||||
20,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</chunk>
|
||||
<chunk x="16" y="0" width="16" height="16">
|
||||
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,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,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,
|
||||
20,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
28,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
</chunk>
|
||||
<chunk x="-16" y="16" width="16" height="16">
|
||||
28,29,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,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,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,0,0,0,0,0,0,0,0,0,0,0
|
||||
</chunk>
|
||||
</data>
|
||||
</layer>
|
||||
</map>
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="8" height="6" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
|
||||
<properties>
|
||||
<property name="bool property - false" type="bool" value="false"/>
|
||||
<property name="bool property - true" type="bool" value="true"/>
|
||||
<property name="color property" type="color" value="#ff49fcff"/>
|
||||
<property name="file property" type="file" value="/var/log/syslog"/>
|
||||
<property name="float property" type="float" value="1.23456789"/>
|
||||
<property name="int property" type="int" value="13"/>
|
||||
<property name="string property" value="Hello, World!!"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="tile_set_image.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="8" height="6">
|
||||
<data encoding="csv">
|
||||
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
|
||||
</data>
|
||||
</layer>
|
||||
</map>
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="8" height="6" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
|
||||
<properties>
|
||||
<property name="bool property - false" type="bool" value="false"/>
|
||||
<property name="bool property - true" type="bool" value="true"/>
|
||||
<property name="color property" type="color" value="#ff49fcff"/>
|
||||
<property name="file property" type="file" value="../../../../../../../../var/log/syslog"/>
|
||||
<property name="float property" type="float" value="1.23456789"/>
|
||||
<property name="int property" type="int" value="13"/>
|
||||
<property name="string property" value="Hello, World!!"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="tile_set_image.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="8" height="6">
|
||||
<data encoding="base64" compression="gzip">
|
||||
H4sIAAAAAAAAAw3DBRKCQAAAwDMRA7BQLMTE9v+vY3dmWyGEth279uwbOTB26MixExNTM6fOnLtwae7KtYUbt+7ce7D0aOXJsxev3rxb+/Dpy7cfv/782wAcvDirwAAAAA==
|
||||
</data>
|
||||
</layer>
|
||||
</map>
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="8" height="6" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
|
||||
<tileset firstgid="1" source="tile_set_image_objects.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="8" height="6">
|
||||
<data encoding="csv">
|
||||
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
|
||||
</data>
|
||||
</layer>
|
||||
</map>
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.2" tiledversion="1.3.1" orientation="orthogonal" renderorder="right-down" compressionlevel="0" width="8" height="6" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1">
|
||||
<properties>
|
||||
<property name="bool property - false" type="bool" value="false"/>
|
||||
<property name="bool property - true" type="bool" value="true"/>
|
||||
<property name="color property" type="color" value="#ff49fcff"/>
|
||||
<property name="float property" type="float" value="1.23456789"/>
|
||||
<property name="int property" type="int" value="13"/>
|
||||
<property name="string property" value="Hello, World!!"/>
|
||||
</properties>
|
||||
<tileset firstgid="1" source="tile_set_image.tsx"/>
|
||||
<layer id="1" name="Tile Layer 1" width="8" height="6" offsetx="16" offsety="-16.42">
|
||||
<data encoding="csv">
|
||||
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
|
||||
</data>
|
||||
</layer>
|
||||
</map>
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tileset version="1.2" tiledversion="1.2.3" name="tile_set_image" tilewidth="32" tileheight="32" spacing="1" margin="1" tilecount="48" columns="8">
|
||||
<image source="images/tmw_desert_spacing.png" width="265" height="199"/>
|
||||
</tileset>
|
||||
@@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tileset version="1.2" tiledversion="1.2.3" name="tile_set_image" tilewidth="32" tileheight="32" spacing="1" margin="1" tilecount="48" columns="8">
|
||||
<image source="images/tmw_desert_spacing.png" width="265" height="199"/>
|
||||
<tile id="9">
|
||||
<objectgroup draworder="index">
|
||||
<object id="2" name="wall" type="rectangle type" x="1" y="1" width="32" height="32" rotation="1"/>
|
||||
</objectgroup>
|
||||
</tile>
|
||||
<tile id="19">
|
||||
<objectgroup draworder="index">
|
||||
<object id="1" name="wall corner" type="polygon type" x="32" y="1" rotation="1">
|
||||
<polygon points="0,0 -32,0 -32,32 -16,32.1818 -15.8182,16.9091 0.181818,17.0909"/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</tile>
|
||||
<tile id="20">
|
||||
<objectgroup draworder="index">
|
||||
<object id="1" name="polyline" type="polyline type" x="1.45455" y="1.45455" rotation="1">
|
||||
<polyline points="0,0 25.0909,21.2727 9.63636,28.3636"/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</tile>
|
||||
<tile id="31">
|
||||
<objectgroup draworder="index">
|
||||
<object id="1" name="rock 1" type="elipse type" x="5.09091" y="2.54545" width="19.6364" height="19.2727" rotation="1">
|
||||
<ellipse/>
|
||||
</object>
|
||||
<object id="2" name="rock 2" type="elipse type" x="16.1818" y="22" width="8.54545" height="8.36364" rotation="-1">
|
||||
<ellipse/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</tile>
|
||||
<tile id="45">
|
||||
<objectgroup draworder="index">
|
||||
<object id="1" name="sign" type="point type" x="14.7273" y="26.3636">
|
||||
<point/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</tile>
|
||||
</tileset>
|
||||
File diff suppressed because one or more lines are too long
@@ -1,223 +0,0 @@
|
||||
"""Unit tests for pytiled_parser"""
|
||||
|
||||
import xml.etree.ElementTree as etree
|
||||
from contextlib import ExitStack as does_not_raise
|
||||
|
||||
import pytest
|
||||
|
||||
from pytiled_parser import objects, utilities, xml_parser
|
||||
|
||||
LAYER_DATA = [
|
||||
(
|
||||
'<layer id="1" name="Tile Layer 1" width="10" height="10">' + "</layer>",
|
||||
(int(1), "Tile Layer 1", None, None, None),
|
||||
),
|
||||
(
|
||||
'<layer id="2" name="Tile Layer 2" width="10" height="10" opacity="0.5">'
|
||||
+ "</layer>",
|
||||
(int(2), "Tile Layer 2", None, float(0.5), None),
|
||||
),
|
||||
(
|
||||
'<layer id="5" name="Tile Layer 4" width="10" height="10" offsetx="49" offsety="-50">'
|
||||
+ "<properties>"
|
||||
+ "</properties>"
|
||||
+ "</layer>",
|
||||
(int(5), "Tile Layer 4", objects.OrderedPair(49, -50), None, "properties",),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("xml,expected", LAYER_DATA)
|
||||
def test_parse_layer(xml, expected, monkeypatch):
|
||||
def mockreturn(*args):
|
||||
return "properties"
|
||||
|
||||
monkeypatch.setattr(xml_parser, "_parse_properties_element", mockreturn)
|
||||
|
||||
result = xml_parser._parse_layer(etree.fromstring(xml))
|
||||
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"test_input,expected",
|
||||
[
|
||||
("#001122", (0x00, 0x11, 0x22, 0xFF)),
|
||||
("001122", (0x00, 0x11, 0x22, 0xFF)),
|
||||
("#FF001122", (0x00, 0x11, 0x22, 0xFF)),
|
||||
("FF001122", (0x00, 0x11, 0x22, 0xFF)),
|
||||
("FF001122", (0x00, 0x11, 0x22, 0xFF)),
|
||||
],
|
||||
)
|
||||
def test_color_parsing(test_input, expected):
|
||||
assert utilities.parse_color(test_input) == expected
|
||||
|
||||
|
||||
layer_data = [
|
||||
(
|
||||
etree.fromstring(
|
||||
"<data>\n1,2,3,4,5,6,7,8,\n"
|
||||
"9,10,11,12,13,14,15,16,\n"
|
||||
"17,18,19,20,21,22,23,24,\n"
|
||||
"25,26,27,28,29,30,31,32,\n"
|
||||
"33,34,35,36,37,38,39,40,\n"
|
||||
"41,42,43,44,45,46,47,48\n</data>"
|
||||
),
|
||||
8,
|
||||
"csv",
|
||||
None,
|
||||
[
|
||||
[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],
|
||||
],
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
etree.fromstring("<data>\n0,0,0,0,0\n</data>"),
|
||||
5,
|
||||
"csv",
|
||||
None,
|
||||
[[0, 0, 0, 0, 0]],
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
etree.fromstring(
|
||||
"<data>AQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAA</data>"
|
||||
),
|
||||
8,
|
||||
"base64",
|
||||
None,
|
||||
[
|
||||
[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],
|
||||
],
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
etree.fromstring(
|
||||
"<data>eJwNwwUSgkAAAMAzEQOwUCzExPb/r2N3ZlshhLYdu/bsGzkwdujIsRMTUzOnzpy7cGnuyrWFG7fu3Huw9GjlybMXr968W/vw6cu3H7/+/NsAMw8EmQ==</data>"
|
||||
),
|
||||
8,
|
||||
"base64",
|
||||
"zlib",
|
||||
[
|
||||
[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],
|
||||
],
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
etree.fromstring(
|
||||
"<data>H4sIAAAAAAAAAw3DBRKCQAAAwDMRA7BQLMTE9v+vY3dmWyGEth279uwbOTB26MixExNTM6fOnLtwae7KtYUbt+7ce7D0aOXJsxev3rxb+/Dpy7cfv/782wAcvDirwAAAAA==</data>"
|
||||
),
|
||||
8,
|
||||
"base64",
|
||||
"gzip",
|
||||
[
|
||||
[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],
|
||||
],
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
etree.fromstring("<data>SGVsbG8gV29ybGQh</data>"),
|
||||
8,
|
||||
"base64",
|
||||
"lzma",
|
||||
[
|
||||
[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],
|
||||
],
|
||||
pytest.raises(ValueError),
|
||||
),
|
||||
(
|
||||
etree.fromstring(
|
||||
"<data>/ .---- --..-- ..--- --..-- ...-- --..-- ....- --..-- ..... --..-- -.... --..-- --... --..-- ---.. --..-- / ----. --..-- .---- ----- --..-- .---- .---- --..-- .---- ..--- --..-- .---- ...-- --..-- .---- ....- --..-- .---- ..... --..-- .---- -.... --..-- / .---- --... --..-- .---- ---.. --..-- .---- ----. --..-- ..--- ----- --..-- ..--- .---- --..-- ..--- ..--- --..-- ..--- ...-- --..-- ..--- ....- --..-- / ..--- ..... --..-- ..--- -.... --..-- ..--- --... --..-- ..--- ---.. --..-- ..--- ----. --..-- ...-- ----- --..-- ...-- .---- --..-- ...-- ..--- --..-- / ...-- ...-- --..-- ...-- ....- --..-- ...-- ..... --..-- ...-- -.... --..-- ...-- --... --..-- ...-- ---.. --..-- ...-- ----. --..-- ....- ----- --..-- / ....- .---- --..-- ....- ..--- --..-- ....- ...-- --..-- ....- ....- --..-- ....- ..... --..-- ....- -.... --..-- ....- --... --..-- ....- ---..</data>"
|
||||
),
|
||||
8,
|
||||
"morse",
|
||||
None,
|
||||
[
|
||||
[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],
|
||||
],
|
||||
pytest.raises(ValueError),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"layer_data,width,encoding,compression,expected,raises", layer_data
|
||||
)
|
||||
def test_decode_layer_data(layer_data, width, encoding, compression, expected, raises):
|
||||
with raises:
|
||||
assert (
|
||||
xml_parser._decode_tile_layer_data(layer_data, width, encoding, compression)
|
||||
== expected
|
||||
)
|
||||
|
||||
|
||||
# FIXME: use hypothesis for this
|
||||
def create_tile_set(qty_of_tiles):
|
||||
""" Create tile set of specific size.
|
||||
"""
|
||||
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(id_=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(id_=0)),
|
||||
(1, {1: create_tile_set(2)}, objects.Tile(id_=0)),
|
||||
(2, {1: create_tile_set(1)}, None),
|
||||
(10, {1: create_tile_set(10)}, objects.Tile(id_=9)),
|
||||
(1, {1: create_tile_set(1), 2: create_tile_set(1)}, objects.Tile(id_=0)),
|
||||
(2, {1: create_tile_set(1), 2: create_tile_set(1)}, objects.Tile(id_=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(id_=9)),
|
||||
(
|
||||
20,
|
||||
{1: create_tile_set(5), 6: create_tile_set(10), 16: create_tile_set(10),},
|
||||
objects.Tile(id_=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,98 +0,0 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
import pytiled_parser
|
||||
|
||||
TESTS_DIR = Path(os.path.dirname(os.path.abspath(__file__)))
|
||||
TEST_DATA = TESTS_DIR / "test_data"
|
||||
|
||||
|
||||
def test_map_simple():
|
||||
"""
|
||||
TMX with a very simple spritesheet tile set and some properties.
|
||||
"""
|
||||
|
||||
test_map = pytiled_parser.parse_tile_map(TEST_DATA / "test_map_simple.tmx")
|
||||
|
||||
# map
|
||||
# unsure how to get paths to compare propperly
|
||||
assert test_map.parent_dir == TEST_DATA
|
||||
assert test_map.version == "1.2"
|
||||
assert test_map.tiled_version == "1.2.3"
|
||||
assert test_map.orientation == "orthogonal"
|
||||
assert test_map.render_order == "right-down"
|
||||
assert test_map.map_size == (8, 6)
|
||||
assert test_map.tile_size == (32, 32)
|
||||
assert test_map.infinite == False
|
||||
assert test_map.next_layer_id == 2
|
||||
assert test_map.next_object_id == 1
|
||||
|
||||
# optional, not for orthogonal maps
|
||||
assert test_map.hex_side_length == None
|
||||
assert test_map.stagger_axis == None
|
||||
assert test_map.stagger_index == None
|
||||
assert test_map.background_color == None
|
||||
|
||||
assert test_map.properties == {
|
||||
"bool property - false": False,
|
||||
"bool property - true": True,
|
||||
"color property": "#ff49fcff",
|
||||
"file property": Path("/var/log/syslog"),
|
||||
"float property": 1.23456789,
|
||||
"int property": 13,
|
||||
"string property": "Hello, World!!",
|
||||
}
|
||||
|
||||
# tileset
|
||||
assert test_map.tile_sets[1].name == "tile_set_image"
|
||||
assert test_map.tile_sets[1].max_tile_size == (32, 32)
|
||||
assert test_map.tile_sets[1].spacing == 1
|
||||
assert test_map.tile_sets[1].margin == 1
|
||||
assert test_map.tile_sets[1].tile_count == 48
|
||||
assert test_map.tile_sets[1].columns == 8
|
||||
assert test_map.tile_sets[1].tile_offset == None
|
||||
assert test_map.tile_sets[1].grid == None
|
||||
assert test_map.tile_sets[1].properties == None
|
||||
|
||||
# unsure how to get paths to compare propperly
|
||||
assert str(test_map.tile_sets[1].image.source) == ("images/tmw_desert_spacing.png")
|
||||
assert test_map.tile_sets[1].image.trans == None
|
||||
assert test_map.tile_sets[1].image.size == (265, 199)
|
||||
|
||||
assert test_map.tile_sets[1].terrain_types == None
|
||||
assert test_map.tile_sets[1].tiles == {}
|
||||
|
||||
# layers
|
||||
assert test_map.layers[0].layer_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],
|
||||
]
|
||||
assert test_map.layers[0].id_ == 1
|
||||
assert test_map.layers[0].name == "Tile Layer 1"
|
||||
assert test_map.layers[0].offset == None
|
||||
assert test_map.layers[0].opacity == None
|
||||
assert test_map.layers[0].properties == None
|
||||
assert test_map.layers[0].size == (8, 6)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"test_input,expected",
|
||||
[
|
||||
("#001122", (0x00, 0x11, 0x22, 0xFF)),
|
||||
("001122", (0x00, 0x11, 0x22, 0xFF)),
|
||||
("#FF001122", (0x00, 0x11, 0x22, 0xFF)),
|
||||
("FF001122", (0x00, 0x11, 0x22, 0xFF)),
|
||||
("FF001122", (0x00, 0x11, 0x22, 0xFF)),
|
||||
],
|
||||
)
|
||||
def test_color_parsing(test_input, expected):
|
||||
"""
|
||||
Tiled has a few different types of color representations.
|
||||
"""
|
||||
assert pytiled_parser.utilities.parse_color(test_input) == expected
|
||||
@@ -1,81 +0,0 @@
|
||||
"""test test_map_simple_offset.tmx"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pytiled_parser
|
||||
|
||||
TESTS_DIR = Path(os.path.dirname(os.path.abspath(__file__)))
|
||||
TEST_DATA = TESTS_DIR / "test_data"
|
||||
|
||||
|
||||
def test_map_simple():
|
||||
"""
|
||||
TMX with a very simple spritesheet tile set and some properties.
|
||||
"""
|
||||
|
||||
test_map = pytiled_parser.parse_tile_map(TEST_DATA / "test_map_simple_offset.tmx")
|
||||
|
||||
# map
|
||||
# unsure how to get paths to compare propperly
|
||||
assert test_map.parent_dir == TEST_DATA
|
||||
assert test_map.version == "1.2"
|
||||
assert test_map.tiled_version == "1.3.1"
|
||||
assert test_map.orientation == "orthogonal"
|
||||
assert test_map.render_order == "right-down"
|
||||
assert test_map.map_size == (8, 6)
|
||||
assert test_map.tile_size == (32, 32)
|
||||
assert test_map.infinite == False
|
||||
assert test_map.next_layer_id == 2
|
||||
assert test_map.next_object_id == 1
|
||||
|
||||
# optional, not for orthogonal maps
|
||||
assert test_map.hex_side_length == None
|
||||
assert test_map.stagger_axis == None
|
||||
assert test_map.stagger_index == None
|
||||
assert test_map.background_color == None
|
||||
|
||||
assert test_map.properties == {
|
||||
"bool property - false": False,
|
||||
"bool property - true": True,
|
||||
"color property": "#ff49fcff",
|
||||
"float property": 1.23456789,
|
||||
"int property": 13,
|
||||
"string property": "Hello, World!!",
|
||||
}
|
||||
|
||||
# tileset
|
||||
assert test_map.tile_sets[1].name == "tile_set_image"
|
||||
assert test_map.tile_sets[1].max_tile_size == (32, 32)
|
||||
assert test_map.tile_sets[1].spacing == 1
|
||||
assert test_map.tile_sets[1].margin == 1
|
||||
assert test_map.tile_sets[1].tile_count == 48
|
||||
assert test_map.tile_sets[1].columns == 8
|
||||
assert test_map.tile_sets[1].tile_offset == None
|
||||
assert test_map.tile_sets[1].grid == None
|
||||
assert test_map.tile_sets[1].properties == None
|
||||
|
||||
# unsure how to get paths to compare propperly
|
||||
assert str(test_map.tile_sets[1].image.source) == ("images/tmw_desert_spacing.png")
|
||||
assert test_map.tile_sets[1].image.trans == None
|
||||
assert test_map.tile_sets[1].image.size == (265, 199)
|
||||
|
||||
assert test_map.tile_sets[1].terrain_types == None
|
||||
assert test_map.tile_sets[1].tiles == {}
|
||||
|
||||
# layers
|
||||
assert test_map.layers[0].layer_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],
|
||||
]
|
||||
assert test_map.layers[0].id_ == 1
|
||||
assert test_map.layers[0].name == "Tile Layer 1"
|
||||
assert test_map.layers[0].offset == pytiled_parser.objects.OrderedPair(
|
||||
x=16.0, y=-16.42
|
||||
)
|
||||
assert test_map.layers[0].opacity == None
|
||||
assert test_map.layers[0].properties == None
|
||||
assert test_map.layers[0].size == (8, 6)
|
||||
@@ -1,19 +0,0 @@
|
||||
"""Tests for typing helpers"""
|
||||
|
||||
import pytest
|
||||
|
||||
from pytiled_parser import typing_helpers as TH
|
||||
|
||||
TEST_IS_FLOAT_PARAMS = [
|
||||
(1, True),
|
||||
("1", True),
|
||||
(1.1, True),
|
||||
("1.1", True),
|
||||
("one", False),
|
||||
(None, False),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("string,expected", TEST_IS_FLOAT_PARAMS)
|
||||
def test_is_float(string, expected):
|
||||
assert TH.is_float(string) == expected
|
||||
Reference in New Issue
Block a user