From c274f6b807aebbcda28449960ce88e9b0886dc7b Mon Sep 17 00:00:00 2001 From: Tao Tien <29749622+taotien@users.noreply.github.com> Date: Tue, 24 Feb 2026 16:46:48 -0800 Subject: [PATCH 1/2] while .next() on db cache is infinite --- docs/queries.rs | 6 ------ jong/src/riichi.rs | 37 +++++++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 14 deletions(-) delete mode 100644 docs/queries.rs diff --git a/docs/queries.rs b/docs/queries.rs deleted file mode 100644 index 522720d..0000000 --- a/docs/queries.rs +++ /dev/null @@ -1,6 +0,0 @@ -commands: Commands - -tiles: Query<(&Tile, &TileId, Entity)>, -player: Option>, -hand_ent: Option>>, - diff --git a/jong/src/riichi.rs b/jong/src/riichi.rs index de16274..93de3f5 100644 --- a/jong/src/riichi.rs +++ b/jong/src/riichi.rs @@ -83,10 +83,19 @@ fn subscriptions(stdb: SpacetimeDB, mut commands: Commands) { // commands.queue(command); let (send, recv) = std::sync::mpsc::channel::(); stdb.subscription_builder() - .on_applied(move |_| send.send(Subscribed).unwrap()) - .on_error(|_, err| error!("sub failed: {err}")) + .on_applied(move |_| { + trace!("subs succeeded"); + send.send(Subscribed).unwrap(); + }) + .on_error(|_, err| { + error!("subs failed: {err}"); + }) .subscribe([ // TODO change these to sub/unsub based on being in lobby and some such + format!( + "SELECT p.* FROM player p WHERE p.identity = '{}'", + stdb.identity() + ), "SELECT p.* FROM player p JOIN lobby l ON p.lobby_id = l.id".to_string(), "SELECT l.* FROM lobby l JOIN player p ON l.id = p.lobby_id".to_string(), "SELECT c.* FROM player_clock c JOIN player p ON c.player_id = p.id".to_string(), @@ -111,14 +120,18 @@ fn on_subscribed( mut next_gamestate: ResMut>, mut next_turnstate: ResMut>, ) { - while let Some(player) = stdb.db().player().iter().next() { + trace!("on_subscribed"); + for player in stdb.db().player().iter() { if player.identity == stdb.identity() { + // trace!("spawn_main_player"); spawn_main_player(&stdb, &mut commands, &mut next_turnstate, &player); } else { + // trace!("spawn_other_player"); spawn_other_player(&stdb, &mut commands, &player); } } - while let Some(bot) = stdb.db().bot().iter().next() { + + for bot in stdb.db().bot().iter() { let id = PlayerOrBot::Bot { id: bot.id }; let hand_view = stdb .db() @@ -143,7 +156,7 @@ fn spawn_main_player( player: &jong_db::Player, ) { - trace!("spawn_main_player"); + // trace!("spawn_main_player"); let main_player = commands .spawn(( Player { @@ -176,9 +189,15 @@ fn spawn_main_hand( .collect(); let pond = commands.spawn(Hand).add_children(&pond_tiles).id(); let hand = commands.spawn(Pond).add_children(&hand_tiles).id(); - let children = commands.entity(main_player).add_children(&[pond, hand]).id(); + let children = commands + .entity(main_player) + .add_children(&[pond, hand]) + .id(); - debug!("main_hand: {:?}\n main_pond: {:?}, children: {:?}", hand_tiles, pond_tiles, children); + debug!( + "main_hand: {:?}\n main_pond: {:?}, children: {:?}", + hand_tiles, pond_tiles, children + ); if player_hand.turn_state == jong_db::TurnState::Tsumo && let Some(drawn_dbt) = &player_hand.working_tile @@ -216,8 +235,9 @@ fn on_player_insert_update( mut next_turnstate: ResMut>, ) { for msg in messages.read() { + debug!("on_player_insert_update: {:?}", msg.new); if main_player.is_none() && msg.new.identity == stdb.identity() { - trace!("spawn_main_player"); + // 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 { @@ -226,6 +246,7 @@ fn on_player_insert_update( false } }) { + trace!("spawn_other_player"); spawn_other_player(&stdb, &mut commands, &msg.new); } else { // TODO update case From 922413cc93d3093d8dd81f0b0e65353f7b8bb540 Mon Sep 17 00:00:00 2001 From: Tao Tien <29749622+taotien@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:18:31 -0800 Subject: [PATCH 2/2] temporary workaround racing against render and spawning hand? --- devenv.nix | 1 + jong/src/main.rs | 8 ++++++-- jong/src/riichi.rs | 20 +++++++------------- jong/src/tui/render.rs | 8 ++++++++ 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/devenv.nix b/devenv.nix index 9899754..2848ba6 100644 --- a/devenv.nix +++ b/devenv.nix @@ -15,6 +15,7 @@ # paths = [./jong]; # }; }; + processes.tail_log.exec = "tail -f jong.log"; # https://devenv.sh/packages/ packages = with pkgs; [ diff --git a/jong/src/main.rs b/jong/src/main.rs index dcb9492..ae1c58b 100644 --- a/jong/src/main.rs +++ b/jong/src/main.rs @@ -4,7 +4,7 @@ use bevy::{log::LogPlugin, prelude::*}; use clap::{Parser, Subcommand}; use tracing::Level; use tracing_subscriber::{ - Layer, + EnvFilter, Layer, fmt::{self, layer}, layer::SubscriberExt, util::SubscriberInitExt, @@ -40,7 +40,11 @@ fn main() { Mode::RunTui => { tracing_subscriber::registry() .with(tui_logger::TuiTracingSubscriberLayer) - .with(fmt::layer().with_writer(File::create("jong.log").unwrap())) + .with( + fmt::layer() + .with_writer(File::create("jong.log").unwrap()) + .with_filter(EnvFilter::from_default_env()), + ) .init(); tui_logger::init_logger(tui_logger::LevelFilter::Trace).unwrap(); tui_logger::set_env_filter_from_string(FILTERSTRING); diff --git a/jong/src/riichi.rs b/jong/src/riichi.rs index 93de3f5..d5ae098 100644 --- a/jong/src/riichi.rs +++ b/jong/src/riichi.rs @@ -131,7 +131,7 @@ fn on_subscribed( } } - for bot in stdb.db().bot().iter() { + for bot in stdb.db().bot().iter() { let id = PlayerOrBot::Bot { id: bot.id }; let hand_view = stdb .db() @@ -187,17 +187,11 @@ fn spawn_main_hand( .iter() .map(|dbt| commands.spawn((Tile::from(&dbt.tile), TileId(dbt.id))).id()) .collect(); - let pond = commands.spawn(Hand).add_children(&pond_tiles).id(); - let hand = commands.spawn(Pond).add_children(&hand_tiles).id(); - let children = commands - .entity(main_player) - .add_children(&[pond, hand]) - .id(); + let hand = commands.spawn(Hand).add_children(&hand_tiles).id(); + let pond = commands.spawn(Pond).add_children(&pond_tiles).id(); + commands.entity(main_player).add_children(&[hand, pond]); - debug!( - "main_hand: {:?}\n main_pond: {:?}, children: {:?}", - hand_tiles, pond_tiles, children - ); + debug!("main_hand: {:?}\n main_pond: {:?}", hand_tiles, pond_tiles); if player_hand.turn_state == jong_db::TurnState::Tsumo && let Some(drawn_dbt) = &player_hand.working_tile @@ -319,10 +313,10 @@ 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); + // trace!("new hand: {:?}", msg.new); if main_player.1.is_none() { - trace!("spawn_main_hand, {:?}", *main_player); + // trace!("spawn_main_hand, {:?}", *main_player); spawn_main_hand(&mut commands, &mut next_turnstate, main_player.0, &msg.new); continue; } diff --git a/jong/src/tui/render.rs b/jong/src/tui/render.rs index 2135fa9..34f5495 100644 --- a/jong/src/tui/render.rs +++ b/jong/src/tui/render.rs @@ -112,6 +112,10 @@ pub(crate) fn render_main_hand( let mut frame = tui.get_frame(); debug_blocks(layouts.clone(), &mut frame); + if hand.is_empty() { + return Ok(()); + } + let hand: Vec<_> = hand .iter() .find_map(|(c, e)| { @@ -222,6 +226,10 @@ pub(crate) fn render_main_pond( ) -> Result { let mut frame = tui.get_frame(); + if pond.is_empty() { + return Ok(()); + } + let pond: Vec<_> = pond .iter() .find_map(|(c, e)| {