From 25f7e2c301dfb7da4c40518d697f88f5a5fe038f Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Sun, 29 Oct 2023 12:06:45 +0100 Subject: [PATCH] Add bevy_matchbox examples --- bevy_matchbox/Cargo.toml | 25 ++++++++ bevy_matchbox/examples/hello.rs | 45 +++++++++++++ bevy_matchbox/examples/hello_host.rs | 77 +++++++++++++++++++++++ bevy_matchbox/examples/hello_signaling.rs | 39 ++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 bevy_matchbox/examples/hello.rs create mode 100644 bevy_matchbox/examples/hello_host.rs create mode 100644 bevy_matchbox/examples/hello_signaling.rs diff --git a/bevy_matchbox/Cargo.toml b/bevy_matchbox/Cargo.toml index 6ea3ec76..6877ec99 100644 --- a/bevy_matchbox/Cargo.toml +++ b/bevy_matchbox/Cargo.toml @@ -35,3 +35,28 @@ cfg-if = "1.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] matchbox_signaling = { version = "0.7", path = "../matchbox_signaling", optional = true } async-compat = { version = "0.2", optional = true } + +[dev-dependencies] +bevy = { version = "0.12", default-features = false, features = [ + "bevy_winit", + "bevy_render", + "bevy_pbr", + "bevy_core_pipeline", + "bevy_ui", + "bevy_text", + "bevy_asset", + "ktx2", + "zstd", + "tonemapping_luts", + "webgl2", + # gh actions runners don't like wayland + "x11", +] } + +[[example]] +name = "hello_host" +required-features = ["signaling"] + +[[example]] +name = "hello_signaling" +required-features = ["signaling"] diff --git a/bevy_matchbox/examples/hello.rs b/bevy_matchbox/examples/hello.rs new file mode 100644 index 00000000..a27f6c8e --- /dev/null +++ b/bevy_matchbox/examples/hello.rs @@ -0,0 +1,45 @@ +//! Sends messages periodically to all connected peers (or host if connected in +//! a client server topology). + +use bevy::{prelude::*, time::common_conditions::on_timer, utils::Duration}; +use bevy_matchbox::prelude::*; + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_systems(Startup, start_socket) + .add_systems(Update, receive_messages) + .add_systems( + Update, + send_message.run_if(on_timer(Duration::from_secs(5))), + ) + .run(); +} + +fn start_socket(mut commands: Commands) { + let socket = MatchboxSocket::new_reliable("ws://localhost:3536/hello"); + commands.insert_resource(socket); +} + +fn send_message(mut socket: ResMut>) { + let peers: Vec<_> = socket.connected_peers().collect(); + + for peer in peers { + let message = "Hello"; + info!("Sending message: {message:?} to {peer}"); + socket.send(message.as_bytes().into(), peer); + } +} + +fn receive_messages(mut socket: ResMut>) { + for (peer, state) in socket.update_peers() { + info!("{peer}: {state:?}"); + } + + for (_id, message) in socket.receive() { + match std::str::from_utf8(&message) { + Ok(message) => info!("Received message: {message:?}"), + Err(e) => error!("Failed to convert message to string: {e}"), + } + } +} diff --git a/bevy_matchbox/examples/hello_host.rs b/bevy_matchbox/examples/hello_host.rs new file mode 100644 index 00000000..056c3d2b --- /dev/null +++ b/bevy_matchbox/examples/hello_host.rs @@ -0,0 +1,77 @@ +//! Runs both signaling with server/client topology and runs the host in the same process +//! +//! Sends messages periodically to all connected clients. + +use bevy::{ + app::ScheduleRunnerPlugin, log::LogPlugin, prelude::*, time::common_conditions::on_timer, + utils::Duration, +}; +use bevy_matchbox::{matchbox_signaling::SignalingServer, prelude::*}; +use std::net::{Ipv4Addr, SocketAddrV4}; + +fn main() { + App::new() + // .add_plugins(DefaultPlugins) + .add_plugins(( + MinimalPlugins.set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f32( + 1. / 120., // be nice to the CPU + ))), + LogPlugin::default(), + )) + .add_systems(Startup, (start_signaling_server, start_host_socket).chain()) + .add_systems(Update, receive_messages) + .add_systems( + Update, + send_message.run_if(on_timer(Duration::from_secs(5))), + ) + .run(); +} + +fn start_signaling_server(mut commands: Commands) { + info!("Starting signaling server"); + let addr = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 3536); + let signaling_server = MatchboxServer::from( + SignalingServer::client_server_builder(addr) + .on_connection_request(|connection| { + info!("Connecting: {connection:?}"); + Ok(true) // Allow all connections + }) + .on_id_assignment(|(socket, id)| info!("{socket} received {id}")) + .on_host_connected(|id| info!("Host joined: {id}")) + .on_host_disconnected(|id| info!("Host left: {id}")) + .on_client_connected(|id| info!("Client joined: {id}")) + .on_client_disconnected(|id| info!("Client left: {id}")) + .cors() + .trace() + .build(), + ); + commands.insert_resource(signaling_server); +} + +fn start_host_socket(mut commands: Commands) { + let socket = MatchboxSocket::new_reliable("ws://localhost:3536/hello"); + commands.insert_resource(socket); +} + +fn send_message(mut socket: ResMut>) { + let peers: Vec<_> = socket.connected_peers().collect(); + + for peer in peers { + let message = "Hello, I'm the host"; + info!("Sending message: {message:?} to {peer}"); + socket.send(message.as_bytes().into(), peer); + } +} + +fn receive_messages(mut socket: ResMut>) { + for (peer, state) in socket.update_peers() { + info!("{peer}: {state:?}"); + } + + for (_id, message) in socket.receive() { + match std::str::from_utf8(&message) { + Ok(message) => info!("Received message: {message:?}"), + Err(e) => error!("Failed to convert message to string: {e}"), + } + } +} diff --git a/bevy_matchbox/examples/hello_signaling.rs b/bevy_matchbox/examples/hello_signaling.rs new file mode 100644 index 00000000..7126f3b3 --- /dev/null +++ b/bevy_matchbox/examples/hello_signaling.rs @@ -0,0 +1,39 @@ +//! Runs a signaling server with server/client topology as a headless bevy +//! application. + +use bevy::{app::ScheduleRunnerPlugin, log::LogPlugin, prelude::*, utils::Duration}; +use bevy_matchbox::{matchbox_signaling::SignalingServer, prelude::*}; +use std::net::{Ipv4Addr, SocketAddrV4}; + +fn main() { + App::new() + .add_plugins(( + MinimalPlugins.set(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f32( + 1. / 120., // be nice to the CPU + ))), + LogPlugin::default(), + )) + .add_systems(Startup, (start_signaling_server).chain()) + .run(); +} + +fn start_signaling_server(mut commands: Commands) { + info!("Starting signaling server"); + let addr = SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 3536); + let signaling_server = MatchboxServer::from( + SignalingServer::client_server_builder(addr) + .on_connection_request(|connection| { + info!("Connecting: {connection:?}"); + Ok(true) // Allow all connections + }) + .on_id_assignment(|(socket, id)| info!("{socket} received {id}")) + .on_host_connected(|id| info!("Host joined: {id}")) + .on_host_disconnected(|id| info!("Host left: {id}")) + .on_client_connected(|id| info!("Client joined: {id}")) + .on_client_disconnected(|id| info!("Client left: {id}")) + .cors() + .trace() + .build(), + ); + commands.insert_resource(signaling_server); +}