From 4c6e190ea10b830496b60150fca7b2f2d575f2ab Mon Sep 17 00:00:00 2001 From: Broker0 Date: Thu, 29 Jun 2023 01:05:16 +0500 Subject: [PATCH] setting additional flags for path search via http api function to check whether a tile is occupied by a multi-object additional move cost option for multi-objects --- src/http/server.rs | 53 ++++++++++++++++++++++++++++++++++++++----- src/world/surveyor.rs | 29 ++++++++++++++++++++++- src/world/tiles.rs | 2 +- src/world/world.rs | 19 ++++++++++++++++ 4 files changed, 95 insertions(+), 8 deletions(-) diff --git a/src/http/server.rs b/src/http/server.rs index a9666f8..2e507fd 100644 --- a/src/http/server.rs +++ b/src/http/server.rs @@ -18,6 +18,7 @@ use serde::{Deserialize, Serialize}; use image::{ImageBuffer, Rgb}; use log::{error, info}; +use crate::mul::tiledata::MulTileFlags; use crate::world::{WorldModel, WorldSurveyor}; use crate::world::tiles::TopLevelItem; @@ -30,6 +31,29 @@ pub enum DistanceFunc { Euclidean, } +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +pub enum TileFlags { + Impassable, + Surface, + Wet, + HoverOver, + Door, + Wall, +} + +impl TileFlags { + pub fn to_mul_flags(&self) -> u32 { + match self { + TileFlags::Impassable => MulTileFlags::Impassable as u32, + TileFlags::Surface => MulTileFlags::Surface as u32, + TileFlags::Wet => MulTileFlags::Wet as u32, + TileFlags::HoverOver => MulTileFlags::HoverOver as u32, + TileFlags::Door => MulTileFlags::Door as u32, + TileFlags::Wall => MulTileFlags::Wall as u32, + } + } +} + #[derive(Serialize, Deserialize, Debug, Clone)] pub struct TraceOptions { // area @@ -41,15 +65,18 @@ pub struct TraceOptions { pub accuracy_x: Option, pub accuracy_y: Option, pub accuracy_z: Option, + // extended passability checking flags + pub flags_walk: Option>, + pub flags_ignore: Option>, // misc pub all_points: Option, - pub open_doors: Option, pub allow_diagonal_move: Option, - pub cost_limit: Option, // movement cost + pub cost_limit: Option, pub cost_turn: Option, pub cost_move_straight: Option, pub cost_move_diagonal: Option, + pub cost_move_multi: Option, // heuristic pub heuristic_distance: Option, pub heuristic_straight: Option, @@ -64,19 +91,26 @@ impl TraceOptions { top: None, right: None, bottom: None, + accuracy_x: None, accuracy_y: None, accuracy_z: None, - open_doors: None, + + flags_walk: None, + flags_ignore: None, + + all_points: None, + allow_diagonal_move: None, + cost_limit: None, cost_turn: None, cost_move_straight: None, cost_move_diagonal: None, - allow_diagonal_move: None, + cost_move_multi: None, + heuristic_distance: None, heuristic_straight: None, heuristic_diagonal: None, - all_points: None, } } } @@ -341,10 +375,17 @@ impl ApiHandler { let model = self.world_model.clone(); let options = options.clone(); + let walkable = options.flags_walk.clone().unwrap_or(vec![]); + let ignore = options.flags_ignore .clone().unwrap_or(vec![]); let task = tokio::task::spawn_blocking(move || { let mut points = Vec::new(); let world = model.world(world).unwrap(); - let surv = WorldSurveyor::new(world); + let surv = if walkable.len() == 0 && ignore.len() == 0 { + WorldSurveyor::new(world) + } else { + WorldSurveyor::new_with_flags(world, walkable, ignore) + }; + surv.trace_a_star(sx, sy, sz, 0, dx, dy, dz, 0, &mut points, &options); points }); diff --git a/src/world/surveyor.rs b/src/world/surveyor.rs index e6e2477..9f356da 100644 --- a/src/world/surveyor.rs +++ b/src/world/surveyor.rs @@ -4,7 +4,8 @@ use std::collections::hash_map::{Entry}; use std::time::Instant; use log::{debug, info, warn}; -use crate::http::server::{DistanceFunc, Point, TraceOptions}; +use crate::http::server::{DistanceFunc, Point, TileFlags, TraceOptions}; +use crate::mul::tiledata::MulTileFlags; use crate::world::{DynamicWorld, TileShape, WorldTile}; @@ -56,6 +57,25 @@ impl<'a> WorldSurveyor<'a> { } } + pub fn new_with_flags(model: &'a DynamicWorld, walkable_flags: Vec, ignore_flags: Vec) -> Self { + let mut walkable = 0; + let mut ignore = 0; + for flag in walkable_flags { + walkable |= flag.to_mul_flags(); + } + + for flag in ignore_flags { + ignore |= flag.to_mul_flags(); + } + + Self { + model, + walkable, + ignore, + fly: walkable & MulTileFlags::HoverOver as u32 != 0 + } + } + /// returns a vector of elements located at the given coordinates and used in movement testing pub fn get_tile_objects(&self, x: isize, y: isize, direction: u8, result: &mut Vec) { self.model.query_tile_full(x, y, direction, self.walkable, self.ignore, result); @@ -284,6 +304,7 @@ impl<'a> WorldSurveyor<'a> { let y_accuracy = options.accuracy_y.unwrap_or(0); let z_accuracy = options.accuracy_z.unwrap_or(0); + let cost_move_multi = options.cost_move_multi.unwrap_or(0); let cost_limit = options.cost_limit.unwrap_or(isize::MAX); let cost_turn = options.cost_turn.unwrap_or(1); let cost_move_straight = options.cost_move_straight.unwrap_or(1); @@ -421,6 +442,12 @@ impl<'a> WorldSurveyor<'a> { if direction == curr_dir { cost_move_straight } else { cost_move_straight + cost_turn } }; + let dest_gval = if cost_move_multi > 0 && self.model.is_tile_multi_occupied(dest_x, dest_y) { + dest_gval + cost_move_multi + } else { + dest_gval + }; + if dest_gval > cost_limit { continue } diff --git a/src/world/tiles.rs b/src/world/tiles.rs index 9ba1735..275d489 100644 --- a/src/world/tiles.rs +++ b/src/world/tiles.rs @@ -240,7 +240,7 @@ impl WorldTile { match self.shape { TileShape::Slope { z_stand, passable: true, .. } => z_stand, TileShape::Surface { z_stand, passable: true, .. } => z_stand, - TileShape::HoverOver { z_base, ..} => z_base, + TileShape::HoverOver { z_base, .. } => z_base, _ => panic!("z_stand called for invalid tile type"), } } diff --git a/src/world/world.rs b/src/world/world.rs index 286329a..30b5a14 100644 --- a/src/world/world.rs +++ b/src/world/world.rs @@ -431,6 +431,25 @@ impl DynamicWorld { } } + pub fn is_tile_multi_occupied(&self, x: isize, y: isize) -> bool { + let (idx, (_ox, _oy)) = self.base.tile_to_block_offsets(x, y); + + let overlay = self.read_overlay(); + if let Some(block) = overlay.get(&idx) { + let min_item = DynamicWorldObject::min_item(x, y); + let max_item = DynamicWorldObject::max_item(x, y); + + for item in block.range(min_item..=max_item) { + match item { + DynamicWorldObject::MultiPart { .. } => return true, + _ => continue + } + } + } + + false + } + /// adds to `result` all objects in the given tile, and sorts them by z and height /// in fact it just calls query_tile_ground, query_tile_static and query_tile_dynamic and sorts `result`