use std::{collections::HashMap, net::SocketAddr}; use godot::{classes::CharacterBody3D, prelude::*, tools::get_autoload_by_name}; use serde::{Deserialize, Serialize}; use crate::{ map::Map, map_resource::MapResource, net::{ network_manager::{ NetworkManager, Package::{self, SelfSync}, PeerKind, }, util::NetVector3, }, player::{IPlayer, NetPlayerTransform}, }; pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal"; #[derive(GodotClass)] #[class(base=Node, init)] pub struct GameManager { pub game: Option>, base: Base, #[export] pub maps: Array>, } #[godot_api] impl GameManager { #[signal] pub fn on_players_updated(); #[signal] pub fn on_new_player(id: u16); #[signal] pub fn on_player_disconnected(id: u16); #[signal] pub fn on_map_changed(id: u8); pub fn singleton() -> Gd { get_autoload_by_name::(GAME_MANAGER_GLOBAL) } pub fn init_game(&mut self, is_host: bool) { if let Some(mut game) = self.game.take() { game.queue_free(); } let mut game = Game::new_alloc(); game.bind_mut().is_host = is_host; game.bind_mut().maps = self.maps.clone(); self.run_deferred(|s| { if let Some(game) = &s.game { game.signals() .on_new_player() .connect_other(s, |s, id| s.signals().on_new_player().emit(id)); game.signals() .on_player_disconnected() .connect_other(s, |s, id| s.signals().on_player_disconnected().emit(id)); game.signals() .on_players_updated() .connect_other(s, |s| s.signals().on_players_updated().emit()); game.signals() .on_map_changed() .connect_other(s, |s, id| s.signals().on_map_changed().emit(id)); } }); self.base_mut().add_child(&game); self.game = Some(game); } } #[derive(GodotClass)] #[class(base=Node, init)] pub struct Game { pub selected_map_idx: u8, pub selected_map: Option>, pub maps: Array>, is_host: bool, player_counter: u16, pub self_id: Option, pub players: Vec, game_started: bool, pub current_map: Option>, since_last_sync: f64, base: Base, } #[godot_api] impl INode for Game { fn process(&mut self, delta: f64) { self.since_last_sync += delta; if self.since_last_sync > (1. / 60.) { self.since_last_sync = 0.; if let Some(_) = self.current_map { if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer { match peer { PeerKind::Client(peer, socket_addr) => { if let Some(player) = self .players .iter() .find(|p| p.id == self.self_id.unwrap_or(0)) { if let Some((dir, rot)) = &player.get_self_sync() { peer.send_unreliable( socket_addr, SelfSync(dir.clone(), rot.clone()), ); } } } PeerKind::Server(peer, _) => { let mut sync_data = HashMap::new(); for player in &self.players { if let (Some(dir), Some(transform)) = (player.get_move_dir(), player.get_transform()) { sync_data.insert(player.id, (dir, transform)); } } peer.broadcast_unreliable(Package::Sync(sync_data)); } } } } } } } #[godot_api] impl Game { #[signal] pub fn on_players_updated(); #[signal] pub fn on_new_player(id: u16); #[signal] pub fn on_player_disconnected(id: u16); #[signal] pub fn on_map_changed(id: u8); pub fn singleton() -> Option> { GameManager::singleton() .get_child(0) .map(|g| g.cast::()) } pub fn change_map_selection(&mut self, map_idx: u8, emit: bool) { self.selected_map_idx = map_idx; if let Some(map) = self.maps.get(map_idx as usize) { self.selected_map = Some(map); if emit { self.run_deferred(move |s| s.signals().on_map_changed().emit(map_idx)); } } } pub fn start_game(&mut self) { self.game_started = true; if let Some(map) = &self.selected_map { if let Some(scene) = &map.bind().scene { self.base().get_tree().change_scene_to_packed(scene); } } self.run_deferred(|_| { if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer { if let PeerKind::Server(peer, _) = peer { peer.broadcast_reliable(Package::GameStarted); peer.set_accepting_connections(false); } } }); } pub fn set_self(&mut self, id: u16) { self.self_id = Some(id); } pub fn new_player(&mut self, addr: SocketAddr, name: String, id: Option) -> u16 { let id = if let Some(id) = id { id } else { let id = self.player_counter; self.player_counter += 1; id }; self.players.push(Player { id, connection_addr: addr, name, ping: 0, ready: false, character: None, }); self.run_deferred(move |s| s.signals().on_new_player().emit(id)); id } pub fn set_players(&mut self, players: Vec) { self.players = players; for player in self.players.clone() { self.run_deferred(move |s| s.signals().on_new_player().emit(player.id)); } } pub fn find_player_by_addr(&self, addr: &SocketAddr) -> Option<&Player> { self.players.iter().find(|p| p.connection_addr == *addr) } pub fn find_player_by_addr_mut(&mut self, addr: &SocketAddr) -> Option<&mut Player> { self.players.iter_mut().find(|p| p.connection_addr == *addr) } pub fn find_player(&self, player_id: u16) -> Option<&Player> { self.players.iter().find(|p| p.id == player_id) } pub fn find_player_mut(&mut self, player_id: u16) -> Option<&mut Player> { self.players.iter_mut().find(|p| p.id == player_id) } pub fn remove_player(&mut self, id: u16) { self.players.retain(|p| p.id != id); self.run_deferred(move |s| s.signals().on_player_disconnected().emit(id)); } pub fn update_player_nick(&mut self, player_id: u16, nick: String) { if let Some(player) = self.players.iter_mut().find(|p| p.id == player_id) { player.name = nick; } self.run_deferred(|s| s.signals().on_players_updated().emit()); } pub fn update_player_ping(&mut self, player_id: u16, ping: u128) { if let Some(player) = self.players.iter_mut().find(|p| p.id == player_id) { player.ping = ping; } self.run_deferred(|s| s.signals().on_players_updated().emit()); } pub fn update_player_ready(&mut self, player_id: u16, ready: bool) { if let Some(player) = self.players.iter_mut().find(|p| p.id == player_id) { player.ready = ready; } self.run_deferred(|s| s.signals().on_players_updated().emit()); } pub fn on_map_loaded(&mut self, map: Gd) { self.current_map = Some(map); if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer { if let PeerKind::Client(peer, to) = peer { peer.send_reliable(to, Package::MapLoaded); } else { self.run_deferred(|s| { for player in &mut s.players { if let Some(map) = &mut s.current_map { let character = map.bind_mut().spawn_player( player, player.id == s.self_id.unwrap_or(0), None, ); player.character = character; } } }); } } } pub fn spawn_player(&mut self, id: u16, transform: NetPlayerTransform) { if let Some(map) = &mut self.current_map { if let Some(player) = self.players.iter_mut().find(|p| p.id == id) { let character = map.bind_mut().spawn_player( player, player.id == self.self_id.unwrap_or(0), Some(transform), ); player.character = character; } } } pub fn handle_sync(&mut self, sync_data: HashMap) { for (player_id, (dir, transform)) in sync_data { if let Some(player) = self.players.iter_mut().find(|p| p.id == player_id) { if player.id != self.self_id.unwrap_or(0) { // Sync remote players always player.set_transform(transform); player.set_move_dir(dir); } else { // Sync local player only if it's far enough if let Some(local_net_transform) = player.get_transform() { let local_location: Vector3 = local_net_transform.location.into(); let remote_location: Vector3 = transform.location.into(); if local_location.distance_squared_to(remote_location) > 2. { player.set_transform(transform); } } } } } } pub fn handle_jump(&mut self, player_id: u16) { if player_id != self.self_id.unwrap_or(0) { if let Some(player) = self.find_player_mut(player_id) { player.apply_jump(); } } } } #[derive(Clone, Debug)] pub struct Player { pub id: u16, pub connection_addr: SocketAddr, pub name: String, pub ping: u128, pub ready: bool, pub character: Option>, } impl Player { pub fn get_transform(&self) -> Option { if let Some(character) = &self.character { Some(character.dyn_bind().get_transform()) } else { None } } pub fn set_transform(&mut self, transform: NetPlayerTransform) { if let Some(character) = &mut self.character { character.dyn_bind_mut().apply_transform(transform); } } pub fn get_move_dir(&self) -> Option { if let Some(character) = &self.character { Some(character.dyn_bind().get_movement_dir().into()) } else { None } } pub fn set_move_dir(&mut self, dir: NetVector3) { if let Some(character) = &mut self.character { character.dyn_bind_mut().set_movement_dir(dir.into()); } } pub fn get_self_sync(&self) -> Option<(NetVector3, NetVector3)> { if let Some(character) = &self.character { Some(( character.dyn_bind().get_movement_dir().into(), character.dyn_bind().get_transform().rotation, )) } else { None } } pub fn apply_self_sync(&mut self, dir: NetVector3, rot: NetVector3) { if let Some(character) = &mut self.character { character.dyn_bind_mut().set_movement_dir(dir.into()); character.dyn_bind_mut().apply_rotation(rot.into()); } } pub fn apply_jump(&mut self) { if let Some(character) = &mut self.character { character.dyn_bind_mut().jump(); } } } #[derive(Debug, Serialize, Deserialize, Clone)] pub struct NetPlayer { pub id: u16, pub name: String, pub ping: u128, } impl From for Player { fn from(value: NetPlayer) -> Self { Player { id: value.id, connection_addr: SocketAddr::from(([0, 0, 0, 0], 0)), name: value.name, ping: value.ping, ready: false, character: None, } } } impl From for NetPlayer { fn from(value: Player) -> Self { NetPlayer { id: value.id, name: value.name, ping: value.ping, } } }