From de685b00b21e55938aa0f3c104ac33f3fbc2b1f3 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sat, 14 Nov 2020 23:45:27 +0000 Subject: [PATCH] Improved water pathfinding --- assets/voxygen/shaders/sprite-vert.glsl | 1 + common/src/path.rs | 58 ++++++++++++++----------- common/src/sys/agent.rs | 6 +-- common/src/terrain/mod.rs | 14 +++--- server/src/rtsim/entity.rs | 2 +- server/src/rtsim/mod.rs | 2 +- world/src/lib.rs | 1 + world/src/pathfinding.rs | 35 +++++++++++++++ 8 files changed, 83 insertions(+), 36 deletions(-) create mode 100644 world/src/pathfinding.rs diff --git a/assets/voxygen/shaders/sprite-vert.glsl b/assets/voxygen/shaders/sprite-vert.glsl index 4146be684d..73aa6f92e7 100644 --- a/assets/voxygen/shaders/sprite-vert.glsl +++ b/assets/voxygen/shaders/sprite-vert.glsl @@ -139,6 +139,7 @@ void main() { // f_pos = v_pos + (model_offs - focus_off.xyz); f_pos = (inst_mat * vec4(v_pos_, 1.0)).xyz * SCALE + inst_offs; + f_pos.z -= 250.0 * (1.0 - min(1.0001 - 0.02 / pow(tick.x - load_time, 10.0), 1.0)); // f_pos = (inst_mat * v_pos_) * SCALE + sprite_pos; // f_pos = (inst_mat * vec4(v_pos * SCALE, 1)).xyz + (model_offs - focus_off.xyz); diff --git a/common/src/path.rs b/common/src/path.rs index a3f6fd881e..54a7c2ef64 100644 --- a/common/src/path.rs +++ b/common/src/path.rs @@ -131,17 +131,18 @@ impl Route { // Determine whether we're close enough to the next to to consider it completed let dist_sqrd = pos.xy().distance_squared(closest_tgt.xy()); if dist_sqrd < traversal_cfg.node_tolerance.powf(2.0) * if be_precise { 0.25 } else { 1.0 } - && (pos.z - closest_tgt.z > 1.2 || (pos.z - closest_tgt.z > -0.2 && (traversal_cfg.on_ground || traversal_cfg.in_liquid))) - && (pos.z - closest_tgt.z < 1.2 || (pos.z - closest_tgt.z < 2.9 && vel.z < -0.05)) - && vel.z <= 0.0 - // Only consider the node reached if there's nothing solid between us and it - && (vol - .ray(pos + Vec3::unit_z() * 1.5, closest_tgt + Vec3::unit_z() * 1.5) - .until(Block::is_solid) - .cast() - .0 - > pos.distance(closest_tgt) * 0.9 || dist_sqrd < 0.5) - && self.next_idx < self.path.len() + && (((pos.z - closest_tgt.z > 1.2 || (pos.z - closest_tgt.z > -0.2 && traversal_cfg.on_ground)) + && (pos.z - closest_tgt.z < 1.2 || (pos.z - closest_tgt.z < 2.9 && vel.z < -0.05)) + && vel.z <= 0.0 + // Only consider the node reached if there's nothing solid between us and it + && (vol + .ray(pos + Vec3::unit_z() * 1.5, closest_tgt + Vec3::unit_z() * 1.5) + .until(Block::is_solid) + .cast() + .0 + > pos.distance(closest_tgt) * 0.9 || dist_sqrd < 0.5) + && self.next_idx < self.path.len()) + || (traversal_cfg.in_liquid && pos.z < closest_tgt.z + 0.8 && pos.z > closest_tgt.z)) { // Node completed, move on to the next one self.next_idx += 1; @@ -419,7 +420,7 @@ impl Chaser { vol.get( (pos + Vec3::::from(tgt_dir) * 2.5).map(|e| e as i32) + Vec3::unit_z() * z, ) - .map(|b| !b.is_solid()) + .map(|b| b.is_air()) .unwrap_or(false) }); @@ -437,17 +438,22 @@ fn walkable(vol: &V, pos: Vec3) -> bool where V: BaseVol + ReadVol, { - vol.get(pos - Vec3::new(0, 0, 1)) - .map(|b| b.is_filled()) - .unwrap_or(false) - && vol - .get(pos + Vec3::new(0, 0, 0)) - .map(|b| !b.is_filled()) - .unwrap_or(true) - && vol - .get(pos + Vec3::new(0, 0, 1)) - .map(|b| !b.is_filled()) - .unwrap_or(true) + let below = vol.get(pos - Vec3::unit_z()) + .ok() + .copied() + .unwrap_or_else(Block::empty); + let a = vol.get(pos) + .ok() + .copied() + .unwrap_or_else(Block::empty); + let b = vol.get(pos + Vec3::unit_z()) + .ok() + .copied() + .unwrap_or_else(Block::empty); + + let on_ground = below.is_filled(); + let in_liquid = a.is_liquid(); + (on_ground || in_liquid) && !a.is_solid() && !b.is_solid() } /// Attempt to search for a path to a target, returning the path (if one was @@ -546,17 +552,17 @@ where && ((dir.z < 1 || vol .get(pos + Vec3::unit_z() * 2) - .map(|b| !b.is_filled()) + .map(|b| !b.is_solid()) .unwrap_or(true)) && (dir.z < 2 || vol .get(pos + Vec3::unit_z() * 3) - .map(|b| !b.is_filled()) + .map(|b| !b.is_solid()) .unwrap_or(true)) && (dir.z >= 0 || vol .get(pos + *dir + Vec3::unit_z() * 2) - .map(|b| !b.is_filled()) + .map(|b| !b.is_solid()) .unwrap_or(true))) }) .map(move |(pos, dir)| pos + dir) diff --git a/common/src/sys/agent.rs b/common/src/sys/agent.rs index df8ef63ab5..ff885fae35 100644 --- a/common/src/sys/agent.rs +++ b/common/src/sys/agent.rs @@ -239,9 +239,9 @@ impl<'a> System<'a> for Sys { .unwrap_or(Vec2::zero()) * speed.min(agent.rtsim_controller.speed_factor); inputs.jump.set_state(bearing.z > 1.5); - inputs.climb = Some(comp::Climb::Up) - .filter(|_| bearing.z > 1.5 || physics_state.in_liquid.is_some()); - inputs.move_z = bearing.z; + inputs.climb = Some(comp::Climb::Up); + //.filter(|_| bearing.z > 0.1 || physics_state.in_liquid.is_some()); + inputs.move_z = bearing.z + 0.05; } } else { *bearing += Vec2::new( diff --git a/common/src/terrain/mod.rs b/common/src/terrain/mod.rs index 878eb9648b..9c44c92f16 100644 --- a/common/src/terrain/mod.rs +++ b/common/src/terrain/mod.rs @@ -116,11 +116,15 @@ impl TerrainGrid { let mut z_diff = 0; for _ in 0..128 { let test_pos = pos + Vec3::unit_z() * z_diff; - if (0..2) - .all(|z| self - .get(test_pos + Vec3::unit_z() * z) - .map(|b| !b.is_solid()) - .unwrap_or(true)) + if self + .get(test_pos - Vec3::unit_z()) + .map(|b| b.is_filled()) + .unwrap_or(false) + && (0..2) + .all(|z| self + .get(test_pos + Vec3::unit_z() * z) + .map(|b| !b.is_solid()) + .unwrap_or(true)) { return test_pos; } diff --git a/server/src/rtsim/entity.rs b/server/src/rtsim/entity.rs index 2c5fb14a4f..ea7688ac97 100644 --- a/server/src/rtsim/entity.rs +++ b/server/src/rtsim/entity.rs @@ -101,7 +101,7 @@ impl Entity { let travel_to = self.pos.xy() + Vec3::from((wpos.map(|e| e as f32 + 0.5) - self.pos.xy()) .try_normalized() - .unwrap_or_else(Vec2::zero)) * 32.0; + .unwrap_or_else(Vec2::zero)) * 64.0; let travel_to_alt = world.sim().get_alt_approx(travel_to.map(|e| e as i32)).unwrap_or(0.0) as i32; let travel_to = terrain.find_space(Vec3::new(travel_to.x as i32, travel_to.y as i32, travel_to_alt)).map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0); self.controller.travel_to = Some(travel_to); diff --git a/server/src/rtsim/mod.rs b/server/src/rtsim/mod.rs index 2aa5cf0ef3..4a87f862a4 100644 --- a/server/src/rtsim/mod.rs +++ b/server/src/rtsim/mod.rs @@ -87,7 +87,7 @@ pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) { pub fn init(state: &mut State, world: &world::World) { let mut rtsim = RtSim::new(world.sim().get_size()); - for _ in 0..10000 { + for _ in 0..2500 { let pos = rtsim.chunks.size().map2( TerrainChunk::RECT_SIZE, |sz, chunk_sz| thread_rng().gen_range(0, sz * chunk_sz) as i32, diff --git a/world/src/lib.rs b/world/src/lib.rs index 944653450f..4c2065e616 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -24,6 +24,7 @@ pub mod sim; pub mod sim2; pub mod site; pub mod util; +pub mod pathfinding; // Reexports pub use crate::{ diff --git a/world/src/pathfinding.rs b/world/src/pathfinding.rs new file mode 100644 index 0000000000..c8677d9707 --- /dev/null +++ b/world/src/pathfinding.rs @@ -0,0 +1,35 @@ +use crate::sim::WorldSim; +use common::{ + astar::Astar, + path::Path, +}; +use hashbrown::hash_map::DefaultHashBuilder; +use vek::*; + +pub struct SearchCfg { + // 0.0 = no discount, 1.0 = free travel + path_discount: f32, + // Cost per metre altitude change per metre horizontal + // 0.0 = no cost, 1.0 = same cost vertical as horizontal + gradient_aversion: f32, +} + +pub struct Searcher<'a> { + land: &'a WorldSim, + pub cfg: SearchCfg, +} + +impl<'a> Searcher<'a> { + /// Attempt to find a path between two chunks on the map. + pub fn search(self, a: Vec2, b: Vec2) -> Option> { + let heuristic = |pos: &Vec2| (pos - b).map(|e| e as f32).magnitude(); + // Astar::new( + // 100_000, + // a, + // heuristc, + // DefaultHashBuilder::default(), + // ); + + None + } +}