~starkingdoms/starkingdoms

2da0954c6ae9dc630ff3a1dad75b826d4be38aea — core 5 months ago 66ecf5a
client start
M Cargo.lock => Cargo.lock +93 -4
@@ 1646,7 1646,21 @@ dependencies = [
 "bitflags 2.9.1",
 "log",
 "nalgebra 0.32.6",
 "rapier2d",
 "rapier2d 0.18.0",
 "serde",
]

[[package]]
name = "bevy_rapier2d"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ad67c66adfccd20a3253e2abc135aa38d57b5b35a63abe682737c763c2807f9"
dependencies = [
 "bevy 0.16.1",
 "bitflags 2.9.1",
 "log",
 "nalgebra 0.33.2",
 "rapier2d 0.25.1",
 "serde",
]



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

[[package]]
name = "bit_field"


@@ 3698,6 3715,15 @@ dependencies = [
]

[[package]]
name = "ena"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5"
dependencies = [
 "log",
]

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


@@ 5642,11 5668,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b"
dependencies = [
 "approx",
 "glam 0.29.3",
 "matrixmultiply",
 "nalgebra-macros",
 "num-complex",
 "num-rational",
 "num-traits",
 "serde",
 "simba 0.9.0",
 "typenum",
]


@@ 6317,6 6345,15 @@ dependencies = [
]

[[package]]
name = "ordered-float"
version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01"
dependencies = [
 "num-traits",
]

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


@@ 6395,6 6432,31 @@ dependencies = [
]

[[package]]
name = "parry2d"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b89f8a3309b82a3a81a6957c7916fe00834e79678451683b048e8d75109b9e4"
dependencies = [
 "approx",
 "arrayvec",
 "bitflags 2.9.1",
 "downcast-rs 2.0.1",
 "either",
 "ena",
 "hashbrown 0.15.4",
 "log",
 "nalgebra 0.33.2",
 "num-derive",
 "num-traits",
 "ordered-float 5.0.0",
 "serde",
 "simba 0.9.0",
 "slab",
 "spade",
 "thiserror 2.0.12",
]

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


@@ 6873,13 6935,38 @@ dependencies = [
 "nalgebra 0.32.6",
 "num-derive",
 "num-traits",
 "parry2d",
 "parry2d 0.13.8",
 "rustc-hash 1.1.0",
 "serde",
 "simba 0.8.1",
]

[[package]]
name = "rapier2d"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ec6acdc5db3699c64e000945450c844d34b215dae3bf875b40e20b1909c0063"
dependencies = [
 "approx",
 "arrayvec",
 "bit-vec 0.8.0",
 "bitflags 2.9.1",
 "crossbeam",
 "downcast-rs 2.0.1",
 "log",
 "nalgebra 0.33.2",
 "num-derive",
 "num-traits",
 "ordered-float 5.0.0",
 "parry2d 0.20.2",
 "profiling",
 "rustc-hash 2.1.1",
 "serde",
 "simba 0.9.0",
 "thiserror 2.0.12",
]

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


@@ 7642,6 7729,7 @@ dependencies = [
 "hashbrown 0.15.4",
 "num-traits",
 "robust",
 "serde",
 "smallvec",
]



