Skip to content

Commit

Permalink
Impl game joined menu screen (#688)
Browse files Browse the repository at this point in the history
  • Loading branch information
Indy2222 authored Aug 16, 2023
1 parent 16469bf commit 757173c
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 22 deletions.
4 changes: 2 additions & 2 deletions crates/lobby_model/src/games.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl Game {
}
}

#[derive(Serialize, Deserialize)]
#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GamePlayer {
username: String,
Expand All @@ -57,7 +57,7 @@ impl GamePlayer {
}
}

#[derive(Serialize, Deserialize)]
#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GamePlayerInfo {
ordinal: u8,
Expand Down
19 changes: 0 additions & 19 deletions crates/menu/src/multiplayer/joined.rs

This file was deleted.

14 changes: 14 additions & 0 deletions crates/menu/src/multiplayer/joined/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use bevy::prelude::*;

use self::{state::JoinedGameStatePlugin, ui::JoinedGameUiPlugin};

mod state;
mod ui;

pub(super) struct JoinedGamePlugin;

impl Plugin for JoinedGamePlugin {
fn build(&self, app: &mut App) {
app.add_plugins((JoinedGameStatePlugin, JoinedGameUiPlugin));
}
}
60 changes: 60 additions & 0 deletions crates/menu/src/multiplayer/joined/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use bevy::prelude::*;
use de_core::state::AppState;
use de_gui::ToastEvent;
use de_lobby_client::GetGameRequest;
use de_multiplayer::{PeerJoinedEvent, PeerLeftEvent, ShutdownMultiplayerEvent};

use super::ui::RefreshPlayersEvent;
use crate::multiplayer::{
current::GameNameRes,
requests::{Receiver, Sender},
MultiplayerState,
};

pub(super) struct JoinedGameStatePlugin;

impl Plugin for JoinedGameStatePlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(MultiplayerState::GameJoined), refresh)
.add_systems(OnExit(MultiplayerState::GameJoined), cleanup)
.add_systems(
Update,
(
refresh
.run_if(on_event::<PeerJoinedEvent>().or_else(on_event::<PeerLeftEvent>())),
handle_get_response,
)
.run_if(in_state(MultiplayerState::GameJoined)),
);
}
}

fn cleanup(state: Res<State<AppState>>, mut shutdown: EventWriter<ShutdownMultiplayerEvent>) {
if state.as_ref() != &AppState::InGame {
shutdown.send(ShutdownMultiplayerEvent);
}
}

fn refresh(game_name: Res<GameNameRes>, mut sender: Sender<GetGameRequest>) {
info!("Refreshing game info...");
sender.send(GetGameRequest::new(game_name.name_owned()));
}

fn handle_get_response(
mut multi_state: ResMut<NextState<MultiplayerState>>,
mut receiver: Receiver<GetGameRequest>,
mut refresh: EventWriter<RefreshPlayersEvent>,
mut toasts: EventWriter<ToastEvent>,
) {
while let Some(result) = receiver.receive() {
match result {
Ok(game) => {
refresh.send(RefreshPlayersEvent::from_slice(game.players()));
}
Err(error) => {
toasts.send(ToastEvent::new(error));
multi_state.set(MultiplayerState::SignIn);
}
}
}
}
121 changes: 121 additions & 0 deletions crates/menu/src/multiplayer/joined/ui.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use bevy::prelude::*;
use de_gui::{GuiCommands, LabelCommands, OuterStyle};
use de_lobby_model::GamePlayer;

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

pub(super) struct JoinedGameUiPlugin;

impl Plugin for JoinedGameUiPlugin {
fn build(&self, app: &mut App) {
app.add_event::<RefreshPlayersEvent>()
.add_systems(OnEnter(MultiplayerState::GameJoined), setup)
.add_systems(OnExit(MultiplayerState::GameJoined), cleanup)
.add_systems(
PostUpdate,
refresh
.run_if(in_state(MultiplayerState::GameJoined))
.run_if(on_event::<RefreshPlayersEvent>()),
);
}
}

#[derive(Event)]
pub(super) struct RefreshPlayersEvent(Vec<GamePlayer>);

impl RefreshPlayersEvent {
pub(super) fn from_slice(players: &[GamePlayer]) -> Self {
Self(players.to_vec())
}
}

#[derive(Resource)]
struct PlayersBoxRes(Entity);

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

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

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.),
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(column_id);
column_id
}

fn refresh(
mut commands: GuiCommands,
mut events: EventReader<RefreshPlayersEvent>,
box_id: Res<PlayersBoxRes>,
) {
let Some(event) = events.iter().last() else {
return;
};

commands.entity(box_id.0).despawn_descendants();

for player in event.0.iter() {
let row_id = row(&mut commands, player);
commands.entity(box_id.0).add_child(row_id);
}
}

fn row(commands: &mut GuiCommands, player: &GamePlayer) -> Entity {
let row_id = commands
.spawn(NodeBundle {
style: Style {
flex_direction: FlexDirection::Row,
width: Val::Percent(100.),
height: Val::Percent(8.),
margin: UiRect::vertical(Val::Percent(0.5)),
align_items: AlignItems::Center,
justify_content: JustifyContent::FlexStart,
..default()
},
..default()
})
.id();

let ordinal_id = commands
.spawn_label(
OuterStyle {
width: Val::Percent(25.),
height: Val::Percent(100.),
margin: UiRect::right(Val::Percent(5.)),
},
format!("P{}", player.info().ordinal()),
)
.id();
commands.entity(row_id).add_child(ordinal_id);

let username_id = commands
.spawn_label(
OuterStyle {
width: Val::Percent(70.),
height: Val::Percent(100.),
..default()
},
player.username(),
)
.id();
commands.entity(row_id).add_child(username_id);

row_id
}
24 changes: 24 additions & 0 deletions crates/multiplayer/src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ impl Plugin for GamePlugin {
fn build(&self, app: &mut App) {
app.add_event::<GameOpenedEvent>()
.add_event::<GameJoinedEvent>()
.add_event::<PeerJoinedEvent>()
.add_event::<PeerLeftEvent>()
.add_systems(OnEnter(NetState::Connected), open_or_join)
.add_systems(
PreMovement,
Expand Down Expand Up @@ -56,6 +58,24 @@ impl GameJoinedEvent {
}
}

#[derive(Event)]
pub struct PeerJoinedEvent(u8);

impl PeerJoinedEvent {
pub fn id(&self) -> u8 {
self.0
}
}

#[derive(Event)]
pub struct PeerLeftEvent(u8);

impl PeerLeftEvent {
pub fn id(&self) -> u8 {
self.0
}
}

fn open_or_join(
conf: Res<NetGameConfRes>,
mut main_server: EventWriter<ToMainServerEvent>,
Expand Down Expand Up @@ -118,6 +138,8 @@ fn process_from_game(
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 next_state: ResMut<NextState<NetState>>,
) {
for event in inputs.iter() {
Expand Down Expand Up @@ -169,9 +191,11 @@ fn process_from_game(
}
FromGame::PeerJoined(id) => {
info!("Peer {id} joined.");
peer_joined_events.send(PeerJoinedEvent(*id));
}
FromGame::PeerLeft(id) => {
info!("Peer {id} left.");
peer_left_events.send(PeerLeftEvent(*id));
}
FromGame::GameReadiness(readiness) => {
info!("Game readiness changed to: {readiness:?}");
Expand Down
2 changes: 1 addition & 1 deletion crates/multiplayer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use stats::StatsPlugin;

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

0 comments on commit 757173c

Please sign in to comment.