~starkingdoms/starkingdoms

a21b4f99045f8cc466ebe7be645f3ab251510349 — ghostly_zsh 25 days ago dab0664
fix: joint damping now applies specifically parallel to the joint
M crates/unified/assets/config/world.wc.toml => crates/unified/assets/config/world.wc.toml +3 -3
@@ 8,10 8,10 @@ spawn_parts_interval_secs = 1
default_height = 50
default_width = 50
default_mass = 100
joint_align_compliance = 0.00002
joint_point_compliance = 0.00002
joint_angle_compliance = 0.000000002
joint_limit_compliance = 0.0006
joint_linear_damping = 4.0
joint_distance_damping = 360.0
#joint_linear_damping = 0.0
joint_angular_damping = 2.0

[hearty]

M crates/unified/src/config/world.rs => crates/unified/src/config/world.rs +2 -3
@@ 22,10 22,9 @@ pub struct WPartConfig {
    pub default_width: f32,
    pub default_height: f32,
    pub default_mass: f32,
    pub joint_align_compliance: f32,
    pub joint_point_compliance: f32,
    pub joint_angle_compliance: f32,
    pub joint_limit_compliance: f32,
    pub joint_linear_damping: f32,
    pub joint_distance_damping: f32,
    pub joint_angular_damping: f32,
}


A crates/unified/src/server/damping.rs => crates/unified/src/server/damping.rs +76 -0
@@ 0,0 1,76 @@
use avian2d::{dynamics::{joints::EntityConstraint, solver::{joint_damping, schedule::SubstepSolverSystems, solver_body::{SolverBody, SolverBodyInertia}}}, math::RecipOrZero};

use crate::prelude::*;

pub fn damping_plugin(app: &mut App) {
    let substeps = app.get_schedule_mut(SubstepSchedule).expect("Add SubstepSchedule first");
    substeps.add_systems(
        module_joint_damping::<FixedJoint>
        .after(joint_damping::<DistanceJoint>) // DistanceJoint is the last damping in vanilla avian
        .in_set(SubstepSolverSystems::Damping)
    );
}

#[derive(Component, Debug, Clone, Copy)]
pub struct ModuleJointDamping {
    pub distance: f32,
    pub angular: f32,
}
fn module_joint_damping<T: Component + EntityConstraint<2>>(
    bodies: Query<(&mut SolverBody, &SolverBodyInertia, &Transform)>,
    joints: Query<(&T, &ModuleJointDamping)>,
    time: Res<Time>,
) {
    let delta_secs = time.delta_secs();

    let mut dummy_body1 = SolverBody::DUMMY;
    let mut dummy_body2 = SolverBody::DUMMY;

    for (joint, damping) in &joints {
        let entities = joint.entities();

        let (mut body1, mut inertia1, mut transform1) = (&mut dummy_body1, &SolverBodyInertia::DUMMY, Transform::default());
        let (mut body2, mut inertia2, mut transform2) = (&mut dummy_body2, &SolverBodyInertia::DUMMY, Transform::default());

        // Get the solver bodies for the two jointed entities.
        if let Ok((body, inertia, transform)) = unsafe { bodies.get_unchecked(entities[0]) } {
            body1 = body.into_inner();
            inertia1 = inertia;
            transform1 = *transform;
        }
        if let Ok((body, inertia, transform)) = unsafe { bodies.get_unchecked(entities[1]) } {
            body2 = body.into_inner();
            inertia2 = inertia;
            transform2 = *transform;
        }

        let delta_omega = (body2.angular_velocity - body1.angular_velocity)
            * (damping.angular * delta_secs).min(1.0);

        if !body1.flags.is_kinematic() {
            body1.angular_velocity += delta_omega;
        }
        if !body2.flags.is_kinematic() {
            body2.angular_velocity -= delta_omega;
        }

        let position1 = transform1.translation.truncate() + body1.delta_position;
        let position2 = transform2.translation.truncate() + body2.delta_position;

        let relative_position = position1 - position2;

        let parallel_velocity1 = body1.linear_velocity.project_onto(relative_position.normalize());
        let parallel_velocity2 = body2.linear_velocity.project_onto(relative_position.normalize());
        
        let delta_v = (parallel_velocity2 - parallel_velocity1)
            * (damping.distance * delta_secs).min(1.0);

        let w1 = inertia1.effective_inv_mass();
        let w2 = inertia2.effective_inv_mass();

        let p = delta_v * (w1 + w2).recip_or_zero();

        body1.linear_velocity += p * w1;
        body2.linear_velocity -= p * w2;
    }
}

