From 4f51f3488d3807ba315f9a7553b65dcda35e7dab Mon Sep 17 00:00:00 2001 From: Txreq Date: Sun, 25 Feb 2024 15:01:15 +0100 Subject: [PATCH] akshwali working weapons (finally) --- src/client/main.rs | 91 +++++++++++----------- src/lib/configs/mod.rs | 2 +- src/lib/entities/enemy.rs | 19 ++--- src/lib/entities/player.rs | 29 ++++--- src/lib/entities/weapon.rs | 156 ++++++++++++++++++++----------------- src/lib/network/mod.rs | 1 + src/lib/utils/mod.rs | 4 +- src/server/main.rs | 54 +++++++------ 8 files changed, 188 insertions(+), 168 deletions(-) diff --git a/src/client/main.rs b/src/client/main.rs index f5f79c1..549e98c 100644 --- a/src/client/main.rs +++ b/src/client/main.rs @@ -169,7 +169,7 @@ impl NetUpdateHandle for Game { .into_iter() .map(|(id, data)| { let client_id = ClientId::from_raw(id); - let mut enemy = Enemy::new( + let enemy = Enemy::new( client_id, data.position.0, data.position.1, @@ -178,9 +178,6 @@ impl NetUpdateHandle for Game { Rc::clone(&self.assets), ); - enemy.inventory.select(data.weapon); - enemy.inventory.add(Weapon::new(data.weapon)); - (client_id, enemy) }) .collect::>() @@ -202,7 +199,7 @@ impl NetUpdateHandle for Game { local_player.inventory.add(Weapon::new(data.weapon)); } else { let id = ClientId::from_raw(data._id); - let mut enemy = Enemy::new( + let enemy = Enemy::new( id, pos_x, pos_y, @@ -211,18 +208,43 @@ impl NetUpdateHandle for Game { Rc::clone(&self.assets), ); - enemy.inventory.select(data.weapon); - enemy.inventory.add(Weapon::new(data.weapon)); self.world.enemies.insert(id, enemy); } } - // these run at every frame - GameNetworkPacket::NET_PLAYER_WORLD_POSITION(id, (x, y)) => { - if let Some(enemy) = self.world.enemies.get_mut(&ClientId::from_raw(id)) { - enemy.rectangle.x = x; - enemy.rectangle.y = y; + _ => {} + } + }; + } + + while let Some(message) = network + .client + .receive_message(DefaultChannel::ReliableUnordered) + { + if let Ok(packet) = rmp_serde::from_slice::(&message) { + match packet { + GameNetworkPacket::NET_PLAYER_LEFT(id) => { + log::info!("player {:?} left", id); + self.world + .enemies + .remove(&ClientId::from_raw(id)) + .expect("failed to remove player data"); + } + GameNetworkPacket::NET_PLAYER_RESPAWN(d_id, data) => { + if d_id == network.transport.client_id().raw() { + local_player.rectangle.x = data.position.0; + local_player.rectangle.y = data.position.1; + local_player.health = data.health; + local_player.ready = true; + local_player.inventory.cash = data.cash; + local_player.inventory.reset_weapons(); } } + GameNetworkPacket::NET_PLAYER_KILL_REWARD(data) => { + local_player.inventory.cash = data.cash; + } + GameNetworkPacket::NET_PLAYER_WEAPON(variant) => { + local_player.inventory.add(variant.weapon_instance()); + } GameNetworkPacket::NET_PROJECTILE_CREATE(projectile) => { self.world.projectiles.insert( projectile.id, @@ -254,40 +276,11 @@ impl NetUpdateHandle for Game { } } } - _ => {} - } - }; - } - - while let Some(message) = network - .client - .receive_message(DefaultChannel::ReliableUnordered) - { - if let Ok(packet) = rmp_serde::from_slice::(&message) { - match packet { - GameNetworkPacket::NET_PLAYER_LEFT(id) => { - log::info!("player {:?} left", id); - self.world - .enemies - .remove(&ClientId::from_raw(id)) - .expect("failed to remove player data"); - } - GameNetworkPacket::NET_PLAYER_RESPAWN(d_id, data) => { - if d_id == network.transport.client_id().raw() { - local_player.rectangle.x = data.position.0; - local_player.rectangle.y = data.position.1; - local_player.health = data.health; - local_player.ready = true; - local_player.inventory.cash = data.cash; - local_player.inventory.reset_weapons(); + GameNetworkPacket::NET_PLAYER_WEAPON_SELECT(id, variant) => { + if let Some(enemy) = self.world.enemies.get_mut(&ClientId::from_raw(id)) { + enemy.weapon = Some(variant) } } - GameNetworkPacket::NET_PLAYER_KILL_REWARD(data) => { - local_player.inventory.cash = data.cash; - } - GameNetworkPacket::NET_PLAYER_WEAPON(variant) => { - local_player.inventory.add(variant.weapon_instance()); - } _ => {} } } @@ -301,6 +294,12 @@ impl NetUpdateHandle for Game { puppet.orientation = orientation } } + GameNetworkPacket::NET_PLAYER_WORLD_POSITION(id, (x, y)) => { + if let Some(enemy) = self.world.enemies.get_mut(&ClientId::from_raw(id)) { + enemy.rectangle.x = x; + enemy.rectangle.y = y; + } + } _ => {} } } @@ -326,7 +325,7 @@ impl NetUpdateHandle for Game { ); network.client.send_message( - DefaultChannel::ReliableOrdered, + DefaultChannel::ReliableUnordered, GameNetworkPacket::NET_PROJECTILE_CREATE(ProjectileData { id: p.id, position: (p.position.x, p.position.y), @@ -363,7 +362,7 @@ impl NetUpdateHandle for Game { let position = local_player.move_to(position); network.client.send_message( - DefaultChannel::ReliableUnordered, + DefaultChannel::Unreliable, GameNetworkPacket::NET_PLAYER_WORLD_POSITION( network.uuid, (position.x, position.y), diff --git a/src/lib/configs/mod.rs b/src/lib/configs/mod.rs index fa13ae5..aa06e92 100644 --- a/src/lib/configs/mod.rs +++ b/src/lib/configs/mod.rs @@ -4,7 +4,7 @@ use crate::types::Health; pub static INITIAL_PAYLOAD_SIZE: usize = 255; -pub static WORLD_TILE_SIZE: f32 = 50.0; +pub static WORLD_TILE_SIZE: f32 = 70.0; pub static ENTITY_PLAYER_SIZE: f32 = WORLD_TILE_SIZE * 0.8; pub static ENTITY_WEAPON_SIZE: f32 = ENTITY_PLAYER_SIZE * 0.0018; pub static ENTITY_PLAYER_MAX_HEALTH: Health = 100; diff --git a/src/lib/entities/enemy.rs b/src/lib/entities/enemy.rs index d0b86ed..29faf81 100644 --- a/src/lib/entities/enemy.rs +++ b/src/lib/entities/enemy.rs @@ -2,9 +2,10 @@ use raylib::prelude::*; use nalgebra::Vector2; use renet::ClientId; +use std::path::is_separator; use std::rc::Rc; -use super::Invenotry; +use super::WeaponVariant; use crate::configs::*; use crate::core::*; @@ -17,7 +18,7 @@ pub struct Enemy { pub rectangle: Rectangle, pub origin: Vector2, pub health: Health, - pub inventory: Invenotry, + pub weapon: Option, assets: SharedAssets, } @@ -36,7 +37,7 @@ impl Enemy { rectangle: Rectangle::new(x, y, ENTITY_PLAYER_SIZE as f32, ENTITY_PLAYER_SIZE as f32), origin: Default::default(), health: hp, - inventory: Invenotry::new(Rc::clone(&assets)), + weapon: None, assets, } } @@ -47,12 +48,12 @@ impl RenderHandle for Enemy { where Self: AssetsHandle, { - d.draw_rectangle_pro(self.rectangle, RVector2::zero(), 0.0, Color::RED); - - let radius = self.rectangle.width / 2.0; - let origin = Vector2::new(self.rectangle.x, self.rectangle.y).add_scalar(radius); - self.inventory - .render_weapon(d, &self.rectangle, self.orientation); + let assets = Rc::clone(&self.assets); + d.draw_rectangle_pro(self.rectangle, RVector2::zero(), 0.0, Color::WHITE); + if let Some(wpn) = self.weapon { + wpn.weapon_instance() + .render_weapon(d, &self.rectangle, self.orientation, assets); + } } } diff --git a/src/lib/entities/player.rs b/src/lib/entities/player.rs index 5648ba0..a693652 100644 --- a/src/lib/entities/player.rs +++ b/src/lib/entities/player.rs @@ -199,7 +199,7 @@ impl NetUpdateHandle for Player { if let Some(wpn) = self.inventory.selected_weapon_mut() { if handle.is_key_pressed(KeyboardKey::KEY_R) { self.reloading = true; - self.timers.add(Timers::PlayerReloading, Instant::now()); + self.timers.add(Timers::PlayerReloading); } if self.reloading @@ -215,16 +215,27 @@ impl NetUpdateHandle for Player { for wpn_variant in WeaponVariant::VARIANTS { let wpn = Weapon::new(*wpn_variant); - if !self.inventory.has(wpn_variant) { - network.client.send_message( - DefaultChannel::ReliableUnordered, - GameNetworkPacket::NET_PLAYER_WEAPON(*wpn_variant) + if handle.is_key_pressed(wpn.equip_key()) && !self.reloading { + if !self.inventory.has(wpn_variant) { + network.client.send_message( + DefaultChannel::ReliableUnordered, + GameNetworkPacket::NET_PLAYER_WEAPON(*wpn_variant) + .serialized() + .unwrap(), + ) + } else { + self.inventory.select(*wpn_variant); + network.client.send_message( + DefaultChannel::ReliableUnordered, + GameNetworkPacket::NET_PLAYER_WEAPON_SELECT( + network.transport.client_id().raw(), + *wpn_variant, + ) .serialized() .unwrap(), - ) - } else if handle.is_key_pressed(wpn.equip_key()) && !self.reloading { - self.inventory.select(*wpn_variant); - }; + ) + } + } } } } diff --git a/src/lib/entities/weapon.rs b/src/lib/entities/weapon.rs index f1338f1..a8ac27d 100644 --- a/src/lib/entities/weapon.rs +++ b/src/lib/entities/weapon.rs @@ -5,6 +5,7 @@ use raylib::prelude::*; use lazy_static::lazy_static; use nalgebra::{Rotation2, Vector2}; use serde::{Deserialize, Serialize}; +use std::rc::Rc; use std::{collections::HashMap, time::Duration}; use strum_macros::VariantArray; @@ -21,7 +22,7 @@ lazy_static! { Duration::from_millis(1500), 30, 4, - 2700 + 27 ); pub static ref WPN_STATS_SHOTPEW: WeaponStats = WeaponStats::new( "PUMP Shotpew", @@ -31,7 +32,7 @@ lazy_static! { Duration::from_millis(2000), 5, 5, - 2100 + 21 ); pub static ref WPN_STATS_DEAN_1911: WeaponStats = WeaponStats::new( "DEAN 1911", @@ -41,7 +42,7 @@ lazy_static! { Duration::from_millis(1100), 7, 4, - 400 + 4 ); pub static ref WPN_STATS_PRRR: WeaponStats = WeaponStats::new( "PRRR", @@ -51,7 +52,7 @@ lazy_static! { Duration::from_millis(2500), 30, 4, - 5200 + 52 ); } @@ -161,7 +162,7 @@ wpn_stats_mapping!( WPN_STATS_PRRR ); -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub struct Weapon { pub variant: WeaponVariant, pub texture: LTexture, @@ -174,8 +175,6 @@ pub struct Weapon { impl Weapon { pub fn new(variant: WeaponVariant) -> Self { - let _ = WeaponStatsMapping::WPN_STATS_AKA_69.get(); - match variant { WeaponVariant::DEAN_1911 => { let stats = WeaponStatsMapping::WPN_STATS_DEAN_1911.get(); @@ -190,7 +189,7 @@ impl Weapon { } } WeaponVariant::AKA_69 => { - let stats = WeaponStatsMapping::WPN_STATS_DEAN_1911.get(); + let stats = WeaponStatsMapping::WPN_STATS_AKA_69.get(); Weapon { variant, texture: LTexture::WPN_AKA, @@ -202,7 +201,7 @@ impl Weapon { } } WeaponVariant::SHOTPEW => { - let stats = WeaponStatsMapping::WPN_STATS_DEAN_1911.get(); + let stats = WeaponStatsMapping::WPN_STATS_SHOTPEW.get(); Weapon { variant, texture: LTexture::WPN_SHOTPEW, @@ -214,7 +213,7 @@ impl Weapon { } } WeaponVariant::PRRR => { - let stats = WeaponStatsMapping::WPN_STATS_DEAN_1911.get(); + let stats = WeaponStatsMapping::WPN_STATS_PRRR.get(); Weapon { variant, texture: LTexture::WPN_PRRR, @@ -287,6 +286,68 @@ impl Weapon { pub fn equip_key(&self) -> KeyboardKey { self.key } + + pub fn render_weapon( + &self, + d: &mut RaylibMode2D, + player_rect: &Rectangle, + orientation: f32, + assets: SharedAssets, + ) { + let assets = assets.borrow(); + let buffer = assets.textures.get(&self.texture).unwrap(); + + let (wpn_w, wpn_h) = ( + buffer.width as f32 * ENTITY_WEAPON_SIZE, + buffer.height as f32 * ENTITY_WEAPON_SIZE, + ); + + let radius = player_rect.width / 2.0; + let origin = Vector2::new(player_rect.x, player_rect.y).add_scalar(radius); + + let wpn_coords = + Vector2::new(radius * orientation.cos(), radius * orientation.sin()) + origin; + let theta = orientation.to_degrees(); + + let flip_y = if theta.abs() <= 180.0 && theta.abs() > 90.0 { + true + } else { + false + }; + + let src_rect = Rectangle::new( + 0.0, + 0.0, + buffer.width as f32, + buffer.height as f32 * if flip_y { -1.0 } else { 1.0 }, + ); + + let wpn_x = wpn_coords.x; + let wpn_y = wpn_coords.y; + + let dest_rect = Rectangle::new(wpn_x, wpn_y, wpn_w, wpn_h); + + d.draw_texture_pro( + buffer, + src_rect, + dest_rect, + RVector2::new(0.0, wpn_h / 2.0), + theta, + Color::WHITE, + ); + + #[cfg(debug_assertions)] + { + if d.is_key_down(KeyboardKey::KEY_LEFT_ALT) { + d.draw_rectangle_pro(dest_rect, RVector2::zero(), theta, Color::YELLOW); + } + + let coords = self.muzzle(buffer, player_rect, orientation); + + d.draw_circle(coords.x as i32, coords.y as i32, 2.0, Color::RED); + d.draw_circle_lines(origin.x as i32, origin.y as i32, radius, Color::RED); + } + } } /// controllers some puppet's (`Player`, `Enemy`) weapons 'n' ammo @@ -308,6 +369,18 @@ impl Invenotry { } } + pub fn render_weapon( + &self, + d: &mut RaylibMode2D, + player_rect: &Rectangle, + orientation: f32, + ) { + if let Some(wpn) = self.selected_weapon() { + // let wpn = *wpn; + wpn.render_weapon(d, player_rect, orientation, Rc::clone(&self.assets)); + } + } + pub fn reset_weapons(&mut self) { self.weapons = HashMap::new(); self.add(Weapon::new(WeaponVariant::DEAN_1911)); @@ -324,69 +397,6 @@ impl Invenotry { self.weapons.get(variant) } - pub fn render_weapon( - &mut self, - d: &mut RaylibMode2D, - player_rect: &Rectangle, - orientation: f32, - ) { - if let Some(wpn) = &self.selected_weapon() { - let assets = self.assets.borrow(); - let buffer = assets.textures.get(&wpn.texture).unwrap(); - - let (wpn_w, wpn_h) = ( - buffer.width as f32 * ENTITY_WEAPON_SIZE, - buffer.height as f32 * ENTITY_WEAPON_SIZE, - ); - - let radius = player_rect.width / 2.0; - let origin = Vector2::new(player_rect.x, player_rect.y).add_scalar(radius); - - let wpn_coords = - Vector2::new(radius * orientation.cos(), radius * orientation.sin()) + origin; - let theta = orientation.to_degrees(); - - let flip_y = if theta.abs() <= 180.0 && theta.abs() > 90.0 { - true - } else { - false - }; - - let src_rect = Rectangle::new( - 0.0, - 0.0, - buffer.width as f32, - buffer.height as f32 * if flip_y { -1.0 } else { 1.0 }, - ); - - let wpn_x = wpn_coords.x; - let wpn_y = wpn_coords.y; - - let dest_rect = Rectangle::new(wpn_x, wpn_y, wpn_w, wpn_h); - - d.draw_texture_pro( - buffer, - src_rect, - dest_rect, - RVector2::new(0.0, wpn_h / 2.0), - theta, - Color::WHITE, - ); - - #[cfg(debug_assertions)] - { - if d.is_key_down(KeyboardKey::KEY_LEFT_ALT) { - d.draw_rectangle_pro(dest_rect, RVector2::zero(), theta, Color::YELLOW); - } - - let coords = wpn.muzzle(buffer, player_rect, orientation); - - d.draw_circle(coords.x as i32, coords.y as i32, 2.0, Color::RED); - d.draw_circle_lines(origin.x as i32, origin.y as i32, radius, Color::RED); - } - }; - } - pub fn selected_weapon(&self) -> Option<&Weapon> { self.selected_weapon .as_ref() diff --git a/src/lib/network/mod.rs b/src/lib/network/mod.rs index a3c3811..6135d1b 100644 --- a/src/lib/network/mod.rs +++ b/src/lib/network/mod.rs @@ -59,6 +59,7 @@ pub enum GameNetworkPacket { NET_PLAYER_ORIENTATION(u64, f32), NET_PLAYER_LEFT(RawClientId), NET_PLAYER_WEAPON(WeaponVariant), + NET_PLAYER_WEAPON_SELECT(RawClientId, WeaponVariant), NET_PROJECTILE_CREATE(ProjectileData), NET_PROJECTILE_IMPACT(RawProjectileId, Option, Damage), } diff --git a/src/lib/utils/mod.rs b/src/lib/utils/mod.rs index 12b0b95..84e7da3 100644 --- a/src/lib/utils/mod.rs +++ b/src/lib/utils/mod.rs @@ -81,13 +81,13 @@ pub mod time { } } None => { - self.add(id, Instant::now()); + self.add(id); true } } } - pub fn add(&mut self, id: T, instant: Instant) { + pub fn add(&mut self, id: T) { self.value.insert(id, Instant::now()); } } diff --git a/src/server/main.rs b/src/server/main.rs index cc4520d..0d3df65 100644 --- a/src/server/main.rs +++ b/src/server/main.rs @@ -157,38 +157,18 @@ fn main() { for client_id in server.clients_id() { while let Some(message) = - server.receive_message(client_id, DefaultChannel::ReliableOrdered) + server.receive_message(client_id, DefaultChannel::ReliableUnordered) { - if let (Ok(packet), Some(_)) = ( + if let (Ok(packet), Some(player)) = ( rmp_serde::from_slice::(&message), state.players.get_mut(&client_id), ) { match packet { GameNetworkPacket::NET_PROJECTILE_CREATE(projectile) => { state.projectiles.insert(projectile.id, projectile); - server.broadcast_message(DefaultChannel::ReliableOrdered, message); + server.broadcast_message(DefaultChannel::ReliableUnordered, message); } - _ => {} - } - } - } - while let Some(message) = - server.receive_message(client_id, DefaultChannel::ReliableUnordered) - { - if let (Ok(packet), Some(player)) = ( - rmp_serde::from_slice::(&message), - state.players.get_mut(&client_id), - ) { - match packet { - GameNetworkPacket::NET_PLAYER_WORLD_POSITION(_, (x, y)) => { - player.data.position = (x, y); - server.broadcast_message_except( - client_id, - DefaultChannel::ReliableOrdered, - message, - ) - } GameNetworkPacket::NET_PLAYER_DIED(id) => { if player.id.raw() == id { let rnd_spwn = map.get_random_spawn_position(); @@ -232,7 +212,11 @@ fn main() { } GameNetworkPacket::NET_PLAYER_WEAPON(variant) => { let wpn = variant.weapon_instance(); - if player.data.cash >= *wpn.stats.price() as i64 { + let price = *wpn.stats.price() as i64; + + if player.data.cash >= price { + player.data.cash -= price; + server.send_message( client_id, DefaultChannel::ReliableUnordered, @@ -242,6 +226,12 @@ fn main() { ) } } + GameNetworkPacket::NET_PLAYER_WEAPON_SELECT(_, _) => server + .broadcast_message_except( + client_id, + DefaultChannel::ReliableUnordered, + message, + ), _ => {} } } @@ -249,11 +239,19 @@ fn main() { while let Some(message) = server.receive_message(client_id, DefaultChannel::Unreliable) { - if let (Ok(packet), Some(_)) = ( + if let (Ok(packet), Some(player)) = ( rmp_serde::from_slice::(&message), state.players.get_mut(&client_id), ) { match packet { + GameNetworkPacket::NET_PLAYER_WORLD_POSITION(_, (x, y)) => { + player.data.position = (x, y); + server.broadcast_message_except( + client_id, + DefaultChannel::Unreliable, + message, + ) + } GameNetworkPacket::NET_PLAYER_ORIENTATION(_, _) => { server.broadcast_message(DefaultChannel::Unreliable, message) } @@ -296,7 +294,7 @@ fn main() { { hits.push(*id); server.broadcast_message( - DefaultChannel::ReliableOrdered, + DefaultChannel::ReliableUnordered, GameNetworkPacket::NET_PROJECTILE_IMPACT(*id, None, projectile.damage) .serialized() .unwrap(), @@ -317,7 +315,7 @@ fn main() { player.data._last = Some(projectile.shooter); hits.push(*id); server.broadcast_message( - DefaultChannel::ReliableOrdered, + DefaultChannel::ReliableUnordered, GameNetworkPacket::NET_PROJECTILE_IMPACT( *id, Some(player.id.raw()), @@ -358,7 +356,7 @@ impl Client { orientation: 0.0, health: 100, weapon: WeaponVariant::DEAN_1911, - cash: 2200, + cash: 200, }, } }