use log::{info, trace}; use std::net::{SocketAddr, UdpSocket, IpAddr, Ipv4Addr}; use std::time::{Duration, Instant, SystemTime}; use store::EndGameReason; use renet::{ transport::{ NetcodeServerTransport, ServerAuthentication, ServerConfig, NETCODE_USER_DATA_BYTES, }, ConnectionConfig, DefaultChannel, RenetClient, RenetServer, ServerEvent, }; // Only clients that can provide the same PROTOCOL_ID that the server is using will be able to connect. // This can be used to make sure players use the most recent version of the client for instance. pub const PROTOCOL_ID: u64 = 2878; fn main() { env_logger::init(); let mut server = RenetServer::new(ConnectionConfig::default()); // Setup transport layer const SERVER_ADDR: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 5000); let socket: UdpSocket = UdpSocket::bind(SERVER_ADDR).unwrap(); let server_config = ServerConfig { max_clients: 2, protocol_id: PROTOCOL_ID, public_addr: SERVER_ADDR, authentication: ServerAuthentication::Unsecure, }; let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); let mut transport = NetcodeServerTransport::new(current_time, server_config, socket).unwrap(); trace!("❂ TricTrac server listening on {}", SERVER_ADDR); let mut last_updated = Instant::now(); loop { // Update server time let now = Instant::now(); let delta_time = now - last_updated; server.update(delta_time); transport.update(delta_time, &mut server).unwrap(); last_updated = now; // Receive connection events from clients while let Some(event) = server.get_event() { match event { ServerEvent::ClientConnected { client_id } => { let user_data = transport.user_data(client_id).unwrap(); info!("🎉 Client {} connected.", client_id); // Tell the recently joined player about the other player for (player_id, player) in game_state.players.iter() { let event = store::GameEvent::PlayerJoined { player_id: *player_id, name: player.name.clone(), }; server.send_message(client_id, 0, bincode::serialize(&event).unwrap()); } // Add the new player to the game let event = store::GameEvent::PlayerJoined { player_id: client_id, name: name_from_user_data(&user_data), }; game_state.consume(&event); // Tell all players that a new player has joined server.broadcast_message(0, bincode::serialize(&event).unwrap()); info!("Client {} connected.", id); // In TicTacTussle the game can begin once two players has joined if game_state.players.len() == 2 { let event = store::GameEvent::BeginGame { goes_first: client_id }; game_state.consume(&event); server.broadcast_message(0, bincode::serialize(&event).unwrap()); trace!("The game gas begun"); } } ServerEvent::ClientDisconnected { client_id, reason } => { // First consume a disconnect event let event = store::GameEvent::PlayerDisconnected { player_id: client_id }; game_state.consume(&event); server.broadcast_message(0, bincode::serialize(&event).unwrap()); info!("Client {} disconnected", client_id); // Then end the game, since tic tac toe can't go on with a single player let event = store::GameEvent::EndGame { reason: EndGameReason::PlayerLeft { player_id: client_id }, }; game_state.consume(&event); server.broadcast_message(0, bincode::serialize(&event).unwrap()); // NOTE: Since we don't authenticate users we can't do any reconnection attempts. // We simply have no way to know if the next user is the same as the one that disconnected. } } } // Receive GameEvents from clients. Broadcast valid events. for client_id in server.clients_id().into_iter() { while let Some(message) = server.receive_message(client_id, 0) { if let Ok(event) = bincode::deserialize::(&message) { if game_state.validate(&event) { game_state.consume(&event); trace!("Player {} sent:\n\t{:#?}", client_id, event); server.broadcast_message(0, bincode::serialize(&event).unwrap()); // Determine if a player has won the game if let Some(winner) = game_state.determine_winner() { let event = store::GameEvent::EndGame { reason: store::EndGameReason::PlayerWon { winner }, }; server.broadcast_message(0, bincode::serialize(&event).unwrap()); } } else { warn!("Player {} sent invalid event:\n\t{:#?}", client_id, event); } } } } server.send_packets().unwrap(); thread::sleep(Duration::from_millis(50));} }