fix
This commit is contained in:
@@ -58,9 +58,18 @@ pub enum HaulStep {
|
|||||||
/// 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.
|
||||||
MovingToDest,
|
MovingToDest {
|
||||||
|
/// Chosen drop position, computed once on first tick.
|
||||||
|
/// Stored here so Dropping uses the exact same tile — avoids
|
||||||
|
/// a second search that could return a different result.
|
||||||
|
chosen_drop: Option<IVec3>,
|
||||||
|
},
|
||||||
/// At destination — dropping this tick.
|
/// At destination — dropping this tick.
|
||||||
Dropping,
|
Dropping {
|
||||||
|
/// Exact tile returned by the MovingToDest search. Used directly
|
||||||
|
/// so cargo_tiles always matches where the entity walked.
|
||||||
|
drop_pos: IVec3,
|
||||||
|
},
|
||||||
/// Haul complete.
|
/// Haul complete.
|
||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
@@ -69,9 +78,16 @@ pub enum HaulStep {
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum DropStep {
|
pub enum DropStep {
|
||||||
/// Walking to drop position.
|
/// Walking to drop position.
|
||||||
Moving,
|
Moving {
|
||||||
|
/// Chosen drop position, computed once on first tick.
|
||||||
|
chosen_drop: Option<IVec3>,
|
||||||
|
},
|
||||||
/// At drop position — dropping this tick.
|
/// At drop position — dropping this tick.
|
||||||
Dropping,
|
Dropping {
|
||||||
|
/// Exact tile returned by the Moving search. Used directly
|
||||||
|
/// so cargo_tiles always matches where the entity walked.
|
||||||
|
drop_pos: IVec3,
|
||||||
|
},
|
||||||
/// Drop complete.
|
/// Drop complete.
|
||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
//! Uses Changed<TaskQueue> + Changed<TaskState> to minimise queries.
|
//! Uses Changed<TaskQueue> + Changed<TaskState> to minimise queries.
|
||||||
|
|
||||||
use crate::entities::behaviour::{EntityBehaviourRegistry, EntityType};
|
use crate::entities::behaviour::{EntityBehaviourRegistry, EntityType};
|
||||||
use crate::entities::cargo::HaulSlot;
|
use crate::entities::cargo::{Cargo, HaulSlot};
|
||||||
use crate::entities::shared_components::Ambulatory;
|
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,
|
||||||
@@ -33,6 +33,7 @@ pub fn task_executor_system(
|
|||||||
mut rng_q: Query<&mut WyRand, With<GlobalRng>>,
|
mut rng_q: Query<&mut WyRand, With<GlobalRng>>,
|
||||||
mut tick: Local<u32>,
|
mut tick: Local<u32>,
|
||||||
tree_parts: Query<(Entity, &TreePart)>,
|
tree_parts: Query<(Entity, &TreePart)>,
|
||||||
|
mut cargo_query: Query<&mut Cargo>,
|
||||||
mut query: Query<(
|
mut query: Query<(
|
||||||
Entity,
|
Entity,
|
||||||
&mut TaskQueue,
|
&mut TaskQueue,
|
||||||
@@ -124,7 +125,7 @@ pub fn task_executor_system(
|
|||||||
ambulatory.target = Some(Vec3::new(
|
ambulatory.target = Some(Vec3::new(
|
||||||
target.x as f32,
|
target.x as f32,
|
||||||
target.y as f32,
|
target.y as f32,
|
||||||
transform.translation.z,
|
target.z as f32 + 1.0,
|
||||||
));
|
));
|
||||||
ambulatory.current_path = None;
|
ambulatory.current_path = None;
|
||||||
}
|
}
|
||||||
@@ -250,7 +251,7 @@ 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);
|
||||||
*step = HaulStep::MovingToDest;
|
*step = HaulStep::MovingToDest { chosen_drop: None };
|
||||||
} else {
|
} else {
|
||||||
failed_writer.write(TaskFailed {
|
failed_writer.write(TaskFailed {
|
||||||
entity,
|
entity,
|
||||||
@@ -260,11 +261,16 @@ pub fn task_executor_system(
|
|||||||
*state = TaskState::Failed;
|
*state = TaskState::Failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HaulStep::MovingToDest => {
|
HaulStep::MovingToDest { chosen_drop } => {
|
||||||
if ambulatory.target.is_none() {
|
if chosen_drop.is_none() {
|
||||||
let drop_pos = tilemap_mut
|
*chosen_drop = Some(
|
||||||
|
tilemap_mut
|
||||||
.find_nearest_free_cargo_tile(*dest, 8)
|
.find_nearest_free_cargo_tile(*dest, 8)
|
||||||
.unwrap_or(*dest);
|
.unwrap_or(*dest),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let drop_pos = chosen_drop.unwrap();
|
||||||
|
if ambulatory.target.is_none() {
|
||||||
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,
|
||||||
@@ -280,19 +286,15 @@ pub fn task_executor_system(
|
|||||||
* (crate::constants::TILE_SIZE * 1.5);
|
* (crate::constants::TILE_SIZE * 1.5);
|
||||||
if dist_sq <= arrive_sq {
|
if dist_sq <= arrive_sq {
|
||||||
ambulatory.target = None;
|
ambulatory.target = None;
|
||||||
*step = HaulStep::Dropping;
|
*step = HaulStep::Dropping { drop_pos };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HaulStep::Dropping => {
|
HaulStep::Dropping { drop_pos } => {
|
||||||
if let Some(cargo) = haul.release() {
|
if let Some(cargo_entity) = haul.release() {
|
||||||
let drop_pos = tilemap_mut
|
let _ = tilemap_mut.place_cargo(*drop_pos, cargo_entity);
|
||||||
.find_nearest_free_cargo_tile(
|
if let Ok(mut cargo) = cargo_query.get_mut(cargo_entity) {
|
||||||
transform.translation.as_ivec3(),
|
cargo.tile_pos = *drop_pos;
|
||||||
8,
|
}
|
||||||
)
|
|
||||||
.unwrap_or(transform.translation.as_ivec3());
|
|
||||||
let _ = tilemap_mut.place_cargo(drop_pos, cargo);
|
|
||||||
// TODO: update Cargo.tile_pos via CargoDroppedEvent
|
|
||||||
}
|
}
|
||||||
*step = HaulStep::Done;
|
*step = HaulStep::Done;
|
||||||
}
|
}
|
||||||
@@ -308,11 +310,16 @@ pub fn task_executor_system(
|
|||||||
};
|
};
|
||||||
|
|
||||||
match step {
|
match step {
|
||||||
DropStep::Moving => {
|
DropStep::Moving { chosen_drop } => {
|
||||||
if ambulatory.target.is_none() {
|
if chosen_drop.is_none() {
|
||||||
let drop_pos = tilemap_mut
|
*chosen_drop = Some(
|
||||||
|
tilemap_mut
|
||||||
.find_nearest_free_cargo_tile(*pos, 8)
|
.find_nearest_free_cargo_tile(*pos, 8)
|
||||||
.unwrap_or(*pos);
|
.unwrap_or(*pos),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let drop_pos = chosen_drop.unwrap();
|
||||||
|
if ambulatory.target.is_none() {
|
||||||
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,
|
||||||
@@ -328,18 +335,15 @@ pub fn task_executor_system(
|
|||||||
* (crate::constants::TILE_SIZE * 1.5);
|
* (crate::constants::TILE_SIZE * 1.5);
|
||||||
if dist_sq <= arrive_sq {
|
if dist_sq <= arrive_sq {
|
||||||
ambulatory.target = None;
|
ambulatory.target = None;
|
||||||
*step = DropStep::Dropping;
|
*step = DropStep::Dropping { drop_pos };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DropStep::Dropping => {
|
DropStep::Dropping { drop_pos } => {
|
||||||
if let Some(cargo) = haul.release() {
|
if let Some(cargo_entity) = haul.release() {
|
||||||
let drop_pos = tilemap_mut
|
let _ = tilemap_mut.place_cargo(*drop_pos, cargo_entity);
|
||||||
.find_nearest_free_cargo_tile(
|
if let Ok(mut cargo) = cargo_query.get_mut(cargo_entity) {
|
||||||
transform.translation.as_ivec3(),
|
cargo.tile_pos = *drop_pos;
|
||||||
8,
|
}
|
||||||
)
|
|
||||||
.unwrap_or(transform.translation.as_ivec3());
|
|
||||||
let _ = tilemap_mut.place_cargo(drop_pos, cargo);
|
|
||||||
}
|
}
|
||||||
*step = DropStep::Done;
|
*step = DropStep::Done;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -298,39 +298,24 @@ pub fn fell_tree(
|
|||||||
let trunk_y = trunk_pos.y;
|
let trunk_y = trunk_pos.y;
|
||||||
let canopy_radius_world = (TREE_LEAF_BASE_RADIUS * TILE_SIZE) as i32 + ITILE_SIZE;
|
let canopy_radius_world = (TREE_LEAF_BASE_RADIUS * TILE_SIZE) as i32 + ITILE_SIZE;
|
||||||
|
|
||||||
let to_remove: SmallVec<[_; 96]> = tree_parts
|
let to_remove: SmallVec<[(_, IVec3, bool); 96]> = tree_parts
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, part)| {
|
.filter(|(_, part)| {
|
||||||
part.chunk_pos == target_chunk
|
part.chunk_pos == target_chunk
|
||||||
&& (part.tile_pos.x - trunk_x).abs() <= canopy_radius_world
|
&& (part.tile_pos.x - trunk_x).abs() <= canopy_radius_world
|
||||||
&& (part.tile_pos.y - trunk_y).abs() <= canopy_radius_world
|
&& (part.tile_pos.y - trunk_y).abs() <= canopy_radius_world
|
||||||
})
|
})
|
||||||
.map(|(entity, part)| (entity, part.tile_pos))
|
.map(|(entity, part)| (entity, part.tile_pos, part.is_trunk))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Collect unique occlusion positions across all removed tiles, then fire once each.
|
|
||||||
// Adjacent tree parts share column positions, so deduplication cuts event count
|
|
||||||
// significantly vs. firing per-tile per-column.
|
|
||||||
let mut dirty_columns: FxHashSet<IVec3> = FxHashSet::default();
|
let mut dirty_columns: FxHashSet<IVec3> = FxHashSet::default();
|
||||||
// calculate_visibility traces up arbitrarily deep, so refresh the full column.
|
|
||||||
// z_total is constant per call — hoist above the loop.
|
|
||||||
let z_total = crate::world::chunks::Z_BELOW as i32 + crate::world::chunks::Z_ABOVE as i32 + 1;
|
let z_total = crate::world::chunks::Z_BELOW as i32 + crate::world::chunks::Z_ABOVE as i32 + 1;
|
||||||
|
|
||||||
// Collect trunk positions before despawning — we need is_trunk from TreePart
|
|
||||||
// while the entity still exists. This is why we DON'T immediately despawn
|
|
||||||
// in the to_remove mapping step.
|
|
||||||
let mut trunk_positions: SmallVec<[IVec3; 8]> = SmallVec::new();
|
let mut trunk_positions: SmallVec<[IVec3; 8]> = SmallVec::new();
|
||||||
|
|
||||||
for (entity, tile_pos) in to_remove.iter() {
|
for (entity, tile_pos, is_trunk) in to_remove.iter() {
|
||||||
// Check if this was a trunk (is_trunk stored on TreePart).
|
if *is_trunk {
|
||||||
// We need to look up is_trunk before the entity is despawned.
|
|
||||||
// to_remove was collected from tree_parts query, so find it again:
|
|
||||||
if let Ok((_, part)) = tree_parts.get(*entity) {
|
|
||||||
if part.is_trunk {
|
|
||||||
trunk_positions.push(*tile_pos);
|
trunk_positions.push(*tile_pos);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tilemap.remove_fixture(tile_pos);
|
tilemap.remove_fixture(tile_pos);
|
||||||
tile_changed.write(TileChangedEvent { pos: *tile_pos });
|
tile_changed.write(TileChangedEvent { pos: *tile_pos });
|
||||||
commands.entity(*entity).despawn();
|
commands.entity(*entity).despawn();
|
||||||
|
|||||||
Reference in New Issue
Block a user