From b8bd27dd7fcbade514bc75433e7a0ed068be3f65 Mon Sep 17 00:00:00 2001 From: Jonni Liljamo Date: Mon, 15 May 2023 14:11:09 +0300 Subject: [PATCH] feat(client): finish new refresh, impl game lock --- client/src/game_status/mod.rs | 3 ++ client/src/macros/async_task.rs | 29 +++++++++++++++++ .../plugins/async_tasks/parse_game_status.rs | 7 ++-- .../async_tasks/req_game_action_create.rs | 9 +++--- .../plugins/async_tasks/req_game_details.rs | 1 - client/src/plugins/game/mod.rs | 32 ++++++++++++------- client/src/plugins/game/supply/mod.rs | 16 ++++++++-- client/src/plugins/game/ui/mod.rs | 30 ++++++++--------- client/src/plugins/game/ui/state_button.rs | 13 ++++++-- 9 files changed, 99 insertions(+), 41 deletions(-) diff --git a/client/src/game_status/mod.rs b/client/src/game_status/mod.rs index ed7edaa..27e6492 100644 --- a/client/src/game_status/mod.rs +++ b/client/src/game_status/mod.rs @@ -35,6 +35,7 @@ pub struct Card { } /// a supply pile holds an amount of some card +#[derive(Clone)] pub struct SupplyPile { /// the card type that the supply pile holds pub card: Card, @@ -52,6 +53,7 @@ pub enum PlayerState { BuyPhase, } +#[derive(Clone)] pub struct PlayerStatus { pub display_name: String, pub state: PlayerState, @@ -65,6 +67,7 @@ pub struct PlayerStatus { } /// constructed from a vector of [`Action`]s +#[derive(Clone)] pub struct GameStatus { /// a modifiable Actions Vector, will be modified when parsing actions, /// used for showing the log diff --git a/client/src/macros/async_task.rs b/client/src/macros/async_task.rs index 38b4678..3cbe443 100644 --- a/client/src/macros/async_task.rs +++ b/client/src/macros/async_task.rs @@ -147,3 +147,32 @@ macro_rules! async_task_handle_call { } }; } + +#[macro_export] +macro_rules! async_task_handle_call_refresh { + ($call_type:ty, |$response:ident, $game_data:ident, $parse_ev_w:ident| $handler_func:expr) => { + pub fn handle_call( + mut commands: Commands, + mut tasks: Query<(Entity, &mut $call_type)>, + mut $game_data: ResMut, + mut $parse_ev_w: EventWriter, + mut rg_ev_w: EventWriter, + ) { + match tasks.get_single_mut() { + Ok((entity, mut task)) => { + if let Some($response) = future::block_on(future::poll_once(&mut task.0)) { + $handler_func; + + rg_ev_w.send(RefreshGameEvent); + + // remove the task + commands.entity(entity).remove::<$call_type>(); + commands.entity(entity).despawn_recursive(); + } + } + // NOTE: don't do anything if the wanted thingy doesn't exist + _ => {} + } + } + }; +} diff --git a/client/src/plugins/async_tasks/parse_game_status.rs b/client/src/plugins/async_tasks/parse_game_status.rs index f807553..d8a7fa0 100644 --- a/client/src/plugins/async_tasks/parse_game_status.rs +++ b/client/src/plugins/async_tasks/parse_game_status.rs @@ -6,7 +6,7 @@ * See LICENSE for licensing information. */ -use crate::{api::game::Game, game_status::GameStatus, plugins::game::GameData}; +use crate::{api::game::Game, game_status::GameStatus, plugins::{game::GameData, FinishedRefreshGameEvent}}; use bevy::{ prelude::*, @@ -35,11 +35,14 @@ pub fn handle_call( mut commands: Commands, mut tasks: Query<(Entity, &mut ParseGameStatus)>, mut game_data: ResMut, + mut frg_ev_w: EventWriter, ) { if let Ok((entity, mut task)) = tasks.get_single_mut() { if let Some(response) = future::block_on(future::poll_once(&mut task.0)) { game_data.game_status = Some(response); - game_data.parsing_data = false; + game_data.locked = false; + + frg_ev_w.send(FinishedRefreshGameEvent); // remove the task commands.entity(entity).remove::(); diff --git a/client/src/plugins/async_tasks/req_game_action_create.rs b/client/src/plugins/async_tasks/req_game_action_create.rs index ed44c0d..4c1e2c3 100644 --- a/client/src/plugins/async_tasks/req_game_action_create.rs +++ b/client/src/plugins/async_tasks/req_game_action_create.rs @@ -11,8 +11,8 @@ use crate::{ self, game::{Action, CreateActionResponse}, }, - async_task_handle_call, async_task_start_call, - plugins::GameData, + async_task_handle_call_refresh, async_task_start_call, + plugins::{GameData, RefreshGameEvent}, NetworkingOptions, }; @@ -36,9 +36,8 @@ async_task_start_call!(GameActionCreateCallEvent, GameActionCreateCall, |ev, no| api::game::create_action(&no, &ev.action) }); -async_task_handle_call!( - GameActionCreateCall, - |_u0, _u1, response, _game_data, _u2| { +async_task_handle_call_refresh!( + GameActionCreateCall, |response, _game_data, _u2| { match response { Err(_err) => panic!("login failed, handle me"), Ok(resp) => { diff --git a/client/src/plugins/async_tasks/req_game_details.rs b/client/src/plugins/async_tasks/req_game_details.rs index 1ae5097..802e772 100644 --- a/client/src/plugins/async_tasks/req_game_details.rs +++ b/client/src/plugins/async_tasks/req_game_details.rs @@ -41,7 +41,6 @@ async_task_handle_call!( game_data.game = Some(resp); // start data parsing - game_data.parsing_data = true; parse_ev_w.send(ParseGameStatusEvent { game: game_data.game.as_ref().unwrap().clone(), }); diff --git a/client/src/plugins/game/mod.rs b/client/src/plugins/game/mod.rs index 83cb715..30d7e0e 100644 --- a/client/src/plugins/game/mod.rs +++ b/client/src/plugins/game/mod.rs @@ -11,7 +11,7 @@ use bevy_rapier3d::prelude::*; use crate::{api::game::Game, game_status::GameStatus, AppState, Global}; -use self::card::VisualCardBundle; +use self::supply::SpawnSupplyPilesEvent; use super::GameDetailsCallEvent; @@ -29,17 +29,20 @@ impl Plugin for GamePlugin { .add_plugin(card::CardPlugin) .add_plugin(supply::SupplyPlugin) .add_plugin(hand::HandPlugin) + .add_event::() + .add_event::() .add_system(game_setup.in_schedule(OnEnter(AppState::InGame))) - .add_system(handle_refresh_game_event.run_if(on_event::())); + .add_system(handle_refresh_game_event.run_if(on_event::())) + .add_system(handle_finished_refresh_game_event.run_if(on_event::())); } } -#[derive(Resource)] +#[derive(Resource, Clone)] pub struct GameData { pub game: Option, pub game_status: Option, - pub parsing_data: bool, + pub locked: bool, } impl Default for GameData { @@ -48,19 +51,16 @@ impl Default for GameData { game: None, game_status: None, - parsing_data: false, + locked: true, } } } fn game_setup( mut commands: Commands, - mut details_ev_w: EventWriter, - global: Res, + mut rg_ev_w: EventWriter, ) { - details_ev_w.send(GameDetailsCallEvent { - game_id: global.cur_game_id.clone(), - }); + rg_ev_w.send(RefreshGameEvent); // create the playing surface commands @@ -73,11 +73,21 @@ pub struct RefreshGameEvent; fn handle_refresh_game_event( mut details_ev_w: EventWriter, mut game_data: ResMut, + global: Res, ) { + game_data.locked = true; game_data.game = None; game_data.game_status = None; details_ev_w.send(GameDetailsCallEvent { - game_id: game_data.game.as_ref().unwrap().id.clone(), + game_id: global.cur_game_id.clone(), }); } + +pub struct FinishedRefreshGameEvent; + +fn handle_finished_refresh_game_event( + mut ssp_ev_w: EventWriter, +) { + ssp_ev_w.send(SpawnSupplyPilesEvent); +} diff --git a/client/src/plugins/game/supply/mod.rs b/client/src/plugins/game/supply/mod.rs index 0a47f95..c0d0ad8 100644 --- a/client/src/plugins/game/supply/mod.rs +++ b/client/src/plugins/game/supply/mod.rs @@ -23,8 +23,13 @@ impl Plugin for SupplyPlugin { fn build(&self, app: &mut App) { app.add_event::() .add_event::() - .add_system(spawn_supply_piles.run_if(on_event::())) - .add_system(position_supply_piles.run_if(on_event::())) + .add_systems( + ( + spawn_supply_piles.run_if(on_event::()), + apply_system_buffers, + position_supply_piles.run_if(on_event::()) + ).chain() + ) .add_system(handle_clicked_supply_pile); } } @@ -106,9 +111,13 @@ fn handle_clicked_supply_pile( mut commands: Commands, mut card_query: Query<(Entity, &VisualCard, &visual_card_kind::Supply), (With, With)>, mut gac_ev_w: EventWriter, - game_data: Res, + mut game_data: ResMut, global: Res, ) { + if game_data.locked { + return; + } + let Ok((entity, card, card_kind)) = card_query.get_single() else { return; }; @@ -130,6 +139,7 @@ fn handle_clicked_supply_pile( return; } + game_data.locked = true; gac_ev_w.send(GameActionCreateCallEvent { action: Action::new( &game_data.game.as_ref().unwrap().id, diff --git a/client/src/plugins/game/ui/mod.rs b/client/src/plugins/game/ui/mod.rs index 2d322b1..f70e708 100644 --- a/client/src/plugins/game/ui/mod.rs +++ b/client/src/plugins/game/ui/mod.rs @@ -16,7 +16,7 @@ use crate::{ AppState, Global, seed_gen, }; -use super::{supply::SpawnSupplyPilesEvent, GameData}; +use super::{supply::{SpawnSupplyPilesEvent, PositionSupplyPilesEvent}, GameData, RefreshGameEvent}; mod state_button; @@ -362,7 +362,7 @@ pub fn dev_details_ui( global: Res, game_data: Res, mut create_action_ev_w: EventWriter, - mut ssp_ev_w: EventWriter, + mut rg_ev_w: EventWriter, ) { egui::Window::new("Game Details").show(contexts.ctx_mut(), |ui| { let Some(game) = &game_data.game else { @@ -370,25 +370,23 @@ pub fn dev_details_ui( return; }; let Some(status) = &game_data.game_status else { - if game_data.parsing_data { - // early return if game_status is None, and we're parsing it - return; - } - // game_status is None, but we're not parsing it... - // should be unreachable, I think? + // early return if game_status is None return; }; - if status.actions.is_empty() && game.host_id == global.user.as_ref().unwrap().id { - if ui.button("Init Game").clicked() { - // NOTE/FIXME: hardcoded game init - hardcoded_init(game, &mut create_action_ev_w); + ui.add_enabled_ui(!game_data.locked, |ui| { + if status.actions.is_empty() && game.host_id == global.user.as_ref().unwrap().id { + if ui.button("Init Game").clicked() { + // NOTE/FIXME: hardcoded game init + hardcoded_init(game, &mut create_action_ev_w); + rg_ev_w.send(RefreshGameEvent); + } } - } - if ui.button("spawn things").clicked() { - ssp_ev_w.send(SpawnSupplyPilesEvent); - } + if ui.button("Force Refresh").clicked() { + rg_ev_w.send(RefreshGameEvent); + } + }); ui.separator(); diff --git a/client/src/plugins/game/ui/state_button.rs b/client/src/plugins/game/ui/state_button.rs index 99172a1..8dd4c60 100644 --- a/client/src/plugins/game/ui/state_button.rs +++ b/client/src/plugins/game/ui/state_button.rs @@ -84,15 +84,16 @@ fn update_state_button( (Changed, With) >, mut text_query: Query<&mut Text>, - game_data: Res, + mut game_data: ResMut, global: Res, mut gac_ev_w: EventWriter, ) { for (interaction, mut color, mut visibility, children) in &mut interaction_query { - let Some(game) = &game_data.game else { + // NOTE: horrible clones because of borrow funnies + let Some(game) = game_data.clone().game else { return; }; - let Some(status) = &game_data.game_status else { + let Some(status) = game_data.clone().game_status else { return; }; let Some(user) = &global.user else { @@ -116,10 +117,16 @@ fn update_state_button( } *visibility = Visibility::Inherited; + if game_data.locked { + // input locked rn, so don't show any signs of interactivity + return; + } + match interaction { Interaction::Clicked => { *color = PRESSED_BUTTON.into(); + game_data.locked = true; match player.state { PlayerState::PlayPhase => { gac_ev_w.send(GameActionCreateCallEvent { -- 2.44.1