veloren_voxygen/scene/terrain/
watcher.rs1use crate::hud::CraftingTab;
2use common::{
3 terrain::{Block, BlockKind, SpriteKind, sprite},
4 vol::ReadVol,
5};
6use common_base::span;
7use rand::prelude::*;
8use rand_chacha::ChaCha8Rng;
9use vek::*;
10
11#[derive(Clone, Copy, Debug)]
12pub enum Interaction {
13 Collect,
16 Craft(CraftingTab),
17 Mount,
18 Read,
19 LightToggle(bool),
20}
21
22pub enum FireplaceType {
23 House,
24 Workshop, }
26
27pub struct SmokerProperties {
28 pub position: Vec3<i32>,
29 pub kind: FireplaceType,
30}
31
32impl SmokerProperties {
33 fn new(position: Vec3<i32>, kind: FireplaceType) -> Self { Self { position, kind } }
34}
35
36#[derive(Default)]
37pub struct BlocksOfInterest {
38 pub leaves: Vec<Vec3<i32>>,
39 pub drip: Vec<Vec3<i32>>,
40 pub grass: Vec<Vec3<i32>>,
41 pub slow_river: Vec<Vec3<i32>>,
42 pub fast_river: Vec<Vec3<i32>>,
43 pub waterfall: Vec<(Vec3<i32>, Vec3<f32>)>,
44 pub lavapool: Vec<Vec3<i32>>,
45 pub fires: Vec<Vec3<i32>>,
46 pub smokers: Vec<SmokerProperties>,
47 pub beehives: Vec<Vec3<i32>>,
48 pub reeds: Vec<Vec3<i32>>,
49 pub fireflies: Vec<Vec3<i32>>,
50 pub flowers: Vec<Vec3<i32>>,
51 pub fire_bowls: Vec<Vec3<i32>>,
52 pub snow: Vec<Vec3<i32>>,
53 pub spores: Vec<Vec3<i32>>,
54 pub cricket1: Vec<Vec3<i32>>,
56 pub cricket2: Vec<Vec3<i32>>,
57 pub cricket3: Vec<Vec3<i32>>,
58 pub frogs: Vec<Vec3<i32>>,
59 pub one_way_walls: Vec<(Vec3<i32>, Vec3<f32>)>,
60 pub interactables: Vec<(Vec3<i32>, Interaction)>,
63 pub lights: Vec<(Vec3<i32>, u8)>,
64 pub temperature: f32,
66 pub humidity: f32,
67}
68
69impl BlocksOfInterest {
70 pub fn from_blocks(
71 blocks: impl Iterator<Item = (Vec3<i32>, Block)>,
72 river_velocity: Vec3<f32>,
73 temperature: f32,
74 humidity: f32,
75 chunk: &impl ReadVol<Vox = Block>,
76 ) -> Self {
77 span!(_guard, "from_chunk", "BlocksOfInterest::from_chunk");
78 let mut leaves = Vec::new();
79 let mut drip = Vec::new();
80 let mut grass = Vec::new();
81 let mut slow_river = Vec::new();
82 let mut fast_river = Vec::new();
83 let mut waterfall = Vec::new();
84 let mut lavapool = Vec::new();
85 let mut fires = Vec::new();
86 let mut smokers = Vec::new();
87 let mut beehives = Vec::new();
88 let mut reeds = Vec::new();
89 let mut fireflies = Vec::new();
90 let mut flowers = Vec::new();
91 let mut interactables = Vec::new();
92 let mut lights = Vec::new();
93 let mut minor_lights = Vec::new();
96 let mut fire_bowls = Vec::new();
97 let mut snow = Vec::new();
98 let mut cricket1 = Vec::new();
99 let mut cricket2 = Vec::new();
100 let mut cricket3 = Vec::new();
101 let mut frogs = Vec::new();
102 let mut one_way_walls = Vec::new();
103 let mut spores = Vec::new();
104
105 let mut rng = ChaCha8Rng::from_seed(thread_rng().gen());
106
107 blocks.for_each(|(pos, block)| {
108 match block.kind() {
109 BlockKind::Leaves
110 if rng.gen_range(0..16) == 0
111 && chunk
112 .get(pos - Vec3::unit_z())
113 .map_or(true, |b| !b.is_filled()) =>
114 {
115 leaves.push(pos)
116 },
117 BlockKind::WeakRock if rng.gen_range(0..6) == 0 => drip.push(pos),
118 BlockKind::Grass => {
119 if rng.gen_range(0..16) == 0 {
120 grass.push(pos);
121 }
122 match rng.gen_range(0..8192) {
123 1 => cricket1.push(pos),
124 2 => cricket2.push(pos),
125 3 => cricket3.push(pos),
126 _ => {},
127 }
128 },
129 BlockKind::Water => {
130 let is_waterfall = chunk
131 .get(pos + vek::Vec3::unit_z())
132 .is_ok_and(|b| b.is_air())
133 && [
134 vek::Vec2::new(0, 1),
135 vek::Vec2::new(1, 0),
136 vek::Vec2::new(0, -1),
137 vek::Vec2::new(-1, 0),
138 ]
139 .iter()
140 .map(|p| {
141 (1..=2)
142 .take_while(|i| {
143 chunk.get(pos + p.with_z(*i)).is_ok_and(|b| b.is_liquid())
144 })
145 .count()
146 })
147 .any(|s| s >= 2);
148
149 if is_waterfall {
150 waterfall.push((pos, river_velocity));
151 }
152
153 let river_speed_sq = river_velocity.magnitude_squared();
154 if is_waterfall || river_speed_sq > 0.9_f32.powi(2) {
156 fast_river.push(pos)
157 } else if river_speed_sq > 0.3_f32.powi(2) {
158 slow_river.push(pos)
159 }
160 },
161 BlockKind::Snow if rng.gen_range(0..16) == 0 => snow.push(pos),
162 BlockKind::Lava
163 if chunk
164 .get(pos + Vec3::unit_z())
165 .map_or(true, |b| !b.is_filled()) =>
166 {
167 if rng.gen_range(0..5) == 0 {
168 fires.push(pos + Vec3::unit_z())
169 }
170 if rng.gen_range(0..16) == 0 {
171 lavapool.push(pos)
172 }
173 },
174 BlockKind::GlowingMushroom if rng.gen_range(0..8) == 0 => spores.push(pos),
175 BlockKind::Snow | BlockKind::Ice if rng.gen_range(0..16) == 0 => snow.push(pos),
176 _ => {
177 if let Some(sprite) = block.get_sprite() {
178 if sprite.category() == sprite::Category::Lamp {
179 if let Ok(sprite::LightEnabled(enabled)) = block.get_attr() {
180 interactables.push((pos, Interaction::LightToggle(!enabled)));
181 }
182 }
183
184 if block.is_mountable() {
185 interactables.push((pos, Interaction::Mount));
186 }
187
188 match sprite {
189 SpriteKind::Ember => {
190 fires.push(pos);
191 smokers.push(SmokerProperties::new(pos, FireplaceType::House));
192 },
193 SpriteKind::FireBlock => {
194 fire_bowls.push(pos);
195 },
196 SpriteKind::StreetLamp => fire_bowls.push(pos + Vec3::unit_z() * 2),
199 SpriteKind::FireBowlGround => fire_bowls.push(pos + Vec3::unit_z()),
200 SpriteKind::StreetLampTall => fire_bowls.push(pos + Vec3::unit_z() * 4),
201 SpriteKind::WallSconce => fire_bowls.push(pos + Vec3::unit_z()),
202 SpriteKind::Beehive => beehives.push(pos),
203 SpriteKind::Reed => {
204 reeds.push(pos);
205 fireflies.push(pos);
206 if rng.gen_range(0..12) == 0 {
207 frogs.push(pos);
208 }
209 },
210 SpriteKind::CaveMushroom => fireflies.push(pos),
211 SpriteKind::PinkFlower => flowers.push(pos),
212 SpriteKind::PurpleFlower => flowers.push(pos),
213 SpriteKind::RedFlower => flowers.push(pos),
214 SpriteKind::WhiteFlower => flowers.push(pos),
215 SpriteKind::YellowFlower => flowers.push(pos),
216 SpriteKind::Sunflower => flowers.push(pos),
217 SpriteKind::CraftingBench => {
218 interactables.push((pos, Interaction::Craft(CraftingTab::All)))
219 },
220 SpriteKind::SmokeDummy => {
221 smokers.push(SmokerProperties::new(pos, FireplaceType::Workshop));
222 },
223 SpriteKind::Forge => interactables
224 .push((pos, Interaction::Craft(CraftingTab::ProcessedMaterial))),
225 SpriteKind::TanningRack => interactables
226 .push((pos, Interaction::Craft(CraftingTab::ProcessedMaterial))),
227 SpriteKind::SpinningWheel => {
228 interactables.push((pos, Interaction::Craft(CraftingTab::All)))
229 },
230 SpriteKind::Loom => {
231 interactables.push((pos, Interaction::Craft(CraftingTab::All)))
232 },
233 SpriteKind::Cauldron => {
234 fires.push(pos);
235 interactables.push((pos, Interaction::Craft(CraftingTab::Potion)))
236 },
237 SpriteKind::Anvil => {
238 interactables.push((pos, Interaction::Craft(CraftingTab::Weapon)))
239 },
240 SpriteKind::CookingPot => {
241 fires.push(pos);
242 interactables.push((pos, Interaction::Craft(CraftingTab::Food)))
243 },
244 SpriteKind::DismantlingBench => {
245 fires.push(pos);
246 interactables
247 .push((pos, Interaction::Craft(CraftingTab::Dismantle)))
248 },
249 SpriteKind::RepairBench => {
250 interactables.push((pos, Interaction::Craft(CraftingTab::All)))
251 },
252 SpriteKind::OneWayWall => one_way_walls.push((
253 pos,
254 Vec2::unit_y()
255 .rotated_z(
256 std::f32::consts::PI
257 * 0.25
258 * block.get_ori().unwrap_or(0) as f32,
259 )
260 .with_z(0.0),
261 )),
262 SpriteKind::Sign | SpriteKind::HangingSign => {
263 interactables.push((pos, Interaction::Read))
264 },
265 SpriteKind::MycelBlue => spores.push(pos),
266 SpriteKind::Mold => spores.push(pos),
267 _ => {},
268 }
269 }
270 },
271 }
272 if block.collectible_id().is_some() {
273 interactables.push((pos, Interaction::Collect));
274 }
275 if let Some(glow) = block.get_glow() {
276 if block.get_sprite().is_none() {
279 minor_lights.push((pos, glow));
280 } else {
281 lights.push((pos, glow));
282 }
283 }
284 });
285
286 const MAX_MINOR_LIGHTS: usize = 64;
289 lights.extend(
290 minor_lights
291 .choose_multiple(&mut rng, MAX_MINOR_LIGHTS)
292 .copied(),
293 );
294
295 Self {
296 leaves,
297 drip,
298 grass,
299 slow_river,
300 fast_river,
301 waterfall,
302 lavapool,
303 fires,
304 smokers,
305 beehives,
306 reeds,
307 fireflies,
308 flowers,
309 fire_bowls,
310 snow,
311 spores,
312 cricket1,
313 cricket2,
314 cricket3,
315 frogs,
316 one_way_walls,
317 interactables,
318 lights,
319 temperature,
320 humidity,
321 }
322 }
323}