Phase 1: Safety & performance foundation for Grid/Entity overhaul
- Fix Entity3D self-reference cycle: replace raw `self` pointer with `pyobject` strong-ref pattern matching UIEntity (closes #266) - TileLayer inherits Grid texture when none set, in all three attachment paths: constructor, add_layer(), and .grid property (closes #254) - Add SpatialHash::queryCell() for O(1) entity-at-cell lookup; fix missing spatial_hash.insert() in Entity.__init__ grid= kwarg path; use queryCell in GridPoint.entities (closes #253) - Add FOV dirty flag and parameter cache to skip redundant computeFOV calls when map unchanged and params match (closes #292) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
836a0584df
commit
94f5f5a3fd
13 changed files with 436 additions and 47 deletions
73
tests/regression/issue_253_spatial_hash_test.py
Normal file
73
tests/regression/issue_253_spatial_hash_test.py
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
"""Regression test for #253: GridPoint.entities uses spatial hash for O(1) lookup."""
|
||||
import mcrfpy
|
||||
import sys
|
||||
|
||||
def test_gridpoint_entities_basic():
|
||||
"""Entities at known positions are returned correctly."""
|
||||
scene = mcrfpy.Scene("test253")
|
||||
mcrfpy.current_scene = scene
|
||||
|
||||
tex = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16)
|
||||
grid = mcrfpy.Grid(grid_size=(20, 20), texture=tex, pos=(0, 0), size=(320, 320))
|
||||
scene.children.append(grid)
|
||||
|
||||
# Place entities at specific cells
|
||||
e1 = mcrfpy.Entity((5, 5), grid=grid)
|
||||
e2 = mcrfpy.Entity((5, 5), grid=grid)
|
||||
e3 = mcrfpy.Entity((10, 10), grid=grid)
|
||||
|
||||
# Query cell (5, 5) - should have 2 entities
|
||||
cell_5_5 = grid.at(5, 5)
|
||||
ents = cell_5_5.entities
|
||||
assert len(ents) == 2, f"Expected 2 entities at (5,5), got {len(ents)}"
|
||||
print("PASS: 2 entities at (5,5)")
|
||||
|
||||
# Query cell (10, 10) - should have 1 entity
|
||||
cell_10_10 = grid.at(10, 10)
|
||||
ents = cell_10_10.entities
|
||||
assert len(ents) == 1, f"Expected 1 entity at (10,10), got {len(ents)}"
|
||||
print("PASS: 1 entity at (10,10)")
|
||||
|
||||
def test_gridpoint_entities_empty():
|
||||
"""Empty cells return empty list."""
|
||||
scene = mcrfpy.Scene("test253b")
|
||||
mcrfpy.current_scene = scene
|
||||
|
||||
tex = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16)
|
||||
grid = mcrfpy.Grid(grid_size=(20, 20), texture=tex, pos=(0, 0), size=(320, 320))
|
||||
scene.children.append(grid)
|
||||
|
||||
# No entities placed - empty cell should return empty list
|
||||
cell = grid.at(0, 0)
|
||||
ents = cell.entities
|
||||
assert len(ents) == 0, f"Expected 0 entities, got {len(ents)}"
|
||||
print("PASS: empty cell returns empty list")
|
||||
|
||||
def test_gridpoint_entities_after_move():
|
||||
"""Moving an entity updates spatial hash so GridPoint.entities reflects new position."""
|
||||
scene = mcrfpy.Scene("test253c")
|
||||
mcrfpy.current_scene = scene
|
||||
|
||||
tex = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16)
|
||||
grid = mcrfpy.Grid(grid_size=(20, 20), texture=tex, pos=(0, 0), size=(320, 320))
|
||||
scene.children.append(grid)
|
||||
|
||||
e = mcrfpy.Entity((3, 3), grid=grid)
|
||||
|
||||
# Verify entity is at (3, 3)
|
||||
assert len(grid.at(3, 3).entities) == 1, "Entity should be at (3,3)"
|
||||
|
||||
# Move entity to (7, 7)
|
||||
e.grid_pos = (7, 7)
|
||||
|
||||
# Old cell should be empty, new cell should have the entity
|
||||
assert len(grid.at(3, 3).entities) == 0, "Old cell should be empty after move"
|
||||
assert len(grid.at(7, 7).entities) == 1, "New cell should have entity after move"
|
||||
print("PASS: entity move updates spatial hash correctly")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_gridpoint_entities_basic()
|
||||
test_gridpoint_entities_empty()
|
||||
test_gridpoint_entities_after_move()
|
||||
print("All #253 tests passed")
|
||||
sys.exit(0)
|
||||
Loading…
Add table
Add a link
Reference in a new issue