use crate::{config::planet::{Planet, PlanetBundle, PlanetConfigCollection}, ecs::PlanetSensor};
use bevy::asset::Handle;
use crate::prelude::*;
use bevy_replicon::prelude::Replicated;
use crate::config::planet::{PlanetSpring, PlanetSpringJoint};
pub fn planets_plugin(app: &mut App) {
app.init_resource::<PlanetConfigResource>()
.add_systems(Startup, start_loading_planets)
.add_systems(Update, update_planets);
}
#[derive(Resource, Default)]
pub struct PlanetConfigResource {
handle: Option<Handle<PlanetConfigCollection>>,
}
fn start_loading_planets(assets: Res<AssetServer>, mut planets: ResMut<PlanetConfigResource>) {
planets.handle = Some(assets.load("config/planets.pc.toml"));
}
pub fn update_planets(
mut commands: Commands,
mut ev_config: MessageReader<AssetEvent<PlanetConfigCollection>>,
assets: ResMut<Assets<PlanetConfigCollection>>,
planets: ResMut<PlanetConfigResource>,
mut q_planets: Query<(
Entity,
&mut Planet,
&mut Transform,
&mut Mass,
)>,
mut planet_joint_springs: Query<(&PlanetSpringJoint, &mut FixedJoint)>
) {
let Some(handle) = planets.handle.as_ref() else {
return;
};
let waiting_for_asset_id = handle.id();
for ev in ev_config.read() {
match ev {
AssetEvent::Added { id } => {
if *id == waiting_for_asset_id {
debug!("planet config loaded - creating planets");
let planet_config = assets.get(*id).unwrap();
for planet in &planet_config.planets {
let mut planet_entity = commands
.spawn((PlanetBundle {
planet: planet.clone(),
transform: Transform::from_xyz(
planet.default_transform[0],
planet.default_transform[1],
planet.default_transform[2],
),
collider: Collider::circle(planet.radius),
mass: Mass(planet.mass)
},
SleepingDisabled
)).with_child((
Collider::circle(planet.radius+2.0),
Sensor,
PlanetSensor(planet.name.clone()),
CollisionEventsEnabled,
)).id();
if planet.orbit.is_some() {
let spring =commands.spawn((
PlanetSpring {
name: planet.name.clone()
},
Transform::from_xyz(
planet.default_transform[0],
planet.default_transform[1],
planet.default_transform[2],
),
Mass(planet.mass),
RigidBody::Static,
)).id();
commands.spawn((
PlanetSpringJoint {
name: planet.name.clone()
},
FixedJoint::new(planet_entity, spring)/*.with_point_compliance(planet_config.orbit.planet_spring_compliance)*/,
));
}
trace!(?planet, "new planet spawned");
}
}
}
AssetEvent::Modified { id } => {
if *id == waiting_for_asset_id {
trace!("planet config modified - reloading planets");
let planet_config = assets.get(*id).unwrap();
info!("updating compliance on all planet spring joints");
planet_joint_springs.iter_mut().for_each(|mut u| u.1.point_compliance = planet_config.orbit.planet_spring_compliance);
for planet in &planet_config.planets {
let existing_planet = q_planets
.iter_mut()
.find(|(_, p, _, _)| p.name == planet.name);
if let Some((existing, mut e_planet, mut e_transform, mut e_mass)) =
existing_planet
{
commands
.entity(existing)
.remove::<Collider>()
.insert(Collider::circle(planet.radius));
*e_planet = planet.clone();
*e_mass = Mass(planet.mass);
trace!(?planet, "planet hot-reloaded");
} else {
let planet_entity = commands
.spawn(PlanetBundle {
planet: planet.clone(),
transform: Transform::from_xyz(
planet.default_transform[0],
planet.default_transform[1],
planet.default_transform[2],
),
collider: Collider::circle(planet.radius),
mass: Mass(
planet.mass,
),
}).id();
if planet.orbit.is_some() {
let spring =commands.spawn((
PlanetSpring {
name: planet.name.clone()
},
Transform::from_xyz(
planet.default_transform[0],
planet.default_transform[1],
planet.default_transform[2],
)
)).id();
commands.spawn((
PlanetSpringJoint {
name: planet.name.clone()
},
FixedJoint::new(planet_entity, spring).with_point_compliance(planet_config.orbit.planet_spring_compliance)
));
}
trace!(?planet, "new planet spawned");
}
}
}
}
_ => {}
}
}
}