mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Switched to _squared(), added comments, parallelised waypoint gen
This commit is contained in:
parent
9ee72eb810
commit
631124f3fc
@ -1,6 +1,6 @@
|
||||
#![deny(unsafe_code)]
|
||||
#![type_length_limit = "1664759"]
|
||||
#![feature(trait_alias, arbitrary_enum_discriminant)]
|
||||
#![feature(trait_alias, arbitrary_enum_discriminant, label_break_value)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
@ -89,8 +89,7 @@ impl Route {
|
||||
}
|
||||
}
|
||||
|
||||
// Chaser: A self-contained system that attempts to chase a moving target
|
||||
|
||||
/// A self-contained system that attempts to chase a moving target, only performing pathfinding if necessary
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct Chaser {
|
||||
last_search_tgt: Option<Vec3<f32>>,
|
||||
|
@ -80,83 +80,93 @@ impl<'a> System<'a> for Sys {
|
||||
let mut do_idle = false;
|
||||
let mut choose_target = false;
|
||||
|
||||
match &mut agent.activity {
|
||||
Activity::Idle(bearing) => {
|
||||
*bearing += Vec2::new(
|
||||
thread_rng().gen::<f32>() - 0.5,
|
||||
thread_rng().gen::<f32>() - 0.5,
|
||||
) * 0.1
|
||||
- *bearing * 0.01
|
||||
- if let Some(patrol_origin) = agent.patrol_origin {
|
||||
Vec2::<f32>::from(pos.0 - patrol_origin) * 0.0002
|
||||
} else {
|
||||
Vec2::zero()
|
||||
};
|
||||
'activity: {
|
||||
match &mut agent.activity {
|
||||
Activity::Idle(bearing) => {
|
||||
*bearing += Vec2::new(
|
||||
thread_rng().gen::<f32>() - 0.5,
|
||||
thread_rng().gen::<f32>() - 0.5,
|
||||
) * 0.1
|
||||
- *bearing * 0.01
|
||||
- if let Some(patrol_origin) = agent.patrol_origin {
|
||||
Vec2::<f32>::from(pos.0 - patrol_origin) * 0.0002
|
||||
} else {
|
||||
Vec2::zero()
|
||||
};
|
||||
|
||||
if bearing.magnitude_squared() > 0.25f32.powf(2.0) {
|
||||
inputs.move_dir = bearing.normalized() * 0.65;
|
||||
}
|
||||
|
||||
// Sometimes try searching for new targets
|
||||
if thread_rng().gen::<f32>() < 0.1 {
|
||||
choose_target = true;
|
||||
}
|
||||
}
|
||||
Activity::Follow(target, chaser) => {
|
||||
if let (Some(tgt_pos), _tgt_stats) =
|
||||
(positions.get(*target), stats.get(*target))
|
||||
{
|
||||
let dist = pos.0.distance(tgt_pos.0);
|
||||
// Follow, or return to idle
|
||||
if dist > AVG_FOLLOW_DIST {
|
||||
if let Some(bearing) =
|
||||
chaser.chase(&*terrain, pos.0, tgt_pos.0, AVG_FOLLOW_DIST)
|
||||
{
|
||||
inputs.move_dir =
|
||||
Vec2::from(bearing).try_normalized().unwrap_or(Vec2::zero());
|
||||
inputs.jump.set_state(bearing.z > 1.0);
|
||||
}
|
||||
} else {
|
||||
do_idle = true;
|
||||
if bearing.magnitude_squared() > 0.25f32.powf(2.0) {
|
||||
inputs.move_dir = bearing.normalized() * 0.65;
|
||||
}
|
||||
|
||||
// Sometimes try searching for new targets
|
||||
if thread_rng().gen::<f32>() < 0.1 {
|
||||
choose_target = true;
|
||||
}
|
||||
} else {
|
||||
do_idle = true;
|
||||
}
|
||||
}
|
||||
Activity::Attack(target, chaser, _) => {
|
||||
if let (Some(tgt_pos), _tgt_stats, tgt_alignment) = (
|
||||
positions.get(*target),
|
||||
stats.get(*target),
|
||||
alignments.get(*target),
|
||||
) {
|
||||
// Don't attack aligned entities
|
||||
if let (Some(alignment), Some(tgt_alignment)) = (alignment, tgt_alignment) {
|
||||
if !tgt_alignment.hostile_towards(*alignment) {
|
||||
Activity::Follow(target, chaser) => {
|
||||
if let (Some(tgt_pos), _tgt_stats) =
|
||||
(positions.get(*target), stats.get(*target))
|
||||
{
|
||||
let dist_sqrd = pos.0.distance_squared(tgt_pos.0);
|
||||
// Follow, or return to idle
|
||||
if dist_sqrd > AVG_FOLLOW_DIST.powf(2.0) {
|
||||
if let Some(bearing) =
|
||||
chaser.chase(&*terrain, pos.0, tgt_pos.0, AVG_FOLLOW_DIST)
|
||||
{
|
||||
inputs.move_dir = Vec2::from(bearing)
|
||||
.try_normalized()
|
||||
.unwrap_or(Vec2::zero());
|
||||
inputs.jump.set_state(bearing.z > 1.0);
|
||||
}
|
||||
} else {
|
||||
do_idle = true;
|
||||
}
|
||||
} else {
|
||||
do_idle = true;
|
||||
}
|
||||
}
|
||||
Activity::Attack(target, chaser, _) => {
|
||||
if let (Some(tgt_pos), _tgt_stats, tgt_alignment) = (
|
||||
positions.get(*target),
|
||||
stats.get(*target),
|
||||
alignments.get(*target),
|
||||
) {
|
||||
// Don't attack aligned entities
|
||||
// TODO: This is a bit of a hack, find a better way to do this
|
||||
if let (Some(alignment), Some(tgt_alignment)) =
|
||||
(alignment, tgt_alignment)
|
||||
{
|
||||
if !tgt_alignment.hostile_towards(*alignment) {
|
||||
do_idle = true;
|
||||
break 'activity;
|
||||
}
|
||||
}
|
||||
|
||||
let dist = pos.0.distance(tgt_pos.0);
|
||||
if dist < MIN_ATTACK_DIST {
|
||||
// Close-range attack
|
||||
inputs.look_dir = tgt_pos.0 - pos.0;
|
||||
inputs.move_dir = Vec2::from(tgt_pos.0 - pos.0)
|
||||
.try_normalized()
|
||||
.unwrap_or(Vec2::unit_y())
|
||||
* 0.01;
|
||||
inputs.primary.set_state(true);
|
||||
} else if dist < MAX_CHASE_DIST {
|
||||
// Long-range chase
|
||||
if let Some(bearing) = chaser.chase(&*terrain, pos.0, tgt_pos.0, 1.25) {
|
||||
inputs.move_dir =
|
||||
Vec2::from(bearing).try_normalized().unwrap_or(Vec2::zero());
|
||||
inputs.jump.set_state(bearing.z > 1.0);
|
||||
let dist_sqrd = pos.0.distance_squared(tgt_pos.0);
|
||||
if dist_sqrd < MIN_ATTACK_DIST.powf(2.0) {
|
||||
// Close-range attack
|
||||
inputs.look_dir = tgt_pos.0 - pos.0;
|
||||
inputs.move_dir = Vec2::from(tgt_pos.0 - pos.0)
|
||||
.try_normalized()
|
||||
.unwrap_or(Vec2::unit_y())
|
||||
* 0.01;
|
||||
inputs.primary.set_state(true);
|
||||
} else if dist_sqrd < MAX_CHASE_DIST.powf(2.0) {
|
||||
// Long-range chase
|
||||
if let Some(bearing) =
|
||||
chaser.chase(&*terrain, pos.0, tgt_pos.0, 1.25)
|
||||
{
|
||||
inputs.move_dir = Vec2::from(bearing)
|
||||
.try_normalized()
|
||||
.unwrap_or(Vec2::zero());
|
||||
inputs.jump.set_state(bearing.z > 1.0);
|
||||
}
|
||||
} else {
|
||||
do_idle = true;
|
||||
}
|
||||
} else {
|
||||
do_idle = true;
|
||||
}
|
||||
} else {
|
||||
do_idle = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,12 +175,15 @@ impl<'a> System<'a> for Sys {
|
||||
agent.activity = Activity::Idle(Vec2::zero());
|
||||
}
|
||||
|
||||
// Choose a new target to attack: only go out of our way to attack targets we are
|
||||
// hostile toward!
|
||||
if choose_target {
|
||||
// Search for new targets
|
||||
// Search for new targets (this looks expensive, but it's only run occasionally)
|
||||
// TODO: Replace this with a better system that doesn't consider *all* entities
|
||||
let entities = (&entities, &positions, &stats, alignments.maybe())
|
||||
.join()
|
||||
.filter(|(e, e_pos, e_stats, e_alignment)| {
|
||||
(e_pos.0 - pos.0).magnitude() < SIGHT_DIST
|
||||
(e_pos.0 - pos.0).magnitude_squared() < SIGHT_DIST.powf(2.0)
|
||||
&& *e != entity
|
||||
&& !e_stats.is_dead
|
||||
&& alignment
|
||||
@ -206,8 +219,8 @@ impl<'a> System<'a> for Sys {
|
||||
// Follow owner if we're too far, or if they're under attack
|
||||
if let Some(owner) = agent.owner {
|
||||
if let Some(owner_pos) = positions.get(owner) {
|
||||
let dist = pos.0.distance(owner_pos.0);
|
||||
if dist > MAX_FOLLOW_DIST && !agent.activity.is_follow() {
|
||||
let dist_sqrd = pos.0.distance_squared(owner_pos.0);
|
||||
if dist_sqrd > MAX_FOLLOW_DIST.powf(2.0) && !agent.activity.is_follow() {
|
||||
agent.activity = Activity::Follow(owner, Chaser::default());
|
||||
}
|
||||
|
||||
|
@ -1088,10 +1088,11 @@ fn handle_remove_lights(
|
||||
match opt_player_pos {
|
||||
Some(player_pos) => {
|
||||
let ecs = server.state.ecs();
|
||||
for (entity, pos, _, _) in (
|
||||
for (entity, pos, _, _, _) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<comp::Pos>(),
|
||||
&ecs.read_storage::<comp::LightEmitter>(),
|
||||
!&ecs.read_storage::<comp::WaypointArea>(),
|
||||
!&ecs.read_storage::<comp::Player>(),
|
||||
)
|
||||
.join()
|
||||
|
@ -1,11 +1,8 @@
|
||||
use common::comp::{Player, Pos, Waypoint, WaypointArea};
|
||||
use specs::{Entities, Join, ReadStorage, System, WriteStorage};
|
||||
|
||||
/// This system will handle loading generated chunks and unloading uneeded chunks.
|
||||
/// 1. Inserts newly generated chunks into the TerrainGrid
|
||||
/// 2. Sends new chunks to neaby clients
|
||||
/// 3. Handles the chunk's supplement (e.g. npcs)
|
||||
/// 4. Removes chunks outside the range of players
|
||||
/// This system updates player waypoints
|
||||
/// TODO: Make this faster by only considering local waypoints
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
|
@ -1454,40 +1454,41 @@ impl WorldSim {
|
||||
.map(|i| {
|
||||
(0..WORLD_SIZE.y)
|
||||
.step_by(WAYPOINT_EVERY)
|
||||
.filter_map(move |j| {
|
||||
let mut pos = Vec2::new(i as i32, j as i32);
|
||||
|
||||
// Slide the waypoints down hills
|
||||
for _ in 0..32 {
|
||||
let last_pos = pos;
|
||||
let chunk = this.get(pos)?;
|
||||
|
||||
for dir in [
|
||||
Vec2::new(1, 0),
|
||||
Vec2::new(-1, 0),
|
||||
Vec2::new(0, 1),
|
||||
Vec2::new(0, -1),
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
const MAX_HEIGHT_DIFF: f32 = 8.0;
|
||||
let tgt_chunk = this.get(pos + *dir)?;
|
||||
if tgt_chunk.alt + MAX_HEIGHT_DIFF < chunk.alt
|
||||
&& !tgt_chunk.is_underwater
|
||||
{
|
||||
pos += *dir;
|
||||
}
|
||||
}
|
||||
|
||||
if last_pos == pos {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Some(pos)
|
||||
})
|
||||
.map(move |j| (i, j))
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
.into_par_iter()
|
||||
.filter_map(|(i, j)| {
|
||||
let mut pos = Vec2::new(i as i32, j as i32);
|
||||
|
||||
// Slide the waypoints down hills
|
||||
for _ in 0..32 {
|
||||
let last_pos = pos;
|
||||
let chunk = this.get(pos)?;
|
||||
|
||||
for dir in [
|
||||
Vec2::new(1, 0),
|
||||
Vec2::new(-1, 0),
|
||||
Vec2::new(0, 1),
|
||||
Vec2::new(0, -1),
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
const MAX_HEIGHT_DIFF: f32 = 8.0;
|
||||
let tgt_chunk = this.get(pos + *dir)?;
|
||||
if tgt_chunk.alt + MAX_HEIGHT_DIFF < chunk.alt && !tgt_chunk.is_underwater {
|
||||
pos += *dir;
|
||||
}
|
||||
}
|
||||
|
||||
if last_pos == pos {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Some(pos)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for waypoint in waypoints {
|
||||
|
Loading…
Reference in New Issue
Block a user