advance_game stuff
This commit is contained in:
parent
151f7a3489
commit
a39ad4cf7c
6 changed files with 95 additions and 79 deletions
|
|
@ -4,19 +4,13 @@
|
|||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::game_timer_type::GameTimer;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
pub(super) struct AdvanceGameArgs {
|
||||
pub game_timer: GameTimer,
|
||||
}
|
||||
pub(super) struct AdvanceGameArgs {}
|
||||
|
||||
impl From<AdvanceGameArgs> for super::Reducer {
|
||||
fn from(args: AdvanceGameArgs) -> Self {
|
||||
Self::AdvanceGame {
|
||||
game_timer: args.game_timer,
|
||||
}
|
||||
Self::AdvanceGame
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -35,8 +29,8 @@ pub trait advance_game {
|
|||
/// The reducer will run asynchronously in the future,
|
||||
/// and this method provides no way to listen for its completion status.
|
||||
/// /// Use [`advance_game:advance_game_then`] to run a callback after the reducer completes.
|
||||
fn advance_game(&self, game_timer: GameTimer) -> __sdk::Result<()> {
|
||||
self.advance_game_then(game_timer, |_, _| {})
|
||||
fn advance_game(&self) -> __sdk::Result<()> {
|
||||
self.advance_game_then(|_, _| {})
|
||||
}
|
||||
|
||||
/// Request that the remote module invoke the reducer `advance_game` to run as soon as possible,
|
||||
|
|
@ -47,7 +41,6 @@ pub trait advance_game {
|
|||
/// and its status can be observed with the `callback`.
|
||||
fn advance_game_then(
|
||||
&self,
|
||||
game_timer: GameTimer,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
|
|
@ -58,13 +51,12 @@ pub trait advance_game {
|
|||
impl advance_game for super::RemoteReducers {
|
||||
fn advance_game_then(
|
||||
&self,
|
||||
game_timer: GameTimer,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(AdvanceGameArgs { game_timer }, callback)
|
||||
.invoke_reducer_with_callback(AdvanceGameArgs {}, callback)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ pub use wind_type::Wind;
|
|||
|
||||
pub enum Reducer {
|
||||
AddBot { lobby_id: u32 },
|
||||
AdvanceGame { game_timer: GameTimer },
|
||||
AdvanceGame,
|
||||
ClearAll,
|
||||
DiscardTile { tile_id: u32 },
|
||||
JoinOrCreateLobby { lobby_id: u32 },
|
||||
|
|
@ -92,7 +92,7 @@ impl __sdk::Reducer for Reducer {
|
|||
fn reducer_name(&self) -> &'static str {
|
||||
match self {
|
||||
Reducer::AddBot { .. } => "add_bot",
|
||||
Reducer::AdvanceGame { .. } => "advance_game",
|
||||
Reducer::AdvanceGame => "advance_game",
|
||||
Reducer::ClearAll => "clear_all",
|
||||
Reducer::DiscardTile { .. } => "discard_tile",
|
||||
Reducer::JoinOrCreateLobby { .. } => "join_or_create_lobby",
|
||||
|
|
@ -106,10 +106,8 @@ impl __sdk::Reducer for Reducer {
|
|||
Reducer::AddBot { lobby_id } => __sats::bsatn::to_vec(&add_bot_reducer::AddBotArgs {
|
||||
lobby_id: lobby_id.clone(),
|
||||
}),
|
||||
Reducer::AdvanceGame { game_timer } => {
|
||||
__sats::bsatn::to_vec(&advance_game_reducer::AdvanceGameArgs {
|
||||
game_timer: game_timer.clone(),
|
||||
})
|
||||
Reducer::AdvanceGame => {
|
||||
__sats::bsatn::to_vec(&advance_game_reducer::AdvanceGameArgs {})
|
||||
}
|
||||
Reducer::ClearAll => __sats::bsatn::to_vec(&clear_all_reducer::ClearAllArgs {}),
|
||||
Reducer::DiscardTile { tile_id } => {
|
||||
|
|
|
|||
|
|
@ -15,10 +15,77 @@ mod hand;
|
|||
mod lobby;
|
||||
|
||||
#[reducer]
|
||||
pub fn advance_game(ctx: &ReducerContext, mut game_timer: GameTimer) -> Result<(), String> {
|
||||
pub fn advance_game(ctx: &ReducerContext) -> Result<(), String> {
|
||||
let game_timer = ctx
|
||||
.db
|
||||
.game_timer()
|
||||
.lobby_id()
|
||||
.find(
|
||||
ctx.db
|
||||
.player()
|
||||
.identity()
|
||||
.find(ctx.sender())
|
||||
.ok_or("player not in lobby")?
|
||||
.lobby_id,
|
||||
)
|
||||
.ok_or("no such lobby")?;
|
||||
|
||||
advance_game_private(ctx, game_timer)
|
||||
}
|
||||
|
||||
fn shuffle_wall(ctx: &ReducerContext, lobby: &mut Lobby) {
|
||||
let tiles = {
|
||||
let mut rng = ctx.rng();
|
||||
let mut wall: Vec<_> = jong_types::tiles::tiles()
|
||||
.into_iter()
|
||||
.map(|tile| ctx.db.tile().insert(DbTile { id: 0, tile }))
|
||||
.collect();
|
||||
wall.shuffle(&mut rng);
|
||||
wall
|
||||
};
|
||||
ctx.db.wall().insert(DbWall {
|
||||
// id: 0,
|
||||
lobby_id: lobby.id,
|
||||
tiles,
|
||||
});
|
||||
lobby.game_state = GameState::Deal;
|
||||
}
|
||||
|
||||
fn deal_hands(ctx: &ReducerContext, lobby: &mut Lobby) -> Result<(), String> {
|
||||
let mut wall = ctx.db.wall().lobby_id().find(lobby.id).unwrap();
|
||||
for pob in &lobby.players {
|
||||
let mut tiles = wall.tiles.split_off(wall.tiles.len() - 13);
|
||||
wall = ctx.db.wall().lobby_id().update(wall);
|
||||
tiles.sort_by_key(|t| t.tile);
|
||||
match pob {
|
||||
PlayerOrBot::Player { id } if let Some(p) = ctx.db.player().id().find(id) => {
|
||||
ctx.db.player_hand().insert(PlayerHand {
|
||||
id: 0,
|
||||
player_id: p.id,
|
||||
turn_state: jong_types::TurnState::None,
|
||||
pond: vec![],
|
||||
hand: tiles,
|
||||
working_tile: None,
|
||||
});
|
||||
ctx.db.player_clock().insert(PlayerClock {
|
||||
id: 0,
|
||||
player_id: p.id,
|
||||
renewable: 5,
|
||||
total: 30,
|
||||
});
|
||||
}
|
||||
PlayerOrBot::Bot { id } if let Some(mut b) = ctx.db.bot().id().find(id) => {
|
||||
b.hand = tiles;
|
||||
ctx.db.bot().id().update(b);
|
||||
}
|
||||
_ => Err("couldn't find player or bot".to_string())?,
|
||||
}
|
||||
}
|
||||
lobby.game_state = jong_types::states::GameState::Play;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[reducer]
|
||||
pub fn advance_game_private(ctx: &ReducerContext, mut game_timer: GameTimer) -> Result<(), String> {
|
||||
// checks every second (or more? when users make moves) on whether to advance the game's various states
|
||||
|
|
@ -30,60 +97,19 @@ pub fn advance_game_private(ctx: &ReducerContext, mut game_timer: GameTimer) ->
|
|||
GameState::Setup => {
|
||||
// TODO reduce interval beforehand so we don't wait a second?
|
||||
// TODO keep a count to clear stale lobbies
|
||||
trace!("shuffle wall");
|
||||
let tiles = {
|
||||
let mut rng = ctx.rng();
|
||||
let mut wall: Vec<_> = jong_types::tiles::tiles()
|
||||
.into_iter()
|
||||
.map(|tile| ctx.db.tile().insert(DbTile { id: 0, tile }))
|
||||
.collect();
|
||||
wall.shuffle(&mut rng);
|
||||
wall
|
||||
};
|
||||
ctx.db.wall().insert(DbWall {
|
||||
// id: 0,
|
||||
lobby_id: lobby.id,
|
||||
tiles,
|
||||
});
|
||||
lobby.game_state = GameState::Deal;
|
||||
// trace!("shuffle wall");
|
||||
shuffle_wall(ctx, &mut lobby);
|
||||
ctx.db.lobby().id().update(lobby);
|
||||
advance_game_private(ctx, game_timer)?;
|
||||
return Ok(());
|
||||
}
|
||||
GameState::Deal => {
|
||||
// TODO reduce interval beforehand so this can animate?
|
||||
// TODO change loop to be per interval somehow?
|
||||
// trace!("deal hands");
|
||||
let mut wall = ctx.db.wall().lobby_id().find(lobby.id).unwrap();
|
||||
for pob in &lobby.players {
|
||||
let mut tiles = wall.tiles.split_off(wall.tiles.len() - 13);
|
||||
wall = ctx.db.wall().lobby_id().update(wall);
|
||||
tiles.sort_by_key(|t| t.tile);
|
||||
match pob {
|
||||
PlayerOrBot::Player { id }
|
||||
if let Some(p) = ctx.db.player().id().find(id) =>
|
||||
{
|
||||
ctx.db.player_hand().insert(PlayerHand {
|
||||
id: 0,
|
||||
player_id: p.id,
|
||||
turn_state: jong_types::TurnState::None,
|
||||
pond: vec![],
|
||||
hand: tiles,
|
||||
working_tile: None,
|
||||
});
|
||||
ctx.db.player_clock().insert(PlayerClock {
|
||||
id: 0,
|
||||
player_id: p.id,
|
||||
renewable: 5,
|
||||
total: 30,
|
||||
});
|
||||
}
|
||||
PlayerOrBot::Bot { id } if let Some(mut b) = ctx.db.bot().id().find(id) => {
|
||||
b.hand = tiles;
|
||||
ctx.db.bot().id().update(b);
|
||||
}
|
||||
_ => Err("couldn't find player or bot".to_string())?,
|
||||
}
|
||||
}
|
||||
lobby.game_state = jong_types::states::GameState::Play;
|
||||
// trace!("dealt hands");
|
||||
deal_hands(ctx, &mut lobby)?;
|
||||
ctx.db.lobby().id().update(lobby);
|
||||
advance_game_private(ctx, game_timer)?;
|
||||
return Ok(());
|
||||
}
|
||||
GameState::Play => {
|
||||
// trace!("in play");
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use spacetimedb::{ReducerContext, Table, rand::seq::SliceRandom, reducer};
|
|||
|
||||
use jong_types::PlayerOrBot;
|
||||
|
||||
use crate::tables::*;
|
||||
use crate::{reducers::advance_game_private, tables::*};
|
||||
|
||||
#[reducer]
|
||||
pub fn join_or_create_lobby(ctx: &ReducerContext, mut lobby_id: u32) -> Result<(), String> {
|
||||
|
|
@ -87,11 +87,13 @@ pub fn set_ready(ctx: &ReducerContext, ready: bool) -> Result<(), String> {
|
|||
let lobby = ctx.db.lobby().id().update(lobby);
|
||||
|
||||
// TODO should we schedule this outside so that we can clear out stale lobbies?
|
||||
ctx.db.game_timer().insert(GameTimer {
|
||||
let game_timer = ctx.db.game_timer().insert(GameTimer {
|
||||
id: 0,
|
||||
lobby_id: lobby.id,
|
||||
scheduled_at: spacetimedb::ScheduleAt::Interval(Duration::from_secs(1).into()),
|
||||
});
|
||||
|
||||
advance_game_private(ctx, game_timer)?;
|
||||
} else {
|
||||
// if lobby doesn't exist, reset player state
|
||||
player.lobby_id = 0;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use bevy_spacetimedb::{
|
|||
ReadStdbDisconnectedMessage, ReadUpdateMessage, StdbPlugin,
|
||||
};
|
||||
|
||||
use jong_db::{self, GameTimerTableAccess, add_bot, set_ready};
|
||||
use jong_db::{self, GameTimerTableAccess, add_bot, advance_game, set_ready};
|
||||
use jong_db::{
|
||||
BotTableAccess, DbConnection, LobbyTableAccess, PlayerHand, PlayerTableAccess, RemoteTables,
|
||||
ViewClosedHandsTableAccess, ViewHandTableAccess,
|
||||
|
|
@ -25,7 +25,6 @@ impl Plugin for Riichi {
|
|||
.with_run_fn(DbConnection::run_threaded)
|
||||
.add_table(RemoteTables::player)
|
||||
.add_table(RemoteTables::lobby)
|
||||
.add_table(RemoteTables::game_timer)
|
||||
// TODO check bevy_spacetimedb PR status
|
||||
.add_view_with_pk(RemoteTables::view_hand, |p| p.id)
|
||||
.add_view_with_pk(RemoteTables::view_closed_hands, |p| {
|
||||
|
|
@ -102,7 +101,6 @@ fn subscriptions(stdb: SpacetimeDB, mut commands: Commands) {
|
|||
"SELECT b.* FROM bot b JOIN lobby l ON l.id = b.lobby_id".to_string(),
|
||||
"SELECT * FROM view_hand".to_string(),
|
||||
"SELECT * FROM view_closed_hands".to_string(),
|
||||
"SELECT g.* FROM game_timer g JOIN player p ON g.lobby_id = p.lobby_id".to_string(),
|
||||
]);
|
||||
|
||||
while let Ok(event) = recv.recv() {
|
||||
|
|
@ -278,6 +276,7 @@ fn on_lobby_insert_update(
|
|||
stdb.reducers().add_bot(player.lobby_id).unwrap();
|
||||
}
|
||||
stdb.reducers().set_ready(true).unwrap();
|
||||
// stdb.reducers().advance_game().unwrap();
|
||||
}
|
||||
}
|
||||
jong_db::GameState::Setup => {
|
||||
|
|
|
|||
|
|
@ -106,14 +106,13 @@ fn discard_tile(
|
|||
drawn: Single<(Entity, &TileId), With<Drawn>>,
|
||||
tiles: Query<&TileId>,
|
||||
) {
|
||||
// FIXME why is this not consuming the messages?
|
||||
// FIXME why is this not consuming the messages? or is it just getting updated too frequently?
|
||||
// TODO disable this when we're not current player?
|
||||
while let Some(message) = selected.read().next() {
|
||||
trace!("{message:?}");
|
||||
if let Ok(tile_id) = tiles.get(message.0) {
|
||||
stdb.reducers().discard_tile(tile_id.0).unwrap();
|
||||
stdb.reducers()
|
||||
.advance_game(stdb.db().game_timer().iter().next().unwrap())
|
||||
.unwrap();
|
||||
stdb.reducers().advance_game().unwrap();
|
||||
commands.entity(drawn.0).remove::<Drawn>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue