From 2da0954c6ae9dc630ff3a1dad75b826d4be38aea Mon Sep 17 00:00:00 2001 From: core Date: Mon, 30 Jun 2025 00:21:57 -0400 Subject: [PATCH] client start --- Cargo.lock | 97 ++++++++++++++++++++++++++-- crates/unified/Cargo.toml | 1 + crates/unified/src/client/mod.rs | 64 +++++++++++++++++- crates/unified/src/client_plugins.rs | 2 + crates/unified/src/ecs.rs | 15 +++++ crates/unified/src/server/mod.rs | 35 +++++++++- crates/unified/src/shared_plugins.rs | 11 +++- 7 files changed, 215 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6be48cd7c72557ca4adb1729679d6a64efd074d2..57b57aaf219b615788c2226e90e45a17f7fbe4fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" @@ -3697,6 +3714,15 @@ dependencies = [ "bytemuck", ] +[[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" @@ -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", ] @@ -6316,6 +6344,15 @@ dependencies = [ "num-traits", ] +[[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" @@ -6394,6 +6431,31 @@ dependencies = [ "spade", ] +[[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" @@ -6873,12 +6935,37 @@ 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" @@ -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", diff --git a/crates/unified/Cargo.toml b/crates/unified/Cargo.toml index 2d79285eba683ad7f2314dc61040368190fbf1c6..fb607f589491e25fa5bb46a913d38907fd855964 100644 --- a/crates/unified/Cargo.toml +++ b/crates/unified/Cargo.toml @@ -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"] } diff --git a/crates/unified/src/client/mod.rs b/crates/unified/src/client/mod.rs index 24100fbd9ebb77357028cafbe75075d6a1d9ed7b..513aca353a89850f4b83395ff9b69867df2d54a8 100644 --- a/crates/unified/src/client/mod.rs +++ b/crates/unified/src/client/mod.rs @@ -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| { 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>, asset_server: Res) { + 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>, asset_server: Res) { + 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>, + q_camera: Query<(&Camera, &GlobalTransform), With>, + mut coords: ResMut +) { + 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, + button_input: Res>, + mut events: EventWriter +) { + if let Some(position) = cursor_world_coordinates.0 && button_input.pressed(MouseButton::Left) { + events.write(SendBallHere(position)); } } \ No newline at end of file diff --git a/crates/unified/src/client_plugins.rs b/crates/unified/src/client_plugins.rs index 5f6144c9491dfd24a4c39bb7fc2c18bb1574151b..88b93f0993cda142bf225fa2b5deade9173d1255 100644 --- a/crates/unified/src/client_plugins.rs +++ b/crates/unified/src/client_plugins.rs @@ -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 diff --git a/crates/unified/src/ecs.rs b/crates/unified/src/ecs.rs index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a5b730ce0cf84caa44c32d9bc3988ad82286a8a9 100644 --- a/crates/unified/src/ecs.rs +++ b/crates/unified/src/ecs.rs @@ -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); + +#[derive(Debug, Default, Deserialize, Event, Serialize)] +pub struct SendBallHere(pub Vec2); \ No newline at end of file diff --git a/crates/unified/src/server/mod.rs b/crates/unified/src/server/mod.rs index fd0384b07d6b354fed3a0907ca18b8f021dd457d..088dc6ae95575c7cf61543588f193971d8a72c20 100644 --- a/crates/unified/src/server/mod.rs +++ b/crates/unified/src/server/mod.rs @@ -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>, mut ball: Query<(&mut Transform, &mut Velocity), With>) { + 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 diff --git a/crates/unified/src/shared_plugins.rs b/crates/unified/src/shared_plugins.rs index 237d25feac6af69d5bef26b49d61ac87c14de046..02efe4b048ad895e542d0941ebcc0ad15f5cab99 100644 --- a/crates/unified/src/shared_plugins.rs +++ b/crates/unified/src/shared_plugins.rs @@ -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::() + .add(RapierPhysicsPlugin::::pixels_per_meter(100.0)) .add(register_everything) } } pub fn register_everything(app: &mut App) { - app; + app + .add_client_event::(Channel::Ordered) + .replicate::() + .replicate::() + .replicate::(); } \ No newline at end of file