From 1991fb85e494fb35c0c5c9b6838f9e87c31b8908 Mon Sep 17 00:00:00 2001 From: core Date: Sat, 15 Nov 2025 21:36:20 -0500 Subject: [PATCH] mystery work? --- crates/unified/assets/config/world.wc.toml | 2 +- crates/unified/src/attachment.rs | 2 +- crates/unified/src/client/parts.rs | 42 ++++++++++++--- crates/unified/src/server/player.rs | 59 ++++++++++++++-------- 4 files changed, 76 insertions(+), 29 deletions(-) diff --git a/crates/unified/assets/config/world.wc.toml b/crates/unified/assets/config/world.wc.toml index b4ac55ac9d033ff63bebff34242bde7de857b6cf..f3cb64053f7a95db94859cc440058d746801f814 100644 --- a/crates/unified/assets/config/world.wc.toml +++ b/crates/unified/assets/config/world.wc.toml @@ -1,7 +1,7 @@ [world] gravity = 0.005 spawn_parts_at = "Earth" -spawn_parts_interval_secs = 10 +spawn_parts_interval_secs = 1 [part] default_height = 50 diff --git a/crates/unified/src/attachment.rs b/crates/unified/src/attachment.rs index 4ac038b40e7ee2d8a4f97fe8ca048ca7e02ed4c4..30e9e6c363a2ca2b6a586b2aa88d6addcd2503f1 100644 --- a/crates/unified/src/attachment.rs +++ b/crates/unified/src/attachment.rs @@ -27,7 +27,7 @@ pub struct Peer(#[entities] pub Entity); #[derive(Component, Serialize, Deserialize, MapEntities)] #[relationship(relationship_target = Joints)] pub struct JointOf(#[entities] pub Entity); -#[derive(Component, Serialize, Deserialize, MapEntities)] +#[derive(Component, Serialize, Deserialize, MapEntities, Debug)] #[relationship_target(relationship = JointOf)] pub struct Joints(#[entities] Vec); impl Deref for Joints { diff --git a/crates/unified/src/client/parts.rs b/crates/unified/src/client/parts.rs index a961b6add8f31ab23843f487687c86dbc023e536..44a161073db72d9deb8c7c0b35d5304b6afee6c8 100644 --- a/crates/unified/src/client/parts.rs +++ b/crates/unified/src/client/parts.rs @@ -17,6 +17,7 @@ pub fn parts_plugin(app: &mut App) { handle_incoming_parts, handle_updated_parts, update_drag_ghosts, + update_part_sprites ), ); app.add_observer(on_part_release); @@ -24,12 +25,17 @@ pub fn parts_plugin(app: &mut App) { fn handle_incoming_parts( mut commands: Commands, - new_parts: Query<(Entity, &Part), Added>, + new_parts: Query<(Entity, &Part, Option<&PartInShip>), Added>, asset_server: Res, ) { - for (new_entity, new_part) in new_parts.iter() { - let mut sprite = - Sprite::from_image(asset_server.load(&new_part.strong_config.part.sprite_disconnected)); + 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, @@ -49,12 +55,16 @@ fn handle_incoming_parts( } fn handle_updated_parts( mut commands: Commands, - updated_parts: Query<(Entity, &Part), Changed>, + updated_parts: Query<(Entity, &Part, Option<&PartInShip>), Changed>, asset_server: Res, ) { - for (updated_entity, updated_part) in updated_parts.iter() { + for (updated_entity, updated_part, is_connected) in updated_parts.iter() { let mut sprite = Sprite::from_image( - asset_server.load(&updated_part.strong_config.part.sprite_disconnected), + 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, @@ -74,6 +84,24 @@ fn handle_updated_parts( } } +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)] diff --git a/crates/unified/src/server/player.rs b/crates/unified/src/server/player.rs index 543861963014b7dcc90d16ddc36fe0e6bc8a8892..d529f007f8f7ee94505b9398857975ea0163e776 100644 --- a/crates/unified/src/server/player.rs +++ b/crates/unified/src/server/player.rs @@ -20,12 +20,44 @@ pub fn player_management_plugin(app: &mut App) { #[derive(Component)] struct JointNeedsCreation(ImpulseJoint); +fn disconnect_part( + entity: Entity, + recursed_entity: Entity, + joints: &Joints, + q_joints: Query<&Joints>, + q_peer: Query<(&Peer, &JointOf)>, + + mut commands: Commands, +) { + trace!(?entity, ?joints, "recursive disconnect"); + // recursive disconnect part + for joint in &**joints { + let Ok((other_joint_handle, _)) = q_peer.get(*joint) else { continue }; + let other_joint = other_joint_handle.0; + + commands.entity(*joint).remove::(); + + let Ok((_, other_joint_of)) = q_peer.get(other_joint) else { continue }; + + commands.entity(other_joint).remove::(); + + let Ok(joints) = q_joints.get(other_joint_of.0) else { continue }; + /*if other_joint != recursed_entity { + disconnect_part(other_joint, entity, joints, q_joints, q_peer, commands.reborrow()); + } TODO this loops forever? */ + } + commands.entity(entity).remove::(); + commands.entity(entity).remove::(); +} + fn dragging( mut events: EventReader>, mut parts: Query<(&mut Transform, Option<&PartInShip>, Entity, &mut Velocity, &Joints), (With, Without)>, snaps: Query<(&SnapOf, &SnapOfJoint)>, joints: Query<(&Joint, &JointOf, &Transform, Option<&Peer>, Entity)>, - peer: Query<&Peer>, + peer: Query<(&Peer, &JointOf)>, + q_joints: Query<&Joints>, + q_joint: Query<&ImpulseJoint>, clients: Query<&ConnectedNetworkEntity>, mut commands: Commands ) { @@ -88,15 +120,8 @@ fn dragging( // great, we have a valid peering request - let mut did_disconnect = false; - // disconnect it, if it is connected - for joint in &**source_part.4 { - let Ok(joint_peer) = peer.get(*joint) else { continue }; - did_disconnect = true; - commands.entity(*joint).remove::(); - commands.entity(joint_peer.0).remove::(); - } - commands.entity(source_part.2).remove::(); + let did_disconnect = q_joint.get(source_part.2).is_ok(); + disconnect_part(source_part.2, Entity::PLACEHOLDER, source_part.4, q_joints, peer, commands.reborrow()); // create the peering component... commands.entity(source_joint.4) @@ -133,13 +158,13 @@ fn dragging( } else { // we disconnected this part this tick, and are performing a "reattachment" // (dragging an already attached part from peering point A to peering point B) - + // If we're reattaching to a different part, rapier will ignore our new attachment // as it will be seen as a mutation (removing and adding a component in the - // same tick is considered equivalent to mutation by Bevy). + // same tick is considered equivalent to mutation by Bevy). // As Rapier does not allow you to mutate the source/destination of a joint, // the change will be outright ignored. - + // Since there is no (easy) way to get the real joint information back out of Rapier, // or to force it to accept what it sees as invalid mutation, // we need to delay the creation of the new joint by 1 tick so it's noticed by Rapier @@ -157,13 +182,7 @@ fn dragging( warn!("blindly accepting non-attachment request, someone should change this eventually"); warn!("dragging already attached entities may cause inconsistent behavior!!"); let source_part = parts.get(event.drag_target).unwrap(); - // disconnect it, if it is connected - for joint in &**source_part.4 { - let Ok(joint_peer) = peer.get(*joint) else { continue }; - commands.entity(*joint).remove::(); - commands.entity(joint_peer.0).remove::(); - } - commands.entity(source_part.2).remove::(); + disconnect_part(source_part.2, Entity::PLACEHOLDER, source_part.4, q_joints, peer, commands.reborrow()); teleport_to_translation = event.drag_to; teleport_to_rotation = event.set_rotation; }