use bevy::asset::Handle; use bevy::prelude::*; use bevy_rapier2d::prelude::{AdditionalMassProperties, Collider}; use bevy_replicon::prelude::Replicated; use crate::attachment::{Joint, JointId, JointOf, JointSnapFor, JointSnaps, Joints}; use crate::config::part::{JointOffset, PartConfig}; use crate::ecs::Part; pub fn part_config_plugin(app: &mut App) { app.add_systems(PreUpdate, handle_spawn_part_requests) .add_systems(Update, update_part_requests); } #[derive(Component, Debug)] pub struct SpawnPart(pub String); #[derive(Component)] struct LoadingPart(Handle); #[derive(Component, Debug)] struct PartType(AssetId); #[derive(Component)] /// STOP DELETING MY ASSET BEVY struct LiveConfigHandle(Handle); // watch for new SpawnPart components and start loading their config files fn handle_spawn_part_requests(new_parts: Query<(Entity, &SpawnPart), Added>, mut commands: Commands, asset_server: Res, assets: Res>, parts: Query<(&Joints, &JointSnaps), With>,) { for (new_part, request) in &new_parts { trace!(?new_part, ?request, "answering part request"); let hdl: Handle = asset_server.load(request.0.clone()); commands.entity(new_part) .remove::() .insert(LiveConfigHandle(hdl.clone())); if let Some(cfg) = assets.get(&hdl) { spawn_part(commands.reborrow(), new_part, cfg, &hdl.id(), parts, false); } else { commands.entity(new_part) .insert(LoadingPart(hdl.clone())); } } } fn update_part_requests( mut ev_config: EventReader>, loading_parts: Query<(Entity, &LoadingPart)>, existing_parts: Query<(Entity, &PartType)>, mut assets: ResMut>, mut commands: Commands, parts: Query<(&Joints, &JointSnaps), With>, ) { for ev in ev_config.read() { match ev { AssetEvent::Added { id } => { trace!(?id, "asset added"); for (loading_part, req) in &loading_parts { if req.0.id() == *id { let Some(asset) = assets.get(*id) else { continue; }; spawn_part(commands.reborrow(), loading_part, asset, id, parts, false); } } }, AssetEvent::Modified { id } => { trace!(?id, "updating part"); for (existing_part, ptype) in &existing_parts { if ptype.0 == *id { let Some(asset) = assets.get(ptype.0) else { continue; }; spawn_part(commands.reborrow(), existing_part, asset, id, parts, true); } } } _ => {} } } } fn spawn_part(mut commands: Commands, entity: Entity, part: &PartConfig, id: &AssetId, parts: Query<(&Joints, &JointSnaps), With>, is_update: bool) { commands.entity(entity) .remove::() .insert(Part { sprite: part.part.sprite_disconnected.clone(), width: part.physics.width, height: part.physics.height, mass: part.physics.mass, }) .insert(Collider::cuboid(part.physics.width / 2.0, part.physics.height / 2.0)) .insert(AdditionalMassProperties::Mass(part.physics.mass)) .insert(PartType(*id)) .insert(Replicated); for joint in &part.joints { if is_update { // find all entities for (joints, snaps) in &parts { for joint_entity in joints.iter() { commands.entity(joint_entity).insert(( ChildOf(entity), Joint { id: JointId::from_part_and_joint_id(part.part.name.clone(), joint.id.clone()), transform: joint.target.into() }, >::into(joint.target), JointOf(entity), Replicated, )); } for snap_entity in snaps.iter() { commands.entity(snap_entity).insert(( >::into(joint.snap), )); } } } else { let e = commands.spawn(( ChildOf(entity), Joint { id: JointId::from_part_and_joint_id(part.part.name.clone(), joint.id.clone()), transform: joint.target.into() }, >::into(joint.target), JointOf(entity), Replicated, )).id(); commands.spawn(( ChildOf(entity), JointSnapFor(e), >::into(joint.snap), Replicated, )); } } }