@@ 7680,6 7768,7 @@ name = "starkingdoms"
version = "0.1.0"
dependencies = [
 "bevy 0.16.1",
 "bevy_rapier2d 0.30.0",
 "bevy_replicon",
 "bevy_replicon_renet2",
 "clap",


@@ 7742,7 7831,7 @@ name = "starkingdoms-server"
version = "0.1.0-alpha1"
dependencies = [
 "bevy 0.16.1",
 "bevy_rapier2d",
 "bevy_rapier2d 0.25.0",
 "crossbeam-channel",
 "hex",
 "hmac",


@@ 9193,7 9282,7 @@ dependencies = [
 "ndk-sys 0.5.0+25.2.9519653",
 "objc",
 "once_cell",
 "ordered-float",
 "ordered-float 4.6.0",
 "parking_lot",
 "profiling",
 "range-alloc",

M crates/unified/Cargo.toml => crates/unified/Cargo.toml +1 -0
@@ 6,6 6,7 @@ version = "0.1.0"

[dependencies]
bevy = { version = "0.16", features = ["serialize"] }
bevy_rapier2d = { version = "0.30", features = ["serde-serialize"] }

bevy_replicon = "0.34"
bevy_replicon_renet2 = { version = "0.10", features = ["native_transport"] }

M crates/unified/src/client/mod.rs => crates/unified/src/client/mod.rs +61 -3
@@ 1,12 1,13 @@
use std::net::{SocketAddr, UdpSocket};
use std::time::SystemTime;
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use bevy_rapier2d::prelude::RigidBody;
use bevy_replicon::prelude::RepliconChannels;
use bevy_replicon_renet2::netcode::{ClientAuthentication, NetcodeClientTransport, NativeSocket};
use bevy_replicon_renet2::renet2::{ConnectionConfig, RenetClient};
use bevy_replicon_renet2::RenetChannelsExt;


use crate::ecs::{Ball, CursorWorldCoordinates, Ground, MainCamera, SendBallHere};

pub struct ClientPlugin {
    pub server: SocketAddr


@@ 15,6 16,7 @@ impl Plugin for ClientPlugin {
    fn build(&self, app: &mut App) {
        let server = self.server.clone();
        app
            .insert_resource(CursorWorldCoordinates(None))
            .add_systems(Startup, move |mut commands: Commands, channels: Res<RepliconChannels>| {
                let client = RenetClient::new(
                    ConnectionConfig::from_channels(channels.server_configs(), channels.client_configs()),


@@ 36,7 38,63 @@ impl Plugin for ClientPlugin {
                commands.insert_resource(transport);

                info!(?client_id, "connected!");
            });
            })
            .add_systems(Startup, setup_graphics)
            .add_systems(Update, add_ball_sprite)
            .add_systems(Update, add_ground_sprite)
            .add_systems(Update, update_cursor_position)
            .add_systems(Update, teleport_cube_around);
    }
}

fn setup_graphics(mut commands: Commands) {
    commands.spawn(Camera2d::default())
        .insert(MainCamera);
}

fn add_ball_sprite(mut commands: Commands, q: Query<Entity, Added<Ball>>, asset_server: Res<AssetServer>) {
    for item in &q {
        let mut sprite = Sprite::from_image(asset_server.load("textures/earth.png"));
        sprite.custom_size = Some(Vec2::new(100.0, 100.0));

        commands
            .entity(item)
            .insert(sprite);
    }
}
fn add_ground_sprite(mut commands: Commands, q: Query<Entity, Added<Ground>>, asset_server: Res<AssetServer>) {
    for item in &q {
        let mut sprite = Sprite::from_image(asset_server.load("textures/hearty.png"));
        sprite.custom_size = Some(Vec2::new(1000.0, 100.0));

        commands
            .entity(item)
            .insert(sprite);
    }
}

fn update_cursor_position(
    q_windows: Query<&Window, With<PrimaryWindow>>,
    q_camera: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
    mut coords: ResMut<CursorWorldCoordinates>
) {
    let (camera, camera_transform) = q_camera.single().unwrap();
    let window = q_windows.single().unwrap();

    if let Some(world_position) = window.cursor_position()
        .and_then(|cursor| camera.viewport_to_world(camera_transform, cursor).ok())
        .map(|ray| ray.origin.truncate()) {
        coords.0 = Some(world_position);
    } else {
        coords.0 = None;
    }
}
fn teleport_cube_around(
    cursor_world_coordinates: Res<CursorWorldCoordinates>,
    button_input: Res<ButtonInput<MouseButton>>,
    mut events: EventWriter<SendBallHere>
) {
    if let Some(position) = cursor_world_coordinates.0 && button_input.pressed(MouseButton::Left) {
        events.write(SendBallHere(position));
    }
}
\ No newline at end of file

M crates/unified/src/client_plugins.rs => crates/unified/src/client_plugins.rs +2 -0
@@ 1,6 1,7 @@
use std::net::SocketAddr;
use bevy::app::{PluginGroup, PluginGroupBuilder};
use bevy::DefaultPlugins;
use bevy_rapier2d::render::RapierDebugRenderPlugin;
use bevy_replicon::RepliconPlugins;
use bevy_replicon_renet2::RepliconRenetClientPlugin;
use crate::client::ClientPlugin;


@@ 17,5 18,6 @@ impl PluginGroup for ClientPluginGroup {
            )
            .add(RepliconRenetClientPlugin)
            .add(ClientPlugin { server: self.server })
            .add(RapierDebugRenderPlugin::default())
    }
}
\ No newline at end of file

M crates/unified/src/ecs.rs => crates/unified/src/ecs.rs +15 -0
@@ 0,0 1,15 @@
use bevy::math::Vec2;
use bevy::prelude::{Component, Event, Resource};
use serde::{Deserialize, Serialize};

#[derive(Component, Serialize, Deserialize)]
pub struct Ball;
#[derive(Component, Serialize, Deserialize)]
pub struct Ground;
#[derive(Component)]
pub struct MainCamera;
#[derive(Resource, Default)]
pub struct CursorWorldCoordinates(pub Option<Vec2>);

#[derive(Debug, Default, Deserialize, Event, Serialize)]
pub struct SendBallHere(pub Vec2);
\ No newline at end of file

M crates/unified/src/server/mod.rs => crates/unified/src/server/mod.rs +33 -2
@@ 1,10 1,12 @@
use std::net::{SocketAddr, UdpSocket};
use std::time::{SystemTime, UNIX_EPOCH};
use bevy::prelude::*;
use bevy_replicon::prelude::RepliconChannels;
use bevy_rapier2d::prelude::{Collider, Restitution, RigidBody, Velocity};
use bevy_replicon::prelude::{FromClient, Replicated, RepliconChannels};
use bevy_replicon_renet2::netcode::{NativeSocket, NetcodeServerTransport, ServerAuthentication, ServerSetupConfig};
use bevy_replicon_renet2::renet2::{ConnectionConfig, RenetServer};
use bevy_replicon_renet2::RenetChannelsExt;
use crate::ecs::{Ball, Ground, SendBallHere};

pub struct ServerPlugin {
    pub bind: SocketAddr,


@@ 38,6 40,35 @@ impl Plugin for ServerPlugin {
                commands.insert_resource(transport);

                info!("websocket server listening");
            });
            })
            .add_systems(Startup, setup_physics)
            .add_systems(PreUpdate, receive_send_ball_here);
    }
}

