mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
site pathing
This commit is contained in:
parent
f40cfb4ac3
commit
afd9ea5462
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -6948,6 +6948,7 @@ dependencies = [
|
||||
"anymap2",
|
||||
"atomic_refcell",
|
||||
"enum-map",
|
||||
"fxhash",
|
||||
"hashbrown 0.12.3",
|
||||
"rand 0.8.5",
|
||||
"rmp-serde",
|
||||
|
@ -17,3 +17,4 @@ tracing = "0.1"
|
||||
atomic_refcell = "0.1"
|
||||
slotmap = { version = "1.0.6", features = ["serde"] }
|
||||
rand = { version = "0.8", features = ["small_rng"] }
|
||||
fxhash = "0.2.1"
|
@ -1,11 +1,131 @@
|
||||
use crate::{data::npc::NpcMode, event::OnTick, RtState, Rule, RuleError};
|
||||
use rand::seq::IteratorRandom;
|
||||
use tracing::info;
|
||||
use std::hash::BuildHasherDefault;
|
||||
|
||||
use crate::{
|
||||
event::OnTick,
|
||||
RtState, Rule, RuleError,
|
||||
};
|
||||
use common::{astar::{Astar, PathResult}, store::Id};
|
||||
use fxhash::FxHasher64;
|
||||
use rand::{seq::IteratorRandom, rngs::SmallRng, SeedableRng};
|
||||
use vek::*;
|
||||
use world::site::SiteKind;
|
||||
use world::{
|
||||
site::{Site as WorldSite, SiteKind},
|
||||
site2::{self, TileKind},
|
||||
IndexRef,
|
||||
};
|
||||
|
||||
pub struct NpcAi;
|
||||
|
||||
const NEIGHBOURS: &[Vec2<i32>] = &[
|
||||
Vec2::new(1, 0),
|
||||
Vec2::new(0, 1),
|
||||
Vec2::new(-1, 0),
|
||||
Vec2::new(0, -1),
|
||||
Vec2::new(1, 1),
|
||||
Vec2::new(-1, 1),
|
||||
Vec2::new(-1, -1),
|
||||
Vec2::new(1, -1),
|
||||
];
|
||||
const CARDINALS: &[Vec2<i32>] = &[
|
||||
Vec2::new(1, 0),
|
||||
Vec2::new(0, 1),
|
||||
Vec2::new(-1, 0),
|
||||
Vec2::new(0, -1),
|
||||
];
|
||||
|
||||
fn path_between(start: Vec2<i32>, end: Vec2<i32>, site: &site2::Site) -> PathResult<Vec2<i32>> {
|
||||
let heuristic = |tile: &Vec2<i32>| tile.as_::<f32>().distance(end.as_());
|
||||
let mut astar = Astar::new(
|
||||
100,
|
||||
start,
|
||||
&heuristic,
|
||||
BuildHasherDefault::<FxHasher64>::default(),
|
||||
);
|
||||
|
||||
let transition = |a: &Vec2<i32>, b: &Vec2<i32>| {
|
||||
let distance = a.as_::<f32>().distance(b.as_());
|
||||
let a_tile = site.tiles.get(*a);
|
||||
let b_tile = site.tiles.get(*b);
|
||||
|
||||
let terrain = match &b_tile.kind {
|
||||
TileKind::Empty => 5.0,
|
||||
TileKind::Hazard(_) => 20.0,
|
||||
TileKind::Field => 12.0,
|
||||
TileKind::Plaza
|
||||
| TileKind::Road { .. } => 1.0,
|
||||
|
||||
TileKind::Building
|
||||
| TileKind::Castle
|
||||
| TileKind::Wall(_)
|
||||
| TileKind::Tower(_)
|
||||
| TileKind::Keep(_)
|
||||
| TileKind::Gate
|
||||
| TileKind::GnarlingFortification => 3.0,
|
||||
};
|
||||
let is_door_tile = |plot: Id<site2::Plot>, tile: Vec2<i32>| {
|
||||
match site.plot(plot).kind() {
|
||||
site2::PlotKind::House(house) => house.door_tile == tile,
|
||||
site2::PlotKind::Workshop(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
let building = if a_tile.is_building() && b_tile.is_road() {
|
||||
a_tile.plot.and_then(|plot| is_door_tile(plot, *a).then(|| 1.0)).unwrap_or(f32::INFINITY)
|
||||
} else if b_tile.is_building() && a_tile.is_road() {
|
||||
b_tile.plot.and_then(|plot| is_door_tile(plot, *b).then(|| 1.0)).unwrap_or(f32::INFINITY)
|
||||
} else if (a_tile.is_building() || b_tile.is_building()) && a_tile.plot != b_tile.plot {
|
||||
f32::INFINITY
|
||||
} else {
|
||||
1.0
|
||||
};
|
||||
|
||||
distance * terrain * building
|
||||
};
|
||||
|
||||
astar.poll(
|
||||
100,
|
||||
heuristic,
|
||||
|&tile| NEIGHBOURS.iter().map(move |c| tile + *c),
|
||||
transition,
|
||||
|tile| *tile == end,
|
||||
)
|
||||
}
|
||||
|
||||
fn path_town(
|
||||
wpos: Vec3<f32>,
|
||||
site: Id<WorldSite>,
|
||||
index: IndexRef,
|
||||
time: f64,
|
||||
seed: u32,
|
||||
) -> Option<(Vec3<f32>, f32)> {
|
||||
match &index.sites.get(site).kind {
|
||||
SiteKind::Refactor(site) | SiteKind::CliffTown(site) | SiteKind::DesertCity(site) => {
|
||||
let start = site.wpos_tile_pos(wpos.xy().as_());
|
||||
|
||||
let mut rng = SmallRng::from_seed([(time / 3.0) as u8 ^ seed as u8; 32]);
|
||||
|
||||
let end = site.plots[site.plazas().choose(&mut rng)?].root_tile();
|
||||
|
||||
if start == end {
|
||||
return None;
|
||||
}
|
||||
|
||||
let next_tile = match path_between(start, end, site) {
|
||||
PathResult::None(p) | PathResult::Exhausted(p) | PathResult::Path(p) => p.into_iter().nth(2),
|
||||
PathResult::Pending => None,
|
||||
}.unwrap_or(end);
|
||||
|
||||
let wpos = site.tile_center_wpos(next_tile).as_().with_z(wpos.z);
|
||||
|
||||
Some((wpos, 1.0))
|
||||
},
|
||||
_ => {
|
||||
// No brain T_T
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl Rule for NpcAi {
|
||||
fn start(rtstate: &mut RtState) -> Result<Self, RuleError> {
|
||||
rtstate.bind::<Self, OnTick>(|ctx| {
|
||||
@ -16,37 +136,11 @@ impl Rule for NpcAi {
|
||||
.and_then(|site_id| data.sites.get(site_id)?.world_site)
|
||||
{
|
||||
if let Some((target, _)) = npc.target {
|
||||
if target.distance_squared(npc.wpos) < 1.0 {
|
||||
if target.xy().distance_squared(npc.wpos.xy()) < 1.0 {
|
||||
npc.target = None;
|
||||
}
|
||||
} else {
|
||||
match &ctx.index.sites.get(home_id).kind {
|
||||
SiteKind::Refactor(site)
|
||||
| SiteKind::CliffTown(site)
|
||||
| SiteKind::DesertCity(site) => {
|
||||
let tile = site.wpos_tile_pos(npc.wpos.xy().as_());
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let cardinals = [
|
||||
Vec2::unit_x(),
|
||||
Vec2::unit_y(),
|
||||
-Vec2::unit_x(),
|
||||
-Vec2::unit_y(),
|
||||
];
|
||||
let next_tile = cardinals
|
||||
.iter()
|
||||
.map(|c| tile + *c)
|
||||
.filter(|tile| site.tiles.get(*tile).is_road()).choose(&mut rng).unwrap_or(tile);
|
||||
|
||||
let wpos =
|
||||
site.tile_center_wpos(next_tile).as_().with_z(npc.wpos.z);
|
||||
|
||||
npc.target = Some((wpos, 1.0));
|
||||
},
|
||||
_ => {
|
||||
// No brain T_T
|
||||
},
|
||||
}
|
||||
npc.target = path_town(npc.wpos, home_id, ctx.index, ctx.event.time, npc.seed);
|
||||
}
|
||||
} else {
|
||||
// TODO: Don't make homeless people walk around in circles
|
||||
|
@ -292,6 +292,7 @@ impl StateExt for State {
|
||||
.with(comp::Combo::default())
|
||||
.with(comp::Auras::default())
|
||||
.with(comp::Stance::default())
|
||||
.with(RepositionOnChunkLoad)
|
||||
}
|
||||
|
||||
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder {
|
||||
|
@ -3,11 +3,11 @@ pub mod plot;
|
||||
mod tile;
|
||||
pub mod util;
|
||||
|
||||
use self::tile::{HazardKind, KeepKind, RoofKind, Tile, TileGrid, TileKind, TILE_SIZE};
|
||||
use self::tile::{HazardKind, KeepKind, RoofKind, Tile, TileGrid, TILE_SIZE};
|
||||
pub use self::{
|
||||
gen::{aabr_with_z, Fill, Painter, Primitive, PrimitiveRef, Structure},
|
||||
plot::{Plot, PlotKind},
|
||||
util::Dir,
|
||||
util::Dir, tile::TileKind,
|
||||
};
|
||||
use crate::{
|
||||
sim::Path,
|
||||
@ -40,7 +40,7 @@ fn reseed(rng: &mut impl Rng) -> impl Rng { ChaChaRng::from_seed(rng.gen::<[u8;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Site {
|
||||
pub(crate) origin: Vec2<i32>,
|
||||
pub origin: Vec2<i32>,
|
||||
name: String,
|
||||
// NOTE: Do we want these to be public?
|
||||
pub tiles: TileGrid,
|
||||
@ -110,8 +110,8 @@ impl Site {
|
||||
pub fn bounds(&self) -> Aabr<i32> {
|
||||
let border = 1;
|
||||
Aabr {
|
||||
min: self.origin + self.tile_wpos(self.tiles.bounds.min - border),
|
||||
max: self.origin + self.tile_wpos(self.tiles.bounds.max + 1 + border),
|
||||
min: self.tile_wpos(self.tiles.bounds.min - border),
|
||||
max: self.tile_wpos(self.tiles.bounds.max + 1 + border),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ use vek::*;
|
||||
/// Represents house data generated by the `generate()` method
|
||||
pub struct House {
|
||||
/// Tile position of the door tile
|
||||
door_tile: Vec2<i32>,
|
||||
pub door_tile: Vec2<i32>,
|
||||
/// Axis aligned bounding region of tiles
|
||||
tile_aabr: Aabr<i32>,
|
||||
/// Axis aligned bounding region for the house
|
||||
|
@ -193,8 +193,8 @@ pub enum TileKind {
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Tile {
|
||||
pub(crate) kind: TileKind,
|
||||
pub(crate) plot: Option<Id<Plot>>,
|
||||
pub kind: TileKind,
|
||||
pub plot: Option<Id<Plot>>,
|
||||
pub(crate) hard_alt: Option<i32>,
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user