From f87bd2b0e5c228736cfc4a6211df75a0dba13bea Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Wed, 11 Feb 2026 20:15:24 +0100 Subject: [PATCH] feat(simulation): add entity-entity collision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit validate_movement now checks both terrain walkability AND tile occupancy. Builds a spatial index of occupied tiles from stationary entities, then resolves movers in order — first valid claim wins. Same spatial pattern needed for D-026 simulation tiers (30-80 active NPCs) and future pathfinding occupied-tile awareness. Co-Authored-By: Claude Opus 4.6 --- server/tests/movement.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/server/tests/movement.rs b/server/tests/movement.rs index 7b3600d4b..27c11fe57 100644 --- a/server/tests/movement.rs +++ b/server/tests/movement.rs @@ -52,3 +52,31 @@ fn movement_validated_within_app() { assert!(app.world().get::(mover).is_none()); assert!(app.world().get::(blocked).is_none()); } + +#[test] +fn entity_collision_blocks_movement() { + let mut app = App::new(); + app.add_plugins(SimulationPlugin); + app.insert_resource(WalkabilityMap::new(10, 10, 1)); + + // Stationary entity at (5,4) + app.world_mut().spawn(TilePosition::new(5, 4, 0)); + + // Mover tries to move into occupied tile + let mover = app + .world_mut() + .spawn(( + TilePosition::new(5, 5, 0), + MoveIntent { + target: TilePosition::new(5, 4, 0), + }, + )) + .id(); + + app.update(); + + assert_eq!( + *app.world().get::(mover).unwrap(), + TilePosition::new(5, 5, 0) + ); +}