fn setup_physics(mut commands: Commands) {
    commands.spawn(Collider::cuboid(500.0, 50.0))
        .insert(Transform::from_xyz(0.0, -100.0, 0.0))
        .insert(Restitution::coefficient(1.0))
        .insert(Ground)
        .insert(Replicated);

    commands.spawn(RigidBody::Dynamic)
        .insert(Collider::ball(50.0))
        .insert(Restitution::coefficient(1.0))
        .insert(Transform::from_xyz(0.0, 400.0, 0.0))
        .insert(Velocity::default())
        .insert(Ball)
        .insert(Replicated);
}

fn receive_send_ball_here(mut events: EventReader<FromClient<SendBallHere>>, mut ball: Query<(&mut Transform, &mut Velocity), With<Ball>>) {
    for FromClient { client_entity, event } in events.read() {
        for (mut position, mut velocity) in &mut ball {
            position.translation.x = event.0.x;
            position.translation.y = event.0.y;
            velocity.linvel = Vec2::ZERO;
            velocity.angvel = 0.0;
        }
    }
}
\ No newline at end of file

M crates/unified/src/shared_plugins.rs => crates/unified/src/shared_plugins.rs +10 -1
@@ 1,14 1,23 @@
use bevy::app::{App, PluginGroup, PluginGroupBuilder};
use bevy::prelude::{Sprite, Transform};
use bevy_rapier2d::prelude::*;
use bevy_replicon::prelude::{AppRuleExt, Channel, ClientEventAppExt};
use crate::ecs::{Ball, Ground, SendBallHere};

pub struct SharedPluginGroup;

impl PluginGroup for SharedPluginGroup {
    fn build(self) -> PluginGroupBuilder {
        PluginGroupBuilder::start::<Self>()
            .add(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0))
            .add(register_everything)
    }
}

pub fn register_everything(app: &mut App) {
    app;
    app
        .add_client_event::<SendBallHere>(Channel::Ordered)
        .replicate::<Transform>()
        .replicate::<Ball>()
        .replicate::<Ground>();
}
\ No newline at end of file