use crate::config::planet::Planet; use crate::ecs::{DragRequestEvent, Part, Player, PlayerStorage, PlayerThrust, ThrustEvent}; use crate::server::part::SpawnPartRequest; use crate::server::system_sets::PlayerInputSet; use crate::server::world_config::WorldConfigResource; use crate::server::{ConnectedGameEntity, ConnectedNetworkEntity}; use bevy::prelude::*; use bevy_rapier2d::prelude::ExternalForce; use bevy_replicon::prelude::FromClient; use std::f32::consts::PI; pub fn player_management_plugin(app: &mut App) { app.add_systems( Update, (handle_new_players, player_thrust, dragging).in_set(PlayerInputSet), ); } fn dragging( mut events: EventReader>, mut parts: Query<&mut Transform, With>, ) { for FromClient { event, .. } in events.read() { 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; } } fn handle_new_players( mut commands: Commands, q_new_clients: Query>, world_config: Res, planets: Query<(&Transform, &Planet)>, asset_server: Res, ) { let Some(wc) = &world_config.config else { return; }; for joined_player in &q_new_clients { trace!(?joined_player, "detected joined player!"); // find earth let (spawn_planet_pos, spawn_planet) = planets .iter() .find(|p| p.1.name == wc.hearty.spawn_at) .unwrap_or_else(|| { panic!( "spawn planet {} is missing? (check that the planet is named exactly '{}')", wc.hearty.spawn_at, wc.hearty.spawn_at ) }); let angle = rand::random::() * std::f32::consts::TAU; let offset = spawn_planet.radius + 150.0; let mut new_transform = Transform::from_xyz(angle.cos() * offset, angle.sin() * offset, 0.0); new_transform.rotate_z(angle); new_transform.translation += spawn_planet_pos.translation; info!(?new_transform, ?joined_player, "set player's position!"); commands .entity(joined_player) .insert(new_transform) .insert(SpawnPartRequest( asset_server.load("config/parts/hearty.part.toml"), )) .insert(PlayerThrust::default()) .insert(PlayerStorage { fuel_capacity: 25.0, fuel: 25.0, power_capacity: 25.0, power: 25.0, }) .insert(Player { client: joined_player, }); } } fn player_thrust( mut players: Query<(&Transform, &Part, &mut ExternalForce, &mut PlayerThrust, &mut PlayerStorage)>, clients: Query<&ConnectedNetworkEntity>, mut thrust_event: EventReader>, world_config: Res, ) { for FromClient { client_entity, event, } in thrust_event.read() { let ConnectedNetworkEntity { game_entity } = clients.get(*client_entity).unwrap(); let Ok((_, _, _, mut thrust, _)) = players.get_mut(*game_entity) else { continue; }; match *event { ThrustEvent::Up(on) => thrust.up = on, ThrustEvent::Down(on) => thrust.down = on, ThrustEvent::Left(on) => thrust.left = on, ThrustEvent::Right(on) => thrust.right = on, } } for (transform, part, mut force, thrust, mut storage) in &mut players { let Some(world_config) = &world_config.config else { return; }; let forward = (transform.rotation * Vec3::Y).xy(); let mut external_force = ExternalForce::default(); let mut thrusters = [0.0; 4]; // counterclockwise wrt +y axis if thrust.up { thrusters[1] = 1.0; thrusters[2] = 1.0; } if thrust.down { thrusters[0] = 1.0; thrusters[3] = 1.0; } if thrust.left { thrusters[0] = 1.0; thrusters[2] = 1.0; } if thrust.right { thrusters[1] = 1.0; thrusters[3] = 1.0; } let half_size = Vec2::new( world_config.part.default_width / 2.0, world_config.part.default_height / 2.0, ) .length(); external_force += ExternalForce::at_point( -forward * thrusters[0] * world_config.hearty.thrust, transform.translation.xy() + half_size * Vec2::new((1.0 * PI / 4.0).cos(), (1.0 * PI / 4.0).sin()).rotate(forward), transform.translation.xy(), ); external_force += ExternalForce::at_point( forward * thrusters[1] * world_config.hearty.thrust, transform.translation.xy() + half_size * Vec2::new((3.0 * PI / 4.0).cos(), (3.0 * PI / 4.0).sin()).rotate(forward), transform.translation.xy(), ); external_force += ExternalForce::at_point( forward * thrusters[2] * world_config.hearty.thrust, transform.translation.xy() + half_size * Vec2::new((5.0 * PI / 4.0).cos(), (5.0 * PI / 4.0).sin()).rotate(forward), transform.translation.xy(), ); external_force += ExternalForce::at_point( -forward * thrusters[3] * world_config.hearty.thrust, transform.translation.xy() + half_size * Vec2::new((7.0 * PI / 4.0).cos(), (7.0 * PI / 4.0).sin()).rotate(forward), transform.translation.xy(), ); *force += external_force; storage.fuel -= thrusters.iter().sum::() * part.strong_config.thruster.as_ref().unwrap().flow_rate; } }