M crates/unified/assets/config/parts/housing.part.toml => crates/unified/assets/config/parts/housing.part.toml +1 -1
@@ 10,7 10,7 @@ mass = 50
[[thruster]]
id = "primary"
-thrust_vector = [ 0.0, 50.0 ]
+thrust_vector = [ 0.0, -50.0 ]
[[joint]]
id = "Top"
M crates/unified/src/client/ship/thrusters.rs => crates/unified/src/client/ship/thrusters.rs +1 -1
@@ 143,7 143,7 @@ fn solve_thrust(
let thruster_torque = relative_translation.extend(0.0).cross(thruster_vector.extend(0.0)).z;
- // magically assemble the vector!
+ // magically assemble the worldspace vector! for the solver (not shipspace)
let target_vector = thruster_vector.extend(thruster_torque);
all_thrusters.push((thruster_id, target_vector));
M crates/unified/src/ecs.rs => crates/unified/src/ecs.rs +2 -6
@@ 7,6 7,7 @@ use crate::prelude::*;
use bevy_replicon::prelude::Replicated;
use serde::{Deserialize, Serialize};
use avian2d::prelude::*;
+use crate::thrust::ThrustSolution;
#[derive(Component)]
pub struct MainCamera;
@@ 23,12 24,7 @@ pub struct FuelText;
pub struct PowerText;
#[derive(Debug, Deserialize, Message, Serialize)]
-pub enum ThrustEvent {
- Up(bool),
- Down(bool),
- Left(bool),
- Right(bool),
-}
+pub struct ThrustEvent(pub ThrustSolution);
#[derive(Component, Serialize, Deserialize, Debug)]
#[require(
M crates/unified/src/server/mod.rs => crates/unified/src/server/mod.rs +2 -0
@@ 21,6 21,7 @@ use aeronet_websocket::server::WebSocketServer;
use crate::prelude::*;
use bevy_replicon::prelude::Replicated;
use std::net::SocketAddr;
+use crate::server::player::thrust::server_thrust_plugin;
pub struct ServerPlugin {
pub bind: SocketAddr,
@@ 49,6 50,7 @@ impl Plugin for ServerPlugin {
.add_plugins(player_management_plugin)
.add_plugins(spawn_parts_plugin)
.add_plugins(part_management_plugin)
+ .add_plugins(server_thrust_plugin)
.configure_sets(Update, WorldUpdateSet.before(PlayerInputSet));
//.configure_sets(Update, PlayerInputSet.before(PhysicsSet::SyncBackend));
}
M crates/unified/src/server/player.rs => crates/unified/src/server/player.rs +1 -0
@@ 1,4 1,5 @@
pub mod join;
+pub mod thrust;
use crate::attachment::{Joint, JointOf, Joints, PartInShip, Peer, SnapOf, SnapOfJoint};
use crate::ecs::{DragRequestEvent, Part, Player, PlayerStorage};
A crates/unified/src/server/player/thrust.rs => crates/unified/src/server/player/thrust.rs +68 -0
@@ 0,0 1,68 @@
+use crate::prelude::*;
+use crate::ecs::ThrustEvent;
+use crate::server::ConnectedNetworkEntity;
+
+pub fn server_thrust_plugin(app: &mut App) {
+ app
+ .add_systems(Update, process_thrust_events);
+}
+
+pub fn process_thrust_events(
+ mut events: MessageReader<FromClient<ThrustEvent>>,
+
+ clients: Query<&ConnectedNetworkEntity>,
+ q_ls_me: Query<Entity, With<crate::ecs::Me>>,
+) {
+ for FromClient {
+ client_id,
+ message: event,
+ } in events.read()
+ {
+ let player_hearty_entity = match client_id {
+ ClientId::Client(client_entity) => {
+ let ConnectedNetworkEntity {
+ game_entity: player_hearty_entity,
+ } = clients.get(*client_entity).unwrap();
+ player_hearty_entity
+ },
+ ClientId::Server => &q_ls_me.iter().next().unwrap()
+ };
+ let thrust_solution = &event.0;
+ if !thrust_solution.converged { return };
+ /* TODO: @tm85: have fun!
+ TODO: The ThrustSolution contains a set of thrusters that should be on.
+ TODO: All other thrusters should be off.
+ TODO: If a thruster should be on, apply it's force vector at it's point
+ TODO: (RigidBodyForces::apply_force_at_point,
+ TODO: note this is worldspace!! [GlobalTransform is your friend])
+
+ TODO: Note that this is only an event handler, and will only run
+ TODO: when the client sends us a NEW thrust solution.
+
+ TODO: You probably want to add a Component to the player entity (player_hearty_entity,
+ TODO: it's also the hearty part entity) that stores the current ThrustSolution
+ TODO: and applies it every tick, since avian's ExternalForces only apply for a single
+ TODO: physics tick and must be applied every tick to be continuous.
+ TODO: Hint: you probably want a mut commands: Commands in this system,
+ TODO: and then insert a component with commands.entity(hearty).insert(YourNewComponent)
+
+ TODO: To do this, create a new system (e.g. apply_thrust) or something, and apply thrust
+ TODO: there, every tick (Update). Register it with the plugin above.
+
+ TODO: I'll leave you to that. Have fun! ping me if you've got questions, I'll be up
+ TODO: a while so can help you decipher the attachment system if need be.
+
+ TODO: Overall, your goal is:
+ TODO: - find all parts in the ship (hint: query for Parts on the ship (hearty))
+ TODO: - for each part, find all thrusters (hint: query for PartThrusters on the part)
+ TODO: - for each thruster, if it's on (check if it's in the player's current thrust soln)
+ TODO: - apply a force at the correct point
+ TODO: Much of the same logic is done in the client counterpart, to calculate effective
+ TODO: force for the solver. Take a look at client::ship::thrusters.
+ TODO: Note that relationship components (eg Parts, PartThrusters) wont exist if there are
+ TODO: no children - eg hearty won't have Parts if nothing is attached, a part won't have
+ TODO: PartThrusters if it has no thrusters.
+ TODO: Handle this with Option<&Component> in the query
+ */
+ }
+}<
\ No newline at end of file