valence_weather/
lib.rs

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