### Start MatchboxServer in Bevy Source: https://context7.com/johanhelsing/matchbox/llms.txt Starts an embedded signaling server using Bevy's Commands extension. This example also demonstrates connecting a local socket to the newly started server. ```rust use bevy::prelude::*; use bevy_matchbox::prelude::*; use bevy_matchbox::matchbox_signaling::topologies::full_mesh::{FullMesh, FullMeshState}; use std::net::Ipv4Addr; fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, start_server) .run(); } fn start_server(mut commands: Commands) { // Option 1: Using Commands extension let builder = SignalingServerBuilder::new( (Ipv4Addr::UNSPECIFIED, 3536), FullMesh, FullMeshState::default(), ); commands.start_server(builder); // Option 2: Insert resource directly // let server: MatchboxServer = SignalingServerBuilder::new( // (Ipv4Addr::UNSPECIFIED, 3536), // FullMesh, // FullMeshState::default(), // ).into(); // commands.insert_resource(server); // Also connect a socket to the local server commands.open_socket( WebRtcSocketBuilder::new("ws://localhost:3536/lobby") .add_channel(ChannelConfig::reliable()) ); } fn stop_server(mut commands: Commands) { commands.stop_server(); } ``` -------------------------------- ### Matchbox Signaling Server Example Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_signaling/README.md A basic example of a Matchbox signaling server using Tokio. This server facilitates the WebRTC connection setup between peers. ```rust use matchbox_signaling::signaling; #[tokio::main] async fn main() { let listener = tokio::net::TcpListener::bind("127.0.0.1:3030").await.unwrap(); println!("Signaling server listening on 127.0.0.1:3030"); loop { let (socket, _) = listener.accept().await.unwrap(); tokio::spawn(signaling(socket)); } } ``` -------------------------------- ### Start MatchboxSocket in Bevy Source: https://context7.com/johanhelsing/matchbox/llms.txt Opens a WebRTC socket using Bevy's Commands extension. This example shows how to add systems for handling connections, messages, and sending messages. ```rust use bevy::prelude::*; use bevy_matchbox::prelude::*; const CHANNEL_ID: usize = 0; fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, start_socket) .add_systems(Update, (handle_connections, receive_messages, send_messages)) .run(); } fn start_socket(mut commands: Commands) { // Option 1: Using Commands extension commands.open_socket( WebRtcSocketBuilder::new("ws://localhost:3536/my_room") .add_channel(ChannelConfig::reliable()) ); // Option 2: Insert as resource directly // let socket = MatchboxSocket::new_reliable("ws://localhost:3536/my_room"); // commands.insert_resource(socket); // Option 3: Spawn as component // commands.spawn(MatchboxSocket::new_unreliable("ws://localhost:3536/room")); } fn handle_connections(mut socket: ResMut) { for (peer, state) in socket.update_peers() { match state { PeerState::Connected => info!("Peer {peer} connected"), PeerState::Disconnected => info!("Peer {peer} disconnected"), } } } fn receive_messages(mut socket: ResMut) { for (peer, message) in socket.channel_mut(CHANNEL_ID).receive() { let text = String::from_utf8_lossy(&message); info!("From {peer}: {text}"); } } fn send_messages(mut socket: ResMut) { let peers: Vec<_> = socket.connected_peers().collect(); for peer in peers { socket.channel_mut(CHANNEL_ID).send(b"Hello!".to_vec().into(), peer); } } fn close_socket(mut commands: Commands) { commands.close_socket(); } ``` -------------------------------- ### Bevy Matchbox Integration Example Source: https://github.com/johanhelsing/matchbox/blob/main/README.md This example demonstrates integrating `matchbox_socket` with the Bevy game engine. `bevy_matchbox` handles the socket's message loop automatically, simplifying setup for Bevy applications. ```rust use bevy::prelude::*; use bevy_matchbox::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(MatchboxPlugins) .add_systems(Startup, setup) .run(); } fn setup(mut commands: Commands) { // Add your game setup logic here commands.insert_resource(bevy_matchbox::MatchboxConfig { // Configure your signaling server URL and room name // Example: // signaling_server_url: "wss://match.example.com".to_string(), // room_url: "my_cool_game".to_string(), }); } ``` -------------------------------- ### Run the Signaling Server Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_server/README.md Execute this command in your terminal to start the Matchbox signaling server. Ensure you have Rust and Cargo installed. ```sh cargo run ``` -------------------------------- ### Bevy Matchbox Integration Example Source: https://github.com/johanhelsing/matchbox/blob/main/bevy_matchbox/README.md This example showcases how to integrate Matchbox with the Bevy game engine. Bevy's plugin system automatically handles the socket's message loop, simplifying setup for Bevy applications. ```rust use bevy::prelude::*; use bevy_matchbox::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(MatchboxPlugin) .add_systems(Startup, setup) .run(); } fn setup(mut commands: Commands) { // Create a new socket let (socket, _message_loop) = MatchboxSocket::<()>::new("ws://127.0.0.1:3030/").await; // Insert the socket into Bevy's ECS commands.insert_resource(socket); } ``` -------------------------------- ### Install WASM Target and Server Runner Source: https://github.com/johanhelsing/matchbox/blob/main/examples/simple/README.md Install the necessary WASM target and a lightweight web server for serving WASM applications. These are prerequisites for running the demo on WASM. ```sh rustup target install wasm32-unknown-unknown ``` ```sh cargo install wasm-server-runner ``` -------------------------------- ### Setup GGRS Session with Matchbox Socket Source: https://context7.com/johanhelsing/matchbox/llms.txt Configure and start a GGRS P2P session using Matchbox Socket. Ensure to use an unreliable channel for GGRS as it handles its own reliability. ```rust use bevy::prelude::*; use bevy_ggrs::prelude::*; use bevy_matchbox::prelude::*; use matchbox_socket::PeerId; // Define your GGRS config struct MyGameConfig; impl ggrs::Config for MyGameConfig { type Input = u8; type State = u8; type Address = PeerId; } fn setup_ggrs_session( mut commands: Commands, mut socket: ResMut, args: Res, ) { // Wait for all players to connect socket.update_peers(); let connected = socket.connected_peers().count(); if connected + 1 < args.num_players { return; // Still waiting for players } // Get player list (sorted for consistency across peers) let players = socket.players(); // Returns Vec> // Build GGRS session let mut session_builder = SessionBuilder::::new() .with_num_players(args.num_players) .with_max_prediction_window(12) .with_input_delay(2); for (i, player) in players.into_iter().enumerate() { session_builder = session_builder.add_player(player, i).unwrap(); } // Take the unreliable channel for GGRS (IMPORTANT: use unreliable!) let channel = socket.take_channel(0).unwrap(); // Start P2P session let session = session_builder.start_p2p_session(channel).unwrap(); commands.insert_resource(Session::P2P(session)); } fn start_socket(mut commands: Commands, args: Res) { let room_url = format!("ws://localhost:3536/game?next={}", args.num_players); // GGRS works best with unreliable channels commands.insert_resource(MatchboxSocket::new_unreliable(room_url)); } ``` -------------------------------- ### Bevy Matchbox Integration Example Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_socket/README.md Example demonstrating how `bevy_matchbox` automatically handles the message loop for Bevy applications. This simplifies integration with the Bevy game engine. ```rust App::new().add_plugins(bevy_matchbox::MatchboxPlugins::new(bevy_matchbox::MatchboxConfig::new( "ws://127.0.0.1:3030", "/main/{session_id}"))).run(); ``` -------------------------------- ### Complete P2P Chat Example in Rust Source: https://context7.com/johanhelsing/matchbox/llms.txt This example sets up a WebRTC socket, manages peer connections, and handles bidirectional messaging for a P2P chat. It includes platform-specific main function definitions for WASM and native targets. Ensure a signaling server is running at the specified WebSocket URL. ```rust use futures::{FutureExt, select}; use futures_timer::Delay; use matchbox_socket::{PeerState, WebRtcSocket}; use std::time::Duration; const CHANNEL_ID: usize = 0; #[cfg(target_arch = "wasm32")] fn main() { console_error_panic_hook::set_once(); console_log::init_with_level(log::Level::Debug).unwrap(); wasm_bindgen_futures::spawn_local(async_main()); } #[cfg(not(target_arch = "wasm32"))] #[tokio::main] async fn main() { tracing_subscriber::fmt::init(); async_main().await; } async fn async_main() { println!("Connecting to signaling server..."); // Create socket with reliable channel let (mut socket, loop_fut) = WebRtcSocket::new_reliable("ws://localhost:3536/chat_room"); let loop_fut = loop_fut.fuse(); futures::pin_mut!(loop_fut); let timeout = Delay::new(Duration::from_millis(100)); futures::pin_mut!(timeout); loop { // Process peer connection events for (peer, state) in socket.update_peers() { match state { PeerState::Connected => { println!("Peer joined: {peer}"); // Send greeting to new peer let greeting = format!("Hello from {:?}!", socket.id()); socket.channel_mut(CHANNEL_ID) .send(greeting.into_bytes().into_boxed_slice(), peer); } PeerState::Disconnected => { println!("Peer left: {peer}"); } } } // Process incoming messages for (peer, packet) in socket.channel_mut(CHANNEL_ID).receive() { let message = String::from_utf8_lossy(&packet); println!("[{peer}]: {message}"); } select! { // Poll every 100ms _ = (&mut timeout).fuse() => { timeout.reset(Duration::from_millis(100)); } // Exit if socket disconnects _ = &mut loop_fut => { println!("Disconnected from server"); break; } } } } ``` -------------------------------- ### Send Data Over a Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/README.md This example shows how to send data to connected peers using the `send` method on a `WebRtcSocket`. Ensure a connection is established before attempting to send data. ```rust use matchbox_socket::WebRtcSocket; use matchbox_socket::PeerId; async fn send_data(socket: &WebRtcSocket, peer_id: PeerId) { let data = vec![1, 2, 3]; socket.send(data, peer_id).await; } ``` -------------------------------- ### Install WASM Server Runner Source: https://github.com/johanhelsing/matchbox/blob/main/examples/error_handling/README.md Install wasm-server-runner, a lightweight web server for serving WebAssembly applications. This is required for the WASM demo. ```sh cargo install wasm-server-runner ``` -------------------------------- ### Install WASM Target Source: https://github.com/johanhelsing/matchbox/blob/main/examples/error_handling/README.md Install the necessary WebAssembly target for Rust compilation. This is a prerequisite for building WASM applications. ```sh rustup target install wasm32-unknown-unknown ``` -------------------------------- ### Run Second Node (Native) Source: https://github.com/johanhelsing/matchbox/blob/main/examples/custom_signaller/README.md Execute this command to start the second node, passing the Iroh ID obtained from the first node as an argument. ```sh cargo run -- "000DEADBEEF....FFF" ``` -------------------------------- ### Manage Peer Connections and Data Channels Source: https://context7.com/johanhelsing/matchbox/llms.txt The WebRtcSocket manages peer connections, providing methods to get the local peer ID, track connection states, and check channel status. Regularly call update_peers() to process connection changes and iterate over connected_peers() for active connections. ```rust use matchbox_socket::{WebRtcSocket, PeerState}; async fn handle_peers(socket: &mut WebRtcSocket) { // Get this peer's ID (assigned by signaling server) if let Some(my_id) = socket.id() { println!("My peer ID: {my_id}"); } // Process peer connection changes for (peer_id, state) in socket.update_peers() { match state { PeerState::Connected => { println!("Peer connected: {peer_id}"); } PeerState::Disconnected => { println!("Peer disconnected: {peer_id}"); } } } // Iterate over currently connected peers for peer_id in socket.connected_peers() { println!("Currently connected to: {peer_id}"); } // Check channel status if socket.any_channel_closed() { println!("At least one channel is closed"); } // Close all channels when done socket.close(); } ``` -------------------------------- ### Build and Serve WASM Demo Source: https://github.com/johanhelsing/matchbox/blob/main/examples/error_handling/README.md Compile the Matchbox demo for the WebAssembly target and serve it using wasm-server-runner. Access the demo via a web browser. ```sh cargo run --target wasm32-unknown-unknown ``` -------------------------------- ### Run Bevy + GGRS Demo on Native Source: https://github.com/johanhelsing/matchbox/blob/main/examples/bevy_ggrs/README.md Command to run the Bevy + GGRS demo on a native platform. Allows specifying the Matchbox server address, number of players, and a room name. ```sh cargo run -- [--matchbox ws://127.0.0.1:3536] [--players 2] [--room ] ``` -------------------------------- ### Create a Matchbox Socket and Connect Source: https://github.com/johanhelsing/matchbox/blob/main/bevy_matchbox/README.md This snippet demonstrates how to create a new socket instance for Matchbox, providing the signaling server URL. It then awaits the message loop future to process incoming messages. This is essential for establishing and maintaining peer-to-peer connections. ```rust let (socket, message_loop) = MatchboxSocket::::new("ws://127.0.0.1:3030/").await; // For WASM, you can use wasm_bindgen_futures to await the message loop //wasm_bindgen_futures::spawn_local(message_loop); // Or poll it manually //loop { // let _ = message_loop.poll(); // // ... other logic //} ``` -------------------------------- ### Configure WebRTC Data Channels with ChannelConfig Source: https://context7.com/johanhelsing/matchbox/llms.txt Illustrates creating different `ChannelConfig` instances for unreliable, reliable, and custom data channels. Shows how to add these configurations when building a `WebRtcSocket`. ```rust use matchbox_socket::{WebRtcSocketBuilder, ChannelConfig}; // Unreliable channel: messages may be lost or arrive out of order // Best for: real-time game state, position updates, audio/video let unreliable = ChannelConfig::unreliable(); // equivalent to: ChannelConfig { ordered: false, max_retransmits: Some(0) } // Reliable channel: messages are guaranteed to arrive in order // Best for: chat messages, game events, critical state changes let reliable = ChannelConfig::reliable(); // equivalent to: ChannelConfig { ordered: true, max_retransmits: None } // Custom channel with partial reliability let custom = ChannelConfig { ordered: true, // Maintain message order max_retransmits: Some(3), // Retry up to 3 times, then give up }; let (socket, loop_fut) = WebRtcSocketBuilder::new("wss://example.com/room") .add_channel(unreliable) // Channel 0 .add_channel(reliable) // Channel 1 .add_channel(custom) // Channel 2 .build(); ``` -------------------------------- ### Handle New Peers with Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/bevy_matchbox/README.md Demonstrates how to detect and handle new peers joining the network. The `new_peer_connected` method returns `true` if a new peer has connected since the last check. This is crucial for managing the peer list and initiating communication. ```rust if socket.new_peer_connected().await { println!("New peer connected!"); } ``` -------------------------------- ### Load and Initialize WebAssembly Application Source: https://github.com/johanhelsing/matchbox/blob/main/website/index.html JavaScript code to dynamically import a WebAssembly application, handle download progress, and initialize it. ```javascript (async () => { // let params = (new URL(document.location)).searchParams; // const app = params.get("app").replace(/[^0-9a-z_-]/g, "") const app = "bevy_ggrs"; console.log(`loading ${app}`); const appRoot = `https://johanhelsing.github.io/matchbox/${app}` const appModule = await import(`${appRoot}/app.js`) const init = appModule.default; const fetchWithProgress = async (path, progress) => { const response = await fetch(path) // May be incorrect if compressed const contentLength = response.headers.get("Content-Length") const total = parseInt(contentLength, 10) let bytesLoaded = 0 const ts = new TransformStream({ transform(chunk, ctrl) { bytesLoaded += chunk.byteLength progress(bytesLoaded / total) ctrl.enqueue(chunk) } }) return new Response(response.body.pipeThrough(ts), response) } const initWasmWithProgress = async (wasmFile, progress) => { console.log("starting download") if (typeof TransformStream === "function" && ReadableStream.prototype.pipeThrough) { let done = false const response = await fetchWithProgress(wasmFile, function () { if (done) { return } if (arguments[0] >= 1) { progress(1) done = true console.log("Fetching wasm finished") window.jgjkSplash.loadingFinished() } else { progress.apply(null, arguments) } }); await init(response) } else { // xhr fallback, this is slower and doesn't use WebAssembly.InstantiateStreaming, // but it's only happening on Firefox, and we can probably live with the game // starting slightly slower there... const xhr = new XMLHttpRequest() await new Promise(function (resolve, reject) { xhr.open("GET", wasmFile) xhr.responseType = "arraybuffer" xhr.onload = resolve xhr.onerror = reject xhr.onprogress = e => progress(e.loaded / e.total) xhr.send() }) progress(1) window.jgjkSplash.loadingFinished() await init(xhr.response) } } const wasmFile = `${appRoot}/app.wasm` // await initWasmWithProgress(wasmFile, p => console.log(`progress: ${p}`)); await initWasmWithProgress(wasmFile, jgjkSplash.loadingProgress) // init never returns on bevy apps :( // window.jgjkSplash.loadingFinished() console.log("Initialized wasm") })() ``` -------------------------------- ### Run a Full-Mesh Signaling Server Source: https://context7.com/johanhelsing/matchbox/llms.txt Sets up and runs a full-mesh `SignalingServer` with custom callbacks for connection requests, ID assignments, and peer connection/disconnection events. Enables CORS and tracing. ```rust use matchbox_signaling::SignalingServer; use std::net::Ipv4Addr; #[tokio::main] async fn main() -> Result<(), matchbox_signaling::Error> { // Full-mesh signaling server with callbacks let server = SignalingServer::full_mesh_builder((Ipv4Addr::UNSPECIFIED, 3536)) .on_connection_request(|connection| { println!("Connection request: {:?}", connection); Ok(true) // Return Ok(false) to reject }) .on_id_assignment(|(socket_addr, peer_id)| { println!("{socket_addr} assigned ID: {peer_id}"); }) .on_peer_connected(|peer_id| { println!("Peer joined: {peer_id}"); }) .on_peer_disconnected(|peer_id| { println!("Peer left: {peer_id}"); }) .cors() // Enable CORS for browser clients .trace() // Enable request tracing .build(); println!("Signaling server running on port 3536"); server.serve().await } // Client-server topology (one host, multiple clients) // let server = SignalingServer::client_server_builder((Ipv4Addr::UNSPECIFIED, 3536)) // .build(); ``` -------------------------------- ### Create and Connect a Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/README.md This snippet demonstrates how to create a new socket and connect to a signaling server. It's essential for initiating peer-to-peer communication. The message loop future must be awaited to process incoming messages. ```rust use matchbox_socket::WebRtcSocket; async fn main() { let signaling_url = "wss://match.example.com"; let (socket, _)= WebRtcSocket::new(signaling_url).await; // Process messages in a loop socket.next_message().await; } ``` -------------------------------- ### Create a Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_socket/README.md Instantiate a new socket for peer-to-peer communication, providing the signaling server URL. This is the primary step for establishing connections. ```rust let (socket, message_loop) = matchbox_socket::WebRtcSocket::new("ws://127.0.0.1:3030").await; ``` -------------------------------- ### Create Basic and Advanced WebRTC Sockets Source: https://context7.com/johanhelsing/matchbox/llms.txt Use WebRtcSocketBuilder to configure signaling server URLs, ICE servers, and data channels. Ensure at least one channel is added before building. The message loop future must be awaited for the socket to function. ```rust use matchbox_socket::{WebRtcSocketBuilder, ChannelConfig, RtcIceServerConfig}; use std::time::Duration; // Basic socket with one unreliable channel let (socket, message_loop) = WebRtcSocketBuilder::new("wss://matchbox.example.com/room_name") .add_unreliable_channel() .build(); // Advanced socket configuration with multiple channels let (socket, message_loop) = WebRtcSocketBuilder::new("wss://matchbox.example.com/my_game?next=2") .ice_server(RtcIceServerConfig { urls: vec![ "stun:stun.l.google.com:19302".to_string(), "turn:turn.example.com:3478".to_string(), ], username: Some("user".to_string()), credential: Some("password".to_string()), }) .add_channel(ChannelConfig::reliable()) // Channel 0: reliable, ordered .add_channel(ChannelConfig::unreliable()) // Channel 1: unreliable, unordered .reconnect_attempts(Some(5)) .signaling_keep_alive_interval(Some(Duration::from_secs(15))) .build(); // The message loop future must be awaited for the socket to function // On native: tokio::spawn(message_loop); // On WASM: wasm_bindgen_futures::spawn_local(message_loop); ``` -------------------------------- ### Send and Receive Messages with WebRtcChannel Source: https://context7.com/johanhelsing/matchbox/llms.txt Demonstrates sending byte slices as messages on reliable and unreliable channels, and receiving messages with sender IDs. Shows how to take ownership of a channel for async operations. ```rust use matchbox_socket::{WebRtcSocket, PeerId, Packet}; const RELIABLE_CHANNEL: usize = 0; const UNRELIABLE_CHANNEL: usize = 1; fn send_and_receive(socket: &mut WebRtcSocket, target_peer: PeerId) { // Send a message on the reliable channel let message = "Hello, peer!".as_bytes().to_vec().into_boxed_slice(); socket.channel_mut(RELIABLE_CHANNEL).send(message, target_peer); // Send binary data on the unreliable channel (good for game state) let game_state: Packet = vec![0x01, 0x02, 0x03, 0x04].into_boxed_slice(); socket.channel_mut(UNRELIABLE_CHANNEL).send(game_state, target_peer); // Receive all pending messages from a channel for (sender_id, packet) in socket.channel_mut(RELIABLE_CHANNEL).receive() { let message = String::from_utf8_lossy(&packet); println!("Message from {sender_id}: {message}"); } // Take ownership of a channel for async usage let channel = socket.take_channel(UNRELIABLE_CHANNEL).unwrap(); let (tx, rx) = channel.split(); // tx and rx can now be used in separate async tasks } ``` -------------------------------- ### Receive Data with Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/bevy_matchbox/README.md Shows how to receive data from peers. The `receive` method returns an `Option>`, which will contain the received data if available, or `None` otherwise. This is typically called within the message loop. ```rust if let Some(received) = socket.receive().await { // Process received data println!("Received: {:?}", received); } ``` -------------------------------- ### Handle Incoming Messages with Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/README.md This snippet illustrates how to receive data from peers. It uses `socket.next_message().await` to asynchronously wait for and retrieve incoming messages. The `Message` enum can be `Data` or `Control`. ```rust use matchbox_socket::WebRtcSocket; use matchbox_socket::Message; async fn receive_messages(socket: &WebRtcSocket) { while let Some(message) = socket.next_message().await { match message { Message::Data(data) => { // Process received data println!("Received data: {:?}", data); } Message::Control(control_message) => { // Handle control messages if necessary println!("Received control message: {:?}", control_message); } } } } ``` -------------------------------- ### Serve WASM Application Source: https://github.com/johanhelsing/matchbox/blob/main/examples/custom_signaller/README.md Builds and serves the WASM application with the specified RUSTFLAGS to enable the wasm_js backend for getrandom. ```sh RUSTFLAGS='--cfg getrandom_backend="wasm_js"' cargo run --target wasm32-unknown-unknown ``` -------------------------------- ### Send Data with Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/bevy_matchbox/README.md Illustrates how to send data to connected peers using the Matchbox socket. The `send` method is non-blocking and takes a slice of bytes representing the message payload. ```rust let data = vec![1, 2, 3, 4]; socket.send(data.as_slice()).await; ``` -------------------------------- ### GGRS Compatible Socket with Matchbox Source: https://github.com/johanhelsing/matchbox/blob/main/bevy_matchbox/README.md This snippet demonstrates how to create a `ggrs` compatible socket using the `ggrs` feature of `matchbox_socket`. This is useful for integrating with the `ggrs` rollback networking library for game development. ```rust use matchbox_socket::ggrs::GgrsConfig; // Create a GGRS compatible socket let (socket, message_loop) = MatchboxSocket::::new("ws://127.0.0.1:3030/").await; ``` -------------------------------- ### Matchbox Socket with GGRS Feature Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_socket/README.md Utilize the `ggrs` feature for a GGRS-compatible socket. This requires adding `ggrs` as a dependency and enabling the feature. ```rust let (socket, message_loop) = matchbox_socket::ggrs::GgrsSocket::new("ws://127.0.0.1:3030").await; ``` -------------------------------- ### Matchbox Splash Screen and Loading Bar Styles Source: https://github.com/johanhelsing/matchbox/blob/main/website/index.html CSS styles for the Matchbox splash screen, logo, and loading bar. Includes animations and transitions for visual feedback during loading. ```css html { height: 100%; width: 100%; / there is a sub-pixel width visible on the right in embeds, making it black makes it less noticeable */ background: #000; } body { background: #282828; width: 100%; height: 100%; overflow: hidden; margin: 0; display: flex; user-select: none; / Avoid scrolling and other pesky behaviors on mobile */ touch-action: none; } canvas { background: #282828; width: 100vw; height: 100%; } :root { --main-bg-color: #282828; --logo-color: #d3aa77; } .jgjk_splash_bg { color: var(--logo-color); background: var(--main-bg-color); width: 100vw; height: 100%; display: flex; align-items: center; justify-content: center; opacity: 1; z-index: 5; position: absolute; pointer-events: none; flex-direction: column; ; } .jgjk_splash_logo { width: 55%; aspect-ratio: 360 / 38; opacity: 0; pointer-events: none; margin: 1.2vmin; } .jgjk_splash_logo_visible { transition: opacity 0.4s ease-in; opacity: 1; } .jgjk_splash_logo_hidden { transition: opacity 0.6s ease-out; opacity: 0; } .jgjk_splash_hidden { opacity: 0; transition: opacity 0.4s ease-out; } .jgjk_loading_bar { display: block; width: 90vmax; max-width: 55%; visibility: visible; opacity: 1; transition: opacity 2s linear; display: flex; align-items: center; margin-bottom: 5vh; } @keyframes slide { 100% { background-position: 100% 100%; } } .jgjk_loading_fill { height: 0.5vmin; min-height: 0.4vw; border-radius: 100vw; background: #ccc; width: 1%; / transition: width 1s cubic-bezier(0.65, 0, 0.35, 1); */ / box-shadow: 0px 0px 1vmin 0px #000; */ box-shadow: 0px 0px 0.3vmin 0px #000; } .jgjk_logo_text { fill: var(--logo-color); } ``` -------------------------------- ### Handle Disconnected Peers with Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/bevy_matchbox/README.md Shows how to detect when a peer has disconnected. The `peer_disconnected` method returns `true` if a peer has disconnected. This allows for cleanup and updating the game state. ```rust if let Some(disconnected_peer_id) = socket.peer_disconnected().await { println!("Peer disconnected: {}", disconnected_peer_id); } ``` -------------------------------- ### Receive Data with Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_socket/README.md Receive incoming messages from peers. The `socket.receive()` method returns an `Option` containing the sender's peer ID and the received data. ```rust if let Some((peer_id, data)) = socket.receive().await { ``` -------------------------------- ### Send Data with Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_socket/README.md Send packets to connected peers using the socket's non-blocking send method. Ensure the peer ID is valid. ```rust socket.send(peer_id, &[1, 2, 3, 4]).await.unwrap(); ``` -------------------------------- ### Send Data via Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_signaling/README.md Send data packets to connected peers using the socket's non-blocking send method. Ensure the peer ID is valid. ```rust let peer_id = socket.control().get_peers()[0]; socket.send(peer_id, "Hello!".into()).await.unwrap(); ``` -------------------------------- ### Receive Data via Matchbox Socket Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_signaling/README.md Receive incoming messages from peers. The `socket.recv().await` future resolves when a message is available, returning the sender's peer ID and the message data. ```rust match socket.recv().await { Ok((peer_id, data)) => { // Process received data } Err(e) => { // Handle error } } ``` -------------------------------- ### Async Socket Handling with Stream and Sink Source: https://context7.com/johanhelsing/matchbox/llms.txt Implement concurrent message handling using the Stream and Sink traits provided by WebRtcSocket and WebRtcChannel. This pattern is useful for managing incoming and outgoing messages asynchronously. ```rust use matchbox_socket::{WebRtcSocket, PeerState, PeerId, Packet}; use futures::{SinkExt, StreamExt}; use tokio::sync::mpsc; async fn async_socket_handling() { let (mut socket, message_loop) = WebRtcSocket::new_reliable("ws://localhost:3536/"); // Spawn the message loop let loop_handle = tokio::spawn(message_loop); // Take and split a channel for concurrent read/write let (mut tx, mut rx) = socket.take_channel(0).unwrap().split(); // Spawn a task to handle incoming messages let receiver_task = tokio::spawn(async move { while let Some((peer_id, packet)) = rx.next().await { let message = String::from_utf8_lossy(&packet); println!("Received from {peer_id}: {message}"); } }); // Handle peer events using Stream interface let (peer_tx, mut peer_rx) = mpsc::channel::<(PeerId, Packet)>(32); let peer_task = tokio::spawn(async move { while let Some((peer_id, state)) = socket.next().await { match state { PeerState::Connected => { println!("Peer connected: {peer_id}"); // Send welcome message let _ = tx.send((peer_id, b"Welcome!".to_vec().into())).await; } PeerState::Disconnected => { println!("Peer disconnected: {peer_id}"); } } } }); // Wait for completion let _ = tokio::join!(loop_handle, receiver_task, peer_task); } ``` -------------------------------- ### Process Matchbox Messages Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_signaling/README.md Continuously await the message loop future to process incoming messages and manage connection states. For WASM, `wasm-bindgen-futures` can be used. This can also be polled manually. ```rust let (socket, message_loop) = matchbox_socket::WebRtcSocket::new("ws://127.0.0.1:3030").await; // For WASM, use wasm_bindgen_futures::spawn_local(message_loop); // Otherwise, poll the future manually or use a task executor. // For Bevy, this is handled automatically by bevy_matchbox. ``` -------------------------------- ### Process Matchbox Messages Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_socket/README.md Continuously await the message loop future to process incoming messages and manage connection states. For WASM, `wasm-bindgen-futures` can be used. This can also be polled manually. ```rust matchbox_socket::future::select(message_loop, async {}).await; ``` -------------------------------- ### Matchbox Socket Connection State Source: https://github.com/johanhelsing/matchbox/blob/main/matchbox_signaling/README.md Monitor connection state changes for the Matchbox socket. This allows reacting to events like connections being established or lost. ```rust for state in socket.states() { match state { matchbox_socket::State::Connected => { // Peer connected } matchbox_socket::State::Disconnected => { // Peer disconnected } } } ``` -------------------------------- ### Prevent Touch Scrolling and Initialize Splash Screen Source: https://github.com/johanhelsing/matchbox/blob/main/website/index.html JavaScript code to prevent default touch behaviors like scrolling and to manage the splash screen's visibility and loading progress. ```javascript window.addEventListener("touchstart", ev => ev.preventDefault()); window.addEventListener("touchend", ev => ev.preventDefault()); function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } const logo = document.getElementsByClassName("jgjk_splash_logo")[0]; const splash_bg = document.getElementsByClassName("jgjk_splash_bg")[0]; const loading_fill = document.getElementsByClassName("jgjk_loading_fill")[0]; let loadingFinished = false; let resolveLoading; window.jgjkSplash = { loadingFinished() { loadingFinished = true; resolveLoading && resolveLoading(); }, loadingProgress(progress) { loading_fill.style.width = `${progress * 100}%` } }; await sleep(300); logo.classList.add("jgjk_splash_logo_visible"); await sleep(2000); if (!loadingFinished) { // TODO: show the progress bar await new Promise(resolve => resolveLoading = resolve); } await sleep(300); // We're done :), hide the splash screen splash_bg.classList.add("jgjk_splash_hidden"); // also try to focus the iframe document.getElementsByTagName("canvas")[0].focus() ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.