add flag to clamp to ground for RepositionOnChunkLoad

This commit is contained in:
Isse 2023-04-12 10:17:49 +02:00
parent 6be4a2b33f
commit 0bb6fa7946
7 changed files with 34 additions and 19 deletions

View File

@ -137,7 +137,7 @@ impl Link for Mounting {
let old_pos = pos.0.map(|e| e.floor() as i32);
pos.0 = safe_pos
.map(|p| p.0.map(|e| e.floor()))
.unwrap_or_else(|| terrain.find_space(old_pos).map(|e| e as f32))
.unwrap_or_else(|| terrain.find_ground(old_pos).map(|e| e as f32))
+ Vec3::new(0.5, 0.5, 0.0);
if let Some(force_update) = force_update.get_mut(rider) {
force_update.update();

View File

@ -222,11 +222,13 @@ impl TerrainChunkMeta {
pub type TerrainChunk = chonk::Chonk<Block, TerrainChunkSize, TerrainChunkMeta>;
pub type TerrainGrid = VolGrid2d<TerrainChunk>;
const TERRAIN_GRID_SEARCH_DIST: i32 = 63;
impl TerrainGrid {
/// Find a location suitable for spawning an entity near the given
/// position (but in the same chunk).
pub fn find_space(&self, pos: Vec3<i32>) -> Vec3<i32> {
self.try_find_space(pos).unwrap_or(pos)
pub fn find_ground(&self, pos: Vec3<i32>) -> Vec3<i32> {
self.try_find_ground(pos).unwrap_or(pos)
}
pub fn is_space(&self, pos: Vec3<i32>) -> bool {
@ -237,8 +239,14 @@ impl TerrainGrid {
}
pub fn try_find_space(&self, pos: Vec3<i32>) -> Option<Vec3<i32>> {
const SEARCH_DIST: i32 = 63;
(0..SEARCH_DIST * 2 + 1)
(0..TERRAIN_GRID_SEARCH_DIST * 2 + 1)
.map(|i| if i % 2 == 0 { i } else { -i } / 2)
.map(|z_diff| pos + Vec3::unit_z() * z_diff)
.find(|pos| self.is_space(*pos))
}
pub fn try_find_ground(&self, pos: Vec3<i32>) -> Option<Vec3<i32>> {
(0..TERRAIN_GRID_SEARCH_DIST * 2 + 1)
.map(|i| if i % 2 == 0 { i } else { -i } / 2)
.map(|z_diff| pos + Vec3::unit_z() * z_diff)
.find(|pos| {

View File

@ -1,6 +1,6 @@
use crate::{
client::Client, events::player::handle_exit_ingame, persistence::PersistedComponents, sys,
CharacterUpdater, Server, StateExt, presence::RepositionOnChunkLoad,
client::Client, events::player::handle_exit_ingame, persistence::PersistedComponents,
presence::RepositionOnChunkLoad, sys, CharacterUpdater, Server, StateExt,
};
use common::{
character::CharacterId,
@ -131,7 +131,9 @@ pub fn handle_create_npc(server: &mut Server, pos: Pos, mut npc: NpcBuilder) ->
};
let entity = if let Some(rtsim_entity) = npc.rtsim_entity {
entity.with(rtsim_entity).with(RepositionOnChunkLoad)
entity.with(rtsim_entity).with(RepositionOnChunkLoad {
needs_ground: false,
})
} else {
entity
};

View File

@ -1,6 +1,6 @@
use hashbrown::HashSet;
use serde::{Deserialize, Serialize};
use specs::{Component, NullStorage};
use specs::{Component, VecStorage};
use vek::*;
// Distance from fuzzy_chunk before snapping to current chunk
@ -20,8 +20,10 @@ impl Component for RegionSubscription {
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
pub struct RepositionOnChunkLoad;
pub struct RepositionOnChunkLoad {
pub needs_ground: bool,
}
impl Component for RepositionOnChunkLoad {
type Storage = NullStorage<Self>;
type Storage = VecStorage<Self>;
}

View File

@ -659,7 +659,9 @@ impl StateExt for State {
);
if let Some(waypoint) = waypoint {
self.write_component_ignore_entity_dead(entity, RepositionOnChunkLoad);
self.write_component_ignore_entity_dead(entity, RepositionOnChunkLoad {
needs_ground: true,
});
self.write_component_ignore_entity_dead(entity, waypoint);
self.write_component_ignore_entity_dead(entity, comp::Pos(waypoint.get_pos()));
self.write_component_ignore_entity_dead(entity, comp::Vel(Vec3::zero()));

View File

@ -66,7 +66,7 @@ impl<'a> System<'a> for Sys {
// TODO: Create a teleportation event to handle this instead of
// processing the entity position move here
pet_pos.0 = terrain
.find_space(owner_pos.0.map(|e| e.floor() as i32))
.find_ground(owner_pos.0.map(|e| e.floor() as i32))
.map(|e| e as f32);
}
}

View File

@ -228,11 +228,11 @@ impl<'a> System<'a> for Sys {
// TODO: Consider putting this in another system since this forces us to take
// positions by write rather than read access.
let repositioned = (&entities, &mut positions, (&mut force_update).maybe(), reposition_on_load.mask())
let repositioned = (&entities, &mut positions, (&mut force_update).maybe(), &mut reposition_on_load)
// TODO: Consider using par_bridge() because Rayon has very poor work splitting for
// sparse joins.
.par_join()
.filter_map(|(entity, pos, force_update, _)| {
.filter_map(|(entity, pos, force_update, reposition)| {
// NOTE: We use regular as casts rather than as_ because we want to saturate on
// overflow.
let entity_pos = pos.0.map(|x| x as i32);
@ -240,10 +240,11 @@ impl<'a> System<'a> for Sys {
// from having just logged in), reposition them.
let chunk_pos = TerrainGrid::chunk_key(entity_pos);
let chunk = terrain.get_key(chunk_pos)?;
let new_pos = terrain
.try_find_space(entity_pos)
.map(|x| x.as_::<f32>())
.unwrap_or_else(|| chunk.find_accessible_pos(entity_pos.xy(), false));
let new_pos = if reposition.needs_ground {
terrain.try_find_ground(entity_pos)
} else {
terrain.try_find_space(entity_pos)
}.map(|x| x.as_::<f32>()).unwrap_or_else(|| chunk.find_accessible_pos(entity_pos.xy(), false));
pos.0 = new_pos;
force_update.map(|force_update| force_update.update());
Some((entity, new_pos))