M Cargo.toml => Cargo.toml +1 -1
@@ 4,7 4,7 @@ members = [
"starkingdoms-backplane",
"starkingdoms-common",
"savefile_decoder"
-, "starkingdoms-api"]
+, "starkingdoms-api", "kabel"]
resolver = "2"
[profile.dev.package."*"]
A kabel/Cargo.toml => kabel/Cargo.toml +6 -0
@@ 0,0 1,6 @@
+[package]
+name = "kabel"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
A kabel/grammar.ebnf => kabel/grammar.ebnf +35 -0
@@ 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 } ] ;
A kabel/src/main.rs => kabel/src/main.rs +3 -0
@@ 0,0 1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
M server/src/main.rs => server/src/main.rs +14 -51
@@ 48,7 48,7 @@ pub mod ws;
struct StkPluginGroup;
-#[derive(Resource)]
+#[derive(Resource, Clone)]
pub struct AppKeys {
pub app_key: Vec<u8>,
}
@@ 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::<Fixed>::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<RapierContext>, server_config: Res<StkConfig>) {
context.integration_parameters = server_config.physics.parameters;
@@ 188,43 191,3 @@ fn setup_integration_parameters(mut context: ResMut<RapierContext>, server_confi
}
}
}
-
-fn gravity_update(
- mut part_query: Query<
- (
- &Transform,
- &ReadMassProperties,
- &mut ExternalForce,
- &mut ExternalImpulse,
- ),
- With<PartType>,
- >,
- planet_query: Query<(&Transform, &ReadMassProperties), With<PlanetType>>,
- server_config: Res<StkConfig>,
-) {
- 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();
- }
- }
-}
M server/src/module/component.rs => server/src/module/component.rs +24 -2
@@ 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)]
M server/src/module/mod.rs => server/src/module/mod.rs +30 -114
@@ 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<PlanetType>, Without<Player>),
>,
- 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<PlanetType>,
>,
) -> 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<PlanetType>, Without<Player>),
>,
- 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<PlanetType>, Without<Player>, Without<Attach>),
>,
- 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<PlanetType>,
>,
) -> 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<RapierContext>,
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<Player>,
>,
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<Player>,
>,
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<RapierContext>,
- 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<PlanetType>, Without<Player>),
>,
- 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<PlanetType>,
>,
) {
M server/src/module/save.rs => server/src/module/save.rs +5 -12
@@ 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,
M server/src/module/thruster.rs => server/src/module/thruster.rs +5 -1
@@ 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::*;
M server/src/planet.rs => server/src/planet.rs +37 -1
@@ 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<PartType>,
+ >,
+ planet_query: Query<(&Transform, &ReadMassProperties), With<PlanetType>>,
+ server_config: Res<StkConfig>,
+) {
+ 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();
+ }
+ }
+}
A server/src/player/client_login.rs => server/src/player/client_login.rs +301 -0
@@ 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<String>, app_keys: AppKeys, from: &SocketAddr,
+ event_queue: &mut Vec<WsEvent>, server_config: StkConfig,
+) -> Result<(), ()> {
+ if let Some(token) = jwt {
+ let key: Hmac<Sha256> = 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::<f32>() * 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<String>, app_keys: AppKeys,
+ attached_query: &mut Query<(Entity, &PartType, &mut Transform, &mut Attach,
+ &Velocity, Option<&CanAttach>, Option<&LooseAttach>, &mut PartFlags),
+ (Without<PlanetType>, Without<Player>),
+ >,
+ part_query: &mut Query<(Entity, &PartType, &mut Transform, &mut Velocity,
+ Option<&LooseAttach>, &mut PartFlags),
+ (Without<PlanetType>, Without<Player>, Without<Attach>),
+ >,
+ player_query: &mut Query<(Entity, &mut Player, &Transform, &Velocity,
+ &mut Attach, &mut PartFlags),
+ Without<PlanetType>,
+ >,
+ player_comp: &mut Player, attach: &mut Attach, from: &SocketAddr,
+ event_queue: &mut Vec<WsEvent>,
+) {
+ 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<WsEvent>, from: &SocketAddr,
+ player_query: &Query<(Entity, &mut Player, &Transform, &Velocity,
+ &mut Attach, &mut PartFlags),
+ Without<PlanetType>,
+ >,
+ index: u32, username: String,
+ part_query: &Query<(Entity, &PartType, &mut Transform, &mut Velocity,
+ Option<&LooseAttach>, &mut PartFlags),
+ (Without<PlanetType>, Without<Player>, Without<Attach>),
+ >,
+ attached_query: &Query<(Entity, &PartType, &mut Transform, &mut Attach,
+ &Velocity, Option<&CanAttach>, Option<&LooseAttach>, &mut PartFlags),
+ (Without<PlanetType>, Without<Player>),
+ >,
+ 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(),
+ });
+}
M server/src/player/component.rs => server/src/player/component.rs +0 -1
@@ 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,
M server/src/player/mod.rs => server/src/player/mod.rs +55 -413
@@ 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<Sha256> = 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::<f32>() * 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(),
M server/src/player/packet.rs => server/src/player/packet.rs +7 -1
@@ 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;
A server/src/player/player_mouse_input.rs => server/src/player/player_mouse_input.rs +138 -0
@@ 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<PlanetType>, Without<Player>),
+ >,
+ player_query: &mut Query<(Entity, &mut Player, &Transform, &Velocity,
+ &mut Attach, &mut PartFlags),
+ Without<PlanetType>,
+ >,
+ part_query: &mut Query<(Entity, &PartType, &mut Transform, &mut Velocity,
+ Option<&LooseAttach>, &mut PartFlags),
+ (Without<PlanetType>, Without<Player>, Without<Attach>),
+ >,
+ 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<PlanetType>, Without<Player>),
+ >,
+ part_query: &Query<(Entity, &PartType, &mut Transform, &mut Velocity,
+ Option<&LooseAttach>, &mut PartFlags),
+ (Without<PlanetType>, Without<Player>, Without<Attach>),
+ >,
+ 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;
+ }
+ }
+}
A server/src/player/request_save.rs => server/src/player/request_save.rs +49 -0
@@ 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<PlanetType>, Without<Player>),
+ >,
+ old_save: Option<String>,
+ app_keys: AppKeys,
+ attach: Attach,
+ event_queue: &mut Vec<WsEvent>,
+ 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(),
+ });
+}
A server/src/player/send_message.rs => server/src/player/send_message.rs +61 -0
@@ 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<PlanetType>,
+ >,
+ from: &SocketAddr,
+ event_queue: &mut Vec<WsEvent>,
+ target: Option<String>,
+ 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(),
+ });
+ }
+}