Compare commits

..

2 Commits

Author SHA1 Message Date
0d745a7789 Respawn ball if holding player disconnects 2026-07-25 22:01:14 +03:00
bc3606a6ad Add respawn_ball command 2026-07-25 21:57:50 +03:00
4 changed files with 75 additions and 23 deletions

View File

@ -24,6 +24,7 @@ use crate::{
remote_player::RemotePlayer, weapon::WeaponType,
},
team_resource::TeamResource,
ui::cli::{Command, CommandLinePanel},
};
pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal";
@ -190,6 +191,19 @@ pub enum GameOptionValue {
Number(f64),
}
pub struct RespawnBallCommand;
impl Command for RespawnBallCommand {
fn execute(&self, _: &mut CommandLinePanel, _: &[&str]) {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().respawn_ball();
}
}
fn help(&self) -> &str {
"respawns the ball"
}
}
#[derive(GodotClass)]
#[class(base=Node, init)]
pub struct Game {
@ -210,6 +224,7 @@ pub struct Game {
pub current_map: Option<Gd<Map>>,
pub world_ball: Option<Gd<Ball>>,
pub ball_holder: Option<u16>,
pub goals: HashMap<u8, u16>,
@ -326,6 +341,28 @@ impl Game {
.map(|g| g.cast::<Game>())
}
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);
let mut cli = CommandLinePanel::singleton();
cli.bind_mut()
.register_command("respawn_ball".to_string(), Box::new(RespawnBallCommand));
}
}
});
}
pub fn reset_game(&mut self) {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer
&& let PeerKind::Server(peer, _) = peer
@ -375,6 +412,10 @@ impl Game {
}
s.signals().on_game_finished().emit()
});
let mut cli = CommandLinePanel::singleton();
cli.bind_mut()
.unregister_command("respawn_ball".to_string());
}
pub fn change_option(&mut self, opt: GameOption, value: GameOptionValue) {
@ -456,24 +497,6 @@ impl Game {
}
}
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);
}
@ -555,7 +578,10 @@ impl Game {
if let Some(player) = self.find_player_mut(id)
&& let Some(mut character) = player.character.take()
{
character.dyn_bind_mut().drop_ball(false);
self.run_deferred(move |_| {
character.queue_free();
});
}
self.players.retain(|p| p.id() != id);
self.run_deferred(move |s| s.signals().on_player_disconnected().emit(id));
@ -628,6 +654,12 @@ impl Game {
}
pub fn despawn_ball(&mut self) {
if let Some(ball_holder) = self.ball_holder.take()
&& let Some(player) = self.find_player_mut(ball_holder).cloned()
{
self.handle_swap_weapon(ball_holder, player.last_held_weapon, false, false);
}
if let Some(mut ball) = self.world_ball.take() {
ball.queue_free();
self.run_deferred(|_| {
@ -678,7 +710,10 @@ impl Game {
pub fn handle_ball_pickup(&mut self, player_id: u16) {
if NetworkManager::singleton().bind_mut().is_host() {
self.despawn_ball();
self.run_deferred(move |s| s.handle_swap_weapon(player_id, WeaponType::Ball, true));
self.run_deferred(move |s| {
s.handle_swap_weapon(player_id, WeaponType::Ball, true, false)
});
self.ball_holder = Some(player_id);
}
}
@ -688,6 +723,7 @@ impl Game {
player_id: u16,
weapon_type: WeaponType,
allow_ball: bool,
drop_ball: bool,
) {
if weapon_type == WeaponType::Ball && !allow_ball {
return;
@ -699,7 +735,7 @@ impl Game {
if weapon_type != WeaponType::Ball {
player.last_held_weapon = weapon_type;
}
character.dyn_bind_mut().swap_weapon(weapon_type, true);
character.dyn_bind_mut().swap_weapon(weapon_type, drop_ball);
let player_id = player.id();
self.run_deferred(move |_| {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer

View File

@ -181,7 +181,8 @@ impl NetworkManager {
}
Package::SwapWeapon(id, weapon_type) => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().handle_swap_weapon(id, weapon_type, true);
game.bind_mut()
.handle_swap_weapon(id, weapon_type, true, true);
}
}
Package::SetTeam(player_id, team) => {
@ -399,6 +400,7 @@ impl NetworkManager {
player.id(),
weapon_type,
false,
true,
);
}
}

View File

@ -12,6 +12,7 @@ use crate::{
chat::Chat,
game_manager::Game,
net::network_manager::{NetworkManager, Package, PeerKind},
ui::cli::CommandLinePanel,
};
#[derive(GodotClass)]
@ -85,6 +86,11 @@ impl IVBoxContainer for ChatBox {
}
fn input(&mut self, event: Gd<InputEvent>) {
let cli = CommandLinePanel::singleton();
if cli.bind().opened {
return;
}
if self.in_game && event.is_action_pressed("open_chat") {
if let Some(line_edit) = &mut self.line_edit {
let is_visible = line_edit.is_visible();

View File

@ -175,9 +175,17 @@ impl CommandLinePanel {
self.publish_message(format!("Unknown command: {}", command), CliColor::Info);
}
}
pub fn register_command(&mut self, name: String, command: Box<dyn Command>) {
self.commands.insert(name, Rc::new(command));
}
trait Command {
pub fn unregister_command(&mut self, name: String) {
self.commands.remove(&name);
}
}
pub trait Command {
fn execute(&self, cli: &mut CommandLinePanel, params: &[&str]);
fn help(&self) -> &str;
}