From 151f7a3489f7c1701b7c4c7e353f68416095c3f3 Mon Sep 17 00:00:00 2001 From: Tao Tien <29749622+taotien@users.noreply.github.com> Date: Sat, 28 Feb 2026 18:41:42 -0800 Subject: [PATCH] view_hand insert handling --- jong-line/src/reducers.rs | 12 +++++----- jong/src/riichi.rs | 49 +++++++++++++++++++-------------------- jong/src/tui.rs | 6 ++--- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/jong-line/src/reducers.rs b/jong-line/src/reducers.rs index 3b07aa3..3bdb745 100644 --- a/jong-line/src/reducers.rs +++ b/jong-line/src/reducers.rs @@ -25,7 +25,7 @@ pub fn advance_game_private(ctx: &ReducerContext, mut game_timer: GameTimer) -> // TODO this, or allow player/debug to call this? if let Some(mut lobby) = ctx.db.lobby().id().find(game_timer.lobby_id) { - trace!("running schedule for lobby {}", lobby.id); + // trace!("running schedule for lobby {}", lobby.id); match lobby.game_state { GameState::Setup => { // TODO reduce interval beforehand so we don't wait a second? @@ -50,7 +50,7 @@ pub fn advance_game_private(ctx: &ReducerContext, mut game_timer: GameTimer) -> GameState::Deal => { // TODO reduce interval beforehand so this can animate? // TODO change loop to be per interval somehow? - trace!("deal hands"); + // trace!("deal hands"); let mut wall = ctx.db.wall().lobby_id().find(lobby.id).unwrap(); for pob in &lobby.players { let mut tiles = wall.tiles.split_off(wall.tiles.len() - 13); @@ -83,14 +83,14 @@ pub fn advance_game_private(ctx: &ReducerContext, mut game_timer: GameTimer) -> } } lobby.game_state = jong_types::states::GameState::Play; - trace!("dealt hands"); + // trace!("dealt hands"); } GameState::Play => { - trace!("in play"); + // trace!("in play"); let curr_player = lobby.players.get(lobby.current_idx as usize).unwrap(); match curr_player { PlayerOrBot::Player { id: player_id } => { - trace!("current player is {player_id}"); + // trace!("current player is {player_id}"); let mut clock = ctx.db.player_clock().player_id().find(player_id).unwrap(); let mut hand = ctx.db.player_hand().player_id().find(player_id).unwrap(); match hand.turn_state { @@ -109,7 +109,7 @@ pub fn advance_game_private(ctx: &ReducerContext, mut game_timer: GameTimer) -> } } TurnState::Tsumo => { - trace!("wait for discard"); + // trace!("wait for discard"); if clock.tick() { ctx.db.player_clock().id().update(clock); } else { diff --git a/jong/src/riichi.rs b/jong/src/riichi.rs index 7b2b902..1b3f4ba 100644 --- a/jong/src/riichi.rs +++ b/jong/src/riichi.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; use bevy_spacetimedb::{ - ReadInsertUpdateMessage, ReadStdbConnectedMessage, ReadStdbDisconnectedMessage, - ReadUpdateMessage, StdbPlugin, + ReadInsertMessage, ReadInsertUpdateMessage, ReadStdbConnectedMessage, + ReadStdbDisconnectedMessage, ReadUpdateMessage, StdbPlugin, }; use jong_db::{self, GameTimerTableAccess, add_bot, set_ready}; @@ -15,7 +15,6 @@ use spacetimedb_sdk::Table; pub mod player; use crate::riichi::player::*; use crate::{SpacetimeDB, creds_store}; -// pub mod round; pub struct Riichi; impl Plugin for Riichi { @@ -44,12 +43,12 @@ impl Plugin for Riichi { .init_state::() .add_sub_state::() .add_systems(Startup, subscriptions) - .add_observer(on_subscribed) + .add_observer(on_subscribed) // TODO fire once then get removed? or keep around for reconnect logic? .add_systems(Update, (on_connect, on_disconnect)) .add_systems(Update, (on_lobby_insert_update, on_player_insert_update)) .add_systems( Update, - (on_view_hand_update) + (on_view_hand_insert, on_view_hand_update) .run_if(in_state(GameState::Play).or(in_state(GameState::Deal))), ); } @@ -234,7 +233,6 @@ fn on_player_insert_update( debug!("on_player_insert_update: {:?}", msg.new); assert_eq!(msg.new.identity, stdb.identity()); if main_player.is_none() && msg.new.identity == stdb.identity() { - // trace!("spawn_main_player"); spawn_main_player(&stdb, &mut commands, &mut next_turnstate, &msg.new); } else if other_players.iter().any(|p| { if let PlayerOrBot::Player { id } = &p.id { @@ -300,6 +298,23 @@ fn on_lobby_insert_update( } } +fn on_view_hand_insert( + mut messages: ReadInsertMessage, + + mut commands: Commands, + main_player: Single<(Entity, Option<&Children>), With>, + + mut next_turnstate: ResMut>, +) { + for msg in messages.read() { + trace!("insert hand: {:?}", msg.row); + + if main_player.1.is_none() { + spawn_main_hand(&mut commands, &mut next_turnstate, main_player.0, &msg.row); + } + } +} + fn on_view_hand_update( stdb: SpacetimeDB, mut messages: ReadUpdateMessage, @@ -307,7 +322,7 @@ fn on_view_hand_update( mut commands: Commands, tiles: Query<(Entity, &TileId)>, - main_player: Single<(Entity, Option<&Children>), With>, + main_player: Single<(Entity, &Children), With>, hand: Query>, pond: Query>, @@ -316,14 +331,6 @@ fn on_view_hand_update( ) { // TODO can this and similar run at startup or on play/reconnect? for msg in messages.read() { - // trace!("new hand: {:?}", msg.new); - - if main_player.1.is_none() { - // trace!("spawn_main_hand, {:?}", *main_player); - spawn_main_hand(&mut commands, &mut next_turnstate, main_player.0, &msg.new); - continue; - } - let hand_tiles: Vec<_> = msg .new .hand @@ -348,18 +355,10 @@ fn on_view_hand_update( .collect(); commands - .entity( - hand.iter() - .find(|e| main_player.1.is_some_and(|mp| mp.contains(e))) - .unwrap(), - ) + .entity(hand.iter().find(|e| main_player.1.contains(e)).unwrap()) .replace_children(&hand_tiles); commands - .entity( - pond.iter() - .find(|e| main_player.1.is_some_and(|mp| mp.contains(e))) - .unwrap(), - ) + .entity(pond.iter().find(|e| main_player.1.contains(e)).unwrap()) .replace_children(&pond_tiles); match msg.new.turn_state { diff --git a/jong/src/tui.rs b/jong/src/tui.rs index ce195ee..da949c7 100644 --- a/jong/src/tui.rs +++ b/jong/src/tui.rs @@ -82,17 +82,17 @@ impl Plugin for TuiPlugin { (input::keyboard, input::mouse).in_set(TuiSet::Input), ) .add_systems(Update, layout::layout.in_set(TuiSet::Layout)) - .add_systems(Update, discard_tile.run_if(in_state(TurnState::Tsumo))) .add_systems( Update, ( (render::render_main_hand, render::render_main_pond) - .run_if(in_state(GameState::Play)), + .run_if(in_state(GameState::Play).or(in_state(GameState::Deal))), render::render, ) .chain() .in_set(TuiSet::Render), - ); + ) + .add_systems(Update, discard_tile.run_if(in_state(TurnState::Tsumo))); } }