From 2bb19925b5d163493e87e8c94cddfc1fe9523af9 Mon Sep 17 00:00:00 2001 From: Bafbi Date: Fri, 4 Aug 2023 03:34:03 +0200 Subject: [PATCH 1/8] Add abilities component on the player The client is updated when a change is detected on one of the player abilities component --- crates/valence_client/src/abilities.rs | 62 +++++++++++++++++++ crates/valence_client/src/lib.rs | 8 +++ .../src/packets/play/player_abilities_s2c.rs | 5 +- examples/cow_sphere.rs | 12 +++- 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 crates/valence_client/src/abilities.rs diff --git a/crates/valence_client/src/abilities.rs b/crates/valence_client/src/abilities.rs new file mode 100644 index 000000000..76a7832d5 --- /dev/null +++ b/crates/valence_client/src/abilities.rs @@ -0,0 +1,62 @@ +pub use valence_packet::packets::play::player_abilities_s2c::PlayerAbilitiesFlags; +use valence_packet::packets::play::PlayerAbilitiesS2c; + +use super::*; + +/// [`Component`] that stores the player's flying speed ability. +/// +/// [`Default`] value: `0.05`. +#[derive(Component)] +pub struct FlyingSpeed(pub f32); + +impl Default for FlyingSpeed { + fn default() -> Self { + Self(0.05) + } +} + +/// [`Component`] that stores the player's field of view modifier ability. +/// The lower the value, the higher the field of view. +/// +/// [`Default`] value: `0.1`. +#[derive(Component)] +pub struct FovModifier(pub f32); + +impl Default for FovModifier { + fn default() -> Self { + Self(0.1) + } +} + +pub(super) fn build(app: &mut App) { + app.add_systems( + PostUpdate, + update_player_abilities + .in_set(UpdateClientsSet) + .after(update_game_mode), + ); +} + +fn update_player_abilities( + mut clients_query: Query< + ( + &mut Client, + &PlayerAbilitiesFlags, + &FlyingSpeed, + &FovModifier, + ), + Or<( + Changed, + Changed, + Changed, + )>, + >, +) { + for (mut client, flags, flying_speed, fov_modifier) in clients_query.iter_mut() { + client.write_packet(&PlayerAbilitiesS2c { + flags: *flags, + flying_speed: flying_speed.0, + fov_modifier: fov_modifier.0, + }) + } +} diff --git a/crates/valence_client/src/lib.rs b/crates/valence_client/src/lib.rs index b0b730acd..c468f69b9 100644 --- a/crates/valence_client/src/lib.rs +++ b/crates/valence_client/src/lib.rs @@ -68,6 +68,7 @@ use valence_packet::protocol::encode::{PacketEncoder, WritePacket}; use valence_packet::protocol::Packet; use valence_registry::RegistrySet; +pub mod abilities; pub mod action; pub mod command; pub mod custom_payload; @@ -160,6 +161,7 @@ impl Plugin for ClientPlugin { op_level::build(app); resource_pack::build(app); status::build(app); + abilities::build(app); } } @@ -196,6 +198,9 @@ pub struct ClientBundle { pub is_debug: spawn::IsDebug, pub is_flat: spawn::IsFlat, pub portal_cooldown: spawn::PortalCooldown, + pub player_abilities_flags: abilities::PlayerAbilitiesFlags, + pub flying_speed: abilities::FlyingSpeed, + pub fov_modifier: abilities::FovModifier, pub player: PlayerEntityBundle, } @@ -234,6 +239,9 @@ impl ClientBundle { reduced_debug_info: spawn::ReducedDebugInfo::default(), is_debug: spawn::IsDebug::default(), portal_cooldown: spawn::PortalCooldown::default(), + player_abilities_flags: abilities::PlayerAbilitiesFlags::default(), + flying_speed: abilities::FlyingSpeed::default(), + fov_modifier: abilities::FovModifier::default(), player: PlayerEntityBundle { uuid: UniqueId(args.uuid), ..Default::default() diff --git a/crates/valence_packet/src/packets/play/player_abilities_s2c.rs b/crates/valence_packet/src/packets/play/player_abilities_s2c.rs index bc8621f94..783d71721 100644 --- a/crates/valence_packet/src/packets/play/player_abilities_s2c.rs +++ b/crates/valence_packet/src/packets/play/player_abilities_s2c.rs @@ -1,3 +1,5 @@ +use bevy_ecs::prelude::Component; + use super::*; #[derive(Clone, Debug, Encode, Decode, Packet)] @@ -8,8 +10,9 @@ pub struct PlayerAbilitiesS2c { pub fov_modifier: f32, } +/// [`Component`] that stores the player's abilities flags. #[bitfield(u8)] -#[derive(PartialEq, Eq, Encode, Decode)] +#[derive(PartialEq, Eq, Encode, Decode, Component, Default)] pub struct PlayerAbilitiesFlags { pub invulnerable: bool, pub flying: bool, diff --git a/examples/cow_sphere.rs b/examples/cow_sphere.rs index 90e9e1707..6f0d7a9e7 100644 --- a/examples/cow_sphere.rs +++ b/examples/cow_sphere.rs @@ -4,6 +4,7 @@ use std::f64::consts::TAU; use glam::{DQuat, EulerRot}; use valence::prelude::*; +use valence_client::abilities::{FlyingSpeed, FovModifier, PlayerAbilitiesFlags}; type SpherePartBundle = valence::entity::cow::CowEntityBundle; @@ -67,6 +68,9 @@ fn init_clients( &mut VisibleEntityLayers, &mut Position, &mut GameMode, + &mut PlayerAbilitiesFlags, + &mut FlyingSpeed, + &mut FovModifier, ), Added, >, @@ -78,6 +82,9 @@ fn init_clients( mut visible_entity_layers, mut pos, mut game_mode, + mut abilities, + mut flying_speed, + mut fov_modifier, ) in &mut clients { let layer = layers.single(); @@ -90,7 +97,10 @@ fn init_clients( SPAWN_POS.y as f64 + 1.0, SPAWN_POS.z as f64 + 0.5, ]); - *game_mode = GameMode::Creative; + *game_mode = GameMode::Adventure; + abilities.set_allow_flying(true); + flying_speed.0 = 0.1; + fov_modifier.0 = 0.05; } } From 0cb016487b6f36a7fa0c036f7e10f062cd197d44 Mon Sep 17 00:00:00 2001 From: Bafbi Date: Fri, 4 Aug 2023 14:45:59 +0200 Subject: [PATCH 2/8] Handle client abilities change I'm updating the `PlayerAbilitiesFlags` when the client send `UpdatePlayerAbilitiesC2s` packet and when the `Gamemode` is change. --- crates/valence_client/src/abilities.rs | 52 +++++++++++++++++-- .../play/update_player_abilities_c2s.rs | 2 +- examples/anvil_loading.rs | 13 ++++- examples/cow_sphere.rs | 28 +++++----- 4 files changed, 76 insertions(+), 19 deletions(-) diff --git a/crates/valence_client/src/abilities.rs b/crates/valence_client/src/abilities.rs index 76a7832d5..e8656de65 100644 --- a/crates/valence_client/src/abilities.rs +++ b/crates/valence_client/src/abilities.rs @@ -1,7 +1,8 @@ pub use valence_packet::packets::play::player_abilities_s2c::PlayerAbilitiesFlags; -use valence_packet::packets::play::PlayerAbilitiesS2c; +use valence_packet::packets::play::{PlayerAbilitiesS2c, UpdatePlayerAbilitiesC2s}; use super::*; +use crate::event_loop::{PacketEvent, EventLoopPreUpdate}; /// [`Component`] that stores the player's flying speed ability. /// @@ -31,13 +32,14 @@ impl Default for FovModifier { pub(super) fn build(app: &mut App) { app.add_systems( PostUpdate, - update_player_abilities + (update_client_player_abilities, update_player_abilities.before(update_client_player_abilities)) .in_set(UpdateClientsSet) .after(update_game_mode), - ); + ).add_systems(EventLoopPreUpdate, update_server_player_abilities) + ; } -fn update_player_abilities( +fn update_client_player_abilities( mut clients_query: Query< ( &mut Client, @@ -60,3 +62,45 @@ fn update_player_abilities( }) } } + +fn update_player_abilities( + mut client_query: Query<(&mut PlayerAbilitiesFlags, &GameMode), Changed>, +) { + for (mut flags, gamemode) in client_query.iter_mut() { + match gamemode { + GameMode::Creative => { + flags.set_invulnerable(true); + flags.set_allow_flying(true); + flags.set_instant_break(true); + } + GameMode::Spectator => { + flags.set_invulnerable(true); + flags.set_allow_flying(true); + flags.set_instant_break(false); + flags.set_flying(true); + } + _ => { + flags.set_invulnerable(false); + flags.set_allow_flying(false); + flags.set_instant_break(false); + } + + } + } +} + +fn update_server_player_abilities( + mut packet_events: EventReader, + mut client_query: Query<&mut PlayerAbilitiesFlags>, +) { + for packets in packet_events.iter() { + if let Some(pkt) = packets.decode::() { + if let Ok(mut flags) = + client_query.get_mut(packets.client) + { + flags.set_flying(UpdatePlayerAbilitiesC2s::StartFlying.eq(&pkt)); + flags.bypass_change_detection(); + } + } + } +} diff --git a/crates/valence_packet/src/packets/play/update_player_abilities_c2s.rs b/crates/valence_packet/src/packets/play/update_player_abilities_c2s.rs index 979e14280..c3de90d28 100644 --- a/crates/valence_packet/src/packets/play/update_player_abilities_c2s.rs +++ b/crates/valence_packet/src/packets/play/update_player_abilities_c2s.rs @@ -1,6 +1,6 @@ use super::*; -#[derive(Copy, Clone, Debug, Encode, Decode, Packet)] +#[derive(Copy, Clone, Debug, Encode, Decode, Packet, PartialEq, Eq)] #[packet(id = packet_id::UPDATE_PLAYER_ABILITIES_C2S)] pub enum UpdatePlayerAbilitiesC2s { #[packet(tag = 0b00)] diff --git a/examples/anvil_loading.rs b/examples/anvil_loading.rs index 86f96c8b2..fd533747f 100644 --- a/examples/anvil_loading.rs +++ b/examples/anvil_loading.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use clap::Parser; use valence::prelude::*; use valence_anvil::{AnvilLevel, ChunkLoadEvent, ChunkLoadStatus}; -use valence_client::message::SendMessage; +use valence_client::{message::SendMessage, abilities::{PlayerAbilitiesFlags, FlyingSpeed, FovModifier}}; const SPAWN_POS: DVec3 = DVec3::new(0.0, 256.0, 0.0); @@ -78,6 +78,9 @@ fn init_clients( &mut VisibleEntityLayers, &mut Position, &mut GameMode, + &mut PlayerAbilitiesFlags, + &mut FlyingSpeed, + &mut FovModifier, ), Added, >, @@ -89,6 +92,9 @@ fn init_clients( mut visible_entity_layers, mut pos, mut game_mode, + mut abilities, + mut flying_speed, + mut fov_modifier, ) in &mut clients { let layer = layers.single(); @@ -97,7 +103,10 @@ fn init_clients( visible_chunk_layer.0 = layer; visible_entity_layers.0.insert(layer); pos.set(SPAWN_POS); - *game_mode = GameMode::Spectator; + *game_mode = GameMode::Adventure; + abilities.set_allow_flying(true); + flying_speed.0 = 0.1; + fov_modifier.0 = 0.05; } } diff --git a/examples/cow_sphere.rs b/examples/cow_sphere.rs index 6f0d7a9e7..86b326afa 100644 --- a/examples/cow_sphere.rs +++ b/examples/cow_sphere.rs @@ -4,7 +4,7 @@ use std::f64::consts::TAU; use glam::{DQuat, EulerRot}; use valence::prelude::*; -use valence_client::abilities::{FlyingSpeed, FovModifier, PlayerAbilitiesFlags}; +use valence_client::{abilities::PlayerAbilitiesFlags, message::SendMessage}; type SpherePartBundle = valence::entity::cow::CowEntityBundle; @@ -26,7 +26,7 @@ fn main() { .add_systems(Startup, setup) .add_systems( Update, - (init_clients, update_sphere, despawn_disconnected_clients), + (init_clients, update_sphere, despawn_disconnected_clients, display_is_flying), ) .run(); } @@ -68,9 +68,6 @@ fn init_clients( &mut VisibleEntityLayers, &mut Position, &mut GameMode, - &mut PlayerAbilitiesFlags, - &mut FlyingSpeed, - &mut FovModifier, ), Added, >, @@ -82,9 +79,6 @@ fn init_clients( mut visible_entity_layers, mut pos, mut game_mode, - mut abilities, - mut flying_speed, - mut fov_modifier, ) in &mut clients { let layer = layers.single(); @@ -97,10 +91,7 @@ fn init_clients( SPAWN_POS.y as f64 + 1.0, SPAWN_POS.z as f64 + 0.5, ]); - *game_mode = GameMode::Adventure; - abilities.set_allow_flying(true); - flying_speed.0 = 0.1; - fov_modifier.0 = 0.05; + *game_mode = GameMode::Creative; } } @@ -152,3 +143,16 @@ fn fibonacci_spiral(n: usize) -> impl Iterator { fn lerp(a: f64, b: f64, t: f64) -> f64 { a * (1.0 - t) + b * t } + +fn display_is_flying( + mut clients: Query<(&mut Client, &PlayerAbilitiesFlags), Changed>, +) { + for (mut client, abilities_flags) in clients.iter_mut() { + if abilities_flags.flying() { + client.send_action_bar_message("You are flying!".into_text().color(Color::GREEN)); + } else { + client.send_action_bar_message("You are not flying!".into_text().color(Color::RED)); + } + } +} + From 08ed5eb39e135c1c92128116262ca0a8a50dbf79 Mon Sep 17 00:00:00 2001 From: Bafbi Date: Fri, 4 Aug 2023 15:02:43 +0200 Subject: [PATCH 3/8] fmt + add test We test if the `PlayerAbilitiesFlags` componant is nicely handle when the client start flying or the `Gamemode` component is changed --- crates/valence_client/src/abilities.rs | 16 ++--- examples/anvil_loading.rs | 3 +- examples/cow_sphere.rs | 12 +++- src/tests/client.rs | 92 +++++++++++++++++++++++++- 4 files changed, 110 insertions(+), 13 deletions(-) diff --git a/crates/valence_client/src/abilities.rs b/crates/valence_client/src/abilities.rs index e8656de65..5d1b004e8 100644 --- a/crates/valence_client/src/abilities.rs +++ b/crates/valence_client/src/abilities.rs @@ -2,7 +2,7 @@ pub use valence_packet::packets::play::player_abilities_s2c::PlayerAbilitiesFlag use valence_packet::packets::play::{PlayerAbilitiesS2c, UpdatePlayerAbilitiesC2s}; use super::*; -use crate::event_loop::{PacketEvent, EventLoopPreUpdate}; +use crate::event_loop::{EventLoopPreUpdate, PacketEvent}; /// [`Component`] that stores the player's flying speed ability. /// @@ -32,11 +32,14 @@ impl Default for FovModifier { pub(super) fn build(app: &mut App) { app.add_systems( PostUpdate, - (update_client_player_abilities, update_player_abilities.before(update_client_player_abilities)) + ( + update_client_player_abilities, + update_player_abilities.before(update_client_player_abilities), + ) .in_set(UpdateClientsSet) .after(update_game_mode), - ).add_systems(EventLoopPreUpdate, update_server_player_abilities) - ; + ) + .add_systems(EventLoopPreUpdate, update_server_player_abilities); } fn update_client_player_abilities( @@ -84,7 +87,6 @@ fn update_player_abilities( flags.set_allow_flying(false); flags.set_instant_break(false); } - } } } @@ -95,9 +97,7 @@ fn update_server_player_abilities( ) { for packets in packet_events.iter() { if let Some(pkt) = packets.decode::() { - if let Ok(mut flags) = - client_query.get_mut(packets.client) - { + if let Ok(mut flags) = client_query.get_mut(packets.client) { flags.set_flying(UpdatePlayerAbilitiesC2s::StartFlying.eq(&pkt)); flags.bypass_change_detection(); } diff --git a/examples/anvil_loading.rs b/examples/anvil_loading.rs index fd533747f..d55fd1d6d 100644 --- a/examples/anvil_loading.rs +++ b/examples/anvil_loading.rs @@ -3,7 +3,8 @@ use std::path::PathBuf; use clap::Parser; use valence::prelude::*; use valence_anvil::{AnvilLevel, ChunkLoadEvent, ChunkLoadStatus}; -use valence_client::{message::SendMessage, abilities::{PlayerAbilitiesFlags, FlyingSpeed, FovModifier}}; +use valence_client::abilities::{FlyingSpeed, FovModifier, PlayerAbilitiesFlags}; +use valence_client::message::SendMessage; const SPAWN_POS: DVec3 = DVec3::new(0.0, 256.0, 0.0); diff --git a/examples/cow_sphere.rs b/examples/cow_sphere.rs index 86b326afa..b996f6225 100644 --- a/examples/cow_sphere.rs +++ b/examples/cow_sphere.rs @@ -4,7 +4,8 @@ use std::f64::consts::TAU; use glam::{DQuat, EulerRot}; use valence::prelude::*; -use valence_client::{abilities::PlayerAbilitiesFlags, message::SendMessage}; +use valence_client::abilities::PlayerAbilitiesFlags; +use valence_client::message::SendMessage; type SpherePartBundle = valence::entity::cow::CowEntityBundle; @@ -26,7 +27,12 @@ fn main() { .add_systems(Startup, setup) .add_systems( Update, - (init_clients, update_sphere, despawn_disconnected_clients, display_is_flying), + ( + init_clients, + update_sphere, + despawn_disconnected_clients, + display_is_flying, + ), ) .run(); } @@ -144,6 +150,7 @@ fn lerp(a: f64, b: f64, t: f64) -> f64 { a * (1.0 - t) + b * t } +// Send an actionbar message to all clients when their flying state changes. fn display_is_flying( mut clients: Query<(&mut Client, &PlayerAbilitiesFlags), Changed>, ) { @@ -155,4 +162,3 @@ fn display_is_flying( } } } - diff --git a/src/tests/client.rs b/src/tests/client.rs index 1690c7b5d..7e4d4c6ec 100644 --- a/src/tests/client.rs +++ b/src/tests/client.rs @@ -1,9 +1,11 @@ use glam::DVec3; +use valence_client::abilities::PlayerAbilitiesFlags; use valence_core::chunk_pos::ChunkPos; +use valence_core::game_mode::GameMode; use valence_layer::chunk::UnloadedChunk; use valence_layer::ChunkLayer; use valence_packet::packets::play::{ - FullC2s, MoveRelativeS2c, PlayerPositionLookS2c, TeleportConfirmC2s, + FullC2s, MoveRelativeS2c, PlayerPositionLookS2c, TeleportConfirmC2s, UpdatePlayerAbilitiesC2s, }; use crate::testing::{create_mock_client, ScenarioSingleClient}; @@ -60,3 +62,91 @@ fn client_teleport_and_move() { .collect_received() .assert_count::(1); } + +#[test] +fn client_start_flying() { + let mut senario = ScenarioSingleClient::new(); + + assert_eq!( + senario + .app + .world + .get::(senario.client) + .unwrap() + .flying(), + false + ); + + senario + .helper + .send::(&UpdatePlayerAbilitiesC2s::StartFlying); + + senario.app.update(); + + assert_eq!( + senario + .app + .world + .get::(senario.client) + .unwrap() + .flying(), + true + ); + + senario + .helper + .send::(&UpdatePlayerAbilitiesC2s::StopFlying); + + senario.app.update(); + + assert_eq!( + senario + .app + .world + .get::(senario.client) + .unwrap() + .flying(), + false + ); +} + +#[test] +fn client_gamemode_changed() { + let mut senario = ScenarioSingleClient::new(); + + *senario + .app + .world + .get_mut::(senario.client) + .unwrap() = GameMode::Creative; + + senario.app.update(); + + let abilities = senario + .app + .world + .get::(senario.client) + .unwrap(); + + assert_eq!(abilities.allow_flying(), true); + assert_eq!(abilities.instant_break(), true); + assert_eq!(abilities.invulnerable(), true); + + *senario + .app + .world + .get_mut::(senario.client) + .unwrap() = GameMode::Adventure; + + senario.app.update(); + + let abilities = senario + .app + .world + .get::(senario.client) + .unwrap(); + + assert_eq!(abilities.allow_flying(), false); + assert_eq!(abilities.instant_break(), false); + assert_eq!(abilities.invulnerable(), false); +} From ce9469493939910f0f535d21711e18e90bfd890c Mon Sep 17 00:00:00 2001 From: Bafbi Date: Fri, 4 Aug 2023 19:04:25 +0200 Subject: [PATCH 4/8] clippy --- examples/anvil_loading.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/anvil_loading.rs b/examples/anvil_loading.rs index d55fd1d6d..f5efc9555 100644 --- a/examples/anvil_loading.rs +++ b/examples/anvil_loading.rs @@ -1,3 +1,5 @@ +#![allow(clippy::type_complexity)] + use std::path::PathBuf; use clap::Parser; From 8357df74be01ce707f5736f13c51d61e8b445f05 Mon Sep 17 00:00:00 2001 From: Bafbi Date: Fri, 4 Aug 2023 19:51:07 +0200 Subject: [PATCH 5/8] reclippy --- src/tests/client.rs | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/tests/client.rs b/src/tests/client.rs index 7e4d4c6ec..cfec1524c 100644 --- a/src/tests/client.rs +++ b/src/tests/client.rs @@ -67,14 +67,13 @@ fn client_teleport_and_move() { fn client_start_flying() { let mut senario = ScenarioSingleClient::new(); - assert_eq!( - senario + assert!( + !senario .app .world .get::(senario.client) .unwrap() - .flying(), - false + .flying() ); senario @@ -83,14 +82,13 @@ fn client_start_flying() { senario.app.update(); - assert_eq!( + assert!( senario .app .world .get::(senario.client) .unwrap() - .flying(), - true + .flying() ); senario @@ -99,19 +97,18 @@ fn client_start_flying() { senario.app.update(); - assert_eq!( - senario + assert!( + !senario .app .world .get::(senario.client) .unwrap() - .flying(), - false + .flying() ); } #[test] -fn client_gamemode_changed() { +fn client_gamemode_changed_ability() { let mut senario = ScenarioSingleClient::new(); *senario @@ -128,9 +125,9 @@ fn client_gamemode_changed() { .get::(senario.client) .unwrap(); - assert_eq!(abilities.allow_flying(), true); - assert_eq!(abilities.instant_break(), true); - assert_eq!(abilities.invulnerable(), true); + assert!(abilities.allow_flying()); + assert!(abilities.instant_break()); + assert!(abilities.invulnerable()); *senario .app @@ -146,7 +143,7 @@ fn client_gamemode_changed() { .get::(senario.client) .unwrap(); - assert_eq!(abilities.allow_flying(), false); - assert_eq!(abilities.instant_break(), false); - assert_eq!(abilities.invulnerable(), false); + assert!(!abilities.allow_flying()); + assert!(!abilities.instant_break()); + assert!(!abilities.invulnerable()); } From 0d8f2a3768ecdedbecfbdb32147020ae54580110 Mon Sep 17 00:00:00 2001 From: Bafbi Date: Fri, 4 Aug 2023 19:52:56 +0200 Subject: [PATCH 6/8] fmt --- src/tests/client.rs | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/tests/client.rs b/src/tests/client.rs index cfec1524c..b2cf4c05a 100644 --- a/src/tests/client.rs +++ b/src/tests/client.rs @@ -67,14 +67,12 @@ fn client_teleport_and_move() { fn client_start_flying() { let mut senario = ScenarioSingleClient::new(); - assert!( - !senario - .app - .world - .get::(senario.client) - .unwrap() - .flying() - ); + assert!(!senario + .app + .world + .get::(senario.client) + .unwrap() + .flying()); senario .helper @@ -82,14 +80,12 @@ fn client_start_flying() { senario.app.update(); - assert!( - senario - .app - .world - .get::(senario.client) - .unwrap() - .flying() - ); + assert!(senario + .app + .world + .get::(senario.client) + .unwrap() + .flying()); senario .helper @@ -97,14 +93,12 @@ fn client_start_flying() { senario.app.update(); - assert!( - !senario - .app - .world - .get::(senario.client) - .unwrap() - .flying() - ); + assert!(!senario + .app + .world + .get::(senario.client) + .unwrap() + .flying()); } #[test] From a82b7ee116efa53f6caecee9c3dd49d8d07b9b79 Mon Sep 17 00:00:00 2001 From: Bafbi Date: Sat, 5 Aug 2023 18:17:23 +0200 Subject: [PATCH 7/8] Add fly event + remove useless packets sending The systems updating the flags after the gamemode change or the client packet were making the server send an `PlayerAbilitiesS2c` uselessly. One of the test don't pass anymore for unknown reason, but by ingame testing it should pass. --- crates/valence_client/src/abilities.rs | 86 +++++++++++++++++++++----- examples/cow_sphere.rs | 21 ++++--- src/tests/client.rs | 38 ------------ 3 files changed, 85 insertions(+), 60 deletions(-) diff --git a/crates/valence_client/src/abilities.rs b/crates/valence_client/src/abilities.rs index 5d1b004e8..827ea94bd 100644 --- a/crates/valence_client/src/abilities.rs +++ b/crates/valence_client/src/abilities.rs @@ -29,17 +29,41 @@ impl Default for FovModifier { } } +/// Send if the client sends [`UpdatePlayerAbilitiesC2s::StartFlying`] +#[derive(Event)] +pub struct PlayerStartFlyingEvent { + pub client: Entity, +} + +/// Send if the client sends [`UpdatePlayerAbilitiesC2s::StopFlying`] +#[derive(Event)] +pub struct PlayerStopFlyingEvent { + pub client: Entity, +} + +/// Order of execution : +/// 1. [`update_game_mode`] : Watch [`GameMode`] changes => Send +/// [`GameStateChangeS2c`] to update the client's gamemode +/// 2. [`update_client_player_abilities`] : Watch [`PlayerAbilitiesFlags`], +/// [`FlyingSpeed`] and [`FovModifier`] changes => Send [`PlayerAbilitiesS2c`] +/// to update the client's abilities 3. [`update_player_abilities`] : Watch +/// [`GameMode`] changes => Update [`PlayerAbilitiesFlags`] according to the +/// [`GameMode`] 4. [`update_server_player_abilities`] : Watch +/// [`UpdatePlayerAbilitiesC2s`] packets => Update [`PlayerAbilitiesFlags`] +/// according to the packet pub(super) fn build(app: &mut App) { - app.add_systems( - PostUpdate, - ( - update_client_player_abilities, - update_player_abilities.before(update_client_player_abilities), + app.add_event::() + .add_event::() + .add_systems( + PostUpdate, + ( + update_client_player_abilities, + update_player_abilities.before(update_client_player_abilities), + ) + .in_set(UpdateClientsSet) + .after(update_game_mode), ) - .in_set(UpdateClientsSet) - .after(update_game_mode), - ) - .add_systems(EventLoopPreUpdate, update_server_player_abilities); + .add_systems(EventLoopPreUpdate, update_server_player_abilities); } fn update_client_player_abilities( @@ -66,10 +90,15 @@ fn update_client_player_abilities( } } +/// /!\ This system does not trigger change detection on +/// [`PlayerAbilitiesFlags`] fn update_player_abilities( - mut client_query: Query<(&mut PlayerAbilitiesFlags, &GameMode), Changed>, + mut player_start_flying_event_writer: EventWriter, + mut player_stop_flying_event_writer: EventWriter, + mut client_query: Query<(Entity, &mut PlayerAbilitiesFlags, &GameMode), Changed>, ) { - for (mut flags, gamemode) in client_query.iter_mut() { + for (entity, mut mut_flags, gamemode) in client_query.iter_mut() { + let flags = mut_flags.bypass_change_detection(); match gamemode { GameMode::Creative => { flags.set_invulnerable(true); @@ -81,25 +110,52 @@ fn update_player_abilities( flags.set_allow_flying(true); flags.set_instant_break(false); flags.set_flying(true); + player_start_flying_event_writer.send(PlayerStartFlyingEvent { client: entity }); + } + GameMode::Survival => { + flags.set_invulnerable(false); + flags.set_allow_flying(false); + flags.set_instant_break(false); + flags.set_flying(false); + player_stop_flying_event_writer.send(PlayerStopFlyingEvent { client: entity }); } - _ => { + GameMode::Adventure => { flags.set_invulnerable(false); flags.set_allow_flying(false); flags.set_instant_break(false); + flags.set_flying(false); + player_stop_flying_event_writer.send(PlayerStopFlyingEvent { client: entity }); } } } } +/// /!\ This system does not trigger change detection on +/// [`PlayerAbilitiesFlags`] fn update_server_player_abilities( mut packet_events: EventReader, + mut player_start_flying_event_writer: EventWriter, + mut player_stop_flying_event_writer: EventWriter, mut client_query: Query<&mut PlayerAbilitiesFlags>, ) { for packets in packet_events.iter() { if let Some(pkt) = packets.decode::() { - if let Ok(mut flags) = client_query.get_mut(packets.client) { - flags.set_flying(UpdatePlayerAbilitiesC2s::StartFlying.eq(&pkt)); - flags.bypass_change_detection(); + if let Ok(mut mut_flags) = client_query.get_mut(packets.client) { + let flags = mut_flags.bypass_change_detection(); + match pkt { + UpdatePlayerAbilitiesC2s::StartFlying => { + flags.set_flying(true); + player_start_flying_event_writer.send(PlayerStartFlyingEvent { + client: packets.client, + }); + } + UpdatePlayerAbilitiesC2s::StopFlying => { + flags.set_flying(false); + player_stop_flying_event_writer.send(PlayerStopFlyingEvent { + client: packets.client, + }); + } + } } } } diff --git a/examples/cow_sphere.rs b/examples/cow_sphere.rs index b996f6225..621d9e3a0 100644 --- a/examples/cow_sphere.rs +++ b/examples/cow_sphere.rs @@ -4,8 +4,9 @@ use std::f64::consts::TAU; use glam::{DQuat, EulerRot}; use valence::prelude::*; -use valence_client::abilities::PlayerAbilitiesFlags; +use valence_client::abilities::{PlayerStartFlyingEvent, PlayerStopFlyingEvent}; use valence_client::message::SendMessage; +use valence_core::text::color::NamedColor; type SpherePartBundle = valence::entity::cow::CowEntityBundle; @@ -152,13 +153,19 @@ fn lerp(a: f64, b: f64, t: f64) -> f64 { // Send an actionbar message to all clients when their flying state changes. fn display_is_flying( - mut clients: Query<(&mut Client, &PlayerAbilitiesFlags), Changed>, + mut player_start_flying_events: EventReader, + mut player_stop_flying_events: EventReader, + mut clients: Query<&mut Client>, ) { - for (mut client, abilities_flags) in clients.iter_mut() { - if abilities_flags.flying() { - client.send_action_bar_message("You are flying!".into_text().color(Color::GREEN)); - } else { - client.send_action_bar_message("You are not flying!".into_text().color(Color::RED)); + for event in player_start_flying_events.iter() { + if let Ok(mut client) = clients.get_mut(event.client) { + client.send_action_bar_message("You are flying!".color(NamedColor::Green)); + } + } + + for event in player_stop_flying_events.iter() { + if let Ok(mut client) = clients.get_mut(event.client) { + client.send_action_bar_message("You are no longer flying!".color(NamedColor::Red)); } } } diff --git a/src/tests/client.rs b/src/tests/client.rs index b2cf4c05a..3672f2cf0 100644 --- a/src/tests/client.rs +++ b/src/tests/client.rs @@ -63,44 +63,6 @@ fn client_teleport_and_move() { .assert_count::(1); } -#[test] -fn client_start_flying() { - let mut senario = ScenarioSingleClient::new(); - - assert!(!senario - .app - .world - .get::(senario.client) - .unwrap() - .flying()); - - senario - .helper - .send::(&UpdatePlayerAbilitiesC2s::StartFlying); - - senario.app.update(); - - assert!(senario - .app - .world - .get::(senario.client) - .unwrap() - .flying()); - - senario - .helper - .send::(&UpdatePlayerAbilitiesC2s::StopFlying); - - senario.app.update(); - - assert!(!senario - .app - .world - .get::(senario.client) - .unwrap() - .flying()); -} - #[test] fn client_gamemode_changed_ability() { let mut senario = ScenarioSingleClient::new(); From c36a60cf8168846f7eec37cdd32d81621b8f6692 Mon Sep 17 00:00:00 2001 From: Bafbi Date: Sat, 5 Aug 2023 18:40:11 +0200 Subject: [PATCH 8/8] clippy --- src/tests/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/client.rs b/src/tests/client.rs index 3672f2cf0..f9e8c87aa 100644 --- a/src/tests/client.rs +++ b/src/tests/client.rs @@ -5,7 +5,7 @@ use valence_core::game_mode::GameMode; use valence_layer::chunk::UnloadedChunk; use valence_layer::ChunkLayer; use valence_packet::packets::play::{ - FullC2s, MoveRelativeS2c, PlayerPositionLookS2c, TeleportConfirmC2s, UpdatePlayerAbilitiesC2s, + FullC2s, MoveRelativeS2c, PlayerPositionLookS2c, TeleportConfirmC2s, }; use crate::testing::{create_mock_client, ScenarioSingleClient};