From 50fd406dbfe4f806d7238f7e1e55b5c1259a8759 Mon Sep 17 00:00:00 2001 From: Tao Tien <29749622+taotien@users.noreply.github.com> Date: Tue, 10 Feb 2026 01:38:13 -0800 Subject: [PATCH 1/5] small changes --- jong/src/game.rs | 2 +- jong/src/tui.rs | 2 +- jong/src/tui/render.rs | 76 ++++++++++++++++++------------------ justfile | 4 +- spacetimedb/src/game.rs | 2 +- spacetimedb/src/game/wall.rs | 5 ++- 6 files changed, 46 insertions(+), 45 deletions(-) diff --git a/jong/src/game.rs b/jong/src/game.rs index cb4d61f..438627a 100644 --- a/jong/src/game.rs +++ b/jong/src/game.rs @@ -190,7 +190,7 @@ fn on_lobby_insert_update( trace!("game entered none"); } stdb::GameState::Lobby => { - trace!("game in lobby"); + trace!("game entered lobby"); if !player.ready { for _ in 0..3 { stdb.reducers().add_bot(player.lobby_id).unwrap(); diff --git a/jong/src/tui.rs b/jong/src/tui.rs index 3c2bade..821e3a1 100644 --- a/jong/src/tui.rs +++ b/jong/src/tui.rs @@ -86,7 +86,7 @@ impl Plugin for TuiPlugin { .add_systems( Update, ( - (render::render_hands, render::render_arg_check).run_if(in_state(GameState::Play)), + render::render_hands.run_if(in_state(GameState::Play)), render::render, ) .chain() diff --git a/jong/src/tui/render.rs b/jong/src/tui/render.rs index 42a0fd2..f5e919b 100644 --- a/jong/src/tui/render.rs +++ b/jong/src/tui/render.rs @@ -95,22 +95,22 @@ pub(crate) fn render( Ok(()) } -pub(crate) fn render_arg_check( - mut commands: Commands, - mut tui: ResMut, +// pub(crate) fn render_arg_check( +// mut commands: Commands, +// mut tui: ResMut, - hovered: Query>, - layouts: Res, +// hovered: Query>, +// layouts: Res, - tiles: Query<&jong_types::Tile>, - // main_player: Single<(&Player, Entity, &Wind), With>, - curr_player: Single>, - players: Query<(&Player, Entity, &Children)>, - hands: Query<(&Children, Entity), (With, Without)>, - // drawn_tile: Single>, -) { - // trace!("arg!"); -} +// tiles: Query<&jong_types::Tile>, +// // main_player: Single<(&Player, Entity, &Wind), With>, +// curr_player: Single>, +// players: Query<(&Player, Entity, &Children)>, +// hands: Query<(&Children, Entity), (With, Without)>, +// // drawn_tile: Single>, +// ) { +// // trace!("arg!"); +// } #[allow(clippy::too_many_arguments, clippy::type_complexity)] pub(crate) fn render_hands( @@ -121,14 +121,12 @@ pub(crate) fn render_hands( layouts: Res, tiles: Query<&jong_types::Tile>, - main_player: Single<(&Player, Entity, &Wind), With>, + main_player: Single<(&Player, Entity /* , &Wind */), With>, curr_player: Single>, players: Query<(&Player, Entity, &Children)>, hands: Query<(&Children, Entity), (With, Without)>, - drawn_tile: Single>, + // drawn_tile: Single>, ) -> Result { - trace!("render_hands"); - let mut frame = tui.get_frame(); debug_blocks(*layouts, &mut frame); @@ -194,27 +192,27 @@ pub(crate) fn render_hands( } // tsumo tile - if this_drawer { - // trace!("this_drawer"); - let mut area = drawn_area.resize(Size { - width: 5, - height: 4, - }); - area = area.offset(Offset { x: 2, y: 0 }); - let hovered = hovered.contains(*drawn_tile); - let widget = render_tile(tiles.get(*drawn_tile)?, hovered); - if hovered { - area = area.offset(Offset { x: 0, y: -1 }); - let mut hitbox = area.as_size(); - hitbox.height += 1; - commands.entity(*drawn_tile).insert(PickRegion { - area: area.resize(hitbox), - }); - } else { - commands.entity(*drawn_tile).insert(PickRegion { area }); - } - frame.render_widget(widget, area); - } + // if this_drawer { + // // trace!("this_drawer"); + // let mut area = drawn_area.resize(Size { + // width: 5, + // height: 4, + // }); + // area = area.offset(Offset { x: 2, y: 0 }); + // let hovered = hovered.contains(*drawn_tile); + // let widget = render_tile(tiles.get(*drawn_tile)?, hovered); + // if hovered { + // area = area.offset(Offset { x: 0, y: -1 }); + // let mut hitbox = area.as_size(); + // hitbox.height += 1; + // commands.entity(*drawn_tile).insert(PickRegion { + // area: area.resize(hitbox), + // }); + // } else { + // commands.entity(*drawn_tile).insert(PickRegion { area }); + // } + // frame.render_widget(widget, area); + // } // TODO draw melds } else { // match mainplayer.1.relate(wind) { diff --git a/justfile b/justfile index 8962781..0d4b9f7 100644 --- a/justfile +++ b/justfile @@ -8,8 +8,8 @@ default: just --list run-tui: - # mprocs -s localhost:4050 --ctl $"({c: restart-proc, name: spacetimedb_generate_bindings} | to yaml)" - # sleep 3sec + mprocs -s localhost:4050 --ctl $"({c: restart-proc, name: spacetimedb_generate_bindings} | to yaml)" + sleep 3sec cargo run -- run-tui update: diff --git a/spacetimedb/src/game.rs b/spacetimedb/src/game.rs index 37a6a69..5ade52f 100644 --- a/spacetimedb/src/game.rs +++ b/spacetimedb/src/game.rs @@ -80,7 +80,7 @@ pub fn start_game(ctx: &ReducerContext) { PlayerOrBot::Bot { id } => ctx.db.bot().id().find(id).is_some(), }) { - lobby.game_state = GameState::Deal; + lobby.game_state = GameState::Setup; ctx.db.lobby().id().update(lobby); } } diff --git a/spacetimedb/src/game/wall.rs b/spacetimedb/src/game/wall.rs index f33c898..7096559 100644 --- a/spacetimedb/src/game/wall.rs +++ b/spacetimedb/src/game/wall.rs @@ -10,7 +10,10 @@ pub fn shuffle_deal(ctx: &ReducerContext, lobby_id: u32) { debug!("lobby_id: {lobby_id}"); let mut lobby = ctx.db.lobby().id().find(lobby_id).unwrap(); - if lobby.game_state == GameState::Deal { + if lobby.game_state == GameState::Setup { + lobby.game_state = GameState::Deal; + lobby = ctx.db.lobby().id().update(lobby); + let tiles = new_shuffled_wall(ctx); ctx.db.wall().insert(Wall { // id: 0, From f6bd7fd6f780b8ae3836e222b2732de0d0167c20 Mon Sep 17 00:00:00 2001 From: Tao Tien <29749622+taotien@users.noreply.github.com> Date: Tue, 10 Feb 2026 01:38:13 -0800 Subject: [PATCH 2/5] spawn each player and hand --- states => docs/states | 0 jong/src/game.rs | 2 + jong/src/tui/render.rs | 152 +++++++++++++++++++++-------------------- 3 files changed, 79 insertions(+), 75 deletions(-) rename states => docs/states (100%) diff --git a/states b/docs/states similarity index 100% rename from states rename to docs/states diff --git a/jong/src/game.rs b/jong/src/game.rs index 438627a..0a0f91e 100644 --- a/jong/src/game.rs +++ b/jong/src/game.rs @@ -228,6 +228,8 @@ fn view_hand( // trace!("view_hand"); if let Some(view) = stdb.db().view_player_hand().iter().next() { let mut view = view.tiles.iter().map(Tile::from).collect::>(); + // view.sort(); + debug!("view: {view:?}"); let tiles = tiles .iter() diff --git a/jong/src/tui/render.rs b/jong/src/tui/render.rs index f5e919b..2377516 100644 --- a/jong/src/tui/render.rs +++ b/jong/src/tui/render.rs @@ -112,6 +112,7 @@ pub(crate) fn render( // // trace!("arg!"); // } +// FIXME we don't care about other players atm #[allow(clippy::too_many_arguments, clippy::type_complexity)] pub(crate) fn render_hands( mut commands: Commands, @@ -124,7 +125,7 @@ pub(crate) fn render_hands( main_player: Single<(&Player, Entity /* , &Wind */), With>, curr_player: Single>, players: Query<(&Player, Entity, &Children)>, - hands: Query<(&Children, Entity), (With, Without)>, + hands: Query<(&Children, Entity), With>, // drawn_tile: Single>, ) -> Result { let mut frame = tui.get_frame(); @@ -132,10 +133,10 @@ pub(crate) fn render_hands( for (hand, hand_ent) in hands { // debug!("{hand:?}"); - let (player, player_ent, _) = players - .iter() - .find(|(_, e, c)| c.contains(&hand_ent)) - .unwrap(); + // let (player, player_ent, _) = players + // .iter() + // .find(|(_, e, c)| c.contains(&hand_ent)) + // .unwrap(); let hand: Vec<_> = hand .iter() .map(|entity| -> Result<_> { @@ -147,80 +148,81 @@ pub(crate) fn render_hands( }) .collect::>()?; - if player == main_player.0 { - // split main box into thirds - let mut this_hand = layouts.this_hand; - // let this_drawer = drawn_tile..is_some_and(|dt| dt.0 == player); - let this_drawer = player_ent == *curr_player; - let tile_drawn = if this_drawer { 7 } else { 0 }; - let hand_draw_meld = Layout::horizontal([ - Constraint::Max(hand.len() as u16 * 5), - Constraint::Max(tile_drawn), - Constraint::Fill(1), - ]) - .flex(Flex::SpaceBetween); - this_hand = this_hand.offset(Offset { - x: 0, - y: this_hand.height.abs_diff(5) as i32 + 1, - }); - this_hand = this_hand.resize(Size { - width: this_hand.width, - height: 4, - }); - let [hand_area, drawn_area, meld_area] = hand_draw_meld.areas::<3>(this_hand); + let (player, player_ent) = *main_player; + // if player == main_player.0 { + // split main box into thirds + let mut this_hand = layouts.this_hand; + // let this_drawer = drawn_tile..is_some_and(|dt| dt.0 == player); + let this_drawer = player_ent == *curr_player; + let tile_drawn = if this_drawer { 7 } else { 0 }; + let hand_draw_meld = Layout::horizontal([ + Constraint::Max(hand.len() as u16 * 5), + Constraint::Max(tile_drawn), + Constraint::Fill(1), + ]) + .flex(Flex::SpaceBetween); + this_hand = this_hand.offset(Offset { + x: 0, + y: this_hand.height.abs_diff(5) as i32 + 1, + }); + this_hand = this_hand.resize(Size { + width: this_hand.width, + height: 4, + }); + let [hand_area, drawn_area, meld_area] = hand_draw_meld.areas::<3>(this_hand); - // split hand area into tile areas - let mut constraints = vec![Constraint::Max(5); hand.len()]; - constraints.push(Constraint::Fill(1)); - let layout = Layout::horizontal(constraints).flex(Flex::Start); - let tile_areas = layout.split(hand_area); + // split hand area into tile areas + let mut constraints = vec![Constraint::Max(5); hand.len()]; + constraints.push(Constraint::Fill(1)); + let layout = Layout::horizontal(constraints).flex(Flex::Start); + let tile_areas = layout.split(hand_area); - for ((entity, widget, hovered), mut area) in - hand.into_iter().zip(tile_areas.iter().copied()) - { - if hovered { - area = area.offset(Offset { x: 0, y: -1 }); - let mut hitbox = area.as_size(); - hitbox.height += 1; - commands.entity(entity).insert(PickRegion { - area: area.resize(hitbox), - }); - } else { - commands.entity(entity).insert(PickRegion { area }); - } - frame.render_widget(widget, area); + for ((entity, widget, hovered), mut area) in + hand.into_iter().zip(tile_areas.iter().copied()) + { + if hovered { + area = area.offset(Offset { x: 0, y: -1 }); + let mut hitbox = area.as_size(); + hitbox.height += 1; + commands.entity(entity).insert(PickRegion { + area: area.resize(hitbox), + }); + } else { + commands.entity(entity).insert(PickRegion { area }); } - - // tsumo tile - // if this_drawer { - // // trace!("this_drawer"); - // let mut area = drawn_area.resize(Size { - // width: 5, - // height: 4, - // }); - // area = area.offset(Offset { x: 2, y: 0 }); - // let hovered = hovered.contains(*drawn_tile); - // let widget = render_tile(tiles.get(*drawn_tile)?, hovered); - // if hovered { - // area = area.offset(Offset { x: 0, y: -1 }); - // let mut hitbox = area.as_size(); - // hitbox.height += 1; - // commands.entity(*drawn_tile).insert(PickRegion { - // area: area.resize(hitbox), - // }); - // } else { - // commands.entity(*drawn_tile).insert(PickRegion { area }); - // } - // frame.render_widget(widget, area); - // } - // TODO draw melds - } else { - // match mainplayer.1.relate(wind) { - // jong::game::round::WindRelation::Shimocha => todo!(), - // jong::game::round::WindRelation::Toimen => todo!(), - // jong::game::round::WindRelation::Kamicha => todo!(), - // } + frame.render_widget(widget, area); } + + // tsumo tile + // if this_drawer { + // // trace!("this_drawer"); + // let mut area = drawn_area.resize(Size { + // width: 5, + // height: 4, + // }); + // area = area.offset(Offset { x: 2, y: 0 }); + // let hovered = hovered.contains(*drawn_tile); + // let widget = render_tile(tiles.get(*drawn_tile)?, hovered); + // if hovered { + // area = area.offset(Offset { x: 0, y: -1 }); + // let mut hitbox = area.as_size(); + // hitbox.height += 1; + // commands.entity(*drawn_tile).insert(PickRegion { + // area: area.resize(hitbox), + // }); + // } else { + // commands.entity(*drawn_tile).insert(PickRegion { area }); + // } + // frame.render_widget(widget, area); + // } + // TODO draw melds + // } else { + // match mainplayer.1.relate(wind) { + // jong::game::round::WindRelation::Shimocha => todo!(), + // jong::game::round::WindRelation::Toimen => todo!(), + // jong::game::round::WindRelation::Kamicha => todo!(), + // } + // } } Ok(()) From 7cef787f385ada692bfe731d10b608006db2de2f Mon Sep 17 00:00:00 2001 From: Tao Tien <29749622+taotien@users.noreply.github.com> Date: Wed, 11 Feb 2026 01:18:24 -0800 Subject: [PATCH 3/5] use deprecated RLS until views work in bevy_stdb --- .ignore | 1 + Cargo.toml | 4 +++- jong/src/game.rs | 44 ++++++++++++++++----------------------- spacetimedb/src/tables.rs | 12 +++++++++-- 4 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 .ignore diff --git a/.ignore b/.ignore new file mode 100644 index 0000000..c380951 --- /dev/null +++ b/.ignore @@ -0,0 +1 @@ +jong/src/stdb diff --git a/Cargo.toml b/Cargo.toml index c283329..eb2e720 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,9 @@ bevy.default-features = false bevy_ratatui = "0.10.0" bevy_spacetimedb = "0.7" -spacetimedb = "1.11.*" +spacetimedb.version = "1.11.*" +spacetimedb.features = ["unstable"] + spacetimedb-sdk = "1.11.*" strum.version = "0.27.2" diff --git a/jong/src/game.rs b/jong/src/game.rs index 0a0f91e..c00eee6 100644 --- a/jong/src/game.rs +++ b/jong/src/game.rs @@ -45,11 +45,15 @@ impl Plugin for Riichi { .with_uri("http://localhost:3000") .with_module_name("jongline") .with_run_fn(DbConnection::run_threaded) + // TODO why don't I need to call add_reducer? // TODO do these need to be subscription & vice-versa? .add_table(RemoteTables::player) .add_table(RemoteTables::lobby) + + // TODO until views work, we're using RLS .add_table(RemoteTables::hand) + // .add_table_without_pk(RemoteTables::view_player_hand) // semicolon stopper ; @@ -83,7 +87,11 @@ impl Plugin for Riichi { .add_systems(Update, on_player_insert_update) .add_systems(Update, on_lobby_insert_update) // .add_systems(OnEnter(GameState::Lobby), join_or_create_lobby) - .add_systems(Update, view_hand.run_if(in_state(GameState::Play))) + + // TODO figure out how to run_if OR run_if? + .add_systems(Update, on_hand_insert_update.run_if(in_state(GameState::Deal))) + .add_systems(Update, on_hand_insert_update.run_if(in_state(GameState::Play))) + // semicolon stopper ; } @@ -115,7 +123,8 @@ fn subscriptions(stdb: SpacetimeDB) { stdb.identity() ), "SELECT l.* FROM lobby l JOIN player p ON l.host_player_id = p.id".to_string(), - "SELECT * FROM view_player_hand vph".to_string(), + // "SELECT * FROM view_player_hand vph".to_string(), + "SELECT * FROM hand".to_string(), // TODO remove once views work ]); // .subscribe_to_all_tables(); } @@ -130,7 +139,7 @@ fn on_player_insert_update( use player::*; for msg in messages.read() { - debug!("player_insert_update msg:\n{:#?}", msg.new); + // debug!("player_insert_update msg:\n{:#?}", msg.new); if let Some(ref player) = player { // if msg.old.as_ref().is_some_and(|m| !m.ready) && msg.new.ready { // trace!("entered ready"); @@ -152,21 +161,6 @@ fn on_player_insert_update( } } -// fn join_or_create_lobby(stdb: SpacetimeDB) { -// let player = stdb -// .db() -// .player() -// .identity() -// .find(&stdb.identity()) -// .unwrap(); - -// if player.lobby_id == 0 { -// stdb.reducers().join_or_create_lobby(0).unwrap(); -// } else { -// info!("in lobby: {}", player.lobby_id) -// } -// } - fn on_lobby_insert_update( stdb: SpacetimeDB, mut messages: ReadInsertUpdateMessage, @@ -175,7 +169,7 @@ fn on_lobby_insert_update( mut next_gamestate: ResMut>, ) { for msg in messages.read() { - trace!("on_lobby_insert_update msg:\n{:#?}", msg.new); + // trace!("on_lobby_insert_update msg:\n{:#?}", msg.new); let player = stdb .db() @@ -218,19 +212,17 @@ fn on_lobby_insert_update( } } -fn view_hand( +fn on_hand_insert_update( stdb: SpacetimeDB, + mut messages: ReadInsertUpdateMessage, mut commands: Commands, tiles: Query<(&Tile, Entity)>, hand_ent: Single>, ) { - // trace!("view_hand"); - if let Some(view) = stdb.db().view_player_hand().iter().next() { - let mut view = view.tiles.iter().map(Tile::from).collect::>(); - // view.sort(); - debug!("view: {view:?}"); - + for msg in messages.read() { + trace!("view_hand"); + let mut view: Vec<_> = msg.new.tiles.iter().map(Tile::from).collect(); let tiles = tiles .iter() .filter(|(tt, _)| { diff --git a/spacetimedb/src/tables.rs b/spacetimedb/src/tables.rs index 02efc8e..e06de8e 100644 --- a/spacetimedb/src/tables.rs +++ b/spacetimedb/src/tables.rs @@ -1,4 +1,4 @@ -use spacetimedb::{Identity, SpacetimeType, table}; +use spacetimedb::{Filter, Identity, SpacetimeType, client_visibility_filter, table}; use jong_types::*; @@ -63,7 +63,15 @@ pub struct Wall { pub tiles: Vec, } -#[table(name = hand)] +// TODO temp use deprecated RLS instead of view until bevy_spacetimedb supp is better +#[client_visibility_filter] +const HAND_FILTER: Filter = Filter::Sql( + "SELECT h.* FROM hand h + JOIN player p ON h.id = p.hand_id + WHERE p.identity = :sender", +); + +#[table(name = hand, public)] pub struct Hand { #[primary_key] #[auto_inc] From 71ad4cada62554453cf973897dfb769e38337607 Mon Sep 17 00:00:00 2001 From: Tao Tien <29749622+taotien@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:14:02 -0800 Subject: [PATCH 4/5] extract player tables --- spacetimedb/src/game.rs | 2 +- spacetimedb/src/game/hand.rs | 2 +- spacetimedb/src/lib.rs | 2 +- spacetimedb/src/tables.rs | 47 ++++---------------------------- spacetimedb/src/tables/player.rs | 40 +++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 44 deletions(-) create mode 100644 spacetimedb/src/tables/player.rs diff --git a/spacetimedb/src/game.rs b/spacetimedb/src/game.rs index 5ade52f..07eff79 100644 --- a/spacetimedb/src/game.rs +++ b/spacetimedb/src/game.rs @@ -1,7 +1,7 @@ use log::{info, trace}; use spacetimedb::{ReducerContext, Table, reducer}; -use crate::tables::*; +use crate::tables::{player::player, *}; use jong_types::*; mod hand; diff --git a/spacetimedb/src/game/hand.rs b/spacetimedb/src/game/hand.rs index 546ad66..adc9845 100644 --- a/spacetimedb/src/game/hand.rs +++ b/spacetimedb/src/game/hand.rs @@ -1,6 +1,6 @@ use spacetimedb::{ReducerContext, Table, ViewContext, reducer, view}; -use crate::tables::*; +use crate::tables::{player::player, *}; use jong_types::*; pub fn deal_hands(ctx: &ReducerContext, lobby_id: u32) { diff --git a/spacetimedb/src/lib.rs b/spacetimedb/src/lib.rs index 505db51..3af5855 100644 --- a/spacetimedb/src/lib.rs +++ b/spacetimedb/src/lib.rs @@ -1,7 +1,7 @@ use log::info; use spacetimedb::{ReducerContext, Table, reducer}; -use crate::tables::*; +use crate::tables::{player::player, *}; mod game; mod tables; diff --git a/spacetimedb/src/tables.rs b/spacetimedb/src/tables.rs index e06de8e..f92657c 100644 --- a/spacetimedb/src/tables.rs +++ b/spacetimedb/src/tables.rs @@ -1,44 +1,9 @@ -use spacetimedb::{Filter, Identity, SpacetimeType, client_visibility_filter, table}; +use spacetimedb::{Filter, SpacetimeType, client_visibility_filter, table}; use jong_types::*; -#[derive(Debug)] -#[table(name = player, public)] -pub struct Player { - #[primary_key] - pub identity: Identity, - - #[unique] - #[auto_inc] - pub id: u32, - - pub name: Option, - - #[index(btree)] - pub lobby_id: u32, - pub hand_id: u32, - pub pond_id: u32, - - pub ready: bool, -} - -#[table(name = bot)] -pub struct Bot { - #[primary_key] - #[auto_inc] - pub id: u32, - - #[index(btree)] - pub lobby_id: u32, - pub hand_id: u32, - pub pond_id: u32, -} - -#[derive(Debug, Clone, SpacetimeType)] -pub enum PlayerOrBot { - Player { id: u32 }, - Bot { id: u32 }, -} +pub mod player; +pub use player::*; #[derive(Debug, Clone)] #[table(name = lobby, public)] @@ -49,7 +14,7 @@ pub struct Lobby { #[unique] pub host_player_id: u32, - pub players: Vec, + pub players: Vec, pub game_state: GameState, pub turn_state: TurnState, @@ -77,7 +42,7 @@ pub struct Hand { #[auto_inc] pub id: u32, - pub owner: PlayerOrBot, + pub owner: player::PlayerOrBot, pub sort: bool, pub tiles: Vec, @@ -89,7 +54,7 @@ pub struct Pond { #[auto_inc] pub id: u32, - pub owner: PlayerOrBot, + pub owner: player::PlayerOrBot, pub tiles: Vec, } diff --git a/spacetimedb/src/tables/player.rs b/spacetimedb/src/tables/player.rs new file mode 100644 index 0000000..0f580df --- /dev/null +++ b/spacetimedb/src/tables/player.rs @@ -0,0 +1,40 @@ +use spacetimedb::Identity; +use spacetimedb::{SpacetimeType, table}; + +#[derive(Debug)] +#[table(name = player, public)] +pub struct Player { + #[primary_key] + pub identity: Identity, + + #[unique] + #[auto_inc] + pub id: u32, + + pub name: Option, + + #[index(btree)] + pub lobby_id: u32, + pub hand_id: u32, + pub pond_id: u32, + + pub ready: bool, +} + +#[table(name = bot)] +pub struct Bot { + #[primary_key] + #[auto_inc] + pub id: u32, + + #[index(btree)] + pub lobby_id: u32, + pub hand_id: u32, + pub pond_id: u32, +} + +#[derive(Debug, Clone, SpacetimeType)] +pub enum PlayerOrBot { + Player { id: u32 }, + Bot { id: u32 }, +} From 9b01f6b96aac313c575bb93c1a02f94d001896f7 Mon Sep 17 00:00:00 2001 From: Tao Tien <29749622+taotien@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:16:21 -0800 Subject: [PATCH 5/5] merge all extra tables back into player for now --- jong/src/game.rs | 70 +++++------- jong/src/stdb/bot_table.rs | 1 + jong/src/stdb/bot_type.rs | 6 +- jong/src/stdb/hand_table.rs | 144 ------------------------ jong/src/stdb/hand_type.rs | 21 ---- jong/src/stdb/mod.rs | 43 ------- jong/src/stdb/player_table.rs | 1 + jong/src/stdb/player_type.rs | 7 +- jong/src/stdb/pond_table.rs | 144 ------------------------ jong/src/stdb/pond_type.rs | 20 ---- jong/src/stdb/view_player_hand_table.rs | 97 ---------------- spacetimedb/src/game.rs | 4 +- spacetimedb/src/game/hand.rs | 36 ++---- spacetimedb/src/lib.rs | 5 +- spacetimedb/src/tables.rs | 31 ----- spacetimedb/src/tables/player.rs | 15 ++- 16 files changed, 66 insertions(+), 579 deletions(-) delete mode 100644 jong/src/stdb/hand_table.rs delete mode 100644 jong/src/stdb/hand_type.rs delete mode 100644 jong/src/stdb/pond_table.rs delete mode 100644 jong/src/stdb/pond_type.rs delete mode 100644 jong/src/stdb/view_player_hand_table.rs diff --git a/jong/src/game.rs b/jong/src/game.rs index c00eee6..85ff3cd 100644 --- a/jong/src/game.rs +++ b/jong/src/game.rs @@ -9,9 +9,8 @@ use spacetimedb::Identity; use spacetimedb_sdk::{DbContext, Table, credentials}; use crate::stdb::{ - self, DbConnection, HandTableAccess, LobbyTableAccess, PlayerTableAccess, RemoteTables, - ViewPlayerHandTableAccess, add_bot, join_or_create_lobby, login_or_add_player, set_ready, - shuffle_deal, start_game, + self, DbConnection, LobbyTableAccess, PlayerTableAccess, RemoteTables, add_bot, + join_or_create_lobby, login_or_add_player, set_ready, shuffle_deal, start_game, }; use crate::{ SpacetimeDB, creds_store, @@ -51,10 +50,6 @@ impl Plugin for Riichi { .add_table(RemoteTables::player) .add_table(RemoteTables::lobby) - // TODO until views work, we're using RLS - .add_table(RemoteTables::hand) - // .add_table_without_pk(RemoteTables::view_player_hand) - // semicolon stopper ; let plugins = @@ -88,10 +83,6 @@ impl Plugin for Riichi { .add_systems(Update, on_lobby_insert_update) // .add_systems(OnEnter(GameState::Lobby), join_or_create_lobby) - // TODO figure out how to run_if OR run_if? - .add_systems(Update, on_hand_insert_update.run_if(in_state(GameState::Deal))) - .add_systems(Update, on_hand_insert_update.run_if(in_state(GameState::Play))) - // semicolon stopper ; } @@ -123,8 +114,6 @@ fn subscriptions(stdb: SpacetimeDB) { stdb.identity() ), "SELECT l.* FROM lobby l JOIN player p ON l.host_player_id = p.id".to_string(), - // "SELECT * FROM view_player_hand vph".to_string(), - "SELECT * FROM hand".to_string(), // TODO remove once views work ]); // .subscribe_to_all_tables(); } @@ -134,18 +123,43 @@ fn on_player_insert_update( mut messages: ReadInsertUpdateMessage, mut commands: Commands, + + tiles: Query<(&Tile, Entity)>, mut player: Option>, + mut hand_ent: Option>>, ) { use player::*; for msg in messages.read() { - // debug!("player_insert_update msg:\n{:#?}", msg.new); + debug!("player_insert_update msg:\n{:#?}", msg.new); if let Some(ref player) = player { // if msg.old.as_ref().is_some_and(|m| !m.ready) && msg.new.ready { // trace!("entered ready"); // // TODO add a start game button in the future // stdb.reducers().start_game().unwrap(); // } + let mut view: Vec<_> = msg.new.hand.iter().map(Tile::from).collect(); + // let mut tiles = tiles + // .iter() + // .filter(|(tt, _)| { + // if let Some((i, _)) = view.iter().enumerate().find(|(_, t)| t == tt) { + // view.swap_remove(i); + // true + // } else { + // false + // } + // }) + // // .map(|(t, e)| e) + // .collect::>(); + // tiles.sort_by_key(|(t, e)| **t); + // tiles.get_many(entities) + + + let tiles = tiles.into_iter().map(|(_, e)| e).collect::>(); + + commands + .entity(**hand_ent.as_ref().unwrap()) + .replace_children(&tiles); } else { let player = Player { name: msg @@ -211,31 +225,3 @@ fn on_lobby_insert_update( next_gamestate.set(msg.new.game_state.into()); } } - -fn on_hand_insert_update( - stdb: SpacetimeDB, - mut messages: ReadInsertUpdateMessage, - - mut commands: Commands, - tiles: Query<(&Tile, Entity)>, - hand_ent: Single>, -) { - for msg in messages.read() { - trace!("view_hand"); - let mut view: Vec<_> = msg.new.tiles.iter().map(Tile::from).collect(); - let tiles = tiles - .iter() - .filter(|(tt, _)| { - if let Some((i, _)) = view.iter().enumerate().find(|(_, t)| t == tt) { - view.swap_remove(i); - true - } else { - false - } - }) - .map(|(_, e)| e) - .collect::>(); - - commands.entity(*hand_ent).replace_children(&tiles); - } -} diff --git a/jong/src/stdb/bot_table.rs b/jong/src/stdb/bot_table.rs index 9e4c080..6d53305 100644 --- a/jong/src/stdb/bot_table.rs +++ b/jong/src/stdb/bot_table.rs @@ -3,6 +3,7 @@ #![allow(unused, clippy::all)] use super::bot_type::Bot; +use super::tile_type::Tile; use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; /// Table handle for the table `bot`. diff --git a/jong/src/stdb/bot_type.rs b/jong/src/stdb/bot_type.rs index 0d4fd2c..deaeada 100644 --- a/jong/src/stdb/bot_type.rs +++ b/jong/src/stdb/bot_type.rs @@ -4,13 +4,15 @@ #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; +use super::tile_type::Tile; + #[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] #[sats(crate = __lib)] pub struct Bot { pub id: u32, pub lobby_id: u32, - pub hand_id: u32, - pub pond_id: u32, + pub hand: Vec, + pub pond: Vec, } impl __sdk::InModule for Bot { diff --git a/jong/src/stdb/hand_table.rs b/jong/src/stdb/hand_table.rs deleted file mode 100644 index d967559..0000000 --- a/jong/src/stdb/hand_table.rs +++ /dev/null @@ -1,144 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::hand_type::Hand; -use super::player_or_bot_type::PlayerOrBot; -use super::tile_type::Tile; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `hand`. -/// -/// Obtain a handle from the [`HandTableAccess::hand`] method on [`super::RemoteTables`], -/// like `ctx.db.hand()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.hand().on_insert(...)`. -pub struct HandTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `hand`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait HandTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`HandTableHandle`], which mediates access to the table `hand`. - fn hand(&self) -> HandTableHandle<'_>; -} - -impl HandTableAccess for super::RemoteTables { - fn hand(&self) -> HandTableHandle<'_> { - HandTableHandle { - imp: self.imp.get_table::("hand"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct HandInsertCallbackId(__sdk::CallbackId); -pub struct HandDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::Table for HandTableHandle<'ctx> { - type Row = Hand; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = HandInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> HandInsertCallbackId { - HandInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: HandInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = HandDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> HandDeleteCallbackId { - HandDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: HandDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("hand"); - _table.add_unique_constraint::("id", |row| &row.id); -} -pub struct HandUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for HandTableHandle<'ctx> { - type UpdateCallbackId = HandUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> HandUpdateCallbackId { - HandUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: HandUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::TableUpdate<__ws::BsatnFormat>, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -/// Access to the `id` unique index on the table `hand`, -/// which allows point queries on the field of the same name -/// via the [`HandIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.hand().id().find(...)`. -pub struct HandIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> HandTableHandle<'ctx> { - /// Get a handle on the `id` unique index on the table `hand`. - pub fn id(&self) -> HandIdUnique<'ctx> { - HandIdUnique { - imp: self.imp.get_unique_constraint::("id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> HandIdUnique<'ctx> { - /// Find the subscribed row whose `id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &u32) -> Option { - self.imp.find(col_val) - } -} diff --git a/jong/src/stdb/hand_type.rs b/jong/src/stdb/hand_type.rs deleted file mode 100644 index 2c4f86b..0000000 --- a/jong/src/stdb/hand_type.rs +++ /dev/null @@ -1,21 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::player_or_bot_type::PlayerOrBot; -use super::tile_type::Tile; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct Hand { - pub id: u32, - pub owner: PlayerOrBot, - pub sort: bool, - pub tiles: Vec, -} - -impl __sdk::InModule for Hand { - type Module = super::RemoteModule; -} diff --git a/jong/src/stdb/mod.rs b/jong/src/stdb/mod.rs index 356ab0c..5c7e382 100644 --- a/jong/src/stdb/mod.rs +++ b/jong/src/stdb/mod.rs @@ -11,8 +11,6 @@ pub mod bot_table; pub mod bot_type; pub mod dragon_type; pub mod game_state_type; -pub mod hand_table; -pub mod hand_type; pub mod join_or_create_lobby_reducer; pub mod lobby_table; pub mod lobby_type; @@ -20,8 +18,6 @@ pub mod login_or_add_player_reducer; pub mod player_or_bot_type; pub mod player_table; pub mod player_type; -pub mod pond_table; -pub mod pond_type; pub mod rank_type; pub mod set_ready_reducer; pub mod shuffle_deal_reducer; @@ -29,7 +25,6 @@ pub mod start_game_reducer; pub mod suit_type; pub mod tile_type; pub mod turn_state_type; -pub mod view_player_hand_table; pub mod wall_table; pub mod wall_type; pub mod wind_type; @@ -39,8 +34,6 @@ pub use bot_table::*; pub use bot_type::Bot; pub use dragon_type::Dragon; pub use game_state_type::GameState; -pub use hand_table::*; -pub use hand_type::Hand; pub use join_or_create_lobby_reducer::{ join_or_create_lobby, set_flags_for_join_or_create_lobby, JoinOrCreateLobbyCallbackId, }; @@ -52,8 +45,6 @@ pub use login_or_add_player_reducer::{ pub use player_or_bot_type::PlayerOrBot; pub use player_table::*; pub use player_type::Player; -pub use pond_table::*; -pub use pond_type::Pond; pub use rank_type::Rank; pub use set_ready_reducer::{set_flags_for_set_ready, set_ready, SetReadyCallbackId}; pub use shuffle_deal_reducer::{set_flags_for_shuffle_deal, shuffle_deal, ShuffleDealCallbackId}; @@ -61,7 +52,6 @@ pub use start_game_reducer::{set_flags_for_start_game, start_game, StartGameCall pub use suit_type::Suit; pub use tile_type::Tile; pub use turn_state_type::TurnState; -pub use view_player_hand_table::*; pub use wall_table::*; pub use wall_type::Wall; pub use wind_type::Wind; @@ -152,11 +142,8 @@ impl TryFrom<__ws::ReducerCallInfo<__ws::BsatnFormat>> for Reducer { #[doc(hidden)] pub struct DbUpdate { bot: __sdk::TableUpdate, - hand: __sdk::TableUpdate, lobby: __sdk::TableUpdate, player: __sdk::TableUpdate, - pond: __sdk::TableUpdate, - view_player_hand: __sdk::TableUpdate, wall: __sdk::TableUpdate, } @@ -169,21 +156,12 @@ impl TryFrom<__ws::DatabaseUpdate<__ws::BsatnFormat>> for DbUpdate { "bot" => db_update .bot .append(bot_table::parse_table_update(table_update)?), - "hand" => db_update - .hand - .append(hand_table::parse_table_update(table_update)?), "lobby" => db_update .lobby .append(lobby_table::parse_table_update(table_update)?), "player" => db_update .player .append(player_table::parse_table_update(table_update)?), - "pond" => db_update - .pond - .append(pond_table::parse_table_update(table_update)?), - "view_player_hand" => db_update - .view_player_hand - .append(view_player_hand_table::parse_table_update(table_update)?), "wall" => db_update .wall .append(wall_table::parse_table_update(table_update)?), @@ -216,23 +194,15 @@ impl __sdk::DbUpdate for DbUpdate { diff.bot = cache .apply_diff_to_table::("bot", &self.bot) .with_updates_by_pk(|row| &row.id); - diff.hand = cache - .apply_diff_to_table::("hand", &self.hand) - .with_updates_by_pk(|row| &row.id); diff.lobby = cache .apply_diff_to_table::("lobby", &self.lobby) .with_updates_by_pk(|row| &row.id); diff.player = cache .apply_diff_to_table::("player", &self.player) .with_updates_by_pk(|row| &row.identity); - diff.pond = cache - .apply_diff_to_table::("pond", &self.pond) - .with_updates_by_pk(|row| &row.id); diff.wall = cache .apply_diff_to_table::("wall", &self.wall) .with_updates_by_pk(|row| &row.lobby_id); - diff.view_player_hand = - cache.apply_diff_to_table::("view_player_hand", &self.view_player_hand); diff } @@ -243,11 +213,8 @@ impl __sdk::DbUpdate for DbUpdate { #[doc(hidden)] pub struct AppliedDiff<'r> { bot: __sdk::TableAppliedDiff<'r, Bot>, - hand: __sdk::TableAppliedDiff<'r, Hand>, lobby: __sdk::TableAppliedDiff<'r, Lobby>, player: __sdk::TableAppliedDiff<'r, Player>, - pond: __sdk::TableAppliedDiff<'r, Pond>, - view_player_hand: __sdk::TableAppliedDiff<'r, Hand>, wall: __sdk::TableAppliedDiff<'r, Wall>, __unused: std::marker::PhantomData<&'r ()>, } @@ -263,15 +230,8 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { callbacks: &mut __sdk::DbCallbacks, ) { callbacks.invoke_table_row_callbacks::("bot", &self.bot, event); - callbacks.invoke_table_row_callbacks::("hand", &self.hand, event); callbacks.invoke_table_row_callbacks::("lobby", &self.lobby, event); callbacks.invoke_table_row_callbacks::("player", &self.player, event); - callbacks.invoke_table_row_callbacks::("pond", &self.pond, event); - callbacks.invoke_table_row_callbacks::( - "view_player_hand", - &self.view_player_hand, - event, - ); callbacks.invoke_table_row_callbacks::("wall", &self.wall, event); } } @@ -993,11 +953,8 @@ impl __sdk::SpacetimeModule for RemoteModule { fn register_tables(client_cache: &mut __sdk::ClientCache) { bot_table::register_table(client_cache); - hand_table::register_table(client_cache); lobby_table::register_table(client_cache); player_table::register_table(client_cache); - pond_table::register_table(client_cache); - view_player_hand_table::register_table(client_cache); wall_table::register_table(client_cache); } } diff --git a/jong/src/stdb/player_table.rs b/jong/src/stdb/player_table.rs index 93eb034..2cfb5b3 100644 --- a/jong/src/stdb/player_table.rs +++ b/jong/src/stdb/player_table.rs @@ -3,6 +3,7 @@ #![allow(unused, clippy::all)] use super::player_type::Player; +use super::tile_type::Tile; use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; /// Table handle for the table `player`. diff --git a/jong/src/stdb/player_type.rs b/jong/src/stdb/player_type.rs index 311ac9b..269c160 100644 --- a/jong/src/stdb/player_type.rs +++ b/jong/src/stdb/player_type.rs @@ -4,6 +4,8 @@ #![allow(unused, clippy::all)] use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; +use super::tile_type::Tile; + #[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] #[sats(crate = __lib)] pub struct Player { @@ -11,9 +13,10 @@ pub struct Player { pub id: u32, pub name: Option, pub lobby_id: u32, - pub hand_id: u32, - pub pond_id: u32, pub ready: bool, + pub sort: bool, + pub hand: Vec, + pub pond: Vec, } impl __sdk::InModule for Player { diff --git a/jong/src/stdb/pond_table.rs b/jong/src/stdb/pond_table.rs deleted file mode 100644 index 9f079c2..0000000 --- a/jong/src/stdb/pond_table.rs +++ /dev/null @@ -1,144 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::player_or_bot_type::PlayerOrBot; -use super::pond_type::Pond; -use super::tile_type::Tile; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `pond`. -/// -/// Obtain a handle from the [`PondTableAccess::pond`] method on [`super::RemoteTables`], -/// like `ctx.db.pond()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.pond().on_insert(...)`. -pub struct PondTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `pond`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait PondTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`PondTableHandle`], which mediates access to the table `pond`. - fn pond(&self) -> PondTableHandle<'_>; -} - -impl PondTableAccess for super::RemoteTables { - fn pond(&self) -> PondTableHandle<'_> { - PondTableHandle { - imp: self.imp.get_table::("pond"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct PondInsertCallbackId(__sdk::CallbackId); -pub struct PondDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::Table for PondTableHandle<'ctx> { - type Row = Pond; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = PondInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PondInsertCallbackId { - PondInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: PondInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = PondDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> PondDeleteCallbackId { - PondDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: PondDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("pond"); - _table.add_unique_constraint::("id", |row| &row.id); -} -pub struct PondUpdateCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::TableWithPrimaryKey for PondTableHandle<'ctx> { - type UpdateCallbackId = PondUpdateCallbackId; - - fn on_update( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, - ) -> PondUpdateCallbackId { - PondUpdateCallbackId(self.imp.on_update(Box::new(callback))) - } - - fn remove_on_update(&self, callback: PondUpdateCallbackId) { - self.imp.remove_on_update(callback.0) - } -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::TableUpdate<__ws::BsatnFormat>, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} - -/// Access to the `id` unique index on the table `pond`, -/// which allows point queries on the field of the same name -/// via the [`PondIdUnique::find`] method. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.pond().id().find(...)`. -pub struct PondIdUnique<'ctx> { - imp: __sdk::UniqueConstraintHandle, - phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -impl<'ctx> PondTableHandle<'ctx> { - /// Get a handle on the `id` unique index on the table `pond`. - pub fn id(&self) -> PondIdUnique<'ctx> { - PondIdUnique { - imp: self.imp.get_unique_constraint::("id"), - phantom: std::marker::PhantomData, - } - } -} - -impl<'ctx> PondIdUnique<'ctx> { - /// Find the subscribed row whose `id` column value is equal to `col_val`, - /// if such a row is present in the client cache. - pub fn find(&self, col_val: &u32) -> Option { - self.imp.find(col_val) - } -} diff --git a/jong/src/stdb/pond_type.rs b/jong/src/stdb/pond_type.rs deleted file mode 100644 index bf08228..0000000 --- a/jong/src/stdb/pond_type.rs +++ /dev/null @@ -1,20 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -use super::player_or_bot_type::PlayerOrBot; -use super::tile_type::Tile; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct Pond { - pub id: u32, - pub owner: PlayerOrBot, - pub tiles: Vec, -} - -impl __sdk::InModule for Pond { - type Module = super::RemoteModule; -} diff --git a/jong/src/stdb/view_player_hand_table.rs b/jong/src/stdb/view_player_hand_table.rs deleted file mode 100644 index 82cfb91..0000000 --- a/jong/src/stdb/view_player_hand_table.rs +++ /dev/null @@ -1,97 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE -// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. - -#![allow(unused, clippy::all)] -use super::hand_type::Hand; -use super::player_or_bot_type::PlayerOrBot; -use super::tile_type::Tile; -use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; - -/// Table handle for the table `view_player_hand`. -/// -/// Obtain a handle from the [`ViewPlayerHandTableAccess::view_player_hand`] method on [`super::RemoteTables`], -/// like `ctx.db.view_player_hand()`. -/// -/// Users are encouraged not to explicitly reference this type, -/// but to directly chain method calls, -/// like `ctx.db.view_player_hand().on_insert(...)`. -pub struct ViewPlayerHandTableHandle<'ctx> { - imp: __sdk::TableHandle, - ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, -} - -#[allow(non_camel_case_types)] -/// Extension trait for access to the table `view_player_hand`. -/// -/// Implemented for [`super::RemoteTables`]. -pub trait ViewPlayerHandTableAccess { - #[allow(non_snake_case)] - /// Obtain a [`ViewPlayerHandTableHandle`], which mediates access to the table `view_player_hand`. - fn view_player_hand(&self) -> ViewPlayerHandTableHandle<'_>; -} - -impl ViewPlayerHandTableAccess for super::RemoteTables { - fn view_player_hand(&self) -> ViewPlayerHandTableHandle<'_> { - ViewPlayerHandTableHandle { - imp: self.imp.get_table::("view_player_hand"), - ctx: std::marker::PhantomData, - } - } -} - -pub struct ViewPlayerHandInsertCallbackId(__sdk::CallbackId); -pub struct ViewPlayerHandDeleteCallbackId(__sdk::CallbackId); - -impl<'ctx> __sdk::Table for ViewPlayerHandTableHandle<'ctx> { - type Row = Hand; - type EventContext = super::EventContext; - - fn count(&self) -> u64 { - self.imp.count() - } - fn iter(&self) -> impl Iterator + '_ { - self.imp.iter() - } - - type InsertCallbackId = ViewPlayerHandInsertCallbackId; - - fn on_insert( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ViewPlayerHandInsertCallbackId { - ViewPlayerHandInsertCallbackId(self.imp.on_insert(Box::new(callback))) - } - - fn remove_on_insert(&self, callback: ViewPlayerHandInsertCallbackId) { - self.imp.remove_on_insert(callback.0) - } - - type DeleteCallbackId = ViewPlayerHandDeleteCallbackId; - - fn on_delete( - &self, - callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, - ) -> ViewPlayerHandDeleteCallbackId { - ViewPlayerHandDeleteCallbackId(self.imp.on_delete(Box::new(callback))) - } - - fn remove_on_delete(&self, callback: ViewPlayerHandDeleteCallbackId) { - self.imp.remove_on_delete(callback.0) - } -} - -#[doc(hidden)] -pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("view_player_hand"); -} - -#[doc(hidden)] -pub(super) fn parse_table_update( - raw_updates: __ws::TableUpdate<__ws::BsatnFormat>, -) -> __sdk::Result<__sdk::TableUpdate> { - __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") - .with_cause(e) - .into() - }) -} diff --git a/spacetimedb/src/game.rs b/spacetimedb/src/game.rs index 07eff79..8777e2d 100644 --- a/spacetimedb/src/game.rs +++ b/spacetimedb/src/game.rs @@ -50,8 +50,8 @@ pub fn add_bot(ctx: &ReducerContext, lobby_id: u32) -> Result<(), String> { let bot = ctx.db.bot().insert(Bot { id: 0, lobby_id, - hand_id: 0, - pond_id: 0, + hand: vec![], + pond: vec![], }); lobby.players.push(PlayerOrBot::Bot { id: bot.id }); ctx.db.lobby().id().update(lobby); diff --git a/spacetimedb/src/game/hand.rs b/spacetimedb/src/game/hand.rs index adc9845..294b6d9 100644 --- a/spacetimedb/src/game/hand.rs +++ b/spacetimedb/src/game/hand.rs @@ -12,40 +12,28 @@ pub fn deal_hands(ctx: &ReducerContext, lobby_id: u32) { // FIXME rectify deal orders for mut player in players { let mut tiles = wall.tiles.split_off(wall.tiles.len() - 13); - tiles.sort(); wall = ctx.db.wall().lobby_id().update(wall); - let hand = ctx.db.hand().insert(Hand { - id: 0, - owner: PlayerOrBot::Player { id: player.id }, - sort: true, - tiles, - }); - player.hand_id = hand.id; + tiles.sort(); + player.hand = tiles; ctx.db.player().id().update(player); } for mut bot in bots { let mut tiles = wall.tiles.split_off(wall.tiles.len() - 13); - tiles.sort(); wall = ctx.db.wall().lobby_id().update(wall); - let hand = ctx.db.hand().insert(Hand { - id: 0, - owner: PlayerOrBot::Bot { id: bot.id }, - sort: true, - tiles, - }); - bot.hand_id = hand.id; + tiles.sort(); + bot.hand = tiles; ctx.db.bot().id().update(bot); } } -#[view(name = view_player_hand, public)] -pub fn view_player_hand(ctx: &ViewContext) -> Option { - ctx.db - .player() - .identity() - .find(ctx.sender) - .map(|p| ctx.db.hand().id().find(p.hand_id))? -} +// #[view(name = view_player_hand, public)] +// pub fn view_player_hand(ctx: &ViewContext) -> Option { +// ctx.db +// .player() +// .identity() +// .find(ctx.sender) +// .map(|p| ctx.db.hand().id().find(p.hand_id))? +// } // #[reducer] // pub fn sort_hand(ctx: &ReducerContext) { diff --git a/spacetimedb/src/lib.rs b/spacetimedb/src/lib.rs index 3af5855..2c6d8d1 100644 --- a/spacetimedb/src/lib.rs +++ b/spacetimedb/src/lib.rs @@ -16,9 +16,10 @@ pub fn login_or_add_player(ctx: &ReducerContext) { id: 0, name: None, lobby_id: 0, - hand_id: 0, - pond_id: 0, ready: false, + sort: true, + hand: vec![], + pond: vec![], }) { info!("added player: {:?}", player); } else { diff --git a/spacetimedb/src/tables.rs b/spacetimedb/src/tables.rs index f92657c..4e84432 100644 --- a/spacetimedb/src/tables.rs +++ b/spacetimedb/src/tables.rs @@ -27,34 +27,3 @@ pub struct Wall { pub tiles: Vec, } - -// TODO temp use deprecated RLS instead of view until bevy_spacetimedb supp is better -#[client_visibility_filter] -const HAND_FILTER: Filter = Filter::Sql( - "SELECT h.* FROM hand h - JOIN player p ON h.id = p.hand_id - WHERE p.identity = :sender", -); - -#[table(name = hand, public)] -pub struct Hand { - #[primary_key] - #[auto_inc] - pub id: u32, - - pub owner: player::PlayerOrBot, - - pub sort: bool, - pub tiles: Vec, -} - -#[table(name = pond, public)] -pub struct Pond { - #[primary_key] - #[auto_inc] - pub id: u32, - - pub owner: player::PlayerOrBot, - - pub tiles: Vec, -} diff --git a/spacetimedb/src/tables/player.rs b/spacetimedb/src/tables/player.rs index 0f580df..ab03a06 100644 --- a/spacetimedb/src/tables/player.rs +++ b/spacetimedb/src/tables/player.rs @@ -1,6 +1,8 @@ use spacetimedb::Identity; use spacetimedb::{SpacetimeType, table}; +use jong_types::*; + #[derive(Debug)] #[table(name = player, public)] pub struct Player { @@ -15,10 +17,12 @@ pub struct Player { #[index(btree)] pub lobby_id: u32, - pub hand_id: u32, - pub pond_id: u32, - pub ready: bool, + + pub sort: bool, + + pub hand: Vec, + pub pond: Vec, } #[table(name = bot)] @@ -29,8 +33,9 @@ pub struct Bot { #[index(btree)] pub lobby_id: u32, - pub hand_id: u32, - pub pond_id: u32, + + pub hand: Vec, + pub pond: Vec, } #[derive(Debug, Clone, SpacetimeType)]