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#[derive(Bundle, Default, PartialEq, PartialOrd)]
52pub struct WeatherBundle {
53 pub rain: Rain,
54 pub thunder: Thunder,
55}
56
57#[derive(Component, Default, PartialEq, PartialOrd)]
60pub struct Rain(pub f32);
61
62#[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}