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

View File

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

View File

@ -41,9 +41,12 @@ pub fn handle_loaded_character_data(
Option<comp::Waypoint>,
),
) {
server
.state
.update_character_data(entity, loaded_components);
server.state.update_character_data(
entity,
loaded_components,
&*server.world,
&server.index.as_index_ref(),
);
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"))]
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);
/// Update the components associated with the entity's current character.
/// 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`
fn send_chat(&self, msg: comp::UnresolvedChatMsg);
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;
if let Some(player_uid) = self.read_component_copied::<Uid>(entity) {
@ -525,8 +537,13 @@ impl StateExt for State {
);
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, 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::ForceUpdate);
}

View File

@ -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,9 +189,13 @@ 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
@ -199,9 +205,19 @@ impl World {
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);
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| 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| {
let chunk_relative_xy = test_pos
.xy()