M crates/unified/src/server/mod.rs => crates/unified/src/server/mod.rs +5 -2
@@ 4,11 4,13 @@ mod part;
mod heat;
mod drill;
mod craft;
mod damping;
pub mod planets;
pub mod player;
mod system_sets;

use crate::server::craft::craft_plugin;
use crate::server::damping::damping_plugin;
use crate::server::drill::drill_plugin;
use crate::server::earth_parts::spawn_parts_plugin;
use crate::server::gravity::newtonian_gravity_plugin;


@@ 56,11 58,12 @@ impl Plugin for ServerPlugin {
        .add_plugins(spawn_parts_plugin)
        .add_plugins(part_management_plugin)
        .add_plugins(server_thrust_plugin)
        .add_plugins(heat_cooling_plugin)
        /*.add_plugins(heat_cooling_plugin)
        .add_plugins(heat_radiation_plugin)
        .add_plugins(heat_conduction_plugin)
        .add_plugins(heat_conduction_plugin)*/
        .add_plugins(drill_plugin)
        .add_plugins(craft_plugin)
        .add_plugins(damping_plugin)
        .configure_sets(Update, WorldUpdateSet.before(PlayerInputSet));
        //.configure_sets(Update, PlayerInputSet.before(PhysicsSet::SyncBackend));
    }

M crates/unified/src/server/player.rs => crates/unified/src/server/player.rs +12 -4
@@ 3,6 3,7 @@ pub mod thrust;

use crate::attachment::{Joint, JointOf, Joints, PartInShip, Peer, SnapOf, SnapOfJoint};
use crate::ecs::{DragRequestEvent, Part, Player, PlayerStorage};
use crate::server::damping::ModuleJointDamping;
use crate::server::system_sets::PlayerInputSet;
use crate::server::ConnectedNetworkEntity;
use crate::prelude::*;


@@ 22,6 23,7 @@ pub fn player_management_plugin(app: &mut App) {
            .in_set(PlayerInputSet),
    );
    app.add_systems(Update, complete_partial_disconnects);
    app.add_systems(FixedUpdate, complete_partial_disconnects);
}

#[derive(Component)]


@@ 349,7 351,7 @@ fn dragging(
            );

            // create the joint...
            let joint = PrismaticJoint::new(target_part.2, source_part.2)
            /*let joint = PrismaticJoint::new(target_part.2, source_part.2)
                .with_slider_axis(source_joint.2.translation.xy().normalize())
                .with_local_anchor1(target_joint.2.translation.xy())
                .with_local_basis1(target_joint.0.transform.rotation.to_euler(EulerRot::ZYX).0 + PI


@@ 357,9 359,15 @@ fn dragging(
                .with_limits(0.0, 0.0)
                .with_align_compliance(world_config.part.joint_align_compliance)
                .with_angle_compliance(world_config.part.joint_angle_compliance)
                .with_limit_compliance(world_config.part.joint_limit_compliance);
            let joint_damping = JointDamping {
                linear: world_config.part.joint_linear_damping,
                .with_limit_compliance(world_config.part.joint_limit_compliance);*/
            let joint = FixedJoint::new(target_part.2, source_part.2)
                .with_local_anchor1(target_joint.2.translation.xy())
                .with_local_basis1(target_joint.0.transform.rotation.to_euler(EulerRot::ZYX).0 + PI
                    - source_joint.0.transform.rotation.to_euler(EulerRot::ZYX).0)
                .with_point_compliance(world_config.part.joint_point_compliance)
                .with_angle_compliance(world_config.part.joint_angle_compliance);
            let joint_damping = ModuleJointDamping {
                distance: world_config.part.joint_distance_damping,
                angular: world_config.part.joint_angular_damping,
            };