generated from tipragot/rust
Start game from the lobby by the admin #86
|
@ -26,7 +26,7 @@ pub enum CurrentScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A player in the game.
|
/// A player in the game.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Component, Resource)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Component, Resource, PartialEq, Eq, Hash)]
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
/// The name of the player.
|
/// The name of the player.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
118
crates/border-wars/src/networking/check_connection.rs
Normal file
118
crates/border-wars/src/networking/check_connection.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
//! All the code related to the check connection (check every X seconds if any
|
||||||
|
//! player is still connected).
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use bevnet::{Connection, NetworkAppExt, Receive, SendTo};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::utils::HashMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::Player;
|
||||||
|
|
||||||
|
/// A plugin that check if a player is still connected.
|
||||||
|
pub struct CheckConnectionPlugin;
|
||||||
|
|
||||||
|
/// An event that is trigger when a player is disconnected.
|
||||||
|
#[derive(Event)]
|
||||||
|
pub struct PlayerDisconnected(pub Player);
|
||||||
|
|
||||||
|
/// An event that is send between all players to check if a player is still
|
||||||
|
/// connected.
|
||||||
|
#[derive(Event, Serialize, Deserialize)]
|
||||||
|
struct IAmConnected(Player);
|
||||||
|
|
||||||
|
impl Plugin for CheckConnectionPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_systems(
|
||||||
|
Update,
|
||||||
|
(
|
||||||
|
check_connection,
|
||||||
|
send_check_connection,
|
||||||
|
handle_disconnect_player,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.add_event::<PlayerDisconnected>()
|
||||||
|
.add_network_event::<IAmConnected>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The interval to check if a player is still connected.
|
||||||
|
/// We put this into a const because we don't want to change it.
|
||||||
|
const CHECK_CONNECTION_INTERVAL: std::time::Duration = std::time::Duration::from_secs(5);
|
||||||
|
|
||||||
|
/// A fonction that check if a player is still connected.
|
||||||
|
fn check_connection(
|
||||||
|
all_players_query: Query<&Player>,
|
||||||
|
mut disconnect_event: EventWriter<PlayerDisconnected>,
|
||||||
|
mut checked_players: Local<HashMap<Player, Instant>>,
|
||||||
|
mut connect_event: EventReader<Receive<IAmConnected>>,
|
||||||
|
) {
|
||||||
|
for Receive(_, IAmConnected(player)) in connect_event.read() {
|
||||||
|
checked_players.insert(player.clone(), Instant::now());
|
||||||
|
}
|
||||||
|
for player in all_players_query.iter() {
|
||||||
|
if !(*checked_players).contains_key(player) {
|
||||||
|
checked_players.insert(player.clone(), Instant::now());
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(last_seen) = (*checked_players).get_mut(player) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if last_seen.elapsed() > CHECK_CONNECTION_INTERVAL {
|
||||||
|
disconnect_event.send(PlayerDisconnected(player.clone()));
|
||||||
|
checked_players.remove(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A simple time/instant that implement Default.
|
||||||
|
struct Time(std::time::Instant);
|
||||||
|
|
||||||
|
impl Default for Time {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(std::time::Instant::now())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A fonction that send a check connection event to all players.
|
||||||
|
fn send_check_connection(
|
||||||
|
mut check_connection_event: EventWriter<SendTo<IAmConnected>>,
|
||||||
|
all_players_query: Query<&Player>,
|
||||||
|
connection: Res<Connection>,
|
||||||
|
mut timer: Local<Time>,
|
||||||
|
) {
|
||||||
|
if timer.0.elapsed() < CHECK_CONNECTION_INTERVAL / 2 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Some(self_player) = all_players_query
|
||||||
|
.iter()
|
||||||
|
.find(|player| connection.identifier() == Some(player.uuid))
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
for player in all_players_query.iter() {
|
||||||
|
check_connection_event.send(SendTo(player.uuid, IAmConnected(self_player.clone())));
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.0 = std::time::Instant::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A fonction that handle player disconnection.
|
||||||
|
fn handle_disconnect_player(
|
||||||
|
mut disconnect_players: EventReader<PlayerDisconnected>,
|
||||||
|
all_players_query: Query<(&Player, Entity)>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
for PlayerDisconnected(disconnect_player) in disconnect_players.read() {
|
||||||
|
let Some((_, entity)) = all_players_query
|
||||||
|
.iter()
|
||||||
|
.find(|(player, _entity)| *player == disconnect_player)
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.entity(entity).despawn();
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,10 +4,12 @@ use bevnet::{NetworkAppExt, NetworkPlugin, Receive};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use self::check_connection::CheckConnectionPlugin;
|
||||||
use self::connection::ConnectionPlugin;
|
use self::connection::ConnectionPlugin;
|
||||||
use crate::map::generation::StartMapGeneration;
|
use crate::map::generation::StartMapGeneration;
|
||||||
use crate::CurrentScene;
|
use crate::CurrentScene;
|
||||||
|
|
||||||
|
pub mod check_connection;
|
||||||
pub mod connection;
|
pub mod connection;
|
||||||
|
|
||||||
/// The plugin for the networking.
|
/// The plugin for the networking.
|
||||||
|
@ -18,12 +20,13 @@ impl Plugin for NetworkingPlugin {
|
||||||
app.add_plugins(NetworkPlugin::new("relay.cocosol.fr".to_string()))
|
app.add_plugins(NetworkPlugin::new("relay.cocosol.fr".to_string()))
|
||||||
.add_plugins(ConnectionPlugin)
|
.add_plugins(ConnectionPlugin)
|
||||||
.add_systems(Update, start_game)
|
.add_systems(Update, start_game)
|
||||||
.add_network_event::<StartGame>();
|
.add_network_event::<StartGame>()
|
||||||
|
.add_plugins(CheckConnectionPlugin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The rank of the player.
|
/// The rank of the player.
|
||||||
#[derive(PartialEq, Eq, Serialize, Deserialize, Clone, Copy, Debug)]
|
#[derive(PartialEq, Eq, Serialize, Deserialize, Clone, Copy, Debug, Hash)]
|
||||||
pub enum PlayerRank {
|
pub enum PlayerRank {
|
||||||
/// A spectator. He does not play the game, just renderer the game.
|
/// A spectator. He does not play the game, just renderer the game.
|
||||||
Spectator,
|
Spectator,
|
||||||
|
|
|
@ -46,7 +46,6 @@ fn lobby_ui(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ui.label("Game ID: ");
|
ui.label("Game ID: ");
|
||||||
// TODO : get the game ID and display it.
|
|
||||||
ui.text_edit_singleline(&mut connection.identifier().unwrap_or_default().to_string());
|
ui.text_edit_singleline(&mut connection.identifier().unwrap_or_default().to_string());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue