station/crates/game_server/src/network.rs

69 lines
2.2 KiB
Rust

//! 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<RepliconChannels>, port: Res<ServerPort>) {
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<dyn std::error::Error>> {
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))
}