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/game.rs b/jong/src/game.rs index 571e066..d22b3cc 100644 --- a/jong/src/game.rs +++ b/jong/src/game.rs @@ -1,17 +1,28 @@ +#![allow(unused)] + use bevy::prelude::*; use bevy_spacetimedb::{ ReadInsertUpdateMessage, ReadStdbConnectedMessage, ReadStdbDisconnectedMessage, StdbPlugin, + TableMessages, }; -use spacetimedb_sdk::{DbContext, Table}; +use spacetimedb::Identity; +use spacetimedb_sdk::{DbContext, Table, credentials}; use crate::stdb::{self, DbConnection, LobbyTableAccess, PlayerTableAccess, RemoteTables}; use crate::stdb::{ - add_bot, draw_tile, set_ready, shuffle_deal, + add_bot, draw_tile, join_or_create_lobby, login_or_add_player, set_ready, shuffle_deal, skip_call, start_game, }; use crate::{ SpacetimeDB, creds_store, - game::hand::{Drawn, Hand, Pond}, + game::{ + self, + hand::{Drawn, Hand, Pond}, + player::{CurrentPlayer, MainPlayer, Player}, + round::Wind, + wall::Wall, + }, + tile::{self}, }; use jong_types::*; @@ -20,10 +31,17 @@ pub mod player; pub mod round; pub mod wall; +#[derive(Message)] +pub enum GameMessage { + Discarded(Entity), + CallPending, + Called { player: Entity, calltype: Entity }, +} + pub struct Riichi; impl Plugin for Riichi { fn build(&self, app: &mut App) { - let plugins = StdbPlugin::default() + let mut plugins = StdbPlugin::default() .with_uri("http://localhost:3000") .with_module_name("jongline") .with_run_fn(DbConnection::run_threaded) @@ -48,6 +66,7 @@ impl Plugin for Riichi { .add_sub_state::() // .init_resource::() // .init_resource::() + .add_message::() // .add_systems(Startup, tile::init_tiles) // .add_systems(Update, hand::sort_hands.run_if(in_state(GameState::Play))) // .add_systems(OnEnter(TurnState::Tsumo), round::tsumo) @@ -69,12 +88,9 @@ impl Plugin for Riichi { ; } } -fn on_connect(stdb: SpacetimeDB, mut messages: ReadStdbConnectedMessage, _commands: Commands) { +fn on_connect(stdb: SpacetimeDB, mut messages: ReadStdbConnectedMessage, mut commands: Commands) { for msg in messages.read() { info!("you're now jongline"); - - while stdb.try_identity().is_none() {} - debug!("with identity: {}", stdb.identity()); creds_store() .save(&msg.access_token) @@ -83,7 +99,7 @@ fn on_connect(stdb: SpacetimeDB, mut messages: ReadStdbConnectedMessage, _comman } // TODO how reconnect? -fn on_disconnect(_stdb: SpacetimeDB, mut messages: ReadStdbDisconnectedMessage) { +fn on_disconnect(stdb: SpacetimeDB, mut messages: ReadStdbDisconnectedMessage) { for msg in messages.read() { warn!("lost connection: {:#?}", msg.err); } @@ -107,26 +123,26 @@ fn subscriptions(stdb: SpacetimeDB) { pub struct TileId(pub u32); fn on_player_insert_update( - _stdb: SpacetimeDB, + stdb: SpacetimeDB, mut messages: ReadInsertUpdateMessage, mut commands: Commands, tiles: Query<(&Tile, &TileId, Entity)>, - player: Option>, - hand_ent: Option>>, + mut player: Option>, + mut hand_ent: Option>>, ) { use player::*; for msg in messages.read() { // debug!("player_insert_update msg:\n{:#?}", msg.new); - if let (Some(_player), Some(hand_ent)) = (player.as_ref(), hand_ent.as_ref()) { + if let (Some(player), Some(hand_ent)) = (player.as_ref(), hand_ent.as_ref()) { // 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 tiles: Vec<_> = msg + let mut tiles: Vec<_> = msg .new .hand .iter() @@ -166,7 +182,7 @@ fn on_lobby_insert_update( stdb: SpacetimeDB, mut messages: ReadInsertUpdateMessage, - _commands: Commands, + mut commands: Commands, mut next_gamestate: ResMut>, mut next_turnstate: ResMut>, ) { diff --git a/jong/src/game/hand.rs b/jong/src/game/hand.rs index 2387f4a..4e89c13 100644 --- a/jong/src/game/hand.rs +++ b/jong/src/game/hand.rs @@ -1,6 +1,8 @@ +use std::mem::discriminant; use bevy::prelude::*; +use crate::game::{GameState, player::Player, wall::Wall}; use jong_types::*; #[derive(Component)] @@ -24,7 +26,7 @@ pub struct Discarded; // } /// assumes hand is sorted -pub(crate) fn check_wincon(_hand: &[Tile; 14], _melds: &[&[Tile]]) -> bool { +pub(crate) fn check_wincon(hand: &[Tile; 14], melds: &[&[Tile]]) -> bool { // 4x3 + pair // assume sorted // diff --git a/jong/src/game/round.rs b/jong/src/game/round.rs index 031e8ed..9953c57 100644 --- a/jong/src/game/round.rs +++ b/jong/src/game/round.rs @@ -1,8 +1,17 @@ +use std::rc::Weak; use bevy::{platform::collections::HashMap, prelude::*}; use strum::{EnumCount, FromRepr}; -use crate::EnumNextCycle; +use crate::{ + EnumNextCycle, + game::{ + GameMessage, GameState, + hand::{Discarded, Drawn, Hand, Pond}, + player::{CurrentPlayer, Player}, + wall::Wall, + }, +}; use jong_types::TurnState; // #[derive(Resource)] @@ -102,85 +111,85 @@ impl EnumNextCycle for TurnState { } } -// pub(crate) fn tsumo( -// mut commands: Commands, +pub(crate) fn tsumo( + mut commands: Commands, -// // curr_player: Res, -// curr_player: Single>, -// wall: Single>, -// walltiles: Single<&Children, With>, + // curr_player: Res, + curr_player: Single>, + wall: Single>, + walltiles: Single<&Children, With>, -// curr_turnstate: Res>, -// mut next_turnstate: ResMut>, -// ) { -// let drawn = walltiles.last().unwrap(); -// commands.entity(*wall).remove_child(*drawn); + curr_turnstate: Res>, + mut next_turnstate: ResMut>, +) { + let drawn = walltiles.last().unwrap(); + commands.entity(*wall).remove_child(*drawn); -// let drawn = commands.entity(*drawn).insert(Drawn).id(); -// commands.entity(*curr_player).add_child(drawn); + let drawn = commands.entity(*drawn).insert(Drawn).id(); + commands.entity(*curr_player).add_child(drawn); -// debug!("tsumo for: {:?}, tile: {:?}", *curr_player, drawn); -// next_turnstate.set(curr_turnstate.next()); -// } + debug!("tsumo for: {:?}, tile: {:?}", *curr_player, drawn); + next_turnstate.set(curr_turnstate.next()); +} -// pub(crate) fn menzen( -// curr_turnstate: Res>, -// mut next_turnstate: ResMut>, -// ) { -// trace!("menzen check"); -// next_turnstate.set(curr_turnstate.next()); -// } +pub(crate) fn menzen( + curr_turnstate: Res>, + mut next_turnstate: ResMut>, +) { + trace!("menzen check"); + next_turnstate.set(curr_turnstate.next()); +} -// pub(crate) fn riichi_kan( -// curr_turnstate: Res>, -// mut next_turnstate: ResMut>, -// ) { -// trace!("riichi_kan"); -// next_turnstate.set(curr_turnstate.next()); -// } +pub(crate) fn riichi_kan( + curr_turnstate: Res>, + mut next_turnstate: ResMut>, +) { + trace!("riichi_kan"); + next_turnstate.set(curr_turnstate.next()); +} -// #[allow(clippy::too_many_arguments, irrefutable_let_patterns)] -// pub(crate) fn discard( -// mut commands: Commands, -// mut reader: MessageReader, +#[allow(clippy::too_many_arguments, irrefutable_let_patterns)] +pub(crate) fn discard( + mut commands: Commands, + mut reader: MessageReader, -// curr_player: Single>, -// players: Query<&Children, With>, -// mut hands: Query<(&Children, Entity), (With, Without)>, -// drawn: Single>, + curr_player: Single>, + players: Query<&Children, With>, + mut hands: Query<(&Children, Entity), (With, Without)>, + drawn: Single>, -// curr_turnstate: Res>, -// mut next_turnstate: ResMut>, -// ) -> Result { -// // trace!("discard"); -// let (handtiles, hand) = hands.get_mut(players.get(*curr_player)?.iter().next().unwrap())?; + curr_turnstate: Res>, + mut next_turnstate: ResMut>, +) -> Result { + // trace!("discard"); + let (handtiles, hand) = hands.get_mut(players.get(*curr_player)?.iter().next().unwrap())?; -// let mut done = false; -// while let Some(message) = reader.read().next() { -// if let GameMessage::Discarded(discarded) = message { -// debug!("discarded: {discarded:?}"); -// if *discarded == *drawn { -// } else if handtiles.contains(discarded) { -// commands -// .entity(hand) -// .remove_child(*discarded) -// .add_child(*drawn); -// } else { -// panic!("current hand nor drawn tile contains discarded tile") -// } -// commands.entity(*drawn).remove::(); -// commands.entity(*discarded).insert(Discarded); + let mut done = false; + while let Some(message) = reader.read().next() { + if let GameMessage::Discarded(discarded) = message { + debug!("discarded: {discarded:?}"); + if *discarded == *drawn { + } else if handtiles.contains(discarded) { + commands + .entity(hand) + .remove_child(*discarded) + .add_child(*drawn); + } else { + panic!("current hand nor drawn tile contains discarded tile") + } + commands.entity(*drawn).remove::(); + commands.entity(*discarded).insert(Discarded); -// done = true; -// break; -// } -// } + done = true; + break; + } + } -// if done { -// next_turnstate.set(curr_turnstate.next()); -// } -// Ok(()) -// } + if done { + next_turnstate.set(curr_turnstate.next()); + } + Ok(()) +} #[derive(Resource)] pub struct PendingCalls { @@ -188,45 +197,45 @@ pub struct PendingCalls { calls: HashMap, } -// pub(crate) fn notify_callable() {} +pub(crate) fn notify_callable() {} -// pub(crate) fn ron_chi_pon_kan( -// mut commands: Commands, -// mut reader: MessageReader, +pub(crate) fn ron_chi_pon_kan( + mut commands: Commands, + mut reader: MessageReader, -// discarded: Single>, -// mut ponds: Query<(&Children, Entity), (With, Without)>, -// calls: Query<&CallType>, + discarded: Single>, + mut ponds: Query<(&Children, Entity), (With, Without)>, + calls: Query<&CallType>, -// curr_turnstate: Res>, -// mut next_turnstate: ResMut>, -// ) { -// // check if can call? -// // message players? -// // collect then prioritize + curr_turnstate: Res>, + mut next_turnstate: ResMut>, +) { + // check if can call? + // message players? + // collect then prioritize -// // let mut received = vec![]; -// let mut received: Vec<_> = reader -// .read() -// .filter_map(|m| { -// if let GameMessage::Called { player, calltype } = m -// && let Ok(calltype) = calls.get(*calltype) -// { -// Some((calltype, player)) -// } else { -// None -// } -// }) -// .collect(); -// // received.sort_unstable_by_key(|(c, t)| c); -// // received.sort_unstable_by_key(|m| m.); + // let mut received = vec![]; + let mut received: Vec<_> = reader + .read() + .filter_map(|m| { + if let GameMessage::Called { player, calltype } = m + && let Ok(calltype) = calls.get(*calltype) + { + Some((calltype, player)) + } else { + None + } + }) + .collect(); + // received.sort_unstable_by_key(|(c, t)| c); + // received.sort_unstable_by_key(|m| m.); -// next_turnstate.set(curr_turnstate.next()); -// } + next_turnstate.set(curr_turnstate.next()); +} -// pub(crate) fn end( -// curr_turnstate: Res>, -// mut next_turnstate: ResMut>, -// ) { -// next_turnstate.set(curr_turnstate.next()); -// } +pub(crate) fn end( + curr_turnstate: Res>, + mut next_turnstate: ResMut>, +) { + next_turnstate.set(curr_turnstate.next()); +} diff --git a/jong/src/main.rs b/jong/src/main.rs index 66cb09b..b29e0e9 100644 --- a/jong/src/main.rs +++ b/jong/src/main.rs @@ -1,4 +1,5 @@ use bevy::{log::LogPlugin, prelude::*}; +use bevy_spacetimedb::{StdbConnection, StdbPlugin}; use clap::{Parser, Subcommand}; use tracing::Level; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; @@ -41,6 +42,7 @@ fn main() { tui_logger::init_logger(tui_logger::LevelFilter::Trace).unwrap(); tui_logger::set_env_filter_from_string(FILTERSTRING); + // app.add_plugins(tui::RiichiTui) app.add_plugins(tui::TuiPlugin) } }; diff --git a/jong/src/stdb/clear_all_reducer.rs b/jong/src/stdb/clear_all_reducer.rs deleted file mode 100644 index 5870024..0000000 --- a/jong/src/stdb/clear_all_reducer.rs +++ /dev/null @@ -1,100 +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}; - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub(super) struct ClearAllArgs {} - -impl From for super::Reducer { - fn from(args: ClearAllArgs) -> Self { - Self::ClearAll - } -} - -impl __sdk::InModule for ClearAllArgs { - type Module = super::RemoteModule; -} - -pub struct ClearAllCallbackId(__sdk::CallbackId); - -#[allow(non_camel_case_types)] -/// Extension trait for access to the reducer `clear_all`. -/// -/// Implemented for [`super::RemoteReducers`]. -pub trait clear_all { - /// Request that the remote module invoke the reducer `clear_all` to run as soon as possible. - /// - /// This method returns immediately, and errors only if we are unable to send the request. - /// The reducer will run asynchronously in the future, - /// and its status can be observed by listening for [`Self::on_clear_all`] callbacks. - fn clear_all(&self) -> __sdk::Result<()>; - /// Register a callback to run whenever we are notified of an invocation of the reducer `clear_all`. - /// - /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] - /// to determine the reducer's status. - /// - /// The returned [`ClearAllCallbackId`] can be passed to [`Self::remove_on_clear_all`] - /// to cancel the callback. - fn on_clear_all( - &self, - callback: impl FnMut(&super::ReducerEventContext) + Send + 'static, - ) -> ClearAllCallbackId; - /// Cancel a callback previously registered by [`Self::on_clear_all`], - /// causing it not to run in the future. - fn remove_on_clear_all(&self, callback: ClearAllCallbackId); -} - -impl clear_all for super::RemoteReducers { - fn clear_all(&self) -> __sdk::Result<()> { - self.imp.call_reducer("clear_all", ClearAllArgs {}) - } - fn on_clear_all( - &self, - mut callback: impl FnMut(&super::ReducerEventContext) + Send + 'static, - ) -> ClearAllCallbackId { - ClearAllCallbackId(self.imp.on_reducer( - "clear_all", - Box::new(move |ctx: &super::ReducerEventContext| { - #[allow(irrefutable_let_patterns)] - let super::ReducerEventContext { - event: - __sdk::ReducerEvent { - reducer: super::Reducer::ClearAll {}, - .. - }, - .. - } = ctx - else { - unreachable!() - }; - callback(ctx) - }), - )) - } - fn remove_on_clear_all(&self, callback: ClearAllCallbackId) { - self.imp.remove_on_reducer("clear_all", callback.0) - } -} - -#[allow(non_camel_case_types)] -#[doc(hidden)] -/// Extension trait for setting the call-flags for the reducer `clear_all`. -/// -/// Implemented for [`super::SetReducerFlags`]. -/// -/// This type is currently unstable and may be removed without a major version bump. -pub trait set_flags_for_clear_all { - /// Set the call-reducer flags for the reducer `clear_all` to `flags`. - /// - /// This type is currently unstable and may be removed without a major version bump. - fn clear_all(&self, flags: __ws::CallReducerFlags); -} - -impl set_flags_for_clear_all for super::SetReducerFlags { - fn clear_all(&self, flags: __ws::CallReducerFlags) { - self.imp.set_call_reducer_flags("clear_all", flags); - } -} diff --git a/jong/src/stdb/mod.rs b/jong/src/stdb/mod.rs index fcf6370..2784d78 100644 --- a/jong/src/stdb/mod.rs +++ b/jong/src/stdb/mod.rs @@ -9,7 +9,6 @@ use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; pub mod add_bot_reducer; pub mod bot_table; pub mod bot_type; -pub mod clear_all_reducer; pub mod db_tile_type; pub mod db_wall_type; pub mod discard_tile_reducer; @@ -38,7 +37,6 @@ pub mod wind_type; pub use add_bot_reducer::{add_bot, set_flags_for_add_bot, AddBotCallbackId}; pub use bot_table::*; pub use bot_type::Bot; -pub use clear_all_reducer::{clear_all, set_flags_for_clear_all, ClearAllCallbackId}; pub use db_tile_type::DbTile; pub use db_wall_type::DbWall; pub use discard_tile_reducer::{discard_tile, set_flags_for_discard_tile, DiscardTileCallbackId}; @@ -77,7 +75,6 @@ pub use wind_type::Wind; pub enum Reducer { AddBot { lobby_id: u32 }, - ClearAll, DiscardTile { tile_id: u32 }, DrawTile, JoinOrCreateLobby { lobby_id: u32 }, @@ -96,7 +93,6 @@ impl __sdk::Reducer for Reducer { fn reducer_name(&self) -> &'static str { match self { Reducer::AddBot { .. } => "add_bot", - Reducer::ClearAll => "clear_all", Reducer::DiscardTile { .. } => "discard_tile", Reducer::DrawTile => "draw_tile", Reducer::JoinOrCreateLobby { .. } => "join_or_create_lobby", @@ -118,13 +114,6 @@ impl TryFrom<__ws::ReducerCallInfo<__ws::BsatnFormat>> for Reducer { &value.args, )? .into()), - "clear_all" => Ok( - __sdk::parse_reducer_args::( - "clear_all", - &value.args, - )? - .into(), - ), "discard_tile" => Ok( __sdk::parse_reducer_args::( "discard_tile", diff --git a/jong/src/tui.rs b/jong/src/tui.rs index 4c6c664..6201947 100644 --- a/jong/src/tui.rs +++ b/jong/src/tui.rs @@ -13,6 +13,7 @@ use jong::stdb::{self, discard_tile as _}; use jong::{ SpacetimeDB, game::{ + GameMessage, hand::{Drawn, Hand}, player::{CurrentPlayer, Player}, }, @@ -105,6 +106,7 @@ impl Plugin for TuiPlugin { fn discard_tile( stdb: SpacetimeDB, + mut writer: MessageWriter, mut selected: MessageReader, mut commands: Commands, @@ -113,8 +115,8 @@ fn discard_tile( // player_hands: Populated<(&Player, &Children), With>, // hands: Populated<&Children, (With, Without)>, main_player: Single<(&Player, Entity), With>, - hands: Query<(&Children, Entity), With>, - tiles: Query<&TileId>, + hands: Query<(&mut Children, Entity), With >, + tiles: Populated<&TileId>, ) { // trace!("discard_tile"); @@ -123,9 +125,17 @@ fn discard_tile( while let Some(message) = selected.read().next() // && (message.0 == drawn.0 || hand.contains(&message.0)) { - if let Ok(tile_id) = tiles.get(message.0) { - stdb.reducers().discard_tile(tile_id.0).unwrap(); + if message.0 == drawn.0 { + stdb.reducers().discard_tile(drawn.1.0).unwrap(); + // commands.get_entity(drawn.0).unwrap().remove_parent_in_place(); commands.get_entity(drawn.0).unwrap().despawn(); + } else if let Some(tile_ent) = hand.iter().find(|t| *t == message.0) { + stdb.reducers() + .discard_tile(tiles.get(tile_ent).unwrap().0) + .unwrap(); } + + // FIXME check if discard actually in hand? + writer.write(GameMessage::Discarded(message.0)); } } diff --git a/justfile b/justfile index da1758e..de4df8c 100644 --- a/justfile +++ b/justfile @@ -13,7 +13,6 @@ default: just --list run-tui: - spacetime call jongline "clear_all" cargo run -- run-tui update: diff --git a/spacetimedb/src/lib.rs b/spacetimedb/src/lib.rs index 4a1b889..9589173 100644 --- a/spacetimedb/src/lib.rs +++ b/spacetimedb/src/lib.rs @@ -1,5 +1,5 @@ -use log::debug; -use spacetimedb::{ReducerContext, Table, reducer}; +use log::info; +use spacetimedb::{ReducerContext, Table, ViewContext, reducer, view}; use crate::tables::{player::player, *}; @@ -8,13 +8,6 @@ mod reducers { } mod tables; -#[reducer] -pub fn clear_all(ctx: &ReducerContext) { - for row in ctx.db.player().iter() { - ctx.db.player().delete(row); - } -} - #[reducer(client_connected)] pub fn login_or_add_player(ctx: &ReducerContext) { let identity = ctx.sender; @@ -31,10 +24,10 @@ pub fn login_or_add_player(ctx: &ReducerContext) { pond: vec![], drawn_tile: None, }) { - debug!("added player: {:?}", player); + info!("added player: {:?}", player); } else { let player = ctx.db.player().identity().find(identity).unwrap(); - debug!("player {:?} has reconnected", player) + info!("player {:?} has reconnected", player) } } diff --git a/spacetimedb/src/reducers/game.rs b/spacetimedb/src/reducers/game.rs index 0519bd2..69cf86c 100644 --- a/spacetimedb/src/reducers/game.rs +++ b/spacetimedb/src/reducers/game.rs @@ -1,4 +1,4 @@ -use log::info; +use log::{info, trace}; use spacetimedb::{ReducerContext, Table, rand::seq::SliceRandom, reducer}; use crate::tables::{player::player, *}; diff --git a/spacetimedb/src/reducers/game/deal.rs b/spacetimedb/src/reducers/game/deal.rs index 99069f6..acc74a7 100644 --- a/spacetimedb/src/reducers/game/deal.rs +++ b/spacetimedb/src/reducers/game/deal.rs @@ -1,8 +1,8 @@ -use log::debug; +use log::{debug, trace}; use spacetimedb::{ReducerContext, Table, rand::seq::SliceRandom, reducer}; use super::hand::deal_hands; -use crate::tables::*; +use crate::tables::{player::player, *}; use jong_types::*; #[reducer] diff --git a/spacetimedb/src/reducers/game/hand.rs b/spacetimedb/src/reducers/game/hand.rs index 96fedb2..b1904bc 100644 --- a/spacetimedb/src/reducers/game/hand.rs +++ b/spacetimedb/src/reducers/game/hand.rs @@ -1,5 +1,5 @@ -use log::{debug, trace}; -use spacetimedb::{ReducerContext, Table, reducer}; +use log::{debug, info, trace}; +use spacetimedb::{ReducerContext, Table, ViewContext, reducer, view}; use crate::tables::{player::player, *}; use jong_types::*; @@ -80,7 +80,7 @@ pub fn discard_tile(ctx: &ReducerContext, tile_id: u32) -> Result<(), String> { pub fn skip_call(ctx: &ReducerContext) { trace!("skip_call"); - let player = ctx.db.player().identity().find(ctx.sender).unwrap(); + let mut player = ctx.db.player().identity().find(ctx.sender).unwrap(); let mut lobby = ctx.db.lobby().id().find(player.lobby_id).unwrap(); lobby.turn_state = TurnState::Tsumo; diff --git a/spacetimedb/src/tables.rs b/spacetimedb/src/tables.rs index 4295811..6288970 100644 --- a/spacetimedb/src/tables.rs +++ b/spacetimedb/src/tables.rs @@ -1,4 +1,4 @@ -use spacetimedb::table; +use spacetimedb::{Filter, SpacetimeType, client_visibility_filter, table}; use jong_types::*;