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)]
|
#![allow(unused, clippy::all)]
|
||||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
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)]
|
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||||
#[sats(crate = __lib)]
|
#[sats(crate = __lib)]
|
||||||
pub(super) struct AdvanceGameArgs {
|
pub(super) struct AdvanceGameArgs {}
|
||||||
pub game_timer: GameTimer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AdvanceGameArgs> for super::Reducer {
|
impl From<AdvanceGameArgs> for super::Reducer {
|
||||||
fn from(args: AdvanceGameArgs) -> Self {
|
fn from(args: AdvanceGameArgs) -> Self {
|
||||||
Self::AdvanceGame {
|
Self::AdvanceGame
|
||||||
game_timer: args.game_timer,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,8 +29,8 @@ pub trait advance_game {
|
||||||
/// The reducer will run asynchronously in the future,
|
/// The reducer will run asynchronously in the future,
|
||||||
/// and this method provides no way to listen for its completion status.
|
/// 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.
|
/// /// Use [`advance_game:advance_game_then`] to run a callback after the reducer completes.
|
||||||
fn advance_game(&self, game_timer: GameTimer) -> __sdk::Result<()> {
|
fn advance_game(&self) -> __sdk::Result<()> {
|
||||||
self.advance_game_then(game_timer, |_, _| {})
|
self.advance_game_then(|_, _| {})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request that the remote module invoke the reducer `advance_game` to run as soon as possible,
|
/// 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`.
|
/// and its status can be observed with the `callback`.
|
||||||
fn advance_game_then(
|
fn advance_game_then(
|
||||||
&self,
|
&self,
|
||||||
game_timer: GameTimer,
|
|
||||||
|
|
||||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||||
+ Send
|
+ Send
|
||||||
|
|
@ -58,13 +51,12 @@ pub trait advance_game {
|
||||||
impl advance_game for super::RemoteReducers {
|
impl advance_game for super::RemoteReducers {
|
||||||
fn advance_game_then(
|
fn advance_game_then(
|
||||||
&self,
|
&self,
|
||||||
game_timer: GameTimer,
|
|
||||||
|
|
||||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||||
+ Send
|
+ Send
|
||||||
+ 'static,
|
+ 'static,
|
||||||
) -> __sdk::Result<()> {
|
) -> __sdk::Result<()> {
|
||||||
self.imp
|
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 {
|
pub enum Reducer {
|
||||||
AddBot { lobby_id: u32 },
|
AddBot { lobby_id: u32 },
|
||||||
AdvanceGame { game_timer: GameTimer },
|
AdvanceGame,
|
||||||
ClearAll,
|
ClearAll,
|
||||||
DiscardTile { tile_id: u32 },
|
DiscardTile { tile_id: u32 },
|
||||||
JoinOrCreateLobby { lobby_id: u32 },
|
JoinOrCreateLobby { lobby_id: u32 },
|
||||||
|
|
@ -92,7 +92,7 @@ impl __sdk::Reducer for Reducer {
|
||||||
fn reducer_name(&self) -> &'static str {
|
fn reducer_name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Reducer::AddBot { .. } => "add_bot",
|
Reducer::AddBot { .. } => "add_bot",
|
||||||
Reducer::AdvanceGame { .. } => "advance_game",
|
Reducer::AdvanceGame => "advance_game",
|
||||||
Reducer::ClearAll => "clear_all",
|
Reducer::ClearAll => "clear_all",
|
||||||
Reducer::DiscardTile { .. } => "discard_tile",
|
Reducer::DiscardTile { .. } => "discard_tile",
|
||||||
Reducer::JoinOrCreateLobby { .. } => "join_or_create_lobby",
|
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 {
|
Reducer::AddBot { lobby_id } => __sats::bsatn::to_vec(&add_bot_reducer::AddBotArgs {
|
||||||
lobby_id: lobby_id.clone(),
|
lobby_id: lobby_id.clone(),
|
||||||
}),
|
}),
|
||||||
Reducer::AdvanceGame { game_timer } => {
|
Reducer::AdvanceGame => {
|
||||||
__sats::bsatn::to_vec(&advance_game_reducer::AdvanceGameArgs {
|
__sats::bsatn::to_vec(&advance_game_reducer::AdvanceGameArgs {})
|
||||||
game_timer: game_timer.clone(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
Reducer::ClearAll => __sats::bsatn::to_vec(&clear_all_reducer::ClearAllArgs {}),
|
Reducer::ClearAll => __sats::bsatn::to_vec(&clear_all_reducer::ClearAllArgs {}),
|
||||||
Reducer::DiscardTile { tile_id } => {
|
Reducer::DiscardTile { tile_id } => {
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,77 @@ mod hand;
|
||||||
mod lobby;
|
mod lobby;
|
||||||
|
|
||||||
#[reducer]
|
#[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)
|
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]
|
#[reducer]
|
||||||
pub fn advance_game_private(ctx: &ReducerContext, mut game_timer: GameTimer) -> Result<(), String> {
|
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
|
// 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 => {
|
GameState::Setup => {
|
||||||
// TODO reduce interval beforehand so we don't wait a second?
|
// TODO reduce interval beforehand so we don't wait a second?
|
||||||
// TODO keep a count to clear stale lobbies
|
// TODO keep a count to clear stale lobbies
|
||||||
trace!("shuffle wall");
|
// trace!("shuffle wall");
|
||||||
let tiles = {
|
shuffle_wall(ctx, &mut lobby);
|
||||||
let mut rng = ctx.rng();
|
ctx.db.lobby().id().update(lobby);
|
||||||
let mut wall: Vec<_> = jong_types::tiles::tiles()
|
advance_game_private(ctx, game_timer)?;
|
||||||
.into_iter()
|
return Ok(());
|
||||||
.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;
|
|
||||||
}
|
}
|
||||||
GameState::Deal => {
|
GameState::Deal => {
|
||||||
// TODO reduce interval beforehand so this can animate?
|
// TODO reduce interval beforehand so this can animate?
|
||||||
// TODO change loop to be per interval somehow?
|
// TODO change loop to be per interval somehow?
|
||||||
// trace!("deal hands");
|
deal_hands(ctx, &mut lobby)?;
|
||||||
let mut wall = ctx.db.wall().lobby_id().find(lobby.id).unwrap();
|
ctx.db.lobby().id().update(lobby);
|
||||||
for pob in &lobby.players {
|
advance_game_private(ctx, game_timer)?;
|
||||||
let mut tiles = wall.tiles.split_off(wall.tiles.len() - 13);
|
return Ok(());
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
GameState::Play => {
|
GameState::Play => {
|
||||||
// trace!("in play");
|
// trace!("in play");
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use spacetimedb::{ReducerContext, Table, rand::seq::SliceRandom, reducer};
|
||||||
|
|
||||||
use jong_types::PlayerOrBot;
|
use jong_types::PlayerOrBot;
|
||||||
|
|
||||||
use crate::tables::*;
|
use crate::{reducers::advance_game_private, tables::*};
|
||||||
|
|
||||||
#[reducer]
|
#[reducer]
|
||||||
pub fn join_or_create_lobby(ctx: &ReducerContext, mut lobby_id: u32) -> Result<(), String> {
|
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);
|
let lobby = ctx.db.lobby().id().update(lobby);
|
||||||
|
|
||||||
// TODO should we schedule this outside so that we can clear out stale lobbies?
|
// 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,
|
id: 0,
|
||||||
lobby_id: lobby.id,
|
lobby_id: lobby.id,
|
||||||
scheduled_at: spacetimedb::ScheduleAt::Interval(Duration::from_secs(1).into()),
|
scheduled_at: spacetimedb::ScheduleAt::Interval(Duration::from_secs(1).into()),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
advance_game_private(ctx, game_timer)?;
|
||||||
} else {
|
} else {
|
||||||
// if lobby doesn't exist, reset player state
|
// if lobby doesn't exist, reset player state
|
||||||
player.lobby_id = 0;
|
player.lobby_id = 0;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use bevy_spacetimedb::{
|
||||||
ReadStdbDisconnectedMessage, ReadUpdateMessage, StdbPlugin,
|
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::{
|
use jong_db::{
|
||||||
BotTableAccess, DbConnection, LobbyTableAccess, PlayerHand, PlayerTableAccess, RemoteTables,
|
BotTableAccess, DbConnection, LobbyTableAccess, PlayerHand, PlayerTableAccess, RemoteTables,
|
||||||
ViewClosedHandsTableAccess, ViewHandTableAccess,
|
ViewClosedHandsTableAccess, ViewHandTableAccess,
|
||||||
|
|
@ -25,7 +25,6 @@ impl Plugin for Riichi {
|
||||||
.with_run_fn(DbConnection::run_threaded)
|
.with_run_fn(DbConnection::run_threaded)
|
||||||
.add_table(RemoteTables::player)
|
.add_table(RemoteTables::player)
|
||||||
.add_table(RemoteTables::lobby)
|
.add_table(RemoteTables::lobby)
|
||||||
.add_table(RemoteTables::game_timer)
|
|
||||||
// TODO check bevy_spacetimedb PR status
|
// TODO check bevy_spacetimedb PR status
|
||||||
.add_view_with_pk(RemoteTables::view_hand, |p| p.id)
|
.add_view_with_pk(RemoteTables::view_hand, |p| p.id)
|
||||||
.add_view_with_pk(RemoteTables::view_closed_hands, |p| {
|
.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 b.* FROM bot b JOIN lobby l ON l.id = b.lobby_id".to_string(),
|
||||||
"SELECT * FROM view_hand".to_string(),
|
"SELECT * FROM view_hand".to_string(),
|
||||||
"SELECT * FROM view_closed_hands".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() {
|
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().add_bot(player.lobby_id).unwrap();
|
||||||
}
|
}
|
||||||
stdb.reducers().set_ready(true).unwrap();
|
stdb.reducers().set_ready(true).unwrap();
|
||||||
|
// stdb.reducers().advance_game().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jong_db::GameState::Setup => {
|
jong_db::GameState::Setup => {
|
||||||
|
|
|
||||||
|
|
@ -106,14 +106,13 @@ fn discard_tile(
|
||||||
drawn: Single<(Entity, &TileId), With<Drawn>>,
|
drawn: Single<(Entity, &TileId), With<Drawn>>,
|
||||||
tiles: Query<&TileId>,
|
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?
|
// TODO disable this when we're not current player?
|
||||||
while let Some(message) = selected.read().next() {
|
while let Some(message) = selected.read().next() {
|
||||||
|
trace!("{message:?}");
|
||||||
if let Ok(tile_id) = tiles.get(message.0) {
|
if let Ok(tile_id) = tiles.get(message.0) {
|
||||||
stdb.reducers().discard_tile(tile_id.0).unwrap();
|
stdb.reducers().discard_tile(tile_id.0).unwrap();
|
||||||
stdb.reducers()
|
stdb.reducers().advance_game().unwrap();
|
||||||
.advance_game(stdb.db().game_timer().iter().next().unwrap())
|
|
||||||
.unwrap();
|
|
||||||
commands.entity(drawn.0).remove::<Drawn>();
|
commands.entity(drawn.0).remove::<Drawn>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue