use std::f32::consts::PI; use crate::attachment::{Joint, JointOf, Joints, PartInShip, Peer, SnapOf, SnapOfJoint}; use crate::client::Me; use crate::client::colors::GREEN; use crate::client::key_input::AttachmentDebugRes; use crate::ecs::{CursorWorldCoordinates, DragRequestEvent, Part}; use bevy::color::palettes::css::{ORANGE, PURPLE, RED, YELLOW}; use crate::prelude::*; pub fn parts_plugin(app: &mut App) { app.insert_resource(DragResource(None)); app.insert_resource(SnapResource(None, None)); app.add_systems( Update, ( handle_incoming_parts, handle_updated_parts, update_drag_ghosts, update_part_sprites, ), ); app.add_observer(on_part_release); } fn handle_incoming_parts( mut commands: Commands, new_parts: Query<(Entity, &Part, Option<&PartInShip>), Added>, asset_server: Res, ) { for (new_entity, new_part, is_connected) in new_parts.iter() { let mut sprite = Sprite::from_image(asset_server.load(if is_connected.is_some() { &new_part.strong_config.part.sprite_connected } else { &new_part.strong_config.part.sprite_disconnected })); sprite.custom_size = Some(Vec2::new( new_part.strong_config.physics.width, new_part.strong_config.physics.height, )); commands .entity(new_entity) .insert(sprite) /*.insert(AdditionalMassProperties::MassProperties(MassProperties { local_center_of_mass: Vec2::ZERO, mass: new_part.strong_config.physics.mass, principal_inertia: 7.5, }))*/ .insert(Pickable::default()) .observe(on_part_click); } } fn handle_updated_parts( mut commands: Commands, updated_parts: Query<(Entity, &Part, Option<&PartInShip>), Changed>, asset_server: Res, ) { for (updated_entity, updated_part, is_connected) in updated_parts.iter() { let mut sprite = Sprite::from_image(asset_server.load(if is_connected.is_some() { &updated_part.strong_config.part.sprite_connected } else { &updated_part.strong_config.part.sprite_disconnected })); sprite.custom_size = Some(Vec2::new( updated_part.strong_config.physics.width, updated_part.strong_config.physics.height, )); commands .entity(updated_entity) .remove::() //.remove::() .insert(sprite) /* .insert(AdditionalMassProperties::MassProperties(MassProperties { local_center_of_mass: Vec2::ZERO, mass: updated_part.strong_config.physics.mass, principal_inertia: 7.5, }))*/; } } fn update_part_sprites( added: Query>, mut removed: RemovedComponents, parts: Query<(&Part, Option<&PartInShip>)>, asset_server: Res, mut commands: Commands, ) { for e in added.into_iter().chain(removed.read()) { let Ok((part, connected_to)) = parts.get(e) else { continue; }; let sprite = if connected_to.is_some() { &part.strong_config.part.sprite_connected } else { &part.strong_config.part.sprite_disconnected }; let mut sprite = Sprite::from_image(asset_server.load(sprite)); sprite.custom_size = Some(Vec2::new( part.strong_config.physics.width, part.strong_config.physics.height, )); commands.entity(e).insert(sprite); } } #[derive(Resource)] struct DragResource(Option); #[derive(Resource)] struct SnapResource(Option, Option); #[derive(Component)] struct DragGhost; #[derive(Component)] struct Ghost { pub rot: Quat, pub last_target_pos: Vec3, pub vel: Vec3, } const TRANSLATION_SMOOTH: f32 = 0.3; const ROTATION_SMOOTH: f32 = 0.1; fn on_part_click( ev: On>, sprites: Query<(&Sprite, &Transform, &Joints), Without>, joints: Query<&Joint, Without>, mut drag: ResMut, mut commands: Commands, ) { if ev.button != PointerButton::Primary { return; } let Ok(sprite) = sprites.get(ev.event_target()) else { return; }; // make sure it has at least 1 valid unpeered joint let mut valid_peers = 0; for joint in &**sprite.2 { if joints.get(*joint).is_ok() { valid_peers += 1; } } if valid_peers == 0 { return; // ignore } let mut s = sprite.0.clone(); s.color = Color::srgba(0.7, 0.7, 0.7, 1.0); commands.spawn((DragGhost, Ghost { rot: sprite.1.rotation, last_target_pos: sprite.1.translation, vel: Vec3::ZERO, }, *sprite.1, s)); drag.0 = Some(ev.event().event_target()); } fn on_part_release( ev: On>, mut drag: ResMut, mut events: MessageWriter, cursor: Res, mut commands: Commands, ghost: Single<(Entity, &Transform), With>, snap: Res, ) { if ev.button != PointerButton::Primary { return; } if let Some(e) = drag.0 { let rotation = ghost.1.rotation; commands.entity(ghost.0).despawn(); if let Some(c) = cursor.0 { debug!(?e, ?c, "sending drag request"); events.write(DragRequestEvent { drag_target: e, drag_to: c, set_rotation: rotation, snap_target: snap.0, peer_snap: snap.1, }); } } drag.0 = None; } /// !IMPORTANT! /// This function forms the bulk of the attachment system. /// PLEASE DO NOT MODIFY OR MOVE /// /// This code is super cursed, and it will break at the lightest breeze fn update_drag_ghosts( ghost: Single< (&mut Transform, &mut Ghost), ( With, Without, Without, Without, ), >, cursor: Res, snaps: Query<(&Transform, &SnapOfJoint, &SnapOf, Entity)>, joints: Query<(&Transform, &JointOf, Entity), Without>, parts: Query<(&GlobalTransform, Option<&Me>, Option<&PartInShip>), With>, me: Single>, debug: Res, mut rsnap: ResMut, drag: Res, mut gizmos: Gizmos, keys: Res>, time: Res