valence_weather/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use bevy_app::prelude::*;
4use bevy_ecs::prelude::*;
5use derive_more::{Deref, DerefMut};
6use valence_server::client::{Client, FlushPacketsSet, UpdateClientsSet, VisibleChunkLayer};
7use valence_server::protocol::packets::play::game_state_change_s2c::GameEventKind;
8use valence_server::protocol::packets::play::GameStateChangeS2c;
9use valence_server::protocol::WritePacket;
10use valence_server::ChunkLayer;
11
12pub struct WeatherPlugin;
13
14impl Plugin for WeatherPlugin {
15    fn build(&self, app: &mut App) {
16        app.add_systems(
17            PostUpdate,
18            (
19                init_weather_on_layer_join,
20                change_client_rain_level,
21                change_client_thunder_level,
22            )
23                .before(FlushPacketsSet),
24        )
25        .add_systems(
26            PostUpdate,
27            (change_layer_rain_level, change_layer_thunder_level).before(UpdateClientsSet),
28        );
29    }
30}
31
32/// Bundle containing rain and thunder components. `valence_weather` allows this
33/// to be added to clients and chunk layer entities.
34#[derive(Bundle, Default, PartialEq, PartialOrd)]
35pub struct WeatherBundle {
36    pub rain: Rain,
37    pub thunder: Thunder,
38}
39
40/// Component containing the rain level. Valid values are in \[0, 1] with 0
41/// being no rain and 1 being full rain.
42#[derive(Component, Default, PartialEq, PartialOrd, Deref, DerefMut)]
43pub struct Rain(pub f32);
44
45/// Component containing the thunder level. Valid values are in \[0, 1] with 0
46/// being no rain and 1 being full rain.
47#[derive(Component, Default, PartialEq, PartialOrd, Deref, DerefMut)]
48pub struct Thunder(pub f32);
49
50fn init_weather_on_layer_join(
51    mut clients: Query<(&mut Client, &VisibleChunkLayer), Changed<VisibleChunkLayer>>,
52    layers: Query<(Option<&Rain>, Option<&Thunder>), With<ChunkLayer>>,
53) {
54    for (mut client, visible_chunk_layer) in &mut clients {
55        if let Ok((rain, thunder)) = layers.get(visible_chunk_layer.0) {
56            if let Some(rain) = rain {
57                if rain.0 != 0.0 {
58                    client.write_packet(&GameStateChangeS2c {
59                        kind: GameEventKind::RainLevelChange,
60                        value: rain.0,
61                    });
62                }
63            }
64
65            if let Some(thunder) = thunder {
66                if thunder.0 != 0.0 {
67                    client.write_packet(&GameStateChangeS2c {
68                        kind: GameEventKind::ThunderLevelChange,
69                        value: thunder.0,
70                    });
71                }
72            }
73        }
74    }
75}
76
77fn change_layer_rain_level(
78    mut layers: Query<(&mut ChunkLayer, &Rain), (Changed<Rain>, Without<Client>)>,
79) {
80    for (mut layer, rain) in &mut layers {
81        layer.write_packet(&GameStateChangeS2c {
82            kind: GameEventKind::RainLevelChange,
83            value: rain.0,
84        });
85    }
86}
87
88fn change_layer_thunder_level(
89    mut layers: Query<(&mut ChunkLayer, &Thunder), (Changed<Thunder>, Without<Client>)>,
90) {
91    for (mut layer, thunder) in &mut layers {
92        layer.write_packet(&GameStateChangeS2c {
93            kind: GameEventKind::ThunderLevelChange,
94            value: thunder.0,
95        });
96    }
97}
98
99fn change_client_rain_level(mut clients: Query<(&mut Client, &Rain), Changed<Rain>>) {
100    for (mut client, rain) in &mut clients {
101        client.write_packet(&GameStateChangeS2c {
102            kind: GameEventKind::RainLevelChange,
103            value: rain.0,
104        });
105    }
106}
107
108fn change_client_thunder_level(mut clients: Query<(&mut Client, &Thunder), Changed<Thunder>>) {
109    for (mut client, thunder) in &mut clients {
110        client.write_packet(&GameStateChangeS2c {
111            kind: GameEventKind::RainLevelChange,
112            value: thunder.0,
113        });
114    }
115}