292 lines
8.4 KiB
Rust
292 lines
8.4 KiB
Rust
use std::io::Cursor;
|
|
|
|
use godot::{
|
|
classes::{
|
|
Button, Camera3D, FileAccess, FileDialog, Label, LineEdit, OptionButton, Panel, SpinBox,
|
|
file_access::ModeFlags,
|
|
},
|
|
prelude::*,
|
|
register::property::SimpleVar,
|
|
};
|
|
|
|
use crate::{
|
|
game_manager::GameManager,
|
|
game_settings::{GameSettingsManager, RecentServer},
|
|
net::network_manager::NetworkManager,
|
|
popup_queue::{Popup, PopupQueue},
|
|
replay::{Replay, StandaloneReplayManager},
|
|
ui::credits::CreditsMenu,
|
|
};
|
|
|
|
#[derive(Debug, Clone, GodotConvert, Default, Export)]
|
|
#[godot(via = u8)]
|
|
pub enum Menu {
|
|
#[default]
|
|
MainMenu,
|
|
HostMenu,
|
|
JoinMenu,
|
|
}
|
|
|
|
impl SimpleVar for Menu {}
|
|
|
|
#[derive(GodotClass)]
|
|
#[class(base=Node3D, init, tool)]
|
|
pub struct MainMenu {
|
|
#[export]
|
|
camera: Option<Gd<Camera3D>>,
|
|
|
|
#[export]
|
|
main_position: Option<Gd<Node3D>>,
|
|
#[export]
|
|
host_position: Option<Gd<Node3D>>,
|
|
|
|
#[export]
|
|
main_panel: Option<Gd<Panel>>,
|
|
#[export]
|
|
host_panel: Option<Gd<Panel>>,
|
|
#[export]
|
|
join_panel: Option<Gd<Panel>>,
|
|
|
|
#[export]
|
|
host_port: Option<Gd<SpinBox>>,
|
|
#[export]
|
|
join_addr: Option<Gd<LineEdit>>,
|
|
#[export]
|
|
recent_servers_button: Option<Gd<OptionButton>>,
|
|
|
|
#[export]
|
|
popup_panel: Option<Gd<Panel>>,
|
|
#[export]
|
|
popup_title: Option<Gd<Label>>,
|
|
#[export]
|
|
popup_text: Option<Gd<Label>>,
|
|
#[export]
|
|
popup_button: Option<Gd<Button>>,
|
|
|
|
#[export]
|
|
current_menu: Menu,
|
|
#[export]
|
|
credits: Option<Gd<PackedScene>>,
|
|
|
|
#[export]
|
|
open_replay_dialog: Option<Gd<FileDialog>>,
|
|
|
|
prev_panel: Option<Gd<Panel>>,
|
|
|
|
recent_servers: Vec<RecentServer>,
|
|
|
|
base: Base<Node3D>,
|
|
}
|
|
|
|
#[godot_api]
|
|
impl INode3D for MainMenu {
|
|
fn ready(&mut self) {
|
|
if let Some(mut recent_servers_button) = self.recent_servers_button.clone() {
|
|
self.recent_servers = GameSettingsManager::singleton()
|
|
.bind()
|
|
.settings
|
|
.recent_servers
|
|
.clone();
|
|
for server in &self.recent_servers {
|
|
recent_servers_button.add_item(&server.addr.to_string());
|
|
}
|
|
recent_servers_button.select(-1);
|
|
|
|
recent_servers_button
|
|
.signals()
|
|
.item_selected()
|
|
.connect_other(self, |s, idx| s.on_recent_server_selected(idx));
|
|
}
|
|
if let Some(dialog) = &self.open_replay_dialog {
|
|
dialog
|
|
.signals()
|
|
.file_selected()
|
|
.connect_other(self, Self::on_open_replay);
|
|
}
|
|
self.hide_popup();
|
|
}
|
|
|
|
fn process(&mut self, _delta: f64) {
|
|
if let Some(camera) = &mut self.camera {
|
|
let target = match self.current_menu {
|
|
Menu::MainMenu => {
|
|
if let Some(pos) = &self.main_position {
|
|
Some((
|
|
pos.get_global_position(),
|
|
pos.get_global_rotation(),
|
|
self.main_panel.clone(),
|
|
))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
Menu::HostMenu => {
|
|
if let Some(pos) = &self.host_position {
|
|
Some((
|
|
pos.get_global_position(),
|
|
pos.get_global_rotation(),
|
|
self.host_panel.clone(),
|
|
))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
Menu::JoinMenu => {
|
|
if let Some(pos) = &self.host_position {
|
|
Some((
|
|
pos.get_global_position(),
|
|
pos.get_global_rotation(),
|
|
self.join_panel.clone(),
|
|
))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
};
|
|
|
|
if let Some((target_pos, target_rot, target_panel)) = target {
|
|
let prev_pos = camera.get_global_position();
|
|
let prev_rot = camera.get_global_rotation();
|
|
let new_pos = prev_pos.lerp(target_pos, 0.2);
|
|
let new_rot = prev_rot.lerp(target_rot, 0.2);
|
|
camera.set_global_position(new_pos);
|
|
camera.set_global_rotation(new_rot);
|
|
|
|
if let Some(mut panel) = target_panel {
|
|
if let Some(prev_panel) = &mut self.prev_panel {
|
|
if prev_panel.instance_id() != panel.instance_id() {
|
|
prev_panel.set_visible(false);
|
|
}
|
|
}
|
|
self.prev_panel = Some(panel.clone());
|
|
panel.set_visible(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
if let Some(popup_panel) = self.popup_panel.clone()
|
|
&& let Some(button) = self.popup_button.clone()
|
|
{
|
|
if !popup_panel.is_visible() || !button.is_visible() {
|
|
if let Some(popup) = PopupQueue::singleton().bind_mut().poll() {
|
|
self.show_popup(&popup.title, &popup.message, popup.ok);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[godot_api]
|
|
impl MainMenu {
|
|
#[func]
|
|
pub fn open_replay_dialog(&mut self) {
|
|
if let Some(dialog) = &mut self.open_replay_dialog {
|
|
dialog.popup_file_dialog();
|
|
}
|
|
}
|
|
|
|
pub fn on_open_replay(&mut self, path: GString) {
|
|
self.run_deferred(move |_| {
|
|
StandaloneReplayManager::singleton()
|
|
.bind_mut()
|
|
.open_replay(&path);
|
|
});
|
|
}
|
|
|
|
#[func]
|
|
pub fn host_game(&mut self) {
|
|
if let Some(host_port) = &self.host_port {
|
|
NetworkManager::singleton()
|
|
.bind_mut()
|
|
.host(host_port.get_value() as u16);
|
|
}
|
|
}
|
|
|
|
#[func]
|
|
pub fn join_game(&mut self) {
|
|
if let Some(addr) = self.join_addr.clone() {
|
|
self.show_popup("Joining", "joining game", false);
|
|
PopupQueue::singleton().bind_mut().queue(Popup {
|
|
title: "Joining".to_owned(),
|
|
message: "joining game".to_owned(),
|
|
ok: false,
|
|
});
|
|
match addr.get_text().to_string().parse() {
|
|
Ok(addr) => {
|
|
NetworkManager::singleton().bind_mut().join(addr);
|
|
}
|
|
Err(err) => {
|
|
PopupQueue::singleton().bind_mut().queue(Popup {
|
|
title: "Error".to_owned(),
|
|
message: format!("Error joining: {}", err),
|
|
ok: true,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[func]
|
|
pub fn go_to_main_menu(&mut self) {
|
|
self.current_menu = Menu::MainMenu;
|
|
}
|
|
|
|
#[func]
|
|
pub fn go_to_host_game(&mut self) {
|
|
self.current_menu = Menu::HostMenu;
|
|
}
|
|
|
|
#[func]
|
|
pub fn go_to_join_game(&mut self) {
|
|
self.current_menu = Menu::JoinMenu;
|
|
}
|
|
|
|
#[func]
|
|
pub fn quit_game(&mut self) {
|
|
self.base().get_tree().quit();
|
|
}
|
|
|
|
#[func]
|
|
pub fn open_credits(&mut self) {
|
|
if let Some(credits) = self.credits.clone() {
|
|
let credits = credits.instantiate_as::<CreditsMenu>();
|
|
self.base_mut().add_child(&credits);
|
|
}
|
|
}
|
|
|
|
pub fn show_popup(&mut self, title: &str, text: &str, ok: bool) {
|
|
if let Some(panel) = &mut self.popup_panel {
|
|
panel.set_visible(true);
|
|
if let Some(title_label) = &mut self.popup_title {
|
|
title_label.set_text(title);
|
|
}
|
|
if let Some(text_label) = &mut self.popup_text {
|
|
text_label.set_text(text);
|
|
}
|
|
if let Some(button) = &mut self.popup_button {
|
|
button.set_visible(ok);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[func]
|
|
pub fn hide_popup(&mut self) {
|
|
if let Some(panel) = &mut self.popup_panel {
|
|
panel.set_visible(false);
|
|
}
|
|
}
|
|
|
|
pub fn on_recent_server_selected(&mut self, idx: i64) {
|
|
if idx >= 0 {
|
|
if let Some(server) = self.recent_servers.get(idx as usize)
|
|
&& let Some(addr) = &mut self.join_addr
|
|
{
|
|
addr.set_text(&server.addr.to_string());
|
|
}
|
|
if let Some(button) = &mut self.recent_servers_button {
|
|
button.select(-1);
|
|
}
|
|
}
|
|
}
|
|
}
|