quakeball-rust/rust/src/ui/lobby.rs
2026-07-22 04:06:56 +03:00

295 lines
10 KiB
Rust

use godot::{
classes::{
Button, CheckBox, Control, GridContainer, IPanel, Label, OptionButton, Panel, TextEdit,
VBoxContainer,
},
prelude::*,
};
use crate::{
game_manager::{Game, GameManager, GameOption, GameOptionValue, GameOptions},
net::network_manager::{NetworkManager, Package, PeerKind},
ui::player_listing::PlayerListing,
};
#[derive(GodotClass)]
#[class(base=Panel, init)]
pub struct LobbyPanel {
#[export]
players_list: Option<Gd<VBoxContainer>>,
#[export]
name_field: Option<Gd<TextEdit>>,
#[export]
player_listing_prefab: Option<Gd<PackedScene>>,
#[export]
ready_button: Option<Gd<Button>>,
#[export]
map_selection: Option<Gd<OptionButton>>,
#[export]
options_panel: Option<Gd<Panel>>,
#[export]
options_grid: Option<Gd<GridContainer>>,
is_ready: bool,
base: Base<Panel>,
}
#[godot_api]
impl IPanel for LobbyPanel {
fn ready(&mut self) {
GameManager::singleton()
.signals()
.on_new_player()
.connect_other(self, |s, _| s.update_players(true));
GameManager::singleton()
.signals()
.on_player_disconnected()
.connect_other(self, |s, _| s.update_players(true));
GameManager::singleton()
.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
.signals()
.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() {
game.signals().options_changed().connect_other(self, |s| {
s.run_deferred(|s| {
if let Some(game) = Game::singleton() {
s.on_game_opts_update(
&game.bind().opts,
NetworkManager::singleton().bind().is_host(),
);
}
});
});
if let Some(map_selection) = &mut self.map_selection {
for map in game.bind().maps.iter_shared() {
map_selection.add_item(&map.bind().name);
}
map_selection.select(0);
}
let is_host = if let Some(peer) = &NetworkManager::singleton().bind().peer {
peer.is_host()
} else {
false
};
self.on_game_opts_update(&game.bind().opts, is_host);
}
self.update_map_selection(0);
if let Some(name_field) = &self.name_field {
name_field
.signals()
.text_changed()
.connect_other(self, |s| {
if let Some(name_field) = &s.name_field {
if let Some(game) = &mut Game::singleton() {
let player_id = game.bind().self_id;
if let Some(player_id) = player_id {
game.bind_mut().update_player_nick(
player_id,
name_field.get_text().to_string(),
);
}
}
NetworkManager::singleton()
.bind_mut()
.update_nick(name_field.get_text().to_string());
}
});
}
self.update_players(true);
if let Some(peer) = &NetworkManager::singleton().bind().peer
&& peer.is_host()
{
if let Some(button) = &mut self.ready_button {
button.set_text("Start Game");
button.set_disabled(true);
}
}
self.update_ready_button();
let mut nodes = Vec::new();
if let Some(game) = Game::singleton() {
for (option, value) in &game.bind().opts.values {
let mut label = Label::new_alloc();
label.set_text(&format!("{}:", option.to_string()));
nodes.push(label.upcast());
let value_node = match value {
GameOptionValue::Boolean(value) => {
let mut checkbox = CheckBox::new_alloc();
checkbox.set_pressed(*value);
checkbox.set_disabled(!NetworkManager::singleton().bind().is_host());
let checkbox_clone = checkbox.clone();
let option = option.clone();
checkbox.signals().pressed().connect_other(self, move |s| {
s.option_changed(
option,
GameOptionValue::Boolean(checkbox_clone.is_pressed()),
);
});
checkbox.upcast::<Control>()
}
};
nodes.push(value_node);
}
}
if let Some(grid) = &mut self.options_grid {
for node in nodes {
grid.add_child(&node);
}
}
}
}
#[godot_api]
impl LobbyPanel {
#[func]
fn open_options(&mut self) {
if let Some(panel) = &mut self.options_panel {
panel.set_visible(true);
}
}
#[func]
fn close_options(&mut self) {
if let Some(panel) = &mut self.options_panel {
panel.set_visible(false);
}
}
fn option_changed(&mut self, key: GameOption, value: GameOptionValue) {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().change_option(key, value);
}
}
fn on_game_opts_update(&mut self, opts: &GameOptions, is_host: bool) {
if let Some(selection) = &mut self.map_selection {
selection.set_disabled(!is_host && !opts.is_true(GameOption::AllowAnyMap));
}
}
fn update_ready_button(&mut self) {
if let Some(game) = Game::singleton()
&& let Some(peer) = &NetworkManager::singleton().bind().peer
{
if let PeerKind::Server(_, _) = peer
&& let Some(button) = &mut self.ready_button
{
let all_ready = game.bind().players.iter().all(|p| p.ready);
button.set_disabled(!all_ready);
}
}
}
pub fn update_players(&mut self, replace: bool) {
self.update_ready_button();
if let Some(list) = &mut self.players_list {
if replace {
for child in list.get_children().iter_shared() {
list.remove_child(&child);
}
if let Some(game) = &Game::singleton() {
if let Some(prefab) = &self.player_listing_prefab {
for player in &game.bind().players {
if let Some(node) = prefab.instantiate() {
let mut listing = node.cast::<PlayerListing>();
listing.bind_mut().player_id = Some(player.id());
listing.bind_mut().update_teams(game.bind().get_teams());
listing.bind_mut().update();
list.add_child(&listing);
}
}
}
}
} else {
for child in list.get_children().iter_shared() {
let mut listing = child.cast::<PlayerListing>();
if let Some(game) = Game::singleton() {
listing.bind_mut().update_teams(game.bind().get_teams());
}
listing.bind_mut().update();
}
}
}
}
pub fn on_ready(&mut self) {
let is_host = if let Some(peer) = &NetworkManager::singleton().bind().peer {
peer.is_host()
} else {
false
};
if !is_host {
self.is_ready = !self.is_ready;
if let Some(button) = &mut self.ready_button {
if self.is_ready {
button.set_text("Ready");
} else {
button.set_text("Not Ready");
}
}
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
if let PeerKind::Client(peer, socket_addr) = peer {
peer.send_reliable(&socket_addr, Package::SetReady(0, self.is_ready));
}
}
} else {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().start_game();
}
}
}
pub fn update_map_selection(&mut self, idx: u8) {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
match peer {
PeerKind::Client(peer, addr) => {
if let Some(map_selection) = &mut self.map_selection {
map_selection.select(idx as i32);
self.run_deferred(|s| s.update_players(false));
peer.send_reliable(addr, Package::SelectMap(idx));
}
}
PeerKind::Server(peer, _) => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().change_map_selection(idx, false);
}
self.run_deferred(|s| s.update_players(false));
peer.broadcast_reliable(Package::SelectMap(idx));
}
}
}
}
}