use bevy::{ecs::event::ManualEventReader, math::vec2, prelude::*}; use bevy_rapier2d::prelude::*; use client_login::packet_stream; use component::Player; use player_mouse_input::{attach_or_detach, mouse_picking}; use request_save::request_save; use send_message::send_message; use starkingdoms_common::{packet::Packet, PartType as c_PartType}; use crate::{ config::StkConfig, crafting::components::IsMining, err_or_cont, mathutil::rot2d, module::{ component::{Attach, CanAttach, LooseAttach, PartFlags, PartType}, PART_HALF_SIZE, }, part, planet::PlanetType, ws::{PacketMessageConvert, WsEvent}, AppKeys, CLIENT_SCALE }; pub mod client_login; pub mod component; pub mod packet; pub mod player_mouse_input; pub mod request_save; pub mod send_message; pub fn on_message( mut commands: Commands, planet_query: Query<(Entity, &PlanetType, &Transform)>, mut part_query: Query< ( Entity, &PartType, &mut Transform, &mut Velocity, Option<&LooseAttach>, &mut PartFlags, ), (Without, Without, Without), >, mut attached_query: Query< ( Entity, &PartType, &mut Transform, &mut Attach, &Velocity, Option<&CanAttach>, Option<&LooseAttach>, &mut PartFlags, ), (Without, Without), >, mut player_query: Query< ( Entity, &mut Player, &Transform, &Velocity, &mut Attach, &mut PartFlags, ), Without, >, mut mining_query: Query<&mut IsMining>, mut packet_recv: Local>, mut packet_event_send: ResMut>, app_keys: Res, server_config: Res, ) { let mut event_queue = Vec::new(); for ev in packet_recv.read(&packet_event_send) { if let WsEvent::Recv { from, message } = ev { let packet: Packet = err_or_cont!(Packet::from_message(message)); match packet { Packet::ClientLogin { username, save, jwt, } => { // auth if !client_login::join_auth( jwt, app_keys.clone(), from, &mut event_queue, server_config.clone(), ) { continue; } // create player in world let (id, transform, mut player_comp) = client_login::spawn_player(&mut commands, from, username.clone()); let index = id.index(); let mut attach = Attach { associated_player: None, parent: None, children: [None, None, None, None], }; // create ship from potential save client_login::load_save( &mut commands, transform, id, save, app_keys.clone(), &mut attached_query, &mut part_query, &mut player_query, &mut player_comp, &mut attach, from, &mut event_queue, ); // finish player entity let mut entity_id = commands.entity(id); entity_id.insert(player_comp); entity_id.insert(attach); // send packets that tell player initial world state packet_stream( &planet_query, &mut event_queue, from, &player_query, index, username, &part_query, &attached_query, transform, ); } Packet::SendMessage { target, content } => { // a player sent a message send_message(&player_query, from, &mut event_queue, target, content); } Packet::PlayerInput { up, down, left, right, } => { for (_, mut q_player, _, _, _, _) in &mut player_query { if q_player.addr == *from { q_player.input.up = up; q_player.input.down = down; q_player.input.left = left; q_player.input.right = right; } } } Packet::PlayerMouseInput { x, y, released, button, } => { let x = x / CLIENT_SCALE; let y = y / CLIENT_SCALE; for (entity, mut q_player, transform, _velocity, _attach, _) in &mut player_query { if q_player.addr == *from { if released { let select = if let Some(s) = q_player.selected { s } else { break; }; q_player.selected = None; // process if module was attach or detached attach_or_detach( select, &mut attached_query, &mut player_query, &mut part_query, &mut commands, x, y, entity, ); break; } // check if mouse touched a module mouse_picking( &attached_query, &part_query, (entity, transform), &mut mining_query, &mut q_player, x, y, &button, entity, &mut event_queue, ); } } } Packet::RequestSave { old_save } => { for (_, q_player, _, _, attach, _) in &mut player_query { if q_player.addr == *from { // HEY! GHOSTLY! PLEASE FILL THIS STRUCT WITH DATA! // THANKS! // mhm yeah done // client asked to save, generate save data and send it back request_save( &attached_query, old_save.clone(), app_keys.clone(), attach.clone(), &mut event_queue, from, ); } } } _ => continue, } } } for event in event_queue { packet_event_send.send(event); } } pub fn player_input_update( mut player_and_body_query: Query<( Entity, &mut Player, &Attach, &mut ExternalForce, &Transform, )>, mut attached_query: Query< (&Attach, &PartType, &mut ExternalForce, &Transform), Without, >, ) { for (_, mut player, attach, mut forces, transform) in &mut player_and_body_query { //forces.torque = 0.0; //forces.force = Vec2::ZERO; if !(player.input.up || player.input.down || player.input.right || player.input.left) { continue; } let mut fmul_bottom_left_thruster: f32 = 0.0; let mut fmul_bottom_right_thruster: f32 = 0.0; let mut fmul_top_left_thruster: f32 = 0.0; let mut fmul_top_right_thruster: f32 = 0.0; // figure out directions to use thrusters if player.input.up { fmul_bottom_left_thruster -= 1.0; fmul_bottom_right_thruster -= 1.0; } if player.input.down { fmul_top_left_thruster += 1.0; fmul_top_right_thruster += 1.0; } if player.input.left { fmul_top_left_thruster += 1.0; fmul_bottom_right_thruster -= 1.0; } if player.input.right { fmul_top_right_thruster += 1.0; fmul_bottom_left_thruster -= 1.0; } // normalize fmul_top_left_thruster = fmul_top_left_thruster.clamp(-1.0, 1.0); fmul_top_right_thruster = fmul_top_right_thruster.clamp(-1.0, 1.0); fmul_bottom_left_thruster = fmul_bottom_left_thruster.clamp(-1.0, 1.0); fmul_bottom_right_thruster = fmul_bottom_right_thruster.clamp(-1.0, 1.0); // increase power for up and down if player.input.up { fmul_bottom_left_thruster -= 2.0; fmul_bottom_right_thruster -= 2.0; } if player.input.down { fmul_top_left_thruster += 2.0; fmul_top_right_thruster += 2.0; } let rot = transform.rotation.to_euler(EulerRot::ZYX).0; // hearty thruster forces and respective positions let thrusters = [ (fmul_bottom_left_thruster, -PART_HALF_SIZE, -PART_HALF_SIZE), (fmul_bottom_right_thruster, PART_HALF_SIZE, -PART_HALF_SIZE), (fmul_top_left_thruster, -PART_HALF_SIZE, PART_HALF_SIZE), (fmul_top_right_thruster, PART_HALF_SIZE, PART_HALF_SIZE), ]; // process each thruster on hearty for (force_multiplier, x_offset, y_offset) in thrusters { if force_multiplier != 0.0 && player.energy >= part!(c_PartType::Hearty.into()).thruster_energy { player.energy -= part!(c_PartType::Hearty.into()).thruster_energy; let thruster_pos_uncast = vec2(x_offset, y_offset); let thruster_pos_cast = rot2d(thruster_pos_uncast, rot) + transform.translation.xy(); let thruster_force = force_multiplier * part!(c_PartType::Hearty.into()).thruster_force; let thruster_vec = vec2(-thruster_force * rot.sin(), thruster_force * rot.cos()); let thruster_force = ExternalForce::at_point( thruster_vec, thruster_pos_cast, transform.translation.xy(), ); forces.force += thruster_force.force; forces.torque += thruster_force.torque; } } // change to support other thruster types later // check if the player has enough energy to use thruster if player.energy >= part!(c_PartType::LandingThruster.into()).thruster_energy { // go through all thrusters and apply force crate::module::thruster::search_thrusters( player.input, attach.clone(), *transform, &mut player.energy, &mut attached_query, ); } } }