valence_registry/
biome.rs
1use std::ops::{Deref, DerefMut};
12
13use bevy_app::prelude::*;
14use bevy_ecs::prelude::*;
15use serde::{Deserialize, Serialize};
16use tracing::error;
17use valence_ident::{ident, Ident};
18use valence_nbt::serde::CompoundSerializer;
19
20use crate::codec::{RegistryCodec, RegistryValue};
21use crate::{Registry, RegistryIdx, RegistrySet};
22
23pub struct BiomePlugin;
24
25impl Plugin for BiomePlugin {
26 fn build(&self, app: &mut App) {
27 app.init_resource::<BiomeRegistry>()
28 .add_systems(PreStartup, load_default_biomes)
29 .add_systems(PostUpdate, update_biome_registry.before(RegistrySet));
30 }
31}
32
33fn load_default_biomes(mut reg: ResMut<BiomeRegistry>, codec: Res<RegistryCodec>) {
34 let mut helper = move || -> anyhow::Result<()> {
35 for value in codec.registry(BiomeRegistry::KEY) {
36 let biome = Biome::deserialize(value.element.clone())?;
37
38 reg.insert(value.name.clone(), biome);
39 }
40
41 reg.swap_to_front(ident!("plains"));
43
44 Ok(())
45 };
46
47 if let Err(e) = helper() {
48 error!("failed to load default biomes from registry codec: {e:#}");
49 }
50}
51
52fn update_biome_registry(reg: Res<BiomeRegistry>, mut codec: ResMut<RegistryCodec>) {
53 if reg.is_changed() {
54 let biomes = codec.registry_mut(BiomeRegistry::KEY);
55
56 biomes.clear();
57
58 biomes.extend(reg.iter().map(|(_, name, biome)| {
59 RegistryValue {
60 name: name.into(),
61 element: biome
62 .serialize(CompoundSerializer)
63 .expect("failed to serialize biome"),
64 }
65 }));
66 }
67}
68
69#[derive(Resource, Default, Debug)]
70pub struct BiomeRegistry {
71 reg: Registry<BiomeId, Biome>,
72}
73
74impl BiomeRegistry {
75 pub const KEY: Ident<&'static str> = ident!("worldgen/biome");
76}
77
78impl Deref for BiomeRegistry {
79 type Target = Registry<BiomeId, Biome>;
80
81 fn deref(&self) -> &Self::Target {
82 &self.reg
83 }
84}
85
86impl DerefMut for BiomeRegistry {
87 fn deref_mut(&mut self) -> &mut Self::Target {
88 &mut self.reg
89 }
90}
91
92#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
93pub struct BiomeId(u32);
94
95impl BiomeId {
96 pub const DEFAULT: Self = BiomeId(0);
97}
98
99impl RegistryIdx for BiomeId {
100 const MAX: usize = u32::MAX as usize;
101
102 #[inline]
103 fn to_index(self) -> usize {
104 self.0 as usize
105 }
106
107 #[inline]
108 fn from_index(idx: usize) -> Self {
109 Self(idx as u32)
110 }
111}
112
113#[derive(Serialize, Deserialize, Clone, Debug)]
114pub struct Biome {
115 pub downfall: f32,
116 pub effects: BiomeEffects,
117 pub has_precipitation: bool,
118 pub temperature: f32,
119 }
121
122#[derive(Serialize, Deserialize, Clone, Debug)]
123pub struct BiomeEffects {
124 pub fog_color: u32,
125 pub sky_color: u32,
126 pub water_color: u32,
127 pub water_fog_color: u32,
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub grass_color: Option<u32>,
130 }
132
133impl Default for Biome {
134 fn default() -> Self {
135 Self {
136 downfall: 0.4,
137 effects: BiomeEffects::default(),
138 has_precipitation: true,
139 temperature: 0.8,
140 }
141 }
142}
143
144impl Default for BiomeEffects {
145 fn default() -> Self {
146 Self {
147 fog_color: 12638463,
148 sky_color: 7907327,
149 water_color: 4159204,
150 water_fog_color: 329011,
151 grass_color: None,
152 }
153 }
154}