From 951784e80608cfcfd36706b63028af7995bdd17e Mon Sep 17 00:00:00 2001 From: leo <80651389+civilwarinfrance@users.noreply.github.com> Date: Tue, 27 Oct 2026 17:52:10 -0700 Subject: [PATCH] Default missing layer offset axes independently --- pytiled_parser/parsers/json/layer.py | 5 +- pytiled_parser/parsers/tmx/layer.py | 8 ++-- tests/test_layer_offsets.py | 69 ++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 tests/test_layer_offsets.py diff --git a/pytiled_parser/parsers/json/layer.py b/pytiled_parser/parsers/json/layer.py index d4ae6e69..46b600f6 100644 --- a/pytiled_parser/parsers/json/layer.py +++ b/pytiled_parser/parsers/json/layer.py @@ -229,8 +229,9 @@ def _parse_common(raw_layer: RawLayer) -> Layer: if raw_layer.get("width") is not None: common.size = Size(raw_layer["width"], raw_layer["height"]) - if raw_layer.get("offsetx") is not None: - common.offset = OrderedPair(raw_layer["offsetx"], raw_layer["offsety"]) + common.offset = OrderedPair( + raw_layer.get("offsetx", 0), raw_layer.get("offsety", 0) + ) if raw_layer.get("properties") is not None: common.properties = parse_properties(raw_layer["properties"]) diff --git a/pytiled_parser/parsers/tmx/layer.py b/pytiled_parser/parsers/tmx/layer.py index b4ebc17d..e2724234 100644 --- a/pytiled_parser/parsers/tmx/layer.py +++ b/pytiled_parser/parsers/tmx/layer.py @@ -171,10 +171,10 @@ def _parse_common(raw_layer: etree.Element) -> Layer: if raw_layer.attrib.get("id") is not None: common.id = int(raw_layer.attrib["id"]) - if raw_layer.attrib.get("offsetx") is not None: - common.offset = OrderedPair( - float(raw_layer.attrib["offsetx"]), float(raw_layer.attrib["offsety"]) - ) + common.offset = OrderedPair( + float(raw_layer.attrib.get("offsetx", 0)), + float(raw_layer.attrib.get("offsety", 0)), + ) properties_element = raw_layer.find("./properties") if properties_element is not None: diff --git a/tests/test_layer_offsets.py b/tests/test_layer_offsets.py new file mode 100644 index 00000000..ad5957aa --- /dev/null +++ b/tests/test_layer_offsets.py @@ -0,0 +1,69 @@ +"""Layer offset axes are independently optional in both map formats.""" + +import xml.etree.ElementTree as etree + +import pytest + +from pytiled_parser.common_types import OrderedPair +from pytiled_parser.parsers.json.layer import parse as parse_json +from pytiled_parser.parsers.tmx.layer import parse as parse_tmx + + +@pytest.mark.parametrize("parser_type", ["json", "tmx"]) +@pytest.mark.parametrize( + "layer_type", ["tilelayer", "objectgroup", "imagelayer", "group"] +) +@pytest.mark.parametrize( + "offsets,expected", + [ + ({}, (0, 0)), + ({"offsetx": 17.5}, (17.5, 0)), + ({"offsety": -6.25}, (0, -6.25)), + ({"offsetx": 0}, (0, 0)), + ({"offsety": 0}, (0, 0)), + ({"offsetx": 0, "offsety": -6.25}, (0, -6.25)), + ({"offsetx": -17.5, "offsety": 6.25}, (-17.5, 6.25)), + ], +) +def test_independent_layer_offsets(parser_type, layer_type, offsets, expected): + if parser_type == "json": + raw = { + "name": "test", + "type": layer_type, + "opacity": 1, + "visible": True, + **offsets, + } + if layer_type == "tilelayer": + raw.update(width=1, height=1, data=[0]) + elif layer_type == "objectgroup": + raw.update(objects=[], draworder="topdown") + elif layer_type == "imagelayer": + raw["image"] = "background.png" + else: + raw["layers"] = [] + # Exercise recursive parsing as well as each concrete layer parser. + group = parse_json( + { + "name": "parent", + "type": "group", + "opacity": 1, + "visible": True, + "layers": [raw], + }, + encoding="utf-8", + ) + else: + parent = etree.Element("group", name="parent") + tag = "layer" if layer_type == "tilelayer" else layer_type + raw = etree.SubElement(parent, tag, name="test") + raw.attrib.update({key: str(value) for key, value in offsets.items()}) + if layer_type == "tilelayer": + raw.attrib.update(width="1", height="1") + etree.SubElement(raw, "data", encoding="csv").text = "0" + elif layer_type == "imagelayer": + etree.SubElement(raw, "image", source="background.png") + group = parse_tmx(parent, encoding="utf-8") + + assert group.offset == OrderedPair(0, 0) + assert group.layers[0].offset == OrderedPair(*expected)