This commit is contained in:
2026-03-22 01:58:34 +00:00
parent adc236dc3d
commit 749913a028
2 changed files with 34 additions and 17 deletions
+12 -6
View File
@@ -81,7 +81,7 @@ use crate::world::{
use crate::{constants::*, entities::shared_components::Ambulatory}; use crate::{constants::*, entities::shared_components::Ambulatory};
use bevy::math::ivec3; use bevy::math::ivec3;
use bevy_rand::prelude::*; use bevy_rand::prelude::*;
use rand::RngExt; use rand::{RngExt, SeedableRng};
thread_local! { thread_local! {
static LOCAL_PATH_TIMES: RefCell<Vec<u128>> = const { RefCell::new(Vec::new()) }; static LOCAL_PATH_TIMES: RefCell<Vec<u128>> = const { RefCell::new(Vec::new()) };
@@ -236,6 +236,7 @@ impl Plugin for PathfindingPlugin {
collect_pathfinding_dirty_chunks, collect_pathfinding_dirty_chunks,
invalidate_paths_on_tile_change, invalidate_paths_on_tile_change,
crate::entities::tasks::task_executor_system, crate::entities::tasks::task_executor_system,
update_wandering_targets,
prepare_paths, prepare_paths,
movement, movement,
) )
@@ -529,14 +530,19 @@ pub fn merge_benchmark_stats(mut bench: ResMut<PathfindingBenchmark>) {
} }
pub fn update_wandering_targets( pub fn update_wandering_targets(
mut query: Query<(&mut Ambulatory, &Transform)>, mut query: Query<(&mut Ambulatory, &Transform), Without<crate::entities::tasks::TaskQueue>>,
tilemap: Res<TileMap>, tilemap: Res<TileMap>,
chunk_map: Res<ChunkMap>, chunk_map: Res<ChunkMap>,
mut rng_q: Query<&mut WyRand, With<GlobalRng>>, time: Res<Time>,
) { ) {
let Ok(mut rng) = rng_q.single_mut() else { // Use deterministic RNG - seed from SEED + time
return; use std::collections::hash_map::DefaultHasher;
}; use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
crate::constants::SEED.hash(&mut hasher);
time.elapsed_secs().to_bits().hash(&mut hasher);
let seed = hasher.finish();
let mut rng = WyRand::seed_from_u64(seed);
for (mut ambulatory, transform) in query.iter_mut() { for (mut ambulatory, transform) in query.iter_mut() {
if ambulatory.target.is_none() { if ambulatory.target.is_none() {
+22 -11
View File
@@ -44,10 +44,11 @@ pub(super) fn execute_idle(
// Only reset path if target changed or no path exists // Only reset path if target changed or no path exists
if target_changed || ambulatory.current_path.is_none() { if target_changed || ambulatory.current_path.is_none() {
// +1.0 sub-tile offset matching original wandering 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;
ambulatory.path_index = 0; ambulatory.path_index = 0;
@@ -56,6 +57,7 @@ pub(super) fn execute_idle(
/// Pick a random standable tile within wander radius of origin. /// Pick a random standable tile within wander radius of origin.
/// Uses reservoir sampling to avoid heap allocation. /// Uses reservoir sampling to avoid heap allocation.
/// Searches for actual surface z at each XY position (like original wandering system).
fn pick_wander_target( fn pick_wander_target(
origin: &IVec3, origin: &IVec3,
radius: i32, radius: i32,
@@ -67,16 +69,25 @@ fn pick_wander_target(
for dx in -radius..=radius { for dx in -radius..=radius {
for dy in -radius..=radius { for dy in -radius..=radius {
let candidate = IVec3::new( // Search for actual surface z at this XY - same logic as original wandering
origin.x + dx * ITILE_SIZE, for z in -3i32..=4i32 {
origin.y + dy * ITILE_SIZE, let floor_pos = IVec3::new(
origin.z, origin.x + dx * ITILE_SIZE,
); origin.y + dy * ITILE_SIZE,
if tilemap.is_standable(candidate) { z * ITILE_SIZE,
count += 1; );
// Reservoir sampling: 1/count chance to replace chosen // Check if there's a floor tile at this z
if rng.random_range(0..count) == 0 { if tilemap.floor_tiles.get(&floor_pos).is_some() {
chosen = Some(candidate); // Check if standable one tile above
let above = IVec3::new(floor_pos.x, floor_pos.y, floor_pos.z + ITILE_SIZE);
if tilemap.is_standable(above) {
count += 1;
// Reservoir sampling: 1/count chance to replace chosen
if rng.random_range(0..count) == 0 {
chosen = Some(above);
}
break; // found surface at this XY, stop z search
}
} }
} }
} }