diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4d9636b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.showUnlinkedFileNotification": false +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 6ac8535..9877720 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1314,10 +1314,13 @@ dependencies = [ name = "border-wars" version = "0.1.0" dependencies = [ + "bevnet", "bevy", "bevy_egui", "noise", "paste", + "serde", + "uuid", ] [[package]] @@ -3805,18 +3808,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", diff --git a/crates/border-wars/Cargo.toml b/crates/border-wars/Cargo.toml index fc84f96..8ad9ea3 100644 --- a/crates/border-wars/Cargo.toml +++ b/crates/border-wars/Cargo.toml @@ -15,3 +15,6 @@ bevy = "0.12.1" bevy_egui = "0.24.0" noise = "0.8.2" paste = "1.0.14" +bevnet = { path = "../bevnet" } +uuid = "1.7.0" +serde = "1.0.197" diff --git a/crates/border-wars/src/connection.rs b/crates/border-wars/src/connection.rs new file mode 100644 index 0000000..d1518b6 --- /dev/null +++ b/crates/border-wars/src/connection.rs @@ -0,0 +1,37 @@ +//! All the code related to the connection to an host. + +use std::collections::HashMap; + +use bevnet::NetworkAppExt; +use bevy::prelude::*; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +/// TODO +#[derive(Resource, Default, Deserialize, Serialize, Clone)] +pub struct AllPlayers(pub HashMap); + +/// The plugin that manages the connection to the host. +pub struct ConnectionPlugin; + +impl Plugin for ConnectionPlugin { + fn build(&self, app: &mut App) { + app.add_network_event::() + .add_network_event::() + .init_resource::(); + } +} + +#[derive(Event, Deserialize, Serialize)] +/// The message sent by the client to the server to request a connection. +pub struct RequestConnection { + /// The name of the player. + pub name: String, +} + +#[derive(Event, Deserialize, Serialize)] +/// The message sent by the server to all clients when a new player joins. +pub struct UpdatePlayers { + /// All players in the game. + pub players: AllPlayers, +} diff --git a/crates/border-wars/src/lib.rs b/crates/border-wars/src/lib.rs index 257aefb..2a298f3 100644 --- a/crates/border-wars/src/lib.rs +++ b/crates/border-wars/src/lib.rs @@ -3,6 +3,7 @@ use bevy::prelude::*; pub mod camera; +pub mod connection; pub mod map; pub mod responsive_scale; pub mod scenes; @@ -14,9 +15,16 @@ pub enum CurrentScene { #[default] Menu, - /// When we are in the lobby waiting for players to join the game. + /// When you are the host in the lobby waiting for players to join the game. Lobby, + /// When you are the player waiting for the host to start. + JoinMenu, + /// When we play this wonderful game. Game, } + +/// The name of the player. +#[derive(Resource, Clone, Default)] +pub struct PlayerName(pub String); diff --git a/crates/border-wars/src/main.rs b/crates/border-wars/src/main.rs index cc2c72e..4a6df7a 100644 --- a/crates/border-wars/src/main.rs +++ b/crates/border-wars/src/main.rs @@ -1,7 +1,9 @@ //! The main entry point of the game. +use bevnet::NetworkPlugin; use bevy::prelude::*; use border_wars::camera::CameraPlugin; +use border_wars::connection::ConnectionPlugin; use border_wars::map::click_tile::TilesClickable; use border_wars::map::renderer::RendererPlugin; use border_wars::scenes::ScenesPlugin; @@ -13,5 +15,7 @@ fn main() { .add_plugins(RendererPlugin) .add_plugins(CameraPlugin) .add_plugins(TilesClickable) + .add_plugins(NetworkPlugin::new("relay.cocosol.fr".to_string())) + .add_plugins(ConnectionPlugin) .run(); } diff --git a/crates/border-wars/src/scenes/join_menu.rs b/crates/border-wars/src/scenes/join_menu.rs new file mode 100644 index 0000000..9107477 --- /dev/null +++ b/crates/border-wars/src/scenes/join_menu.rs @@ -0,0 +1,52 @@ +//! The lobby of the game. + +use std::collections::HashMap; + +use bevnet::{Connection, Receive, SendTo, Uuid}; +use bevy::prelude::*; +use bevy_egui::{egui, EguiContexts}; + +use crate::connection::{AllPlayers, RequestConnection, UpdatePlayers}; +use crate::{CurrentScene, PlayerName}; + +/// The plugin for the lobby. +pub struct JoinMenuPlugin; + +impl Plugin for JoinMenuPlugin { + fn build(&self, app: &mut App) { + app.add_systems( + Update, + (menu_ui, update_players).run_if(in_state(CurrentScene::JoinMenu)), + ); + } +} + +/// Display the UI of the lobby. +fn menu_ui(mut ctx: EguiContexts, all_players: Res) { + egui::CentralPanel::default().show(ctx.ctx_mut(), |ui| { + ui.heading("Border Wars"); + + ui.separator(); + + for player in all_players.0.values() { + ui.horizontal(|ui| { + ui.label(player.to_string()); + }); + } + }); +} + +fn update_players( + mut event_reader: EventReader>, + mut all_players: ResMut, + name: Res, + mut next_scene: ResMut>, +) { + for event in event_reader.read() { + println!( + "{:?}", + event.1.players.0.values().into_iter().collect::>() + ); + *all_players = event.1.players.clone(); + } +} diff --git a/crates/border-wars/src/scenes/lobby.rs b/crates/border-wars/src/scenes/lobby.rs index 84a0348..2c23940 100644 --- a/crates/border-wars/src/scenes/lobby.rs +++ b/crates/border-wars/src/scenes/lobby.rs @@ -1,21 +1,33 @@ //! The lobby of the game. +use std::collections::HashMap; + +use bevnet::{Connection, Receive, SendTo, Uuid}; use bevy::prelude::*; use bevy_egui::{egui, EguiContexts}; -use crate::CurrentScene; +use crate::connection::{AllPlayers, RequestConnection, UpdatePlayers}; +use crate::{CurrentScene, PlayerName}; /// The plugin for the lobby. pub struct LobbyPlugin; impl Plugin for LobbyPlugin { fn build(&self, app: &mut App) { - app.add_systems(Update, lobby_ui.run_if(in_state(CurrentScene::Lobby))); + app.add_systems(Update, lobby_ui.run_if(in_state(CurrentScene::Lobby))) + .add_systems( + Update, + handle_connection.run_if(in_state(CurrentScene::Lobby)), + ); } } /// Display the UI of the lobby. -fn lobby_ui(mut ctx: EguiContexts, mut next_scene: ResMut>) { +fn lobby_ui( + mut ctx: EguiContexts, + mut next_scene: ResMut>, + connection_string: Res, +) { egui::CentralPanel::default().show(ctx.ctx_mut(), |ui| { ui.heading("Border Wars"); @@ -25,7 +37,7 @@ fn lobby_ui(mut ctx: EguiContexts, mut next_scene: ResMut>, + mut event_writer: EventWriter>, + mut all_players: ResMut, +) { + for event in event_reader.read() { + if !all_players.0.contains_key(&event.1.name) { + all_players.0.insert(event.1.name.clone(), event.0); + println!("yes"); + } + for player in all_players.0.values() { + println!("{:?}", player); + event_writer.send(SendTo( + *player, + UpdatePlayers { + players: all_players.clone(), + }, + )); + } + } +} diff --git a/crates/border-wars/src/scenes/menu.rs b/crates/border-wars/src/scenes/menu.rs index c5c84c7..a730608 100644 --- a/crates/border-wars/src/scenes/menu.rs +++ b/crates/border-wars/src/scenes/menu.rs @@ -1,23 +1,30 @@ //! The main menu of the game. +use bevnet::{Connection, SendTo, Uuid}; use bevy::prelude::*; use bevy_egui::{egui, EguiContexts}; -use crate::CurrentScene; +use crate::connection::RequestConnection; +use crate::{CurrentScene, PlayerName}; + +type Name = String; /// The plugin for the menu. pub struct MenuPlugin; impl Plugin for MenuPlugin { fn build(&self, app: &mut App) { - app.add_systems(Update, menu_ui.run_if(in_state(CurrentScene::Menu))); + app.init_resource::() + .add_systems(Update, menu_ui.run_if(in_state(CurrentScene::Menu))); } } /// Display the UI of the menu to host a game or join one. fn menu_ui( mut ctx: EguiContexts, mut connection_string: Local, + mut name: ResMut, mut next_scene: ResMut>, + mut event: EventWriter>, ) { egui::CentralPanel::default().show(ctx.ctx_mut(), |ui| { ui.heading("Border Wars"); @@ -26,12 +33,22 @@ fn menu_ui( ui.label("Connect to an existing game:"); ui.horizontal(|ui| { + ui.label("name: "); + ui.text_edit_singleline(&mut name.0); + ui.separator(); + ui.label("Game ID: "); ui.text_edit_singleline(&mut *connection_string); if ui.button("Join").clicked() { - next_scene.set(CurrentScene::Game); - // TODO: connect to the game + next_scene.set(CurrentScene::JoinMenu); + + event.send(SendTo { + 0: Uuid::parse_str(&connection_string).unwrap(), + 1: RequestConnection { + name: (*name.0).to_string(), + }, + }) } }); @@ -39,7 +56,6 @@ fn menu_ui( if ui.button("Create new game").clicked() { next_scene.set(CurrentScene::Lobby); - // TODO: create a new game } }); } diff --git a/crates/border-wars/src/scenes/mod.rs b/crates/border-wars/src/scenes/mod.rs index da18601..7427dee 100644 --- a/crates/border-wars/src/scenes/mod.rs +++ b/crates/border-wars/src/scenes/mod.rs @@ -5,6 +5,7 @@ use bevy_egui::EguiPlugin; use crate::{responsive_scale, CurrentScene}; +pub mod join_menu; pub mod lobby; pub mod menu; @@ -17,6 +18,7 @@ impl Plugin for ScenesPlugin { .add_state::() .add_plugins(menu::MenuPlugin) .add_plugins(lobby::LobbyPlugin) + .add_plugins(join_menu::JoinMenuPlugin) .add_plugins(responsive_scale::ResponsiveScalingPlugin); } }