valence_server/
action.rs
1use bevy_app::prelude::*;
2use bevy_ecs::prelude::*;
3use derive_more::Deref;
4use valence_protocol::packets::play::player_action_c2s::PlayerAction;
5use valence_protocol::packets::play::{PlayerActionC2s, PlayerActionResponseS2c};
6use valence_protocol::{BlockPos, Direction, VarInt, WritePacket};
7
8use crate::client::{Client, UpdateClientsSet};
9use crate::event_loop::{EventLoopPreUpdate, PacketEvent};
10
11pub struct ActionPlugin;
12
13impl Plugin for ActionPlugin {
14 fn build(&self, app: &mut App) {
15 app.add_event::<DiggingEvent>()
16 .add_systems(EventLoopPreUpdate, handle_player_action)
17 .add_systems(
18 PostUpdate,
19 acknowledge_player_actions.in_set(UpdateClientsSet),
20 );
21 }
22}
23
24#[derive(Event, Copy, Clone, Debug)]
25pub struct DiggingEvent {
26 pub client: Entity,
27 pub position: BlockPos,
28 pub direction: Direction,
29 pub state: DiggingState,
30}
31
32#[derive(Copy, Clone, PartialEq, Eq, Debug)]
33pub enum DiggingState {
34 Start,
35 Abort,
36 Stop,
37}
38
39#[derive(Component, Copy, Clone, PartialEq, Eq, Default, Debug, Deref)]
40pub struct ActionSequence(i32);
41
42impl ActionSequence {
43 pub fn update(&mut self, val: i32) {
44 self.0 = self.0.max(val);
45 }
46
47 pub fn get(&self) -> i32 {
48 self.0
49 }
50}
51
52fn handle_player_action(
53 mut clients: Query<&mut ActionSequence>,
54 mut packets: EventReader<PacketEvent>,
55 mut digging_events: EventWriter<DiggingEvent>,
56) {
57 for packet in packets.read() {
58 if let Some(pkt) = packet.decode::<PlayerActionC2s>() {
59 if let Ok(mut seq) = clients.get_mut(packet.client) {
60 seq.update(pkt.sequence.0);
61 }
62
63 match pkt.action {
67 PlayerAction::StartDestroyBlock => {
68 digging_events.send(DiggingEvent {
69 client: packet.client,
70 position: pkt.position,
71 direction: pkt.direction,
72 state: DiggingState::Start,
73 });
74 }
75 PlayerAction::AbortDestroyBlock => {
76 digging_events.send(DiggingEvent {
77 client: packet.client,
78 position: pkt.position,
79 direction: pkt.direction,
80 state: DiggingState::Abort,
81 });
82 }
83 PlayerAction::StopDestroyBlock => {
84 digging_events.send(DiggingEvent {
85 client: packet.client,
86 position: pkt.position,
87 direction: pkt.direction,
88 state: DiggingState::Stop,
89 });
90 }
91 PlayerAction::DropAllItems => {}
92 PlayerAction::DropItem => {}
93 PlayerAction::ReleaseUseItem => {}
94 PlayerAction::SwapItemWithOffhand => {}
95 }
96 }
97 }
98}
99
100fn acknowledge_player_actions(
101 mut clients: Query<(&mut Client, &mut ActionSequence), Changed<ActionSequence>>,
102) {
103 for (mut client, mut action_seq) in &mut clients {
104 if action_seq.0 != 0 {
105 client.write_packet(&PlayerActionResponseS2c {
106 sequence: VarInt(action_seq.0),
107 });
108
109 action_seq.0 = 0;
110 }
111 }
112}