~starkingdoms/starkingdoms

6de4db94b165e9d18c471cc99c28ff35753347e8 — core 23 days ago 3e5cd41
feat: document for tm
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