use std::time::Duration;
use bevy::ecs::system::SystemParam;
use bevy::prelude::*;
use crate::celestial::{SunState, WorldClock};
use crate::climate::Weather;
use crate::cover::CoverSnapshot;
use crate::hydrology::{WaterDepthSnapshot, WaterVelocitySnapshot};
use crate::terrain::{TerrainLeaves, TerrainSnapshot};
use crate::wind::{WindSnapshot, WindState};
#[derive(Resource, Default, Clone, Debug)]
pub struct EnvironmentSnapshot {
pub(crate) wind: Option<WindSnapshot>,
pub(crate) cloud_transmittance: Option<f32>,
pub(crate) terrain: Option<TerrainSnapshot>,
pub(crate) terrain_leaves: Option<TerrainLeaves>,
pub(crate) water_depth: Option<WaterDepthSnapshot>,
pub(crate) water_velocity: Option<WaterVelocitySnapshot>,
pub(crate) cover: Option<CoverSnapshot>,
pub(crate) updated_at: Option<Duration>,
}
#[derive(SystemParam)]
pub struct Environment<'w> {
snapshot: Res<'w, EnvironmentSnapshot>,
weather: Res<'w, Weather>,
clock: Res<'w, WorldClock>,
sun: Res<'w, SunState>,
wind: Res<'w, WindState>,
time: Res<'w, Time<Real>>,
}
impl Environment<'_> {
pub fn weather(&self) -> &Weather {
&self.weather
}
pub fn clock(&self) -> &WorldClock {
&self.clock
}
pub fn temperature_c(&self) -> f32 {
self.weather.temperature_c
}
pub fn sun(&self) -> &SunState {
&self.sun
}
pub fn is_daylight(&self) -> bool {
self.sun.altitude_deg > -0.833
}
pub fn wind_at(&self, position: Vec3) -> Vec3 {
self.snapshot
.wind
.as_ref()
.and_then(|w| w.sample(position))
.unwrap_or_else(|| self.wind.prevailing_velocity())
}
pub fn terrain_height(&self, position: Vec2) -> Option<f32> {
self.snapshot
.terrain
.as_ref()
.and_then(|t| t.height(position))
}
pub fn water_depth(&self, position: Vec2) -> Option<f32> {
self.snapshot
.water_depth
.as_ref()
.and_then(|w| w.depth_at(position))
}
pub fn water_velocity(&self, position: Vec2) -> Option<Vec2> {
self.snapshot
.water_velocity
.as_ref()
.and_then(|w| w.velocity_at(position))
}
pub fn snow_depth(&self, position: Vec2) -> Option<f32> {
self.snapshot
.cover
.as_ref()
.and_then(|c| c.depth_at(position))
}
pub fn wetness(&self, position: Vec2) -> Option<f32> {
self.snapshot
.cover
.as_ref()
.and_then(|c| c.wetness_at(position))
}
pub fn snapshot_age(&self) -> Duration {
self.snapshot
.updated_at
.map_or(Duration::MAX, |at| self.time.elapsed().saturating_sub(at))
}
}