use std::{ net::SocketAddr, time::{Duration, Instant}, }; use godot::{prelude::*, tools::get_autoload_by_name}; use serde::{Deserialize, Serialize}; use teanet::{Peer, PeerConfig, PeerMessage}; use crate::{ game_manager::{Game, GameManager, Player}, net::net_stats::Stats, ui::cli::{CLI_GLOBAL_NAME, CliColor, CommandLinePanel}, }; #[derive(GodotClass)] #[class(base=Node)] pub struct NetworkManager { #[export] lobby_scene: Option>, pub peer: Option, last_hello: Instant, last_netstat_update: Instant, base: Base, } pub const NETWORK_SINGLETON_NAME: &str = "NetworkManagerGlob"; #[godot_api] impl INode for NetworkManager { fn init(base: Base) -> Self { NetworkManager { lobby_scene: None, peer: None, last_hello: Instant::now(), last_netstat_update: Instant::now(), base, } } fn ready(&mut self) { let mut cli = get_autoload_by_name::(CLI_GLOBAL_NAME); cli.bind_mut() .signals() .on_host() .connect_other(self, |s, port| s.host(port)); cli.bind_mut() .signals() .on_join() .connect_other(self, |s, addr| s.join(addr.parse().unwrap())); cli.bind_mut() .signals() .on_disconnect() .connect_other(self, |s| s.disconnect()); } fn process(&mut self, _delta: f64) { if let Some(peer) = &mut self.peer { let mut cli = CommandLinePanel::singleton(); let now = Instant::now(); if now - self.last_netstat_update > Duration::from_millis(1000) { Stats::singleton().bind_mut().update_stats(match peer { PeerKind::Client(peer, _) => peer.statistics(), PeerKind::Server(peer, _) => peer.statistics(), }); self.last_netstat_update = now; } match peer { PeerKind::Client(..) => {} PeerKind::Server(peer, _) => { if now - self.last_hello > Duration::from_millis(2000) { self.last_hello = now; peer.broadcast_reliable(Package::Hello); } } } match peer { PeerKind::Client(peer, _) => match peer.poll() { Ok(message) => { if let Some(message) = message { match message { teanet::PeerMessage::NewConnection(connection) => { cli.bind_mut().publish_message( format!("Connected to: {}", connection.address), CliColor::Info, ); self.swap_to_lobby(false); } teanet::PeerMessage::Disconnected(connection, connection_error) => { cli.bind_mut().publish_message( format!("Disconnected from: {}", connection.address), CliColor::Info, ); if let Some(err) = &connection_error { cli.bind_mut().publish_message( format!("Error with connection: {}", err), CliColor::Error, ); } peer.close(); } teanet::PeerMessage::Closed => { self.peer = None; GameManager::singleton().bind_mut().game = None; } teanet::PeerMessage::Message(_, msg) => match msg { Package::Hello => { cli.bind_mut().publish_message( format!("Got \"Hello\"!"), CliColor::Info, ); } Package::Players(players, self_id) => { cli.bind_mut().publish_message( format!("Got players"), CliColor::Info, ); if let Some(game) = &mut Game::singleton() { game.bind_mut().set_players(players); game.bind_mut().set_self(self_id); } } Package::SetNick(id, nick) => { if let Some(game) = &mut Game::singleton() { if game.bind().self_id != Some(id) { game.bind_mut().update_player_nick(id, nick); } } } _ => {} }, } } } Err(err) => { cli.bind_mut() .publish_message(format!("Error: {}", err), CliColor::Info); } }, PeerKind::Server(peer, _) => match peer.poll() { Ok(message) => { if let Some(message) = message { match message { teanet::PeerMessage::NewConnection(connection) => { cli.bind_mut().publish_message( format!("Client connected from: {}", connection.address), CliColor::Info, ); if let Some(game) = &mut Game::singleton() { let self_id = game .bind_mut() .new_player(connection.address, String::new()); peer.send_reliable( &connection.address, Package::Players(game.bind().players.clone(), self_id), ); } } teanet::PeerMessage::Disconnected(connection, connection_error) => { cli.bind_mut().publish_message( format!("Client disconnected: {}", connection.address), CliColor::Info, ); if let Some(err) = &connection_error { cli.bind_mut().publish_message( format!("Error with connection: {}", err), CliColor::Error, ); } if let Some(game) = &mut Game::singleton() { let player_id = game .bind() .find_player_by_addr(&connection.address) .map(|p| p.id); if let Some(player_id) = player_id { game.bind_mut().remove_player(player_id); } } } teanet::PeerMessage::Closed => { cli.bind_mut() .publish_message(format!("Server closed"), CliColor::Info); self.peer = None; GameManager::singleton().bind_mut().game = None; } teanet::PeerMessage::Message(conn, msg) => match msg { Package::SetSelfNick(nick) => { if let Some(game) = &mut Game::singleton() { let player = game .bind() .find_player_by_addr(&conn.address) .cloned(); if let Some(player) = player { peer.broadcast_reliable(Package::SetNick( player.id, nick.clone(), )); game.bind_mut().update_player_nick(player.id, nick); } } } _ => {} }, } } } Err(err) => { cli.bind_mut() .publish_message(format!("Error: {}", err), CliColor::Info); } }, } } } } impl NetworkManager { pub fn singleton() -> Gd { get_autoload_by_name::(NETWORK_SINGLETON_NAME) } pub fn host(&mut self, port: u16) { if self.peer.is_none() { let mut cli = CommandLinePanel::singleton(); cli.bind_mut() .publish_message(format!("Hosting server at {}", port), CliColor::Info); let peer = Peer::listen(Some(port), PeerConfig::default()); match peer { Ok(peer) => { self.peer = Some(PeerKind::Server(peer, port)); cli.bind_mut() .publish_message(format!("Server hosted"), CliColor::Info); self.swap_to_lobby(true); if let Some(game) = &mut Game::singleton() { let id = game .bind_mut() .new_player(SocketAddr::from(([0, 0, 0, 0], 0)), "Host".to_owned()); game.bind_mut().set_self(id); } } Err(err) => { cli.bind_mut() .publish_message(format!("Error hosting server: {}", err), CliColor::Error); } } } } pub fn join(&mut self, addr: SocketAddr) { if self.peer.is_none() { let mut cli = CommandLinePanel::singleton(); cli.bind_mut() .publish_message(format!("Joining server at {}", addr), CliColor::Info); let peer = Peer::listen(None, PeerConfig::default()); match peer { Ok(mut peer) => { peer.connect_to(addr); self.peer = Some(PeerKind::Client(peer, addr)); } Err(err) => { cli.bind_mut() .publish_message(format!("Error joining server: {}", err), CliColor::Error); } } } } pub fn disconnect(&mut self) { if let Some(peer) = &mut self.peer { match peer { PeerKind::Client(peer, _) => peer.close(), PeerKind::Server(peer, _) => peer.close(), } } } fn swap_to_lobby(&self, is_host: bool) { if let Some(scene) = &self.lobby_scene { self.base().get_tree().change_scene_to_packed(scene); GameManager::singleton().bind_mut().init_game(is_host); } } pub fn update_nick(&mut self, nick: String) { if let Some(peer) = &mut self.peer { match peer { PeerKind::Client(peer, addr) => { peer.send_reliable(&addr, Package::SetSelfNick(nick)); } PeerKind::Server(..) => {} } } } } #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Package { Hello, Players(Vec, u16), SetNick(u16, String), SetSelfNick(String), } pub enum PeerKind { Client(Peer, SocketAddr), Server(Peer, u16), }