M crates/unified/src/attachment.rs => crates/unified/src/attachment.rs +8 -0
@@ 1,3 1,4 @@
+use std::ops::Deref;
use bevy::ecs::entity::MapEntities;
use bevy::prelude::*;
use serde::{Deserialize, Serialize};
@@ 35,6 36,13 @@ pub struct SnapOf(#[entities] pub Entity);
#[derive(Component, Serialize, Deserialize, MapEntities)]
#[relationship_target(relationship = SnapOf)]
pub struct Snaps(#[entities] Vec<Entity>);
+impl Deref for Snaps {
+ type Target = Vec<Entity>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
#[derive(Serialize, Deserialize)]
pub struct JointId(pub String);
M crates/unified/src/client/parts.rs => crates/unified/src/client/parts.rs +46 -10
@@ 1,4 1,5 @@
use bevy::color::palettes::css::{ORANGE, RED};
+use bevy::color::palettes::tailwind::{CYAN_400, CYAN_800};
use crate::client::Me;
use crate::ecs::{CursorWorldCoordinates, DragRequestEvent, Part};
use bevy::prelude::*;
@@ 10,6 11,7 @@ use crate::client::key_input::AttachmentDebugRes;
pub fn parts_plugin(app: &mut App) {
app.insert_resource(DragResource(None));
+ app.insert_resource(SnapResource(None));
app.add_systems(Update, (handle_incoming_parts, handle_updated_parts, update_drag_ghosts));
app.add_observer(on_part_release);
}
@@ 59,6 61,9 @@ fn handle_updated_parts(
#[derive(Resource)]
struct DragResource(Option<Entity>);
+#[derive(Resource)]
+struct SnapResource(Option<Entity>);
+
#[derive(Component)]
struct DragGhost;
@@ 91,35 96,50 @@ fn on_part_release(
mut events: EventWriter<DragRequestEvent>,
cursor: Res<CursorWorldCoordinates>,
mut commands: Commands,
- ghosts: Query<Entity, With<DragGhost>>,
+ ghost: Single<(Entity, &Transform), With<DragGhost>>,
+ snap: Res<SnapResource>
) {
if ev.button != PointerButton::Primary {
return;
}
if let Some(e) = drag.0 {
- for ghost in &ghosts {
- commands.entity(ghost).despawn();
- }
+ let mut rotation = ghost.1.rotation;
+ commands.entity(ghost.0).despawn();
if let Some(c) = cursor.0 {
debug!(?e, ?c, "sending drag request");
- events.write(DragRequestEvent(e, c));
+ events.write(DragRequestEvent {
+ drag_target: e,
+ drag_to: c,
+ set_rotation: rotation,
+ snap_target: snap.0,
+ });
}
}
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(
mut ghost: Single<&mut Transform, (With<DragGhost>, Without<SnapOf>, Without<JointOf>, Without<Part>)>,
cursor: Res<CursorWorldCoordinates>,
- snaps: Query<(&Transform, &SnapOfJoint, &SnapOf)>,
- joints: Query<(&Transform, &JointOf), Without<Peer>>,
+ snaps: Query<(&Transform, &SnapOfJoint, &SnapOf, Entity)>,
+ joints: Query<(&Transform, &JointOf, Entity), Without<Peer>>,
parts: Query<(&GlobalTransform, Option<&Me>, Option<&PartInShip>), With<Part>>,
me: Single<Entity, With<Me>>,
debug: Res<AttachmentDebugRes>,
+ mut rsnap: ResMut<SnapResource>,
drag: Res<DragResource>,
mut gizmos: Gizmos,
+ keys: Res<ButtonInput<KeyCode>>,
+ time: Res<Time>,
) {
let Some(cursor) = cursor.0 else { return };
@@ 127,8 147,11 @@ fn update_drag_ghosts(
let mut best_distance = f32::INFINITY;
let mut best_target = Transform::from_xyz(cursor.x, cursor.y, 0.0);
+ best_target.rotation = ghost.rotation;
+ let mut snap = None;
+ let mut target_gpos = None;
- for (snap_local_transform, snap_joint, snap_part) in &snaps {
+ for (snap_local_transform, snap_joint, snap_part, snap_id) in &snaps {
if Some(snap_part.0) == drag.0 { continue; }
// only snap to ourselves
@@ 153,7 176,7 @@ fn update_drag_ghosts(
if debug.0 { gizmos.circle_2d(snap_global_translation, 3.0, GREEN); }
- let Ok((offset, _)) = joints.get(snap_joint.0) else { continue; };
+ let Ok((offset, _, _)) = joints.get(snap_joint.0) else { continue; };
let joint_target = parent_position.transform_point(offset.translation);
@@ 161,12 184,25 @@ fn update_drag_ghosts(
let target_transform = Transform {
translation: joint_target,
- rotation: parent_position.rotation().mul_quat(offset.rotation),
+ rotation: ghost.rotation,
scale: offset.scale,
};
best_distance = distance_to_cursor;
best_target = target_transform;
+
+ snap = Some(snap_id);
+ target_gpos = Some(joint_target);
}
**ghost = best_target;
+
+ if keys.pressed(KeyCode::KeyQ) {
+ ghost.rotation = ghost.rotation.mul_quat(Quat::from_rotation_z(180.0_f32.to_radians() * time.delta_secs()));
+ }
+ if keys.pressed(KeyCode::KeyE) {
+ ghost.rotation = ghost.rotation.mul_quat(Quat::from_rotation_z(-180.0_f32.to_radians() * time.delta_secs()));
+ }
+
+ rsnap.0 = snap;
+
}=
\ No newline at end of file
M crates/unified/src/ecs.rs => crates/unified/src/ecs.rs +10 -2
@@ 1,5 1,5 @@
use bevy::ecs::entity::MapEntities;
-use bevy::math::Vec2;
+use bevy::math::{Quat, Vec2};
use bevy::prelude::{Component, Entity, Event, Handle, Resource};
use bevy_rapier2d::dynamics::RigidBody;
use bevy_rapier2d::prelude::*;
@@ 64,4 64,12 @@ pub struct Particles {
}
#[derive(Serialize, Deserialize, Event, Debug, MapEntities, Clone)]
-pub struct DragRequestEvent(#[entities] pub Entity, pub Vec2);
+pub struct DragRequestEvent {
+ #[entities]
+ pub drag_target: Entity,
+ pub drag_to: Vec2,
+ pub set_rotation: Quat,
+ #[entities]
+ pub snap_target: Option<Entity>
+}
+
M crates/unified/src/server/player.rs => crates/unified/src/server/player.rs +16 -6
@@ 1,5 1,5 @@
use std::f32::consts::PI;
-
+use std::ops::Deref;
use crate::config::planet::Planet;
use crate::ecs::{
DragRequestEvent, Part, Player, PlayerThrust, ThrustEvent,
@@ 10,9 10,11 @@ use crate::server::{ConnectedGameEntity, ConnectedNetworkEntity};
use bevy::prelude::*;
use bevy_rapier2d::prelude::ExternalForce;
use bevy_replicon::prelude::FromClient;
-use crate::attachment::PartInShip;
+use crate::attachment::{JointOf, PartInShip, Peer, SnapOf, SnapOfJoint, Snaps};
+use crate::client::Me;
use crate::server::system_sets::PlayerInputSet;
+
pub fn player_management_plugin(app: &mut App) {
app.add_systems(Update, (handle_new_players, player_thrust, dragging).in_set(PlayerInputSet));
}
@@ 20,11 22,19 @@ pub fn player_management_plugin(app: &mut App) {
fn dragging(
mut events: EventReader<FromClient<DragRequestEvent>>,
mut parts: Query<&mut Transform, With<Part>>,
+ clients: Query<&ConnectedNetworkEntity>,
+ snap_parts: Query<(&GlobalTransform, Option<&Me>, Option<&PartInShip>, &Snaps), With<Part>>,
) {
- for event in events.read() {
- let mut part = parts.get_mut(event.event.0).unwrap();
- part.translation.x = event.event.1.x;
- part.translation.y = event.event.1.y;
+ for FromClient {
+ client_entity,
+ event,
+ } in events.read() {
+ let ConnectedNetworkEntity { game_entity } = clients.get(*client_entity).unwrap();
+
+ let mut part = parts.get_mut(event.drag_target).unwrap();
+ part.translation.x = event.drag_to.x;
+ part.translation.y = event.drag_to.y;
+ part.rotation = event.set_rotation;
}
}