~starkingdoms/starkingdoms

ref: 11ed44a250017a0508927b34f18a597d1db1ed7d starkingdoms/crates/unified/src/server/player/thrust.rs -rw-r--r-- 2.7 KiB
11ed44a2ghostly_zsh feat: serverbound messages implemented but untested 9 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//! # Server thrust handling
//! The thrust solver runs on the client and sends a `ThrustSolution` message;
//! this file receives it and applies it to the physics simulation.

use crate::client::components::Me;
use crate::shared::ecs::{Part, Temperature};
use crate::shared::ecs::thruster::{Thruster, ThrusterOfPart};
use crate::prelude::*;
use crate::shared::attachment::Parts;
use crate::shared::thrust::ThrustSolution;

pub fn server_thrust_plugin(app: &mut App) {
    app
        .add_systems(Update, process_thrust_events)
        .add_systems(FixedUpdate, apply_thrust_solutions);
}

fn process_thrust_events(
    mut events: MessageReader<ThrustSolution>,
    me_entity: Query<Entity, With<Me>>,
    mut commands: Commands,
) {
    for thrust_solution in events.read() {
        let Ok(player_entity) = me_entity.single() else { return };
        commands.entity(player_entity).insert(thrust_solution.clone());
    }
}

/// Find all players, and apply their current `ThrustSolution`s
fn apply_thrust_solutions(
    players: Query<(Entity, &ThrustSolution, Option<&Parts>)>,
    thrusters: Query<(&Thruster, &ThrusterOfPart, &GlobalTransform)>,
    mut parts: Query<(Forces, &mut Temperature), With<Part>>,
    time: Res<Time>,
) {
    for (player_entity, thrust_solution, maybe_parts) in players {
        if !thrust_solution.converged {
            debug!(?player_entity, "ignoring unconverged thrust solution");
        }
        if thrust_solution.thrusters_on.is_empty() { continue }

        let attached_parts = if let Some(parts) = maybe_parts {
            parts.as_slice()
        } else {
            &[]
        };

        for thruster_entity in &thrust_solution.thrusters_on {
            let Ok((thruster_info, parent_part, thruster_transform)) = thrusters.get(*thruster_entity) else {
                debug!(?thruster_entity, "couldn't find thruster to apply force");
                continue
            };

            let parent_is_hearty = parent_part.0 == player_entity;
            let parent_is_in_ship = attached_parts.contains(&parent_part.0);
            if !(parent_is_hearty || parent_is_in_ship) {
                debug!(?thruster_entity, "ignoring disallowed thruster action");
                continue
            }

            let (mut part_forces, mut temperature) = parts.get_mut(parent_part.0).unwrap();
            temperature.0 += thruster_info.heat_constant * (thruster_info.exhaust_temperature - temperature.0) * time.delta_secs() as f64;

            part_forces.apply_force_at_point(
                (thruster_transform.rotation() * thruster_info.thrust_vector.extend(0.0)).xy().into(),
                thruster_transform.translation().xy().into(),
            );
        }
    }
}