From f09a962cd10ee3b70177bd86c7c8a88f662c49f5 Mon Sep 17 00:00:00 2001 From: ghostlyzsh Date: Tue, 30 Jul 2024 18:11:20 -0500 Subject: [PATCH] comments? and formal grammar for kabel --- Cargo.toml | 2 +- kabel/Cargo.toml | 6 + kabel/grammar.ebnf | 35 ++ kabel/src/main.rs | 3 + server/src/main.rs | 65 +--- server/src/module/component.rs | 26 +- server/src/module/mod.rs | 144 ++------ server/src/module/save.rs | 17 +- server/src/module/thruster.rs | 6 +- server/src/planet.rs | 38 +- server/src/player/client_login.rs | 301 +++++++++++++++ server/src/player/component.rs | 1 - server/src/player/mod.rs | 468 +++--------------------- server/src/player/packet.rs | 8 +- server/src/player/player_mouse_input.rs | 138 +++++++ server/src/player/request_save.rs | 49 +++ server/src/player/send_message.rs | 61 +++ 17 files changed, 771 insertions(+), 597 deletions(-) create mode 100644 kabel/Cargo.toml create mode 100644 kabel/grammar.ebnf create mode 100644 kabel/src/main.rs create mode 100644 server/src/player/client_login.rs create mode 100644 server/src/player/player_mouse_input.rs create mode 100644 server/src/player/request_save.rs create mode 100644 server/src/player/send_message.rs diff --git a/Cargo.toml b/Cargo.toml index f0502b585fe548779e6b55d9611275c27c4035f4..15ae45c05eb4e5cbd731abd65222eac4bbc144a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ members = [ "starkingdoms-backplane", "starkingdoms-common", "savefile_decoder" -, "starkingdoms-api"] +, "starkingdoms-api", "kabel"] resolver = "2" [profile.dev.package."*"] diff --git a/kabel/Cargo.toml b/kabel/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..5c5441262463aab31b0a789ff1508b08895cbc9d --- /dev/null +++ b/kabel/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "kabel" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/kabel/grammar.ebnf b/kabel/grammar.ebnf new file mode 100644 index 0000000000000000000000000000000000000000..4da81ebb155aacd0544c5b952bb644baeb87061b --- /dev/null +++ b/kabel/grammar.ebnf @@ -0,0 +1,35 @@ +program = { statement } ; + +statement = if | while | ( expression , ";" ) ; + +while = "while" , expression , block ; + +if = "if" , expression , block ; + +block = "{" , { statement } , "}" ; + +expression = assignment | declaration ; + +declaration = "var" , identifier , "=" , expression ; + +assignment = { identifier , "=" , } logical_and ; + +logical_and = logical_or { , "||" , logical_or } ; + +logical_or = equality { , "&&" , equality } ; + +equality = comparison { , ( "==" | "!=" ) , comparison } ; + +comparison = term { , ( ">" | "<" | ">=" | "<=" ) , term } ; + +term = factor { , ( "+" | "-" ) , factor } ; + +factor = primary { , ( "*" | "/" ) , primary } ; + +primary = identifier | number | string | group ; + +group = "(" , expression , ")" ; + +identifier = alphabetic , { alphabetic | digit } ; +string = ( '"' | "'" ) , { character - ( '"' | "'" ) } , ( '"' | "'" ) ; +number = digit , { digit } , [ "." , digit , { digit } ] ; diff --git a/kabel/src/main.rs b/kabel/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..e7a11a969c037e00a796aafeff6258501ec15e9a --- /dev/null +++ b/kabel/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/server/src/main.rs b/server/src/main.rs index b2b9a684539fd0c5439c3c23f55de194dd994161..4f9480a5a810a3908fe6e0a9a7e10468927f4900 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -48,7 +48,7 @@ pub mod ws; struct StkPluginGroup; -#[derive(Resource)] +#[derive(Resource, Clone)] pub struct AppKeys { pub app_key: Vec, } @@ -150,19 +150,21 @@ fn main() { server_config.world.pixels_per_meter, )) .add_plugins(StkTungsteniteServerPlugin) - .add_systems(Startup, setup_integration_parameters) - .add_systems(Startup, planet::spawn_planets) - .add_systems(FixedUpdate, module::module_spawn) - .add_systems(Update, player::on_message) - .add_systems(Update, player::packet::on_close) - .add_systems(FixedUpdate, player::packet::send_player_energy) - .add_systems(FixedUpdate, player::packet::on_position_change) + .add_systems(Startup, (setup_integration_parameters, planet::spawn_planets)) + .add_systems(Update, (player::on_message, player::packet::on_close)) + .add_systems(FixedUpdate, + (module::module_spawn, player::packet::send_player_energy, + player::packet::on_position_change, module::save::save_eligibility, + module::convert_modules)) .add_systems( FixedUpdate, - (module::break_modules, gravity_update, player::player_input_update).chain(), + ( + module::break_modules, + planet::gravity_update, + player::player_input_update, + ) + .chain(), ) - .add_systems(FixedUpdate, module::save::save_eligibility) - .add_systems(FixedUpdate, module::convert_modules) .insert_resource(Time::::from_seconds( server_config.server.world_fixed_timestep, )) @@ -172,6 +174,7 @@ fn main() { info!("Goodbye!"); } +// set settings in physics engine fn setup_integration_parameters(mut context: ResMut, server_config: Res) { context.integration_parameters = server_config.physics.parameters; @@ -188,43 +191,3 @@ fn setup_integration_parameters(mut context: ResMut, server_confi } } } - -fn gravity_update( - mut part_query: Query< - ( - &Transform, - &ReadMassProperties, - &mut ExternalForce, - &mut ExternalImpulse, - ), - With, - >, - planet_query: Query<(&Transform, &ReadMassProperties), With>, - server_config: Res, -) { - for (part_transform, part_mp, mut forces, mut impulses) in &mut part_query { - impulses.impulse = Vec2::ZERO; - forces.force = Vec2::ZERO; - forces.torque = 0.; - let part_mp = part_mp.get(); - let part_mass = part_mp.mass; - let part_translate = part_transform.translation; - for (planet_transform, planet_mp) in &planet_query { - let planet_mp = planet_mp.get(); - let planet_mass = planet_mp.mass; - let planet_translate = planet_transform.translation; - let distance = planet_translate.distance(part_translate); - let force = - server_config.world.gravity * ((part_mass * planet_mass) / (distance * distance)); - let direction = (planet_translate - part_translate).normalize() * force; - /*let gravity_force = ExternalForce::at_point( - direction.xy(), - part_transform.translation.xy(), - part_transform.translation.xy(), - ); - forces.force += gravity_force.force; - forces.torque += gravity_force.torque;*/ - impulses.impulse += direction.xy(); - } - } -} diff --git a/server/src/module/component.rs b/server/src/module/component.rs index 065ba3199670f70fb5b31f7c24d13dd63e7504e4..ab9f20a2482d9b8a116d683e48e9d327455c9ab5 100644 --- a/server/src/module/component.rs +++ b/server/src/module/component.rs @@ -1,9 +1,11 @@ use bevy::prelude::*; +use bevy_rapier2d::prelude::{ExternalForce, ExternalImpulse, ReadMassProperties, RigidBody, Velocity}; use serde::{Deserialize, Serialize}; use starkingdoms_common::PartType as c_PartType; -#[derive(Component, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)] +#[derive(Component, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Debug, Default)] pub enum PartType { + #[default] Placeholder, Hearty, Cargo, @@ -51,7 +53,7 @@ pub struct LooseAttach { #[derive(Component, Clone, Copy, PartialEq, Debug)] pub struct CanAttach(pub u8); // each bit means a slot able to attach to -#[derive(Component, Copy, Clone)] +#[derive(Component, Copy, Clone, Default)] pub struct PartFlags { pub attached: bool, } @@ -61,6 +63,26 @@ pub struct PartBundle { pub transform: TransformBundle, pub part_type: PartType, pub flags: PartFlags, + pub velocity: Velocity, + pub force: ExternalForce, + pub impulse: ExternalImpulse, + pub rigidbody: RigidBody, + pub read_mass_properties: ReadMassProperties, +} + +impl Default for PartBundle { + fn default() -> Self { + Self { + transform: TransformBundle::default(), + part_type: PartType::default(), + flags: PartFlags::default(), + velocity: Velocity::default(), + force: ExternalForce::default(), + impulse: ExternalImpulse::default(), + rigidbody: RigidBody::Dynamic, + read_mass_properties: ReadMassProperties::default(), + } + } } #[derive(Resource)] diff --git a/server/src/module/mod.rs b/server/src/module/mod.rs index 3fb67fc4aa46abdd55c09fea044dd05aa96906ff..87c94201bfae8efe33cfea0d27c6ffef28a64955 100644 --- a/server/src/module/mod.rs +++ b/server/src/module/mod.rs @@ -6,7 +6,8 @@ use component::*; use rand::Rng; use crate::{ - capacity, config::StkConfig, part, planet::PlanetType, player::component::Player, proto_part_flags, proto_transform, ws::WsEvent, Packet, Part + capacity, config::StkConfig, part, planet::PlanetType, player::component::Player, + proto_part_flags, proto_transform, ws::WsEvent, Packet, Part, }; pub mod component; @@ -38,9 +39,9 @@ pub fn module_spawn( part_type: PartType::Cargo, transform: TransformBundle::from(transform), flags, + ..default() }); entity - .insert(RigidBody::Dynamic) .with_children(|children| { children .spawn(Collider::cuboid(0.375, 0.46875)) @@ -50,11 +51,7 @@ pub fn module_spawn( local_center_of_mass: vec2(0.0, 0.0), mass: part!(PartType::Cargo).mass, principal_inertia: 7.5, - })) - .insert(ExternalForce::default()) - .insert(ExternalImpulse::default()) - .insert(Velocity::default()) - .insert(ReadMassProperties::default()); + })); let packet = Packet::SpawnPart { id: entity.id().index(), @@ -74,28 +71,12 @@ pub fn module_spawn( pub fn detach_recursive( commands: &mut Commands, this: Entity, - attached_query: &mut Query< - ( - Entity, - &PartType, - &mut Transform, - &mut Attach, - &Velocity, - Option<&CanAttach>, - Option<&LooseAttach>, - &mut PartFlags, - ), + attached_query: &mut Query<(Entity, &PartType, &mut Transform, &mut Attach, + &Velocity, Option<&CanAttach>, Option<&LooseAttach>, &mut PartFlags), (Without, Without), >, - player_query: &mut Query< - ( - Entity, - &mut Player, - &Transform, - &Velocity, - &mut Attach, - &mut PartFlags, - ), + player_query: &mut Query<(Entity, &mut Player, &Transform, &Velocity, + &mut Attach, &mut PartFlags), Without, >, ) -> u32 { @@ -182,45 +163,22 @@ pub fn despawn_module_tree( } pub fn attach_on_module_tree( - x: f32, - y: f32, + x: f32, y: f32, commands: &mut Commands, this: Entity, select: Entity, player_id: Entity, - attached_query: &mut Query< - ( - Entity, - &PartType, - &mut Transform, - &mut Attach, - &Velocity, - Option<&CanAttach>, - Option<&LooseAttach>, - &mut PartFlags, - ), + attached_query: &mut Query<(Entity, &PartType, &mut Transform, &mut Attach, + &Velocity, Option<&CanAttach>, Option<&LooseAttach>, + &mut PartFlags), (Without, Without), >, - part_query: &mut Query< - ( - Entity, - &PartType, - &mut Transform, - &mut Velocity, - Option<&LooseAttach>, - &mut PartFlags, - ), + part_query: &mut Query<(Entity, &PartType, &mut Transform, &mut Velocity, + Option<&LooseAttach>, &mut PartFlags), (Without, Without, Without), >, - player_query: &mut Query< - ( - Entity, - &mut Player, - &Transform, - &Velocity, - &mut Attach, - &mut PartFlags, - ), + player_query: &mut Query<(Entity, &mut Player, &Transform, &Velocity, + &mut Attach, &mut PartFlags), Without, >, ) -> bool { @@ -236,15 +194,8 @@ pub fn attach_on_module_tree( let part_type = *module.1; ret |= if part_type != PartType::LandingThrusterSuspension { attach_on_module_tree( - x, - y, - commands, - *this, - select, - player_id, - attached_query, - part_query, - player_query, + x, y, commands, *this, select, player_id, attached_query, + part_query, player_query, ) } else { false @@ -373,16 +324,9 @@ pub fn convert_modules( rapier_context: Res, planet_query: Query<(Entity, &PlanetType, &Children)>, mut player_query: Query<(&Attach, &mut Player)>, - mut attached_query: Query< - ( - Entity, - &mut PartType, - &mut Attach, - &mut AdditionalMassProperties, - &Children, - &Transform, - &PartFlags, - ), + mut attached_query: Query<(Entity, &mut PartType, &mut Attach, + &mut AdditionalMassProperties, &Children, &Transform, + &PartFlags), Without, >, mut collider_query: Query< @@ -445,16 +389,8 @@ fn convert_modules_recursive( commands: &mut Commands, planet_type: PlanetType, attach: Attach, - attached_query: &mut Query< - ( - Entity, - &mut PartType, - &mut Attach, - &mut AdditionalMassProperties, - &Children, - &Transform, - &PartFlags, - ), + attached_query: &mut Query<(Entity, &mut PartType, &mut Attach, + &mut AdditionalMassProperties, &Children, &Transform, &PartFlags), Without, >, collider_query: &mut Query< @@ -539,23 +475,19 @@ fn convert_modules_recursive( transform: TransformBundle::from(*module_transform), part_type: PartType::LandingThrusterSuspension, flags: PartFlags { attached: false }, + ..default() }); suspension - .insert(RigidBody::Dynamic) .with_children(|children| { children .spawn(Collider::cuboid(0.5, 0.02)) .insert(TransformBundle::from(Transform::from_xyz(0., -0.48, 0.))); }) .insert(ImpulseJoint::new(module_entity, joint)) - .insert(ExternalForce::default()) - .insert(ExternalImpulse::default()) - .insert(Velocity::default()) - .insert(ReadMassProperties::default()) .insert(AdditionalMassProperties::MassProperties(MassProperties { local_center_of_mass: vec2(0.0, 0.0), - mass: 0.00000000000001, - principal_inertia: 0.0000000000001, + mass: 0.00000000000001, + principal_inertia: 0.00000000000001, })) .insert(Attach { associated_player: attach.associated_player, @@ -618,28 +550,12 @@ fn convert_modules_recursive( pub fn break_modules( mut commands: Commands, rapier_context: Res, - mut attached_query: Query< - ( - Entity, - &PartType, - &mut Transform, - &mut Attach, - &Velocity, - Option<&CanAttach>, - Option<&LooseAttach>, - &mut PartFlags, - ), + 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, - ), + mut player_query: Query<(Entity, &mut Player, &Transform, &Velocity, + &mut Attach, &mut PartFlags), Without, >, ) { diff --git a/server/src/module/save.rs b/server/src/module/save.rs index 5406dc0b92b618a8654e37286d5758520d671584..12bebc98e32abd74e9b2a7fd412f8781b5fddd68 100644 --- a/server/src/module/save.rs +++ b/server/src/module/save.rs @@ -5,7 +5,8 @@ use bevy_rapier2d::prelude::*; use starkingdoms_common::SaveModule; use crate::{ - capacity, mass, planet::PlanetType, player::component::Player, ws::WsEvent, Attach, CanAttach, LooseAttach, Packet, PartBundle, PartFlags, PartType + capacity, mass, planet::PlanetType, player::component::Player, ws::WsEvent, Attach, CanAttach, + LooseAttach, Packet, PartBundle, PartFlags, PartType, }; pub fn load_savefile( @@ -95,6 +96,7 @@ pub fn load_savefile( transform: TransformBundle::from(transform), part_type: child.part_type.into(), flags: PartFlags { attached: true }, + ..default() }); module.id() }; @@ -126,7 +128,6 @@ pub fn load_savefile( ret[i] = Some(module.id()); module - .insert(RigidBody::Dynamic) .with_children(|children| { children .spawn(if part_type == PartType::Cargo { @@ -156,11 +157,7 @@ pub fn load_savefile( local_center_of_mass: vec2(0.0, 0.0), mass: mass!(part_type), principal_inertia: 7.5, - })) - .insert(ExternalForce::default()) - .insert(ExternalImpulse::default()) - .insert(Velocity::default()) - .insert(ReadMassProperties::default()); + })); if part_type == PartType::Hub { module.insert(CanAttach(15)); } @@ -192,19 +189,15 @@ pub fn load_savefile( ), part_type: PartType::LandingThrusterSuspension, flags: PartFlags { attached: true }, + ..default() }); suspension - .insert(RigidBody::Dynamic) .with_children(|children| { children .spawn(Collider::cuboid(0.5, 0.02)) .insert(TransformBundle::from(Transform::from_xyz(0., -0.48, 0.))); }) .insert(ImpulseJoint::new(module_id, joint)) - .insert(ExternalForce::default()) - .insert(ExternalImpulse::default()) - .insert(Velocity::default()) - .insert(ReadMassProperties::default()) .insert(AdditionalMassProperties::MassProperties(MassProperties { local_center_of_mass: vec2(0.0, 0.0), mass: 0.00000000000001, diff --git a/server/src/module/thruster.rs b/server/src/module/thruster.rs index c4cbf997b3dc7b85d5078160ccc0af07fc3a6f92..b8cb4b6af3b10fb2c475e4c5da82bbd7885f9f49 100644 --- a/server/src/module/thruster.rs +++ b/server/src/module/thruster.rs @@ -1,6 +1,10 @@ use std::f32::consts::PI; -use crate::{part, player::component::{Input, Player}, Attach, PartType}; +use crate::{ + part, + player::component::{Input, Player}, + Attach, PartType, +}; use bevy::prelude::*; use bevy_rapier2d::prelude::*; diff --git a/server/src/planet.rs b/server/src/planet.rs index 40f1442b09ab011f086b9320decae4260b55e321..1f84243fb0f1a084f599f2272ec993662cd9775b 100644 --- a/server/src/planet.rs +++ b/server/src/planet.rs @@ -2,7 +2,7 @@ use bevy::prelude::*; use bevy_rapier2d::prelude::*; use serde::{Deserialize, Serialize}; -use crate::planet; +use crate::{config::StkConfig, module::component::PartType, planet}; #[derive(Component, Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)] pub enum PlanetType { @@ -74,3 +74,39 @@ pub fn spawn_planets(mut commands: Commands) { }) .insert(RigidBody::Fixed); } + +pub fn gravity_update( + mut part_query: Query< + ( + &Transform, + &ReadMassProperties, + &mut ExternalForce, + &mut ExternalImpulse, + ), + With, + >, + planet_query: Query<(&Transform, &ReadMassProperties), With>, + server_config: Res, +) { + for (part_transform, part_mp, mut forces, mut impulses) in &mut part_query { + impulses.impulse = Vec2::ZERO; + forces.force = Vec2::ZERO; + forces.torque = 0.; + let part_mp = part_mp.get(); + let part_mass = part_mp.mass; + let part_translate = part_transform.translation; + for (planet_transform, planet_mp) in &planet_query { + let planet_mp = planet_mp.get(); + let planet_mass = planet_mp.mass; + let planet_translate = planet_transform.translation; + let distance = planet_translate.distance(part_translate); + // gravity equation + let force = + server_config.world.gravity * ((part_mass * planet_mass) / (distance * distance)); + // gravity vector + let direction = (planet_translate - part_translate).normalize() * force; + // apply gravity vector as impulse to body + impulses.impulse += direction.xy(); + } + } +} diff --git a/server/src/player/client_login.rs b/server/src/player/client_login.rs new file mode 100644 index 0000000000000000000000000000000000000000..54a0dfe38ddf8502a272136546f58b67b6e80e22 --- /dev/null +++ b/server/src/player/client_login.rs @@ -0,0 +1,301 @@ +use std::net::SocketAddr; + +use bevy::{math::vec2, prelude::*}; +use bevy_rapier2d::prelude::*; +use hmac::{Hmac, Mac}; +use jwt::VerifyWithKey; +use rand::Rng; +use sha2::Sha256; +use starkingdoms_common::unpack_savefile; + +use crate::{config::StkConfig, module::{component::{Attach, CanAttach, LooseAttach, PartBundle, PartFlags, PartType}, save::load_savefile}, planet::PlanetType, proto_part_flags, proto_transform, ws::WsEvent, AppKeys, MessageType, Packet, Part, Planet, ProtoPartFlags, UserToken, CLIENT_SCALE}; + +use super::component::{Input, Player}; + +pub fn join_auth( + jwt: Option, app_keys: AppKeys, from: &SocketAddr, + event_queue: &mut Vec, server_config: StkConfig, +) -> Result<(), ()> { + if let Some(token) = jwt { + let key: Hmac = Hmac::new_from_slice(&app_keys.app_key).unwrap(); + let claims: UserToken = match token.verify_with_key(&key) { + Ok(c) => c, + Err(e) => { + event_queue.push(WsEvent::Send { + to: *from, + message: Packet::Message { message_type: MessageType::Error, actor: "SERVER".to_string(), content: format!("Token is invalid or verification failed: {e}. Please log in again, or contact StarKingdoms staff if the problem persists.") }.into(), + }); + event_queue.push(WsEvent::Close { addr: *from }); + return Err(()); + } + }; + + if claims.permission_level + < server_config.security.required_permission_level + { + event_queue.push(WsEvent::Send { + to: *from, + message: Packet::Message { message_type: MessageType::Error, actor: "SERVER".to_string(), content: format!("Permission level {} is too low, {} is required. If your permissions were just changed, you need to log out and log back in for the change to take effect. If you believe this is a mistake, contact StarKingdoms staff.", claims.permission_level, server_config.security.required_permission_level) }.into(), + }); + event_queue.push(WsEvent::Close { addr: *from }); + return Err(()); + } + + event_queue.push(WsEvent::Send { + to: *from, + message: Packet::Message { message_type: MessageType::Server, actor: "StarKingdoms Team".to_string(), content: "Thank you for participating in the StarKingdoms private alpha! Your feedback is essential to improving the game, so please give us any feedback you have in the Discord! <3".to_string() }.into(), + }); + } else if server_config.security.required_permission_level != 0 { + event_queue.push(WsEvent::Send { + to: *from, + message: Packet::Message { message_type: MessageType::Error, actor: "SERVER".to_string(), content: "Authentication is required to join this server at the moment. Log in and try again, or try again later.".to_string() }.into(), + }); + event_queue.push(WsEvent::Close { addr: *from }); + return Err(()); + } + Ok(()) +} + +pub fn spawn_player( + commands: &mut Commands, from: &SocketAddr, username: String, +) -> (Entity, Transform, Player) { + // generate random angle + let angle: f32 = { + let mut rng = rand::thread_rng(); + rng.gen::() * std::f32::consts::PI * 2. + }; + // convert to cartesian with 30.0 meter radius + let mut transform = + Transform::from_xyz(angle.cos() * 30.0, angle.sin() * 30.0, 0.0); + transform.rotate_z(angle); + let player_comp = Player { + addr: *from, + username, + input: Input::default(), + selected: None, + save_eligibility: false, + energy_capacity: part!(PartType::Hearty).energy_capacity, + energy: part!(PartType::Hearty).energy_capacity, + }; + let mut entity_id = commands.spawn(PartBundle { + part_type: PartType::Hearty, + transform: TransformBundle::from(transform), + flags: PartFlags { attached: false }, + ..default() + }); + entity_id + .insert(Collider::cuboid(0.5, 0.5)) + .insert(AdditionalMassProperties::MassProperties(MassProperties { + local_center_of_mass: vec2(0.0, 0.0), + mass: part!(PartType::Hearty).mass, + principal_inertia: 7.5, + })); + (entity_id.id(), transform, player_comp) +} + +pub fn load_save( + commands: &mut Commands, transform: Transform, id: Entity, + save: Option, app_keys: AppKeys, + attached_query: &mut Query<(Entity, &PartType, &mut Transform, &mut Attach, + &Velocity, Option<&CanAttach>, Option<&LooseAttach>, &mut PartFlags), + (Without, Without), + >, + part_query: &mut Query<(Entity, &PartType, &mut Transform, &mut Velocity, + Option<&LooseAttach>, &mut PartFlags), + (Without, Without, Without), + >, + player_query: &mut Query<(Entity, &mut Player, &Transform, &Velocity, + &mut Attach, &mut PartFlags), + Without, + >, + player_comp: &mut Player, attach: &mut Attach, from: &SocketAddr, + event_queue: &mut Vec, +) { + if let Some(save) = save { + // attempt to decode the savefile + if let Ok(savefile) = unpack_savefile(&app_keys.app_key, save) { + // HEY! GHOSTLY! THIS SAVE FILE IS VALID! PLEASE LOAD IT! + // THANKS! + + let children = load_savefile( + commands, + transform, + id, + id, + savefile.children, + attached_query, + part_query, + player_query, + player_comp, + ); + // update energy and children + player_comp.energy = player_comp.energy_capacity; + attach.children = children; + } else { + let packet = Packet::Message { + message_type: crate::packet::MessageType::Error, + actor: "SERVER".to_string(), + content: "Savefile signature corrupted or inner data invalid. Save was not loaded. Contact StarKingdoms staff for assistance.".to_string(), + }; + event_queue.push(WsEvent::Send { + to: *from, + message: packet.into(), + }); + } + } else { + // nothing to do + } +} + +pub fn packet_stream( + planet_query: &Query<(Entity, &PlanetType, &Transform)>, + event_queue: &mut Vec, from: &SocketAddr, + player_query: &Query<(Entity, &mut Player, &Transform, &Velocity, + &mut Attach, &mut PartFlags), + Without, + >, + index: u32, username: String, + part_query: &Query<(Entity, &PartType, &mut Transform, &mut Velocity, + Option<&LooseAttach>, &mut PartFlags), + (Without, Without, Without), + >, + attached_query: &Query<(Entity, &PartType, &mut Transform, &mut Attach, + &Velocity, Option<&CanAttach>, Option<&LooseAttach>, &mut PartFlags), + (Without, Without), + >, + transform: Transform, +) { + // tell this player the planets + let mut planets = Vec::new(); + for (entity, planet_type, transform) in planet_query.iter() { + let translation = transform.translation; + planets.push(( + entity.index(), + Planet { + planet_type: *planet_type, + transform: proto_transform!(Transform::from_translation( + translation * CLIENT_SCALE + )), + radius: match *planet_type { + PlanetType::Earth => { + planet!(PlanetType::Earth).size * CLIENT_SCALE + } + PlanetType::Moon => { + planet!(PlanetType::Moon).size * CLIENT_SCALE + } + PlanetType::Mars => { + planet!(PlanetType::Mars).size * CLIENT_SCALE + } + }, + }, + )); + } + let packet = Packet::PlanetPositions { planets }; + event_queue.push(WsEvent::Send { + to: *from, + message: packet.into(), + }); + + // tell the player already existing users + let mut players = Vec::new(); + for (entity, player, _, _, _, _) in player_query.iter() { + players.push((entity.index(), player.username.clone())); + } + let packet = Packet::PlayerList { players }; + event_queue.push(WsEvent::Send { + to: *from, + message: packet.into(), + }); + + // tell other players that a player has spawned in + let packet = Packet::SpawnPlayer { + id: index, + username: username.to_string(), + }; + event_queue.push(WsEvent::Broadcast { + message: packet.into(), + }); + let packet = Packet::Message { + message_type: crate::packet::MessageType::Server, + actor: "SERVER".to_string(), + content: format!("{} has joined the server!", username), + }; + event_queue.push(WsEvent::Broadcast { + message: packet.into(), + }); + + // tell the player where parts are + let mut parts = Vec::new(); + for (entity, part_type, transform, _, _, flags) in part_query.iter() { + parts.push(( + entity.index(), + Part { + part_type: *part_type, + transform: proto_transform!(Transform::from_translation( + transform.translation * CLIENT_SCALE + )), + flags: proto_part_flags!(flags), + }, + )); + } + for (entity, part_type, transform, _, _, _, _, flags) in attached_query.iter() { + parts.push(( + entity.index(), + Part { + part_type: *part_type, + transform: proto_transform!(Transform::from_translation( + transform.translation * CLIENT_SCALE + )), + flags: proto_part_flags!(flags), + }, + )); + } + parts.push(( + index, + Part { + part_type: PartType::Hearty, + transform: proto_transform!(Transform::from_translation( + transform.translation + ) + .with_rotation(transform.rotation)), + flags: ProtoPartFlags { attached: false }, + }, + )); + let packet = Packet::PartPositions { parts }; + event_queue.push(WsEvent::Send { + to: *from, + message: packet.into(), + }); + + // and send the welcome message :) + let packet = Packet::Message { + message_type: crate::packet::MessageType::Server, + actor: "SERVER".to_string(), + content: format!( + "starkingdoms-server v{} says hello", + env!("CARGO_PKG_VERSION") + ), + }; + event_queue.push(WsEvent::Send { + to: *from, + message: packet.into(), + }); + let packet = Packet::Message { + message_type: crate::packet::MessageType::Server, + actor: "SERVER".to_string(), + content: "Welcome to StarKingdoms.IO! Have fun!".to_string(), + }; + event_queue.push(WsEvent::Send { + to: *from, + message: packet.into(), + }); + let packet = Packet::Message { + message_type: crate::packet::MessageType::Server, + actor: "SERVER".to_string(), + content: "Found a bug? Have a feature request? Please bring this and all other feedback to the game's official Discord server! Join here: https://discord.gg/3u7Yw8DWtQ".to_string(), + }; + event_queue.push(WsEvent::Send { + to: *from, + message: packet.into(), + }); +} diff --git a/server/src/player/component.rs b/server/src/player/component.rs index 9fcf0cc7064d2e39de1277d1262d72289d0febfa..3fa60de11b0e85455d0636a4a7527fd28ba5a48a 100644 --- a/server/src/player/component.rs +++ b/server/src/player/component.rs @@ -5,7 +5,6 @@ use serde::{Deserialize, Serialize}; use crate::module::component::{Attach, PartBundle}; - #[derive(Component, Clone, Copy, Serialize, Deserialize, Debug, Default)] pub struct Input { pub up: bool, diff --git a/server/src/player/mod.rs b/server/src/player/mod.rs index 86dffb2230bceac8bc4b116329b12b37a5265fc9..245ef16072f0021c7edbe17c4cdce158f4caaf10 100644 --- a/server/src/player/mod.rs +++ b/server/src/player/mod.rs @@ -1,20 +1,28 @@ -use bevy::{ecs::event::ManualEventReader, math::{vec2, vec3}, prelude::*}; +use bevy::{ + ecs::event::ManualEventReader, + math::vec2, + prelude::*, +}; use bevy_rapier2d::prelude::*; +use client_login::packet_stream; use component::Player; -use hmac::{Hmac, Mac}; -use rand::Rng; -use sha2::Sha256; -use starkingdoms_common::{pack_savefile, unpack_savefile, SaveData}; -use jwt::VerifyWithKey; +use player_mouse_input::{attach_or_detach, mouse_picking}; +use request_save::request_save; +use send_message::send_message; -use crate::{config::StkConfig, err_or_cont, mathutil::rot2d, - module::{component::{Attach, CanAttach, LooseAttach, PartBundle, PartFlags, PartType}, save::load_savefile, PART_HALF_SIZE}, - part, planet::PlanetType, - proto_part_flags, proto_transform, ws::WsEvent, AppKeys, MessageType, - Packet, Part, Planet, ProtoPartFlags, UserToken, CLIENT_SCALE}; +use crate::{ + config::StkConfig, err_or_cont, mathutil::rot2d, module::{ + component::{Attach, CanAttach, LooseAttach, PartFlags, PartType}, + PART_HALF_SIZE, + }, part, planet::PlanetType, ws::WsEvent, AppKeys, Packet, CLIENT_SCALE +}; pub mod component; pub mod packet; +pub mod client_login; +pub mod send_message; +pub mod player_mouse_input; +pub mod request_save; pub fn on_message( mut commands: Commands, @@ -71,301 +79,38 @@ pub fn on_message( jwt, } => { // auth - // plz no remove - if let Some(token) = jwt { - let key: Hmac = Hmac::new_from_slice(&app_keys.app_key).unwrap(); - let claims: UserToken = match token.verify_with_key(&key) { - Ok(c) => c, - Err(e) => { - event_queue.push(WsEvent::Send { - to: *from, - message: Packet::Message { message_type: MessageType::Error, actor: "SERVER".to_string(), content: format!("Token is invalid or verification failed: {e}. Please log in again, or contact StarKingdoms staff if the problem persists.") }.into(), - }); - event_queue.push(WsEvent::Close { addr: *from }); - continue; - } - }; - - if claims.permission_level - < server_config.security.required_permission_level - { - event_queue.push(WsEvent::Send { - to: *from, - message: Packet::Message { message_type: MessageType::Error, actor: "SERVER".to_string(), content: format!("Permission level {} is too low, {} is required. If your permissions were just changed, you need to log out and log back in for the change to take effect. If you believe this is a mistake, contact StarKingdoms staff.", claims.permission_level, server_config.security.required_permission_level) }.into(), - }); - event_queue.push(WsEvent::Close { addr: *from }); - continue; - } + err_or_cont!(client_login::join_auth(jwt, app_keys.clone(), + from, &mut event_queue, server_config.clone())); + + // create player in world + let (id, transform, mut player_comp) = + client_login::spawn_player(&mut commands, from, username.clone()); - event_queue.push(WsEvent::Send { - to: *from, - message: Packet::Message { message_type: MessageType::Server, actor: "StarKingdoms Team".to_string(), content: "Thank you for participating in the StarKingdoms private alpha! Your feedback is essential to improving the game, so please give us any feedback you have in the Discord! <3".to_string() }.into(), - }); - } else if server_config.security.required_permission_level != 0 { - event_queue.push(WsEvent::Send { - to: *from, - message: Packet::Message { message_type: MessageType::Error, actor: "SERVER".to_string(), content: "Authentication is required to join this server at the moment. Log in and try again, or try again later.".to_string() }.into(), - }); - event_queue.push(WsEvent::Close { addr: *from }); - continue; - } - let angle: f32 = { - let mut rng = rand::thread_rng(); - rng.gen::() * std::f32::consts::PI * 2. - }; - let mut transform = - Transform::from_xyz(angle.cos() * 30.0, angle.sin() * 30.0, 0.0); - transform.rotate_z(angle); - let mut player_comp = Player { - addr: *from, - username: username.to_string(), - input: component::Input::default(), - selected: None, - save_eligibility: false, - energy_capacity: part!(PartType::Hearty).energy_capacity, - energy: part!(PartType::Hearty).energy_capacity, - }; - let mut entity_id = commands.spawn(PartBundle { - part_type: PartType::Hearty, - transform: TransformBundle::from(transform), - flags: PartFlags { attached: false }, - }); - entity_id - .insert(Collider::cuboid(0.5, 0.5)) - .insert(AdditionalMassProperties::MassProperties(MassProperties { - local_center_of_mass: vec2(0.0, 0.0), - mass: part!(PartType::Hearty).mass, - principal_inertia: 7.5, - })) - .insert(ExternalImpulse { - impulse: Vec2::ZERO, - torque_impulse: 0.0, - }) - .insert(ExternalForce::default()) - .insert(ReadMassProperties::default()) - .insert(Velocity::default()) - .insert(RigidBody::Dynamic); - let id = entity_id.id().index(); + let index = id.index(); - let entity = entity_id.id(); let mut attach = Attach { associated_player: None, parent: None, children: [None, None, None, None], }; - if let Some(save) = save { - // attempt to decode the savefile - if let Ok(savefile) = unpack_savefile(&app_keys.app_key, save) { - // HEY! GHOSTLY! THIS SAVE FILE IS VALID! PLEASE LOAD IT! - // THANKS! - - let children = load_savefile( - &mut commands, - transform, - entity, - entity, - savefile.children, - &mut attached_query, - &mut part_query, - &mut player_query, - &mut player_comp, - ); - player_comp.energy = player_comp.energy_capacity; - attach.children = children; - } else { - let packet = Packet::Message { - message_type: crate::packet::MessageType::Error, - actor: "SERVER".to_string(), - content: "Savefile signature corrupted or inner data invalid. Save was not loaded. Contact StarKingdoms staff for assistance.".to_string(), - }; - event_queue.push(WsEvent::Send { - to: *from, - message: packet.into(), - }); - } - } else { - // nothing to do - } - let mut entity_id = commands.entity(entity); + // 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); - // tell this player the planets - let mut planets = Vec::new(); - for (entity, planet_type, transform) in planet_query.iter() { - let translation = transform.translation; - planets.push(( - entity.index(), - Planet { - planet_type: *planet_type, - transform: proto_transform!(Transform::from_translation( - translation * CLIENT_SCALE - )), - radius: match *planet_type { - PlanetType::Earth => { - planet!(PlanetType::Earth).size * CLIENT_SCALE - } - PlanetType::Moon => { - planet!(PlanetType::Moon).size * CLIENT_SCALE - } - PlanetType::Mars => { - planet!(PlanetType::Mars).size * CLIENT_SCALE - } - }, - }, - )); - } - let packet = Packet::PlanetPositions { planets }; - event_queue.push(WsEvent::Send { - to: *from, - message: packet.into(), - }); - - // tell the player already existing users - let mut players = Vec::new(); - for (entity, player, _, _, _, _) in &player_query { - players.push((entity.index(), player.username.clone())); - } - let packet = Packet::PlayerList { players }; - event_queue.push(WsEvent::Send { - to: *from, - message: packet.into(), - }); - - // tell other players that a player has spawned in - let packet = Packet::SpawnPlayer { - id, - username: username.to_string(), - }; - event_queue.push(WsEvent::Broadcast { - message: packet.into(), - }); - let packet = Packet::Message { - message_type: crate::packet::MessageType::Server, - actor: "SERVER".to_string(), - content: format!("{} has joined the server!", username), - }; - event_queue.push(WsEvent::Broadcast { - message: packet.into(), - }); - - // tell the player where parts are - let mut parts = Vec::new(); - for (entity, part_type, transform, _, _, flags) in &part_query { - parts.push(( - entity.index(), - Part { - part_type: *part_type, - transform: proto_transform!(Transform::from_translation( - transform.translation * CLIENT_SCALE - )), - flags: proto_part_flags!(flags), - }, - )); - } - for (entity, part_type, transform, _, _, _, _, flags) in &attached_query { - parts.push(( - entity.index(), - Part { - part_type: *part_type, - transform: proto_transform!(Transform::from_translation( - transform.translation * CLIENT_SCALE - )), - flags: proto_part_flags!(flags), - }, - )); - } - parts.push(( - id, - Part { - part_type: PartType::Hearty, - transform: proto_transform!(Transform::from_translation( - transform.translation - ) - .with_rotation(transform.rotation)), - flags: ProtoPartFlags { attached: false }, - }, - )); - let packet = Packet::PartPositions { parts }; - event_queue.push(WsEvent::Send { - to: *from, - message: packet.into(), - }); - - // and send the welcome message :) - let packet = Packet::Message { - message_type: crate::packet::MessageType::Server, - actor: "SERVER".to_string(), - content: format!( - "starkingdoms-server v{} says hello", - env!("CARGO_PKG_VERSION") - ), - }; - event_queue.push(WsEvent::Send { - to: *from, - message: packet.into(), - }); - let packet = Packet::Message { - message_type: crate::packet::MessageType::Server, - actor: "SERVER".to_string(), - content: "Welcome to StarKingdoms.IO! Have fun!".to_string(), - }; - event_queue.push(WsEvent::Send { - to: *from, - message: packet.into(), - }); - let packet = Packet::Message { - message_type: crate::packet::MessageType::Server, - actor: "SERVER".to_string(), - content: "Found a bug? Have a feature request? Please bring this and all other feedback to the game's official Discord server! Join here: https://discord.gg/3u7Yw8DWtQ".to_string(), - }; - event_queue.push(WsEvent::Send { - to: *from, - message: packet.into(), - }); + // 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 } => { - // find our player - let mut player = None; - for (_, q_player, _, _, _, _) in &player_query { - if q_player.addr == *from { - player = Some(q_player); - } - } - let player = player.unwrap(); - if let Some(target_username) = target { - let mut target_player = None; - for (_, q_player, _, _, _, _) in &player_query { - if q_player.username == target_username { - target_player = Some(q_player); - } - } - let target_player = target_player.unwrap(); - let packet = Packet::Message { - message_type: crate::packet::MessageType::Direct, - actor: player.username.clone(), - content, - }; - event_queue.push(WsEvent::Send { - to: target_player.addr, - message: packet.clone().into(), - }); - event_queue.push(WsEvent::Send { - to: *from, - message: packet.into(), - }); - } else { - // send to general chat - let packet = Packet::Message { - message_type: crate::packet::MessageType::Chat, - actor: player.username.clone(), - content, - }; - - event_queue.push(WsEvent::Broadcast { - message: packet.into(), - }); - } + // a player sent a message + send_message(&player_query, from, &mut event_queue, target, content); } Packet::PlayerInput { up, @@ -401,103 +146,13 @@ pub fn on_message( break; }; q_player.selected = None; - if attached_query.contains(select) { - let module = attached_query.get(select).unwrap(); - let attach = module.3.clone(); - let lost_energy_capacity = crate::module::detach_recursive( - &mut commands, - module.0, - &mut attached_query, - &mut player_query, - ); - let mut module = attached_query.get_mut(select).unwrap(); - module.2.translation = vec3(x, y, 0.); - if *module.1 == PartType::LandingThruster { - let sub_entity = attach.children[2].unwrap(); - let mut suspension = - attached_query.get_mut(sub_entity).unwrap(); - suspension.2.translation = vec3(x, y, 0.); - } - let mut player = player_query.get_mut(entity).unwrap().1; - player.energy_capacity -= lost_energy_capacity; - player.energy = - std::cmp::min(player.energy, player.energy_capacity); - break; - } - if crate::module::attach_on_module_tree( - x, - y, - &mut commands, - entity, - select, - entity, - &mut attached_query, - &mut part_query, - &mut player_query, - ) { - let mut part = part_query.get_mut(select).unwrap(); - part.5.attached = true; // all of this code is cursed. what the hell is it actually doing - break; - } - // move module to cursor since no attach - let mut part = part_query.get_mut(select).unwrap(); - part.2.translation = vec3(x, y, 0.); - if *part.1 == PartType::LandingThruster { - if let Some(loose_attach) = part.4 { - let sub_entity = loose_attach.children[2].unwrap(); - let mut part = part_query.get_mut(sub_entity).unwrap(); - part.2.translation = vec3(x, y, 0.); - } - } + // 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; } - for (m_entity, part_type, transform, m_attach, _velocity, _, _, _) in - &attached_query - { - if *part_type == PartType::LandingThrusterSuspension { - continue; - } - let pos = transform.translation; - let rel_x = pos.x - x; - let rel_y = pos.y - y; - let angle = -transform.rotation.z; - let x = rel_x * angle.cos() - rel_y * angle.sin(); - let y = rel_x * angle.sin() + rel_y * angle.cos(); - let mut bound = [-0.5, 0.5, -0.5, 0.5]; // left, right, top, bottom - if let PartType::Cargo = part_type { - bound = [-0.375, 0.375, -0.5, 0.4375]; - } - - if bound[0] < x - && x < bound[1] - && bound[2] < y - && y < bound[3] - && m_attach.associated_player.unwrap() == entity - { - q_player.selected = Some(m_entity); - break; - } - } - for (entity, part_type, transform, _, _, _) in &part_query { - if *part_type == PartType::LandingThrusterSuspension { - continue; - } - let pos = transform.translation; - let rel_x = pos.x - x; - let rel_y = pos.y - y; - let angle = -transform.rotation.z; - let x = rel_x * angle.cos() - rel_y * angle.sin(); - let y = rel_x * angle.sin() + rel_y * angle.cos(); - let mut bound = [-0.5, 0.5, -0.5, 0.5]; // left, right, top, bottom - if let PartType::Cargo = part_type { - bound = [-0.375, 0.375, -0.5, 0.4375]; - } - - if bound[0] < x && x < bound[1] && bound[2] < y && y < bound[3] { - q_player.selected = Some(entity); - break; - } - } + // check if mouse touched a module + mouse_picking(&attached_query, &part_query, &mut q_player, x, y, entity); } } } @@ -506,31 +161,11 @@ pub fn on_message( if q_player.addr == *from { // HEY! GHOSTLY! PLEASE FILL THIS STRUCT WITH DATA! // THANKS! + // mhm yeah done - let unused_modules = if let Some(ref old_save) = old_save { - if let Ok(old_savedata) = - unpack_savefile(&app_keys.app_key, old_save.to_string()) - { - old_savedata.unused_modules - } else { - Vec::new() - } - } else { - Vec::new() - }; - let save = SaveData { - children: crate::module::save::construct_save_data(attach.clone(), &attached_query), - unused_modules, - }; - let save_string = pack_savefile(&app_keys.app_key, save); - let packet = Packet::SaveData { - payload: save_string, - }; - - event_queue.push(WsEvent::Send { - to: *from, - message: packet.into(), - }); + // 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); } } } @@ -567,6 +202,7 @@ pub fn player_input_update( 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; @@ -583,10 +219,12 @@ pub fn player_input_update( 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; @@ -598,6 +236,7 @@ pub fn player_input_update( 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), @@ -605,6 +244,7 @@ pub fn player_input_update( (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!(PartType::Hearty).thruster_energy { player.energy -= part!(PartType::Hearty).thruster_energy; @@ -623,7 +263,9 @@ pub fn player_input_update( } } // change to support other thruster types later + // check if the player has enough energy to use thruster if player.energy >= part!(PartType::LandingThruster).thruster_energy { + // go through all thrusters and apply force crate::module::thruster::search_thrusters( player.input, attach.clone(), diff --git a/server/src/player/packet.rs b/server/src/player/packet.rs index 99c11aa7c9967124f224f777a919b3f8b3209d4f..f6eac7bbb43cb8da5f0c2b247ebd9f7b847d033f 100644 --- a/server/src/player/packet.rs +++ b/server/src/player/packet.rs @@ -1,6 +1,12 @@ use bevy::{ecs::event::ManualEventReader, prelude::*}; -use crate::{module::component::{Attach, PartFlags, PartType}, planet::PlanetType, proto_part_flags, proto_transform, ws::WsEvent, Packet, Part, Planet, CLIENT_SCALE}; +use crate::{ + module::component::{Attach, PartFlags, PartType}, + planet::PlanetType, + proto_part_flags, proto_transform, + ws::WsEvent, + Packet, Part, Planet, CLIENT_SCALE, +}; use super::component::Player; diff --git a/server/src/player/player_mouse_input.rs b/server/src/player/player_mouse_input.rs new file mode 100644 index 0000000000000000000000000000000000000000..1e192c9737486d73e49a8c50619973c3dde7e73b --- /dev/null +++ b/server/src/player/player_mouse_input.rs @@ -0,0 +1,138 @@ +use bevy::{math::vec3, prelude::*}; +use bevy_rapier2d::prelude::*; + +use crate::{module::component::{Attach, CanAttach, LooseAttach, PartFlags, PartType}, planet::PlanetType}; + +use super::component::Player; + +pub fn attach_or_detach( + select: Entity, + attached_query: &mut Query<(Entity, &PartType, &mut Transform, &mut Attach, + &Velocity, Option<&CanAttach>, Option<&LooseAttach>, &mut PartFlags), + (Without, Without), + >, + player_query: &mut Query<(Entity, &mut Player, &Transform, &Velocity, + &mut Attach, &mut PartFlags), + Without, + >, + part_query: &mut Query<(Entity, &PartType, &mut Transform, &mut Velocity, + Option<&LooseAttach>, &mut PartFlags), + (Without, Without, Without), + >, + commands: &mut Commands, + x: f32, + y: f32, + entity: Entity, +) { + if attached_query.contains(select) { + let module = attached_query.get(select).unwrap(); + let attach = module.3.clone(); + let lost_energy_capacity = crate::module::detach_recursive( + commands, + module.0, + attached_query, + player_query, + ); + let mut module = attached_query.get_mut(select).unwrap(); + module.2.translation = vec3(x, y, 0.); + if *module.1 == PartType::LandingThruster { + let sub_entity = attach.children[2].unwrap(); + let mut suspension = + attached_query.get_mut(sub_entity).unwrap(); + suspension.2.translation = vec3(x, y, 0.); + } + let mut player = player_query.get_mut(entity).unwrap().1; + player.energy_capacity -= lost_energy_capacity; + player.energy = + std::cmp::min(player.energy, player.energy_capacity); + return; + } + if crate::module::attach_on_module_tree( + x, + y, + commands, + entity, + select, + entity, + attached_query, + part_query, + player_query, + ) { + let mut part = part_query.get_mut(select).unwrap(); + part.5.attached = true; // all of this code is cursed. what the hell is it actually doing + return; + } + // move module to cursor since no attach + let mut part = part_query.get_mut(select).unwrap(); + part.2.translation = vec3(x, y, 0.); + if *part.1 == PartType::LandingThruster { + if let Some(loose_attach) = part.4 { + let sub_entity = loose_attach.children[2].unwrap(); + let mut part = part_query.get_mut(sub_entity).unwrap(); + part.2.translation = vec3(x, y, 0.); + } + } +} + +pub fn mouse_picking( + attached_query: &Query<(Entity, &PartType, &mut Transform, &mut Attach, + &Velocity, Option<&CanAttach>, Option<&LooseAttach>, &mut PartFlags), + (Without, Without), + >, + part_query: &Query<(Entity, &PartType, &mut Transform, &mut Velocity, + Option<&LooseAttach>, &mut PartFlags), + (Without, Without, Without), + >, + q_player: &mut Player, + x: f32, + y: f32, + entity: Entity, +) { + for (m_entity, part_type, transform, m_attach, _velocity, _, _, _) in + attached_query.iter() + { + if *part_type == PartType::LandingThrusterSuspension { + continue; + } + let pos = transform.translation; + let rel_x = pos.x - x; + let rel_y = pos.y - y; + let angle = -transform.rotation.z; + let x = rel_x * angle.cos() - rel_y * angle.sin(); + let y = rel_x * angle.sin() + rel_y * angle.cos(); + let mut bound = [-0.5, 0.5, -0.5, 0.5]; // left, right, top, bottom + if let PartType::Cargo = part_type { + bound = [-0.375, 0.375, -0.5, 0.4375]; + } + + if bound[0] < x + && x < bound[1] + && bound[2] < y + && y < bound[3] + && m_attach.associated_player.unwrap() == entity + { + q_player.selected = Some(m_entity); + break; + } + } + for (entity, part_type, transform, _, _, _) in part_query.iter() { + if *part_type == PartType::LandingThrusterSuspension { + continue; + } + let pos = transform.translation; + let rel_x = pos.x - x; + let rel_y = pos.y - y; + let angle = -transform.rotation.z; + let x = rel_x * angle.cos() - rel_y * angle.sin(); + let y = rel_x * angle.sin() + rel_y * angle.cos(); + let mut bound = [-0.5, 0.5, -0.5, 0.5]; // left, right, top, bottom + if let PartType::Cargo = part_type { + bound = [-0.375, 0.375, -0.5, 0.4375]; + } + + if bound[0] < x && x < bound[1] && bound[2] < y && y < bound[3] { + q_player.selected = Some(entity); + break; + } + } +} diff --git a/server/src/player/request_save.rs b/server/src/player/request_save.rs new file mode 100644 index 0000000000000000000000000000000000000000..140e7042fb646a2e562b74b4100ba6ef53f262d1 --- /dev/null +++ b/server/src/player/request_save.rs @@ -0,0 +1,49 @@ +use std::net::SocketAddr; + +use bevy::prelude::*; +use bevy_rapier2d::prelude::Velocity; +use starkingdoms_common::{pack_savefile, unpack_savefile, SaveData}; + +use crate::{module::component::{Attach, CanAttach, LooseAttach, PartFlags, PartType}, planet::PlanetType, ws::WsEvent, AppKeys, Packet}; + +use super::component::Player; + +pub fn request_save( + attached_query: &Query<(Entity, &PartType, &mut Transform, &mut Attach, + &Velocity, Option<&CanAttach>, Option<&LooseAttach>, &mut PartFlags), + (Without, Without), + >, + old_save: Option, + app_keys: AppKeys, + attach: Attach, + event_queue: &mut Vec, + from: &SocketAddr +) { + let unused_modules = if let Some(ref old_save) = old_save { + if let Ok(old_savedata) = + unpack_savefile(&app_keys.app_key, old_save.to_string()) + { + old_savedata.unused_modules + } else { + Vec::new() + } + } else { + Vec::new() + }; + let save = SaveData { + children: crate::module::save::construct_save_data( + attach.clone(), + attached_query, + ), + unused_modules, + }; + let save_string = pack_savefile(&app_keys.app_key, save); + let packet = Packet::SaveData { + payload: save_string, + }; + + event_queue.push(WsEvent::Send { + to: *from, + message: packet.into(), + }); +} diff --git a/server/src/player/send_message.rs b/server/src/player/send_message.rs new file mode 100644 index 0000000000000000000000000000000000000000..fef8ec14a7913ea29b011e3bf6e20b3ff089af7d --- /dev/null +++ b/server/src/player/send_message.rs @@ -0,0 +1,61 @@ +use std::net::SocketAddr; + +use bevy::prelude::*; +use bevy_rapier2d::prelude::Velocity; + +use crate::{module::component::{Attach, PartFlags}, planet::PlanetType, ws::WsEvent, Packet}; + +use super::component::Player; + +pub fn send_message( + player_query: &Query<(Entity, &mut Player, &Transform, &Velocity, + &mut Attach, &mut PartFlags), + Without, + >, + from: &SocketAddr, + event_queue: &mut Vec, + target: Option, + content: String, +) { + // find our player + let mut player = None; + for (_, q_player, _, _, _, _) in player_query.iter() { + if q_player.addr == *from { + player = Some(q_player); + } + } + let player = player.unwrap(); + if let Some(target_username) = target { + let mut target_player = None; + for (_, q_player, _, _, _, _) in player_query.iter() { + if q_player.username == target_username { + target_player = Some(q_player); + } + } + let target_player = target_player.unwrap(); + let packet = Packet::Message { + message_type: crate::packet::MessageType::Direct, + actor: player.username.clone(), + content, + }; + event_queue.push(WsEvent::Send { + to: target_player.addr, + message: packet.clone().into(), + }); + event_queue.push(WsEvent::Send { + to: *from, + message: packet.into(), + }); + } else { + // send to general chat + let packet = Packet::Message { + message_type: crate::packet::MessageType::Chat, + actor: player.username.clone(), + content, + }; + + event_queue.push(WsEvent::Broadcast { + message: packet.into(), + }); + } +}