From c71366c2e0a9f0b454957feeb87b51f6b27d54bd Mon Sep 17 00:00:00 2001 From: Alexander Foremny Date: Fri, 15 Mar 2024 16:07:58 +0100 Subject: feat: add champions Select champions using the `--champion` flag. Valid values are `ranged` and `meele` (default). --- src/client.rs | 45 ++++++++++++++++++++--- src/main.rs | 5 +++ src/protocol.rs | 8 ++-- src/server.rs | 95 ++++++++++++++++++++++++++++++------------------ src/shared.rs | 4 ++ src/shared/champion.rs | 39 ++++++++++++++++++++ src/shared/projectile.rs | 2 - src/shared/stats.rs | 16 ++++++++ 8 files changed, 169 insertions(+), 45 deletions(-) create mode 100644 src/shared/champion.rs create mode 100644 src/shared/stats.rs diff --git a/src/client.rs b/src/client.rs index 174d615..fff18af 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,5 +1,6 @@ use crate::client::network::*; use crate::protocol::*; +use crate::shared::champion::*; use crate::shared::health::*; use crate::shared::imperative::*; use crate::shared::projectile::*; @@ -17,13 +18,19 @@ const PLAYER_RADIUS: f32 = 10.; const PLAYER_HOVER_INDICATOR_RADIUS: f32 = 13.; const PLAYER_HOVER_RADIUS: f32 = 20.; -pub fn main(server_addr: Option, client_id: u64, transport: TransportConfig) { +pub fn main( + server_addr: Option, + client_id: u64, + transport: TransportConfig, + champion: Champion, +) { App::new() .add_plugins(DefaultPlugins) .add_plugins(ClientPlugin { server_addr, client_id, transport, + champion, }) .run(); } @@ -31,15 +38,20 @@ pub fn main(server_addr: Option, client_id: u64, transport: Transpor #[derive(Resource)] struct ClientId(pub u64); +#[derive(Resource)] +struct MyChampion(pub Champion); + struct ClientPlugin { pub server_addr: Option, pub client_id: u64, pub transport: TransportConfig, + pub champion: Champion, } impl Plugin for ClientPlugin { fn build(&self, app: &mut App) { app.insert_resource(ClientId(self.client_id)) + .insert_resource(MyChampion(self.champion)) .add_plugins(NetworkPlugin { server_addr: self.server_addr.clone(), client_id: self.client_id, @@ -63,9 +75,12 @@ impl Plugin for ClientPlugin { } } -fn setup(mut client: ClientMut, mut commands: Commands) { +fn setup(mut client: ClientMut, mut commands: Commands, champion: Res) { commands.spawn(Camera2dBundle::default()); client.connect().unwrap(); + client + .send_message::(SelectChampion(champion.0)) + .unwrap(); } fn render_players( @@ -200,14 +215,22 @@ fn gizmos_attack_indicator( client_id: Res, hoverables: Query<(&PlayerId, &PlayerPosition)>, mut gizmos: Gizmos, - players: Query<(&PlayerId, &PlayerPosition)>, + player_positions: Query<(&PlayerId, &PlayerPosition)>, + player_champions: Query<(&PlayerId, &Champion)>, windows: Query<&Window>, ) { - let Some(position) = player_position(&client_id, &players) else { + let Some(position) = player_position(&client_id, &player_positions) else { + return; + }; + let Some(champion) = player_champion(&client_id, &player_champions) else { return; }; if hovered_other_player(&cameras, &client_id, &hoverables, &windows).is_some() { - gizmos.circle_2d(position.0, ATTACK_RANGE, Color::YELLOW); + gizmos.circle_2d( + position.0, + Stats::from_champion(champion).attack_range, + Color::YELLOW, + ); } } @@ -223,6 +246,18 @@ fn player_position( None } +fn player_champion( + client_id: &Res, + players: &Query<(&PlayerId, &Champion)>, +) -> Option { + for (id, champion) in players.iter() { + if id.0 == client_id.0 { + return Some(*champion); + } + } + None +} + const HEALTH_OFFSET: f32 = 4.; fn render_health(players: Query<(&Health, &PlayerPosition)>, mut gizmos: Gizmos) { diff --git a/src/main.rs b/src/main.rs index b615ddc..2326310 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use crate::shared::champion::*; use clap::Parser; use lightyear::transport::io::TransportConfig; use rand::Rng; @@ -17,6 +18,8 @@ struct Cli { connect_to: Option, #[arg(long, num_args = 0)] server: bool, + #[arg(long, default_value = "meele")] + champion: Champion, } fn main() { @@ -38,6 +41,7 @@ fn main() { Some(server_addr), client_id as u64, TransportConfig::UdpSocket(client_addr), + cli.champion, ); } else { let (from_server_send, from_server_recv) = crossbeam_channel::unbounded(); @@ -57,6 +61,7 @@ fn main() { recv: from_server_recv, send: to_server_send, }, + cli.champion, ); } } diff --git a/src/protocol.rs b/src/protocol.rs index 3d4567d..7ec3dcb 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -1,3 +1,4 @@ +use crate::shared::champion::*; use crate::shared::cooldown::*; use crate::shared::health::*; use crate::shared::imperative::*; @@ -16,11 +17,11 @@ pub enum Inputs { impl UserAction for Inputs {} #[derive(Message, Serialize, Deserialize, Clone, Debug, PartialEq)] -pub struct Message1(pub usize); +pub struct SelectChampion(pub Champion); #[message_protocol(protocol = "MyProtocol")] pub enum Messages { - Message1(Message1), + SelectChampion(SelectChampion), } #[component_protocol(protocol = "MyProtocol")] @@ -33,10 +34,11 @@ pub enum Components { ProjectilePosition(ProjectilePosition), Cooldown(Cooldown), Health(Health), + Champion(Champion), } #[derive(Channel)] -struct Channel1; +pub struct Channel1; protocolize! { Self = MyProtocol, diff --git a/src/server.rs b/src/server.rs index fab529f..1b9b7ef 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,5 +1,6 @@ use crate::protocol::*; use crate::server::network::*; +use crate::shared::champion::*; use crate::shared::cooldown::*; use crate::shared::health::*; use crate::shared::imperative::*; @@ -9,6 +10,7 @@ use bevy::prelude::*; use bevy::utils::Duration; use bevy::utils::HashMap; use lightyear::prelude::*; +use lightyear::server::events::MessageEvent; use rand::Rng; mod network; @@ -47,6 +49,7 @@ impl Plugin for ServerPlugin { }) .add_systems(Startup, setup) .add_systems(Update, (connects, disconnects)) + .add_systems(Update, receive_message) .add_systems(Update, timers_ticket) .add_systems(Update, health_regen.after(timers_ticket)) .add_systems( @@ -94,6 +97,21 @@ fn connects( } } +fn receive_message( + entity_map: Res, + mut commands: Commands, + mut reader: EventReader>, +) { + for event in reader.read() { + let client_id = event.context(); + let SelectChampion(champion) = event.message(); + let Some(entity) = entity_map.0.get(client_id) else { + return; + }; + commands.entity(*entity).insert(*champion); + } +} + fn disconnects( mut commands: Commands, mut disconnects: EventReader, @@ -175,47 +193,54 @@ fn imperative_attack( mut cooldowns: Query<&mut Cooldown>, mut players: Query<(&PlayerId, &mut Imperative)>, mut positions: Query<&mut PlayerPosition>, + champions: Query<&Champion>, time: Res