feat: soft entity collision, dead code removal, leaf standability fix

- Add TileOccupancy resource and rebuild_tile_occupancy system to track
  per-tile entity counts for soft collision avoidance
- Add collision_delay to Ambulatory; entities try relative-left step on
  occupied tiles, wait 1 tick, then push through
- Fix leaf canopy standability: leaves are now can_stand_in=true,
  can_stand_on=false (walkable, not standable-on)
- Delete FloorTilePrefab / FixtureTilePrefab / FloorTile / FixtureTile /
  TileState (all fully dead — TileMap + ChunkData are sole truth)
- Delete tile_spawns from TerrainBlob (populated but never consumed)
- Delete leaf ghost entity spawn in forestry (orphaned invisible ECS entity)
- Replace log prefab spawn with inline commands.spawn(Transform, Visibility)
- Add TileMap::remove_fixture for future digging/explosion use
- Skip collision avoidance when current tile has >2 entities (handles spawn
  cluster deadlock)
This commit is contained in:
2026-03-21 01:36:38 +00:00
parent 1fe4781bab
commit 90a6196443
25 changed files with 1909 additions and 498 deletions
+1 -10
View File
@@ -9,7 +9,7 @@ use crate::{
constants::{SEED, TILE_SIZE},
world::{
tiles::{ChunkData, FloorTileData, TileMap},
ChunkForrestryEvent, ChunkMap, ChunkTerrainEvent, FloorTilePrefab, TileOcclusionEvent,
ChunkForrestryEvent, ChunkMap, ChunkTerrainEvent, TileOcclusionEvent,
CHUNK_SIZE, Z_ABOVE, Z_BELOW,
},
};
@@ -47,7 +47,6 @@ pub struct TerrainBlob {
pub chunk_data: ChunkData,
pub tile_updates: Vec<(IVec3, FloorTileData)>,
pub surface_positions: Vec<(Vec3, String)>,
pub tile_spawns: Vec<(Vec3, FloorTilePrefab)>,
}
pub fn generate_surface_terrain(x: i32, y: i32) -> f32 {
@@ -75,7 +74,6 @@ fn generate_terrain_blob(chunk_pos: IVec2) -> TerrainBlob {
let mut chunk_data = ChunkData::new(chunk_pos);
let mut tile_updates: Vec<(IVec3, FloorTileData)> = Vec::new();
let mut surface_positions: Vec<(Vec3, String)> = Vec::new();
let mut tile_spawns: Vec<(Vec3, FloorTilePrefab)> = Vec::new();
for local_y in 0..CHUNK_SIZE {
for local_x in 0..CHUNK_SIZE {
@@ -107,7 +105,6 @@ fn generate_terrain_blob(chunk_pos: IVec2) -> TerrainBlob {
]);
if cave_value < -0.75 {
let tile = registry.floor("air");
tile_spawns.push((position, FloorTilePrefab::air(position)));
tile_updates.push((
pos_ivec,
FloorTileData::new(
@@ -130,7 +127,6 @@ fn generate_terrain_blob(chunk_pos: IVec2) -> TerrainBlob {
);
} else if cave_value < 0.8 {
let tile = registry.floor("rock");
tile_spawns.push((position, FloorTilePrefab::rock(position)));
tile_updates.push((
pos_ivec,
FloorTileData::new(
@@ -153,7 +149,6 @@ fn generate_terrain_blob(chunk_pos: IVec2) -> TerrainBlob {
);
} else {
let tile = registry.floor("dirt");
tile_spawns.push((position, FloorTilePrefab::dirt(position)));
tile_updates.push((
pos_ivec,
FloorTileData::new(
@@ -178,7 +173,6 @@ fn generate_terrain_blob(chunk_pos: IVec2) -> TerrainBlob {
} else if noise_position.z > position.z {
if surface_height <= position.z + TILE_SIZE {
let tile = registry.floor("grass");
tile_spawns.push((position, FloorTilePrefab::grass(position)));
tile_updates.push((
pos_ivec,
FloorTileData::new(
@@ -202,7 +196,6 @@ fn generate_terrain_blob(chunk_pos: IVec2) -> TerrainBlob {
surface_positions.push((position, "grass".to_string()));
} else {
let tile = registry.floor("dirt");
tile_spawns.push((position, FloorTilePrefab::dirt(position)));
tile_updates.push((
pos_ivec,
FloorTileData::new(
@@ -226,7 +219,6 @@ fn generate_terrain_blob(chunk_pos: IVec2) -> TerrainBlob {
}
} else {
let tile = registry.floor("air");
tile_spawns.push((position, FloorTilePrefab::air(position)));
tile_updates.push((
pos_ivec,
FloorTileData::new(
@@ -257,7 +249,6 @@ fn generate_terrain_blob(chunk_pos: IVec2) -> TerrainBlob {
chunk_data,
tile_updates,
surface_positions,
tile_spawns,
}
}