Skip to content

Commit

Permalink
setting additional flags for path search via http api
Browse files Browse the repository at this point in the history
function to check whether a tile is occupied by a multi-object
additional move cost option for multi-objects
  • Loading branch information
broker0 committed Jun 28, 2023
1 parent d052138 commit 4c6e190
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 8 deletions.
53 changes: 47 additions & 6 deletions src/http/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
Expand All @@ -41,15 +65,18 @@ pub struct TraceOptions {
pub accuracy_x: Option<isize>,
pub accuracy_y: Option<isize>,
pub accuracy_z: Option<isize>,
// extended passability checking flags
pub flags_walk: Option<Vec<TileFlags>>,
pub flags_ignore: Option<Vec<TileFlags>>,
// misc
pub all_points: Option<bool>,
pub open_doors: Option<bool>,
pub allow_diagonal_move: Option<bool>,
pub cost_limit: Option<isize>,
// movement cost
pub cost_limit: Option<isize>,
pub cost_turn: Option<isize>,
pub cost_move_straight: Option<isize>,
pub cost_move_diagonal: Option<isize>,
pub cost_move_multi: Option<isize>,
// heuristic
pub heuristic_distance: Option<DistanceFunc>,
pub heuristic_straight: Option<isize>,
Expand All @@ -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,
}
}
}
Expand Down Expand Up @@ -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
});
Expand Down
29 changes: 28 additions & 1 deletion src/world/surveyor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};


Expand Down Expand Up @@ -56,6 +57,25 @@ impl<'a> WorldSurveyor<'a> {
}
}

pub fn new_with_flags(model: &'a DynamicWorld, walkable_flags: Vec<TileFlags>, ignore_flags: Vec<TileFlags>) -> 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<WorldTile>) {
self.model.query_tile_full(x, y, direction, self.walkable, self.ignore, result);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion src/world/tiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
}
}
Expand Down
19 changes: 19 additions & 0 deletions src/world/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down

0 comments on commit 4c6e190

Please sign in to comment.