Make weapon swapping and ball dropping work correctly

This commit is contained in:
Sofia 2026-07-24 18:27:07 +03:00
parent 5b8dc1acc4
commit e60645f0f6
3 changed files with 69 additions and 59 deletions

View File

@ -503,6 +503,7 @@ impl Game {
killing_spree: 0,
killing_spree_cd: 0.,
character: None,
last_held_weapon: WeaponType::Raygun,
});
self.run_deferred(move |s| s.signals().on_new_player().emit(id));
@ -698,7 +699,10 @@ impl Game {
if let Some(player) = self.find_player_mut(player_id)
&& let Some(character) = &mut player.character
{
character.dyn_bind_mut().spawn_weapon_common(weapon_type);
if weapon_type != WeaponType::Ball {
player.last_held_weapon = weapon_type;
}
character.dyn_bind_mut().swap_weapon(weapon_type, true);
let player_id = player.id();
self.run_deferred(move |_| {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer
@ -725,6 +729,11 @@ impl Game {
.spawn_player(id, team, id == self.self_id.unwrap_or(0), None);
if let Some(character) = &mut character {
if let Some(player) = self.find_player(id) {
character
.dyn_bind_mut()
.swap_weapon(player.last_held_weapon, true);
}
if let Ok(mut local_player) = character.clone().try_cast::<LocalPlayer>() {
local_player.bind_mut().signals().on_die().connect_other(
self,
@ -982,6 +991,7 @@ pub struct Player {
pub character: Option<DynGd<CharacterBody3D, dyn IPlayer + 'static>>,
pub killing_spree: u16,
pub killing_spree_cd: f64,
pub last_held_weapon: WeaponType,
}
impl Player {
@ -1099,6 +1109,7 @@ impl From<NetPlayer> for Player {
character: None,
killing_spree: 0,
killing_spree_cd: 0.,
last_held_weapon: WeaponType::Raygun,
}
}
}

View File

@ -387,12 +387,16 @@ impl NetworkManager {
}
}
Package::SwapWeapon(_, weapon_type) => {
if let Some(game) = &mut Game::singleton()
&& let Some(player) =
game.bind_mut().find_player_by_addr_mut(&conn.address)
&& let Some(character) = &mut player.character
{
character.dyn_bind_mut().swap_weapon_proxy(weapon_type);
if let Some(game) = &mut Game::singleton() {
let player =
game.bind().find_player_by_addr(&conn.address).cloned();
if let Some(player) = player {
game.bind_mut().handle_swap_weapon(
player.id(),
weapon_type,
false,
);
}
}
}
_ => {}

View File

@ -58,8 +58,7 @@ pub trait IPlayer {
fn is_dead(&self) -> bool;
fn kill(&mut self, source_player: DamageSource);
fn dead_for(&self) -> f64;
fn spawn_weapon_common(&mut self, weapon: WeaponType);
fn swap_weapon_proxy(&mut self, weapon: WeaponType);
fn swap_weapon(&mut self, weapon: WeaponType, drop_ball: bool);
fn get_weapon(&self) -> Option<DynGd<Node3D, dyn Weapon>>;
fn take_weapon(&mut self) -> Option<DynGd<Node3D, dyn Weapon>>;
fn drop_ball(&mut self, with_velocity: bool) -> bool;
@ -70,7 +69,6 @@ pub trait PlayerCommon {
fn player_update(&mut self, delta: f64);
fn try_jump(&mut self) -> bool;
fn drop_ball_common(&mut self, with_velocity: bool) -> bool;
fn swap_weapon(&mut self, ty: WeaponType);
fn get_look_dir(&self) -> Vector3;
fn can_take_damage(&self, source: &DamageSource) -> bool;
}
@ -108,18 +106,16 @@ impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
}
fn drop_ball_common(&mut self, with_velocity: bool) -> bool {
if let Some(weapon) = self.take_weapon()
if let Some(weapon) = self.get_weapon()
&& let Ok(_) = weapon.try_cast::<BallWeapon>()
{
self.run_deferred(move |s| {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer
&& let PeerKind::Server(peer, _) = peer
if let Some(game) = Game::singleton()
&& let Some(player) = game.bind().find_player(s.get_player_id().unwrap_or(0))
{
s.spawn_weapon_common(WeaponType::Raygun);
peer.broadcast_reliable(Package::SwapWeapon(
s.get_player_id().unwrap_or(0),
WeaponType::Raygun,
));
s.swap_weapon(player.last_held_weapon, false);
}
if NetworkManager::singleton().bind().is_host() {
if let Some(mut game) = Game::singleton() {
if let Some(ball_origin) = &s.get_camera_origin() {
let velocity = if with_velocity {
@ -146,28 +142,6 @@ impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
}
}
fn swap_weapon(&mut self, ty: WeaponType) {
if ty == WeaponType::Ball {
return;
}
self.spawn_weapon_common(ty);
self.run_deferred(move |s| {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
match peer {
PeerKind::Client(peer, socket_addr) => {
peer.send_reliable(socket_addr, Package::SwapWeapon(0, ty));
}
PeerKind::Server(peer, _) => {
peer.broadcast_reliable(Package::SwapWeapon(
s.get_player_id().unwrap_or(0),
ty,
));
}
}
}
});
}
fn get_look_dir(&self) -> Vector3 {
if let Some(camera_origin) = self.get_camera_origin() {
camera_origin.get_global_basis().col_c().neg()
@ -384,8 +358,10 @@ impl IPlayer for LocalPlayer {
}
}
fn spawn_weapon_common(&mut self, weapon: WeaponType) {
fn swap_weapon(&mut self, weapon: WeaponType, drop_ball: bool) {
if drop_ball {
self.drop_ball(true);
}
if let Some(mesh) = self.soldier_mesh.clone() {
match weapon {
@ -408,16 +384,12 @@ impl IPlayer for LocalPlayer {
}
}
fn swap_weapon_proxy(&mut self, weapon: WeaponType) {
self.swap_weapon(weapon);
}
fn get_weapon(&self) -> Option<DynGd<Node3D, dyn Weapon>> {
self.weapon.clone()
}
fn take_weapon(&mut self) -> Option<DynGd<Node3D, dyn Weapon>> {
self.weapon.as_ref().take().cloned()
self.weapon.take()
}
fn drop_ball(&mut self, with_velocity: bool) -> bool {
@ -467,7 +439,7 @@ impl ICharacterBody3D for LocalPlayer {
.connect_other(self, |s| s.update_lock());
}
self.spawn_weapon_common(WeaponType::Raygun);
self.swap_weapon(WeaponType::Raygun, false);
if let Some(camera) = &mut self.camera {
camera.set_current(true);
@ -642,10 +614,35 @@ impl ICharacterBody3D for LocalPlayer {
}
}
}
} else if event.is_action_pressed("weapon_1") {
self.swap_weapon(WeaponType::Raygun);
}
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
let weapon_type = if event.is_action_pressed("weapon_1") {
Some(WeaponType::Raygun)
} else if event.is_action_pressed("weapon_2") {
self.swap_weapon(WeaponType::Shotgun);
Some(WeaponType::Shotgun)
} else {
None
};
if let Some(weapon_type) = weapon_type {
self.swap_weapon(weapon_type, true);
match peer {
PeerKind::Client(peer, socket_addr) => {
peer.send_reliable(socket_addr, Package::SwapWeapon(0, weapon_type));
}
PeerKind::Server(peer, _) => {
if let Some(game) = &mut Game::singleton()
&& let Some(player) =
game.bind_mut().find_player_mut(self.player_id.unwrap_or(0))
{
player.last_held_weapon = weapon_type;
}
peer.broadcast_reliable(Package::SwapWeapon(
self.player_id.unwrap_or(0),
weapon_type,
));
}
}
}
}
if let Ok(event) = event.try_cast::<InputEventMouseMotion>() {
@ -894,8 +891,10 @@ impl IPlayer for RemotePlayer {
self.is_dead = true;
}
fn spawn_weapon_common(&mut self, weapon: WeaponType) {
fn swap_weapon(&mut self, weapon: WeaponType, drop_ball: bool) {
if drop_ball {
self.drop_ball(true);
}
if let Some(mesh) = &mut self.soldier_mesh {
match weapon {
@ -906,10 +905,6 @@ impl IPlayer for RemotePlayer {
}
}
fn swap_weapon_proxy(&mut self, weapon: WeaponType) {
self.swap_weapon(weapon);
}
fn get_weapon(&self) -> Option<DynGd<Node3D, dyn Weapon>> {
self.soldier_mesh
.as_ref()
@ -946,7 +941,7 @@ impl ICharacterBody3D for RemotePlayer {
}
});
self.spawn_weapon_common(WeaponType::Raygun);
self.swap_weapon(WeaponType::Raygun, false);
}
fn process(&mut self, delta: f64) {