~starkingdoms/starkingdoms

8a7b962dc400ea73bdc5d559015ccfb21c167f95 — ghostlyzsh 1 year, 11 months ago 261863e
game feels better
1 files changed, 213 insertions(+), 184 deletions(-)

M server/src/main.rs
M server/src/main.rs => server/src/main.rs +213 -184
@@ 43,9 43,9 @@ pub mod macros;
pub mod mathutil;
pub mod packet;

const SCALE: f32 = 10.0;
const CLIENT_SCALE: f32 = 50.;

const EARTH_SIZE: f32 = 1000.0;
const EARTH_SIZE: f32 = 20.0;
const MOON_SIZE: f32 = EARTH_SIZE / 4.;
const MARS_SIZE: f32 = EARTH_SIZE / 2.;



@@ 53,12 53,17 @@ const EARTH_MASS: f32 = 10000.0;
const MOON_MASS: f32 = EARTH_MASS / 30.;
const MARS_MASS: f32 = EARTH_MASS / 8.;

const GRAVITY: f32 = 0.02;
const GRAVITY: f32 = 0.0002;
const PART_HALF_SIZE: f32 = 25.0;

const HEARTY_THRUSTER_FORCE: f32 = 0.08;
const HEARTY_THRUSTER_FORCE: f32 = 0.3;
const LANDING_THRUSTER_FORCE: f32 = 5.;

const HEARTY_MASS: f32 = 1.;
const CARGO_MASS: f32 = 0.5;
const HUB_MASS: f32 = 1.;
const LANDING_THRUSTER_MASS: f32 = 0.9;

// maybe make this only cargo modules later
const FREE_MODULE_CAP: usize = 30;



@@ 88,7 93,7 @@ fn main() {
            ..Default::default()
        })
        .init_resource::<ModuleTimer>()
        .add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(SCALE))
        .add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(1.0))
        .add_plugins(StkTungsteniteServerPlugin)
        .add_systems(Startup, setup_integration_parameters)
        .add_systems(Startup, spawn_planets)


@@ 122,44 127,44 @@ fn spawn_planets(mut commands: Commands) {
            planet_type: PlanetType::Earth,
            transform: TransformBundle::from(earth_pos),
        })
        .insert(Collider::ball(EARTH_SIZE / SCALE))
        .insert(Collider::ball(EARTH_SIZE))
        .insert(AdditionalMassProperties::Mass(EARTH_MASS))
        .insert(ReadMassProperties::default())
        .with_children(|children| {
            children
                .spawn(Collider::ball((EARTH_SIZE + 3.) / SCALE))
                .spawn(Collider::ball(EARTH_SIZE + 0.3))
                .insert(ActiveEvents::COLLISION_EVENTS)
                .insert(Sensor);
        })
        .insert(RigidBody::Fixed);
    let moon_pos = Transform::from_xyz(3000.0 / SCALE, 0.0, 0.0);
    let moon_pos = Transform::from_xyz(50.0, 0.0, 0.0);
    commands
        .spawn(PlanetBundle {
            planet_type: PlanetType::Moon,
            transform: TransformBundle::from(moon_pos),
        })
        .insert(Collider::ball(MOON_SIZE / SCALE))
        .insert(Collider::ball(MOON_SIZE))
        .insert(AdditionalMassProperties::Mass(MOON_MASS))
        .insert(ReadMassProperties::default())
        .with_children(|children| {
            children
                .spawn(Collider::ball((MOON_SIZE + 3.) / SCALE))
                .spawn(Collider::ball(MOON_SIZE + 0.1))
                .insert(ActiveEvents::COLLISION_EVENTS)
                .insert(Sensor);
        })
        .insert(RigidBody::Fixed);
    let mars_pos = Transform::from_xyz(3000.0 / SCALE, 900.0 / SCALE, 0.0);
    let mars_pos = Transform::from_xyz(50.0, 20.0, 0.0);
    commands
        .spawn(PlanetBundle {
            planet_type: PlanetType::Mars,
            transform: TransformBundle::from(mars_pos),
        })
        .insert(Collider::ball(MARS_SIZE / SCALE))
        .insert(Collider::ball(MARS_SIZE))
        .insert(AdditionalMassProperties::Mass(MARS_MASS))
        .insert(ReadMassProperties::default())
        .with_children(|children| {
            children
                .spawn(Collider::ball((MARS_SIZE + 3.) / SCALE))
                .spawn(Collider::ball(MARS_SIZE + 0.1))
                .insert(ActiveEvents::COLLISION_EVENTS)
                .insert(Sensor);
        })


@@ 178,8 183,8 @@ fn module_spawn(
            rng.gen::<f32>() * std::f32::consts::PI * 2.
        };
        let mut transform = Transform::from_xyz(
            angle.cos() * 1500.0 / SCALE,
            angle.sin() * 1500.0 / SCALE,
            angle.cos() * 30.0,
            angle.sin() * 30.0,
            0.0,
        );
        transform.rotate_z(angle);


