This commit is contained in:
2026-03-22 16:38:54 +00:00
parent e7a43457a3
commit 738f595f67
5 changed files with 73 additions and 20 deletions
+4 -4
View File
@@ -1,9 +1,9 @@
initial_chunk_radius = 10 initial_chunk_radius = 6
[display] [display]
vsync = "mailbox" vsync = "mailbox"
[spawn_counts] [spawn_counts]
dorfs = 50 dorfs = 2
pigs = 5 pigs = 0
rabbits = 5 rabbits = 0
+8 -1
View File
@@ -103,7 +103,7 @@ pub fn spawn_log_cargo(
Transform::from_translation(Vec3::new( Transform::from_translation(Vec3::new(
drop_pos.x as f32, drop_pos.x as f32,
drop_pos.y as f32, drop_pos.y as f32,
drop_pos.z as f32 + ITEM_Z_FIGHTING_OFFSET, drop_pos.z as f32 - ITEM_Z_FIGHTING_OFFSET,
)) ))
.with_scale(Vec3::splat(PIXEL_RATIO)), .with_scale(Vec3::splat(PIXEL_RATIO)),
Visibility::Visible, Visibility::Visible,
@@ -111,6 +111,13 @@ pub fn spawn_log_cargo(
)) ))
.id(); .id();
info!(
"spawn_log_cargo: tile_pos={:?} drop_pos={:?} entity_z={}",
tile_pos,
drop_pos,
drop_pos.z as f32 / 16.0 - 1.0
);
tilemap tilemap
.place_cargo(drop_pos, entity) .place_cargo(drop_pos, entity)
.expect("place_cargo failed after find_nearest_free_cargo_tile succeeded"); .expect("place_cargo failed after find_nearest_free_cargo_tile succeeded");
+51 -15
View File
@@ -139,8 +139,14 @@ pub fn demo_system(
// Find one idle dorf — prefer closest to the tree. // Find one idle dorf — prefer closest to the tree.
// Don't interrupt a dorf still carrying cargo. // Don't interrupt a dorf still carrying cargo.
let mut best_dorf: Option<(Entity, i32)> = None; let mut best_dorf: Option<(Entity, i32)> = None;
let mut considered = 0u32;
let mut rejected_busy = 0u32;
let mut rejected_hauling = 0u32;
for (entity, queue, state, transform) in dorf_query.iter() { for (entity, queue, state, transform) in dorf_query.iter() {
considered += 1;
if !is_idle_dorf(&queue, &state) { if !is_idle_dorf(&queue, &state) {
rejected_busy += 1;
continue; continue;
} }
// Skip dorfs still carrying cargo // Skip dorfs still carrying cargo
@@ -149,6 +155,7 @@ pub fn demo_system(
.map(|h| h.is_occupied()) .map(|h| h.is_occupied())
.unwrap_or(false) .unwrap_or(false)
{ {
rejected_hauling += 1;
continue; continue;
} }
let pos = transform.translation.as_ivec3(); let pos = transform.translation.as_ivec3();
@@ -161,6 +168,10 @@ pub fn demo_system(
} }
let Some((chopper, _)) = best_dorf else { let Some((chopper, _)) = best_dorf else {
info!(
"[DEMO] No idle dorf found for ChopTree (considered={} busy={} hauling={})",
considered, rejected_busy, rejected_hauling
);
return; // no idle dorfs available return; // no idle dorfs available
}; };
@@ -181,8 +192,8 @@ pub fn demo_system(
}; };
info!( info!(
"Demo: assigned ChopTree at {:?} to dorf {:?}", "[DEMO] → Chopping: chopper={:?} trunk={:?}",
lowest_trunk, chopper chopper, lowest_trunk
); );
} }
@@ -193,21 +204,24 @@ pub fn demo_system(
// Check if the tree has been felled (fixture gone from tilemap) // Check if the tree has been felled (fixture gone from tilemap)
if tilemap.fixture_tiles.contains_key(&trunk_pos) { if tilemap.fixture_tiles.contains_key(&trunk_pos) {
// Still standing — check chopper hasn't abandoned the task // Still standing — check chopper hasn't abandoned the task
if let Ok((_, queue, _, _)) = dorf_query.get(chopper) { if let Ok((_, queue, state, _)) = dorf_query.get(chopper) {
let still_chopping = queue.current().map_or( let still_chopping = queue.current().map_or(
false, false,
|t| matches!(t, Task::ChopTree { trunk_pos: tp, .. } if *tp == trunk_pos), |t| matches!(t, Task::ChopTree { trunk_pos: tp, .. } if *tp == trunk_pos),
); );
if !still_chopping && queue.is_empty() { if !still_chopping && queue.is_empty() {
*demo_state = DemoState::Idle; *demo_state = DemoState::Idle;
warn!("Demo: chopper {:?} abandoned ChopTree — resetting", chopper); warn!("[DEMO] chopper {:?} abandoned ChopTree at {:?} — queue={:?} state={:?}",
chopper, trunk_pos,
queue.current().map(|t| t.name()),
state);
} }
} }
return; return;
} }
// Tree is felled — transition to Hauling // Tree is felled — transition to Hauling
info!("Demo: tree at {:?} felled, assigning haul tasks", trunk_pos); info!("[DEMO] → Hauling: tree at {:?} felled", trunk_pos);
// Find all Cargo logs near the trunk position // Find all Cargo logs near the trunk position
let search_world = LOG_SEARCH_RADIUS_TILES * ITILE_SIZE; let search_world = LOG_SEARCH_RADIUS_TILES * ITILE_SIZE;
@@ -230,7 +244,7 @@ pub fn demo_system(
logs.sort_by_key(|(_, _, dist)| *dist); logs.sort_by_key(|(_, _, dist)| *dist);
if logs.is_empty() { if logs.is_empty() {
warn!("Demo: no logs found after felling {:?}", trunk_pos); warn!("[DEMO] no logs found after felling {:?}", trunk_pos);
*demo_state = DemoState::Idle; *demo_state = DemoState::Idle;
return; return;
} }
@@ -239,11 +253,7 @@ pub fn demo_system(
let unassigned: VecDeque<(Entity, IVec3)> = let unassigned: VecDeque<(Entity, IVec3)> =
logs.into_iter().map(|(e, pos, _)| (e, pos)).collect(); logs.into_iter().map(|(e, pos, _)| (e, pos)).collect();
info!( info!("[DEMO] → Hauling: {} logs queued", unassigned.len());
"Demo: {} logs to haul from {:?}",
unassigned.len(),
trunk_pos
);
*demo_state = DemoState::Hauling { *demo_state = DemoState::Hauling {
felled_trunk_pos: trunk_pos, felled_trunk_pos: trunk_pos,
@@ -324,6 +334,10 @@ pub fn demo_system(
}); });
*state = TaskState::Pending; *state = TaskState::Pending;
in_progress.insert(dorf_entity); in_progress.insert(dorf_entity);
info!(
"[DEMO] assigned HaulCargo log={:?} → dorf={:?} dest={:?}",
log_entity, dorf_entity, dest
);
} else { } else {
// Couldn't assign — put log back at front of queue // Couldn't assign — put log back at front of queue
unassigned.push_front((log_entity, log_pos)); unassigned.push_front((log_entity, log_pos));
@@ -334,10 +348,7 @@ pub fn demo_system(
// Check if all work is done // Check if all work is done
if unassigned.is_empty() && in_progress.is_empty() { if unassigned.is_empty() && in_progress.is_empty() {
info!( info!("[DEMO] → Idle: all hauled, seeking next tree");
"Demo: all logs hauled from {:?}, finding next tree",
felled_trunk_pos
);
*demo_state = DemoState::Idle; *demo_state = DemoState::Idle;
} }
} }
@@ -356,3 +367,28 @@ fn is_idle_dorf(queue: &TaskQueue, state: &TaskState) -> bool {
.current() .current()
.map_or(true, |t| matches!(t, Task::Idle { .. })) .map_or(true, |t| matches!(t, Task::Idle { .. }))
} }
/// Debug system — prints full task queue state whenever any TaskQueue changes.
/// Only compiles in debug builds.
#[cfg(debug_assertions)]
pub fn debug_task_queues(query: Query<(Entity, &TaskQueue, &TaskState), Changed<TaskQueue>>) {
for (entity, queue, state) in query.iter() {
let current = queue
.current()
.map(|t| format!("{}[{:?}]", t.name(), state))
.unwrap_or_else(|| format!("EMPTY[{:?}]", state));
let pending: Vec<&str> = queue.tasks.iter().skip(1).map(|t| t.name()).collect();
if pending.is_empty() {
info!("[TASK] {:?} → {}", entity, current);
} else {
info!(
"[TASK] {:?} → {} pending:[{}]",
entity,
current,
pending.join(",")
);
}
}
}
+2
View File
@@ -6,6 +6,8 @@ pub mod idle;
pub use components::{IdleState, Task, TaskQueue, TaskState}; pub use components::{IdleState, Task, TaskQueue, TaskState};
pub use demo::{demo_system, DemoState}; pub use demo::{demo_system, DemoState};
#[cfg(debug_assertions)]
pub use demo::debug_task_queues;
pub use events::{TaskBlocked, TaskClaimed, TaskCompleted, TaskDropped, TaskFailed}; pub use events::{TaskBlocked, TaskClaimed, TaskCompleted, TaskDropped, TaskFailed};
pub use executor::task_executor_system; pub use executor::task_executor_system;
+8
View File
@@ -3,6 +3,7 @@
//! Systems: //! Systems:
//! - task_executor_system (FixedUpdate) //! - task_executor_system (FixedUpdate)
//! - demo_system (FixedUpdate, after task_executor_system) //! - demo_system (FixedUpdate, after task_executor_system)
//! - debug_task_queues (FixedUpdate, after demo_system, debug only)
use crate::entities::tasks::{ use crate::entities::tasks::{
demo_system, task_executor_system, DemoState, TaskBlocked, TaskClaimed, TaskCompleted, demo_system, task_executor_system, DemoState, TaskBlocked, TaskClaimed, TaskCompleted,
@@ -24,5 +25,12 @@ impl Plugin for TasksPlugin {
bevy::app::FixedUpdate, bevy::app::FixedUpdate,
demo_system.after(task_executor_system), demo_system.after(task_executor_system),
); );
// Debug only — compiles away in release
#[cfg(debug_assertions)]
{
use crate::entities::tasks::debug_task_queues;
app.add_systems(bevy::app::FixedUpdate, debug_task_queues.after(demo_system));
}
} }
} }