mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'aweinstock/fix-waypoint' into 'master'
Spawn players aboveground when using `/site` or when their waypoint is underground. See merge request veloren/veloren!2612
This commit is contained in:
commit
eb999b2821
@ -49,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Significantly improved the performance of playing sound effects
|
||||
- Dismantle and Material crafting tabs don't have duplicated recipes
|
||||
- Campfires now despawn when underwater
|
||||
- Players no longer spawn underground if their waypoint is underground
|
||||
|
||||
## [0.10.0] - 2021-06-12
|
||||
|
||||
|
@ -175,6 +175,48 @@ impl TerrainGrid {
|
||||
}
|
||||
}
|
||||
|
||||
impl TerrainChunk {
|
||||
/// Find the highest or lowest accessible position within the chunk
|
||||
pub fn find_accessible_pos(&self, spawn_wpos: Vec2<i32>, ascending: bool) -> Vec3<f32> {
|
||||
let min_z = self.get_min_z();
|
||||
let max_z = self.get_max_z();
|
||||
|
||||
let pos = Vec3::new(
|
||||
spawn_wpos.x,
|
||||
spawn_wpos.y,
|
||||
if ascending { min_z } else { max_z },
|
||||
);
|
||||
(0..(max_z - min_z))
|
||||
.map(|z_diff| {
|
||||
if ascending {
|
||||
pos + Vec3::unit_z() * z_diff
|
||||
} else {
|
||||
pos - Vec3::unit_z() * z_diff
|
||||
}
|
||||
})
|
||||
.find(|test_pos| {
|
||||
let chunk_relative_xy = test_pos
|
||||
.xy()
|
||||
.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e.rem_euclid(sz as i32));
|
||||
self.get(
|
||||
Vec3::new(chunk_relative_xy.x, chunk_relative_xy.y, test_pos.z)
|
||||
- Vec3::unit_z(),
|
||||
)
|
||||
.map_or(false, |b| b.is_filled())
|
||||
&& (0..3).all(|z| {
|
||||
self.get(
|
||||
Vec3::new(chunk_relative_xy.x, chunk_relative_xy.y, test_pos.z)
|
||||
+ Vec3::unit_z() * z,
|
||||
)
|
||||
.map_or(true, |b| !b.is_solid())
|
||||
})
|
||||
})
|
||||
.unwrap_or(pos)
|
||||
.map(|e| e as f32)
|
||||
+ 0.5
|
||||
}
|
||||
}
|
||||
|
||||
// Terrain helper functions used across multiple crates.
|
||||
|
||||
/// Computes the position Vec2 of a SimChunk from an index, where the index was
|
||||
|
@ -676,9 +676,11 @@ fn handle_site(
|
||||
})
|
||||
.ok_or_else(|| "Site not found".to_string())?;
|
||||
|
||||
let site_pos = server
|
||||
.world
|
||||
.find_lowest_accessible_pos(server.index.as_index_ref(), site.center);
|
||||
let site_pos = server.world.find_accessible_pos(
|
||||
server.index.as_index_ref(),
|
||||
TerrainChunkSize::center_wpos(site.center),
|
||||
false,
|
||||
);
|
||||
|
||||
position_mut(server, target, "target", |current_pos| {
|
||||
current_pos.0 = site_pos
|
||||
|
@ -50,7 +50,7 @@ use crate::{
|
||||
connection_handler::ConnectionHandler,
|
||||
data_dir::DataDir,
|
||||
login_provider::LoginProvider,
|
||||
presence::{Presence, RegionSubscription},
|
||||
presence::{Presence, RegionSubscription, RepositionOnChunkLoad},
|
||||
rtsim::RtSim,
|
||||
state_ext::StateExt,
|
||||
sys::sentinel::{DeletedEntities, TrackedComps},
|
||||
@ -250,6 +250,7 @@ impl Server {
|
||||
state.ecs_mut().register::<wiring::Circuit>();
|
||||
state.ecs_mut().register::<comp::HomeChunk>();
|
||||
state.ecs_mut().register::<login_provider::PendingLogin>();
|
||||
state.ecs_mut().register::<RepositionOnChunkLoad>();
|
||||
|
||||
//Alias validator
|
||||
let banned_words_paths = &settings.banned_words_files;
|
||||
@ -343,7 +344,7 @@ impl Server {
|
||||
},
|
||||
};
|
||||
|
||||
world.find_lowest_accessible_pos(index, spawn_chunk)
|
||||
world.find_accessible_pos(index, TerrainChunkSize::center_wpos(spawn_chunk), false)
|
||||
});
|
||||
#[cfg(not(feature = "worldgen"))]
|
||||
let spawn_point = SpawnPoint::default();
|
||||
|
@ -1,7 +1,7 @@
|
||||
use common_net::msg::PresenceKind;
|
||||
use hashbrown::HashSet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specs::{Component, DerefFlaggedStorage};
|
||||
use specs::{Component, DerefFlaggedStorage, NullStorage};
|
||||
use specs_idvs::IdvStorage;
|
||||
use vek::*;
|
||||
|
||||
@ -40,3 +40,10 @@ pub struct RegionSubscription {
|
||||
impl Component for RegionSubscription {
|
||||
type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct RepositionOnChunkLoad;
|
||||
|
||||
impl Component for RepositionOnChunkLoad {
|
||||
type Storage = NullStorage<Self>;
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
use crate::{
|
||||
client::Client, persistence::PersistedComponents, presence::Presence, settings::Settings,
|
||||
sys::sentinel::DeletedEntities, wiring, SpawnPoint,
|
||||
client::Client,
|
||||
persistence::PersistedComponents,
|
||||
presence::{Presence, RepositionOnChunkLoad},
|
||||
settings::Settings,
|
||||
sys::sentinel::DeletedEntities,
|
||||
wiring, SpawnPoint,
|
||||
};
|
||||
use common::{
|
||||
character::CharacterId,
|
||||
@ -525,6 +529,7 @@ impl StateExt for State {
|
||||
);
|
||||
|
||||
if let Some(waypoint) = waypoint {
|
||||
self.write_component_ignore_entity_dead(entity, RepositionOnChunkLoad);
|
||||
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()));
|
||||
|
@ -1,9 +1,14 @@
|
||||
use crate::{
|
||||
chunk_generator::ChunkGenerator, client::Client, metrics::NetworkRequestMetrics,
|
||||
presence::Presence, rtsim::RtSim, settings::Settings, SpawnPoint, Tick,
|
||||
chunk_generator::ChunkGenerator,
|
||||
client::Client,
|
||||
metrics::NetworkRequestMetrics,
|
||||
presence::{Presence, RepositionOnChunkLoad},
|
||||
rtsim::RtSim,
|
||||
settings::Settings,
|
||||
SpawnPoint, Tick,
|
||||
};
|
||||
use common::{
|
||||
comp::{self, agent, bird_medium, Alignment, BehaviorCapability, Pos},
|
||||
comp::{self, agent, bird_medium, Alignment, BehaviorCapability, ForceUpdate, Pos},
|
||||
event::{EventBus, ServerEvent},
|
||||
generation::{get_npc_name, EntityInfo},
|
||||
npc::NPC_NAMES,
|
||||
@ -14,7 +19,7 @@ use common_ecs::{Job, Origin, Phase, System};
|
||||
use common_net::msg::{SerializedTerrainChunk, ServerGeneral};
|
||||
use common_state::TerrainChanges;
|
||||
use comp::Behavior;
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, Write, WriteExpect};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, Write, WriteExpect, WriteStorage};
|
||||
use std::sync::Arc;
|
||||
use vek::*;
|
||||
|
||||
@ -93,9 +98,12 @@ impl<'a> System<'a> for Sys {
|
||||
WriteExpect<'a, TerrainGrid>,
|
||||
Write<'a, TerrainChanges>,
|
||||
WriteExpect<'a, RtSim>,
|
||||
ReadStorage<'a, Pos>,
|
||||
WriteStorage<'a, Pos>,
|
||||
ReadStorage<'a, Presence>,
|
||||
ReadStorage<'a, Client>,
|
||||
Entities<'a>,
|
||||
WriteStorage<'a, RepositionOnChunkLoad>,
|
||||
WriteStorage<'a, ForceUpdate>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "terrain";
|
||||
@ -114,9 +122,12 @@ impl<'a> System<'a> for Sys {
|
||||
mut terrain,
|
||||
mut terrain_changes,
|
||||
mut rtsim,
|
||||
positions,
|
||||
mut positions,
|
||||
presences,
|
||||
clients,
|
||||
entities,
|
||||
mut reposition_on_load,
|
||||
mut force_update,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let mut server_emitter = server_event_bus.emitter();
|
||||
@ -306,6 +317,24 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
|
||||
let mut repositioned = Vec::new();
|
||||
for (entity, pos, _) in (&entities, &mut positions, &reposition_on_load).join() {
|
||||
// If an entity is marked as needing repositioning once the chunk loads (e.g.
|
||||
// from having just logged in), reposition them.
|
||||
|
||||
let chunk_pos = terrain.pos_key(pos.0.map(|e| e as i32));
|
||||
if let Some(chunk) = terrain.get_key(chunk_pos) {
|
||||
pos.0 = chunk
|
||||
.find_accessible_pos(pos.0.xy().as_::<i32>(), false)
|
||||
.as_::<f32>();
|
||||
repositioned.push(entity);
|
||||
let _ = force_update.insert(entity, ForceUpdate);
|
||||
}
|
||||
}
|
||||
for entity in repositioned {
|
||||
reposition_on_load.remove(entity);
|
||||
}
|
||||
|
||||
// Send the chunk to all nearby players.
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
new_chunks.into_par_iter().for_each(|(key, chunk)| {
|
||||
|
@ -52,7 +52,9 @@ use common::{
|
||||
assets,
|
||||
generation::{ChunkSupplement, EntityInfo},
|
||||
resources::TimeOfDay,
|
||||
terrain::{Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
||||
terrain::{
|
||||
Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize, TerrainGrid,
|
||||
},
|
||||
vol::{ReadVol, RectVolSize, WriteVol},
|
||||
};
|
||||
use common_net::msg::{world_msg, WorldMapMsg};
|
||||
@ -187,41 +189,21 @@ impl World {
|
||||
|
||||
pub fn sample_blocks(&self) -> BlockGen { BlockGen::new(ColumnGen::new(&self.sim)) }
|
||||
|
||||
pub fn find_lowest_accessible_pos(&self, index: IndexRef, chunk_pos: Vec2<i32>) -> Vec3<f32> {
|
||||
// Calculate the middle of the chunk in the world
|
||||
let spawn_wpos = TerrainChunkSize::center_wpos(chunk_pos);
|
||||
pub fn find_accessible_pos(
|
||||
&self,
|
||||
index: IndexRef,
|
||||
spawn_wpos: Vec2<i32>,
|
||||
ascending: bool,
|
||||
) -> Vec3<f32> {
|
||||
let chunk_pos = TerrainGrid::chunk_key(spawn_wpos);
|
||||
|
||||
// Unwrapping because generate_chunk only returns err when should_continue evals
|
||||
// to true
|
||||
let (tc, _cs) = self
|
||||
.generate_chunk(index, chunk_pos, || false, None)
|
||||
.unwrap();
|
||||
let min_z = tc.get_min_z();
|
||||
let max_z = tc.get_max_z();
|
||||
|
||||
let pos = Vec3::new(spawn_wpos.x, spawn_wpos.y, min_z);
|
||||
(0..(max_z - min_z))
|
||||
.map(|z_diff| pos + Vec3::unit_z() * z_diff)
|
||||
.find(|test_pos| {
|
||||
let chunk_relative_xy = test_pos
|
||||
.xy()
|
||||
.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e.rem_euclid(sz as i32));
|
||||
tc.get(
|
||||
Vec3::new(chunk_relative_xy.x, chunk_relative_xy.y, test_pos.z)
|
||||
- Vec3::unit_z(),
|
||||
)
|
||||
.map_or(false, |b| b.is_filled())
|
||||
&& (0..3).all(|z| {
|
||||
tc.get(
|
||||
Vec3::new(chunk_relative_xy.x, chunk_relative_xy.y, test_pos.z)
|
||||
+ Vec3::unit_z() * z,
|
||||
)
|
||||
.map_or(true, |b| !b.is_solid())
|
||||
})
|
||||
})
|
||||
.unwrap_or(pos)
|
||||
.map(|e| e as f32)
|
||||
+ 0.5
|
||||
tc.find_accessible_pos(spawn_wpos, ascending)
|
||||
}
|
||||
|
||||
#[allow(clippy::eval_order_dependence)]
|
||||
|
Loading…
Reference in New Issue
Block a user