LDtk import support
This commit is contained in:
parent
322beeaf78
commit
de7778b147
24 changed files with 26203 additions and 0 deletions
183
tests/unit/ldtk_apply_test.py
Normal file
183
tests/unit/ldtk_apply_test.py
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
"""Unit tests for LDtk auto-rule apply (resolve + write to TileLayer)."""
|
||||
import mcrfpy
|
||||
import sys
|
||||
|
||||
def test_apply_basic():
|
||||
"""Test applying rules to a TileLayer."""
|
||||
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
|
||||
rs = proj.ruleset("Terrain")
|
||||
ts = proj.tileset("Test_Tileset")
|
||||
texture = ts.to_texture()
|
||||
|
||||
# Create DiscreteMap
|
||||
dm = mcrfpy.DiscreteMap((5, 5), fill=0)
|
||||
for y in range(5):
|
||||
for x in range(5):
|
||||
if x == 0 or x == 4 or y == 0 or y == 4:
|
||||
dm.set(x, y, 1)
|
||||
elif x == 2 and y == 2:
|
||||
dm.set(x, y, 3)
|
||||
else:
|
||||
dm.set(x, y, 2)
|
||||
|
||||
# Create TileLayer and apply
|
||||
layer = mcrfpy.TileLayer(name="terrain", texture=texture, grid_size=(5, 5))
|
||||
rs.apply(dm, layer, seed=0)
|
||||
|
||||
# Verify some tiles were written
|
||||
wall_tile = layer.at(0, 0)
|
||||
assert wall_tile == 0, f"Expected wall tile 0 at (0,0), got {wall_tile}"
|
||||
|
||||
floor_tile = layer.at(1, 1)
|
||||
assert floor_tile >= 0, f"Expected floor tile at (1,1), got {floor_tile}"
|
||||
|
||||
# Empty cells (water, value=3) should still be -1 (no rule matches water)
|
||||
water_tile = layer.at(2, 2)
|
||||
assert water_tile == -1, f"Expected -1 at water (2,2), got {water_tile}"
|
||||
|
||||
print(f" applied: wall={wall_tile}, floor={floor_tile}, water={water_tile}")
|
||||
|
||||
def test_apply_preserves_unmatched():
|
||||
"""Test that unmatched cells retain their original value."""
|
||||
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
|
||||
rs = proj.ruleset("Terrain")
|
||||
ts = proj.tileset("Test_Tileset")
|
||||
texture = ts.to_texture()
|
||||
|
||||
# Pre-fill layer with a sentinel value
|
||||
layer = mcrfpy.TileLayer(name="test", texture=texture, grid_size=(3, 3))
|
||||
layer.fill(99)
|
||||
|
||||
# Create empty map - no rules will match
|
||||
dm = mcrfpy.DiscreteMap((3, 3), fill=0)
|
||||
rs.apply(dm, layer, seed=0)
|
||||
|
||||
# All cells should still be 99 (no rules matched)
|
||||
for y in range(3):
|
||||
for x in range(3):
|
||||
val = layer.at(x, y)
|
||||
assert val == 99, f"Expected 99 at ({x},{y}), got {val}"
|
||||
print(" unmatched cells preserved: OK")
|
||||
|
||||
def test_apply_type_errors():
|
||||
"""Test that apply raises TypeError for wrong argument types."""
|
||||
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
|
||||
rs = proj.ruleset("Terrain")
|
||||
|
||||
# Wrong first argument type
|
||||
try:
|
||||
rs.apply("not_a_dmap", None, seed=0)
|
||||
assert False, "Should have raised TypeError"
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
# Wrong second argument type
|
||||
dm = mcrfpy.DiscreteMap((3, 3))
|
||||
try:
|
||||
rs.apply(dm, "not_a_layer", seed=0)
|
||||
assert False, "Should have raised TypeError"
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
print(" type errors raised correctly: OK")
|
||||
|
||||
def test_apply_clipping():
|
||||
"""Test that apply clips to the smaller of map/layer dimensions."""
|
||||
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
|
||||
rs = proj.ruleset("Terrain")
|
||||
ts = proj.tileset("Test_Tileset")
|
||||
texture = ts.to_texture()
|
||||
|
||||
# DiscreteMap larger than TileLayer
|
||||
dm = mcrfpy.DiscreteMap((10, 10), fill=1)
|
||||
layer = mcrfpy.TileLayer(name="small", texture=texture, grid_size=(3, 3))
|
||||
layer.fill(-1)
|
||||
|
||||
rs.apply(dm, layer, seed=0)
|
||||
|
||||
# Layer should have tiles written only within its bounds
|
||||
for y in range(3):
|
||||
for x in range(3):
|
||||
val = layer.at(x, y)
|
||||
assert val >= 0, f"Expected tile at ({x},{y}), got {val}"
|
||||
print(" clipping (large map, small layer): OK")
|
||||
|
||||
# DiscreteMap smaller than TileLayer
|
||||
dm2 = mcrfpy.DiscreteMap((2, 2), fill=1)
|
||||
layer2 = mcrfpy.TileLayer(name="big", texture=texture, grid_size=(5, 5))
|
||||
layer2.fill(88)
|
||||
|
||||
rs.apply(dm2, layer2, seed=0)
|
||||
|
||||
# Only (0,0)-(1,1) should be overwritten
|
||||
for y in range(2):
|
||||
for x in range(2):
|
||||
val = layer2.at(x, y)
|
||||
assert val >= 0, f"Expected tile at ({x},{y}), got {val}"
|
||||
|
||||
# (3,3) should still be the fill value
|
||||
assert layer2.at(3, 3) == 88, f"Expected 88 at (3,3), got {layer2.at(3, 3)}"
|
||||
print(" clipping (small map, large layer): OK")
|
||||
|
||||
def test_resolve_type_error():
|
||||
"""Test that resolve raises TypeError for wrong argument."""
|
||||
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
|
||||
rs = proj.ruleset("Terrain")
|
||||
|
||||
try:
|
||||
rs.resolve("not_a_dmap", seed=0)
|
||||
assert False, "Should have raised TypeError"
|
||||
except TypeError:
|
||||
pass
|
||||
print(" resolve TypeError: OK")
|
||||
|
||||
def test_precomputed_tiles():
|
||||
"""Test loading pre-computed auto-layer tiles from a level."""
|
||||
proj = mcrfpy.LdtkProject("../tests/fixtures/test_project.ldtk")
|
||||
ts = proj.tileset("Test_Tileset")
|
||||
texture = ts.to_texture()
|
||||
|
||||
level = proj.level("Level_0")
|
||||
layer_info = level["layers"][0]
|
||||
|
||||
# Create TileLayer and write pre-computed tiles
|
||||
layer = mcrfpy.TileLayer(name="precomp", texture=texture, grid_size=(5, 5))
|
||||
layer.fill(-1)
|
||||
|
||||
for tile in layer_info["auto_tiles"]:
|
||||
x, y = tile["x"], tile["y"]
|
||||
if 0 <= x < 5 and 0 <= y < 5:
|
||||
layer.set((x, y), tile["tile_id"])
|
||||
|
||||
# Verify some tiles were written
|
||||
assert layer.at(0, 0) == 0, f"Expected tile 0 at (0,0), got {layer.at(0, 0)}"
|
||||
print(f" precomputed tiles loaded: first = {layer.at(0, 0)}")
|
||||
|
||||
# Run tests
|
||||
tests = [
|
||||
test_apply_basic,
|
||||
test_apply_preserves_unmatched,
|
||||
test_apply_type_errors,
|
||||
test_apply_clipping,
|
||||
test_resolve_type_error,
|
||||
test_precomputed_tiles,
|
||||
]
|
||||
|
||||
passed = 0
|
||||
failed = 0
|
||||
print("=== LDtk Apply Tests ===")
|
||||
for test in tests:
|
||||
name = test.__name__
|
||||
try:
|
||||
print(f"[TEST] {name}...")
|
||||
test()
|
||||
passed += 1
|
||||
print(f" PASS")
|
||||
except Exception as e:
|
||||
failed += 1
|
||||
print(f" FAIL: {e}")
|
||||
|
||||
print(f"\n=== Results: {passed} passed, {failed} failed ===")
|
||||
if failed > 0:
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
Loading…
Add table
Add a link
Reference in a new issue