//! Starting the renet network server (host and dedicated modes). use std::{ net::{Ipv4Addr, SocketAddr, UdpSocket}, time::SystemTime, }; use bevy::prelude::*; use bevy_replicon::prelude::*; use bevy_replicon_renet::{ RenetChannelsExt, RenetServer, netcode::{NetcodeServerTransport, ServerAuthentication, ServerConfig}, renet::ConnectionConfig, }; pub const MAX_CLIENTS: usize = 32; /// Opens a UDP server on `port` once all replicon channels are registered. pub struct NetworkServerPlugin { pub port: u16, } #[derive(Resource)] struct ServerPort(u16); impl Plugin for NetworkServerPlugin { fn build(&self, app: &mut App) { app.insert_resource(ServerPort(self.port)) .add_systems(Startup, start_server); } } fn start_server(mut commands: Commands, channels: Res, port: Res) { match create_server(&channels, port.0) { Ok((server, transport)) => { info!("listening on UDP port {}", port.0); commands.insert_resource(server); commands.insert_resource(transport); } Err(e) => { error!("failed to start server on port {}: {e}", port.0); commands.write_message(AppExit::error()); } } } pub fn create_server( channels: &RepliconChannels, port: u16, ) -> Result<(RenetServer, NetcodeServerTransport), Box> { let server = RenetServer::new(ConnectionConfig { server_channels_config: channels.server_configs(), client_channels_config: channels.client_configs(), ..Default::default() }); let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?; let socket = UdpSocket::bind((Ipv4Addr::UNSPECIFIED, port))?; let server_config = ServerConfig { current_time, max_clients: MAX_CLIENTS, protocol_id: game_core::PROTOCOL_ID, authentication: ServerAuthentication::Unsecure, // Not used with unsecure authentication, but must be valid. public_addresses: vec![SocketAddr::from((Ipv4Addr::LOCALHOST, port))], }; let transport = NetcodeServerTransport::new(server_config, socket)?; Ok((server, transport)) }