Skip to content

Commit

Permalink
Add "Ready" button to game joine screen (#690)
Browse files Browse the repository at this point in the history
  • Loading branch information
Indy2222 authored Aug 17, 2023
1 parent 757173c commit 25dd74f
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 5 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/menu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ de_gui.workspace = true
de_lobby_client.workspace = true
de_lobby_model.workspace = true
de_map.workspace = true
de_messages.workspace = true
de_multiplayer.workspace = true

# Other
Expand Down
68 changes: 65 additions & 3 deletions crates/menu/src/multiplayer/joined/ui.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use bevy::prelude::*;
use de_gui::{GuiCommands, LabelCommands, OuterStyle};
use de_gui::{ButtonCommands, GuiCommands, LabelCommands, OuterStyle};
use de_lobby_model::GamePlayer;
use de_messages::Readiness;
use de_multiplayer::SetReadinessEvent;

use crate::{menu::Menu, multiplayer::MultiplayerState};

Expand All @@ -11,6 +13,10 @@ impl Plugin for JoinedGameUiPlugin {
app.add_event::<RefreshPlayersEvent>()
.add_systems(OnEnter(MultiplayerState::GameJoined), setup)
.add_systems(OnExit(MultiplayerState::GameJoined), cleanup)
.add_systems(
Update,
button_system.run_if(in_state(MultiplayerState::GameJoined)),
)
.add_systems(
PostUpdate,
refresh
Expand All @@ -32,21 +38,47 @@ impl RefreshPlayersEvent {
#[derive(Resource)]
struct PlayersBoxRes(Entity);

#[derive(Clone, Copy, Component)]
enum ButtonAction {
Ready,
}

fn setup(mut commands: GuiCommands, menu: Res<Menu>) {
let players_box_id = players_box(&mut commands, menu.root_node());
let mid_panel_id = mid_panel(&mut commands, menu.root_node());
let players_box_id = players_box(&mut commands, mid_panel_id);
commands.insert_resource(PlayersBoxRes(players_box_id));
ready_button(&mut commands, mid_panel_id);
}

fn cleanup(mut commands: Commands) {
commands.remove_resource::<PlayersBoxRes>();
}

fn mid_panel(commands: &mut GuiCommands, parent_id: Entity) -> Entity {
let panel_id = commands
.spawn(NodeBundle {
style: Style {
flex_direction: FlexDirection::Column,
width: Val::Percent(80.),
height: Val::Percent(80.),
margin: UiRect::all(Val::Auto),
align_items: AlignItems::Center,
justify_content: JustifyContent::FlexStart,
..default()
},
..default()
})
.id();
commands.entity(parent_id).add_child(panel_id);
panel_id
}

fn players_box(commands: &mut GuiCommands, parent_id: Entity) -> Entity {
let column_id = commands
.spawn(NodeBundle {
style: Style {
flex_direction: FlexDirection::Column,
width: Val::Percent(80.),
width: Val::Percent(100.),
height: Val::Percent(80.),
margin: UiRect::all(Val::Auto),
align_items: AlignItems::Center,
Expand Down Expand Up @@ -119,3 +151,33 @@ fn row(commands: &mut GuiCommands, player: &GamePlayer) -> Entity {

row_id
}

fn ready_button(commands: &mut GuiCommands, parent: Entity) {
let button_id = commands
.spawn_button(
OuterStyle {
width: Val::Percent(100.),
height: Val::Percent(8.),
margin: UiRect::top(Val::Percent(12.)),
},
"Ready",
)
.insert(ButtonAction::Ready)
.id();
commands.entity(parent).add_child(button_id);
}

fn button_system(
interactions: Query<(&Interaction, &ButtonAction), Changed<Interaction>>,
mut events: EventWriter<SetReadinessEvent>,
) {
for (&interaction, &action) in interactions.iter() {
if let Interaction::Pressed = interaction {
match action {
ButtonAction::Ready => {
events.send(SetReadinessEvent::from(Readiness::Ready));
}
}
}
}
}
39 changes: 38 additions & 1 deletion crates/multiplayer/src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::net::SocketAddr;

use bevy::prelude::*;
use de_core::{player::Player, schedule::PreMovement};
use de_messages::{FromGame, FromServer, GameOpenError, JoinError, ToGame, ToServer};
use de_messages::{FromGame, FromServer, GameOpenError, JoinError, Readiness, ToGame, ToServer};

use crate::{
config::ConnectionType,
Expand All @@ -22,6 +22,8 @@ impl Plugin for GamePlugin {
.add_event::<GameJoinedEvent>()
.add_event::<PeerJoinedEvent>()
.add_event::<PeerLeftEvent>()
.add_event::<GameReadinessEvent>()
.add_event::<SetReadinessEvent>()
.add_systems(OnEnter(NetState::Connected), open_or_join)
.add_systems(
PreMovement,
Expand All @@ -34,6 +36,13 @@ impl Plugin for GamePlugin {
.after(MessagesSet::RecvMessages),
),
)
.add_systems(
PostUpdate,
set_readiness
.run_if(in_state(NetState::Joined))
.run_if(on_event::<SetReadinessEvent>())
.before(MessagesSet::SendMessages),
)
.add_systems(OnEnter(NetState::ShuttingDown), leave);
}
}
Expand Down Expand Up @@ -76,6 +85,20 @@ impl PeerLeftEvent {
}
}

/// This event is sent when game readiness stage of the joined game changes.
#[derive(Event, Deref)]
pub struct GameReadinessEvent(Readiness);

/// Send this event to change player readiness stage.
#[derive(Event)]
pub struct SetReadinessEvent(Readiness);

impl From<Readiness> for SetReadinessEvent {
fn from(readiness: Readiness) -> Self {
Self(readiness)
}
}

fn open_or_join(
conf: Res<NetGameConfRes>,
mut main_server: EventWriter<ToMainServerEvent>,
Expand Down Expand Up @@ -133,13 +156,15 @@ fn process_from_server(
}
}

#[allow(clippy::too_many_arguments)]
fn process_from_game(
mut inputs: EventReader<FromGameServerEvent>,
mut fatals: EventWriter<FatalErrorEvent>,
state: Res<State<NetState>>,
mut joined_events: EventWriter<GameJoinedEvent>,
mut peer_joined_events: EventWriter<PeerJoinedEvent>,
mut peer_left_events: EventWriter<PeerLeftEvent>,
mut readiness_events: EventWriter<GameReadinessEvent>,
mut next_state: ResMut<NextState<NetState>>,
) {
for event in inputs.iter() {
Expand Down Expand Up @@ -199,11 +224,23 @@ fn process_from_game(
}
FromGame::GameReadiness(readiness) => {
info!("Game readiness changed to: {readiness:?}");
readiness_events.send(GameReadinessEvent(*readiness));
}
}
}
}

fn set_readiness(
mut readiness_events: EventReader<SetReadinessEvent>,
mut message_events: EventWriter<ToGameServerEvent<true>>,
) {
let Some(readiness) = readiness_events.iter().last() else {
return;
};

message_events.send(ToGameServerEvent::from(ToGame::Readiness(readiness.0)));
}

fn leave(mut server: EventWriter<ToGameServerEvent<true>>) {
info!("Sending leave game message.");
// Send this even if not yet joined because the join / open-game request
Expand Down
5 changes: 4 additions & 1 deletion crates/multiplayer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ use stats::StatsPlugin;

pub use crate::{
config::{ConnectionType, NetGameConf},
game::{GameJoinedEvent, GameOpenedEvent, PeerJoinedEvent, PeerLeftEvent},
game::{
GameJoinedEvent, GameOpenedEvent, GameReadinessEvent, PeerJoinedEvent, PeerLeftEvent,
SetReadinessEvent,
},
lifecycle::{MultiplayerShuttingDownEvent, ShutdownMultiplayerEvent, StartMultiplayerEvent},
netstate::NetState,
};
Expand Down

0 comments on commit 25dd74f

Please sign in to comment.