diff --git a/src/entities/sentient/dorf.rs b/src/entities/sentient/dorf.rs index 7f1340d..60f2bbf 100644 --- a/src/entities/sentient/dorf.rs +++ b/src/entities/sentient/dorf.rs @@ -99,12 +99,24 @@ pub fn spawn_dorfs( let seed = hasher.finish(); let mut rng = WyRand::seed_from_u64(seed); + use crate::world::chunks::Z_ABOVE; + for _ in 0..config.spawn_counts.dorfs { let raw_x = rng.random_range(-512.0f32..512.0f32); let raw_y = rng.random_range(-512.0f32..512.0f32); let grid_x = (raw_x / TILE_SIZE).round() * TILE_SIZE; let grid_y = (raw_y / TILE_SIZE).round() * TILE_SIZE; - let grid_z = 35.0 * TILE_SIZE; + // Spawn at top of valid world range (Z_ABOVE * TILE_SIZE) + // The movement system will snap/fall them to surface level + let grid_z = Z_ABOVE * TILE_SIZE; + + info!( + "[SPAWN] Dorf spawning at ({}, {}, {}) z_level={}", + grid_x, + grid_y, + grid_z, + grid_z / TILE_SIZE + ); let cit = commands .spawn(Dorf::new(&asset_server, Vec3::new(grid_x, grid_y, grid_z))) diff --git a/src/entities/shared_systems/pathfinding.rs b/src/entities/shared_systems/pathfinding.rs index 7c6809c..4db8c8d 100644 --- a/src/entities/shared_systems/pathfinding.rs +++ b/src/entities/shared_systems/pathfinding.rs @@ -618,13 +618,13 @@ pub fn update_wandering_targets( } pub fn movement( - mut query: Query<(&mut Ambulatory, &mut Transform)>, + mut query: Query<(Entity, &mut Ambulatory, &mut Transform)>, tilemap: Res, occupancy: Res, ) { query .par_iter_mut() - .for_each(|(mut ambulatory, mut transform)| { + .for_each(|(entity, mut ambulatory, mut transform)| { debug!( "[PATH] Moving: target={:?} current={:?}", ambulatory.target, transform.translation @@ -635,8 +635,20 @@ pub fn movement( // Snap them to the top instead of falling through unloaded z-space one // tile per tick. if transform.translation.z > Z_ABOVE as f32 * TILE_SIZE { + info!( + "[MOVEMENT] Entity {:?} above world at z={}, snapping to z={}", + entity, + transform.translation.z, + Z_ABOVE as f32 * TILE_SIZE + ); transform.translation.z = Z_ABOVE as f32 * TILE_SIZE; } else if transform.translation.z > -(Z_BELOW as f32) * TILE_SIZE { + info!( + "[MOVEMENT] Entity {:?} falling at z={}, z_level={}", + entity, + transform.translation.z, + transform.translation.z / TILE_SIZE + ); transform.translation.z -= TILE_SIZE; } ambulatory.current_path = None; diff --git a/src/entities/tasks/job_pathfinding.rs b/src/entities/tasks/job_pathfinding.rs index 0d763db..1d1595a 100644 --- a/src/entities/tasks/job_pathfinding.rs +++ b/src/entities/tasks/job_pathfinding.rs @@ -45,6 +45,10 @@ pub fn job_pathfinding_system( info!("[PATHFIND] Locked dorfs: {:?}", locked_dorfs.len()); } + // Track dorfs assigned jobs in this frame to prevent multiple assignments + let mut assigned_this_frame: std::collections::HashSet = + std::collections::HashSet::new(); + for job_idx in unclaimed.into_iter().take(MAX_JOBS_PER_TICK) { let (kind, state, _) = match job_queue.get_job_at(job_idx) { Some(k) => k, @@ -80,7 +84,7 @@ pub fn job_pathfinding_system( .filter_map(|(entity, queue, state, transform, _)| { total_dorfs += 1; - if locked_dorfs.contains(&entity) { + if locked_dorfs.contains(&entity) || assigned_this_frame.contains(&entity) { locked_count += 1; return None; } @@ -88,6 +92,12 @@ pub fn job_pathfinding_system( let pos = transform.translation.as_ivec3(); if !tilemap.is_standable(pos) { not_standable_count += 1; + info!( + "[PATHFIND] Dorf {:?} NOT STANDABLE at pos={:?} z_level={}", + entity, + pos, + pos.z / crate::constants::ITILE_SIZE + ); return None; } @@ -296,6 +306,7 @@ pub fn job_pathfinding_system( "[PATHFIND] SUCCESS: Assigned job {:?} to dorf {:?} with approach {:?}", job_id, dorf_entity, approach_target ); + assigned_this_frame.insert(dorf_entity); } } } else {