From d183f5d993f8b0e3b605fcdd45673dfdf53a86b2 Mon Sep 17 00:00:00 2001 From: Tao Tien <29749622+taotien@users.noreply.github.com> Date: Tue, 10 Feb 2026 19:38:41 -0800 Subject: [PATCH] all clients trigger ready, then advance gamestate on last ready --- .helix/languages.toml | 10 +-- devenv.nix | 4 +- jong-types/src/lib.rs | 1 + jong/src/game.rs | 82 +++++++++++----------- jong/src/lib.rs | 4 +- jong/src/stdb/game_state_type.rs | 2 + jong/src/stdb/mod.rs | 22 ++++++ jong/src/stdb/player_type.rs | 1 + jong/src/stdb/set_ready_reducer.rs | 102 ++++++++++++++++++++++++++++ jong/src/stdb/start_game_reducer.rs | 100 +++++++++++++++++++++++++++ jong/src/tui/input/keyboard.rs | 13 ++-- jong/src/tui/render.rs | 2 +- justfile | 4 +- spacetimedb/src/game.rs | 35 ++++++++-- spacetimedb/src/game/wall.rs | 25 ++++--- spacetimedb/src/lib.rs | 8 +-- spacetimedb/src/tables.rs | 2 + states | 18 +++++ 18 files changed, 358 insertions(+), 77 deletions(-) create mode 100644 jong/src/stdb/set_ready_reducer.rs create mode 100644 jong/src/stdb/start_game_reducer.rs create mode 100644 states diff --git a/.helix/languages.toml b/.helix/languages.toml index a35a590..3b9df02 100644 --- a/.helix/languages.toml +++ b/.helix/languages.toml @@ -1,6 +1,6 @@ -[language-server.lspmux] -command = "lspmux" +# [language-server.lspmux] +# command = "lspmux" -[[language]] -name = "rust" -language-servers = ["lspmux"] +# [[language]] +# name = "rust" +# language-servers = ["lspmux"] diff --git a/devenv.nix b/devenv.nix index e1f7c55..656bae8 100644 --- a/devenv.nix +++ b/devenv.nix @@ -4,7 +4,7 @@ ... }: rec { # https://devenv.sh/processes/ - processes.lspmux.exec = "lspmux server"; + # processes.lspmux.exec = "lspmux server"; processes.spacetimedb_start.exec = "spacetime start"; processes.spacetimedb_generate_bindings = { exec = "spacetime dev --module-bindings-path jong/src/stdb jongline --delete-data=always"; @@ -18,7 +18,7 @@ # https://devenv.sh/packages/ packages = with pkgs; [ - lspmux + # lspmux pkg-config # spacetimedb diff --git a/jong-types/src/lib.rs b/jong-types/src/lib.rs index dadb0b0..4d38b2d 100644 --- a/jong-types/src/lib.rs +++ b/jong-types/src/lib.rs @@ -18,6 +18,7 @@ use strum::{EnumCount, FromRepr}; pub enum GameState { #[default] None, + Lobby, Setup, Deal, Play, diff --git a/jong/src/game.rs b/jong/src/game.rs index d84c597..cb4d61f 100644 --- a/jong/src/game.rs +++ b/jong/src/game.rs @@ -8,19 +8,17 @@ use bevy_spacetimedb::{ use spacetimedb::Identity; use spacetimedb_sdk::{DbContext, Table, credentials}; -use crate::{ - SpacetimeDB, creds_store, - game::{self, player::Player}, - stdb::{ - self, DbConnection, HandTableAccess, LobbyTableAccess, PlayerTableAccess, RemoteTables, - ViewPlayerHandTableAccess, add_bot, join_or_create_lobby, login_or_add_player, - shuffle_deal, - }, +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, }; use crate::{ + SpacetimeDB, creds_store, game::{ + self, hand::{Hand, Pond}, - player::{CurrentPlayer, MainPlayer}, + player::{CurrentPlayer, MainPlayer, Player}, round::Wind, wall::Wall, }, @@ -84,7 +82,7 @@ impl Plugin for Riichi { .add_systems(Update, on_disconnect) .add_systems(Update, on_player_insert_update) .add_systems(Update, on_lobby_insert_update) - .add_systems(OnEnter(GameState::Setup), join_or_create_lobby) + // .add_systems(OnEnter(GameState::Lobby), join_or_create_lobby) .add_systems(Update, view_hand.run_if(in_state(GameState::Play))) // semicolon stopper ; @@ -134,7 +132,11 @@ fn on_player_insert_update( for msg in messages.read() { debug!("player_insert_update msg:\n{:#?}", msg.new); if let Some(ref player) = player { - // player.as_mut() = msg.new + // 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(); + // } } else { let player = Player { name: msg @@ -150,20 +152,20 @@ fn on_player_insert_update( } } -fn join_or_create_lobby(stdb: SpacetimeDB) { - let player = stdb - .db() - .player() - .identity() - .find(&stdb.identity()) - .unwrap(); +// 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) - } -} +// 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, @@ -175,30 +177,32 @@ fn on_lobby_insert_update( for msg in messages.read() { trace!("on_lobby_insert_update msg:\n{:#?}", msg.new); + let player = stdb + .db() + .player() + .identity() + .find(&stdb.identity()) + .unwrap(); + next_gamestate.set(msg.new.game_state.into()); match msg.new.game_state { stdb::GameState::None => { trace!("game entered none"); } - stdb::GameState::Setup => { - trace!("game entered setup"); - - let player = stdb - .db() - .player() - .identity() - .find(&stdb.identity()) - .unwrap(); - - if player.lobby_id == msg.new.id { - stdb.reducers().shuffle_deal(player.lobby_id).unwrap(); + stdb::GameState::Lobby => { + trace!("game in lobby"); + if !player.ready { for _ in 0..3 { stdb.reducers().add_bot(player.lobby_id).unwrap(); } - } else { - error!("no player but game in setup") + stdb.reducers().set_ready(true).unwrap(); + stdb.reducers().start_game().unwrap(); } } + stdb::GameState::Setup => { + trace!("game entered setup"); + stdb.reducers().shuffle_deal(player.lobby_id).unwrap(); + } stdb::GameState::Deal => { trace!("game entered deal"); } @@ -209,6 +213,8 @@ fn on_lobby_insert_update( trace!("game enetered exit"); } } + + next_gamestate.set(msg.new.game_state.into()); } } diff --git a/jong/src/lib.rs b/jong/src/lib.rs index ac78c87..dc56646 100644 --- a/jong/src/lib.rs +++ b/jong/src/lib.rs @@ -5,11 +5,10 @@ use bevy_spacetimedb::StdbConnection; use spacetimedb_sdk::credentials; pub mod game; +pub mod stdb; pub mod tile; pub mod yakus; -mod stdb; - trait EnumNextCycle { fn next(&self) -> Self; } @@ -24,6 +23,7 @@ impl From for jong_types::GameState { fn from(value: stdb::GameState) -> Self { match value { stdb::GameState::None => Self::None, + stdb::GameState::Lobby => Self::Lobby, stdb::GameState::Setup => Self::Setup, stdb::GameState::Deal => Self::Deal, stdb::GameState::Play => Self::Play, diff --git a/jong/src/stdb/game_state_type.rs b/jong/src/stdb/game_state_type.rs index 2e26076..b8cafa4 100644 --- a/jong/src/stdb/game_state_type.rs +++ b/jong/src/stdb/game_state_type.rs @@ -10,6 +10,8 @@ use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; pub enum GameState { None, + Lobby, + Setup, Deal, diff --git a/jong/src/stdb/mod.rs b/jong/src/stdb/mod.rs index d46c734..356ab0c 100644 --- a/jong/src/stdb/mod.rs +++ b/jong/src/stdb/mod.rs @@ -23,7 +23,9 @@ 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; +pub mod start_game_reducer; pub mod suit_type; pub mod tile_type; pub mod turn_state_type; @@ -53,7 +55,9 @@ 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}; +pub use start_game_reducer::{set_flags_for_start_game, start_game, StartGameCallbackId}; pub use suit_type::Suit; pub use tile_type::Tile; pub use turn_state_type::TurnState; @@ -73,7 +77,9 @@ pub enum Reducer { AddBot { lobby_id: u32 }, JoinOrCreateLobby { lobby_id: u32 }, LoginOrAddPlayer, + SetReady { ready: bool }, ShuffleDeal { lobby_id: u32 }, + StartGame, } impl __sdk::InModule for Reducer { @@ -86,7 +92,9 @@ impl __sdk::Reducer for Reducer { Reducer::AddBot { .. } => "add_bot", Reducer::JoinOrCreateLobby { .. } => "join_or_create_lobby", Reducer::LoginOrAddPlayer => "login_or_add_player", + Reducer::SetReady { .. } => "set_ready", Reducer::ShuffleDeal { .. } => "shuffle_deal", + Reducer::StartGame => "start_game", _ => unreachable!(), } } @@ -108,6 +116,13 @@ impl TryFrom<__ws::ReducerCallInfo<__ws::BsatnFormat>> for Reducer { login_or_add_player_reducer::LoginOrAddPlayerArgs, >("login_or_add_player", &value.args)? .into()), + "set_ready" => Ok( + __sdk::parse_reducer_args::( + "set_ready", + &value.args, + )? + .into(), + ), "shuffle_deal" => Ok( __sdk::parse_reducer_args::( "shuffle_deal", @@ -115,6 +130,13 @@ impl TryFrom<__ws::ReducerCallInfo<__ws::BsatnFormat>> for Reducer { )? .into(), ), + "start_game" => Ok( + __sdk::parse_reducer_args::( + "start_game", + &value.args, + )? + .into(), + ), unknown => { Err( __sdk::InternalError::unknown_name("reducer", unknown, "ReducerCallInfo") diff --git a/jong/src/stdb/player_type.rs b/jong/src/stdb/player_type.rs index 0e651ec..311ac9b 100644 --- a/jong/src/stdb/player_type.rs +++ b/jong/src/stdb/player_type.rs @@ -13,6 +13,7 @@ pub struct Player { pub lobby_id: u32, pub hand_id: u32, pub pond_id: u32, + pub ready: bool, } impl __sdk::InModule for Player { diff --git a/jong/src/stdb/set_ready_reducer.rs b/jong/src/stdb/set_ready_reducer.rs new file mode 100644 index 0000000..bebd7cf --- /dev/null +++ b/jong/src/stdb/set_ready_reducer.rs @@ -0,0 +1,102 @@ +// 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 SetReadyArgs { + pub ready: bool, +} + +impl From for super::Reducer { + fn from(args: SetReadyArgs) -> Self { + Self::SetReady { ready: args.ready } + } +} + +impl __sdk::InModule for SetReadyArgs { + type Module = super::RemoteModule; +} + +pub struct SetReadyCallbackId(__sdk::CallbackId); + +#[allow(non_camel_case_types)] +/// Extension trait for access to the reducer `set_ready`. +/// +/// Implemented for [`super::RemoteReducers`]. +pub trait set_ready { + /// Request that the remote module invoke the reducer `set_ready` 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_set_ready`] callbacks. + fn set_ready(&self, ready: bool) -> __sdk::Result<()>; + /// Register a callback to run whenever we are notified of an invocation of the reducer `set_ready`. + /// + /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] + /// to determine the reducer's status. + /// + /// The returned [`SetReadyCallbackId`] can be passed to [`Self::remove_on_set_ready`] + /// to cancel the callback. + fn on_set_ready( + &self, + callback: impl FnMut(&super::ReducerEventContext, &bool) + Send + 'static, + ) -> SetReadyCallbackId; + /// Cancel a callback previously registered by [`Self::on_set_ready`], + /// causing it not to run in the future. + fn remove_on_set_ready(&self, callback: SetReadyCallbackId); +} + +impl set_ready for super::RemoteReducers { + fn set_ready(&self, ready: bool) -> __sdk::Result<()> { + self.imp.call_reducer("set_ready", SetReadyArgs { ready }) + } + fn on_set_ready( + &self, + mut callback: impl FnMut(&super::ReducerEventContext, &bool) + Send + 'static, + ) -> SetReadyCallbackId { + SetReadyCallbackId(self.imp.on_reducer( + "set_ready", + Box::new(move |ctx: &super::ReducerEventContext| { + #[allow(irrefutable_let_patterns)] + let super::ReducerEventContext { + event: + __sdk::ReducerEvent { + reducer: super::Reducer::SetReady { ready }, + .. + }, + .. + } = ctx + else { + unreachable!() + }; + callback(ctx, ready) + }), + )) + } + fn remove_on_set_ready(&self, callback: SetReadyCallbackId) { + self.imp.remove_on_reducer("set_ready", callback.0) + } +} + +#[allow(non_camel_case_types)] +#[doc(hidden)] +/// Extension trait for setting the call-flags for the reducer `set_ready`. +/// +/// Implemented for [`super::SetReducerFlags`]. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub trait set_flags_for_set_ready { + /// Set the call-reducer flags for the reducer `set_ready` to `flags`. + /// + /// This type is currently unstable and may be removed without a major version bump. + fn set_ready(&self, flags: __ws::CallReducerFlags); +} + +impl set_flags_for_set_ready for super::SetReducerFlags { + fn set_ready(&self, flags: __ws::CallReducerFlags) { + self.imp.set_call_reducer_flags("set_ready", flags); + } +} diff --git a/jong/src/stdb/start_game_reducer.rs b/jong/src/stdb/start_game_reducer.rs new file mode 100644 index 0000000..5eb59c1 --- /dev/null +++ b/jong/src/stdb/start_game_reducer.rs @@ -0,0 +1,100 @@ +// 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 StartGameArgs {} + +impl From for super::Reducer { + fn from(args: StartGameArgs) -> Self { + Self::StartGame + } +} + +impl __sdk::InModule for StartGameArgs { + type Module = super::RemoteModule; +} + +pub struct StartGameCallbackId(__sdk::CallbackId); + +#[allow(non_camel_case_types)] +/// Extension trait for access to the reducer `start_game`. +/// +/// Implemented for [`super::RemoteReducers`]. +pub trait start_game { + /// Request that the remote module invoke the reducer `start_game` 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_start_game`] callbacks. + fn start_game(&self) -> __sdk::Result<()>; + /// Register a callback to run whenever we are notified of an invocation of the reducer `start_game`. + /// + /// Callbacks should inspect the [`__sdk::ReducerEvent`] contained in the [`super::ReducerEventContext`] + /// to determine the reducer's status. + /// + /// The returned [`StartGameCallbackId`] can be passed to [`Self::remove_on_start_game`] + /// to cancel the callback. + fn on_start_game( + &self, + callback: impl FnMut(&super::ReducerEventContext) + Send + 'static, + ) -> StartGameCallbackId; + /// Cancel a callback previously registered by [`Self::on_start_game`], + /// causing it not to run in the future. + fn remove_on_start_game(&self, callback: StartGameCallbackId); +} + +impl start_game for super::RemoteReducers { + fn start_game(&self) -> __sdk::Result<()> { + self.imp.call_reducer("start_game", StartGameArgs {}) + } + fn on_start_game( + &self, + mut callback: impl FnMut(&super::ReducerEventContext) + Send + 'static, + ) -> StartGameCallbackId { + StartGameCallbackId(self.imp.on_reducer( + "start_game", + Box::new(move |ctx: &super::ReducerEventContext| { + #[allow(irrefutable_let_patterns)] + let super::ReducerEventContext { + event: + __sdk::ReducerEvent { + reducer: super::Reducer::StartGame {}, + .. + }, + .. + } = ctx + else { + unreachable!() + }; + callback(ctx) + }), + )) + } + fn remove_on_start_game(&self, callback: StartGameCallbackId) { + self.imp.remove_on_reducer("start_game", callback.0) + } +} + +#[allow(non_camel_case_types)] +#[doc(hidden)] +/// Extension trait for setting the call-flags for the reducer `start_game`. +/// +/// Implemented for [`super::SetReducerFlags`]. +/// +/// This type is currently unstable and may be removed without a major version bump. +pub trait set_flags_for_start_game { + /// Set the call-reducer flags for the reducer `start_game` to `flags`. + /// + /// This type is currently unstable and may be removed without a major version bump. + fn start_game(&self, flags: __ws::CallReducerFlags); +} + +impl set_flags_for_start_game for super::SetReducerFlags { + fn start_game(&self, flags: __ws::CallReducerFlags) { + self.imp.set_call_reducer_flags("start_game", flags); + } +} diff --git a/jong/src/tui/input/keyboard.rs b/jong/src/tui/input/keyboard.rs index d2415bc..722d6fb 100644 --- a/jong/src/tui/input/keyboard.rs +++ b/jong/src/tui/input/keyboard.rs @@ -1,15 +1,21 @@ use bevy::prelude::*; use bevy_ratatui::crossterm::event::KeyCode; use bevy_ratatui::event::KeyMessage; -// use ratatui::crossterm::event::KeyCode; +use jong::stdb::PlayerTableAccess; +use jong::stdb::join_or_create_lobby; +use jong::stdb::start_game; use tui_logger::TuiWidgetEvent; +use jong::SpacetimeDB; +use jong_types::GameState; + use crate::tui::layout::Overlays; use crate::tui::states::ConsoleWidget; use crate::tui::states::TuiState; -use jong_types::GameState; pub(crate) fn keyboard( + stdb: SpacetimeDB, + mut messages: MessageReader, mut overlays: ResMut, mut consolewidget: ResMut, @@ -17,7 +23,6 @@ pub(crate) fn keyboard( curr_gamestate: Res>, curr_tuistate: Res>, - mut next_gamestate: ResMut>, mut next_tuistate: ResMut>, ) { @@ -38,8 +43,8 @@ pub(crate) fn keyboard( match curr_tuistate.get() { TuiState::MainMenu => match key { KeyCode::Char('p') => { + stdb.reducers().join_or_create_lobby(0).unwrap(); next_tuistate.set(TuiState::InGame); - next_gamestate.set(GameState::Setup); } KeyCode::Char('z') => { // if let Some(ref curr_zenstate) = curr_zenstate { diff --git a/jong/src/tui/render.rs b/jong/src/tui/render.rs index 0fd0ced..42a0fd2 100644 --- a/jong/src/tui/render.rs +++ b/jong/src/tui/render.rs @@ -109,7 +109,7 @@ pub(crate) fn render_arg_check( hands: Query<(&Children, Entity), (With, Without)>, // drawn_tile: Single>, ) { - trace!("arg!"); + // trace!("arg!"); } #[allow(clippy::too_many_arguments, clippy::type_complexity)] diff --git a/justfile b/justfile index 0d4b9f7..8962781 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 b122bcf..37a6a69 100644 --- a/spacetimedb/src/game.rs +++ b/spacetimedb/src/game.rs @@ -1,5 +1,5 @@ -use log::info; -use spacetimedb::{ReducerContext, Table, rand::seq::SliceRandom, reducer}; +use log::{info, trace}; +use spacetimedb::{ReducerContext, Table, reducer}; use crate::tables::*; use jong_types::*; @@ -22,7 +22,7 @@ pub fn join_or_create_lobby(ctx: &ReducerContext, mut lobby_id: u32) -> Result<( id: 0, host_player_id: player.id, players: vec![PlayerOrBot::Player { id: player.id }], - game_state: GameState::Setup, + game_state: GameState::Lobby, turn_state: TurnState::None, }); info!("created lobby: {:?}", lobby); @@ -42,10 +42,10 @@ pub fn join_or_create_lobby(ctx: &ReducerContext, mut lobby_id: u32) -> Result<( pub fn add_bot(ctx: &ReducerContext, lobby_id: u32) -> Result<(), String> { if lobby_id == 0 { Err("cannot add a bot without a lobby".into()) - } else if let Some(lobby) = ctx.db.lobby().id().find(lobby_id) + } else if let Some(mut lobby) = ctx.db.lobby().id().find(lobby_id) && (ctx.db.player().lobby_id().filter(lobby_id).count() + ctx.db.bot().lobby_id().filter(lobby_id).count() - <= 4) + < 4) { let bot = ctx.db.bot().insert(Bot { id: 0, @@ -53,9 +53,34 @@ pub fn add_bot(ctx: &ReducerContext, lobby_id: u32) -> Result<(), String> { hand_id: 0, pond_id: 0, }); + lobby.players.push(PlayerOrBot::Bot { id: bot.id }); + ctx.db.lobby().id().update(lobby); info!("added bot {} to lobby {}", bot.id, lobby_id); Ok(()) } else { Err("lobby doesn't exist".into()) } } + +#[reducer] +pub fn set_ready(ctx: &ReducerContext, ready: bool) { + let mut player = ctx.db.player().identity().find(ctx.sender).unwrap(); + player.ready = ready; + + let player = ctx.db.player().identity().update(player); +} + +#[reducer] +pub fn start_game(ctx: &ReducerContext) { + let player = ctx.db.player().identity().find(ctx.sender).unwrap(); + if let Some(mut lobby) = ctx.db.lobby().host_player_id().find(player.id) + && lobby.players.len() == 4 + && lobby.players.iter().all(|p| match p { + PlayerOrBot::Player { id } => ctx.db.player().id().find(id).is_some_and(|p| p.ready), + PlayerOrBot::Bot { id } => ctx.db.bot().id().find(id).is_some(), + }) + { + lobby.game_state = GameState::Deal; + ctx.db.lobby().id().update(lobby); + } +} diff --git a/spacetimedb/src/game/wall.rs b/spacetimedb/src/game/wall.rs index d46b92c..f33c898 100644 --- a/spacetimedb/src/game/wall.rs +++ b/spacetimedb/src/game/wall.rs @@ -10,21 +10,20 @@ 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(); - lobby.game_state = GameState::Deal; - let mut lobby = ctx.db.lobby().id().update(lobby); + if lobby.game_state == GameState::Deal { + let tiles = new_shuffled_wall(ctx); + ctx.db.wall().insert(Wall { + // id: 0, + lobby_id, + tiles, + }); - let tiles = new_shuffled_wall(ctx); - ctx.db.wall().insert(Wall { - // id: 0, - lobby_id, - tiles, - }); + deal_hands(ctx, lobby_id); - deal_hands(ctx, lobby_id); - - lobby.game_state = GameState::Play; - lobby.turn_state = TurnState::Tsumo; - ctx.db.lobby().id().update(lobby); + lobby.game_state = GameState::Play; + lobby.turn_state = TurnState::Tsumo; + ctx.db.lobby().id().update(lobby); + } } pub fn new_shuffled_wall(ctx: &ReducerContext) -> Vec { diff --git a/spacetimedb/src/lib.rs b/spacetimedb/src/lib.rs index e1669d6..505db51 100644 --- a/spacetimedb/src/lib.rs +++ b/spacetimedb/src/lib.rs @@ -1,10 +1,7 @@ -use log::{debug, info}; -use spacetimedb::{ - ReducerContext, Table, ViewContext, rand::seq::SliceRandom, reducer, table, view, -}; +use log::info; +use spacetimedb::{ReducerContext, Table, reducer}; use crate::tables::*; -use jong_types::*; mod game; mod tables; @@ -21,6 +18,7 @@ pub fn login_or_add_player(ctx: &ReducerContext) { lobby_id: 0, hand_id: 0, pond_id: 0, + ready: false, }) { info!("added player: {:?}", player); } else { diff --git a/spacetimedb/src/tables.rs b/spacetimedb/src/tables.rs index e3a3928..02efc8e 100644 --- a/spacetimedb/src/tables.rs +++ b/spacetimedb/src/tables.rs @@ -18,6 +18,8 @@ pub struct Player { pub lobby_id: u32, pub hand_id: u32, pub pond_id: u32, + + pub ready: bool, } #[table(name = bot)] diff --git a/states b/states new file mode 100644 index 0000000..13e0595 --- /dev/null +++ b/states @@ -0,0 +1,18 @@ +gamestate + + none + join_or_create_lobby() + + lobby + set_ready() + add_bot() + start_game() + + setup + shuffle_deal() + + deal + animations?? + + play + discards??