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",
|
"anymap2",
|
||||||
"atomic_refcell",
|
"atomic_refcell",
|
||||||
"enum-map",
|
"enum-map",
|
||||||
|
"fxhash",
|
||||||
"hashbrown 0.12.3",
|
"hashbrown 0.12.3",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
|
@ -17,3 +17,4 @@ tracing = "0.1"
|
|||||||
atomic_refcell = "0.1"
|
atomic_refcell = "0.1"
|
||||||
slotmap = { version = "1.0.6", features = ["serde"] }
|
slotmap = { version = "1.0.6", features = ["serde"] }
|
||||||
rand = { version = "0.8", features = ["small_rng"] }
|
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 std::hash::BuildHasherDefault;
|
||||||
use rand::seq::IteratorRandom;
|
|
||||||
use tracing::info;
|
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 vek::*;
|
||||||
use world::site::SiteKind;
|
use world::{
|
||||||
|
site::{Site as WorldSite, SiteKind},
|
||||||
|
site2::{self, TileKind},
|
||||||
|
IndexRef,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct NpcAi;
|
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 {
|
impl Rule for NpcAi {
|
||||||
fn start(rtstate: &mut RtState) -> Result<Self, RuleError> {
|
fn start(rtstate: &mut RtState) -> Result<Self, RuleError> {
|
||||||
rtstate.bind::<Self, OnTick>(|ctx| {
|
rtstate.bind::<Self, OnTick>(|ctx| {
|
||||||
@ -16,37 +136,11 @@ impl Rule for NpcAi {
|
|||||||
.and_then(|site_id| data.sites.get(site_id)?.world_site)
|
.and_then(|site_id| data.sites.get(site_id)?.world_site)
|
||||||
{
|
{
|
||||||
if let Some((target, _)) = npc.target {
|
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;
|
npc.target = None;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match &ctx.index.sites.get(home_id).kind {
|
npc.target = path_town(npc.wpos, home_id, ctx.index, ctx.event.time, npc.seed);
|
||||||
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
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO: Don't make homeless people walk around in circles
|
// TODO: Don't make homeless people walk around in circles
|
||||||
|
@ -292,6 +292,7 @@ impl StateExt for State {
|
|||||||
.with(comp::Combo::default())
|
.with(comp::Combo::default())
|
||||||
.with(comp::Auras::default())
|
.with(comp::Auras::default())
|
||||||
.with(comp::Stance::default())
|
.with(comp::Stance::default())
|
||||||
|
.with(RepositionOnChunkLoad)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder {
|
fn create_object(&mut self, pos: comp::Pos, object: comp::object::Body) -> EcsEntityBuilder {
|
||||||
|
@ -3,11 +3,11 @@ pub mod plot;
|
|||||||
mod tile;
|
mod tile;
|
||||||
pub mod util;
|
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::{
|
pub use self::{
|
||||||
gen::{aabr_with_z, Fill, Painter, Primitive, PrimitiveRef, Structure},
|
gen::{aabr_with_z, Fill, Painter, Primitive, PrimitiveRef, Structure},
|
||||||
plot::{Plot, PlotKind},
|
plot::{Plot, PlotKind},
|
||||||
util::Dir,
|
util::Dir, tile::TileKind,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
sim::Path,
|
sim::Path,
|
||||||
@ -40,7 +40,7 @@ fn reseed(rng: &mut impl Rng) -> impl Rng { ChaChaRng::from_seed(rng.gen::<[u8;
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Site {
|
pub struct Site {
|
||||||
pub(crate) origin: Vec2<i32>,
|
pub origin: Vec2<i32>,
|
||||||
name: String,
|
name: String,
|
||||||
// NOTE: Do we want these to be public?
|
// NOTE: Do we want these to be public?
|
||||||
pub tiles: TileGrid,
|
pub tiles: TileGrid,
|
||||||
@ -110,8 +110,8 @@ impl Site {
|
|||||||
pub fn bounds(&self) -> Aabr<i32> {
|
pub fn bounds(&self) -> Aabr<i32> {
|
||||||
let border = 1;
|
let border = 1;
|
||||||
Aabr {
|
Aabr {
|
||||||
min: self.origin + self.tile_wpos(self.tiles.bounds.min - border),
|
min: self.tile_wpos(self.tiles.bounds.min - border),
|
||||||
max: self.origin + self.tile_wpos(self.tiles.bounds.max + 1 + 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
|
/// Represents house data generated by the `generate()` method
|
||||||
pub struct House {
|
pub struct House {
|
||||||
/// Tile position of the door tile
|
/// Tile position of the door tile
|
||||||
door_tile: Vec2<i32>,
|
pub door_tile: Vec2<i32>,
|
||||||
/// Axis aligned bounding region of tiles
|
/// Axis aligned bounding region of tiles
|
||||||
tile_aabr: Aabr<i32>,
|
tile_aabr: Aabr<i32>,
|
||||||
/// Axis aligned bounding region for the house
|
/// Axis aligned bounding region for the house
|
||||||
|
@ -193,8 +193,8 @@ pub enum TileKind {
|
|||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct Tile {
|
pub struct Tile {
|
||||||
pub(crate) kind: TileKind,
|
pub kind: TileKind,
|
||||||
pub(crate) plot: Option<Id<Plot>>,
|
pub plot: Option<Id<Plot>>,
|
||||||
pub(crate) hard_alt: Option<i32>,
|
pub(crate) hard_alt: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user