@@ 194,17 199,17 @@ fn module_spawn(
                .insert(RigidBody::Dynamic)
                .with_children(|children| {
                    children
                        .spawn(Collider::cuboid(18.75 / SCALE, 23.4375 / SCALE))
                        .spawn(Collider::cuboid(0.375, 0.46875))
                        .insert(TransformBundle::from(Transform::from_xyz(
                            0.,
                            1.5625 / SCALE,
                            0.03125,
                            0.,
                        )));
                })
                .insert(AdditionalMassProperties::MassProperties(MassProperties {
                    local_center_of_mass: vec2(0.0, 0.0),
                    mass: 0.0001,
                    principal_inertia: 0.005,
                    mass: CARGO_MASS,
                    principal_inertia: 7.5,
                }))
                .insert(ExternalForce::default())
                .insert(ExternalImpulse::default())


@@ 278,8 283,8 @@ fn on_message(
                        rng.gen::<f32>() * std::f32::consts::PI * 2.
                    };
                    let mut transform = Transform::from_xyz(
                        angle.cos() * 1500.0 / SCALE,
                        angle.sin() * 1500.0 / SCALE,
                        angle.cos() * 30.0,
                        angle.sin() * 30.0,
                        0.0,
                    );
                    transform.rotate_z(angle);


@@ 299,13 304,13 @@ fn on_message(
                    ));
                    entity_id
                        .insert(Collider::cuboid(
                            PART_HALF_SIZE / SCALE,
                            PART_HALF_SIZE / SCALE,
                            0.5,
                            0.5,
                        ))
                        .insert(AdditionalMassProperties::MassProperties(MassProperties {
                            local_center_of_mass: vec2(0.0, 0.0),
                            mass: 0.0001,
                            principal_inertia: 0.005,
                            mass: HEARTY_MASS,
                            principal_inertia: 7.5,
                        }))
                        .insert(ExternalImpulse {
                            impulse: Vec2::ZERO,


@@ 365,12 370,12 @@ fn on_message(
                            Planet {
                                planet_type: *planet_type,
                                transform: proto_transform!(Transform::from_translation(
                                    translation * SCALE
                                    translation * CLIENT_SCALE
                                )),
                                radius: match *planet_type {
                                    PlanetType::Earth => EARTH_SIZE,
                                    PlanetType::Moon => MOON_SIZE,
                                    PlanetType::Mars => MARS_SIZE,
                                    PlanetType::Earth => EARTH_SIZE * CLIENT_SCALE,
                                    PlanetType::Moon => MOON_SIZE * CLIENT_SCALE,
                                    PlanetType::Mars => MARS_SIZE * CLIENT_SCALE,
                                },
                            },
                        ));


@@ 417,7 422,7 @@ fn on_message(
                            Part {
                                part_type: *part_type,
                                transform: proto_transform!(Transform::from_translation(
                                    transform.translation * SCALE
                                    transform.translation * CLIENT_SCALE
                                )),
                                flags: proto_part_flags!(flags),
                            },


@@ 429,7 434,7 @@ fn on_message(
                            Part {
                                part_type: *part_type,
                                transform: proto_transform!(Transform::from_translation(
                                    transform.translation * SCALE
                                    transform.translation * CLIENT_SCALE
                                )),
                                flags: proto_part_flags!(flags),
                            },


@@ 440,7 445,7 @@ fn on_message(
                        Part {
                            part_type: PartType::Hearty,
                            transform: proto_transform!(Transform::from_translation(
                                transform.translation * SCALE
                                transform.translation
                            )
                            .with_rotation(transform.rotation)),
                            flags: ProtoPartFlags { attached: false },


@@ 527,6 532,8 @@ fn on_message(
                    released,
                    button: _,
                } => {
                    let x = x / CLIENT_SCALE;
                    let y = y / CLIENT_SCALE;
                    for (entity, mut q_player, transform, velocity, mut attach) in &mut player_query
                    {
                        if q_player.addr == *from {


@@ 541,7 548,7 @@ fn on_message(
                                    let mut module = part_query.get_mut(select).unwrap();
                                    // attach module
                                    let p_pos = transform.translation;
                                    let (rel_x, rel_y) = (p_pos.x - x / SCALE, p_pos.y - y / SCALE);
                                    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(),


@@ 549,14 556,14 @@ fn on_message(
                                    );

                                    if attach.children[2].is_none()
                                        && 15. / SCALE < rel_y
                                        && rel_y < 30. / SCALE
                                        && -20. / SCALE < rel_x
                                        && rel_x < 20. / SCALE
                                        && 0.3 < rel_y
                                        && rel_y < 0.6
                                        && -0.4 < rel_x
                                        && rel_x < 0.4
                                    {
                                        module.2.translation = vec3(
                                            p_pos.x + 53. / SCALE * angle.sin(),
                                            p_pos.y - 53. / SCALE * angle.cos(),
                                            p_pos.x + 1.06 * angle.sin(),
                                            p_pos.y - 1.06 * angle.cos(),
                                            0.,
                                        );
                                        module.2.rotation =


@@ 564,7 571,7 @@ fn on_message(
                                        module.3.linvel = velocity.linvel;
                                        module.5.attached = true;
                                        let joint = FixedJointBuilder::new()
                                            .local_anchor1(vec2(0. / SCALE, -53. / SCALE));
                                            .local_anchor1(vec2(0., -1.06));
                                        let mut children = [None, None, None, None];
                                        if let Some(loose_attach) = module.4 {
                                            commands.entity(entity).remove::<LooseAttach>();


@@ 594,8 601,8 @@ fn on_message(
                                                .unwrap()
                                                .2;
                                            transform.translation = vec3(
                                                p_pos.x + 53. / SCALE * angle.sin(),
                                                p_pos.y - 53. / SCALE * angle.cos(),
                                                p_pos.x + 1.06 * angle.sin(),
                                                p_pos.y - 1.06 * angle.cos(),
                                                0.,
                                            );
                                            transform.rotation =


@@ 603,14 610,14 @@ fn on_message(
                                        }
                                        break;
                                    } else if attach.children[0].is_none()
                                        && -30. / SCALE < rel_y
                                        && rel_y < -15. / SCALE
                                        && -20. / SCALE < rel_x
                                        && rel_x < 20. / SCALE
                                        && -0.6 < rel_y
                                        && rel_y < -0.3
                                        && -0.4 < rel_x
                                        && rel_x < 0.4
                                    {
                                        module.2.translation = vec3(
                                            p_pos.x - 53. / SCALE * angle.sin(),
                                            p_pos.y + 53. / SCALE * angle.cos(),
                                            p_pos.x - 1.06 * angle.sin(),
                                            p_pos.y + 1.06 * angle.cos(),
                                            0.,
                                        );
                                        module.2.rotation =


@@ 618,7 625,7 @@ fn on_message(
                                        module.3.linvel = velocity.linvel;
                                        module.5.attached = true;
                                        let joint = FixedJointBuilder::new()
                                            .local_anchor1(vec2(0. / SCALE, 53. / SCALE));
                                            .local_anchor1(vec2(0., 1.06));
                                        let mut children = [None, None, None, None];
                                        if let Some(loose_attach) = module.4 {
                                            commands.entity(entity).remove::<LooseAttach>();


@@ 648,8 655,8 @@ fn on_message(
                                                .unwrap()
                                                .2;
                                            transform.translation = vec3(
                                                p_pos.x - 53. / SCALE * angle.sin(),
                                                p_pos.y + 53. / SCALE * angle.cos(),
                                                p_pos.x - 1.06 * angle.sin(),
                                                p_pos.y + 1.06 * angle.cos(),
                                                0.,
                                            );
                                            transform.rotation =


@@ 657,14 664,14 @@ fn on_message(
                                        }
                                        break;
                                    } else if attach.children[1].is_none()
                                        && -30. / SCALE < rel_x
                                        && rel_x < -15. / SCALE
                                        && -20. / SCALE < rel_y
                                        && rel_y < 20. / SCALE
                                        && -0.6 < rel_x
                                        && rel_x < -0.3
                                        && -0.4 < rel_y
                                        && rel_y < 0.4
                                    {
                                        module.2.translation = vec3(
                                            p_pos.x + 53. / SCALE * angle.cos(),
                                            p_pos.y + 53. / SCALE * angle.sin(),
                                            p_pos.x + 1.06 * angle.cos(),
                                            p_pos.y + 1.06 * angle.sin(),
                                            0.,
                                        );
                                        module.2.rotation = Quat::from_euler(


@@ 676,7 683,7 @@ fn on_message(
                                        module.3.linvel = velocity.linvel;
                                        module.5.attached = true;
                                        let joint = FixedJointBuilder::new()
                                            .local_anchor1(vec2(53. / SCALE, 0. / SCALE))
                                            .local_anchor1(vec2(1.06, 0.))
                                            .local_basis2(std::f32::consts::PI / 2.);
                                        let mut children = [None, None, None, None];
                                        if let Some(loose_attach) = module.4 {


@@ 707,8 714,8 @@ fn on_message(
                                                .unwrap()
                                                .2;
                                            transform.translation = vec3(
                                                p_pos.x + 53. / SCALE * angle.cos(),
                                                p_pos.y + 53. / SCALE * angle.sin(),
                                                p_pos.x + 1.06 * angle.cos(),
                                                p_pos.y + 1.06 * angle.sin(),
                                                0.,
                                            );
                                            transform.rotation = Quat::from_euler(


@@ 720,14 727,14 @@ fn on_message(
                                        }
                                        break;
                                    } else if attach.children[3].is_none()
                                        && 15. / SCALE < rel_x
                                        && rel_x < 30. / SCALE
                                        && -20. / SCALE < rel_y
                                        && rel_y < 20. / SCALE
                                        && 0.3 < rel_x
                                        && rel_x < 0.6
                                        && -0.4 < rel_y
                                        && rel_y < 0.4
                                    {
                                        module.2.translation = vec3(
                                            p_pos.x - 53. / SCALE * angle.cos(),
                                            p_pos.y - 53. / SCALE * angle.sin(),
                                            p_pos.x - 1.06 * angle.cos(),
                                            p_pos.y - 1.06 * angle.sin(),
                                            0.,
                                        );
                                        module.2.rotation = Quat::from_euler(


@@ 739,7 746,7 @@ fn on_message(
                                        module.3.linvel = velocity.linvel;
                                        module.5.attached = true;
                                        let joint = FixedJointBuilder::new()
                                            .local_anchor1(vec2(-53. / SCALE, 0. / SCALE))
                                            .local_anchor1(vec2(-1.06, 0.))
                                            .local_basis2(-std::f32::consts::PI / 2.);
                                        let mut children = [None, None, None, None];
                                        if let Some(loose_attach) = module.4 {


@@ 770,8 777,8 @@ fn on_message(
                                                .unwrap()
                                                .2;
                                            transform.translation = vec3(
                                                p_pos.x - 53. / SCALE * angle.cos(),
                                                p_pos.y - 53. / SCALE * angle.sin(),
                                                p_pos.x - 1.06 * angle.cos(),
                                                p_pos.y - 1.06 * angle.sin(),
                                                0.,
                                            );
                                            transform.rotation = Quat::from_euler(


@@ 819,7 826,7 @@ fn on_message(
                                            }
                                        }
                                        let mut module = attached_query.get_mut(select).unwrap();
                                        module.2.translation = vec3(x / SCALE, y / SCALE, 0.);
                                        module.2.translation = vec3(x, y, 0.);
                                    } else {
                                        for (i, child) in attach.children.clone().iter().enumerate()
                                        {


@@ 829,7 836,7 @@ fn on_message(
                                                    let mut module =
                                                        attached_query.get_mut(select).unwrap();
                                                    module.2.translation =
                                                        vec3(x / SCALE, y / SCALE, 0.);
                                                        vec3(x, y, 0.);
                                                    if *module.1 == PartType::LandingThruster {
                                                        let sub_entity =
                                                            children_attach.children[2].unwrap();


@@ 837,7 844,7 @@ fn on_message(
                                                            .get_mut(sub_entity)
                                                            .unwrap();
                                                        suspension.2.translation =
                                                            vec3(x / SCALE, y / SCALE, 0.);
                                                            vec3(x, y, 0.);
                                                    }
                                                }
                                            }


@@ 860,12 867,12 @@ fn on_message(
                                }
                                // move module to cursor since no attach
                                let mut part = part_query.get_mut(select).unwrap();
                                part.2.translation = vec3(x / SCALE, y / SCALE, 0.);
                                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 / SCALE, y / SCALE, 0.);
                                        part.2.translation = vec3(x, y, 0.);
                                    }
                                }
                                break;


@@ 877,19 884,19 @@ fn on_message(
                                    continue;
                                }
                                let pos = transform.translation;
                                let rel_x = pos.x - x / SCALE;
                                let rel_y = pos.y - y / SCALE;
                                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 =
                                    [-25. / SCALE, 25. / SCALE, -25. / SCALE, 25. / SCALE]; // left, right, top, bottom
                                    [-0.5, 0.5, -0.5, 0.5]; // left, right, top, bottom
                                if let PartType::Cargo = part_type {
                                    bound = [
                                        -18.75 / SCALE,
                                        18.75 / SCALE,
                                        -25. / SCALE,
                                        21.875 / SCALE,
                                        -0.375,
                                        0.375,
                                        -0.5,
                                        0.4375,
                                    ];
                                }



@@ 903,19 910,19 @@ fn on_message(
                                    continue;
                                }
                                let pos = transform.translation;
                                let rel_x = pos.x - x / SCALE;
                                let rel_y = pos.y - y / SCALE;
                                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 =
                                    [-25. / SCALE, 25. / SCALE, -25. / SCALE, 25. / SCALE]; // left, right, top, bottom
                                    [-0.5, 0.5, -0.5, 0.5]; // left, right, top, bottom
                                if let PartType::Cargo = part_type {
                                    bound = [
                                        -18.75 / SCALE,
                                        18.75 / SCALE,
                                        -25. / SCALE,
                                        21.875 / SCALE,
                                        -0.375,
                                        0.375,
                                        -0.5,
                                        0.4375
                                    ];
                                }



@@ 998,25 1005,25 @@ fn load_savefile(
            let mut angle_offset = 0.;
            if i == 2 {
                //offset = Vec2::new(53., -53.);
                offset = Vec2::new(0., -53.);
                offset = Vec2::new(0., -1.06);
                angle_offset = 0.;
            } else if i == 0 {
                //offset = Vec2::new(-53., 53.);
                offset = Vec2::new(0., 53.);
                offset = Vec2::new(0., 1.06);
                angle_offset = PI;
            } else if i == 1 {
                //offset = Vec2::new(53., 53.);
                offset = Vec2::new(53., 0.);
                offset = Vec2::new(1.06, 0.);
                angle_offset = PI / 2.;
            } else if i == 3 {
                //offset = Vec2::new(-53., 53.);
                offset = Vec2::new(-53., 0.);
                offset = Vec2::new(-1.06, 0.);
                angle_offset = -PI / 2.;
            }

            let transform = Transform::from_xyz(
                p_pos.x + offset.x / SCALE * angle.cos() - offset.y / SCALE * angle.sin(),
                p_pos.y + offset.x / SCALE * angle.sin() + offset.y / SCALE * angle.cos(),
                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(


@@ 1063,32 1070,40 @@ fn load_savefile(
                .with_children(|children| {
                    children
                        .spawn(if part_type == PartType::Cargo {
                            Collider::cuboid(18.75 / SCALE, 23.4375 / SCALE)
                            Collider::cuboid(0.375, 0.46875)
                        } else if part_type == PartType::Hub {
                            Collider::cuboid(PART_HALF_SIZE / SCALE, PART_HALF_SIZE / SCALE)
                            Collider::cuboid(0.5, 0.5)
                        } else if part_type == PartType::LandingThruster {
                            Collider::cuboid(PART_HALF_SIZE / SCALE, 18.75 / SCALE)
                            Collider::cuboid(0.5, 0.375)
                        } else {
                            Collider::cuboid(PART_HALF_SIZE / SCALE, PART_HALF_SIZE / SCALE)
                            Collider::cuboid(0.5, 0.5)
                        })
                        .insert(TransformBundle::from(Transform::from_xyz(
                            0.,
                            if part_type == PartType::Cargo {
                                1.5625 / SCALE
                                0.03125
                            } else if part_type == PartType::Hub {
                                0. / SCALE
                                0.
                            } else if part_type == PartType::LandingThruster {
                                6.25 / SCALE
                                0.125
                            } else {
                                0. / SCALE
                                0.
                            },
                            0.,
                        )));
                })
                .insert(AdditionalMassProperties::MassProperties(MassProperties {
                    local_center_of_mass: vec2(0.0, 0.0),
                    mass: 0.0001,
                    principal_inertia: 0.005,
                    mass:   if part_type == PartType::Cargo {
                                CARGO_MASS
                            } else if part_type == PartType::Hub {
                                HUB_MASS
                            } else if part_type == PartType::LandingThruster {
                                LANDING_THRUSTER_MASS
                            } else {
                                1.
                            },
                    principal_inertia: 7.5,
                }))
                .insert(ExternalForce::default())
                .insert(ExternalImpulse::default())


@@ 1099,26 1114,24 @@ fn load_savefile(
            }

            let joint = FixedJointBuilder::new()
                .local_anchor1(vec2(offset.x / SCALE, offset.y / SCALE))
                .local_anchor1(vec2(offset.x, offset.y))
                .local_basis2(angle_offset);

            module.insert(ImpulseJoint::new(parent, joint));

            if part_type == PartType::LandingThruster {
                let joint = PrismaticJointBuilder::new(Vec2::new(0., 1.))
                    .local_anchor1(Vec2::new(0., 0.))
                    .local_anchor2(Vec2::new(0., 0.))
                    .motor_position(0., 150., 10.)
                    .limits([0., 50. / SCALE])
                    .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 / SCALE * angle.cos()
                                - offset.y / SCALE * angle.sin(),
                            p_pos.x + offset.x * angle.cos()
                                - offset.y * angle.sin(),
                            p_pos.y
                                + offset.x / SCALE * angle.sin()
                                + offset.y / SCALE * angle.cos(),
                                + offset.x * angle.sin()
                                + offset.y * angle.cos(),
                            0.,
                        )
                        .with_rotation(Quat::from_euler(


@@ 1135,10 1148,10 @@ fn load_savefile(
                    .insert(RigidBody::Dynamic)
                    .with_children(|children| {
                        children
                            .spawn(Collider::cuboid(PART_HALF_SIZE / SCALE, 1. / SCALE))
                            .spawn(Collider::cuboid(0.5, 0.02))
                            .insert(TransformBundle::from(Transform::from_xyz(
                                0.,
                                -24. / SCALE,
                                -0.48,
                                0.,
                            )));
                    })


@@ 1304,7 1317,7 @@ fn attach_on_module_tree(
            attached_query.get_mut(*child).unwrap();

        let p_pos = transform.translation;
        let (rel_x, rel_y) = (p_pos.x - x / SCALE, p_pos.y - y / SCALE);
        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(),


@@ 1314,19 1327,19 @@ fn attach_on_module_tree(
        let attachable = can_attach.is_some();
        if attach.children[2].is_none()
            && attachable
            && 15. / SCALE < rel_y
            && rel_y < 30. / SCALE
            && -20. / SCALE < rel_x
            && rel_x < 20. / SCALE
            && 0.3 < rel_y
            && rel_y < 0.6
            && -0.4 < rel_x
            && rel_x < 0.4
        {
            module.2.translation = vec3(
                p_pos.x + 53. / SCALE * angle.sin(),
                p_pos.y - 53. / SCALE * angle.cos(),
                p_pos.x + 1.06 * angle.sin(),
                p_pos.y - 1.06 * angle.cos(),
                0.,
            );
            module.2.rotation = Quat::from_euler(EulerRot::ZYX, angle, 0., 0.);
            module.3.linvel = velocity.linvel;
            let joint = FixedJointBuilder::new().local_anchor1(vec2(0. / SCALE, -53. / SCALE));
            let joint = FixedJointBuilder::new().local_anchor1(vec2(0., -1.06));
            let mut children = [None, None, None, None];
            if let Some(loose_attach) = loose_attach {
                commands.entity(entity).remove::<LooseAttach>();


@@ 1353,21 1366,21 @@ fn attach_on_module_tree(
            return true;
        } else if attach.children[1].is_none()
            && attachable
            && -30. / SCALE < rel_x
            && rel_x < -15. / SCALE
            && -20. / SCALE < rel_y
            && rel_y < 20. / SCALE
            && -0.6 < rel_x
            && rel_x < -0.3
            && -0.4 < rel_y
            && rel_y < 0.4
        {
            module.2.translation = vec3(
                p_pos.x + 53. / SCALE * angle.cos(),
                p_pos.y + 53. / SCALE * angle.sin(),
                p_pos.x + 1.06 * angle.cos(),
                p_pos.y + 1.06 * angle.sin(),
                0.,
            );
            module.2.rotation =
                Quat::from_euler(EulerRot::ZYX, angle + (std::f32::consts::PI / 2.), 0., 0.);
            module.3.linvel = velocity.linvel;
            let joint = FixedJointBuilder::new()
                .local_anchor1(vec2(53. / SCALE, 0. / SCALE))
                .local_anchor1(vec2(1.06, 0.))
                .local_basis2(std::f32::consts::PI / 2.);
            let mut children = [None, None, None, None];
            if let Some(loose_attach) = loose_attach {


@@ 1395,21 1408,21 @@ fn attach_on_module_tree(
            return true;
        } else if attach.children[3].is_none()
            && attachable
            && 15. / SCALE < rel_x
            && rel_x < 30. / SCALE
            && -20. / SCALE < rel_y
            && rel_y < 20. / SCALE
            && 0.3 < rel_x
            && rel_x < 0.6
            && -0.4 < rel_y
            && rel_y < 0.4
        {
            module.2.translation = vec3(
                p_pos.x - 53. / SCALE * angle.cos(),
                p_pos.y - 53. / SCALE * angle.sin(),
                p_pos.x - 1.06 * angle.cos(),
                p_pos.y - 1.06 * angle.sin(),
                0.,
            );
            module.2.rotation =
                Quat::from_euler(EulerRot::ZYX, angle - (std::f32::consts::PI / 2.), 0., 0.);
            module.3.linvel = velocity.linvel;
            let joint = FixedJointBuilder::new()
                .local_anchor1(vec2(-53. / SCALE, 0. / SCALE))
                .local_anchor1(vec2(-1.06, 0.))
                .local_basis2(-std::f32::consts::PI / 2.);
            let mut children = [None, None, None, None];
            if let Some(loose_attach) = loose_attach {


@@ 1463,6 1476,7 @@ fn convert_modules(
            Entity,
            &mut PartType,
            &mut Attach,
            &mut AdditionalMassProperties,
            &Children,
            &Transform,
            &PartFlags,


@@ 1532,6 1546,7 @@ fn convert_modules_recursive(
            Entity,
            &mut PartType,
            &mut Attach,
            &mut AdditionalMassProperties,
            &Children,
            &Transform,
            &PartFlags,


@@ 1545,15 1560,22 @@ fn convert_modules_recursive(
    packet_send: &mut EventWriter<WsEvent>,
) {
    for child in attach.children.iter().flatten() {
        let (module_entity, mut part_type, mut attach, children, module_transform, part_flags) =
        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: HUB_MASS,
                            principal_inertia: 7.5,
                        }
                    );
                    let (mut collider, mut transform, _) =
                        collider_query.get_mut(*children.first().unwrap()).unwrap();
                    *collider = Collider::cuboid(PART_HALF_SIZE / SCALE, PART_HALF_SIZE / SCALE);
                    *collider = Collider::cuboid(0.5, 0.5);
                    *transform = Transform::from_xyz(0., 0., 0.);
                    commands
                        .get_entity(module_entity)


@@ 1584,16 1606,23 @@ fn convert_modules_recursive(
                }
                PlanetType::Moon => {
                    *part_type = PartType::LandingThruster;
                    *mass_prop = AdditionalMassProperties::MassProperties(
                        MassProperties {
                            local_center_of_mass: Vec2::new(0.0, 0.0),
                            mass: LANDING_THRUSTER_MASS,
                            principal_inertia: 7.5,
                        }
                    );
                    let (mut collider, mut transform, _) =
                        collider_query.get_mut(*children.first().unwrap()).unwrap();
                    *collider = Collider::cuboid(PART_HALF_SIZE / SCALE, 18.75 / SCALE);
                    *transform = Transform::from_xyz(0., 6.25 / SCALE, 0.);
                    *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.))
                        .motor_position(0., 150., 10.)
                        .limits([0., 50. / SCALE])
                        .set_motor(0., 0., 3000., 3000.)
                        .limits([0., 1.])
                        .build();
                    let mut suspension = commands.spawn(PartBundle {
                        transform: TransformBundle::from(*module_transform),


@@ 1604,10 1633,10 @@ fn convert_modules_recursive(
                        .insert(RigidBody::Dynamic)
                        .with_children(|children| {
                            children
                                .spawn(Collider::cuboid(PART_HALF_SIZE / SCALE, 1. / SCALE))
                                .spawn(Collider::cuboid(0.5, 0.02))
                                .insert(TransformBundle::from(Transform::from_xyz(
                                    0.,
                                    -24. / SCALE,
                                    -0.48,
                                    0.,
                                )));
                        })


@@ 1702,7 1731,7 @@ fn break_modules(
        }
        let handle = joints.get(&entity).unwrap();
        let joint = rapier_context.impulse_joints.get(*handle).unwrap();
        if joint.impulses.magnitude() > 0.0001 {
        if joint.impulses.magnitude() > 0.2 {
            flags.attached = false;
            detach_list.push((entity, *part_type, attach.clone()));
        }


@@ 1882,7 1911,7 @@ fn on_position_change(
            Part {
                part_type: *part_type,
                transform: proto_transform!(Transform::from_translation(
                    transform.translation * SCALE
                    transform.translation * CLIENT_SCALE,
                )
                .with_rotation(transform.rotation)),
                flags: proto_part_flags!(flags),


@@ 1908,12 1937,12 @@ fn on_position_change(
            Planet {
                planet_type: *planet_type,
                transform: proto_transform!(Transform::from_translation(
                    transform.translation * SCALE
                    transform.translation * CLIENT_SCALE
                )),
                radius: match *planet_type {
                    PlanetType::Earth => EARTH_SIZE,
                    PlanetType::Moon => MOON_SIZE,
                    PlanetType::Mars => MARS_SIZE,
                    PlanetType::Earth => EARTH_SIZE * CLIENT_SCALE,
                    PlanetType::Moon => MOON_SIZE * CLIENT_SCALE,
                    PlanetType::Mars => MARS_SIZE * CLIENT_SCALE,
                },
            },
        ));


@@ 1953,12 1982,12 @@ fn player_input_update(
        let mut fmul_top_left_thruster: f32 = 0.0;
        let mut fmul_top_right_thruster: f32 = 0.0;
        if player.input.up {
            fmul_bottom_left_thruster += 1.0;
            fmul_bottom_right_thruster += 1.0;
            fmul_bottom_left_thruster -= 1.0;
            fmul_bottom_right_thruster -= 1.0;
        }
        if player.input.down {
            fmul_top_left_thruster -= 1.0;
            fmul_top_right_thruster -= 1.0;
            fmul_top_left_thruster += 1.0;
            fmul_top_right_thruster += 1.0;
        }
        if player.input.left {
            fmul_top_left_thruster += 1.0;


@@ 1973,12 2002,12 @@ fn player_input_update(
        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);
        if player.input.up {
            fmul_bottom_left_thruster -= 60.0;
            fmul_bottom_right_thruster -= 60.0;
            fmul_bottom_left_thruster -= 2.0;
            fmul_bottom_right_thruster -= 2.0;
        }
        if player.input.down {
            fmul_top_left_thruster += 60.0;
            fmul_top_right_thruster += 60.0;
            fmul_top_left_thruster += 2.0;
            fmul_top_right_thruster += 2.0;
        }

        let rot = transform.rotation.to_euler(EulerRot::ZYX).0;


@@ 1992,13 2021,13 @@ fn player_input_update(

        for (force_multiplier, x_offset, y_offset) in thrusters {
            if force_multiplier != 0.0 {
                let thruster_pos_uncast = vec2(x_offset / SCALE, y_offset / SCALE);
                let thruster_pos_uncast = vec2(x_offset, y_offset);
                let thruster_pos_cast =
                    rot2d(thruster_pos_uncast, rot) + transform.translation.xy();
                let thruster_force = force_multiplier * HEARTY_THRUSTER_FORCE;
                let thruster_vec = vec2(
                    -thruster_force / SCALE * rot.sin(),
                    thruster_force / SCALE * rot.cos(),
                    -thruster_force * rot.sin(),
                    thruster_force * rot.cos(),
                );
                let thruster_force = ExternalForce::at_point(
                    thruster_vec,


@@ 2048,8 2077,8 @@ fn search_thrusters(
        if input.up && 3. * PI / 4. < relative_angle && relative_angle < 5. * PI / 4. {
            let thruster_force = ExternalForce::at_point(
                Vec2::new(
                    -force_mult / SCALE * angle.sin(),
                    force_mult / SCALE * angle.cos(),
                    -force_mult * angle.sin(),
                    force_mult * angle.cos(),
                ),
                transform.translation.xy(),
                transform.translation.xy(),


@@ 2063,8 2092,8 @@ fn search_thrusters(
        {
            let thruster_force = ExternalForce::at_point(
                Vec2::new(
                    -force_mult / SCALE * angle.sin(),
                    force_mult / SCALE * angle.cos(),
                    -force_mult * angle.sin(),
                    force_mult * angle.cos(),
                ),
                transform.translation.xy(),
                transform.translation.xy(),


@@ 2075,12 2104,12 @@ fn search_thrusters(
        if input.left {
            if 3. * PI / 4. < relative_angle
                && relative_angle < 5. * PI / 4.
                && relative_pos.x > 24. / SCALE
                && relative_pos.x > 0.48
            {
                let thruster_force = ExternalForce::at_point(
                    Vec2::new(
                        -force_mult / SCALE * angle.sin(),
                        force_mult / SCALE * angle.cos(),
                        -force_mult * angle.sin(),
                        force_mult * angle.cos(),
                    ),
                    transform.translation.xy(),
                    transform.translation.xy(),


@@ 2090,12 2119,12 @@ fn search_thrusters(
            }
            if ((0. < relative_angle && relative_angle < PI / 4.)
                || (7. * PI / 4. < relative_angle && relative_angle < 2. * PI))
                && relative_pos.x < -24. / SCALE
                && relative_pos.x < -0.48
            {
                let thruster_force = ExternalForce::at_point(
                    Vec2::new(
                        -force_mult / SCALE * angle.sin(),
                        force_mult / SCALE * angle.cos(),
                        -force_mult * angle.sin(),
                        force_mult * angle.cos(),
                    ),
                    transform.translation.xy(),
                    transform.translation.xy(),


@@ 2104,11 2133,11 @@ fn search_thrusters(
                force.torque += thruster_force.torque;
            }
            if PI / 4. < relative_angle && relative_angle < 3. * PI / 4. {
                if relative_pos.y < -24. / SCALE {
                if relative_pos.y < -0.48 {
                    let thruster_force = ExternalForce::at_point(
                        Vec2::new(
                            -force_mult / SCALE * angle.sin(),
                            force_mult / SCALE * angle.cos(),
                            -force_mult * angle.sin(),
                            force_mult * angle.cos(),
                        ),
                        transform.translation.xy(),
                        transform.translation.xy(),


@@ 2116,11 2145,11 @@ fn search_thrusters(
                    force.force += thruster_force.force;
                    force.torque += thruster_force.torque;
                }
                if -24. / SCALE < relative_pos.y && relative_pos.y < 24. / SCALE {
                if -0.48 < relative_pos.y && relative_pos.y < 0.48 {
                    let thruster_force = ExternalForce::at_point(
                        Vec2::new(
                            -force_mult / SCALE * angle.sin(),
                            force_mult / SCALE * angle.cos(),
                            -force_mult * angle.sin(),
                            force_mult * angle.cos(),
                        ),
                        transform.translation.xy(),
                        transform.translation.xy(),


@@ 2130,11 2159,11 @@ fn search_thrusters(
                }
            }
            if 5. * PI / 4. < relative_angle && relative_angle < 7. * PI / 4. {
                if relative_pos.y > 24. / SCALE {
                if relative_pos.y > 0.48 {
                    let thruster_force = ExternalForce::at_point(
                        Vec2::new(
                            -force_mult / SCALE * angle.sin(),
                            force_mult / SCALE * angle.cos(),
                            -force_mult * angle.sin(),
                            force_mult * angle.cos(),
                        ),
                        transform.translation.xy(),
                        transform.translation.xy(),


@@ 2142,11 2171,11 @@ fn search_thrusters(
                    force.force += thruster_force.force;
                    force.torque += thruster_force.torque;
                }
                if -24. / SCALE < relative_pos.y && relative_pos.y < 24. / SCALE {
                if -0.48 < relative_pos.y && relative_pos.y < 0.48 {
                    let thruster_force = ExternalForce::at_point(
                        Vec2::new(
                            -force_mult / SCALE * angle.sin(),
                            force_mult / SCALE * angle.cos(),
                            -force_mult * angle.sin(),
                            force_mult * angle.cos(),
                        ),
                        transform.translation.xy(),
                        transform.translation.xy(),