use std::{ sync::Arc, }; use futures::StreamExt; use tokio::sync::Mutex; use opengl_rust::{ network_protocol::*, quinn_common::make_server_endpoint, }; struct ConnectedPlayer { connection: quinn::Connection, cmd: NetworkCommand, position: (f32, f32), } #[tokio::main] async fn main () -> anyhow::Result <()> { let server_addr = "127.0.0.1:5000".parse().unwrap(); let (mut incoming, server_cert) = make_server_endpoint (server_addr)?; tokio::fs::write ("quic_server.crt", &server_cert).await?; let connected_players = Arc::new (Mutex::new (vec! [])); { let connected_players = Arc::clone (&connected_players); tokio::spawn (async move { let mut player_seq = 0; while let Some (incoming_conn) = incoming.next ().await { let new_conn = incoming_conn.await?; println! ( "[server] connection accepted: addr={}", new_conn.connection.remote_address () ); let quinn::NewConnection { connection, mut datagrams, .. } = new_conn; { let mut guard = connected_players.lock ().await; guard.push (ConnectedPlayer { connection, cmd: NetworkCommand::default (), position: (32.0, 32.0), }); } // Read player commands { let player_seq = player_seq; let connected_players = Arc::clone (&connected_players); tokio::spawn (async move { while let Some (Ok (datagram)) = datagrams.next ().await { let cmd: NetworkCommand = rmp_serde::from_slice (&datagram)?; let mut guard = connected_players.lock ().await; guard [player_seq].cmd = cmd; } Ok::<_, anyhow::Error> (()) }); } player_seq += 1; } Ok::<_, anyhow::Error> (()) }); } let mut time_step = opengl_rust::timestep::TimeStep::new (120, 1000); let mut state = NetworkedState { positions: vec! [ (32.0, 32.0), ], }; let mut i = 0_u64; loop { let frames_to_do = time_step.step (); let state; { let mut guard = connected_players.lock ().await; for _ in 0..frames_to_do { let speed = 0.25; for player in &mut guard [..] { let cmd = &player.cmd; let mut pos = &mut player.position; if cmd.left { pos.0 -= speed; } if cmd.right { pos.0 += speed; } if cmd.up { pos.1 += speed; } if cmd.down { pos.1 -= speed; } } } state = NetworkedState { positions: guard.iter () .map (|player| player.position) .collect (), }; let bytes = bytes::Bytes::from (rmp_serde::to_vec (&state)?); for player in &guard [..] { player.connection.send_datagram (bytes.clone ())?; } i += 1; } tokio::time::sleep (std::time::Duration::from_millis(16)).await; } Ok(()) }