Spawn players aboveground when using /site or when their waypoint is underground.

This commit is contained in:
Avi Weinstock 2021-07-15 17:52:20 -04:00
parent eb08b6a153
commit 7555be0e25
6 changed files with 55 additions and 16 deletions

View File

@ -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

View File

@ -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

View File

@ -41,9 +41,12 @@ pub fn handle_loaded_character_data(
Option<comp::Waypoint>, Option<comp::Waypoint>,
), ),
) { ) {
server server.state.update_character_data(
.state entity,
.update_character_data(entity, loaded_components); loaded_components,
&*server.world,
&server.index.as_index_ref(),
);
sys::subscription::initialize_region_subscription(server.state.ecs(), entity); sys::subscription::initialize_region_subscription(server.state.ecs(), entity);
} }

View File

@ -343,7 +343,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();

View File

@ -97,7 +97,13 @@ pub trait StateExt {
fn initialize_character_data(&mut self, entity: EcsEntity, character_id: CharacterId); fn initialize_character_data(&mut self, entity: EcsEntity, character_id: CharacterId);
/// Update the components associated with the entity's current character. /// Update the components associated with the entity's current character.
/// Performed after loading component data from the database /// Performed after loading component data from the database
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents); fn update_character_data(
&mut self,
entity: EcsEntity,
components: PersistedComponents,
world: &world::World,
index: &world::IndexRef,
);
/// Iterates over registered clients and send each `ServerMsg` /// Iterates over registered clients and send each `ServerMsg`
fn send_chat(&self, msg: comp::UnresolvedChatMsg); fn send_chat(&self, msg: comp::UnresolvedChatMsg);
fn notify_players(&self, msg: ServerGeneral); fn notify_players(&self, msg: ServerGeneral);
@ -480,7 +486,13 @@ impl StateExt for State {
} }
} }
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents) { fn update_character_data(
&mut self,
entity: EcsEntity,
components: PersistedComponents,
world: &world::World,
index: &world::IndexRef,
) {
let (body, stats, skill_set, inventory, waypoint) = components; let (body, stats, skill_set, inventory, waypoint) = components;
if let Some(player_uid) = self.read_component_copied::<Uid>(entity) { if let Some(player_uid) = self.read_component_copied::<Uid>(entity) {
@ -525,8 +537,13 @@ impl StateExt for State {
); );
if let Some(waypoint) = waypoint { if let Some(waypoint) = waypoint {
// Avoid spawning the player in terrain by finding the highest solid point in
// their waypoint's column to spawn them at
let spawn_pos =
world.find_accessible_pos(*index, waypoint.get_pos().xy().as_::<i32>(), false);
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(spawn_pos));
self.write_component_ignore_entity_dead(entity, comp::Vel(Vec3::zero())); self.write_component_ignore_entity_dead(entity, comp::Vel(Vec3::zero()));
self.write_component_ignore_entity_dead(entity, comp::ForceUpdate); self.write_component_ignore_entity_dead(entity, comp::ForceUpdate);
} }

View File

@ -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,9 +189,13 @@ 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
@ -199,9 +205,19 @@ impl World {
let min_z = tc.get_min_z(); let min_z = tc.get_min_z();
let max_z = tc.get_max_z(); let max_z = tc.get_max_z();
let pos = Vec3::new(spawn_wpos.x, spawn_wpos.y, min_z); let pos = Vec3::new(
spawn_wpos.x,
spawn_wpos.y,
if ascending { min_z } else { max_z },
);
(0..(max_z - min_z)) (0..(max_z - min_z))
.map(|z_diff| pos + Vec3::unit_z() * z_diff) .map(|z_diff| {
if ascending {
pos + Vec3::unit_z() * z_diff
} else {
pos - Vec3::unit_z() * z_diff
}
})
.find(|test_pos| { .find(|test_pos| {
let chunk_relative_xy = test_pos let chunk_relative_xy = test_pos
.xy() .xy()