valence_server/
abilities.rs
1use bevy_app::prelude::*;
2use bevy_ecs::prelude::*;
3use derive_more::{Deref, DerefMut};
4pub use valence_protocol::packets::play::player_abilities_s2c::PlayerAbilitiesFlags;
5use valence_protocol::packets::play::{PlayerAbilitiesS2c, UpdatePlayerAbilitiesC2s};
6use valence_protocol::{GameMode, WritePacket};
7
8use crate::client::{update_game_mode, Client, UpdateClientsSet};
9use crate::event_loop::{EventLoopPreUpdate, PacketEvent};
10
11#[derive(Component, Deref, DerefMut)]
15pub struct FlyingSpeed(pub f32);
16
17impl Default for FlyingSpeed {
18 fn default() -> Self {
19 Self(0.05)
20 }
21}
22
23#[derive(Component, Deref, DerefMut)]
28pub struct FovModifier(pub f32);
29
30impl Default for FovModifier {
31 fn default() -> Self {
32 Self(0.1)
33 }
34}
35
36#[derive(Event)]
38pub struct PlayerStartFlyingEvent {
39 pub client: Entity,
40}
41
42#[derive(Event)]
44pub struct PlayerStopFlyingEvent {
45 pub client: Entity,
46}
47
48pub struct AbilitiesPlugin;
62
63impl Plugin for AbilitiesPlugin {
64 fn build(&self, app: &mut App) {
65 app.add_event::<PlayerStartFlyingEvent>()
66 .add_event::<PlayerStopFlyingEvent>()
67 .add_systems(
68 PostUpdate,
69 (
70 update_client_player_abilities,
71 update_player_abilities.before(update_client_player_abilities),
72 )
73 .in_set(UpdateClientsSet)
74 .after(update_game_mode),
75 )
76 .add_systems(EventLoopPreUpdate, update_server_player_abilities);
77 }
78}
79
80fn update_client_player_abilities(
81 mut clients_query: Query<
82 (
83 &mut Client,
84 &PlayerAbilitiesFlags,
85 &FlyingSpeed,
86 &FovModifier,
87 ),
88 Or<(
89 Changed<PlayerAbilitiesFlags>,
90 Changed<FlyingSpeed>,
91 Changed<FovModifier>,
92 )>,
93 >,
94) {
95 for (mut client, flags, flying_speed, fov_modifier) in &mut clients_query {
96 client.write_packet(&PlayerAbilitiesS2c {
97 flags: *flags,
98 flying_speed: flying_speed.0,
99 fov_modifier: fov_modifier.0,
100 })
101 }
102}
103
104fn update_player_abilities(
107 mut player_start_flying_event_writer: EventWriter<PlayerStartFlyingEvent>,
108 mut player_stop_flying_event_writer: EventWriter<PlayerStopFlyingEvent>,
109 mut client_query: Query<(Entity, &mut PlayerAbilitiesFlags, &GameMode), Changed<GameMode>>,
110) {
111 for (entity, mut mut_flags, gamemode) in &mut client_query {
112 let flags = mut_flags.bypass_change_detection();
113 match gamemode {
114 GameMode::Creative => {
115 flags.set_invulnerable(true);
116 flags.set_allow_flying(true);
117 flags.set_instant_break(true);
118 }
119 GameMode::Spectator => {
120 flags.set_invulnerable(true);
121 flags.set_allow_flying(true);
122 flags.set_instant_break(false);
123 flags.set_flying(true);
124 player_start_flying_event_writer.send(PlayerStartFlyingEvent { client: entity });
125 }
126 GameMode::Survival => {
127 flags.set_invulnerable(false);
128 flags.set_allow_flying(false);
129 flags.set_instant_break(false);
130 flags.set_flying(false);
131 player_stop_flying_event_writer.send(PlayerStopFlyingEvent { client: entity });
132 }
133 GameMode::Adventure => {
134 flags.set_invulnerable(false);
135 flags.set_allow_flying(false);
136 flags.set_instant_break(false);
137 flags.set_flying(false);
138 player_stop_flying_event_writer.send(PlayerStopFlyingEvent { client: entity });
139 }
140 }
141 }
142}
143
144fn update_server_player_abilities(
147 mut packet_events: EventReader<PacketEvent>,
148 mut player_start_flying_event_writer: EventWriter<PlayerStartFlyingEvent>,
149 mut player_stop_flying_event_writer: EventWriter<PlayerStopFlyingEvent>,
150 mut client_query: Query<&mut PlayerAbilitiesFlags>,
151) {
152 for packets in packet_events.read() {
153 if let Some(pkt) = packets.decode::<UpdatePlayerAbilitiesC2s>() {
154 if let Ok(mut mut_flags) = client_query.get_mut(packets.client) {
155 let flags = mut_flags.bypass_change_detection();
156 match pkt {
157 UpdatePlayerAbilitiesC2s::StartFlying => {
158 flags.set_flying(true);
159 player_start_flying_event_writer.send(PlayerStartFlyingEvent {
160 client: packets.client,
161 });
162 }
163 UpdatePlayerAbilitiesC2s::StopFlying => {
164 flags.set_flying(false);
165 player_stop_flying_event_writer.send(PlayerStopFlyingEvent {
166 client: packets.client,
167 });
168 }
169 }
170 }
171 }
172 }
173}