From 3e6313b1fbbea06725847bcf9eedf9b97b353e7e Mon Sep 17 00:00:00 2001 From: jacopograndi Date: Wed, 3 Aug 2022 22:23:52 +0200 Subject: integrating ggrs and rapier --- Cargo.lock | 113 ++++++++++++++++++++++++++++++++++++-- Cargo.toml | 3 ++ launch_2p.sh | 4 ++ src/main.rs | 174 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 261 insertions(+), 33 deletions(-) create mode 100755 launch_2p.sh diff --git a/Cargo.lock b/Cargo.lock index 146c0c6..0d8296e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -178,6 +178,17 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -949,9 +960,9 @@ checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] name = "bytemuck" -version = "1.9.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" +checksum = "a5377c8865e74a160d21f29c2d40669f53286db6eab59b88540cbb12ffc8b835" dependencies = [ "bytemuck_derive", ] @@ -1038,6 +1049,21 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim 0.8.0", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "cocoa" version = "0.24.0" @@ -1368,7 +1394,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn", ] @@ -1821,6 +1847,15 @@ dependencies = [ "serde", ] +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1934,8 +1969,11 @@ dependencies = [ "bevy", "bevy_ggrs", "bevy_rapier2d", + "bytemuck", + "ggrs", "serde", "serde_json", + "structopt", ] [[package]] @@ -2697,6 +2735,30 @@ dependencies = [ "toml", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.39" @@ -3042,12 +3104,42 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "structopt" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "svg_fmt" version = "0.4.1" @@ -3099,6 +3191,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.31" @@ -3243,6 +3344,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +[[package]] +name = "unicode-segmentation" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" + [[package]] name = "unicode-width" version = "0.1.9" diff --git a/Cargo.toml b/Cargo.toml index e0ae8c6..609e9af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,6 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" bevy_ggrs = { git = "https://github.com/paxsethorld/bevy_ggrs", rev = "bc78d31" } +ggrs = { git = "https://github.com/gschup/ggrs", features = ["sync-send"] } +bytemuck = "1.11.0" +structopt = "0.3.26" diff --git a/launch_2p.sh b/launch_2p.sh new file mode 100755 index 0000000..14fd8a7 --- /dev/null +++ b/launch_2p.sh @@ -0,0 +1,4 @@ +#! /usr/bin/bash + +cargo run -- --local-port=40000 --players localhost 127.0.0.1:40001 & +cargo run -- --local-port=40001 --players localhost 127.0.0.1:40001 & diff --git a/src/main.rs b/src/main.rs index d37fdde..1074319 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,36 +8,150 @@ use bevy::{prelude::*, render::camera::ScalingMode, window::WindowResized}; use bevy_rapier2d::{pipeline::CollisionEvent::*, prelude::*}; -/// i can step the rapier simulation by adding to the rollback systems -/// the rapier system set. bevy_rapier provides 4 system sets. -/// bevy_ggrs can take a schedule and a type, so no RapierContext -/// in the schedule i can -/// deserialize RapierContext -/// run the game logic -/// run the rapier systems -/// serialize RapierContext -/// the only problem is the first RapierContext, but default should be fine - -fn main() { - App::new() - .insert_resource(WindowDescriptor { - title: "Tanks!".to_string(), - resizable: true, - ..Default::default() - }) - .add_plugins(DefaultPlugins) - .add_startup_system(spawn_camera) - .add_startup_system(setup) - .add_plugin(LogDiagnosticsPlugin::default()) - .add_plugin(FrameTimeDiagnosticsPlugin::default()) - .add_plugin(RapierPhysicsPlugin::::pixels_per_meter(100.0)) - .add_plugin(RapierDebugRenderPlugin::default()) - .add_system_to_stage(CoreStage::Update, movement) - .add_system_to_stage(CoreStage::Update, shoot) - .add_system_to_stage(CoreStage::PostUpdate, camera_follow) - .add_system_to_stage(CoreStage::PostUpdate, hits) - .add_system(window_resized_event) - .run(); +use bevy_ggrs::{GGRSPlugin, SessionType}; +use ggrs::{Config, PlayerHandle, PlayerType, SessionBuilder, UdpNonBlockingSocket}; + +use bytemuck::{Pod, Zeroable}; +use std::net::SocketAddr; + +use structopt::StructOpt; + +#[derive(Debug)] +pub struct GGRSConfig; +impl Config for GGRSConfig { + type Input = BoxInput; + type State = u8; + type Address = SocketAddr; +} + +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Pod, Zeroable)] +pub struct BoxInput { + pub inp: u8, +} + +const FPS: usize = 60; +const ROLLBACK_DEFAULT: &str = "rollback_default"; + +const INPUT_UP: u8 = 1 << 0; +const INPUT_DOWN: u8 = 1 << 1; +const INPUT_LEFT: u8 = 1 << 2; +const INPUT_RIGHT: u8 = 1 << 3; + +pub fn input(_handle: In, keyboard_input: Res>) -> BoxInput { + let mut input: u8 = 0; + + if keyboard_input.pressed(KeyCode::W) { + input |= INPUT_UP; + } + if keyboard_input.pressed(KeyCode::A) { + input |= INPUT_LEFT; + } + if keyboard_input.pressed(KeyCode::S) { + input |= INPUT_DOWN; + } + if keyboard_input.pressed(KeyCode::D) { + input |= INPUT_RIGHT; + } + + BoxInput { inp: input } +} + +// structopt will read command line parameters for u +#[derive(StructOpt)] +struct Opt { + #[structopt(short, long)] + local_port: u16, + #[structopt(short, long)] + players: Vec, + #[structopt(short, long)] + spectators: Vec, +} + +fn main() -> Result<(), Box> { + // read cmd line arguments + let opt = Opt::from_args(); + let num_players = opt.players.len(); + assert!(num_players > 0); + + // create a GGRS session + let mut sess_build = SessionBuilder::::new() + .with_num_players(num_players) + .with_max_prediction_window(12) // (optional) set max prediction window + .with_input_delay(2); // (optional) set input delay for the local player + + // add players + for (i, player_addr) in opt.players.iter().enumerate() { + // local player + if player_addr == "localhost" { + sess_build = sess_build.add_player(PlayerType::Local, i)?; + } else { + // remote players + let remote_addr: SocketAddr = player_addr.parse()?; + sess_build = sess_build.add_player(PlayerType::Remote(remote_addr), i)?; + } + } + + // optionally, add spectators + for (i, spec_addr) in opt.spectators.iter().enumerate() { + sess_build = sess_build.add_player(PlayerType::Spectator(*spec_addr), num_players + i)?; + } + + // start the GGRS session + let socket = UdpNonBlockingSocket::bind_to_port(opt.local_port)?; + let sess = sess_build.start_p2p_session(socket)?; + + let mut app = App::new(); + GGRSPlugin::::new() + .with_update_frequency(FPS) + .with_input_system(input) + .register_rollback_type::() + .register_rollback_type::() + .with_rollback_schedule( + Schedule::default().with_stage( + ROLLBACK_DEFAULT, + SystemStage::parallel() + .with_system_set(RapierPhysicsPlugin::<()>::get_systems( + PhysicsStages::SyncBackend, + )) + .with_system_set(RapierPhysicsPlugin::<()>::get_systems( + PhysicsStages::StepSimulation, + )) + .with_system_set(RapierPhysicsPlugin::<()>::get_systems( + PhysicsStages::Writeback, + )) + .with_system_set(RapierPhysicsPlugin::<()>::get_systems( + PhysicsStages::DetectDespawn, + )), + ), + ) + .build(&mut app); + + app.insert_resource(WindowDescriptor { + title: "Tanks!".to_string(), + resizable: true, + ..Default::default() + }) + // add your GGRS session + .insert_resource(sess) + .insert_resource(SessionType::P2PSession) + .add_plugins(DefaultPlugins) + .add_startup_system(spawn_camera) + .add_startup_system(setup) + .add_plugin(LogDiagnosticsPlugin::default()) + .add_plugin(FrameTimeDiagnosticsPlugin::default()) + .add_plugin( + RapierPhysicsPlugin::::pixels_per_meter(100.0).with_default_system_setup(false), + ) + .add_plugin(RapierDebugRenderPlugin::default()) + .add_system_to_stage(CoreStage::Update, movement) + .add_system_to_stage(CoreStage::Update, shoot) + .add_system_to_stage(CoreStage::PostUpdate, camera_follow) + .add_system_to_stage(CoreStage::PostUpdate, hits) + .add_system(window_resized_event) + .run(); + + Ok(()) } fn window_resized_event( -- cgit v1.2.3-54-g00ecf