use bevy::ecs::spawn::SpawnRelatedBundle;
use bevy::prelude::Component;
use bevy::prelude::*;
use bevy_rapier2d::prelude::{AdditionalMassProperties, Collider};
use bevy_replicon::prelude::Replicated;
use crate::attachment::{Joint, JointId, JointOf, SnapOf, SnapOfJoint};
use crate::config::part::{JointConfig, PartConfig};
use crate::ecs::{Part, PartHandle};
pub fn part_management_plugin(app: &mut App) {
app.add_systems(PreUpdate, (handle_ready_parts, handle_part_reloading));
}
#[derive(Bundle)]
pub struct SpawnPartBundle {
pub req: SpawnPartRequest,
pub transform: Transform,
}
#[derive(Component)]
pub struct SpawnPartRequest(pub Handle<PartConfig>);
// wait for parts assets to be ready, then spawn the full part
fn handle_ready_parts(loading_parts: Query<(Entity, &SpawnPartRequest)>, mut commands: Commands, assets: Res<Assets<PartConfig>>) {
for (entity, loading_part) in &loading_parts {
if let Some(strong_config) = assets.get(&loading_part.0) {
// config is strong; spawn 'er in!
commands.entity(entity)
.insert(calculate_bundle(strong_config, &loading_part.0))
.remove::<SpawnPartRequest>();
spawn_joints(strong_config, entity, commands.reborrow());
}
}
}
fn handle_part_reloading(existing_parts: Query<(Entity, &PartHandle)>, assets: Res<Assets<PartConfig>>, mut asset_events: EventReader<AssetEvent<PartConfig>>, mut commands: Commands) {
for event in asset_events.read() {
match event {
AssetEvent::Modified { id } => {
let config = assets.get(*id).unwrap();
for existing_part in existing_parts.iter() {
if existing_part.1.0.id() == *id {
commands.entity(existing_part.0)
.insert(calculate_bundle(config, &existing_part.1.0));
}
}
},
_ => {}
}
}
}
fn calculate_bundle(config: &PartConfig, handle: &Handle<PartConfig>) -> impl Bundle {
let part = Part {
strong_config: config.clone(),
};
let part_handle = PartHandle(handle.clone());
let collider = Collider::cuboid(config.physics.width / 2.0, config.physics.height / 2.0);
let additional_mass_properties = AdditionalMassProperties::Mass(config.physics.mass);
(
part,
part_handle,
collider,
additional_mass_properties,
Replicated
)
}
fn spawn_joint_bundle(joint: &JointConfig, part: &PartConfig, parent: &Entity) -> impl Bundle {
let j_comp = Joint {
id: JointId::from_part_and_joint_id(part.part.name.clone(), joint.id.clone()),
transform: joint.target.into(),
};
let joint_transform: Transform = j_comp.transform;
let joint_of = JointOf(*parent);
(
j_comp,
joint_transform,
joint_of,
Replicated
)
}
fn spawn_snap_bundle(joint: &JointConfig, parent: &Entity, p_joint: &Entity) -> impl Bundle {
let snap_transform: Transform = joint.snap.into();
let snap_for = SnapOf(*parent);
let snap_of = SnapOfJoint(*p_joint);
(
snap_transform,
snap_for,
snap_of,
Replicated
)
}
fn spawn_joints(config: &PartConfig, parent: Entity, mut commands: Commands) {
for joint in &config.joints {
let joint_id = commands.spawn(spawn_joint_bundle(joint, config, &parent)).id();
commands.spawn(spawn_snap_bundle(joint, &parent, &joint_id));
}
}