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
+8 -1
View File
@@ -103,7 +103,7 @@ pub fn spawn_log_cargo(
Transform::from_translation(Vec3::new(
drop_pos.x 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)),
Visibility::Visible,
@@ -111,6 +111,13 @@ pub fn spawn_log_cargo(
))
.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
.place_cargo(drop_pos, entity)
.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.
// Don't interrupt a dorf still carrying cargo.
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() {
considered += 1;
if !is_idle_dorf(&queue, &state) {
rejected_busy += 1;
continue;
}
// Skip dorfs still carrying cargo
@@ -149,6 +155,7 @@ pub fn demo_system(
.map(|h| h.is_occupied())
.unwrap_or(false)
{
rejected_hauling += 1;
continue;
}
let pos = transform.translation.as_ivec3();
@@ -161,6 +168,10 @@ pub fn demo_system(
}
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
};
@@ -181,8 +192,8 @@ pub fn demo_system(
};
info!(
"Demo: assigned ChopTree at {:?} to dorf {:?}",
lowest_trunk, chopper
"[DEMO] → Chopping: chopper={:?} trunk={:?}",
chopper, lowest_trunk
);
}
@@ -193,21 +204,24 @@ pub fn demo_system(
// Check if the tree has been felled (fixture gone from tilemap)
if tilemap.fixture_tiles.contains_key(&trunk_pos) {
// 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(
false,
|t| matches!(t, Task::ChopTree { trunk_pos: tp, .. } if *tp == trunk_pos),
);
if !still_chopping && queue.is_empty() {
*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;
}
// 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
let search_world = LOG_SEARCH_RADIUS_TILES * ITILE_SIZE;
@@ -230,7 +244,7 @@ pub fn demo_system(
logs.sort_by_key(|(_, _, dist)| *dist);
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;
return;
}
@@ -239,11 +253,7 @@ pub fn demo_system(
let unassigned: VecDeque<(Entity, IVec3)> =
logs.into_iter().map(|(e, pos, _)| (e, pos)).collect();
info!(
"Demo: {} logs to haul from {:?}",
unassigned.len(),
trunk_pos
);
info!("[DEMO] → Hauling: {} logs queued", unassigned.len());
*demo_state = DemoState::Hauling {
felled_trunk_pos: trunk_pos,
@@ -324,6 +334,10 @@ pub fn demo_system(
});
*state = TaskState::Pending;
in_progress.insert(dorf_entity);
info!(
"[DEMO] assigned HaulCargo log={:?} → dorf={:?} dest={:?}",
log_entity, dorf_entity, dest
);
} else {
// Couldn't assign — put log back at front of queue
unassigned.push_front((log_entity, log_pos));
@@ -334,10 +348,7 @@ pub fn demo_system(
// Check if all work is done
if unassigned.is_empty() && in_progress.is_empty() {
info!(
"Demo: all logs hauled from {:?}, finding next tree",
felled_trunk_pos
);
info!("[DEMO] → Idle: all hauled, seeking next tree");
*demo_state = DemoState::Idle;
}
}
@@ -356,3 +367,28 @@ fn is_idle_dorf(queue: &TaskQueue, state: &TaskState) -> bool {
.current()
.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 demo::{demo_system, DemoState};
#[cfg(debug_assertions)]
pub use demo::debug_task_queues;
pub use events::{TaskBlocked, TaskClaimed, TaskCompleted, TaskDropped, TaskFailed};
pub use executor::task_executor_system;
+8
View File
@@ -3,6 +3,7 @@
//! Systems:
//! - task_executor_system (FixedUpdate)
//! - demo_system (FixedUpdate, after task_executor_system)
//! - debug_task_queues (FixedUpdate, after demo_system, debug only)
use crate::entities::tasks::{
demo_system, task_executor_system, DemoState, TaskBlocked, TaskClaimed, TaskCompleted,
@@ -24,5 +25,12 @@ impl Plugin for TasksPlugin {
bevy::app::FixedUpdate,
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));
}
}
}