diff --git a/crates/valence/examples/death.rs b/crates/valence/examples/death.rs index 9232480..33fe9f5 100644 --- a/crates/valence/examples/death.rs +++ b/crates/valence/examples/death.rs @@ -22,7 +22,7 @@ fn setup( dimensions: Query<&DimensionType>, biomes: Query<&Biome>, ) { - for block in [BlockState::GRASS_BLOCK, BlockState::DEEPSLATE] { + for block in [BlockState::GRASS_BLOCK, BlockState::DEEPSLATE, BlockState::MAGMA_BLOCK] { let mut instance = Instance::new(ident!("overworld"), &dimensions, &biomes, &server); for z in -5..5 { @@ -42,21 +42,12 @@ fn setup( } fn init_clients( - mut clients: Query< - ( - &mut Client, - &mut Location, - &mut Position, - &mut HasRespawnScreen, - ), - Added, - >, + mut clients: Query<(&mut Client, &mut Location, &mut Position), Added>, instances: Query>, ) { - for (mut client, mut loc, mut pos, mut has_respawn_screen) in &mut clients { + for (mut client, mut loc, mut pos) in &mut clients { loc.0 = instances.iter().next().unwrap(); pos.set([0.0, SPAWN_Y as f64 + 1.0, 0.0]); - has_respawn_screen.0 = true; client.send_message( "Welcome to Valence! Sneak to die in the game (but not in real life).".italic(), @@ -75,15 +66,13 @@ fn squat_and_die(mut clients: Query<&mut Client>, mut events: EventReader, + mut clients: Query<(&mut Location, &mut RespawnPosition)>, mut events: EventReader, instances: Query>, ) { for event in events.iter() { - if let Ok((mut pos, mut look, mut loc)) = clients.get_mut(event.client) { - pos.set([0.0, SPAWN_Y as f64 + 1.0, 0.0]); - look.yaw = 0.0; - look.pitch = 0.0; + if let Ok((mut loc, mut spawn_pos)) = clients.get_mut(event.client) { + spawn_pos.pos = BlockPos::new(0, SPAWN_Y, 0); // make the client respawn in another instance let idx = instances.iter().position(|i| i == loc.0).unwrap(); diff --git a/crates/valence/src/lib.rs b/crates/valence/src/lib.rs index e316d0e..99d0133 100644 --- a/crates/valence/src/lib.rs +++ b/crates/valence/src/lib.rs @@ -65,7 +65,7 @@ pub mod prelude { pub use client::event_loop::{EventLoopSchedule, EventLoopSet}; pub use client::interact_entity::*; pub use client::{ - despawn_disconnected_clients, Client, CompassPos, DeathLocation, HasRespawnScreen, + despawn_disconnected_clients, Client, RespawnPosition, DeathLocation, HasRespawnScreen, HashedSeed, Ip, IsDebug, IsFlat, IsHardcore, OldView, OldViewDistance, OpLevel, PrevGameMode, Properties, ReducedDebugInfo, Username, View, ViewDistance, }; diff --git a/crates/valence_client/src/lib.rs b/crates/valence_client/src/lib.rs index 37c6eb6..63fdec4 100644 --- a/crates/valence_client/src/lib.rs +++ b/crates/valence_client/src/lib.rs @@ -108,9 +108,9 @@ impl Plugin for ClientPlugin { .after(WriteUpdatePacketsToInstancesSet) .after(update_chunk_load_dist), update_view.after(initial_join).after(read_data_in_old_view), - respawn.after(update_view), + update_respawn_position.after(update_view), + respawn.after(update_respawn_position), remove_entities.after(update_view), - update_spawn_position.after(update_view), update_old_view_dist.after(update_view), update_game_mode, update_tracked_data.after(WriteUpdatePacketsToInstancesSet), @@ -154,7 +154,7 @@ pub struct ClientBundle { pub username: Username, pub ip: Ip, pub properties: Properties, - pub compass_pos: CompassPos, + pub respawn_pos: RespawnPosition, pub game_mode: GameMode, pub op_level: OpLevel, pub action_sequence: action::ActionSequence, @@ -187,7 +187,7 @@ impl ClientBundle { username: Username(args.username), ip: Ip(args.ip), properties: Properties(args.properties), - compass_pos: CompassPos::default(), + respawn_pos: RespawnPosition::default(), game_mode: GameMode::default(), op_level: OpLevel::default(), action_sequence: action::ActionSequence::default(), @@ -589,9 +589,16 @@ impl Deref for Properties { #[derive(Component, Clone, PartialEq, Eq, Debug)] pub struct Ip(pub IpAddr); -/// The position that regular compass items will point to. -#[derive(Component, Copy, Clone, PartialEq, Eq, Default, Debug)] -pub struct CompassPos(pub BlockPos); +/// The position and angle that clients will respawn with. Also +/// controls the position that compasses point towards. +#[derive(Component, Copy, Clone, PartialEq, Default, Debug)] +pub struct RespawnPosition { + /// The position that clients will respawn at. This can be changed at any + /// time to set the position that compasses point towards. + pub pos: BlockPos, + /// The yaw angle that clients will respawn with (in degrees). + pub yaw: f32, +} #[derive(Component, Clone, PartialEq, Eq, Default, Debug)] pub struct OpLevel(u8); @@ -948,7 +955,7 @@ fn read_data_in_old_view( &Position, &OldPosition, &OldViewDistance, - Option<&PacketByteRange>, + &PacketByteRange, )>, instances: Query<&Instance>, entities: Query<(EntityInitQuery, &OldPosition)>, @@ -1010,15 +1017,12 @@ fn read_data_in_old_view( // Send all data in the chunk's packet buffer to this client. This will update // entities in the cell, spawn or update the chunk in the cell, or send any // other packet data that was added here by users. - match byte_range { - Some(byte_range) if pos == new_chunk_pos && loc == old_loc => { - // Skip range of bytes for the client's own entity. - client.write_packet_bytes(&cell.packet_buf[..byte_range.0.start]); - client.write_packet_bytes(&cell.packet_buf[byte_range.0.end..]); - } - _ => { - client.write_packet_bytes(&cell.packet_buf); - } + if pos == new_chunk_pos && loc == old_loc { + // Skip range of bytes for the client's own entity. + client.write_packet_bytes(&cell.packet_buf[..byte_range.0.start]); + client.write_packet_bytes(&cell.packet_buf[byte_range.0.end..]); + } else { + client.write_packet_bytes(&cell.packet_buf); } } }); @@ -1223,15 +1227,17 @@ fn update_old_view_dist( } } -/// Sets the client's compass position. +/// Sets the client's respawn and compass position. /// /// This also closes the "downloading terrain" screen when first joining, so /// it should happen after the initial chunks are written. -fn update_spawn_position(mut clients: Query<(&mut Client, &CompassPos), Changed>) { - for (mut client, compass_pos) in &mut clients { +fn update_respawn_position( + mut clients: Query<(&mut Client, &RespawnPosition), Changed>, +) { + for (mut client, respawn_pos) in &mut clients { client.write_packet(&PlayerSpawnPositionS2c { - position: compass_pos.0, - angle: 0.0, // TODO: does this do anything? + position: respawn_pos.pos, + angle: respawn_pos.yaw, }); } } diff --git a/crates/valence_client/src/teleport.rs b/crates/valence_client/src/teleport.rs index 003ab6e..9130ef6 100644 --- a/crates/valence_client/src/teleport.rs +++ b/crates/valence_client/src/teleport.rs @@ -4,12 +4,17 @@ use super::*; use crate::event_loop::{EventLoopSchedule, EventLoopSet, PacketEvent}; pub(super) fn build(app: &mut App) { - app.add_system(teleport.after(update_view).in_set(UpdateClientsSet)) - .add_system( - handle_teleport_confirmations - .in_schedule(EventLoopSchedule) - .in_base_set(EventLoopSet::PreUpdate), - ); + app.add_system( + teleport + .after(update_view) + .before(update_respawn_position) + .in_set(UpdateClientsSet), + ) + .add_system( + handle_teleport_confirmations + .in_schedule(EventLoopSchedule) + .in_base_set(EventLoopSet::PreUpdate), + ); } #[derive(Component, Debug)] @@ -29,11 +34,12 @@ impl TeleportState { Self { teleport_id_counter: 0, pending_teleports: 0, - synced_pos: DVec3::ZERO, + // Set initial synced pos and look to NaN so a teleport always happens when first + // joining. + synced_pos: DVec3::NAN, synced_look: Look { - // Client starts facing north. - yaw: 180.0, - pitch: 0.0, + yaw: f32::NAN, + pitch: f32::NAN, }, } }