use bevy::prelude::*;
use crate::Problem;
pub(crate) trait Checked: 'static {
const NAME: &'static str;
fn check(&self) -> Vec<Problem>;
}
macro_rules! checked {
($($t:ty),+ $(,)?) => {$(
impl Checked for $t {
const NAME: &'static str = stringify!($t);
fn check(&self) -> Vec<Problem> {
self.problems()
}
}
)+};
}
checked!(
crate::Flicker,
crate::Kindle,
crate::Snuff,
crate::FlameSite,
crate::FlameEmbers,
crate::PoolCandidate,
crate::LightPool,
crate::FlameLook,
crate::FlameWind,
crate::FlameGust,
);
fn warn_on_add<C: Checked + Component>(add: On<Add<C>>, components: Query<&C>, mut warned: Local<bool>) {
if *warned {
return;
}
let Ok(component) = components.get(add.entity) else {
return;
};
let problems = component.check();
if problems.is_empty() {
return;
}
*warned = true;
let list = problems.iter().map(ToString::to_string).collect::<Vec<_>>().join("; ");
warn!(
"bevy_lights: {} on {} has unusable settings ({} problem(s); further ones are not reported): {list}",
C::NAME,
add.entity,
problems.len()
);
}
pub(crate) fn watch<C: Checked + Component>(app: &mut App) {
app.add_observer(warn_on_add::<C>);
}
fn warn_on_change<R: Checked + Resource>(resource: Option<Res<R>>, mut warned: Local<Vec<Problem>>) {
let Some(resource) = resource else {
return;
};
if !resource.is_changed() {
return;
}
let problems = resource.check();
if problems == *warned {
return;
}
if !problems.is_empty() {
let list = problems.iter().map(ToString::to_string).collect::<Vec<_>>().join("; ");
warn!("bevy_lights: {} has unusable settings ({} problem(s)): {list}", R::NAME, problems.len());
}
*warned = problems;
}
pub(crate) fn watch_resource<R: Checked + Resource>(app: &mut App) {
app.add_systems(Last, warn_on_change::<R>);
}