~starkingdoms/starkingdoms

d733c4e3b55f6eaed09948f4309c32ab33f4c02b — core 28 days ago e2f6d6a
feat: avian!
M Cargo.lock => Cargo.lock +132 -62
@@ 725,6 725,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"

[[package]]
name = "avian2d"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1527c0529592ee609cdf44cfba8ba5190f0bef5f04ae057b1d1e28d412aee63a"
dependencies = [
 "approx",
 "arrayvec",
 "avian_derive",
 "bevy",
 "bevy_heavy",
 "bevy_math",
 "bevy_transform_interpolation",
 "bitflags 2.10.0",
 "derive_more",
 "disqualified",
 "glam_matrix_extras",
 "itertools 0.13.0",
 "libm",
 "nalgebra",
 "parry2d",
 "parry2d-f64",
 "serde",
 "slab",
 "smallvec",
 "thiserror 2.0.17",
 "thread_local",
]

[[package]]
name = "avian_derive"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b257f601a1535e0d4a7a7796f535e3a13de62fd422b16dff7c14d27f0d4048"
dependencies = [
 "proc-macro-error2",
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "aws-lc-rs"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1236,6 1277,18 @@ dependencies = [
]

[[package]]
name = "bevy_heavy"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7c0651daa331c326e1460cb19ee5bf497ed2810982dafca8784db44725f5c4b"
dependencies = [
 "bevy_math",
 "bevy_reflect",
 "glam_matrix_extras",
 "serde",
]

[[package]]
name = "bevy_image"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1568,19 1621,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28ab4074e7b781bab84e9b0a41ede245d673d1f75646ce0db27643aedcfb3a85"

[[package]]
name = "bevy_rapier2d"
version = "0.31.0"
source = "git+https://github.com/Deniskore/bevy_rapier?branch=bevy-0.17#47e1fd32c6ea61cfe9a71cb1c42819d7b7fc88ac"
dependencies = [
 "bevy",
 "bitflags 2.10.0",
 "log",
 "nalgebra",
 "rapier2d",
 "serde",
]

[[package]]
name = "bevy_reflect"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1902,6 1942,16 @@ dependencies = [
]

[[package]]
name = "bevy_transform_interpolation"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284738382605476667bbe80cf0959f4dffb61adbdb0149e22e67f4dbf97a5bc2"
dependencies = [
 "bevy",
 "serde",
]

[[package]]
name = "bevy_ui"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 2073,9 2123,6 @@ name = "bit-vec"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
dependencies = [
 "serde",
]

[[package]]
name = "bitflags"


@@ 4101,6 4148,7 @@ version = "0.30.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd47b05dddf0005d850e5644cae7f2b14ac3df487979dbfff3b56f20b1a6ae46"
dependencies = [
 "approx",
 "bytemuck",
 "libm",
 "rand 0.9.2",


@@ 4108,6 4156,18 @@ dependencies = [
]

[[package]]
name = "glam_matrix_extras"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cb141d04d0bbebc52c325352ae0c930a6d42c77ccd02b7c591a73bd7bc1d859"
dependencies = [
 "bevy_reflect",
 "glam 0.30.9",
 "libm",
 "serde",
]

[[package]]
name = "glob"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 5968,11 6028,43 @@ dependencies = [
 "ena",
 "foldhash 0.2.0",
 "hashbrown 0.16.0",
 "indexmap",
 "log",
 "nalgebra",
 "num-derive",
 "num-traits",
 "ordered-float 5.1.0",
 "rayon",
 "serde",
 "serde_arrays",
 "simba",
 "slab",
 "smallvec",
 "spade",
 "thiserror 2.0.17",
]

[[package]]
name = "parry2d-f64"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "835d4ca2b68026b04a75ca6196da961d8c0895420eacc9cc2201f7ad54775780"
dependencies = [
 "approx",
 "arrayvec",
 "bitflags 2.10.0",
 "downcast-rs 2.0.2",
 "either",
 "ena",
 "foldhash 0.2.0",
 "hashbrown 0.16.0",
 "indexmap",
 "log",
 "nalgebra",
 "num-derive",
 "num-traits",
 "ordered-float 5.1.0",
 "rayon",
 "serde",
 "serde_arrays",
 "simba",


@@ 6295,34 6387,43 @@ dependencies = [
]

[[package]]
name = "proc-macro2"
version = "1.0.103"
name = "proc-macro-error-attr2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
dependencies = [
 "unicode-ident",
 "proc-macro2",
 "quote",
]

[[package]]
name = "profiling"
version = "1.0.17"
name = "proc-macro-error2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
dependencies = [
 "profiling-procmacros",
 "proc-macro-error-attr2",
 "proc-macro2",
 "quote",
 "syn",
]

[[package]]
name = "profiling-procmacros"
version = "1.0.17"
name = "proc-macro2"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
 "quote",
 "syn",
 "unicode-ident",
]

[[package]]
name = "profiling"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"

[[package]]
name = "pxfm"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 6448,32 6549,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbbbbea733ec66275512d0b9694f34102e7d5406fdbe2ad8d21b28dce92887c"

[[package]]
name = "rapier2d"
version = "0.30.1"
source = "git+https://github.com/dimforge/rapier?rev=ef5dcaccaf405da41f6f379bde71f9cf33ffd78b#ef5dcaccaf405da41f6f379bde71f9cf33ffd78b"
dependencies = [
 "approx",
 "arrayvec",
 "bit-vec",
 "bitflags 2.10.0",
 "downcast-rs 2.0.2",
 "log",
 "nalgebra",
 "num-derive",
 "num-traits",
 "ordered-float 5.1.0",
 "parry2d",
 "profiling",
 "rustc-hash 2.1.1",
 "serde",
 "simba",
 "static_assertions",
 "thiserror 2.0.17",
 "vec_map",
 "wide",
]

[[package]]
name = "raw-window-handle"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 7073,6 7148,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c99284beb21666094ba2b75bbceda012e610f5479dfcc2d6e2426f53197ffd95"
dependencies = [
 "approx",
 "libm",
 "num-complex",
 "num-traits",
 "paste",


@@ 7285,11 7361,11 @@ dependencies = [
 "aeronet_replicon",
 "aeronet_transport",
 "aeronet_websocket",
 "avian2d",
 "bevy",
 "bevy-inspector-egui",
 "bevy_common_assets",
 "bevy_egui",
 "bevy_rapier2d",
 "bevy_replicon",
 "clap",
 "console_error_panic_hook",


@@ 8216,12 8292,6 @@ dependencies = [
]

[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"

[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"

M crates/unified/Cargo.toml => crates/unified/Cargo.toml +14 -1
@@ 37,7 37,20 @@ bevy = { version = "0.17", default-features = false, features = [
    "bevy_sprite_render",
    "bevy_ui_render"
] }
bevy_rapier2d = { features = ["serde-serialize", "simd-stable"], git = "https://github.com/Deniskore/bevy_rapier", branch = "bevy-0.17" }
#bevy_rapier2d = { features = ["serde-serialize", "simd-stable"], git = "https://github.com/Deniskore/bevy_rapier", branch = "bevy-0.17" }

avian2d = { version = "0.4", default-features = false, features = [
    "2d",
    "f32",
    "default-collider",
    "parry-f32",
    "xpbd_joints",
    "bevy_picking",
    "debug-plugin",
    "parallel",
    "serialize",
    "enhanced-determinism"
]}
bevy_common_assets = { version = "0.14", features = ["toml"] }

bevy_replicon = "0.36"

M crates/unified/src/attachment.rs => crates/unified/src/attachment.rs +8 -2
@@ 1,5 1,5 @@
use bevy::ecs::entity::MapEntities;
use bevy::prelude::*;
use crate::prelude::*;
use serde::{Deserialize, Serialize};
use std::ops::Deref;



@@ 22,7 22,13 @@ pub struct Joint {
    pub transform: Transform,
}
#[derive(Component, Serialize, Deserialize, MapEntities)]
pub struct Peer(#[entities] pub Entity, pub bool);
pub struct Peer {
    #[entities]
    pub peer_joint_entity_id: Entity,
    pub processed: bool,
    #[entities]
    pub physics_joint: Entity
}

#[derive(Component, Serialize, Deserialize, MapEntities)]
#[relationship(relationship_target = Joints)]

M crates/unified/src/client/key_input.rs => crates/unified/src/client/key_input.rs +13 -7
@@ 4,19 4,20 @@ use bevy::color::palettes::css::{FUCHSIA, GREEN, ORANGE, WHITE};
use bevy::dev_tools::picking_debug::DebugPickingMode;
use bevy::gizmos::gizmos::Gizmos;
use bevy::math::{Vec3, Vec3Swizzles};
use bevy::prelude::{GlobalTransform, Query, ResMut, Resource, Transform, With};
use crate::prelude::*;
use bevy::{
    app::{App, Update},
    ecs::{message::MessageWriter, system::Res},
    input::{ButtonInput, keyboard::KeyCode},
};
use bevy_rapier2d::render::DebugRenderContext;
use std::ops::Deref;
use avian2d::prelude::*;

pub fn key_input_plugin(app: &mut App) {
    app.add_systems(Update, directional_keys)
        .add_systems(Update, debug_render_keybind)
        .init_resource::<AttachmentDebugRes>()
        .init_resource::<PhysicsDebugRes>()
        .add_systems(Update, draw_attachment_debug);
}



@@ 29,16 30,21 @@ impl Deref for AttachmentDebugRes {
        &self.0
    }
}
#[derive(Resource, Default)]
pub struct PhysicsDebugRes(pub bool);
impl Deref for PhysicsDebugRes {
    type Target = bool;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

fn debug_render_keybind(
    keys: Res<ButtonInput<KeyCode>>,
    mut debug_render: ResMut<DebugRenderContext>,
    mut picking_debug_mode: ResMut<DebugPickingMode>,
    mut attachment_debug: ResMut<AttachmentDebugRes>,
) {
    if keys.just_pressed(KeyCode::F3) {
        debug_render.enabled = !debug_render.enabled;
    }
    if keys.just_pressed(KeyCode::F4) {
        *picking_debug_mode = DebugPickingMode::Noisy;
    }


@@ 91,7 97,7 @@ fn draw_attachment_debug(
        gizmos.cross_2d(joint_target.xy(), 4.0, FUCHSIA);

        if let Some(peer_id) = peer
            && let Ok(peer) = joints.get(peer_id.0)
            && let Ok(peer) = joints.get(peer_id.peer_joint_entity_id)
        {
            let Ok(peer_parent_pos) = parts.get(peer.1.0) else {
                continue;

M crates/unified/src/client/mod.rs => crates/unified/src/client/mod.rs +1 -2
@@ 21,8 21,7 @@ use bevy::anti_alias::fxaa::Fxaa;
use bevy::core_pipeline::tonemapping::DebandDither;
use bevy::dev_tools::picking_debug::DebugPickingMode;
use bevy::post_process::bloom::Bloom;
use bevy::prelude::*;
use bevy::render::render_phase::DrawFunctions;
use crate::prelude::*;
use bevy::window::PrimaryWindow;
use planet::incoming_planets::incoming_planets_plugin;


M crates/unified/src/client/net.rs => crates/unified/src/client/net.rs +1 -1
@@ 2,7 2,7 @@ use aeronet::io::connection::{DisconnectReason, Disconnected};
use aeronet::io::{Session, SessionEndpoint};
use aeronet_replicon::client::AeronetRepliconClient;
use aeronet_transport::TransportConfig;
use bevy::prelude::*;
use crate::prelude::*;

pub fn set_config(mut q: Query<&mut TransportConfig, Added<TransportConfig>>) {
    for mut q in &mut q {

M crates/unified/src/client/parts.rs => crates/unified/src/client/parts.rs +6 -7
@@ 4,9 4,7 @@ use crate::client::colors::GREEN;
use crate::client::key_input::AttachmentDebugRes;
use crate::ecs::{CursorWorldCoordinates, DragRequestEvent, Part};
use bevy::color::palettes::css::{ORANGE, PURPLE, RED, YELLOW};
use bevy::prelude::*;
use bevy_rapier2d::dynamics::MassProperties;
use bevy_rapier2d::prelude::AdditionalMassProperties;
use crate::prelude::*;

pub fn parts_plugin(app: &mut App) {
    app.insert_resource(DragResource(None));


@@ 42,11 40,11 @@ fn handle_incoming_parts(
        commands
            .entity(new_entity)
            .insert(sprite)
            .insert(AdditionalMassProperties::MassProperties(MassProperties {
            /*.insert(AdditionalMassProperties::MassProperties(MassProperties {
                local_center_of_mass: Vec2::ZERO,
                mass: new_part.strong_config.physics.mass,
                principal_inertia: 7.5,
            }))
            }))*/
            .insert(Pickable::default())
            .observe(on_part_click);
    }


@@ 70,13 68,14 @@ fn handle_updated_parts(
        commands
            .entity(updated_entity)
            .remove::<Sprite>()
            .remove::<AdditionalMassProperties>()
            //.remove::<AdditionalMassProperties>()
            .insert(sprite)
            /*
            .insert(AdditionalMassProperties::MassProperties(MassProperties {
                local_center_of_mass: Vec2::ZERO,
                mass: updated_part.strong_config.physics.mass,
                principal_inertia: 7.5,
            }));
            }))*/;
    }
}


M crates/unified/src/client/planet/incoming_planets.rs => crates/unified/src/client/planet/incoming_planets.rs +4 -5
@@ 1,6 1,5 @@
use crate::config::planet::{Planet, SpecialSpriteProperties};
use bevy::prelude::*;
use bevy_rapier2d::prelude::AdditionalMassProperties;
use crate::prelude::*;

pub fn incoming_planets_plugin(app: &mut App) {
    app.add_systems(Update, (handle_incoming_planets, handle_updated_planets));


@@ 22,7 21,7 @@ fn handle_incoming_planets(
        let mut commands = commands.entity(new_entity);

        commands
            .insert(AdditionalMassProperties::Mass(new_planet.mass))
            //.insert(AdditionalMassProperties::Mass(new_planet.mass))
            .insert(sprite);

        trace!(?new_planet, "prepared new planet");


@@ 48,8 47,8 @@ fn handle_updated_planets(

        let mut commands = commands.entity(updated_entity);
        commands
            .remove::<AdditionalMassProperties>()
            .insert(AdditionalMassProperties::Mass(updated_planet.mass))
            //.remove::<AdditionalMassProperties>()
            //.insert(AdditionalMassProperties::Mass(updated_planet.mass))
            .remove::<Sprite>()
            .insert(sprite);


M crates/unified/src/client/planet/indicators.rs => crates/unified/src/client/planet/indicators.rs +1 -1
@@ 1,7 1,7 @@
use crate::client::Me;
use crate::config::planet::Planet;
use crate::ecs::MainCamera;
use bevy::prelude::*;
use crate::prelude::*;
use bevy::window::PrimaryWindow;

pub fn indicators_plugin(app: &mut App) {

M crates/unified/src/client/ui.rs => crates/unified/src/client/ui.rs +1 -1
@@ 1,4 1,4 @@
use bevy::prelude::*;
use crate::prelude::*;

use crate::{
    client::colors,

M crates/unified/src/client_plugins.rs => crates/unified/src/client_plugins.rs +7 -6
@@ 3,15 3,12 @@ use aeronet_replicon::client::AeronetRepliconClientPlugin;
use aeronet_websocket::client::WebSocketClientPlugin;
use bevy::DefaultPlugins;
use bevy::app::{PluginGroup, PluginGroupBuilder};
use bevy::dev_tools::fps_overlay::FpsOverlayPlugin;
use bevy::dev_tools::picking_debug::DebugPickingPlugin;
use bevy::ecs::schedule::ScheduleLabel;
use bevy::log::LogPlugin;
use bevy::prelude::MeshPickingPlugin;
use crate::prelude::*;
use bevy::ui::UiPlugin;
use bevy_egui::EguiPlugin;
use bevy_rapier2d::prelude::RapierDebugRenderPlugin;
use bevy_replicon::RepliconPlugins;
use bevy_inspector_egui::quick::WorldInspectorPlugin;

pub struct ClientPluginGroup {
    pub server: String,


@@ 29,9 26,13 @@ impl PluginGroup for ClientPluginGroup {
            .add(ClientPlugin {
                server: self.server,
            })
            .add(RapierDebugRenderPlugin::default().disabled())

            //.add(PhysicsDebugPlugin) -- debug rendering
            //.add(FpsOverlayPlugin::default())
            //.add(EguiPlugin::default())
            //.add(WorldInspectorPlugin::new())
    }
}

#[derive(ScheduleLabel, Clone, Eq, Debug, Hash, PartialEq)]
pub struct DontRunSchedule;
\ No newline at end of file

M crates/unified/src/config/part.rs => crates/unified/src/config/part.rs +1 -1
@@ 1,6 1,6 @@
use bevy::asset::Asset;
use bevy::math::{Quat, Vec3};
use bevy::prelude::{Transform, TypePath};
use crate::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Deserialize, TypePath, Serialize, Clone, Debug, PartialEq, Asset)]

M crates/unified/src/config/planet.rs => crates/unified/src/config/planet.rs +8 -4
@@ 1,11 1,14 @@
use bevy::asset::Asset;
use bevy::color::Color;
use bevy::prelude::{Bundle, Component, Transform, TypePath};
use bevy_rapier2d::prelude::{AdditionalMassProperties, Collider, ReadMassProperties, RigidBody};
use crate::prelude::*;
use serde::{Deserialize, Serialize};


#[derive(Deserialize, Asset, TypePath, Component, Serialize, Clone, Debug)]
#[require(ReadMassProperties, RigidBody::Fixed)]
#[require(
    RigidBody::Static,
    Replicated,
)]
pub struct Planet {
    pub name: String,
    pub sprite: String,


@@ 26,7 29,8 @@ pub struct PlanetBundle {
    pub planet: Planet,
    pub transform: Transform,
    pub collider: Collider,
    pub additional_mass_properties: AdditionalMassProperties,
    pub mass: Mass
    //pub additional_mass_properties: AdditionalMassProperties,
}

#[derive(Deserialize, Asset, TypePath)]

M crates/unified/src/config/world.rs => crates/unified/src/config/world.rs +1 -1
@@ 1,5 1,5 @@
use bevy::asset::Asset;
use bevy::prelude::TypePath;
use crate::prelude::*;
use serde::Deserialize;

#[derive(Deserialize, Asset, TypePath, Clone)]

M crates/unified/src/ecs.rs => crates/unified/src/ecs.rs +6 -7
@@ 1,11 1,10 @@
use crate::config::part::PartConfig;
use bevy::ecs::entity::MapEntities;
use bevy::math::{Quat, Vec2};
use bevy::prelude::*;
use bevy_rapier2d::dynamics::RigidBody;
use bevy_rapier2d::prelude::*;
use crate::prelude::*;
use bevy_replicon::prelude::Replicated;
use serde::{Deserialize, Serialize};
use avian2d::prelude::*;

#[derive(Component)]
pub struct MainCamera;


@@ 34,11 33,11 @@ pub enum ThrustEvent {

#[derive(Component, Serialize, Deserialize, Debug)]
#[require(
    ReadMassProperties,
    RigidBody::Dynamic,
    ExternalForce,
    ExternalImpulse,
    Replicated
    LinearVelocity,
    AngularVelocity,
    ConstantForce,
    Replicated,
)]
pub struct Part {
    pub strong_config: PartConfig,

M crates/unified/src/lib.rs => crates/unified/src/lib.rs +3 -0
@@ 38,3 38,6 @@ pub mod server;
#[cfg(all(not(target_arch = "wasm32"), feature = "native"))]
pub mod server_plugins;
pub mod shared_plugins;

pub mod physics;
pub mod prelude;
\ No newline at end of file

M crates/unified/src/main.rs => crates/unified/src/main.rs +3 -4
@@ 1,6 1,5 @@
use std::io::Read;
use bevy::log::tracing_subscriber;
use bevy::prelude::*;
use starkingdoms::prelude::*;
use clap::Parser;
use starkingdoms::client_plugins::ClientPluginGroup;
#[cfg(not(target_arch = "wasm32"))]


@@ 27,7 26,7 @@ enum Cli {
        #[arg(short = 'b', long)]
        bind: SocketAddr,
        #[arg(short = 'r', long)]
        tick_rate: f64,
        tick_rate: f32,
        #[arg(short = 'C', long)]
        max_clients: usize,
        #[arg(long, action)]


@@ 126,7 125,7 @@ fn main() -> AppExit {
                    })
                    .unwrap();

                let mut clt_exit;
                let clt_exit;

                    info!("starting client thread...");


M crates/unified/src/particle_editor/ecs.rs => crates/unified/src/particle_editor/ecs.rs +1 -2
@@ 1,13 1,12 @@
use std::time::Duration;

use crate::particles::ParticleEffect;
use bevy::prelude::ColorMaterial;
use bevy::{
    asset::Handle,
    ecs::component::Component,
    prelude::*,
    time::{Timer, TimerMode},
};
use crate::prelude::*;

#[derive(Component)]
pub struct Particle;

M crates/unified/src/particle_editor/hooks.rs => crates/unified/src/particle_editor/hooks.rs +1 -1
@@ 1,4 1,4 @@
use bevy::prelude::*;
use crate::prelude::*;

use crate::{particle_editor::ecs::SpawnDelayTimer, particles::ParticleEffect};


M crates/unified/src/particle_editor/mod.rs => crates/unified/src/particle_editor/mod.rs +3 -3
@@ 2,9 2,8 @@ use crate::{
    particle_editor::{hooks::hooks_plugin, spawn::spawn_plugin},
    particles::{LifetimeCurve, ParticleEffect, RandF32, RandUsize, RandVec2},
};
use bevy::prelude::*;
use crate::prelude::*;
use bevy_egui::{EguiContexts, EguiPlugin, EguiPrimaryContextPass, egui};
use bevy_rapier2d::plugin::{NoUserData, RapierPhysicsPlugin};
use ordered_float::OrderedFloat;
use std::collections::BTreeMap;



@@ 14,8 13,9 @@ mod spawn;

pub fn particle_editor_plugin(app: &mut App) {
    app.add_plugins(DefaultPlugins);
    app.insert_resource(Gravity::ZERO);
    app.add_plugins(EguiPlugin::default());
    app.add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(10.0));
    app.add_plugins(PhysicsPlugins::default().with_length_unit(100.0));
    app.add_systems(Startup, setup_camera_system);
    app.add_systems(EguiPrimaryContextPass, editor_ui);
    app.add_systems(Startup, setup_editor_effect);

M crates/unified/src/particle_editor/spawn.rs => crates/unified/src/particle_editor/spawn.rs +4 -7
@@ 1,7 1,6 @@
use std::time::Duration;

use bevy::prelude::*;
use bevy_rapier2d::prelude::{RigidBody, Velocity};
use avian2d::prelude::*;
use crate::prelude::*;

use crate::{
    particle_editor::ecs::{CircleMesh, LifetimeTimer, ParentEffect, Particle, SpawnDelayTimer},


@@ 44,10 43,8 @@ fn spawn_particles(
                    )),
                    Mesh2d(circle.0.clone()),
                    MeshMaterial2d(circle.1.clone()),
                    Velocity {
                        linvel: effect.initial_linear_velocity.sample(&mut rand::rng()),
                        angvel: effect.initial_angular_velocity.sample(&mut rand::rng()),
                    },
                    LinearVelocity(effect.initial_linear_velocity.sample(&mut rand::rng())),
                    AngularVelocity(effect.initial_angular_velocity.sample(&mut rand::rng())),
                    LifetimeTimer(Timer::from_seconds(
                        effect.lifetime_seconds.sample(&mut rand::rng()),
                        TimerMode::Once,

M crates/unified/src/particles.rs => crates/unified/src/particles.rs +1 -1
@@ 1,6 1,6 @@
use bevy::color::{Color, LinearRgba};
use bevy::math::Vec2;
use bevy::prelude::Component;
use crate::prelude::*;
use ordered_float::OrderedFloat;
use rand::Rng;
use serde::{Deserialize, Serialize};

A crates/unified/src/physics.rs => crates/unified/src/physics.rs +90 -0
@@ 0,0 1,90 @@
use crate::prelude::*;
use bevy_replicon::prelude::*;
use avian2d::prelude::*;

pub fn register_physics_components_for_replication(app: &mut App) {
    app
        // Colliders
        .replicate::<Collider>()
        .replicate::<ColliderDisabled>()
        /*.replicate::<CollidingEntities>()
        .replicate::<CollisionMargin>()
        .replicate::<Sensor>()*/

        // Dynamics - Rigidbodies
        //.replicate::<AngularDamping>()
        .replicate::<AngularVelocity>()
        /*.replicate::<Dominance>()
        .replicate::<Friction>()
        .replicate::<GravityScale>()
        .replicate::<LinearDamping>()*/
        .replicate::<LinearVelocity>()
        /*
        .replicate::<LockedAxes>()
        .replicate::<MaxAngularSpeed>()
        .replicate::<MaxLinearSpeed>()
        .replicate::<Restitution>()
        .replicate::<RigidBodyDisabled>()
         */
        .replicate::<RigidBody>()

        // Dynamics - Rigidbodies - Forces

        //.replicate::<ConstantAngularAcceleration>()
        .replicate::<ConstantForce>()
        //.replicate::<ConstantLinearAcceleration>()
        .replicate::<ConstantLocalForce>()
        //.replicate::<ConstantLocalLinearAcceleration>()
        //.replicate::<ConstantTorque>()


        // Dynamics - Rigidbodies - Mass properties

        //.replicate::<AngularInertia>()
        //.replicate::<CenterOfMass>()
        //.replicate::<ColliderDensity>()
        //.replicate::<ColliderMassProperties>()
        //.replicate::<ComputedAngularInertia>()
        //.replicate::<ComputedCenterOfMass>()
        //.replicate::<ComputedMass>()


        .replicate::<Mass>()

        /*
        .replicate::<NoAutoAngularInertia>()
        .replicate::<NoAutoCenterOfMass>()
        .replicate::<NoAutoMass>()

         */

        // Dynamics - Rigidbodies - Sleeping
        /*
        .replicate::<SleepThreshold>()
        .replicate::<SleepTimer>()
        .replicate::<Sleeping>()
        .replicate::<SleepingDisabled>()

         */

        // Interpolation - TODO

        // Physics transform
        .replicate::<Position>()
        .replicate::<Rotation>()

        // Spatial query
        //.replicate::<RayCaster>()

        // Joints

        //.replicate::<DistanceJoint>()
        .replicate::<FixedJoint>()
        //.replicate::<JointCollisionDisabled>()
        //.replicate::<JointDamping>()
        .replicate::<JointDisabled>()
        //.replicate::<JointForces>()
        //.replicate::<PrismaticJoint>()
        //.replicate::<RevoluteJoint>()
;
}
\ No newline at end of file

A crates/unified/src/prelude.rs => crates/unified/src/prelude.rs +3 -0
@@ 0,0 1,3 @@
pub use bevy::prelude::*;
pub use bevy_replicon::prelude::*;
pub use avian2d::prelude::*;
\ No newline at end of file

M crates/unified/src/server/earth_parts.rs => crates/unified/src/server/earth_parts.rs +1 -2
@@ 2,8 2,7 @@ use crate::config::planet::Planet;
use crate::server::part::SpawnPartRequest;
use crate::server::world_config::WorldConfigResource;
use bevy::app::App;
use bevy::prelude::*;
use bevy::prelude::{Commands, Query, Res, Transform};
use crate::prelude::*;
use bevy::time::Time;

#[derive(Resource, Default)]

M crates/unified/src/server/gravity.rs => crates/unified/src/server/gravity.rs +10 -10
@@ 1,18 1,18 @@
use bevy::math::FloatPow;
use crate::config::planet::Planet;
use crate::ecs::Part;
use crate::prelude::*;
use crate::server::system_sets::WorldUpdateSet;
use crate::server::world_config::WorldConfigResource;
use bevy::math::FloatPow;
use bevy::prelude::*;
use bevy_rapier2d::prelude::*;

pub fn newtonian_gravity_plugin(app: &mut App) {
    app.add_systems(Update, update_gravity.in_set(WorldUpdateSet));
}


fn update_gravity(
    mut part_query: Query<(&Transform, &ReadMassProperties, &mut ExternalForce), With<Part>>,
    planet_query: Query<(&Transform, &ReadMassProperties), With<Planet>>,
    mut part_query: Query<(&Transform, &Mass, &mut ConstantForce), With<Part>>,
    planet_query: Query<(&Transform, &Mass), With<Planet>>,
    world_config: Res<WorldConfigResource>,
) {
    let Some(world_config) = &world_config.config else {


@@ 20,14 20,13 @@ fn update_gravity(
    };

    for (part_transform, part_mass, mut forces) in &mut part_query {
        forces.force = Vec2::ZERO;
        forces.torque = 0.0;
        *forces = ConstantForce::new(0.0, 0.0);

        let part_mass = part_mass.mass;
        let part_mass = part_mass.0;
        let part_translation = part_transform.translation;

        for (planet_transform, planet_mass) in &planet_query {
            let planet_mass = planet_mass.mass;
            let planet_mass = planet_mass.0;
            let planet_translation = planet_transform.translation;

            let distance = planet_translation.distance(part_translation);


@@ 35,7 34,8 @@ fn update_gravity(
            let force =
                world_config.world.gravity * ((part_mass * planet_mass) / distance.squared());
            let direction = (planet_translation - part_translation).normalize() * force;
            forces.force += direction.xy();
            forces.x += direction.x;
            forces.y += direction.y;
        }
    }
}

M crates/unified/src/server/mod.rs => crates/unified/src/server/mod.rs +3 -4
@@ 18,8 18,7 @@ use aeronet::io::connection::{DisconnectReason, Disconnected, LocalAddr};
use aeronet::io::server::Server;
use aeronet_replicon::server::AeronetRepliconServer;
use aeronet_websocket::server::WebSocketServer;
use bevy::prelude::*;
use bevy_rapier2d::prelude::PhysicsSet;
use crate::prelude::*;
use bevy_replicon::prelude::Replicated;
use std::net::SocketAddr;



@@ 50,8 49,8 @@ impl Plugin for ServerPlugin {
        .add_plugins(player_management_plugin)
        .add_plugins(spawn_parts_plugin)
        .add_plugins(part_management_plugin)
        .configure_sets(Update, WorldUpdateSet.before(PlayerInputSet))
        .configure_sets(Update, PlayerInputSet.before(PhysicsSet::SyncBackend));
        .configure_sets(Update, WorldUpdateSet.before(PlayerInputSet));
        //.configure_sets(Update, PlayerInputSet.before(PhysicsSet::SyncBackend));
    }
}
impl ServerPlugin {

M crates/unified/src/server/part.rs => crates/unified/src/server/part.rs +5 -9
@@ 1,9 1,7 @@
use crate::attachment::{Joint, JointId, JointOf, Joints, Peer, SnapOf, SnapOfJoint};
use crate::config::part::{JointConfig, PartConfig};
use crate::ecs::{Part, PartHandle};
use bevy::prelude::Component;
use bevy::prelude::*;
use bevy_rapier2d::prelude::{AdditionalMassProperties, Collider, Velocity};
use crate::prelude::*;
use bevy_replicon::prelude::Replicated;

pub fn part_management_plugin(app: &mut App) {


@@ 65,7 63,7 @@ fn handle_part_reloading(
                        });
                        let Some(joint_cfg) = joint_cfg else {
                            if let Some(peer_id) = peer
                                && let Ok(peer) = joints.get(peer_id.0) {
                                && let Ok(peer) = joints.get(peer_id.peer_joint_entity_id) {
                                    commands.entity(peer.2).remove::<Peer>();
                                }
                            commands.entity(*joint_id).despawn();


@@ 111,16 109,14 @@ fn calculate_bundle(config: &PartConfig, handle: &Handle<PartConfig>) -> impl Bu
        strong_config: config.clone(),
    };
    let part_handle = PartHandle(handle.clone());
    let collider = Collider::cuboid(config.physics.width / 2.0, config.physics.height / 2.0);
    let additional_mass_properties = AdditionalMassProperties::Mass(config.physics.mass);
    let collider = Collider::rectangle(config.physics.width, config.physics.height);
    let mass = Mass(config.physics.mass);

    (
        part,
        part_handle,
        collider,
        additional_mass_properties,
        Velocity::default(),
        Replicated,
        mass,
    )
}
fn spawn_joint_bundle(joint: &JointConfig, part: &PartConfig, parent: &Entity) -> impl Bundle {

M crates/unified/src/server/planets.rs => crates/unified/src/server/planets.rs +8 -12
@@ 1,8 1,6 @@
use crate::config::planet::{Planet, PlanetBundle, PlanetConfigCollection};
use bevy::asset::Handle;
use bevy::prelude::*;
use bevy_rapier2d::dynamics::AdditionalMassProperties;
use bevy_rapier2d::prelude::Collider;
use crate::prelude::*;
use bevy_replicon::prelude::Replicated;

pub fn planets_plugin(app: &mut App) {


@@ 29,7 27,7 @@ pub fn update_planets(
        Entity,
        &mut Planet,
        &mut Transform,
        &mut AdditionalMassProperties,
        &mut Mass,
    )>,
) {
    let Some(handle) = planets.handle.as_ref() else {


@@ 53,10 51,8 @@ pub fn update_planets(
                                    planet.default_transform[1],
                                    planet.default_transform[2],
                                ),
                                collider: Collider::ball(planet.radius),
                                additional_mass_properties: AdditionalMassProperties::Mass(
                                    planet.mass,
                                ),
                                collider: Collider::circle(planet.radius),
                                mass: Mass(planet.mass)
                            })
                            .insert(Replicated);
                        trace!(?planet, "new planet spawned");


@@ 79,14 75,14 @@ pub fn update_planets(
                            commands
                                .entity(existing)
                                .remove::<Collider>()
                                .insert(Collider::ball(planet.radius));
                                .insert(Collider::circle(planet.radius));
                            *e_planet = planet.clone();
                            e_transform.translation = Vec3::new(
                                planet.default_transform[0],
                                planet.default_transform[1],
                                planet.default_transform[2],
                            );
                            *e_mass = AdditionalMassProperties::Mass(planet.mass);
                            *e_mass = Mass(planet.mass);
                            trace!(?planet, "planet hot-reloaded");
                        } else {
                            commands


@@ 97,8 93,8 @@ pub fn update_planets(
                                        planet.default_transform[1],
                                        planet.default_transform[2],
                                    ),
                                    collider: Collider::ball(planet.radius),
                                    additional_mass_properties: AdditionalMassProperties::Mass(
                                    collider: Collider::circle(planet.radius),
                                    mass: Mass(
                                        planet.mass,
                                    ),
                                })

M crates/unified/src/server/player.rs => crates/unified/src/server/player.rs +48 -73
@@ 5,8 5,7 @@ use crate::server::part::SpawnPartRequest;
use crate::server::system_sets::PlayerInputSet;
use crate::server::world_config::WorldConfigResource;
use crate::server::{ConnectedGameEntity, ConnectedNetworkEntity};
use bevy::prelude::*;
use bevy_rapier2d::prelude::{ExternalForce, FixedJointBuilder, ImpulseJoint, Velocity};
use crate::prelude::*;
use bevy_replicon::prelude::{ClientId, FromClient};
use std::f32::consts::PI;



@@ 17,34 16,32 @@ pub fn player_management_plugin(app: &mut App) {
            handle_new_players,
            player_thrust,
            magic_fuel_regen,
            (reprocess_reattached_parts, dragging).chain(),
            dragging,
        )
            .in_set(PlayerInputSet),
    );
}

#[derive(Component)]
struct JointNeedsCreation(ImpulseJoint);

fn disconnect_part(
    entity: Entity,
    recursed_entity: Entity,
    joints: &Joints,
    q_joints: Query<&Joints>,
    q_peer: Query<(Entity, &Peer, &JointOf)>,
    mut processed_peers: &mut Vec<Entity>,
    processed_peers: &mut Vec<Entity>,
    mut commands: Commands,
) {
    trace!(?entity, ?joints, ?processed_peers, "recursive disconnect");
    // recursive disconnect part
    for joint in &**joints {
        let Ok((p_e, other_joint_handle, _)) = q_peer.get(*joint) else {
        let Ok((p_e, our_peer_object, _)) = q_peer.get(*joint) else {
            continue;
        };
        if processed_peers.contains(&p_e) { continue };
        let other_joint = other_joint_handle.0;
        if processed_peers.contains(&p_e) { continue }
        let other_joint = our_peer_object.peer_joint_entity_id;

        commands.entity(*joint).remove::<Peer>();
        commands.entity(our_peer_object.physics_joint).despawn();
        processed_peers.push(p_e);

        let Ok((p_e_2, _, other_joint_of)) = q_peer.get(other_joint) else {


@@ 63,8 60,8 @@ fn disconnect_part(
    }
    for ppeer in processed_peers {
        commands.entity(*ppeer).remove::<Peer>();
        commands.entity(*ppeer).remove::<PartInShip>();
    }
    commands.entity(entity).remove::<ImpulseJoint>();
    commands.entity(entity).remove::<PartInShip>();
}



@@ 75,8 72,9 @@ fn dragging(
            &mut Transform,
            Option<&PartInShip>,
            Entity,
            &mut Velocity,
            &mut LinearVelocity,
            &Joints,
            &mut AngularVelocity,
        ),
        (With<Part>, Without<Joint>),
    >,


@@ 84,7 82,7 @@ fn dragging(
    joints: Query<(&Joint, &JointOf, &Transform, Option<&Peer>, Entity)>,
    peer: Query<(Entity, &Peer, &JointOf)>,
    q_joints: Query<&Joints>,
    q_joint: Query<&ImpulseJoint>,
    q_joint: Query<&FixedJoint>,
    clients: Query<&ConnectedNetworkEntity>,
    mut commands: Commands,
) {


@@ 105,7 103,8 @@ fn dragging(

        let mut teleport_to_translation = Vec2::new(0.0, 0.0);
        let mut teleport_to_rotation = Quat::from_rotation_z(0.0);
        let mut new_vel = None;
        let mut new_linvel = None;
        let mut new_angvel = None;

        if let Some(snap_to) = event.snap_target
            && let Some(peer_snap) = event.peer_snap


@@ 192,9 191,25 @@ fn dragging(
                commands.reborrow(),
            );

            // create the joint...
            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);

            let joint_id = commands.spawn(joint).id();

            // create the peering component...
            commands.entity(source_joint.4).insert(Peer(target_joint.4, true));
            commands.entity(target_joint.4).insert(Peer(source_joint.4, true));
            commands.entity(source_joint.4).insert(Peer {
                peer_joint_entity_id: target_joint.4,
                processed: true,
                physics_joint: joint_id
            });
            commands.entity(target_joint.4).insert(Peer {
                peer_joint_entity_id: source_joint.4,
                processed: true,
                physics_joint: joint_id
            });

            // propagate PartInShip...



@@ 211,44 226,12 @@ fn dragging(
            let rotation = event.set_rotation.to_scaled_axis().z;
            let rotation = Rot2::radians(rotation);

            // create the joint...
            let joint = FixedJointBuilder::new()
                .local_anchor1(target_joint.2.translation.xy())
                .local_basis1(
                    target_joint.0.transform.rotation.to_euler(EulerRot::ZYX).0 + PI
                        - source_joint.0.transform.rotation.to_euler(EulerRot::ZYX).0,
                );

            commands.entity(source_part.2).remove::<ImpulseJoint>();
            if did_disconnect {
                // we disconnected this part this tick, and are performing a "reattachment"
                // (dragging an already attached part from peering point A to peering point B)

                // If we're reattaching to a different part, rapier will ignore our new attachment
                // as it will be seen as a mutation (removing and adding a component in the
                // same tick is considered equivalent to mutation by Bevy).
                // As Rapier does not allow you to mutate the source/destination of a joint,
                // the change will be outright ignored.

                // Since there is no (easy) way to get the real joint information back out of Rapier,
                // or to force it to accept what it sees as invalid mutation,
                // we need to delay the creation of the new joint by 1 tick so it's noticed by Rapier
                // This component will be swapped out for a real ImpulseJoint on the next tick
                // by `reprocess_reattached_parts` (in this file)
                commands
                    .entity(source_part.2)
                    .insert(JointNeedsCreation(ImpulseJoint::new(target_part.2, joint)));
            } else {
                commands
                    .entity(source_part.2)
                    .insert(ImpulseJoint::new(target_part.2, joint));
            }

            teleport_to_translation = target_position.translation.xy();
            teleport_to_rotation = target_position.rotation
                * source_joint.0.transform.rotation.inverse()
                * Quat::from_rotation_z(PI);
            new_vel = Some(*target_part.3);
            new_linvel = Some(*target_part.3);
            new_angvel = Some(*target_part.5);
            // and we're done!
        } else {
            warn!(


@@ 274,26 257,16 @@ fn dragging(
        part.0.translation.x = teleport_to_translation.x;
        part.0.translation.y = teleport_to_translation.y;
        part.0.rotation = teleport_to_rotation; // client calculates this; no reason to recalculate
        if let Some(new_vel) = new_vel {
        if let Some(new_vel) = new_linvel {
            *part.3 = new_vel;
        }
        if let Some(new_vel) = new_angvel {
            *part.5 = new_vel;
        }
        // ( the math sucks )
    }
}

// LOGIC: **MUST** run BEFORE `dragging`
fn reprocess_reattached_parts(
    reattached: Query<(Entity, &JointNeedsCreation)>,
    mut commands: Commands,
) {
    for (e, j) in &reattached {
        commands
            .entity(e)
            .remove::<JointNeedsCreation>()
            .insert(j.0);
    }
}

fn handle_new_players(
    mut commands: Commands,
    q_new_clients: Query<Entity, Added<ConnectedGameEntity>>,


@@ 338,7 311,6 @@ fn handle_new_players(
                power_capacity: 25.0,
                power: 25.0,
            })
            .insert(Velocity::default())
            .insert(Player {
                client: joined_player,
            });


@@ 355,7 327,7 @@ fn player_thrust(
    mut players: Query<(
        &Transform,
        &Part,
        &mut ExternalForce,
        &mut ConstantForce,
        &mut PlayerThrust,
        &mut PlayerStorage,
    )>,


@@ 385,13 357,13 @@ fn player_thrust(
            ThrustEvent::Right(on) => thrust.right = on,
        }
    }
    for (transform, part, mut force, thrust, mut storage) in &mut players {
    for (transform, part, force, thrust, storage) in &mut players {
        let Some(world_config) = &world_config.config else {
            return;
        };

        let forward = (transform.rotation * Vec3::Y).xy();
        let mut external_force = ExternalForce::default();
        let external_force = ConstantForce::default();

        // indices are quadrants:
        // 1 | 0


@@ 430,28 402,31 @@ fn player_thrust(
            world_config.part.default_height / 2.0,
        )
        .length();
        external_force += ExternalForce::at_point(

        // TODO: TF does this mess even do?
        /*
        external_force += ConstantForce::at_point(
            -forward * thrusters[0] * world_config.hearty.thrust,
            transform.translation.xy()
                + half_size
                    * Vec2::new((1.0 * PI / 4.0).cos(), (1.0 * PI / 4.0).sin()).rotate(forward),
            transform.translation.xy(),
        );
        external_force += ExternalForce::at_point(
        external_force += ConstantForce::at_point(
            forward * thrusters[1] * world_config.hearty.thrust,
            transform.translation.xy()
                + half_size
                    * Vec2::new((3.0 * PI / 4.0).cos(), (3.0 * PI / 4.0).sin()).rotate(forward),
            transform.translation.xy(),
        );
        external_force += ExternalForce::at_point(
        external_force += ConstantForce::at_point(
            forward * thrusters[2] * world_config.hearty.thrust,
            transform.translation.xy()
                + half_size
                    * Vec2::new((5.0 * PI / 4.0).cos(), (5.0 * PI / 4.0).sin()).rotate(forward),
            transform.translation.xy(),
        );
        external_force += ExternalForce::at_point(
        external_force += ConstantForce::at_point(
            -forward * thrusters[3] * world_config.hearty.thrust,
            transform.translation.xy()
                + half_size


@@ 461,6 436,6 @@ fn player_thrust(
        *force += external_force;

        storage.fuel -=
            thrusters.iter().sum::<f32>() * part.strong_config.thruster.as_ref().unwrap().flow_rate;
            thrusters.iter().sum::<f32>() * part.strong_config.thruster.as_ref().unwrap().flow_rate;*/
    }
}

M crates/unified/src/server/system_sets.rs => crates/unified/src/server/system_sets.rs +1 -1
@@ 1,4 1,4 @@
use bevy::prelude::SystemSet;
use crate::prelude::*;

#[derive(SystemSet, Clone, PartialEq, Eq, Debug, Hash)]
pub struct WorldUpdateSet;

M crates/unified/src/server/world_config.rs => crates/unified/src/server/world_config.rs +1 -1
@@ 1,6 1,6 @@
use crate::config::world::GlobalWorldConfig;
use bevy::asset::Handle;
use bevy::prelude::*;
use crate::prelude::*;

pub fn world_config_plugin(app: &mut App) {
    app.init_resource::<WorldConfigResource>()

M crates/unified/src/server_plugins.rs => crates/unified/src/server_plugins.rs +3 -2
@@ 11,11 11,12 @@ use bevy_common_assets::toml::TomlAssetPlugin;
use bevy_replicon::RepliconPlugins;
use std::net::SocketAddr;
use std::time::Duration;
use avian2d::PhysicsPlugins;
use bevy::state::app::StatesPlugin;

pub struct ServerPluginGroup {
    pub bind: SocketAddr,
    pub tick_rate: f64,
    pub tick_rate: f32,
    pub max_clients: usize,
}
impl PluginGroup for ServerPluginGroup {


@@ 25,7 26,7 @@ impl PluginGroup for ServerPluginGroup {
            .add(TaskPoolPlugin::default())
            .add(FrameCountPlugin)
            .add(TimePlugin)
            .add(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64(
            .add(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f32(
                1.0 / self.tick_rate,
            )))
            .add_group(RepliconPlugins)

M crates/unified/src/shared_plugins.rs => crates/unified/src/shared_plugins.rs +22 -6
@@ 1,20 1,27 @@
use avian2d::PhysicsPlugins;
use crate::attachment::{Joint, JointOf, PartInShip, Peer, Ship, SnapOf, SnapOfJoint};
use crate::config::planet::Planet;
use crate::ecs::{DragRequestEvent, Part, Particles, Player, PlayerStorage, ThrustEvent};
use bevy::app::{App, PluginGroup, PluginGroupBuilder};
use bevy::prelude::*;
use bevy::state::app::StatesPlugin;
use bevy_rapier2d::prelude::*;
use crate::prelude::*;
//use bevy_rapier2d::prelude::*;
use bevy_replicon::prelude::{AppRuleExt, Channel, ClientMessageAppExt};
use crate::physics::register_physics_components_for_replication;

pub struct SharedPluginGroup;

impl PluginGroup for SharedPluginGroup {
    fn build(self) -> PluginGroupBuilder {
        PluginGroupBuilder::start::<Self>()
            .add(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0))
            //.add(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0))
            .add_group(
                PhysicsPlugins::default()
                    .with_length_unit(100.0)
                    .set(PhysicsInterpolationPlugin::interpolate_all())
            )
            .add(physics_setup_plugin)
            .add(register_everything)
            .add(register_physics_components_for_replication)
    }
}



@@ 23,8 30,8 @@ pub fn register_everything(app: &mut App) {
        .add_mapped_client_message::<DragRequestEvent>(Channel::Ordered)
        .replicate::<Transform>()
        .replicate::<GlobalTransform>()
        .replicate::<Collider>()
        .replicate::<RigidBody>()
        //.replicate::<Collider>()
        //.replicate::<RigidBody>()
        .replicate::<Planet>()
        .replicate::<Part>()
        .replicate::<Player>()


@@ 41,10 48,18 @@ pub fn register_everything(app: &mut App) {
}

fn physics_setup_plugin(app: &mut App) {
    app.insert_resource(Gravity::ZERO);
    app.add_systems(Startup, setup_physics);
}

fn setup_physics(

) {

}

/*
fn setup_physics(
    mut rapier_config: Query<&mut RapierConfiguration>,
    mut rapier_context: Query<&mut RapierContextSimulation>,
) {


@@ 54,3 69,4 @@ fn setup_physics(
    let mut params = ctx.integration_parameters;
    params.num_internal_stabilization_iterations = 16;
}
*/
\ No newline at end of file