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
|
- Significantly improved the performance of playing sound effects
|
||||||
- Dismantle and Material crafting tabs don't have duplicated recipes
|
- Dismantle and Material crafting tabs don't have duplicated recipes
|
||||||
- Campfires now despawn when underwater
|
- Campfires now despawn when underwater
|
||||||
|
- Players no longer spawn underground if their waypoint is underground
|
||||||
|
|
||||||
## [0.10.0] - 2021-06-12
|
## [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.
|
// Terrain helper functions used across multiple crates.
|
||||||
|
|
||||||
/// Computes the position Vec2 of a SimChunk from an index, where the index was
|
/// 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())?;
|
.ok_or_else(|| "Site not found".to_string())?;
|
||||||
|
|
||||||
let site_pos = server
|
let site_pos = server.world.find_accessible_pos(
|
||||||
.world
|
server.index.as_index_ref(),
|
||||||
.find_lowest_accessible_pos(server.index.as_index_ref(), site.center);
|
TerrainChunkSize::center_wpos(site.center),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
position_mut(server, target, "target", |current_pos| {
|
position_mut(server, target, "target", |current_pos| {
|
||||||
current_pos.0 = site_pos
|
current_pos.0 = site_pos
|
||||||
|
@ -50,7 +50,7 @@ use crate::{
|
|||||||
connection_handler::ConnectionHandler,
|
connection_handler::ConnectionHandler,
|
||||||
data_dir::DataDir,
|
data_dir::DataDir,
|
||||||
login_provider::LoginProvider,
|
login_provider::LoginProvider,
|
||||||
presence::{Presence, RegionSubscription},
|
presence::{Presence, RegionSubscription, RepositionOnChunkLoad},
|
||||||
rtsim::RtSim,
|
rtsim::RtSim,
|
||||||
state_ext::StateExt,
|
state_ext::StateExt,
|
||||||
sys::sentinel::{DeletedEntities, TrackedComps},
|
sys::sentinel::{DeletedEntities, TrackedComps},
|
||||||
@ -250,6 +250,7 @@ impl Server {
|
|||||||
state.ecs_mut().register::<wiring::Circuit>();
|
state.ecs_mut().register::<wiring::Circuit>();
|
||||||
state.ecs_mut().register::<comp::HomeChunk>();
|
state.ecs_mut().register::<comp::HomeChunk>();
|
||||||
state.ecs_mut().register::<login_provider::PendingLogin>();
|
state.ecs_mut().register::<login_provider::PendingLogin>();
|
||||||
|
state.ecs_mut().register::<RepositionOnChunkLoad>();
|
||||||
|
|
||||||
//Alias validator
|
//Alias validator
|
||||||
let banned_words_paths = &settings.banned_words_files;
|
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"))]
|
#[cfg(not(feature = "worldgen"))]
|
||||||
let spawn_point = SpawnPoint::default();
|
let spawn_point = SpawnPoint::default();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use common_net::msg::PresenceKind;
|
use common_net::msg::PresenceKind;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use specs::{Component, DerefFlaggedStorage};
|
use specs::{Component, DerefFlaggedStorage, NullStorage};
|
||||||
use specs_idvs::IdvStorage;
|
use specs_idvs::IdvStorage;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -40,3 +40,10 @@ pub struct RegionSubscription {
|
|||||||
impl Component for RegionSubscription {
|
impl Component for RegionSubscription {
|
||||||
type Storage = DerefFlaggedStorage<Self, IdvStorage<Self>>;
|
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::{
|
use crate::{
|
||||||
client::Client, persistence::PersistedComponents, presence::Presence, settings::Settings,
|
client::Client,
|
||||||
sys::sentinel::DeletedEntities, wiring, SpawnPoint,
|
persistence::PersistedComponents,
|
||||||
|
presence::{Presence, RepositionOnChunkLoad},
|
||||||
|
settings::Settings,
|
||||||
|
sys::sentinel::DeletedEntities,
|
||||||
|
wiring, SpawnPoint,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
character::CharacterId,
|
character::CharacterId,
|
||||||
@ -525,6 +529,7 @@ impl StateExt for State {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Some(waypoint) = waypoint {
|
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, waypoint);
|
||||||
self.write_component_ignore_entity_dead(entity, comp::Pos(waypoint.get_pos()));
|
self.write_component_ignore_entity_dead(entity, comp::Pos(waypoint.get_pos()));
|
||||||
self.write_component_ignore_entity_dead(entity, comp::Vel(Vec3::zero()));
|
self.write_component_ignore_entity_dead(entity, comp::Vel(Vec3::zero()));
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
chunk_generator::ChunkGenerator, client::Client, metrics::NetworkRequestMetrics,
|
chunk_generator::ChunkGenerator,
|
||||||
presence::Presence, rtsim::RtSim, settings::Settings, SpawnPoint, Tick,
|
client::Client,
|
||||||
|
metrics::NetworkRequestMetrics,
|
||||||
|
presence::{Presence, RepositionOnChunkLoad},
|
||||||
|
rtsim::RtSim,
|
||||||
|
settings::Settings,
|
||||||
|
SpawnPoint, Tick,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
comp::{self, agent, bird_medium, Alignment, BehaviorCapability, Pos},
|
comp::{self, agent, bird_medium, Alignment, BehaviorCapability, ForceUpdate, Pos},
|
||||||
event::{EventBus, ServerEvent},
|
event::{EventBus, ServerEvent},
|
||||||
generation::{get_npc_name, EntityInfo},
|
generation::{get_npc_name, EntityInfo},
|
||||||
npc::NPC_NAMES,
|
npc::NPC_NAMES,
|
||||||
@ -14,7 +19,7 @@ use common_ecs::{Job, Origin, Phase, System};
|
|||||||
use common_net::msg::{SerializedTerrainChunk, ServerGeneral};
|
use common_net::msg::{SerializedTerrainChunk, ServerGeneral};
|
||||||
use common_state::TerrainChanges;
|
use common_state::TerrainChanges;
|
||||||
use comp::Behavior;
|
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 std::sync::Arc;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
@ -93,9 +98,12 @@ impl<'a> System<'a> for Sys {
|
|||||||
WriteExpect<'a, TerrainGrid>,
|
WriteExpect<'a, TerrainGrid>,
|
||||||
Write<'a, TerrainChanges>,
|
Write<'a, TerrainChanges>,
|
||||||
WriteExpect<'a, RtSim>,
|
WriteExpect<'a, RtSim>,
|
||||||
ReadStorage<'a, Pos>,
|
WriteStorage<'a, Pos>,
|
||||||
ReadStorage<'a, Presence>,
|
ReadStorage<'a, Presence>,
|
||||||
ReadStorage<'a, Client>,
|
ReadStorage<'a, Client>,
|
||||||
|
Entities<'a>,
|
||||||
|
WriteStorage<'a, RepositionOnChunkLoad>,
|
||||||
|
WriteStorage<'a, ForceUpdate>,
|
||||||
);
|
);
|
||||||
|
|
||||||
const NAME: &'static str = "terrain";
|
const NAME: &'static str = "terrain";
|
||||||
@ -114,9 +122,12 @@ impl<'a> System<'a> for Sys {
|
|||||||
mut terrain,
|
mut terrain,
|
||||||
mut terrain_changes,
|
mut terrain_changes,
|
||||||
mut rtsim,
|
mut rtsim,
|
||||||
positions,
|
mut positions,
|
||||||
presences,
|
presences,
|
||||||
clients,
|
clients,
|
||||||
|
entities,
|
||||||
|
mut reposition_on_load,
|
||||||
|
mut force_update,
|
||||||
): Self::SystemData,
|
): Self::SystemData,
|
||||||
) {
|
) {
|
||||||
let mut server_emitter = server_event_bus.emitter();
|
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.
|
// Send the chunk to all nearby players.
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
new_chunks.into_par_iter().for_each(|(key, chunk)| {
|
new_chunks.into_par_iter().for_each(|(key, chunk)| {
|
||||||
|
@ -52,7 +52,9 @@ use common::{
|
|||||||
assets,
|
assets,
|
||||||
generation::{ChunkSupplement, EntityInfo},
|
generation::{ChunkSupplement, EntityInfo},
|
||||||
resources::TimeOfDay,
|
resources::TimeOfDay,
|
||||||
terrain::{Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
terrain::{
|
||||||
|
Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize, TerrainGrid,
|
||||||
|
},
|
||||||
vol::{ReadVol, RectVolSize, WriteVol},
|
vol::{ReadVol, RectVolSize, WriteVol},
|
||||||
};
|
};
|
||||||
use common_net::msg::{world_msg, WorldMapMsg};
|
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 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> {
|
pub fn find_accessible_pos(
|
||||||
// Calculate the middle of the chunk in the world
|
&self,
|
||||||
let spawn_wpos = TerrainChunkSize::center_wpos(chunk_pos);
|
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
|
// Unwrapping because generate_chunk only returns err when should_continue evals
|
||||||
// to true
|
// to true
|
||||||
let (tc, _cs) = self
|
let (tc, _cs) = self
|
||||||
.generate_chunk(index, chunk_pos, || false, None)
|
.generate_chunk(index, chunk_pos, || false, None)
|
||||||
.unwrap();
|
.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);
|
tc.find_accessible_pos(spawn_wpos, ascending)
|
||||||
(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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::eval_order_dependence)]
|
#[allow(clippy::eval_order_dependence)]
|
||||||
|
Loading…
Reference in New Issue
Block a user