mod common;
use std::time::Duration;
use bevy::prelude::*;
use bevy_elements::*;
use common::{ExampleHarness, camera, stand_on_ground};
fn main() {
let rain = std::env::var("ELEMENTS_COVER").as_deref() == Ok("rain");
let quality = match std::env::var("ELEMENTS_QUALITY").as_deref() {
Ok("low") => ElementsQuality::Low,
Ok("medium") => ElementsQuality::Medium,
Ok("ultra") => ElementsQuality::Ultra,
_ => ElementsQuality::High,
};
let clock = if rain {
WorldClock::new(CivilDate::new(2026, 6, 21))
.at_hour(13.0)
.with_time_scale(120.0)
} else {
WorldClock::new(CivilDate::new(2026, 1, 15))
.at_hour(7.5)
.with_time_scale(600.0)
};
App::new()
.add_plugins((DefaultPlugins, ElementsPlugins, ExampleHarness))
.insert_resource(clock)
.insert_resource(Climate::temperate())
.insert_resource(quality)
.insert_resource(Mode { rain })
.insert_resource(ErosionSettings {
enabled: false,
..default()
})
.add_systems(Startup, setup)
.add_systems(
Update,
(clear_after_snow, report).after(ElementsSystems::Readback),
)
.run();
}
fn clear_after_snow(mode: Res<Mode>, mut director: ResMut<WeatherDirector>, mut frame: Local<u32>) {
*frame += 1;
let stop = env_f32("ELEMENTS_SNOW_FRAMES", 300.0) as u32;
if !mode.rain && *frame == stop {
director.force(WeatherPreset::Clear, Duration::ZERO);
}
}
fn report(
env: Environment,
cameras: Query<&Transform, With<ElementsCamera>>,
mut frame: Local<u32>,
) {
*frame += 1;
if !(*frame).is_multiple_of(60) {
return;
}
for transform in &cameras {
let at = transform.translation.xz();
println!(
"under the camera: snow {:.1} mm deep, wetness {:.2}, water {:.1} mm",
env.snow_depth(at).unwrap_or(f32::NAN) * 1000.0,
env.wetness(at).unwrap_or(f32::NAN),
env.water_depth(at).unwrap_or(f32::NAN) * 1000.0,
);
}
}
#[derive(Resource)]
struct Mode {
rain: bool,
}
fn env_f32(name: &str, default: f32) -> f32 {
std::env::var(name)
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(default)
}
fn setup(
mut commands: Commands,
mode: Res<Mode>,
mut director: ResMut<WeatherDirector>,
mut baking: MessageWriter<ErodeTerrain>,
) {
let mountains = std::env::var("ELEMENTS_TERRAIN").as_deref() == Ok("mountains");
commands.spawn(Terrain::procedural(if mountains {
ProceduralTerrain::mountains(7)
} else {
ProceduralTerrain::hills(42)
}));
commands.spawn((
camera(Vec3::new(0.0, 160.0, 0.0), Vec3::new(150.0, 100.0, 80.0)),
stand_on_ground(env_f32("ELEMENTS_AGL", 6.0)),
));
let default = if mode.rain {
WeatherPreset::Rain
} else {
WeatherPreset::Snow
};
let preset = std::env::var("ELEMENTS_PRESET")
.ok()
.and_then(|name| {
WeatherPreset::ALL
.into_iter()
.find(|p| format!("{p:?}").eq_ignore_ascii_case(&name))
})
.unwrap_or(default);
director.force(preset, Duration::ZERO);
if mode.rain {
baking.write(ErodeTerrain {
duration_s: env_f32("ELEMENTS_BAKE_S", 240.0),
rain_mm_h: env_f32("ELEMENTS_BAKE_MM_H", 120.0),
});
}
}