M server/src/component.rs => server/src/component.rs +1 -86
@@ 17,63 17,8 @@ use std::net::SocketAddr;
use bevy::prelude::*;
use serde::{Deserialize, Serialize};
-use starkingdoms_common::PartType as c_PartType;
-#[derive(Component, Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
-pub enum PlanetType {
- Earth,
- Moon,
- Mars,
-}
-
-#[derive(Component, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
-pub enum PartType {
- Placeholder,
- Hearty,
- Cargo,
- Hub,
- LandingThruster,
- LandingThrusterSuspension,
-}
-impl From<PartType> for c_PartType {
- fn from(value: PartType) -> Self {
- match value {
- PartType::Placeholder => c_PartType::Placeholder,
- PartType::Hearty => c_PartType::Hearty,
- PartType::Cargo => c_PartType::Cargo,
- PartType::Hub => c_PartType::Hub,
- PartType::LandingThruster => c_PartType::LandingThruster,
- PartType::LandingThrusterSuspension => c_PartType::LandingThrusterSuspension,
- }
- }
-}
-impl From<c_PartType> for PartType {
- fn from(value: c_PartType) -> Self {
- match value {
- c_PartType::Placeholder => PartType::Placeholder,
- c_PartType::Hearty => PartType::Hearty,
- c_PartType::Cargo => PartType::Cargo,
- c_PartType::Hub => PartType::Hub,
- c_PartType::LandingThruster => PartType::LandingThruster,
- c_PartType::LandingThrusterSuspension => PartType::LandingThrusterSuspension,
- }
- }
-}
-
-#[derive(Component, Clone, Debug)]
-pub struct Attach {
- pub associated_player: Option<Entity>,
- pub parent: Option<Entity>,
- pub children: [Option<Entity>; 4],
-}
-
-#[derive(Component, Clone, Debug)]
-pub struct LooseAttach {
- pub children: [Option<Entity>; 4],
-}
-
-#[derive(Component, Clone, Copy, PartialEq, Debug)]
-pub struct CanAttach(pub u8); // each bit means a slot able to attach to
+use crate::module::component::{Attach, PartBundle};
#[derive(Component, Clone, Copy, Serialize, Deserialize, Debug, Default)]
pub struct Input {
@@ 94,23 39,6 @@ pub struct Player {
pub energy: u32,
}
-#[derive(Bundle)]
-pub struct PlanetBundle {
- pub planet_type: PlanetType,
- pub transform: TransformBundle,
-}
-
-#[derive(Component, Copy, Clone)]
-pub struct PartFlags {
- pub attached: bool,
-}
-
-#[derive(Bundle)]
-pub struct PartBundle {
- pub transform: TransformBundle,
- pub part_type: PartType,
- pub flags: PartFlags,
-}
#[derive(Bundle)]
pub struct PlayerBundle {
@@ 120,19 48,6 @@ pub struct PlayerBundle {
}
#[derive(Resource)]
-pub struct ModuleTimer(pub Timer);
-impl ModuleTimer {
- pub fn new() -> Self {
- Self(Timer::from_seconds(0.3, TimerMode::Repeating))
- }
-}
-impl Default for ModuleTimer {
- fn default() -> Self {
- Self::new()
- }
-}
-
-#[derive(Resource)]
pub struct AppKeys {
pub app_key: Vec<u8>,
}
M server/src/config.rs => server/src/config.rs +35 -1
@@ 14,7 14,8 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
-use crate::component::{PartType, PlanetType};
+use crate::module::component::PartType;
+use crate::planet::PlanetType;
use bevy::ecs::system::Resource;
use bevy_rapier2d::rapier::dynamics::IntegrationParameters;
use serde::{Deserialize, Serialize};
@@ 88,3 89,36 @@ pub struct PartConfig {
pub thruster_force: f32,
pub thruster_energy: u32,
}
+
+#[macro_export]
+macro_rules! mass {
+ ($p:expr) => {
+ match $crate::parts_config().parts.get(&$p) {
+ Some(v) => v.mass,
+ None => 1.0,
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! capacity {
+ ($p:expr) => {
+ match $crate::parts_config().parts.get(&$p) {
+ Some(v) => v.energy_capacity,
+ None => 0,
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! planet {
+ ($t:expr) => {
+ $crate::planets_config().planets.get(&$t).unwrap()
+ };
+}
+#[macro_export]
+macro_rules! part {
+ ($t:expr) => {
+ $crate::parts_config().parts.get(&$t).unwrap()
+ };
+}
M server/src/main.rs => server/src/main.rs +21 -1217
@@ 17,8 17,6 @@
#![allow(clippy::too_many_arguments)] // bevy :(
#![allow(clippy::only_used_in_recursion)] // todo: remove this
-use std::collections::HashMap;
-
use crate::mathutil::rot2d;
use crate::ws::{StkTungsteniteServerConfig, StkTungsteniteServerPlugin, WsEvent};
use bevy::math::{vec2, vec3};
@@ 32,13 30,16 @@ use bevy_rapier2d::prelude::*;
use component::*;
use hmac::{Hmac, Mac};
use jwt::VerifyWithKey;
+use module::component::{Attach, CanAttach, LooseAttach, ModuleTimer, PartBundle, PartFlags, PartType};
+use module::save::{construct_save_data, load_savefile};
+use module::thruster::search_thrusters;
+use module::{attach_on_module_tree, despawn_module_tree, detach_recursive};
use packet::*;
+use planet::PlanetType;
use rand::Rng;
use serde::{Deserialize, Serialize};
use sha2::Sha256;
-use starkingdoms_common::SaveModule;
use starkingdoms_common::{pack_savefile, unpack_savefile, SaveData};
-use std::f32::consts::PI;
use std::fs;
use crate::config::{PartsConfig, PhysicsSolver, PlanetsConfig, StkConfig};
@@ 50,14 51,19 @@ mod config;
pub mod macros;
pub mod mathutil;
pub mod packet;
-pub mod part;
pub mod ws;
+pub mod planet;
+pub mod module;
+pub mod player;
struct StkPluginGroup;
+// factor to multiply positions by to send to the client
pub static CLIENT_SCALE: f32 = 50.0;
+// half size of hearty
pub static PART_HALF_SIZE: f32 = 25.0;
+// good ol' classic almost useless but still necessary code
static _SERVER_CONFIG: OnceLock<StkConfig> = OnceLock::new();
#[inline]
pub fn server_config() -> StkConfig {
@@ 74,6 80,7 @@ pub fn planets_config() -> PlanetsConfig {
_PLANETS_CONFIG.get().unwrap().clone()
}
+// group main stk plugins together
#[cfg(debug_assertions)]
impl PluginGroup for StkPluginGroup {
fn build(self) -> PluginGroupBuilder {
@@ 105,6 112,7 @@ impl PluginGroup for StkPluginGroup {
}
}
+// auth token
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserToken {
pub id: i64,
@@ 119,6 127,7 @@ fn main() {
let parts_config = fs::read_to_string("/etc/starkingdoms/parts.toml").unwrap();
let planets_config = fs::read_to_string("/etc/starkingdoms/planets.toml").unwrap();
+ // put config in variables
let server_config: StkConfig = toml::from_str(&server_config).unwrap();
_SERVER_CONFIG.set(server_config.clone()).unwrap();
let parts_config: PartsConfig = toml::from_str(&parts_config).unwrap();
@@ 126,6 135,7 @@ fn main() {
let planets_config: PlanetsConfig = toml::from_str(&planets_config).unwrap();
_PLANETS_CONFIG.set(planets_config.clone()).unwrap();
+ // make the game, start it in .run()
App::new()
.insert_resource(AppKeys {
app_key: server_config.security.app_key.as_bytes().to_vec(),
@@ 148,23 158,24 @@ fn main() {
))
.add_plugins(StkTungsteniteServerPlugin)
.add_systems(Startup, setup_integration_parameters)
- .add_systems(Startup, spawn_planets)
- .add_systems(FixedUpdate, module_spawn)
+ .add_systems(Startup, planet::spawn_planets)
+ .add_systems(FixedUpdate, module::module_spawn)
.add_systems(Update, on_message)
.add_systems(Update, on_close)
.add_systems(FixedUpdate, send_player_energy)
.add_systems(FixedUpdate, on_position_change)
.add_systems(
FixedUpdate,
- (break_modules, gravity_update, player_input_update).chain(),
+ (module::break_modules, gravity_update, player_input_update).chain(),
)
- .add_systems(FixedUpdate, save_eligibility)
- .add_systems(FixedUpdate, convert_modules)
+ .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,
))
.run();
+ // game is done running
info!("Goodbye!");
}
@@ 184,117 195,6 @@ fn setup_integration_parameters(mut context: ResMut<RapierContext>, server_confi
}
}
}
-fn spawn_planets(mut commands: Commands) {
- info!("Spawning planets");
- let earth_pos = Transform::from_xyz(0.0, 0.0, 0.0);
- commands
- .spawn(PlanetBundle {
- planet_type: PlanetType::Earth,
- transform: TransformBundle::from(earth_pos),
- })
- .insert(Collider::ball(planet!(PlanetType::Earth).size))
- .insert(AdditionalMassProperties::Mass(
- planet!(PlanetType::Earth).mass,
- ))
- .insert(ReadMassProperties::default())
- .with_children(|children| {
- children
- .spawn(Collider::ball(planet!(PlanetType::Earth).size + 0.3))
- .insert(ActiveEvents::COLLISION_EVENTS)
- .insert(Sensor);
- })
- .insert(RigidBody::Fixed);
- let moon_pos = Transform::from_xyz(50.0, 20.0, 0.0);
- commands
- .spawn(PlanetBundle {
- planet_type: PlanetType::Moon,
- transform: TransformBundle::from(moon_pos),
- })
- .insert(Collider::ball(planet!(PlanetType::Moon).size))
- .insert(AdditionalMassProperties::Mass(
- planet!(PlanetType::Moon).mass,
- ))
- .insert(ReadMassProperties::default())
- .with_children(|children| {
- children
- .spawn(Collider::ball(planet!(PlanetType::Moon).size + 0.1))
- .insert(ActiveEvents::COLLISION_EVENTS)
- .insert(Sensor);
- })
- .insert(RigidBody::Fixed);
- let mars_pos = Transform::from_xyz(-50.0, 300.0, 0.0);
- commands
- .spawn(PlanetBundle {
- planet_type: PlanetType::Mars,
- transform: TransformBundle::from(mars_pos),
- })
- .insert(Collider::ball(planet!(PlanetType::Mars).size))
- .insert(AdditionalMassProperties::Mass(
- planet!(PlanetType::Mars).mass,
- ))
- .insert(ReadMassProperties::default())
- .with_children(|children| {
- children
- .spawn(Collider::ball(planet!(PlanetType::Mars).size + 0.1))
- .insert(ActiveEvents::COLLISION_EVENTS)
- .insert(Sensor);
- })
- .insert(RigidBody::Fixed);
-}
-fn module_spawn(
- mut commands: Commands,
- time: Res<Time>,
- mut module_timer: ResMut<ModuleTimer>,
- part_query: Query<&PartType, Without<Attach>>,
- mut packet_send: EventWriter<WsEvent>,
- server_config: Res<StkConfig>,
-) {
- if module_timer.0.tick(time.delta()).just_finished()
- && part_query.iter().count() < server_config.server.max_free_parts
- {
- 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 flags = PartFlags { attached: false };
- let mut entity = commands.spawn(PartBundle {
- part_type: PartType::Cargo,
- transform: TransformBundle::from(transform),
- flags,
- });
- entity
- .insert(RigidBody::Dynamic)
- .with_children(|children| {
- children
- .spawn(Collider::cuboid(0.375, 0.46875))
- .insert(TransformBundle::from(Transform::from_xyz(0., 0.03125, 0.)));
- })
- .insert(AdditionalMassProperties::MassProperties(MassProperties {
- 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(),
- part: Part {
- part_type: PartType::Cargo,
- transform: proto_transform!(transform),
- flags: proto_part_flags!(flags),
- },
- };
-
- packet_send.send(WsEvent::Broadcast {
- message: packet.into(),
- });
- }
-}
fn on_message(
mut commands: Commands,
@@ 823,911 723,6 @@ fn on_message(
}
}
-fn load_savefile(
- commands: &mut Commands,
- transform: Transform,
- player_id: Entity,
- parent: Entity,
- children: Vec<Option<SaveModule>>,
- 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,
-) -> [Option<Entity>; 4] {
- let mut ret = [None, None, None, None];
- for (i, child) in children.iter().enumerate() {
- if let Some(child) = child {
- let part_type = PartType::from(child.part_type);
- //let attachable = can_attach != None;
-
- let p_pos = transform.translation;
- let angle = transform.rotation.to_euler(EulerRot::ZYX).0;
- let mut offset = Vec2::ZERO;
- let mut angle_offset = 0.;
- if i == 2 {
- //offset = Vec2::new(53., -53.);
- offset = Vec2::new(0., -1.06);
- angle_offset = 0.;
- } else if i == 0 {
- //offset = Vec2::new(-53., 53.);
- offset = Vec2::new(0., 1.06);
- angle_offset = PI;
- } else if i == 1 {
- //offset = Vec2::new(53., 53.);
- offset = Vec2::new(1.06, 0.);
- angle_offset = PI / 2.;
- } else if i == 3 {
- //offset = Vec2::new(-53., 53.);
- offset = Vec2::new(-1.06, 0.);
- angle_offset = -PI / 2.;
- }
-
- let transform = Transform::from_xyz(
- p_pos.x + offset.x * angle.cos() - offset.y * angle.sin(),
- p_pos.y + offset.x * angle.sin() + offset.y * angle.cos(),
- 0.,
- )
- .with_rotation(Quat::from_euler(
- EulerRot::ZYX,
- angle + angle_offset,
- 0.,
- 0.,
- ));
- let module_id = {
- let module = commands.spawn(PartBundle {
- transform: TransformBundle::from(transform),
- part_type: child.part_type.into(),
- flags: PartFlags { attached: true },
- });
- module.id()
- };
-
- let children = if part_type != PartType::LandingThruster {
- load_savefile(
- commands,
- transform,
- player_id,
- module_id,
- child.children.clone(),
- attached_query,
- part_query,
- player_query,
- player_comp,
- )
- } else {
- [None, None, None, None]
- };
-
- let mut module = commands.entity(module_id);
-
- module.insert(Attach {
- associated_player: Some(player_id),
- parent: Some(parent),
- children,
- });
- //module.5.attached = true;
- ret[i] = Some(module.id());
-
- module
- .insert(RigidBody::Dynamic)
- .with_children(|children| {
- children
- .spawn(if part_type == PartType::Cargo {
- Collider::cuboid(0.375, 0.46875)
- } else if part_type == PartType::Hub {
- Collider::cuboid(0.5, 0.5)
- } else if part_type == PartType::LandingThruster {
- Collider::cuboid(0.5, 0.375)
- } else {
- Collider::cuboid(0.5, 0.5)
- })
- .insert(TransformBundle::from(Transform::from_xyz(
- 0.,
- if part_type == PartType::Cargo {
- 0.03125
- } else if part_type == PartType::Hub {
- 0.
- } else if part_type == PartType::LandingThruster {
- 0.125
- } else {
- 0.
- },
- 0.,
- )));
- })
- .insert(AdditionalMassProperties::MassProperties(MassProperties {
- 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));
- }
-
- let joint = FixedJointBuilder::new()
- .local_anchor1(vec2(offset.x, offset.y))
- .local_basis1(angle_offset);
-
- module.insert(ImpulseJoint::new(parent, joint));
-
- if part_type == PartType::LandingThruster {
- let joint = PrismaticJointBuilder::new(Vec2::new(0., 1.))
- .set_motor(0., 0., 3000., 3000.)
- .limits([0., 1.])
- .build();
- let mut suspension = commands.spawn(PartBundle {
- transform: TransformBundle::from(
- Transform::from_xyz(
- p_pos.x + offset.x * angle.cos() - offset.y * angle.sin(),
- p_pos.y + offset.x * angle.sin() + offset.y * angle.cos(),
- 0.,
- )
- .with_rotation(Quat::from_euler(
- EulerRot::ZYX,
- angle + angle_offset,
- 0.,
- 0.,
- )),
- ),
- part_type: PartType::LandingThrusterSuspension,
- flags: PartFlags { attached: true },
- });
- 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,
- principal_inertia: 0.0000000000001,
- }))
- .insert(Attach {
- associated_player: Some(player_id),
- parent: Some(module_id),
- children: [None, None, None, None],
- });
- let suspension_id = suspension.id();
- let mut module = commands.entity(module_id);
- module.remove::<Attach>();
- module.insert(Attach {
- associated_player: Some(player_id),
- parent: Some(parent),
- children: [None, None, Some(suspension_id), None],
- });
- }
- player_comp.energy_capacity += capacity!(part_type);
- }
- }
- ret
-}
-
-fn construct_save_data(
- attach: Attach,
- attached_query: &Query<
- (
- Entity,
- &PartType,
- &mut Transform,
- &mut Attach,
- &Velocity,
- Option<&CanAttach>,
- Option<&LooseAttach>,
- &mut PartFlags,
- ),
- (Without<PlanetType>, Without<Player>),
- >,
-) -> Vec<Option<SaveModule>> {
- let mut modules = vec![None, None, None, None];
- for (i, child) in attach.children.iter().enumerate() {
- if let Some(child) = child {
- let (_, part_type, _, attach, _, _, _, _) = attached_query.get(*child).unwrap();
- if *part_type == PartType::LandingThrusterSuspension {
- continue;
- }
- let child_save_module = construct_save_data(attach.clone(), attached_query);
- modules[i] = Some(SaveModule {
- part_type: (*part_type).into(),
- children: child_save_module,
- });
- }
- }
- modules
-}
-
-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,
- ),
- (Without<PlanetType>, Without<Player>),
- >,
- player_query: &mut Query<
- (
- Entity,
- &mut Player,
- &Transform,
- &Velocity,
- &mut Attach,
- &mut PartFlags,
- ),
- Without<PlanetType>,
- >,
-) -> u32 {
- let mut energy = 0;
- let f_attach = if attached_query.contains(this) {
- attached_query.get(this).unwrap().3.clone()
- } else {
- player_query.get(this).unwrap().4.clone()
- };
- for child in f_attach.children.iter().flatten() {
- energy += detach_recursive(commands, *child, attached_query, player_query);
- }
- let (entity, part_type, attach, mut flags) = if attached_query.contains(this) {
- let (entity, part_type, _, attach, _, _, _, flags) = attached_query.get_mut(this).unwrap();
- (entity, part_type, attach, flags)
- } else {
- let (entity, _, _, _, attach, part_flags) = player_query.get_mut(this).unwrap();
- (entity, &PartType::Hearty, attach, part_flags)
- };
- energy += capacity!(*part_type);
- commands.entity(entity).remove::<Attach>();
- flags.attached = false;
- if *part_type == PartType::LandingThrusterSuspension {
- let parent = attach.parent.unwrap();
- let parent_attach = attached_query.get(parent).unwrap().3;
- commands.entity(parent).insert(LooseAttach {
- children: parent_attach.children,
- });
- } else {
- commands.entity(entity).remove::<ImpulseJoint>();
- }
- let parent = f_attach.parent.unwrap();
- if attached_query.contains(parent) {
- let mut parent_attach = attached_query.get_mut(parent).unwrap().3;
- let children = parent_attach.children;
- for (i, child) in children.iter().enumerate() {
- if let Some(child) = child {
- if *child == entity {
- parent_attach.children[i] = None;
- }
- }
- }
- } else if player_query.contains(parent) {
- let mut parent_attach = player_query.get_mut(parent).unwrap().4;
- for (i, child) in parent_attach.children.clone().iter().enumerate() {
- if let Some(child) = child {
- if *child == entity {
- parent_attach.children[i] = None;
- }
- }
- }
- }
- energy
-}
-
-fn attach_on_module_tree(
- 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,
- ),
- (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>,
- >,
-) -> bool {
- let mut ret = false;
-
- let attach = if attached_query.contains(this) {
- attached_query.get(this).unwrap().3
- } else {
- player_query.get(this).unwrap().4
- };
- for this in attach.clone().children.iter().flatten() {
- let module = part_query.get(select).unwrap();
- 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,
- )
- } else {
- false
- };
- }
- let is_player = player_query.contains(this);
- let (entity, transform, mut attach, velocity, can_attach) = if attached_query.contains(this) {
- let (entity, _, transform, attach, velocity, can_attach, _, _) =
- attached_query.get_mut(this).unwrap();
- (entity, *transform, attach, velocity, can_attach)
- } else {
- let (entity, _, transform, velocity, attach, _) = player_query.get_mut(this).unwrap();
- (entity, *transform, attach, velocity, Some(&CanAttach(15)))
- };
-
- let p_pos = transform.translation;
- let (rel_x, rel_y) = (p_pos.x - x, p_pos.y - y);
- let angle = transform.rotation.to_euler(EulerRot::ZYX).0;
- let (rel_x, rel_y) = (
- rel_x * (-angle).cos() - rel_y * (-angle).sin(),
- rel_x * (-angle).sin() + rel_y * (-angle).cos(),
- );
- let mut module = part_query.get_mut(select).unwrap();
-
- let attachable = match can_attach {
- Some(s) => s.0,
- None => return false,
- };
- let mut attachment_slot = 5;
- let mut offset = Vec2::ZERO;
- let mut angle_offset = 0.;
-
- if attach.children[2].is_none() // top
- && attachable & 4 != 0
- && -(rel_x.abs()) + rel_y > 0.0
- && rel_x.abs() + rel_y < 1.0
- {
- attachment_slot = 2;
- offset = Vec2::new(0., -1.06);
- angle_offset = 0.;
- } else if attach.children[0].is_none() // bottom
- && rel_x.abs() + rel_y < 0.0
- && -(rel_x.abs()) + rel_y > -1.0
- {
- attachment_slot = 0;
- offset = Vec2::new(0., 1.06);
- angle_offset = PI;
- } else if attach.children[1].is_none() // left
- && rel_x + rel_y.abs() < 0.0
- && rel_x - rel_y.abs() > -1.0
- {
- attachment_slot = 1;
- offset = Vec2::new(1.06, 0.);
- angle_offset = PI / 2.;
- } else if attach.children[3].is_none() // right
- && rel_x - rel_y.abs() > 0.0
- && rel_x + rel_y.abs() < 1.0
- {
- attachment_slot = 3;
- offset = Vec2::new(-1.06, 0.);
- angle_offset = -PI / 2.;
- }
- let new_transform = Transform::from_xyz(
- p_pos.x + offset.x * angle.cos() - offset.y * angle.sin(),
- p_pos.y + offset.x * angle.sin() + offset.y * angle.cos(),
- 0.,
- )
- .with_rotation(Quat::from_euler(
- EulerRot::ZYX,
- angle + angle_offset,
- 0.,
- 0.,
- ));
- if attachment_slot != 5 {
- let associated_player = if is_player {
- Some(entity)
- } else {
- attach.associated_player
- };
- *module.2 = new_transform;
- module.3.linvel = velocity.linvel;
- let joint = FixedJointBuilder::new()
- .local_anchor1(offset)
- .local_basis1(angle_offset);
- let mut children = [None, None, None, None];
- if let Some(loose_attach) = module.4 {
- if *module.1 == PartType::LandingThruster {
- commands
- .entity(loose_attach.children[2].unwrap())
- .insert(Attach {
- associated_player,
- parent: Some(module.0),
- children: [None, None, None, None],
- });
- }
- children = loose_attach.children;
- commands.entity(entity).remove::<LooseAttach>();
- }
- let mut module_entity = commands.entity(module.0);
- module_entity.insert(ImpulseJoint::new(entity, joint));
- module_entity.insert(Attach {
- associated_player,
- parent: Some(entity),
- children,
- });
- module_entity.insert(CanAttach(15));
- attach.children[attachment_slot] = Some(module.0);
- module.5.attached = true;
- player_query.get_mut(player_id).unwrap().1.energy_capacity += capacity!(*module.1);
- if *module.1 == PartType::LandingThruster {
- let loose_attach = module.4.unwrap().clone();
- let mut transform = part_query
- .get_mut(loose_attach.children[2].unwrap())
- .unwrap()
- .2;
- *transform = new_transform;
- }
- ret = true;
- }
-
- ret
-}
-
-fn convert_modules(
- mut commands: Commands,
- 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,
- ),
- Without<Player>,
- >,
- mut collider_query: Query<
- (&mut Collider, &mut Transform, &Parent),
- (Without<Player>, Without<Attach>),
- >,
- mut packet_send: EventWriter<WsEvent>,
-) {
- for (_planet_entity, planet_type, children) in &planet_query {
- for (entity1, entity2, intersecting) in
- rapier_context.intersection_pairs_with(*children.first().unwrap())
- {
- if intersecting {
- let other = if *children.first().unwrap() == entity1 {
- entity2
- } else {
- entity1
- };
- let player_entity = if player_query.contains(other) {
- other
- } else if attached_query.contains(other) {
- attached_query
- .get(other)
- .unwrap()
- .2
- .associated_player
- .unwrap()
- } else if collider_query.contains(other) {
- let parent = collider_query.get(other).unwrap().2.get();
- if attached_query.contains(parent) {
- attached_query
- .get(parent)
- .unwrap()
- .2
- .associated_player
- .unwrap()
- } else {
- continue;
- }
- } else {
- continue;
- };
- let mut player = player_query.get_mut(player_entity).unwrap();
- let increase_capacity_by = convert_modules_recursive(
- &mut commands,
- *planet_type,
- player.0.clone(),
- &mut attached_query,
- &mut collider_query,
- &mut packet_send,
- );
- player.1.energy_capacity += increase_capacity_by;
- player.1.energy = player.1.energy_capacity;
- }
- }
- }
-}
-
-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,
- ),
- Without<Player>,
- >,
- collider_query: &mut Query<
- (&mut Collider, &mut Transform, &Parent),
- (Without<Player>, Without<Attach>),
- >,
- packet_send: &mut EventWriter<WsEvent>,
-) -> u32 {
- let mut increase_capacity_by = 0;
- for child in attach.children.iter().flatten() {
- let (
- module_entity,
- mut part_type,
- mut attach,
- mut mass_prop,
- children,
- module_transform,
- part_flags,
- ) = attached_query.get_mut(*child).unwrap();
- if *part_type == PartType::Cargo {
- match planet_type {
- PlanetType::Mars => {
- *part_type = PartType::Hub;
- *mass_prop = AdditionalMassProperties::MassProperties(MassProperties {
- local_center_of_mass: Vec2::new(0.0, 0.0),
- mass: part!(PartType::Hub).mass,
- principal_inertia: 7.5,
- });
- let (mut collider, mut transform, _) =
- collider_query.get_mut(*children.first().unwrap()).unwrap();
- *collider = Collider::cuboid(0.5, 0.5);
- *transform = Transform::from_xyz(0., 0., 0.);
- commands
- .get_entity(module_entity)
- .unwrap()
- .remove::<CanAttach>();
- commands
- .get_entity(module_entity)
- .unwrap()
- .insert(CanAttach(15));
-
- increase_capacity_by += part!(PartType::Hub).energy_capacity;
-
- let packet = Packet::DespawnPart { id: child.index() };
-
- packet_send.send(WsEvent::Broadcast {
- message: packet.into(),
- });
-
- let packet = Packet::SpawnPart {
- id: child.index(),
- part: Part {
- part_type: PartType::Hub,
- transform: proto_transform!(transform),
- flags: proto_part_flags!(part_flags),
- },
- };
-
- packet_send.send(WsEvent::Broadcast {
- message: packet.into(),
- });
- }
- PlanetType::Moon => {
- *part_type = PartType::LandingThruster;
- *mass_prop = AdditionalMassProperties::MassProperties(MassProperties {
- local_center_of_mass: Vec2::new(0.0, 0.0),
- mass: part!(PartType::LandingThruster).mass,
- principal_inertia: 7.5,
- });
- let (mut collider, mut transform, _) =
- collider_query.get_mut(*children.first().unwrap()).unwrap();
- *collider = Collider::cuboid(0.5, 0.375);
- *transform = Transform::from_xyz(0., 0.125, 0.);
- //commands.get_entity(module_entity).unwrap().remove::<CanAttach>();
- let joint = PrismaticJointBuilder::new(Vec2::new(0., 1.))
- .local_anchor1(Vec2::new(0., 0.))
- .local_anchor2(Vec2::new(0., 0.))
- .set_motor(0., 0., 3000., 3000.)
- .limits([0., 1.])
- .build();
- let mut suspension = commands.spawn(PartBundle {
- transform: TransformBundle::from(*module_transform),
- part_type: PartType::LandingThrusterSuspension,
- flags: PartFlags { attached: false },
- });
- 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,
- }))
- .insert(Attach {
- associated_player: attach.associated_player,
- parent: Some(module_entity),
- children: [None, None, None, None],
- });
- attach.children[2] = Some(suspension.id());
-
- increase_capacity_by += part!(PartType::LandingThruster).energy_capacity;
-
- let packet = Packet::DespawnPart { id: child.index() };
-
- packet_send.send(WsEvent::Broadcast {
- message: packet.into(),
- });
-
- let packet = Packet::SpawnPart {
- id: child.index(),
- part: Part {
- part_type: PartType::LandingThruster,
- transform: proto_transform!(transform),
- flags: proto_part_flags!(part_flags),
- },
- };
-
- packet_send.send(WsEvent::Broadcast {
- message: packet.into(),
- });
-
- let packet = Packet::SpawnPart {
- id: suspension.id().index(),
- part: Part {
- part_type: PartType::LandingThrusterSuspension,
- transform: proto_transform!(transform),
- flags: proto_part_flags!(part_flags),
- },
- };
-
- packet_send.send(WsEvent::Broadcast {
- message: packet.into(),
- });
- }
- _ => {}
- }
- }
- if *part_type != PartType::LandingThruster {
- increase_capacity_by += convert_modules_recursive(
- commands,
- planet_type,
- attach.clone(),
- attached_query,
- collider_query,
- packet_send,
- );
- }
- }
- increase_capacity_by
-}
-
-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,
- ),
- (Without<PlanetType>, Without<Player>),
- >,
- mut player_query: Query<
- (
- Entity,
- &mut Player,
- &Transform,
- &Velocity,
- &mut Attach,
- &mut PartFlags,
- ),
- Without<PlanetType>,
- >,
-) {
- let joints = rapier_context.entity2impulse_joint();
- let mut detach_list = Vec::new();
- for (entity, part_type, _, attach, _, _, _, mut flags) in &mut attached_query {
- if *part_type == PartType::LandingThrusterSuspension {
- continue;
- }
- let handle = joints.get(&entity).unwrap();
- let joint = rapier_context.impulse_joints.get(*handle).unwrap();
- if joint.impulses.magnitude() > 0.2 {
- flags.attached = false;
- detach_list.push((entity, *part_type, attach.clone()));
- }
- }
- for (entity, _part_type, attach) in detach_list {
- let lost_energy_capacity = detach_recursive(
- &mut commands,
- entity,
- &mut attached_query,
- &mut player_query,
- );
- let id = attach.associated_player.unwrap();
- let mut player = player_query.get_mut(id).unwrap().1;
- player.energy_capacity -= lost_energy_capacity;
- player.energy = std::cmp::min(player.energy, player.energy_capacity);
- }
-}
-
-fn save_eligibility(
- rapier_context: Res<RapierContext>,
- planet_query: Query<(Entity, &PlanetType, &Children)>,
- attached_query: Query<&Attach, (Without<PlanetType>, Without<Player>)>,
- collider_query: Query<(&Collider, &Parent), (Without<Player>, Without<Attach>)>,
- mut player_query: Query<&mut Player>,
- mut packet_send: EventWriter<WsEvent>,
-) {
- let mut player_eligibilities = HashMap::new();
- for (_planet_entity, _planet_type, children) in &planet_query {
- for (entity1, entity2, intersecting) in
- rapier_context.intersection_pairs_with(*children.first().unwrap())
- {
- if intersecting {
- let other = if *children.first().unwrap() == entity1 {
- entity2
- } else {
- entity1
- };
- let player_entity = if player_query.contains(other) {
- other
- } else if attached_query.contains(other) {
- attached_query
- .get(other)
- .unwrap()
- .associated_player
- .unwrap()
- } else if collider_query.contains(other) {
- let parent = collider_query.get(other).unwrap().1.get();
- if attached_query.contains(parent) {
- attached_query
- .get(parent)
- .unwrap()
- .associated_player
- .unwrap()
- } else {
- continue;
- }
- } else {
- continue;
- };
- let player = player_query.get(player_entity).unwrap();
- if !player.save_eligibility {
- if player_eligibilities.contains_key(&player_entity) {
- player_eligibilities.remove(&player_entity);
- }
- player_eligibilities.insert(player_entity, true);
- }
- } else {
- let other = if *children.first().unwrap() == entity1 {
- entity2
- } else {
- entity1
- };
- if player_query.contains(other) {
- let mut player = player_query.get_mut(other).unwrap();
- if player.save_eligibility
- && !(player_eligibilities.contains_key(&other)
- && *player_eligibilities.get(&other).unwrap())
- {
- player.save_eligibility = false;
- player_eligibilities.insert(other, false);
- }
- }
- }
- }
- }
- for (other, eligible) in player_eligibilities.iter() {
- let mut player = player_query.get_mut(*other).unwrap();
- player.save_eligibility = *eligible;
- let packet = Packet::SaveEligibility {
- eligible: *eligible,
- };
-
- packet_send.send(WsEvent::Send {
- to: player.addr,
- message: packet.into(),
- });
- }
-}
-
fn on_close(
player_query: Query<(Entity, &Player, &Attach)>,
attached_query: Query<&Attach, With<PartType>>,
@@ 1769,35 764,6 @@ fn on_close(
}
}
-fn despawn_module_tree(
- commands: &mut Commands,
- attach: &Attach,
- attached_query: &Query<&Attach, With<PartType>>,
- part_query: &Query<&PartType>,
- packets: &mut Vec<WsEvent>,
-) {
- for child in attach.children.iter().flatten() {
- commands.entity(*child).despawn_recursive();
- let packet = Packet::DespawnPart {
- id: (*child).index(),
- };
-
- packets.push(WsEvent::Broadcast {
- message: packet.into(),
- });
-
- let attach = match attached_query.get(*child) {
- Ok(s) => s,
- Err(_) => match part_query.get(*child) {
- Ok(_) => {
- continue;
- }
- Err(e) => panic!("{}", e),
- },
- };
- despawn_module_tree(commands, attach, attached_query, part_query, packets);
- }
-}
fn send_player_energy(player_query: Query<&Player>, mut packet_send: EventWriter<WsEvent>) {
for player in &player_query {
@@ 1964,168 930,6 @@ fn player_input_update(
}
}
}
-fn search_thrusters(
- input: Input,
- attach: Attach,
- p_transform: Transform,
- energy: &mut u32,
- attached_query: &mut Query<
- (&Attach, &PartType, &mut ExternalForce, &Transform),
- Without<Player>,
- >,
-) {
- let p_angle = p_transform.rotation.to_euler(EulerRot::ZYX).0;
- for child in attach.children.iter().flatten() {
- let (attach, part_type, mut force, transform) = attached_query.get_mut(*child).unwrap();
- let angle = transform.rotation.to_euler(EulerRot::ZYX).0;
- let relative_angle = (p_angle - angle).abs();
- let relative_pos = transform.translation - p_transform.translation;
- let relative_pos = Vec2::new(
- relative_pos
- .x
- .mul_add((-p_angle).cos(), -relative_pos.y * (-p_angle).sin()),
- relative_pos
- .x
- .mul_add((-p_angle).sin(), relative_pos.y * (-p_angle).cos()),
- );
-
- let mut force_mult = 0.;
- let mut energy_lose_by = 0;
- if *part_type == PartType::LandingThruster {
- force_mult = part!(PartType::LandingThruster).thruster_force;
- energy_lose_by = part!(PartType::LandingThruster).thruster_energy;
- }
- if input.up && 3. * PI / 4. < relative_angle && relative_angle < 5. * PI / 4. {
- let thruster_force = ExternalForce::at_point(
- Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
- transform.translation.xy(),
- transform.translation.xy(),
- );
- force.force += thruster_force.force;
- force.torque += thruster_force.torque;
- *energy -= energy_lose_by;
- }
- if input.down
- && ((0. < relative_angle && relative_angle < PI / 4.)
- || (7. * PI / 4. < relative_angle && relative_angle < 2. * PI))
- {
- let thruster_force = ExternalForce::at_point(
- Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
- transform.translation.xy(),
- transform.translation.xy(),
- );
- force.force += thruster_force.force;
- force.torque += thruster_force.torque;
- *energy -= energy_lose_by;
- }
- if input.left {
- if 3. * PI / 4. < relative_angle
- && relative_angle < 5. * PI / 4.
- && relative_pos.x > 0.48
- {
- let thruster_force = ExternalForce::at_point(
- Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
- transform.translation.xy(),
- transform.translation.xy(),
- );
- force.force += thruster_force.force;
- force.torque += thruster_force.torque;
- *energy -= energy_lose_by;
- }
- if ((0. < relative_angle && relative_angle < PI / 4.)
- || (7. * PI / 4. < relative_angle && relative_angle < 2. * PI))
- && relative_pos.x < -0.48
- {
- let thruster_force = ExternalForce::at_point(
- Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
- transform.translation.xy(),
- transform.translation.xy(),
- );
- force.force += thruster_force.force;
- force.torque += thruster_force.torque;
- *energy -= energy_lose_by;
- }
- if PI / 4. < relative_angle && relative_angle < 3. * PI / 4. && relative_pos.y < -0.48 {
- let thruster_force = ExternalForce::at_point(
- Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
- transform.translation.xy(),
- transform.translation.xy(),
- );
- force.force += thruster_force.force;
- force.torque += thruster_force.torque;
- *energy -= energy_lose_by;
- }
- if 5. * PI / 4. < relative_angle
- && relative_angle < 7. * PI / 4.
- && relative_pos.y > 0.48
- {
- let thruster_force = ExternalForce::at_point(
- Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
- transform.translation.xy(),
- transform.translation.xy(),
- );
- force.force += thruster_force.force;
- force.torque += thruster_force.torque;
- *energy -= energy_lose_by;
- }
- }
- if input.right {
- if ((0. < relative_angle && relative_angle < PI / 4.)
- || (7. * PI / 4. < relative_angle && relative_angle < 2. * PI))
- && relative_pos.x > 0.48
- {
- let thruster_force = ExternalForce::at_point(
- Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
- transform.translation.xy(),
- transform.translation.xy(),
- );
- force.force += thruster_force.force;
- force.torque += thruster_force.torque;
- *energy -= energy_lose_by;
- }
- if 3. * PI / 4. < relative_angle
- && relative_angle < 5. * PI / 4.
- && relative_pos.x < -0.48
- {
- let thruster_force = ExternalForce::at_point(
- Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
- transform.translation.xy(),
- transform.translation.xy(),
- );
- force.force += thruster_force.force;
- force.torque += thruster_force.torque;
- *energy -= energy_lose_by;
- }
- if PI / 4. < relative_angle && relative_angle < 3. * PI / 4. && relative_pos.y > 0.48 {
- let thruster_force = ExternalForce::at_point(
- Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
- transform.translation.xy(),
- transform.translation.xy(),
- );
- force.force += thruster_force.force;
- force.torque += thruster_force.torque;
- *energy -= energy_lose_by;
- }
- if 5. * PI / 4. < relative_angle
- && relative_angle < 7. * PI / 4.
- && relative_pos.y < -0.48
- {
- let thruster_force = ExternalForce::at_point(
- Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
- transform.translation.xy(),
- transform.translation.xy(),
- );
- force.force += thruster_force.force;
- force.torque += thruster_force.torque;
- *energy -= energy_lose_by;
- }
- }
-
- if *part_type != PartType::LandingThruster && *energy >= energy_lose_by {
- search_thrusters(input, attach.clone(), p_transform, energy, attached_query);
- }
- }
-}
fn gravity_update(
mut part_query: Query<
A server/src/module/component.rs => server/src/module/component.rs +78 -0
@@ 0,0 1,78 @@
+use bevy::prelude::*;
+use serde::{Deserialize, Serialize};
+use starkingdoms_common::PartType as c_PartType;
+
+#[derive(Component, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)]
+pub enum PartType {
+ Placeholder,
+ Hearty,
+ Cargo,
+ Hub,
+ LandingThruster,
+ LandingThrusterSuspension,
+}
+impl From<PartType> for c_PartType {
+ fn from(value: PartType) -> Self {
+ match value {
+ PartType::Placeholder => c_PartType::Placeholder,
+ PartType::Hearty => c_PartType::Hearty,
+ PartType::Cargo => c_PartType::Cargo,
+ PartType::Hub => c_PartType::Hub,
+ PartType::LandingThruster => c_PartType::LandingThruster,
+ PartType::LandingThrusterSuspension => c_PartType::LandingThrusterSuspension,
+ }
+ }
+}
+impl From<c_PartType> for PartType {
+ fn from(value: c_PartType) -> Self {
+ match value {
+ c_PartType::Placeholder => PartType::Placeholder,
+ c_PartType::Hearty => PartType::Hearty,
+ c_PartType::Cargo => PartType::Cargo,
+ c_PartType::Hub => PartType::Hub,
+ c_PartType::LandingThruster => PartType::LandingThruster,
+ c_PartType::LandingThrusterSuspension => PartType::LandingThrusterSuspension,
+ }
+ }
+}
+
+#[derive(Component, Clone, Debug)]
+pub struct Attach {
+ pub associated_player: Option<Entity>,
+ pub parent: Option<Entity>,
+ pub children: [Option<Entity>; 4],
+}
+
+#[derive(Component, Clone, Debug)]
+pub struct LooseAttach {
+ pub children: [Option<Entity>; 4],
+}
+
+#[derive(Component, Clone, Copy, PartialEq, Debug)]
+pub struct CanAttach(pub u8); // each bit means a slot able to attach to
+
+#[derive(Component, Copy, Clone)]
+pub struct PartFlags {
+ pub attached: bool,
+}
+
+#[derive(Bundle)]
+pub struct PartBundle {
+ pub transform: TransformBundle,
+ pub part_type: PartType,
+ pub flags: PartFlags,
+}
+
+#[derive(Resource)]
+pub struct ModuleTimer(pub Timer);
+impl ModuleTimer {
+ pub fn new() -> Self {
+ Self(Timer::from_seconds(0.3, TimerMode::Repeating))
+ }
+}
+impl Default for ModuleTimer {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
A server/src/module/mod.rs => server/src/module/mod.rs +666 -0
@@ 0,0 1,666 @@
+use std::f32::consts::PI;
+
+use bevy::{math::vec2, prelude::*};
+use bevy_rapier2d::prelude::*;
+use component::*;
+use rand::Rng;
+
+use crate::{capacity, config::StkConfig, part, planet::PlanetType, proto_part_flags, proto_transform, ws::WsEvent, Packet, Part, Player};
+
+pub mod thruster;
+pub mod component;
+pub mod save;
+
+pub fn module_spawn(
+ mut commands: Commands,
+ time: Res<Time>,
+ mut module_timer: ResMut<ModuleTimer>,
+ part_query: Query<&PartType, Without<Attach>>,
+ mut packet_send: EventWriter<WsEvent>,
+ server_config: Res<StkConfig>,
+) {
+ if module_timer.0.tick(time.delta()).just_finished()
+ && part_query.iter().count() < server_config.server.max_free_parts
+ {
+ 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 flags = PartFlags { attached: false };
+ let mut entity = commands.spawn(PartBundle {
+ part_type: PartType::Cargo,
+ transform: TransformBundle::from(transform),
+ flags,
+ });
+ entity
+ .insert(RigidBody::Dynamic)
+ .with_children(|children| {
+ children
+ .spawn(Collider::cuboid(0.375, 0.46875))
+ .insert(TransformBundle::from(Transform::from_xyz(0., 0.03125, 0.)));
+ })
+ .insert(AdditionalMassProperties::MassProperties(MassProperties {
+ 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(),
+ part: Part {
+ part_type: PartType::Cargo,
+ transform: proto_transform!(transform),
+ flags: proto_part_flags!(flags),
+ },
+ };
+
+ packet_send.send(WsEvent::Broadcast {
+ message: packet.into(),
+ });
+ }
+}
+
+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,
+ ),
+ (Without<PlanetType>, Without<Player>),
+ >,
+ player_query: &mut Query<
+ (
+ Entity,
+ &mut Player,
+ &Transform,
+ &Velocity,
+ &mut Attach,
+ &mut PartFlags,
+ ),
+ Without<PlanetType>,
+ >,
+) -> u32 {
+ let mut energy = 0;
+ let f_attach = if attached_query.contains(this) {
+ attached_query.get(this).unwrap().3.clone()
+ } else {
+ player_query.get(this).unwrap().4.clone()
+ };
+ for child in f_attach.children.iter().flatten() {
+ energy += detach_recursive(commands, *child, attached_query, player_query);
+ }
+ let (entity, part_type, attach, mut flags) = if attached_query.contains(this) {
+ let (entity, part_type, _, attach, _, _, _, flags) = attached_query.get_mut(this).unwrap();
+ (entity, part_type, attach, flags)
+ } else {
+ let (entity, _, _, _, attach, part_flags) = player_query.get_mut(this).unwrap();
+ (entity, &PartType::Hearty, attach, part_flags)
+ };
+ energy += capacity!(*part_type);
+ commands.entity(entity).remove::<Attach>();
+ flags.attached = false;
+ if *part_type == PartType::LandingThrusterSuspension {
+ let parent = attach.parent.unwrap();
+ let parent_attach = attached_query.get(parent).unwrap().3;
+ commands.entity(parent).insert(LooseAttach {
+ children: parent_attach.children,
+ });
+ } else {
+ commands.entity(entity).remove::<ImpulseJoint>();
+ }
+ let parent = f_attach.parent.unwrap();
+ if attached_query.contains(parent) {
+ let mut parent_attach = attached_query.get_mut(parent).unwrap().3;
+ let children = parent_attach.children;
+ for (i, child) in children.iter().enumerate() {
+ if let Some(child) = child {
+ if *child == entity {
+ parent_attach.children[i] = None;
+ }
+ }
+ }
+ } else if player_query.contains(parent) {
+ let mut parent_attach = player_query.get_mut(parent).unwrap().4;
+ for (i, child) in parent_attach.children.clone().iter().enumerate() {
+ if let Some(child) = child {
+ if *child == entity {
+ parent_attach.children[i] = None;
+ }
+ }
+ }
+ }
+ energy
+}
+
+pub fn despawn_module_tree(
+ commands: &mut Commands,
+ attach: &Attach,
+ attached_query: &Query<&Attach, With<PartType>>,
+ part_query: &Query<&PartType>,
+ packets: &mut Vec<WsEvent>,
+) {
+ for child in attach.children.iter().flatten() {
+ commands.entity(*child).despawn_recursive();
+ let packet = Packet::DespawnPart {
+ id: (*child).index(),
+ };
+
+ packets.push(WsEvent::Broadcast {
+ message: packet.into(),
+ });
+
+ let attach = match attached_query.get(*child) {
+ Ok(s) => s,
+ Err(_) => match part_query.get(*child) {
+ Ok(_) => {
+ continue;
+ }
+ Err(e) => panic!("{}", e),
+ },
+ };
+ despawn_module_tree(commands, attach, attached_query, part_query, packets);
+ }
+}
+
+pub fn attach_on_module_tree(
+ 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,
+ ),
+ (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>,
+ >,
+) -> bool {
+ let mut ret = false;
+
+ let attach = if attached_query.contains(this) {
+ attached_query.get(this).unwrap().3
+ } else {
+ player_query.get(this).unwrap().4
+ };
+ for this in attach.clone().children.iter().flatten() {
+ let module = part_query.get(select).unwrap();
+ 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,
+ )
+ } else {
+ false
+ };
+ }
+ let is_player = player_query.contains(this);
+ let (entity, transform, mut attach, velocity, can_attach) = if attached_query.contains(this) {
+ let (entity, _, transform, attach, velocity, can_attach, _, _) =
+ attached_query.get_mut(this).unwrap();
+ (entity, *transform, attach, velocity, can_attach)
+ } else {
+ let (entity, _, transform, velocity, attach, _) = player_query.get_mut(this).unwrap();
+ (entity, *transform, attach, velocity, Some(&CanAttach(15)))
+ };
+
+ let p_pos = transform.translation;
+ let (rel_x, rel_y) = (p_pos.x - x, p_pos.y - y);
+ let angle = transform.rotation.to_euler(EulerRot::ZYX).0;
+ let (rel_x, rel_y) = (
+ rel_x * (-angle).cos() - rel_y * (-angle).sin(),
+ rel_x * (-angle).sin() + rel_y * (-angle).cos(),
+ );
+ let mut module = part_query.get_mut(select).unwrap();
+
+ let attachable = match can_attach {
+ Some(s) => s.0,
+ None => return false,
+ };
+ let mut attachment_slot = 5;
+ let mut offset = Vec2::ZERO;
+ let mut angle_offset = 0.;
+
+ if attach.children[2].is_none() // top
+ && attachable & 4 != 0
+ && -(rel_x.abs()) + rel_y > 0.0
+ && rel_x.abs() + rel_y < 1.0
+ {
+ attachment_slot = 2;
+ offset = Vec2::new(0., -1.06);
+ angle_offset = 0.;
+ } else if attach.children[0].is_none() // bottom
+ && rel_x.abs() + rel_y < 0.0
+ && -(rel_x.abs()) + rel_y > -1.0
+ {
+ attachment_slot = 0;
+ offset = Vec2::new(0., 1.06);
+ angle_offset = PI;
+ } else if attach.children[1].is_none() // left
+ && rel_x + rel_y.abs() < 0.0
+ && rel_x - rel_y.abs() > -1.0
+ {
+ attachment_slot = 1;
+ offset = Vec2::new(1.06, 0.);
+ angle_offset = PI / 2.;
+ } else if attach.children[3].is_none() // right
+ && rel_x - rel_y.abs() > 0.0
+ && rel_x + rel_y.abs() < 1.0
+ {
+ attachment_slot = 3;
+ offset = Vec2::new(-1.06, 0.);
+ angle_offset = -PI / 2.;
+ }
+ let new_transform = Transform::from_xyz(
+ p_pos.x + offset.x * angle.cos() - offset.y * angle.sin(),
+ p_pos.y + offset.x * angle.sin() + offset.y * angle.cos(),
+ 0.,
+ )
+ .with_rotation(Quat::from_euler(
+ EulerRot::ZYX,
+ angle + angle_offset,
+ 0.,
+ 0.,
+ ));
+ if attachment_slot != 5 {
+ let associated_player = if is_player {
+ Some(entity)
+ } else {
+ attach.associated_player
+ };
+ *module.2 = new_transform;
+ module.3.linvel = velocity.linvel;
+ let joint = FixedJointBuilder::new()
+ .local_anchor1(offset)
+ .local_basis1(angle_offset);
+ let mut children = [None, None, None, None];
+ if let Some(loose_attach) = module.4 {
+ if *module.1 == PartType::LandingThruster {
+ commands
+ .entity(loose_attach.children[2].unwrap())
+ .insert(Attach {
+ associated_player,
+ parent: Some(module.0),
+ children: [None, None, None, None],
+ });
+ }
+ children = loose_attach.children;
+ commands.entity(entity).remove::<LooseAttach>();
+ }
+ let mut module_entity = commands.entity(module.0);
+ module_entity.insert(ImpulseJoint::new(entity, joint));
+ module_entity.insert(Attach {
+ associated_player,
+ parent: Some(entity),
+ children,
+ });
+ module_entity.insert(CanAttach(15));
+ attach.children[attachment_slot] = Some(module.0);
+ module.5.attached = true;
+ player_query.get_mut(player_id).unwrap().1.energy_capacity += capacity!(*module.1);
+ if *module.1 == PartType::LandingThruster {
+ let loose_attach = module.4.unwrap().clone();
+ let mut transform = part_query
+ .get_mut(loose_attach.children[2].unwrap())
+ .unwrap()
+ .2;
+ *transform = new_transform;
+ }
+ ret = true;
+ }
+
+ ret
+}
+
+pub fn convert_modules(
+ mut commands: Commands,
+ 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,
+ ),
+ Without<Player>,
+ >,
+ mut collider_query: Query<
+ (&mut Collider, &mut Transform, &Parent),
+ (Without<Player>, Without<Attach>),
+ >,
+ mut packet_send: EventWriter<WsEvent>,
+) {
+ for (_planet_entity, planet_type, children) in &planet_query {
+ for (entity1, entity2, intersecting) in
+ rapier_context.intersection_pairs_with(*children.first().unwrap())
+ {
+ if intersecting {
+ let other = if *children.first().unwrap() == entity1 {
+ entity2
+ } else {
+ entity1
+ };
+ let player_entity = if player_query.contains(other) {
+ other
+ } else if attached_query.contains(other) {
+ attached_query
+ .get(other)
+ .unwrap()
+ .2
+ .associated_player
+ .unwrap()
+ } else if collider_query.contains(other) {
+ let parent = collider_query.get(other).unwrap().2.get();
+ if attached_query.contains(parent) {
+ attached_query
+ .get(parent)
+ .unwrap()
+ .2
+ .associated_player
+ .unwrap()
+ } else {
+ continue;
+ }
+ } else {
+ continue;
+ };
+ let mut player = player_query.get_mut(player_entity).unwrap();
+ let increase_capacity_by = convert_modules_recursive(
+ &mut commands,
+ *planet_type,
+ player.0.clone(),
+ &mut attached_query,
+ &mut collider_query,
+ &mut packet_send,
+ );
+ player.1.energy_capacity += increase_capacity_by;
+ player.1.energy = player.1.energy_capacity;
+ }
+ }
+ }
+}
+
+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,
+ ),
+ Without<Player>,
+ >,
+ collider_query: &mut Query<
+ (&mut Collider, &mut Transform, &Parent),
+ (Without<Player>, Without<Attach>),
+ >,
+ packet_send: &mut EventWriter<WsEvent>,
+) -> u32 {
+ let mut increase_capacity_by = 0;
+ for child in attach.children.iter().flatten() {
+ let (
+ module_entity,
+ mut part_type,
+ mut attach,
+ mut mass_prop,
+ children,
+ module_transform,
+ part_flags,
+ ) = attached_query.get_mut(*child).unwrap();
+ if *part_type == PartType::Cargo {
+ match planet_type {
+ PlanetType::Mars => {
+ *part_type = PartType::Hub;
+ *mass_prop = AdditionalMassProperties::MassProperties(MassProperties {
+ local_center_of_mass: Vec2::new(0.0, 0.0),
+ mass: part!(PartType::Hub).mass,
+ principal_inertia: 7.5,
+ });
+ let (mut collider, mut transform, _) =
+ collider_query.get_mut(*children.first().unwrap()).unwrap();
+ *collider = Collider::cuboid(0.5, 0.5);
+ *transform = Transform::from_xyz(0., 0., 0.);
+ commands
+ .get_entity(module_entity)
+ .unwrap()
+ .remove::<CanAttach>();
+ commands
+ .get_entity(module_entity)
+ .unwrap()
+ .insert(CanAttach(15));
+
+ increase_capacity_by += part!(PartType::Hub).energy_capacity;
+
+ let packet = Packet::DespawnPart { id: child.index() };
+
+ packet_send.send(WsEvent::Broadcast {
+ message: packet.into(),
+ });
+
+ let packet = Packet::SpawnPart {
+ id: child.index(),
+ part: Part {
+ part_type: PartType::Hub,
+ transform: proto_transform!(transform),
+ flags: proto_part_flags!(part_flags),
+ },
+ };
+
+ packet_send.send(WsEvent::Broadcast {
+ message: packet.into(),
+ });
+ }
+ PlanetType::Moon => {
+ *part_type = PartType::LandingThruster;
+ *mass_prop = AdditionalMassProperties::MassProperties(MassProperties {
+ local_center_of_mass: Vec2::new(0.0, 0.0),
+ mass: part!(PartType::LandingThruster).mass,
+ principal_inertia: 7.5,
+ });
+ let (mut collider, mut transform, _) =
+ collider_query.get_mut(*children.first().unwrap()).unwrap();
+ *collider = Collider::cuboid(0.5, 0.375);
+ *transform = Transform::from_xyz(0., 0.125, 0.);
+ //commands.get_entity(module_entity).unwrap().remove::<CanAttach>();
+ let joint = PrismaticJointBuilder::new(Vec2::new(0., 1.))
+ .local_anchor1(Vec2::new(0., 0.))
+ .local_anchor2(Vec2::new(0., 0.))
+ .set_motor(0., 0., 3000., 3000.)
+ .limits([0., 1.])
+ .build();
+ let mut suspension = commands.spawn(PartBundle {
+ transform: TransformBundle::from(*module_transform),
+ part_type: PartType::LandingThrusterSuspension,
+ flags: PartFlags { attached: false },
+ });
+ 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,
+ }))
+ .insert(Attach {
+ associated_player: attach.associated_player,
+ parent: Some(module_entity),
+ children: [None, None, None, None],
+ });
+ attach.children[2] = Some(suspension.id());
+
+ increase_capacity_by += part!(PartType::LandingThruster).energy_capacity;
+
+ let packet = Packet::DespawnPart { id: child.index() };
+
+ packet_send.send(WsEvent::Broadcast {
+ message: packet.into(),
+ });
+
+ let packet = Packet::SpawnPart {
+ id: child.index(),
+ part: Part {
+ part_type: PartType::LandingThruster,
+ transform: proto_transform!(transform),
+ flags: proto_part_flags!(part_flags),
+ },
+ };
+
+ packet_send.send(WsEvent::Broadcast {
+ message: packet.into(),
+ });
+
+ let packet = Packet::SpawnPart {
+ id: suspension.id().index(),
+ part: Part {
+ part_type: PartType::LandingThrusterSuspension,
+ transform: proto_transform!(transform),
+ flags: proto_part_flags!(part_flags),
+ },
+ };
+
+ packet_send.send(WsEvent::Broadcast {
+ message: packet.into(),
+ });
+ }
+ _ => {}
+ }
+ }
+ if *part_type != PartType::LandingThruster {
+ increase_capacity_by += convert_modules_recursive(
+ commands,
+ planet_type,
+ attach.clone(),
+ attached_query,
+ collider_query,
+ packet_send,
+ );
+ }
+ }
+ increase_capacity_by
+}
+
+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,
+ ),
+ (Without<PlanetType>, Without<Player>),
+ >,
+ mut player_query: Query<
+ (
+ Entity,
+ &mut Player,
+ &Transform,
+ &Velocity,
+ &mut Attach,
+ &mut PartFlags,
+ ),
+ Without<PlanetType>,
+ >,
+) {
+ let joints = rapier_context.entity2impulse_joint();
+ let mut detach_list = Vec::new();
+ for (entity, part_type, _, attach, _, _, _, mut flags) in &mut attached_query {
+ if *part_type == PartType::LandingThrusterSuspension {
+ continue;
+ }
+ let handle = joints.get(&entity).unwrap();
+ let joint = rapier_context.impulse_joints.get(*handle).unwrap();
+ if joint.impulses.magnitude() > 0.2 {
+ flags.attached = false;
+ detach_list.push((entity, *part_type, attach.clone()));
+ }
+ }
+ for (entity, _part_type, attach) in detach_list {
+ let lost_energy_capacity = detach_recursive(
+ &mut commands,
+ entity,
+ &mut attached_query,
+ &mut player_query,
+ );
+ let id = attach.associated_player.unwrap();
+ let mut player = player_query.get_mut(id).unwrap().1;
+ player.energy_capacity -= lost_energy_capacity;
+ player.energy = std::cmp::min(player.energy, player.energy_capacity);
+ }
+}
A server/src/module/save.rs => server/src/module/save.rs +343 -0
@@ 0,0 1,343 @@
+use std::{collections::HashMap, f32::consts::PI};
+
+use bevy::{math::vec2, prelude::*};
+use bevy_rapier2d::prelude::*;
+use starkingdoms_common::SaveModule;
+
+use crate::{capacity, mass, planet::PlanetType, ws::WsEvent, Attach, CanAttach, LooseAttach, Packet, PartBundle, PartFlags, PartType, Player};
+
+pub fn load_savefile(
+ commands: &mut Commands,
+ transform: Transform,
+ player_id: Entity,
+ parent: Entity,
+ children: Vec<Option<SaveModule>>,
+ 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,
+) -> [Option<Entity>; 4] {
+ let mut ret = [None, None, None, None];
+ for (i, child) in children.iter().enumerate() {
+ if let Some(child) = child {
+ let part_type = PartType::from(child.part_type);
+ //let attachable = can_attach != None;
+
+ let p_pos = transform.translation;
+ let angle = transform.rotation.to_euler(EulerRot::ZYX).0;
+ let mut offset = Vec2::ZERO;
+ let mut angle_offset = 0.;
+ if i == 2 {
+ //offset = Vec2::new(53., -53.);
+ offset = Vec2::new(0., -1.06);
+ angle_offset = 0.;
+ } else if i == 0 {
+ //offset = Vec2::new(-53., 53.);
+ offset = Vec2::new(0., 1.06);
+ angle_offset = PI;
+ } else if i == 1 {
+ //offset = Vec2::new(53., 53.);
+ offset = Vec2::new(1.06, 0.);
+ angle_offset = PI / 2.;
+ } else if i == 3 {
+ //offset = Vec2::new(-53., 53.);
+ offset = Vec2::new(-1.06, 0.);
+ angle_offset = -PI / 2.;
+ }
+
+ let transform = Transform::from_xyz(
+ p_pos.x + offset.x * angle.cos() - offset.y * angle.sin(),
+ p_pos.y + offset.x * angle.sin() + offset.y * angle.cos(),
+ 0.,
+ )
+ .with_rotation(Quat::from_euler(
+ EulerRot::ZYX,
+ angle + angle_offset,
+ 0.,
+ 0.,
+ ));
+ let module_id = {
+ let module = commands.spawn(PartBundle {
+ transform: TransformBundle::from(transform),
+ part_type: child.part_type.into(),
+ flags: PartFlags { attached: true },
+ });
+ module.id()
+ };
+
+ let children = if part_type != PartType::LandingThruster {
+ load_savefile(
+ commands,
+ transform,
+ player_id,
+ module_id,
+ child.children.clone(),
+ attached_query,
+ part_query,
+ player_query,
+ player_comp,
+ )
+ } else {
+ [None, None, None, None]
+ };
+
+ let mut module = commands.entity(module_id);
+
+ module.insert(Attach {
+ associated_player: Some(player_id),
+ parent: Some(parent),
+ children,
+ });
+ //module.5.attached = true;
+ ret[i] = Some(module.id());
+
+ module
+ .insert(RigidBody::Dynamic)
+ .with_children(|children| {
+ children
+ .spawn(if part_type == PartType::Cargo {
+ Collider::cuboid(0.375, 0.46875)
+ } else if part_type == PartType::Hub {
+ Collider::cuboid(0.5, 0.5)
+ } else if part_type == PartType::LandingThruster {
+ Collider::cuboid(0.5, 0.375)
+ } else {
+ Collider::cuboid(0.5, 0.5)
+ })
+ .insert(TransformBundle::from(Transform::from_xyz(
+ 0.,
+ if part_type == PartType::Cargo {
+ 0.03125
+ } else if part_type == PartType::Hub {
+ 0.
+ } else if part_type == PartType::LandingThruster {
+ 0.125
+ } else {
+ 0.
+ },
+ 0.,
+ )));
+ })
+ .insert(AdditionalMassProperties::MassProperties(MassProperties {
+ 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));
+ }
+
+ let joint = FixedJointBuilder::new()
+ .local_anchor1(vec2(offset.x, offset.y))
+ .local_basis1(angle_offset);
+
+ module.insert(ImpulseJoint::new(parent, joint));
+
+ if part_type == PartType::LandingThruster {
+ let joint = PrismaticJointBuilder::new(Vec2::new(0., 1.))
+ .set_motor(0., 0., 3000., 3000.)
+ .limits([0., 1.])
+ .build();
+ let mut suspension = commands.spawn(PartBundle {
+ transform: TransformBundle::from(
+ Transform::from_xyz(
+ p_pos.x + offset.x * angle.cos() - offset.y * angle.sin(),
+ p_pos.y + offset.x * angle.sin() + offset.y * angle.cos(),
+ 0.,
+ )
+ .with_rotation(Quat::from_euler(
+ EulerRot::ZYX,
+ angle + angle_offset,
+ 0.,
+ 0.,
+ )),
+ ),
+ part_type: PartType::LandingThrusterSuspension,
+ flags: PartFlags { attached: true },
+ });
+ 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,
+ principal_inertia: 0.0000000000001,
+ }))
+ .insert(Attach {
+ associated_player: Some(player_id),
+ parent: Some(module_id),
+ children: [None, None, None, None],
+ });
+ let suspension_id = suspension.id();
+ let mut module = commands.entity(module_id);
+ module.remove::<Attach>();
+ module.insert(Attach {
+ associated_player: Some(player_id),
+ parent: Some(parent),
+ children: [None, None, Some(suspension_id), None],
+ });
+ }
+ player_comp.energy_capacity += capacity!(part_type);
+ }
+ }
+ ret
+}
+
+pub fn construct_save_data(
+ attach: Attach,
+ attached_query: &Query<
+ (
+ Entity,
+ &PartType,
+ &mut Transform,
+ &mut Attach,
+ &Velocity,
+ Option<&CanAttach>,
+ Option<&LooseAttach>,
+ &mut PartFlags,
+ ),
+ (Without<PlanetType>, Without<Player>),
+ >,
+) -> Vec<Option<SaveModule>> {
+ let mut modules = vec![None, None, None, None];
+ for (i, child) in attach.children.iter().enumerate() {
+ if let Some(child) = child {
+ let (_, part_type, _, attach, _, _, _, _) = attached_query.get(*child).unwrap();
+ if *part_type == PartType::LandingThrusterSuspension {
+ continue;
+ }
+ let child_save_module = construct_save_data(attach.clone(), attached_query);
+ modules[i] = Some(SaveModule {
+ part_type: (*part_type).into(),
+ children: child_save_module,
+ });
+ }
+ }
+ modules
+}
+
+pub fn save_eligibility(
+ rapier_context: Res<RapierContext>,
+ planet_query: Query<(Entity, &PlanetType, &Children)>,
+ attached_query: Query<&Attach, (Without<PlanetType>, Without<Player>)>,
+ collider_query: Query<(&Collider, &Parent), (Without<Player>, Without<Attach>)>,
+ mut player_query: Query<&mut Player>,
+ mut packet_send: EventWriter<WsEvent>,
+) {
+ let mut player_eligibilities = HashMap::new();
+ for (_planet_entity, _planet_type, children) in &planet_query {
+ for (entity1, entity2, intersecting) in
+ rapier_context.intersection_pairs_with(*children.first().unwrap())
+ {
+ if intersecting {
+ let other = if *children.first().unwrap() == entity1 {
+ entity2
+ } else {
+ entity1
+ };
+ let player_entity = if player_query.contains(other) {
+ other
+ } else if attached_query.contains(other) {
+ attached_query
+ .get(other)
+ .unwrap()
+ .associated_player
+ .unwrap()
+ } else if collider_query.contains(other) {
+ let parent = collider_query.get(other).unwrap().1.get();
+ if attached_query.contains(parent) {
+ attached_query
+ .get(parent)
+ .unwrap()
+ .associated_player
+ .unwrap()
+ } else {
+ continue;
+ }
+ } else {
+ continue;
+ };
+ let player = player_query.get(player_entity).unwrap();
+ if !player.save_eligibility {
+ if player_eligibilities.contains_key(&player_entity) {
+ player_eligibilities.remove(&player_entity);
+ }
+ player_eligibilities.insert(player_entity, true);
+ }
+ } else {
+ let other = if *children.first().unwrap() == entity1 {
+ entity2
+ } else {
+ entity1
+ };
+ if player_query.contains(other) {
+ let mut player = player_query.get_mut(other).unwrap();
+ if player.save_eligibility
+ && !(player_eligibilities.contains_key(&other)
+ && *player_eligibilities.get(&other).unwrap())
+ {
+ player.save_eligibility = false;
+ player_eligibilities.insert(other, false);
+ }
+ }
+ }
+ }
+ }
+ for (other, eligible) in player_eligibilities.iter() {
+ let mut player = player_query.get_mut(*other).unwrap();
+ player.save_eligibility = *eligible;
+ let packet = Packet::SaveEligibility {
+ eligible: *eligible,
+ };
+
+ packet_send.send(WsEvent::Send {
+ to: player.addr,
+ message: packet.into(),
+ });
+ }
+}
A server/src/module/thruster.rs => server/src/module/thruster.rs +168 -0
@@ 0,0 1,168 @@
+use std::f32::consts::PI;
+
+use bevy::prelude::*;
+use bevy_rapier2d::prelude::*;
+use crate::{part, Attach, Input, PartType, Player};
+
+pub fn search_thrusters(
+ input: Input,
+ attach: Attach,
+ p_transform: Transform,
+ energy: &mut u32,
+ attached_query: &mut Query<
+ (&Attach, &PartType, &mut ExternalForce, &Transform),
+ Without<Player>,
+ >,
+) {
+ let p_angle = p_transform.rotation.to_euler(EulerRot::ZYX).0;
+ for child in attach.children.iter().flatten() {
+ let (attach, part_type, mut force, transform) = attached_query.get_mut(*child).unwrap();
+ let angle = transform.rotation.to_euler(EulerRot::ZYX).0;
+ let relative_angle = (p_angle - angle).abs();
+ let relative_pos = transform.translation - p_transform.translation;
+ let relative_pos = Vec2::new(
+ relative_pos
+ .x
+ .mul_add((-p_angle).cos(), -relative_pos.y * (-p_angle).sin()),
+ relative_pos
+ .x
+ .mul_add((-p_angle).sin(), relative_pos.y * (-p_angle).cos()),
+ );
+
+ let mut force_mult = 0.;
+ let mut energy_lose_by = 0;
+ if *part_type == PartType::LandingThruster {
+ force_mult = part!(PartType::LandingThruster).thruster_force;
+ energy_lose_by = part!(PartType::LandingThruster).thruster_energy;
+ }
+ if input.up && 3. * PI / 4. < relative_angle && relative_angle < 5. * PI / 4. {
+ let thruster_force = ExternalForce::at_point(
+ Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
+ transform.translation.xy(),
+ transform.translation.xy(),
+ );
+ force.force += thruster_force.force;
+ force.torque += thruster_force.torque;
+ *energy -= energy_lose_by;
+ }
+ if input.down
+ && ((0. < relative_angle && relative_angle < PI / 4.)
+ || (7. * PI / 4. < relative_angle && relative_angle < 2. * PI))
+ {
+ let thruster_force = ExternalForce::at_point(
+ Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
+ transform.translation.xy(),
+ transform.translation.xy(),
+ );
+ force.force += thruster_force.force;
+ force.torque += thruster_force.torque;
+ *energy -= energy_lose_by;
+ }
+ if input.left {
+ if 3. * PI / 4. < relative_angle
+ && relative_angle < 5. * PI / 4.
+ && relative_pos.x > 0.48
+ {
+ let thruster_force = ExternalForce::at_point(
+ Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
+ transform.translation.xy(),
+ transform.translation.xy(),
+ );
+ force.force += thruster_force.force;
+ force.torque += thruster_force.torque;
+ *energy -= energy_lose_by;
+ }
+ if ((0. < relative_angle && relative_angle < PI / 4.)
+ || (7. * PI / 4. < relative_angle && relative_angle < 2. * PI))
+ && relative_pos.x < -0.48
+ {
+ let thruster_force = ExternalForce::at_point(
+ Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
+ transform.translation.xy(),
+ transform.translation.xy(),
+ );
+ force.force += thruster_force.force;
+ force.torque += thruster_force.torque;
+ *energy -= energy_lose_by;
+ }
+ if PI / 4. < relative_angle && relative_angle < 3. * PI / 4. && relative_pos.y < -0.48 {
+ let thruster_force = ExternalForce::at_point(
+ Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
+ transform.translation.xy(),
+ transform.translation.xy(),
+ );
+ force.force += thruster_force.force;
+ force.torque += thruster_force.torque;
+ *energy -= energy_lose_by;
+ }
+ if 5. * PI / 4. < relative_angle
+ && relative_angle < 7. * PI / 4.
+ && relative_pos.y > 0.48
+ {
+ let thruster_force = ExternalForce::at_point(
+ Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
+ transform.translation.xy(),
+ transform.translation.xy(),
+ );
+ force.force += thruster_force.force;
+ force.torque += thruster_force.torque;
+ *energy -= energy_lose_by;
+ }
+ }
+ if input.right {
+ if ((0. < relative_angle && relative_angle < PI / 4.)
+ || (7. * PI / 4. < relative_angle && relative_angle < 2. * PI))
+ && relative_pos.x > 0.48
+ {
+ let thruster_force = ExternalForce::at_point(
+ Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
+ transform.translation.xy(),
+ transform.translation.xy(),
+ );
+ force.force += thruster_force.force;
+ force.torque += thruster_force.torque;
+ *energy -= energy_lose_by;
+ }
+ if 3. * PI / 4. < relative_angle
+ && relative_angle < 5. * PI / 4.
+ && relative_pos.x < -0.48
+ {
+ let thruster_force = ExternalForce::at_point(
+ Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
+ transform.translation.xy(),
+ transform.translation.xy(),
+ );
+ force.force += thruster_force.force;
+ force.torque += thruster_force.torque;
+ *energy -= energy_lose_by;
+ }
+ if PI / 4. < relative_angle && relative_angle < 3. * PI / 4. && relative_pos.y > 0.48 {
+ let thruster_force = ExternalForce::at_point(
+ Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
+ transform.translation.xy(),
+ transform.translation.xy(),
+ );
+ force.force += thruster_force.force;
+ force.torque += thruster_force.torque;
+ *energy -= energy_lose_by;
+ }
+ if 5. * PI / 4. < relative_angle
+ && relative_angle < 7. * PI / 4.
+ && relative_pos.y < -0.48
+ {
+ let thruster_force = ExternalForce::at_point(
+ Vec2::new(-force_mult * angle.sin(), force_mult * angle.cos()),
+ transform.translation.xy(),
+ transform.translation.xy(),
+ );
+ force.force += thruster_force.force;
+ force.torque += thruster_force.torque;
+ *energy -= energy_lose_by;
+ }
+ }
+
+ if *part_type != PartType::LandingThruster && *energy >= energy_lose_by {
+ search_thrusters(input, attach.clone(), p_transform, energy, attached_query);
+ }
+ }
+}
M server/src/packet.rs => server/src/packet.rs +2 -1
@@ 14,10 14,11 @@ use std::fmt::{Display, Formatter};
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
-use crate::component::{PartType, PlanetType};
use serde::{Deserialize, Serialize};
use tungstenite::Message;
+use crate::{module::component::PartType, planet::PlanetType};
+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct ProtoTransform {
pub x: f32,
D server/src/part.rs => server/src/part.rs +0 -32
@@ 1,32 0,0 @@
-#[macro_export]
-macro_rules! mass {
- ($p:expr) => {
- match $crate::parts_config().parts.get(&$p) {
- Some(v) => v.mass,
- None => 1.0,
- }
- };
-}
-
-#[macro_export]
-macro_rules! capacity {
- ($p:expr) => {
- match $crate::parts_config().parts.get(&$p) {
- Some(v) => v.energy_capacity,
- None => 0,
- }
- };
-}
-
-#[macro_export]
-macro_rules! planet {
- ($t:expr) => {
- $crate::planets_config().planets.get(&$t).unwrap()
- };
-}
-#[macro_export]
-macro_rules! part {
- ($t:expr) => {
- $crate::parts_config().parts.get(&$t).unwrap()
- };
-}
A server/src/planet.rs => server/src/planet.rs +76 -0
@@ 0,0 1,76 @@
+use bevy::prelude::*;
+use bevy_rapier2d::prelude::*;
+use serde::{Deserialize, Serialize};
+
+use crate::planet;
+
+#[derive(Component, Clone, Copy, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
+pub enum PlanetType {
+ Earth,
+ Moon,
+ Mars,
+}
+
+#[derive(Bundle)]
+pub struct PlanetBundle {
+ pub planet_type: PlanetType,
+ pub transform: TransformBundle,
+}
+
+pub fn spawn_planets(mut commands: Commands) {
+ info!("Spawning planets");
+ let earth_pos = Transform::from_xyz(0.0, 0.0, 0.0);
+ commands
+ .spawn(PlanetBundle {
+ planet_type: PlanetType::Earth,
+ transform: TransformBundle::from(earth_pos),
+ })
+ .insert(Collider::ball(planet!(PlanetType::Earth).size))
+ .insert(AdditionalMassProperties::Mass(
+ planet!(PlanetType::Earth).mass,
+ ))
+ .insert(ReadMassProperties::default())
+ .with_children(|children| {
+ children
+ .spawn(Collider::ball(planet!(PlanetType::Earth).size + 0.3))
+ .insert(ActiveEvents::COLLISION_EVENTS)
+ .insert(Sensor);
+ })
+ .insert(RigidBody::Fixed);
+ let moon_pos = Transform::from_xyz(50.0, 20.0, 0.0);
+ commands
+ .spawn(PlanetBundle {
+ planet_type: PlanetType::Moon,
+ transform: TransformBundle::from(moon_pos),
+ })
+ .insert(Collider::ball(planet!(PlanetType::Moon).size))
+ .insert(AdditionalMassProperties::Mass(
+ planet!(PlanetType::Moon).mass,
+ ))
+ .insert(ReadMassProperties::default())
+ .with_children(|children| {
+ children
+ .spawn(Collider::ball(planet!(PlanetType::Moon).size + 0.1))
+ .insert(ActiveEvents::COLLISION_EVENTS)
+ .insert(Sensor);
+ })
+ .insert(RigidBody::Fixed);
+ let mars_pos = Transform::from_xyz(-50.0, 300.0, 0.0);
+ commands
+ .spawn(PlanetBundle {
+ planet_type: PlanetType::Mars,
+ transform: TransformBundle::from(mars_pos),
+ })
+ .insert(Collider::ball(planet!(PlanetType::Mars).size))
+ .insert(AdditionalMassProperties::Mass(
+ planet!(PlanetType::Mars).mass,
+ ))
+ .insert(ReadMassProperties::default())
+ .with_children(|children| {
+ children
+ .spawn(Collider::ball(planet!(PlanetType::Mars).size + 0.1))
+ .insert(ActiveEvents::COLLISION_EVENTS)
+ .insert(Sensor);
+ })
+ .insert(RigidBody::Fixed);
+}
A server/src/player/mod.rs => server/src/player/mod.rs +0 -0