use std::net::SocketAddr; use bevy::prelude::*; use clap::Parser; use steamworks::SteamId; pub fn plugin(app: &mut App) { let config = NetworkingConfig::parse(); let config: NetConfig = config.into(); info!("net config: {:?}", config); app.insert_resource(config); } #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct NetworkingConfig { /// Steam id of the host to connect to #[arg(long)] pub steam_host_id: Option, /// Act as steam host #[arg(long)] pub steam_host: bool, /// Act as host using netcode, so we have to define our port #[arg(long)] pub netcode_host: Option>, /// Host address we connect to as a client #[arg(long)] pub netcode_client: Option>, } #[derive(Resource, Debug)] pub enum NetConfig { Singleplayer, SteamHost, NetcodeHost { port: u16 }, SteamClient(SteamId), NetcodeClient(SocketAddr), } impl NetConfig { pub fn is_client(&self) -> bool { matches!( self, NetConfig::SteamClient(_) | NetConfig::NetcodeClient(_) ) } pub fn is_host(&self) -> bool { matches!(self, NetConfig::SteamHost | NetConfig::NetcodeHost { .. }) } pub fn is_singleplayer(&self) -> bool { !self.is_client() && !self.is_host() } } impl From for NetConfig { fn from(config: NetworkingConfig) -> Self { match ( config.steam_host, config.steam_host_id, config.netcode_host, config.netcode_client, ) { (false, None, None, None) => Self::Singleplayer, (true, None, None, None) => Self::SteamHost, (false, Some(id), None, None) => Self::SteamClient(parse_steam_id(id)), (false, None, Some(port), None) => Self::NetcodeHost { port: port.unwrap_or(31111), }, (false, None, None, Some(addr)) => Self::NetcodeClient(parse_addr(addr)), _ => panic!("Invalid configuration"), } } } fn parse_addr(addr: Option) -> SocketAddr { addr.map(|addr| addr.parse().ok()) .flatten() .unwrap_or_else(|| "127.0.0.1:31111".parse().unwrap()) } fn parse_steam_id(id: String) -> SteamId { let id: u64 = id.parse().unwrap(); SteamId::from_raw(id) }