M crates/unified/assets/config/world.wc.toml => crates/unified/assets/config/world.wc.toml +1 -1
@@ 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
M crates/unified/src/attachment.rs => crates/unified/src/attachment.rs +1 -1
@@ 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<Entity>);
impl Deref for Joints {
M crates/unified/src/client/parts.rs => crates/unified/src/client/parts.rs +35 -7
@@ 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<Part>>,
+ new_parts: Query<(Entity, &Part, Option<&PartInShip>), Added<Part>>,
asset_server: Res<AssetServer>,
) {
- 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<Part>>,
+ updated_parts: Query<(Entity, &Part, Option<&PartInShip>), Changed<Part>>,
asset_server: Res<AssetServer>,
) {
- 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<Entity, Added<PartInShip>>, mut removed: RemovedComponents<PartInShip>, parts: Query<(&Part, Option<&PartInShip>)>, asset_server: Res<AssetServer>, 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<Entity>);
#[derive(Resource)]
M crates/unified/src/server/player.rs => crates/unified/src/server/player.rs +39 -20
@@ 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::<Peer>();
+
+ let Ok((_, other_joint_of)) = q_peer.get(other_joint) else { continue };
+
+ commands.entity(other_joint).remove::<Peer>();
+
+ 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::<ImpulseJoint>();
+ commands.entity(entity).remove::<PartInShip>();
+}
+
fn dragging(
mut events: EventReader<FromClient<DragRequestEvent>>,
mut parts: Query<(&mut Transform, Option<&PartInShip>, Entity, &mut Velocity, &Joints), (With<Part>, Without<Joint>)>,
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::<Peer>();
- commands.entity(joint_peer.0).remove::<Peer>();
- }
- commands.entity(source_part.2).remove::<ImpulseJoint>();
+ 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::<Peer>();
- commands.entity(joint_peer.0).remove::<Peer>();
- }
- commands.entity(source_part.2).remove::<ImpulseJoint>();
+ 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;
}