~starkingdoms/starkingdoms

ref: 6f949473ea4886e5054dc2e360af440501a8a0b2 starkingdoms/crates/unified/src/server/player/thrust.rs -rw-r--r-- 3.1 KiB
6f949473 — core netcode: fix attachment(2) (i odiot) 4 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
71
72
73
74
75
76
77
78
79
80
81
//! # 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 bevy_replicon::prelude::{ClientId, FromClient};
use crate::client::components::Me;
use crate::shared::ecs::{Part, Temperature};
use crate::shared::ecs::thruster::{Thruster, ThrusterOfPart};
use crate::prelude::*;
use crate::server::ConnectedNetworkEntity;
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<FromClient<ThrustSolution>>,
    q_ls_me: Query<Entity, With<Me>>,
    clients: Query<&ConnectedNetworkEntity>,
    mut commands: Commands,
) {
    for thrust_solution in events.read() {
        let player_entity = match thrust_solution.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()
        };
        commands.entity(player_entity).insert(thrust_solution.message.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(),
            );
        }
    }
}