tilemap-parser 3.1.22__tar.gz → 4.0.0__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.22 → tilemap_parser-4.0.0}/PKG-INFO +1 -1
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/pyproject.toml +1 -1
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/map_loader.py +83 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser.egg-info/PKG-INFO +1 -1
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_map_loader.py +81 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/LICENSE +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/README.md +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/setup.cfg +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/__init__.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/parser/__init__.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/parser/animation.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/parser/collision.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/parser/collision_loader.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/parser/map_parse.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/parser/node_parse.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/parser/particle.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/__init__.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/animation_player.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/area_node.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/camera.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/collision_cache.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/object_collision.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/particles.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/renderer.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/tile_collision.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/utils/__init__.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/utils/geometry.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser.egg-info/SOURCES.txt +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser.egg-info/dependency_links.txt +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser.egg-info/requires.txt +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser.egg-info/top_level.txt +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_camera.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_collision.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_geometry.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_integration_animation.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_integration_collision.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_integration_map_loader.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_move_grounded.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_object_collision.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_object_surfaces.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_particle_emitter.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/tests/test_render_scale.py +0 -0
- {tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/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
|
+
Version: 4.0.0
|
|
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 = "
|
|
7
|
+
version = "4.0.0"
|
|
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"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
import math
|
|
4
5
|
from copy import deepcopy
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import Dict, List, Optional, Tuple, Union
|
|
@@ -31,6 +32,8 @@ class TilemapData:
|
|
|
31
32
|
self.resolved_paths = resolved_paths
|
|
32
33
|
self.warnings = warnings
|
|
33
34
|
self.map_path = map_path
|
|
35
|
+
# Pixel/world offset applied while normalizing negative source coordinates.
|
|
36
|
+
self.origin_offset = (0, 0)
|
|
34
37
|
self.area_nodes: List[AreaNode] = []
|
|
35
38
|
self.particle_emitters: List[ParticleEmitterNode] = []
|
|
36
39
|
self._tw, self._th = parsed.meta.tile_size
|
|
@@ -98,7 +101,9 @@ class TilemapData:
|
|
|
98
101
|
warnings.append(f"Failed to load nodes: {e}")
|
|
99
102
|
break
|
|
100
103
|
|
|
104
|
+
origin_offset = _normalize_origin(parsed)
|
|
101
105
|
result = cls(parsed, surfaces, resolved_paths, warnings, map_path=p)
|
|
106
|
+
result.origin_offset = origin_offset
|
|
102
107
|
result.area_nodes = [AreaNode(n) for n in parsed.nodes if n.node_type == "area"]
|
|
103
108
|
result.particle_emitters = [
|
|
104
109
|
ParticleEmitterNode(n) for n in parsed.nodes if n.node_type == "particle_emitter"
|
|
@@ -312,5 +317,83 @@ def _resolve_resource_path(path_str: str, map_dir: Path, extra_search_base: Opti
|
|
|
312
317
|
return candidate
|
|
313
318
|
|
|
314
319
|
|
|
320
|
+
def _normalize_origin(parsed: ParsedMap) -> Tuple[int, int]:
|
|
321
|
+
tw, th = parsed.meta.tile_size
|
|
322
|
+
rs = parsed.meta.render_scale
|
|
323
|
+
eff_w = int(tw * rs)
|
|
324
|
+
eff_h = int(th * rs)
|
|
325
|
+
if eff_w <= 0 or eff_h <= 0:
|
|
326
|
+
return (0, 0)
|
|
327
|
+
|
|
328
|
+
min_x = 0
|
|
329
|
+
min_y = 0
|
|
330
|
+
max_x = parsed.meta.map_size[0]
|
|
331
|
+
max_y = parsed.meta.map_size[1]
|
|
332
|
+
|
|
333
|
+
for layer in parsed.layers:
|
|
334
|
+
for x, y in layer.tiles.keys():
|
|
335
|
+
min_x = min(min_x, x)
|
|
336
|
+
min_y = min(min_y, y)
|
|
337
|
+
max_x = max(max_x, x + 1)
|
|
338
|
+
max_y = max(max_y, y + 1)
|
|
339
|
+
|
|
340
|
+
for obj in layer.objects.values():
|
|
341
|
+
left = math.floor(obj.area.x / eff_w)
|
|
342
|
+
top = math.floor(obj.area.y / eff_h)
|
|
343
|
+
right = math.ceil((obj.area.x + obj.area.w) / eff_w)
|
|
344
|
+
bottom = math.ceil((obj.area.y + obj.area.h) / eff_h)
|
|
345
|
+
min_x = min(min_x, left)
|
|
346
|
+
min_y = min(min_y, top)
|
|
347
|
+
max_x = max(max_x, right)
|
|
348
|
+
max_y = max(max_y, bottom)
|
|
349
|
+
|
|
350
|
+
for node in parsed.nodes:
|
|
351
|
+
left = math.floor(node.area.x / eff_w)
|
|
352
|
+
top = math.floor(node.area.y / eff_h)
|
|
353
|
+
right = math.ceil((node.area.x + node.area.w) / eff_w)
|
|
354
|
+
bottom = math.ceil((node.area.y + node.area.h) / eff_h)
|
|
355
|
+
min_x = min(min_x, left)
|
|
356
|
+
min_y = min(min_y, top)
|
|
357
|
+
max_x = max(max_x, right)
|
|
358
|
+
max_y = max(max_y, bottom)
|
|
359
|
+
|
|
360
|
+
if min_x >= 0 and min_y >= 0:
|
|
361
|
+
parsed.meta.map_size = (max_x, max_y)
|
|
362
|
+
return (0, 0)
|
|
363
|
+
|
|
364
|
+
shift_x = -min_x
|
|
365
|
+
shift_y = -min_y
|
|
366
|
+
pixel_shift_x = shift_x * eff_w
|
|
367
|
+
pixel_shift_y = shift_y * eff_h
|
|
368
|
+
|
|
369
|
+
for layer in parsed.layers:
|
|
370
|
+
if layer.tiles:
|
|
371
|
+
shifted_tiles = {}
|
|
372
|
+
for (x, y), tile in layer.tiles.items():
|
|
373
|
+
new_pos = (x + shift_x, y + shift_y)
|
|
374
|
+
tile.pos = new_pos
|
|
375
|
+
shifted_tiles[new_pos] = tile
|
|
376
|
+
layer.tiles = shifted_tiles
|
|
377
|
+
|
|
378
|
+
for obj in layer.objects.values():
|
|
379
|
+
obj.area.x += pixel_shift_x
|
|
380
|
+
obj.area.y += pixel_shift_y
|
|
381
|
+
|
|
382
|
+
for node in parsed.nodes:
|
|
383
|
+
node.area.x += pixel_shift_x
|
|
384
|
+
node.area.y += pixel_shift_y
|
|
385
|
+
|
|
386
|
+
parsed.meta.map_size = (max_x + shift_x, max_y + shift_y)
|
|
387
|
+
parsed.meta.initial_map_size = (
|
|
388
|
+
parsed.meta.initial_map_size[0] + shift_x,
|
|
389
|
+
parsed.meta.initial_map_size[1] + shift_y,
|
|
390
|
+
)
|
|
391
|
+
parsed.meta.scroll = (
|
|
392
|
+
parsed.meta.scroll[0] + pixel_shift_x,
|
|
393
|
+
parsed.meta.scroll[1] + pixel_shift_y,
|
|
394
|
+
)
|
|
395
|
+
return (pixel_shift_x, pixel_shift_y)
|
|
396
|
+
|
|
397
|
+
|
|
315
398
|
def load_map(path: PathLike, *, extra_search_base: Optional[Path] = None, skip_missing_images: bool = True, nodes_dir: Optional[PathLike] = None) -> TilemapData:
|
|
316
399
|
return TilemapData.load(path, extra_search_base=extra_search_base, skip_missing_images=skip_missing_images, nodes_dir=nodes_dir)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tilemap-parser
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
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
|
|
@@ -114,6 +114,87 @@ class TestTilemapDataLoad:
|
|
|
114
114
|
assert td.resolved_paths[0] == png.resolve()
|
|
115
115
|
assert td.surfaces[0] is not None
|
|
116
116
|
|
|
117
|
+
def test_negative_coordinates_normalized_to_zero_origin(self, tmp_project):
|
|
118
|
+
tmp, data_dir, assets_dir = tmp_project
|
|
119
|
+
payload = {
|
|
120
|
+
"meta": {
|
|
121
|
+
"tile_size": "16;16",
|
|
122
|
+
"map_size": "4;4",
|
|
123
|
+
"initial_map_size": "4;4",
|
|
124
|
+
"render_scale": 2,
|
|
125
|
+
"scroll": "-64;-32",
|
|
126
|
+
"version": "1.1",
|
|
127
|
+
},
|
|
128
|
+
"resources": {"tilesets": []},
|
|
129
|
+
"project_state": {"rules": [], "groups": []},
|
|
130
|
+
"data": {
|
|
131
|
+
"layers": [
|
|
132
|
+
{
|
|
133
|
+
"name": "Terrain",
|
|
134
|
+
"type": "tile",
|
|
135
|
+
"visible": True,
|
|
136
|
+
"locked": False,
|
|
137
|
+
"opacity": 1.0,
|
|
138
|
+
"z_index": 0,
|
|
139
|
+
"tiles": {
|
|
140
|
+
"-2;-1": {"pos": "-2;-1", "ttype": 0, "variant": 1},
|
|
141
|
+
"1;0": {"pos": "1;0", "ttype": 0, "variant": 2},
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"name": "Objects",
|
|
146
|
+
"type": "object",
|
|
147
|
+
"visible": True,
|
|
148
|
+
"locked": False,
|
|
149
|
+
"opacity": 1.0,
|
|
150
|
+
"z_index": 1,
|
|
151
|
+
"tiles": {},
|
|
152
|
+
"objects": {
|
|
153
|
+
"1": {
|
|
154
|
+
"area": {"x": -8, "y": -20, "w": 16, "h": 16},
|
|
155
|
+
"ttype": 0,
|
|
156
|
+
"tileset_type": "object",
|
|
157
|
+
"variant": 0,
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
]
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
map_path = data_dir / "test_map.json"
|
|
165
|
+
with open(map_path, "w") as f:
|
|
166
|
+
json.dump(payload, f, indent=2)
|
|
167
|
+
nodes_path = data_dir / "test_map.nodes.json"
|
|
168
|
+
with open(nodes_path, "w") as f:
|
|
169
|
+
json.dump(
|
|
170
|
+
{
|
|
171
|
+
"nodes": [
|
|
172
|
+
{
|
|
173
|
+
"node_id": "pe_neg",
|
|
174
|
+
"name": "Mist",
|
|
175
|
+
"node_type": "particle_emitter",
|
|
176
|
+
"area": {"x": -40, "y": 0, "w": 16, "h": 16},
|
|
177
|
+
"layer_name": "fx",
|
|
178
|
+
"properties": {},
|
|
179
|
+
"group": "",
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
"groups": [],
|
|
183
|
+
},
|
|
184
|
+
f,
|
|
185
|
+
indent=2,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
td = TilemapData.load(map_path)
|
|
189
|
+
|
|
190
|
+
assert td.origin_offset == (64, 32)
|
|
191
|
+
assert td.map_size == (6, 5)
|
|
192
|
+
assert td.get_tile_at("Terrain", 0, 0).variant == 1
|
|
193
|
+
assert td.get_tile_at("Terrain", 3, 1).variant == 2
|
|
194
|
+
obj = td.get_layer("Objects").objects[1]
|
|
195
|
+
assert (obj.area.x, obj.area.y) == (56, 12)
|
|
196
|
+
assert td.particle_emitters[0].rect == Rect(24, 32, 16, 16)
|
|
197
|
+
|
|
117
198
|
|
|
118
199
|
MINIMAL_NODES = {
|
|
119
200
|
"nodes": [
|
|
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.22 → tilemap_parser-4.0.0}/src/tilemap_parser/parser/collision_loader.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/animation_player.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/collision_cache.py
RENAMED
|
File without changes
|
{tilemap_parser-3.1.22 → tilemap_parser-4.0.0}/src/tilemap_parser/runtime/object_collision.py
RENAMED
|
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.22 → tilemap_parser-4.0.0}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|