diff --git a/godot/maps/default_map.tres b/godot/maps/default_map.tres new file mode 100644 index 0000000..129624d --- /dev/null +++ b/godot/maps/default_map.tres @@ -0,0 +1,7 @@ +[gd_resource type="Map" format=3 uid="uid://b4rw48yjf7q3q"] + +[ext_resource type="PackedScene" uid="uid://lahirbqfppvw" path="res://scenes/main.tscn" id="1_k5804"] + +[resource] +name = "Default Map" +scene = ExtResource("1_k5804") diff --git a/godot/maps/default_map_2.tres b/godot/maps/default_map_2.tres new file mode 100644 index 0000000..79c11a4 --- /dev/null +++ b/godot/maps/default_map_2.tres @@ -0,0 +1,7 @@ +[gd_resource type="Map" format=3 uid="uid://crti664evgfmj"] + +[ext_resource type="PackedScene" uid="uid://lahirbqfppvw" path="res://scenes/main.tscn" id="1_gr7ev"] + +[resource] +name = "Default Map 2" +scene = ExtResource("1_gr7ev") diff --git a/godot/scenes/game_manager.tscn b/godot/scenes/game_manager.tscn index 82652f0..c906cae 100644 --- a/godot/scenes/game_manager.tscn +++ b/godot/scenes/game_manager.tscn @@ -1,3 +1,7 @@ [gd_scene format=3 uid="uid://bii6018k3ip3t"] +[ext_resource type="Map" uid="uid://b4rw48yjf7q3q" path="res://maps/default_map.tres" id="1_glms7"] +[ext_resource type="Map" uid="uid://crti664evgfmj" path="res://maps/default_map_2.tres" id="2_udu3i"] + [node name="game_manager" type="GameManager" unique_id=1442044769] +maps = Array[Map]([ExtResource("1_glms7"), ExtResource("2_udu3i")]) diff --git a/godot/scenes/lobby.tscn b/godot/scenes/lobby.tscn index 62e5e34..8071481 100644 --- a/godot/scenes/lobby.tscn +++ b/godot/scenes/lobby.tscn @@ -5,11 +5,12 @@ [sub_resource type="LabelSettings" id="LabelSettings_1cgct"] font_size = 32 -[node name="lobby" type="LobbyPanel" unique_id=915192272 node_paths=PackedStringArray("players_list", "name_field", "ready_button")] +[node name="lobby" type="LobbyPanel" unique_id=915192272 node_paths=PackedStringArray("players_list", "name_field", "ready_button", "map_selection")] players_list = NodePath("v_box_container/players_list") name_field = NodePath("v_box_container/h_box_container/text_edit") player_listing_prefab = ExtResource("1_o1atq") ready_button = NodePath("ready_button") +map_selection = NodePath("v_box_container2/option_button") anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 @@ -73,3 +74,13 @@ offset_top = 504.0 offset_right = 278.0 offset_bottom = 555.0 text = "Not Ready" + +[node name="v_box_container2" type="VBoxContainer" parent="." unique_id=653902328] +layout_mode = 0 +offset_left = 716.0 +offset_top = 146.0 +offset_right = 824.0 +offset_bottom = 204.0 + +[node name="option_button" type="OptionButton" parent="v_box_container2" unique_id=426342653] +layout_mode = 2 diff --git a/rust/src/game_manager.rs b/rust/src/game_manager.rs index aebba08..5df00fb 100644 --- a/rust/src/game_manager.rs +++ b/rust/src/game_manager.rs @@ -3,6 +3,8 @@ use std::net::SocketAddr; use godot::{prelude::*, tools::get_autoload_by_name}; use serde::{Deserialize, Serialize}; +use crate::map_resource::Map; + pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal"; #[derive(GodotClass)] @@ -10,6 +12,9 @@ pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal"; pub struct GameManager { pub game: Option>, base: Base, + + #[export] + pub maps: Array>, } #[godot_api] @@ -20,6 +25,8 @@ impl GameManager { 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) @@ -31,6 +38,7 @@ impl GameManager { } 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 { @@ -43,6 +51,9 @@ impl GameManager { 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)); } }); @@ -55,10 +66,15 @@ impl GameManager { #[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, base: Base, } @@ -71,6 +87,8 @@ impl Game { 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() @@ -78,6 +96,26 @@ impl Game { .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; + godot_print!("{:?}", self.selected_map); + if let Some(map) = &self.selected_map { + if let Some(scene) = &map.bind().scene { + self.base().get_tree().change_scene_to_packed(scene); + } + } + } + pub fn set_self(&mut self, id: u16) { self.self_id = Some(id); } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index efec1d3..908cd6f 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -3,6 +3,7 @@ use std::net::SocketAddr; use godot::prelude::*; pub mod game_manager; +pub mod map_resource; pub mod net; pub mod ui; diff --git a/rust/src/map_resource.rs b/rust/src/map_resource.rs new file mode 100644 index 0000000..46547f8 --- /dev/null +++ b/rust/src/map_resource.rs @@ -0,0 +1,27 @@ +use godot::prelude::*; + +#[derive(GodotClass)] +#[class(base=Resource, init, tool)] +pub struct Map { + #[export] + pub name: GString, + #[export] + pub scene: Option>, + + base: Base, +} + +#[godot_api] +impl IResource for Map { + fn on_notification(&mut self, what: godot::classes::notify::ObjectNotification) {} + + fn to_string(&self) -> GString { + "Hello there".to_gstring() + } + + fn setup_local_to_scene(&mut self) {} + + fn reset_state(&mut self) {} + + fn set_path_cache(&self, path: GString) {} +} diff --git a/rust/src/net/network_manager.rs b/rust/src/net/network_manager.rs index 5ab69a3..a17d77d 100644 --- a/rust/src/net/network_manager.rs +++ b/rust/src/net/network_manager.rs @@ -196,6 +196,17 @@ impl INode for NetworkManager { .update_player_ready(player_id, is_ready); } } + Package::SelectMap(map_id) => { + if let Some(game) = &mut Game::singleton() { + game.bind_mut().change_map_selection(map_id, true); + } + } + Package::GameStarted => { + if let Some(game) = &mut Game::singleton() { + godot_print!("Game started"); + game.bind_mut().start_game(); + } + } _ => {} }, } @@ -236,6 +247,11 @@ impl INode for NetworkManager { sent_player.connection_addr = SocketAddr::from(([0, 0, 0, 0], 0)); peer.broadcast_reliable(Package::NewPlayer(sent_player)); + + peer.send_reliable( + &connection.address, + Package::SelectMap(game.bind().selected_map_idx), + ); } } teanet::PeerMessage::Disconnected(connection, connection_error) => { @@ -416,6 +432,8 @@ pub enum Package { NewPlayer(Player), PlayerLeft(Player), SetReady(u16, bool), + SelectMap(u8), + GameStarted, } pub enum PeerKind { diff --git a/rust/src/ui/lobby.rs b/rust/src/ui/lobby.rs index 5dd7e02..842a5ba 100644 --- a/rust/src/ui/lobby.rs +++ b/rust/src/ui/lobby.rs @@ -1,10 +1,11 @@ use godot::{ - classes::{Button, IPanel, Label, Panel, TextEdit, VBoxContainer}, + classes::{Button, IPanel, Label, OptionButton, Panel, TextEdit, VBoxContainer}, prelude::*, }; use crate::{ game_manager::{Game, GameManager}, + map_resource::Map, net::network_manager::{NetworkManager, Package, PeerKind}, ui::player_listing::PlayerListing, }; @@ -20,6 +21,8 @@ pub struct LobbyPanel { player_listing_prefab: Option>, #[export] ready_button: Option>, + #[export] + map_selection: Option>, is_ready: bool, @@ -41,6 +44,10 @@ impl IPanel for LobbyPanel { .signals() .on_players_updated() .connect_other(self, |s| s.update_players(false)); + GameManager::singleton() + .signals() + .on_map_changed() + .connect_other(self, |s, id| s.update_map_selection(id)); if let Some(ready_button) = &self.ready_button { ready_button @@ -48,6 +55,30 @@ impl IPanel for LobbyPanel { .pressed() .connect_other(self, |s| s.on_ready()); } + if let Some(map_selection) = &self.map_selection { + map_selection + .signals() + .item_selected() + .connect_other(self, |s, id| { + s.update_map_selection(id as u8); + }); + } + + if let Some(game) = Game::singleton() { + if let Some(map_selection) = &mut self.map_selection { + for map in game.bind().maps.iter_shared() { + map_selection.add_item(&map.bind().name); + } + let is_host = if let Some(peer) = &NetworkManager::singleton().bind().peer { + peer.is_host() + } else { + false + }; + map_selection.set_disabled(!is_host); + map_selection.select(0); + } + } + self.update_map_selection(0); if let Some(name_field) = &self.name_field { name_field @@ -143,8 +174,29 @@ impl LobbyPanel { peer.send_reliable(socket_addr, Package::SetReady(0, self.is_ready)); } - PeerKind::Server(_, _) => { - godot_print!("Start game!"); + PeerKind::Server(peer, _) => { + if let Some(game) = &mut Game::singleton() { + game.bind_mut().start_game(); + } + peer.broadcast_reliable(Package::GameStarted); + } + } + } + } + + pub fn update_map_selection(&mut self, idx: u8) { + if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer { + match peer { + PeerKind::Client(..) => { + if let Some(map_selection) = &mut self.map_selection { + map_selection.select(idx as i32); + } + } + PeerKind::Server(peer, _) => { + if let Some(game) = &mut Game::singleton() { + game.bind_mut().change_map_selection(idx, false); + } + peer.broadcast_reliable(Package::SelectMap(idx)); } } } diff --git a/teanet-rust b/teanet-rust index 4d843d2..a947f3a 160000 --- a/teanet-rust +++ b/teanet-rust @@ -1 +1 @@ -Subproject commit 4d843d2ccb5566a4bc7dc4f3af2bdf181ebf0c38 +Subproject commit a947f3a8cbad03b939dedfc1486de75226d90c0a