Task fix attempt
This commit is contained in:
@@ -49,6 +49,9 @@ pub struct Cargo {
|
|||||||
pub size: u8,
|
pub size: u8,
|
||||||
/// Sprite handle for rendering when on the ground.
|
/// Sprite handle for rendering when on the ground.
|
||||||
pub ground_sprite: Handle<Image>,
|
pub ground_sprite: Handle<Image>,
|
||||||
|
/// True once this cargo has been hauled to its destination.
|
||||||
|
/// Used to prevent re-hauling logs that have already been delivered.
|
||||||
|
pub delivered: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks a Cargo entity as haulable by entities with a HaulSlot.
|
/// Marks a Cargo entity as haulable by entities with a HaulSlot.
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ pub fn spawn_log_cargo(
|
|||||||
weight: LOG_WEIGHT_KG,
|
weight: LOG_WEIGHT_KG,
|
||||||
size: SIZE_LARGE,
|
size: SIZE_LARGE,
|
||||||
ground_sprite: log_sprite.clone(),
|
ground_sprite: log_sprite.clone(),
|
||||||
|
delivered: false,
|
||||||
},
|
},
|
||||||
Haulable,
|
Haulable,
|
||||||
Sprite {
|
Sprite {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ pub mod systems;
|
|||||||
pub use crate::world::tiles::tilemap::CargoPlaceError;
|
pub use crate::world::tiles::tilemap::CargoPlaceError;
|
||||||
pub use components::{Cargo, CarryVisualState, HaulSlot, Haulable};
|
pub use components::{Cargo, CarryVisualState, HaulSlot, Haulable};
|
||||||
pub use log::spawn_log_cargo;
|
pub use log::spawn_log_cargo;
|
||||||
pub use systems::{any_hauling, carry_visual_system, haul_encumbrance_system};
|
pub use systems::{
|
||||||
|
any_hauling, cargo_position_sync_system, carry_visual_system, haul_encumbrance_system,
|
||||||
|
};
|
||||||
|
|
||||||
pub use crate::plugins::cargo::CargoPlugin;
|
pub use crate::plugins::cargo::CargoPlugin;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
//! Cargo systems: carry visual cycling and haul encumbrance.
|
//! Cargo systems: carry visual cycling, position sync, and haul encumbrance.
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
use crate::entities::cargo::components::{CarryVisualState, HaulSlot};
|
use crate::entities::cargo::components::{Cargo, CarryVisualState, HaulSlot};
|
||||||
|
use crate::entities::item::constants::ITEM_Z_FIGHTING_OFFSET;
|
||||||
use crate::entities::item::inventory::constants::ENCUMBERED_SPEED_MULTIPLIER;
|
use crate::entities::item::inventory::constants::ENCUMBERED_SPEED_MULTIPLIER;
|
||||||
use crate::entities::item::inventory::InventoryChangedEvent;
|
use crate::entities::item::inventory::InventoryChangedEvent;
|
||||||
use crate::entities::shared_components::Ambulatory;
|
use crate::entities::shared_components::Ambulatory;
|
||||||
@@ -60,3 +61,16 @@ pub fn haul_encumbrance_system(
|
|||||||
events.write(InventoryChangedEvent { carrier: entity });
|
events.write(InventoryChangedEvent { carrier: entity });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sync cargo visual position when tile_pos changes.
|
||||||
|
/// When cargo is picked up or dropped, tile_pos updates but Transform doesn't.
|
||||||
|
/// This system keeps Transform in sync with the logical position.
|
||||||
|
pub fn cargo_position_sync_system(mut query: Query<(&Cargo, &mut Transform), Changed<Cargo>>) {
|
||||||
|
for (cargo, mut transform) in query.iter_mut() {
|
||||||
|
transform.translation = Vec3::new(
|
||||||
|
cargo.tile_pos.x as f32,
|
||||||
|
cargo.tile_pos.y as f32,
|
||||||
|
cargo.tile_pos.z as f32 - ITEM_Z_FIGHTING_OFFSET,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ pub enum ChopStep {
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum HaulStep {
|
pub enum HaulStep {
|
||||||
/// Walking to the cargo tile.
|
/// Walking to the cargo tile.
|
||||||
MovingToCargo,
|
/// `approach` locks the target to prevent pathfinding stutter.
|
||||||
|
MovingToCargo { approach: Option<IVec3> },
|
||||||
/// At cargo — picking up this tick.
|
/// At cargo — picking up this tick.
|
||||||
PickingUp,
|
PickingUp,
|
||||||
/// Cargo in HaulSlot — walking to destination.
|
/// Cargo in HaulSlot — walking to destination.
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use crate::entities::cargo::{Cargo, HaulSlot, Haulable};
|
|||||||
use crate::entities::tasks::components::{
|
use crate::entities::tasks::components::{
|
||||||
ChopStep, HaulStep, Task, TaskQueue, TaskState, CHOP_TICKS_DEFAULT,
|
ChopStep, HaulStep, Task, TaskQueue, TaskState, CHOP_TICKS_DEFAULT,
|
||||||
};
|
};
|
||||||
use crate::entities::tasks::events::TaskFailed;
|
use crate::entities::tasks::events::{LogsSpawned, TaskFailed};
|
||||||
use crate::world::chunks::ChunkMap;
|
use crate::world::chunks::ChunkMap;
|
||||||
use crate::world::generation::forestry::TreePart;
|
use crate::world::generation::forestry::TreePart;
|
||||||
use crate::world::tiles::TileMap;
|
use crate::world::tiles::TileMap;
|
||||||
@@ -84,6 +84,7 @@ pub fn demo_system(
|
|||||||
haul_slot_query: Query<&HaulSlot>,
|
haul_slot_query: Query<&HaulSlot>,
|
||||||
mut dorf_query: Query<(Entity, &mut TaskQueue, &mut TaskState, &Transform)>,
|
mut dorf_query: Query<(Entity, &mut TaskQueue, &mut TaskState, &Transform)>,
|
||||||
mut task_failed: MessageReader<TaskFailed>,
|
mut task_failed: MessageReader<TaskFailed>,
|
||||||
|
mut logs_spawned: MessageReader<LogsSpawned>,
|
||||||
) {
|
) {
|
||||||
// Handle task failures that should reset the demo state for retry
|
// Handle task failures that should reset the demo state for retry
|
||||||
for event in task_failed.read() {
|
for event in task_failed.read() {
|
||||||
@@ -98,6 +99,35 @@ pub fn demo_system(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle logs spawned from felling — transition to Hauling
|
||||||
|
// Collect events first to avoid double-mutable borrow conflict with demo_state
|
||||||
|
let pending_logs: Vec<_> = logs_spawned.read().collect();
|
||||||
|
for event in pending_logs {
|
||||||
|
if let DemoState::Chopping {
|
||||||
|
trunk_pos,
|
||||||
|
chopper: _,
|
||||||
|
} = *demo_state
|
||||||
|
{
|
||||||
|
// Look up cargo positions from the newly spawned entities
|
||||||
|
let mut unassigned: VecDeque<(Entity, IVec3)> = VecDeque::new();
|
||||||
|
for &log_entity in event.log_entities.iter() {
|
||||||
|
if let Ok((_, cargo)) = cargo_query.get(log_entity) {
|
||||||
|
unassigned.push_back((log_entity, cargo.tile_pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!(
|
||||||
|
"[DEMO] → Hauling: {} logs spawned from tree at {:?}",
|
||||||
|
unassigned.len(),
|
||||||
|
trunk_pos
|
||||||
|
);
|
||||||
|
*demo_state = DemoState::Hauling {
|
||||||
|
felled_trunk_pos: trunk_pos,
|
||||||
|
unassigned,
|
||||||
|
in_progress: Default::default(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match &mut *demo_state {
|
match &mut *demo_state {
|
||||||
DemoState::Idle => {
|
DemoState::Idle => {
|
||||||
// Find the nearest standing tree to (0,0).
|
// Find the nearest standing tree to (0,0).
|
||||||
@@ -345,7 +375,7 @@ pub fn demo_system(
|
|||||||
cargo_entity: log_entity,
|
cargo_entity: log_entity,
|
||||||
cargo_pos: log_pos,
|
cargo_pos: log_pos,
|
||||||
dest,
|
dest,
|
||||||
step: HaulStep::MovingToCargo,
|
step: HaulStep::MovingToCargo { approach: None },
|
||||||
});
|
});
|
||||||
*state = TaskState::Pending;
|
*state = TaskState::Pending;
|
||||||
in_progress.insert(dorf_entity);
|
in_progress.insert(dorf_entity);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
use crate::entities::tasks::components::Task;
|
use crate::entities::tasks::components::Task;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
#[derive(Message, Clone)]
|
#[derive(Message, Clone)]
|
||||||
pub struct TaskClaimed {
|
pub struct TaskClaimed {
|
||||||
@@ -38,3 +39,13 @@ pub struct TaskBlocked {
|
|||||||
pub task: Task,
|
pub task: Task,
|
||||||
pub blocker: &'static str,
|
pub blocker: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fired when logs are spawned from felling a tree.
|
||||||
|
/// The demo listens for this to queue HaulCargo tasks.
|
||||||
|
#[derive(Message, Clone)]
|
||||||
|
pub struct LogsSpawned {
|
||||||
|
/// Entities of the spawned logs.
|
||||||
|
pub log_entities: SmallVec<[Entity; 8]>,
|
||||||
|
/// Destination for hauling (currently origin, later stockpile).
|
||||||
|
pub dest: IVec3,
|
||||||
|
}
|
||||||
|
|||||||
+122
-36
@@ -14,7 +14,7 @@ use crate::entities::shared_components::Ambulatory;
|
|||||||
use crate::entities::tasks::components::{
|
use crate::entities::tasks::components::{
|
||||||
ChopStep, DropStep, HaulStep, IdleState, Task, TaskQueue, TaskState,
|
ChopStep, DropStep, HaulStep, IdleState, Task, TaskQueue, TaskState,
|
||||||
};
|
};
|
||||||
use crate::entities::tasks::events::{TaskClaimed, TaskCompleted, TaskFailed};
|
use crate::entities::tasks::events::{LogsSpawned, TaskClaimed, TaskCompleted, TaskFailed};
|
||||||
use crate::entities::tasks::idle::execute_idle;
|
use crate::entities::tasks::idle::execute_idle;
|
||||||
use crate::world::chunks::ChunkMap;
|
use crate::world::chunks::ChunkMap;
|
||||||
use crate::world::generation::forestry::{fell_tree, TreePart};
|
use crate::world::generation::forestry::{fell_tree, TreePart};
|
||||||
@@ -23,6 +23,7 @@ use crate::world::tiles::visibility::TileOcclusionEvent;
|
|||||||
use crate::world::tiles::TileMap;
|
use crate::world::tiles::TileMap;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_rand::prelude::*;
|
use bevy_rand::prelude::*;
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
/// Main task executor. Runs in FixedUpdate.
|
/// Main task executor. Runs in FixedUpdate.
|
||||||
pub fn task_executor_system(
|
pub fn task_executor_system(
|
||||||
@@ -47,6 +48,7 @@ pub fn task_executor_system(
|
|||||||
mut claimed_writer: MessageWriter<TaskClaimed>,
|
mut claimed_writer: MessageWriter<TaskClaimed>,
|
||||||
mut completed_writer: MessageWriter<TaskCompleted>,
|
mut completed_writer: MessageWriter<TaskCompleted>,
|
||||||
mut failed_writer: MessageWriter<TaskFailed>,
|
mut failed_writer: MessageWriter<TaskFailed>,
|
||||||
|
mut logs_spawned_writer: MessageWriter<LogsSpawned>,
|
||||||
mut tile_changed: MessageWriter<TileChangedEvent>,
|
mut tile_changed: MessageWriter<TileChangedEvent>,
|
||||||
mut occlusion: MessageWriter<TileOcclusionEvent>,
|
mut occlusion: MessageWriter<TileOcclusionEvent>,
|
||||||
) {
|
) {
|
||||||
@@ -241,15 +243,27 @@ pub fn task_executor_system(
|
|||||||
fall_dir = Vec2::new(1.0, 0.0); // default: fall east
|
fall_dir = Vec2::new(1.0, 0.0); // default: fall east
|
||||||
}
|
}
|
||||||
let log_sprite: Handle<Image> = asset_server.load("log_cargo.png");
|
let log_sprite: Handle<Image> = asset_server.load("log_cargo.png");
|
||||||
|
let mut log_entities: SmallVec<[Entity; 8]> = SmallVec::new();
|
||||||
for &pos in trunk_positions.iter() {
|
for &pos in trunk_positions.iter() {
|
||||||
crate::entities::cargo::spawn_log_cargo(
|
if let Some(log_entity) =
|
||||||
&mut commands,
|
crate::entities::cargo::spawn_log_cargo(
|
||||||
&mut tilemap_mut,
|
&mut commands,
|
||||||
pos,
|
&mut tilemap_mut,
|
||||||
fall_dir,
|
pos,
|
||||||
log_sprite.clone(),
|
fall_dir,
|
||||||
&mut rng,
|
log_sprite.clone(),
|
||||||
);
|
&mut rng,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
log_entities.push(log_entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Emit event so demo can queue HaulCargo tasks for these logs
|
||||||
|
if !log_entities.is_empty() {
|
||||||
|
logs_spawned_writer.write(LogsSpawned {
|
||||||
|
log_entities,
|
||||||
|
dest: IVec3::ZERO,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
*step = ChopStep::Done;
|
*step = ChopStep::Done;
|
||||||
} else {
|
} else {
|
||||||
@@ -277,7 +291,9 @@ pub fn task_executor_system(
|
|||||||
};
|
};
|
||||||
|
|
||||||
match step {
|
match step {
|
||||||
HaulStep::MovingToCargo => {
|
HaulStep::MovingToCargo { approach } => {
|
||||||
|
use crate::constants::ITILE_SIZE;
|
||||||
|
|
||||||
if !tilemap_mut.cargo_tiles.contains_key(cargo_pos) {
|
if !tilemap_mut.cargo_tiles.contains_key(cargo_pos) {
|
||||||
failed_writer.write(TaskFailed {
|
failed_writer.write(TaskFailed {
|
||||||
entity,
|
entity,
|
||||||
@@ -287,22 +303,75 @@ pub fn task_executor_system(
|
|||||||
*state = TaskState::Failed;
|
*state = TaskState::Failed;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ambulatory.target.is_none() {
|
|
||||||
ambulatory.target = Some(Vec3::new(
|
if approach.is_none() {
|
||||||
cargo_pos.x as f32,
|
// Search for nearest standable tile to approach cargo.
|
||||||
cargo_pos.y as f32,
|
// Radius 0 = cargo tile itself (can stand in same tile as cargo).
|
||||||
cargo_pos.z as f32 + 1.0,
|
// Radius 1-2 = adjacent tiles if cargo tile is blocked.
|
||||||
));
|
let cargo_z = cargo_pos.z;
|
||||||
ambulatory.current_path = None;
|
let approach_tile = (0..=2i32).find_map(|radius: i32| {
|
||||||
|
for dx in -radius..=radius {
|
||||||
|
for dy in -radius..=radius {
|
||||||
|
if radius > 0
|
||||||
|
&& dx.abs() != radius
|
||||||
|
&& dy.abs() != radius
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let candidate = IVec3::new(
|
||||||
|
cargo_pos.x + dx * ITILE_SIZE,
|
||||||
|
cargo_pos.y + dy * ITILE_SIZE,
|
||||||
|
cargo_z,
|
||||||
|
);
|
||||||
|
if tilemap_mut.is_standable(candidate) {
|
||||||
|
return Some(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
});
|
||||||
|
|
||||||
|
match approach_tile {
|
||||||
|
Some(tile) => {
|
||||||
|
*approach = Some(tile);
|
||||||
|
info!(
|
||||||
|
"[HAUL] {:?} target set: cargo={:?} approach={:?}",
|
||||||
|
entity, cargo_pos, tile
|
||||||
|
);
|
||||||
|
// +1.0 z-offset for entity standing height (same as trees)
|
||||||
|
ambulatory.target = Some(Vec3::new(
|
||||||
|
tile.x as f32,
|
||||||
|
tile.y as f32,
|
||||||
|
tile.z as f32 + 1.0,
|
||||||
|
));
|
||||||
|
ambulatory.current_path = None;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
failed_writer.write(TaskFailed {
|
||||||
|
entity,
|
||||||
|
task: current_task.clone(),
|
||||||
|
reason: "no standable tile near cargo",
|
||||||
|
});
|
||||||
|
*state = TaskState::Failed;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let dx = transform.translation.x - cargo_pos.x as f32;
|
|
||||||
let dy = transform.translation.y - cargo_pos.y as f32;
|
// Check arrival at cargo tile
|
||||||
let dist_sq = dx * dx + dy * dy;
|
if approach.is_some() && ambulatory.target.is_none() {
|
||||||
let pickup_range_sq = (crate::constants::TILE_SIZE * 1.5)
|
let dx = transform.translation.x - cargo_pos.x as f32;
|
||||||
* (crate::constants::TILE_SIZE * 1.5);
|
let dy = transform.translation.y - cargo_pos.y as f32;
|
||||||
if dist_sq <= pickup_range_sq {
|
let dist_sq = dx * dx + dy * dy;
|
||||||
ambulatory.target = None;
|
let pickup_range_sq =
|
||||||
*step = HaulStep::PickingUp;
|
(ITILE_SIZE as f32 * 1.5) * (ITILE_SIZE as f32 * 1.5);
|
||||||
|
if dist_sq <= pickup_range_sq {
|
||||||
|
info!(
|
||||||
|
"[HAUL] {:?} arrived at cargo {:?}, picking up",
|
||||||
|
entity, cargo_entity
|
||||||
|
);
|
||||||
|
*step = HaulStep::PickingUp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HaulStep::PickingUp => {
|
HaulStep::PickingUp => {
|
||||||
@@ -317,6 +386,10 @@ pub fn task_executor_system(
|
|||||||
}
|
}
|
||||||
if let Some(_) = tilemap_mut.remove_cargo(cargo_pos) {
|
if let Some(_) = tilemap_mut.remove_cargo(cargo_pos) {
|
||||||
haul.pick_up(*cargo_entity);
|
haul.pick_up(*cargo_entity);
|
||||||
|
info!(
|
||||||
|
"[HAUL] {:?} picked up {:?} → hauling to {:?}",
|
||||||
|
entity, cargo_entity, dest
|
||||||
|
);
|
||||||
*step = HaulStep::MovingToDest { chosen_drop: None };
|
*step = HaulStep::MovingToDest { chosen_drop: None };
|
||||||
} else {
|
} else {
|
||||||
failed_writer.write(TaskFailed {
|
failed_writer.write(TaskFailed {
|
||||||
@@ -337,6 +410,8 @@ pub fn task_executor_system(
|
|||||||
}
|
}
|
||||||
let drop_pos = chosen_drop.unwrap();
|
let drop_pos = chosen_drop.unwrap();
|
||||||
if ambulatory.target.is_none() {
|
if ambulatory.target.is_none() {
|
||||||
|
info!("[HAUL] {:?} target set: drop at {:?}", entity, drop_pos);
|
||||||
|
// +1.0 z-offset for entity standing height (same as approach)
|
||||||
ambulatory.target = Some(Vec3::new(
|
ambulatory.target = Some(Vec3::new(
|
||||||
drop_pos.x as f32,
|
drop_pos.x as f32,
|
||||||
drop_pos.y as f32,
|
drop_pos.y as f32,
|
||||||
@@ -344,19 +419,28 @@ pub fn task_executor_system(
|
|||||||
));
|
));
|
||||||
ambulatory.current_path = None;
|
ambulatory.current_path = None;
|
||||||
}
|
}
|
||||||
let target_pos = ambulatory.target.unwrap_or(Vec3::ZERO);
|
|
||||||
let dx = transform.translation.x - target_pos.x;
|
// Always check arrival distance, not gated by target status
|
||||||
let dy = transform.translation.y - target_pos.y;
|
let dx = transform.translation.x - drop_pos.x as f32;
|
||||||
|
let dy = transform.translation.y - drop_pos.y as f32;
|
||||||
let dist_sq = dx * dx + dy * dy;
|
let dist_sq = dx * dx + dy * dy;
|
||||||
let arrive_sq = (crate::constants::TILE_SIZE * 1.5)
|
let arrive_sq = (crate::constants::TILE_SIZE as f32 * 1.5)
|
||||||
* (crate::constants::TILE_SIZE * 1.5);
|
* (crate::constants::TILE_SIZE as f32 * 1.5);
|
||||||
if dist_sq <= arrive_sq {
|
if dist_sq <= arrive_sq {
|
||||||
ambulatory.target = None;
|
ambulatory.target = None;
|
||||||
|
info!(
|
||||||
|
"[HAUL] {:?} arrived at drop point {:?}",
|
||||||
|
entity, drop_pos
|
||||||
|
);
|
||||||
*step = HaulStep::Dropping { drop_pos };
|
*step = HaulStep::Dropping { drop_pos };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HaulStep::Dropping { drop_pos } => {
|
HaulStep::Dropping { drop_pos } => {
|
||||||
if let Some(cargo_entity) = haul.release() {
|
if let Some(cargo_entity) = haul.release() {
|
||||||
|
info!(
|
||||||
|
"[HAUL] {:?} dropped {:?} at {:?}",
|
||||||
|
entity, cargo_entity, drop_pos
|
||||||
|
);
|
||||||
if tilemap_mut.place_cargo(*drop_pos, cargo_entity).is_err() {
|
if tilemap_mut.place_cargo(*drop_pos, cargo_entity).is_err() {
|
||||||
warn!(
|
warn!(
|
||||||
"place_cargo failed at {:?} — tile occupied. \
|
"place_cargo failed at {:?} — tile occupied. \
|
||||||
@@ -371,6 +455,7 @@ pub fn task_executor_system(
|
|||||||
*step = HaulStep::Done;
|
*step = HaulStep::Done;
|
||||||
}
|
}
|
||||||
HaulStep::Done => {
|
HaulStep::Done => {
|
||||||
|
info!("[HAUL] {:?} haul task COMPLETE", entity);
|
||||||
*state = TaskState::Completed;
|
*state = TaskState::Completed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,16 +480,17 @@ pub fn task_executor_system(
|
|||||||
ambulatory.target = Some(Vec3::new(
|
ambulatory.target = Some(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 + 1.0,
|
drop_pos.z as f32,
|
||||||
));
|
));
|
||||||
ambulatory.current_path = None;
|
ambulatory.current_path = None;
|
||||||
}
|
}
|
||||||
let target_pos = ambulatory.target.unwrap_or(Vec3::ZERO);
|
|
||||||
let dx = transform.translation.x - target_pos.x;
|
// Always check arrival distance, not gated by target status
|
||||||
let dy = transform.translation.y - target_pos.y;
|
let dx = transform.translation.x - drop_pos.x as f32;
|
||||||
|
let dy = transform.translation.y - drop_pos.y as f32;
|
||||||
let dist_sq = dx * dx + dy * dy;
|
let dist_sq = dx * dx + dy * dy;
|
||||||
let arrive_sq = (crate::constants::TILE_SIZE * 1.5)
|
let arrive_sq = (crate::constants::TILE_SIZE as f32 * 1.5)
|
||||||
* (crate::constants::TILE_SIZE * 1.5);
|
* (crate::constants::TILE_SIZE as f32 * 1.5);
|
||||||
if dist_sq <= arrive_sq {
|
if dist_sq <= arrive_sq {
|
||||||
ambulatory.target = None;
|
ambulatory.target = None;
|
||||||
*step = DropStep::Dropping { drop_pos };
|
*step = DropStep::Dropping { drop_pos };
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ pub mod executor;
|
|||||||
pub mod idle;
|
pub mod idle;
|
||||||
|
|
||||||
pub use components::{IdleState, Task, TaskQueue, TaskState};
|
pub use components::{IdleState, Task, TaskQueue, TaskState};
|
||||||
pub use demo::{demo_system, DemoState};
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
pub use demo::debug_task_queues;
|
pub use demo::debug_task_queues;
|
||||||
pub use events::{TaskBlocked, TaskClaimed, TaskCompleted, TaskDropped, TaskFailed};
|
pub use demo::{demo_system, DemoState};
|
||||||
|
pub use events::{LogsSpawned, TaskBlocked, TaskClaimed, TaskCompleted, TaskDropped, TaskFailed};
|
||||||
pub use executor::task_executor_system;
|
pub use executor::task_executor_system;
|
||||||
|
|
||||||
pub use crate::plugins::tasks::TasksPlugin;
|
pub use crate::plugins::tasks::TasksPlugin;
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
//! - haul_encumbrance_system (FixedUpdate, before update_encumbrance)
|
//! - haul_encumbrance_system (FixedUpdate, before update_encumbrance)
|
||||||
//! - carry_visual_system (Update, run_if any_hauling)
|
//! - carry_visual_system (Update, run_if any_hauling)
|
||||||
|
|
||||||
use crate::entities::cargo::{any_hauling, carry_visual_system, haul_encumbrance_system};
|
use crate::entities::cargo::{
|
||||||
|
any_hauling, cargo_position_sync_system, carry_visual_system, haul_encumbrance_system,
|
||||||
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
pub struct CargoPlugin;
|
pub struct CargoPlugin;
|
||||||
@@ -13,7 +15,11 @@ impl Plugin for CargoPlugin {
|
|||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
FixedUpdate,
|
FixedUpdate,
|
||||||
haul_encumbrance_system.before(crate::entities::item::inventory::update_encumbrance),
|
(
|
||||||
|
haul_encumbrance_system
|
||||||
|
.before(crate::entities::item::inventory::update_encumbrance),
|
||||||
|
cargo_position_sync_system,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.add_systems(Update, carry_visual_system.run_if(any_hauling));
|
.add_systems(Update, carry_visual_system.run_if(any_hauling));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
//! - debug_task_queues (FixedUpdate, after demo_system, debug only)
|
//! - 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, LogsSpawned, TaskBlocked, TaskClaimed,
|
||||||
TaskDropped, TaskFailed,
|
TaskCompleted, TaskDropped, TaskFailed,
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ impl Plugin for TasksPlugin {
|
|||||||
.add_message::<TaskFailed>()
|
.add_message::<TaskFailed>()
|
||||||
.add_message::<TaskDropped>()
|
.add_message::<TaskDropped>()
|
||||||
.add_message::<TaskBlocked>()
|
.add_message::<TaskBlocked>()
|
||||||
|
.add_message::<LogsSpawned>()
|
||||||
.init_resource::<DemoState>()
|
.init_resource::<DemoState>()
|
||||||
.add_systems(
|
.add_systems(
|
||||||
bevy::app::FixedUpdate,
|
bevy::app::FixedUpdate,
|
||||||
|
|||||||
Reference in New Issue
Block a user