jong/jong-line/src/reducers/lobby.rs
2026-02-25 17:14:41 -08:00

105 lines
3.3 KiB
Rust

use std::time::Duration;
use log::info;
use spacetimedb::{ReducerContext, Table, rand::seq::SliceRandom, reducer};
use jong_types::PlayerOrBot;
use crate::tables::*;
#[reducer]
pub fn join_or_create_lobby(ctx: &ReducerContext, mut lobby_id: u32) -> Result<(), String> {
let mut player = ctx
.db
.player()
.identity()
.find(ctx.sender())
.ok_or(format!("cannot find player {}", ctx.sender()))?;
if lobby_id == 0 && player.lobby_id == 0 {
// TODO check first if player is already in a lobby
let lobby = ctx.db.lobby().insert(Lobby {
id: 0,
players: vec![PlayerOrBot::Player { id: player.id }],
game_state: jong_types::states::GameState::Lobby,
dealer_idx: 0,
current_idx: 0,
});
info!("created lobby: {}", lobby.id);
lobby_id = lobby.id;
player.lobby_id = lobby_id;
} else {
let lobby = ctx
.db
.lobby()
.id()
.find(player.lobby_id)
.ok_or(format!("can't find lobby {}", player.lobby_id))?;
lobby_id = lobby.id;
}
let player = ctx.db.player().identity().update(player);
info!("player {} joined lobby {}", player.id, lobby_id);
Ok(())
}
#[reducer]
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(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)
{
let bot = ctx.db.bot().insert(Bot {
id: 0,
lobby_id,
hand: vec![],
pond: vec![],
working_tile: None,
turn_state: jong_types::TurnState::None,
});
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) -> Result<(), String> {
let mut player = ctx.db.player().identity().find(ctx.sender()).unwrap();
player.ready = ready;
player = ctx.db.player().identity().update(player);
if let Some(mut lobby) = ctx.db.lobby().id().find(player.lobby_id)
&& lobby.players.len() == 4
&& ctx.db.player().lobby_id().filter(lobby.id).all(|p| p.ready)
{
lobby.game_state = jong_types::states::GameState::Setup;
lobby.players.shuffle(&mut ctx.rng());
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 {
id: 0,
lobby_id: lobby.id,
scheduled_at: spacetimedb::ScheduleAt::Interval(Duration::from_secs(1).into()),
});
} else {
// if lobby doesn't exist, reset player state
player.lobby_id = 0;
player.ready = false;
player = ctx.db.player().identity().update(player);
return Err(format!("couldn't find lobby with id: {}", player.lobby_id));
}
Ok(())
}