view_hand insert handling

This commit is contained in:
Tao Tien 2026-02-28 18:41:42 -08:00
parent edd389c787
commit 151f7a3489
3 changed files with 33 additions and 34 deletions

View file

@ -25,7 +25,7 @@ pub fn advance_game_private(ctx: &ReducerContext, mut game_timer: GameTimer) ->
// TODO this, or allow player/debug to call this? // TODO this, or allow player/debug to call this?
if let Some(mut lobby) = ctx.db.lobby().id().find(game_timer.lobby_id) { 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 { match lobby.game_state {
GameState::Setup => { GameState::Setup => {
// TODO reduce interval beforehand so we don't wait a second? // 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 => { GameState::Deal => {
// TODO reduce interval beforehand so this can animate? // TODO reduce interval beforehand so this can animate?
// TODO change loop to be per interval somehow? // 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(); let mut wall = ctx.db.wall().lobby_id().find(lobby.id).unwrap();
for pob in &lobby.players { for pob in &lobby.players {
let mut tiles = wall.tiles.split_off(wall.tiles.len() - 13); 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; lobby.game_state = jong_types::states::GameState::Play;
trace!("dealt hands"); // trace!("dealt hands");
} }
GameState::Play => { GameState::Play => {
trace!("in play"); // trace!("in play");
let curr_player = lobby.players.get(lobby.current_idx as usize).unwrap(); let curr_player = lobby.players.get(lobby.current_idx as usize).unwrap();
match curr_player { match curr_player {
PlayerOrBot::Player { id: player_id } => { 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 clock = ctx.db.player_clock().player_id().find(player_id).unwrap();
let mut hand = ctx.db.player_hand().player_id().find(player_id).unwrap(); let mut hand = ctx.db.player_hand().player_id().find(player_id).unwrap();
match hand.turn_state { match hand.turn_state {
@ -109,7 +109,7 @@ pub fn advance_game_private(ctx: &ReducerContext, mut game_timer: GameTimer) ->
} }
} }
TurnState::Tsumo => { TurnState::Tsumo => {
trace!("wait for discard"); // trace!("wait for discard");
if clock.tick() { if clock.tick() {
ctx.db.player_clock().id().update(clock); ctx.db.player_clock().id().update(clock);
} else { } else {

View file

@ -1,7 +1,7 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_spacetimedb::{ use bevy_spacetimedb::{
ReadInsertUpdateMessage, ReadStdbConnectedMessage, ReadStdbDisconnectedMessage, ReadInsertMessage, ReadInsertUpdateMessage, ReadStdbConnectedMessage,
ReadUpdateMessage, StdbPlugin, ReadStdbDisconnectedMessage, ReadUpdateMessage, StdbPlugin,
}; };
use jong_db::{self, GameTimerTableAccess, add_bot, set_ready}; use jong_db::{self, GameTimerTableAccess, add_bot, set_ready};
@ -15,7 +15,6 @@ use spacetimedb_sdk::Table;
pub mod player; pub mod player;
use crate::riichi::player::*; use crate::riichi::player::*;
use crate::{SpacetimeDB, creds_store}; use crate::{SpacetimeDB, creds_store};
// pub mod round;
pub struct Riichi; pub struct Riichi;
impl Plugin for Riichi { impl Plugin for Riichi {
@ -44,12 +43,12 @@ impl Plugin for Riichi {
.init_state::<jong_types::states::GameState>() .init_state::<jong_types::states::GameState>()
.add_sub_state::<jong_types::states::TurnState>() .add_sub_state::<jong_types::states::TurnState>()
.add_systems(Startup, subscriptions) .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_connect, on_disconnect))
.add_systems(Update, (on_lobby_insert_update, on_player_insert_update)) .add_systems(Update, (on_lobby_insert_update, on_player_insert_update))
.add_systems( .add_systems(
Update, Update,
(on_view_hand_update) (on_view_hand_insert, on_view_hand_update)
.run_if(in_state(GameState::Play).or(in_state(GameState::Deal))), .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); debug!("on_player_insert_update: {:?}", msg.new);
assert_eq!(msg.new.identity, stdb.identity()); assert_eq!(msg.new.identity, stdb.identity());
if main_player.is_none() && 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); spawn_main_player(&stdb, &mut commands, &mut next_turnstate, &msg.new);
} else if other_players.iter().any(|p| { } else if other_players.iter().any(|p| {
if let PlayerOrBot::Player { id } = &p.id { if let PlayerOrBot::Player { id } = &p.id {
@ -300,6 +298,23 @@ fn on_lobby_insert_update(
} }
} }
fn on_view_hand_insert(
mut messages: ReadInsertMessage<jong_db::PlayerHand>,
mut commands: Commands,
main_player: Single<(Entity, Option<&Children>), With<MainPlayer>>,
mut next_turnstate: ResMut<NextState<jong_types::states::TurnState>>,
) {
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( fn on_view_hand_update(
stdb: SpacetimeDB, stdb: SpacetimeDB,
mut messages: ReadUpdateMessage<jong_db::PlayerHand>, mut messages: ReadUpdateMessage<jong_db::PlayerHand>,
@ -307,7 +322,7 @@ fn on_view_hand_update(
mut commands: Commands, mut commands: Commands,
tiles: Query<(Entity, &TileId)>, tiles: Query<(Entity, &TileId)>,
main_player: Single<(Entity, Option<&Children>), With<MainPlayer>>, main_player: Single<(Entity, &Children), With<MainPlayer>>,
hand: Query<Entity, With<Hand>>, hand: Query<Entity, With<Hand>>,
pond: Query<Entity, With<Pond>>, pond: Query<Entity, With<Pond>>,
@ -316,14 +331,6 @@ fn on_view_hand_update(
) { ) {
// TODO can this and similar run at startup or on play/reconnect? // TODO can this and similar run at startup or on play/reconnect?
for msg in messages.read() { 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 let hand_tiles: Vec<_> = msg
.new .new
.hand .hand
@ -348,18 +355,10 @@ fn on_view_hand_update(
.collect(); .collect();
commands commands
.entity( .entity(hand.iter().find(|e| main_player.1.contains(e)).unwrap())
hand.iter()
.find(|e| main_player.1.is_some_and(|mp| mp.contains(e)))
.unwrap(),
)
.replace_children(&hand_tiles); .replace_children(&hand_tiles);
commands commands
.entity( .entity(pond.iter().find(|e| main_player.1.contains(e)).unwrap())
pond.iter()
.find(|e| main_player.1.is_some_and(|mp| mp.contains(e)))
.unwrap(),
)
.replace_children(&pond_tiles); .replace_children(&pond_tiles);
match msg.new.turn_state { match msg.new.turn_state {

View file

@ -82,17 +82,17 @@ impl Plugin for TuiPlugin {
(input::keyboard, input::mouse).in_set(TuiSet::Input), (input::keyboard, input::mouse).in_set(TuiSet::Input),
) )
.add_systems(Update, layout::layout.in_set(TuiSet::Layout)) .add_systems(Update, layout::layout.in_set(TuiSet::Layout))
.add_systems(Update, discard_tile.run_if(in_state(TurnState::Tsumo)))
.add_systems( .add_systems(
Update, Update,
( (
(render::render_main_hand, render::render_main_pond) (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, render::render,
) )
.chain() .chain()
.in_set(TuiSet::Render), .in_set(TuiSet::Render),
); )
.add_systems(Update, discard_tile.run_if(in_state(TurnState::Tsumo)));
} }
} }