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<PlanetType>, Without<Player>, Without<Attach>),
>,
mut attached_query: Query<
(
Entity,
&PartType,
&mut Transform,
&mut Attach,
&Velocity,
Option<&CanAttach>,
Option<&LooseAttach>,
&mut PartFlags,
),
(Without<PlanetType>, Without<Player>),
>,
mut player_query: Query<
(
Entity,
&mut Player,
&Transform,
&Velocity,
&mut Attach,
&mut PartFlags,
),
Without<PlanetType>,
>,
mut mining_query: Query<&mut IsMining>,
mut packet_recv: Local<ManualEventReader<WsEvent>>,
mut packet_event_send: ResMut<Events<WsEvent>>,
app_keys: Res<AppKeys>,
server_config: Res<StkConfig>,
) {
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<Player>,
>,
) {
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,
);
}
}
}