tilemap-parser 3.1.6__tar.gz → 3.1.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/PKG-INFO +1 -1
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/pyproject.toml +1 -1
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/__init__.py +4 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/parser/__init__.py +4 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/parser/map_parse.py +6 -1
- tilemap_parser-3.1.8/src/tilemap_parser/parser/node_parse.py +77 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/runtime/__init__.py +2 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/runtime/animation_player.py +18 -0
- tilemap_parser-3.1.8/src/tilemap_parser/runtime/area_node.py +38 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/runtime/map_loader.py +23 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser.egg-info/PKG-INFO +1 -1
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser.egg-info/SOURCES.txt +2 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/LICENSE +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/README.md +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/setup.cfg +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/parser/animation.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/parser/collision.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/parser/collision_loader.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/runtime/collision_cache.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/runtime/object_collision.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/runtime/renderer.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/runtime/tile_collision.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/utils/__init__.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/utils/geometry.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser.egg-info/dependency_links.txt +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser.egg-info/requires.txt +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser.egg-info/top_level.txt +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/tests/test_collision.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/tests/test_geometry.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/tests/test_map_loader.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/tests/test_object_collision.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/tests/test_render_scale.py +0 -0
- {tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/tests/test_tile_collision.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tilemap-parser
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.8
|
|
4
4
|
Summary: Standalone parser/loader for tilemap-editor JSON maps, sprite animations, and collision detection runtime.
|
|
5
5
|
Author: tilemap parser contributors
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tilemap-parser"
|
|
7
|
-
version = "3.1.
|
|
7
|
+
version = "3.1.8"
|
|
8
8
|
description = "Standalone parser/loader for tilemap-editor JSON maps, sprite animations, and collision detection runtime."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -9,6 +9,7 @@ __all__ = [
|
|
|
9
9
|
"AnimationMarker",
|
|
10
10
|
"AnimationParseError",
|
|
11
11
|
"AnimationPlayer",
|
|
12
|
+
"AreaNode",
|
|
12
13
|
"CapsuleShape",
|
|
13
14
|
"CharacterCollision",
|
|
14
15
|
"CircleShape",
|
|
@@ -32,6 +33,7 @@ __all__ = [
|
|
|
32
33
|
"ParsedLayer",
|
|
33
34
|
"ParsedMap",
|
|
34
35
|
"ParsedMeta",
|
|
36
|
+
"ParsedNode",
|
|
35
37
|
"ParsedObject",
|
|
36
38
|
"ParsedObjectArea",
|
|
37
39
|
"ParsedProjectState",
|
|
@@ -62,6 +64,8 @@ __all__ = [
|
|
|
62
64
|
"parse_map_dict",
|
|
63
65
|
"parse_map_file",
|
|
64
66
|
"parse_map_json",
|
|
67
|
+
"parse_nodes_dict",
|
|
68
|
+
"parse_nodes_file",
|
|
65
69
|
"parse_object_collision",
|
|
66
70
|
"parse_tileset_collision",
|
|
67
71
|
"polygon_vs_circle",
|
|
@@ -44,6 +44,7 @@ from .map_parse import (
|
|
|
44
44
|
parse_map_file,
|
|
45
45
|
parse_map_json,
|
|
46
46
|
)
|
|
47
|
+
from .node_parse import ParsedNode, parse_nodes_dict, parse_nodes_file
|
|
47
48
|
|
|
48
49
|
__all__ = [
|
|
49
50
|
"AnimationClip",
|
|
@@ -60,6 +61,7 @@ __all__ = [
|
|
|
60
61
|
"ObjectCollisionData",
|
|
61
62
|
"ObjectCollisionRegionData",
|
|
62
63
|
"ParsedAutotileGroup",
|
|
64
|
+
"ParsedNode",
|
|
63
65
|
"ParsedAutotileRule",
|
|
64
66
|
"ParsedLayer",
|
|
65
67
|
"ParsedMap",
|
|
@@ -82,6 +84,8 @@ __all__ = [
|
|
|
82
84
|
"parse_map_dict",
|
|
83
85
|
"parse_map_file",
|
|
84
86
|
"parse_map_json",
|
|
87
|
+
"parse_nodes_dict",
|
|
88
|
+
"parse_nodes_file",
|
|
85
89
|
"parse_object_collision",
|
|
86
90
|
"parse_tileset_collision",
|
|
87
91
|
]
|
|
@@ -5,7 +5,10 @@ import re
|
|
|
5
5
|
import string
|
|
6
6
|
from dataclasses import dataclass, field
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from .node_parse import ParsedNode
|
|
9
12
|
|
|
10
13
|
JsonDict = Dict[str, Any]
|
|
11
14
|
Point = Tuple[int, int]
|
|
@@ -187,6 +190,8 @@ class ParsedMap:
|
|
|
187
190
|
tilesets: List[ParsedTileset]
|
|
188
191
|
project_state: ParsedProjectState
|
|
189
192
|
raw: JsonDict
|
|
193
|
+
nodes: List["ParsedNode"] = field(default_factory=list)
|
|
194
|
+
node_groups: List[str] = field(default_factory=list)
|
|
190
195
|
|
|
191
196
|
|
|
192
197
|
def _parse_tile(tile_data: JsonDict, ctx: str) -> ParsedTile:
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, Dict, List, Optional, Union
|
|
7
|
+
|
|
8
|
+
from .map_parse import (
|
|
9
|
+
JsonDict,
|
|
10
|
+
MapParseError,
|
|
11
|
+
ParsedObjectArea,
|
|
12
|
+
_coerce_bool,
|
|
13
|
+
_coerce_float,
|
|
14
|
+
_coerce_int,
|
|
15
|
+
_optional_dict,
|
|
16
|
+
_require_dict,
|
|
17
|
+
_require_list,
|
|
18
|
+
_require_str,
|
|
19
|
+
_ctx,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ParsedNode:
|
|
25
|
+
node_id: str
|
|
26
|
+
name: str
|
|
27
|
+
node_type: str
|
|
28
|
+
area: ParsedObjectArea
|
|
29
|
+
layer_name: str
|
|
30
|
+
properties: JsonDict = field(default_factory=dict)
|
|
31
|
+
group: Optional[str] = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _parse_area(raw: Any, ctx: str) -> ParsedObjectArea:
|
|
35
|
+
d = _require_dict(raw, ctx)
|
|
36
|
+
return ParsedObjectArea(
|
|
37
|
+
x=_coerce_int(d.get("x"), f"{ctx}.x"),
|
|
38
|
+
y=_coerce_int(d.get("y"), f"{ctx}.y"),
|
|
39
|
+
w=_coerce_int(d.get("w"), f"{ctx}.w"),
|
|
40
|
+
h=_coerce_int(d.get("h"), f"{ctx}.h"),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _parse_node(raw: Any, ctx: str) -> ParsedNode:
|
|
45
|
+
d = _require_dict(raw, ctx)
|
|
46
|
+
group_raw = d.get("group")
|
|
47
|
+
group = str(group_raw) if group_raw is not None else None
|
|
48
|
+
return ParsedNode(
|
|
49
|
+
node_id=_require_str(d.get("node_id"), f"{ctx}.node_id"),
|
|
50
|
+
name=_require_str(d.get("name"), f"{ctx}.name"),
|
|
51
|
+
node_type=_require_str(d.get("node_type", "area"), f"{ctx}.node_type"),
|
|
52
|
+
area=_parse_area(d.get("area"), f"{ctx}.area"),
|
|
53
|
+
layer_name=_require_str(d.get("layer_name", ""), f"{ctx}.layer_name"),
|
|
54
|
+
properties=_optional_dict(d.get("properties"), f"{ctx}.properties") or {},
|
|
55
|
+
group=group,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def parse_nodes_dict(root: JsonDict) -> List[ParsedNode]:
|
|
60
|
+
root = _require_dict(root, "root")
|
|
61
|
+
raw_nodes = _require_list(root.get("nodes", []), "root.nodes")
|
|
62
|
+
return [_parse_node(item, f"root.nodes[{i}]") for i, item in enumerate(raw_nodes)]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def parse_nodes_file(path: Union[str, Path]) -> List[ParsedNode]:
|
|
66
|
+
p = Path(path)
|
|
67
|
+
if not p.is_file():
|
|
68
|
+
raise MapParseError(f"Not a file: {p}")
|
|
69
|
+
try:
|
|
70
|
+
text = p.read_text(encoding="utf-8")
|
|
71
|
+
except OSError as e:
|
|
72
|
+
raise MapParseError(f"Cannot read {p}: {e}") from e
|
|
73
|
+
try:
|
|
74
|
+
payload = json.loads(text)
|
|
75
|
+
except json.JSONDecodeError as e:
|
|
76
|
+
raise MapParseError(f"Invalid JSON in {p}: {e}") from e
|
|
77
|
+
return parse_nodes_dict(payload)
|
|
@@ -23,9 +23,11 @@ from .object_collision import (
|
|
|
23
23
|
check_collision,
|
|
24
24
|
)
|
|
25
25
|
from .renderer import LayerRenderStats, TileLayerRenderer
|
|
26
|
+
from .area_node import AreaNode
|
|
26
27
|
|
|
27
28
|
__all__ = [
|
|
28
29
|
"AnimationPlayer",
|
|
30
|
+
"AreaNode",
|
|
29
31
|
"CollisionCache",
|
|
30
32
|
"CollisionHit",
|
|
31
33
|
"CollisionResult",
|
{tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/runtime/animation_player.py
RENAMED
|
@@ -68,6 +68,24 @@ class SpriteAnimationSet:
|
|
|
68
68
|
grid_offset_y=library.grid_offset[1],
|
|
69
69
|
)
|
|
70
70
|
|
|
71
|
+
def get_content_bounds(self, clip_name: str) -> Optional[Rect]:
|
|
72
|
+
clip = self.library.get(clip_name)
|
|
73
|
+
if clip is None or not clip.frames:
|
|
74
|
+
return None
|
|
75
|
+
union: Optional[Rect] = None
|
|
76
|
+
for frame in clip.frames:
|
|
77
|
+
surf = self.get_image(frame.variant_id, copy_surface=False)
|
|
78
|
+
if surf is None:
|
|
79
|
+
continue
|
|
80
|
+
rect = surf.get_bounding_rect()
|
|
81
|
+
if rect.width == 0 or rect.height == 0:
|
|
82
|
+
continue
|
|
83
|
+
if union is None:
|
|
84
|
+
union = rect.copy()
|
|
85
|
+
else:
|
|
86
|
+
union.union_ip(rect)
|
|
87
|
+
return union
|
|
88
|
+
|
|
71
89
|
def get_image(self, variant_id: int, *, copy_surface: bool = True) -> Optional[Surface]:
|
|
72
90
|
tw, th = self.library.tile_size
|
|
73
91
|
if tw <= 0 or th <= 0:
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Tuple
|
|
4
|
+
|
|
5
|
+
from pygame import Rect
|
|
6
|
+
|
|
7
|
+
from ..parser.node_parse import ParsedNode
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AreaNode:
|
|
11
|
+
def __init__(self, parsed: ParsedNode) -> None:
|
|
12
|
+
self.node_id = parsed.node_id
|
|
13
|
+
self.name = parsed.name
|
|
14
|
+
self.node_type = parsed.node_type
|
|
15
|
+
self._rect = Rect(parsed.area.x, parsed.area.y, parsed.area.w, parsed.area.h)
|
|
16
|
+
self.layer_name = parsed.layer_name
|
|
17
|
+
self.properties = dict(parsed.properties)
|
|
18
|
+
self.group = parsed.group
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def rect(self) -> Rect:
|
|
22
|
+
return self._rect
|
|
23
|
+
|
|
24
|
+
@rect.setter
|
|
25
|
+
def rect(self, r: Rect) -> None:
|
|
26
|
+
self._rect = r
|
|
27
|
+
|
|
28
|
+
def contains_point(self, point: Tuple[float, float]) -> bool:
|
|
29
|
+
return self._rect.collidepoint(point)
|
|
30
|
+
|
|
31
|
+
def overlaps_rect(self, other: Rect) -> bool:
|
|
32
|
+
return self._rect.colliderect(other)
|
|
33
|
+
|
|
34
|
+
def __repr__(self) -> str:
|
|
35
|
+
return (
|
|
36
|
+
f"AreaNode(id={self.node_id!r}, name={self.name!r}, "
|
|
37
|
+
f"rect={self._rect}, layer={self.layer_name!r})"
|
|
38
|
+
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
from copy import deepcopy
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import Dict, List, Optional, Tuple, Union
|
|
@@ -8,6 +9,7 @@ import pygame
|
|
|
8
9
|
from pygame import Rect, Surface
|
|
9
10
|
|
|
10
11
|
from ..parser.map_parse import MapParseError, ParsedLayer, ParsedMap, ParsedTile, parse_map_file
|
|
12
|
+
from ..parser.node_parse import parse_nodes_dict
|
|
11
13
|
|
|
12
14
|
PathLike = Union[str, Path]
|
|
13
15
|
|
|
@@ -66,6 +68,27 @@ class TilemapData:
|
|
|
66
68
|
raise MapParseError(msg) from e
|
|
67
69
|
surfaces.append(None)
|
|
68
70
|
|
|
71
|
+
nodes_name = f"{p.stem}.nodes.json"
|
|
72
|
+
nodes_candidates = [
|
|
73
|
+
map_dir / nodes_name,
|
|
74
|
+
map_dir.parent / "nodes" / nodes_name,
|
|
75
|
+
]
|
|
76
|
+
if extra_search_base is not None:
|
|
77
|
+
nodes_candidates.append(extra_search_base / "nodes" / nodes_name)
|
|
78
|
+
for nodes_path in nodes_candidates:
|
|
79
|
+
if nodes_path.is_file():
|
|
80
|
+
try:
|
|
81
|
+
nodes_text = nodes_path.read_text(encoding="utf-8")
|
|
82
|
+
nodes_raw = json.loads(nodes_text)
|
|
83
|
+
parsed.nodes = parse_nodes_dict(nodes_raw)
|
|
84
|
+
groups_raw = nodes_raw.get("groups", [])
|
|
85
|
+
if not isinstance(groups_raw, list):
|
|
86
|
+
raise MapParseError("root.groups must be a list")
|
|
87
|
+
parsed.node_groups = groups_raw
|
|
88
|
+
except (json.JSONDecodeError, OSError, MapParseError) as e:
|
|
89
|
+
warnings.append(f"Failed to load nodes: {e}")
|
|
90
|
+
break
|
|
91
|
+
|
|
69
92
|
return cls(parsed, surfaces, resolved_paths, warnings, map_path=p)
|
|
70
93
|
|
|
71
94
|
def _build_path_index(self) -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tilemap-parser
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.8
|
|
4
4
|
Summary: Standalone parser/loader for tilemap-editor JSON maps, sprite animations, and collision detection runtime.
|
|
5
5
|
Author: tilemap parser contributors
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -12,8 +12,10 @@ src/tilemap_parser/parser/animation.py
|
|
|
12
12
|
src/tilemap_parser/parser/collision.py
|
|
13
13
|
src/tilemap_parser/parser/collision_loader.py
|
|
14
14
|
src/tilemap_parser/parser/map_parse.py
|
|
15
|
+
src/tilemap_parser/parser/node_parse.py
|
|
15
16
|
src/tilemap_parser/runtime/__init__.py
|
|
16
17
|
src/tilemap_parser/runtime/animation_player.py
|
|
18
|
+
src/tilemap_parser/runtime/area_node.py
|
|
17
19
|
src/tilemap_parser/runtime/collision_cache.py
|
|
18
20
|
src/tilemap_parser/runtime/map_loader.py
|
|
19
21
|
src/tilemap_parser/runtime/object_collision.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser/runtime/object_collision.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tilemap_parser-3.1.6 → tilemap_parser-3.1.8}/src/tilemap_parser.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|