hack for player-lobby and Res<Player> race?

This commit is contained in:
Tao Tien 2026-02-08 23:47:57 -08:00
parent 9f6a5b6423
commit ce84478376
34 changed files with 517 additions and 1330 deletions

60
spacetimedb/src/game.rs Normal file
View file

@ -0,0 +1,60 @@
use log::info;
use spacetimedb::{ReducerContext, Table, rand::seq::SliceRandom, reducer};
use crate::tables::*;
use jong_types::*;
mod hand;
mod wall;
#[reducer]
pub fn join_or_create_lobby(ctx: &ReducerContext, mut lobby_id: u32) -> Result<(), String> {
let ok_or = ctx
.db
.player()
.identity()
.find(ctx.sender)
.ok_or(format!("cannot find player {}", ctx.sender))?;
let mut player = ok_or;
if lobby_id == 0 {
let lobby = ctx.db.lobby().insert(Lobby {
id: 0,
host_player_id: player.id,
players: vec![PlayerOrBot::Player { id: player.id }],
game_state: GameState::Setup,
});
info!("created lobby: {:?}", lobby);
lobby_id = lobby.id;
}
player.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(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_id: 0,
pond_id: 0,
});
info!("added bot {} to lobby {}", bot.id, lobby_id);
Ok(())
} else {
Err("lobby doesn't exist".into())
}
}

View file

@ -0,0 +1,53 @@
use spacetimedb::{ReducerContext, Table, ViewContext, reducer, view};
use crate::tables::*;
use jong_types::*;
pub fn deal_hands(ctx: &ReducerContext, lobby_id: u32) {
let players = ctx.db.player().lobby_id().filter(lobby_id);
let bots = ctx.db.bot().lobby_id().filter(lobby_id);
let mut wall = ctx.db.wall().lobby_id().find(lobby_id).unwrap();
// FIXME rectify deal orders
for mut player in players {
let mut tiles = wall.tiles.split_off(wall.tiles.len() - 13);
tiles.sort();
wall = ctx.db.wall().lobby_id().update(wall);
let hand = ctx.db.hand().insert(Hand {
id: 0,
owner: PlayerOrBot::Player { id: player.id },
sort: true,
tiles,
});
player.hand_id = hand.id;
ctx.db.player().id().update(player);
}
for mut bot in bots {
let mut tiles = wall.tiles.split_off(wall.tiles.len() - 13);
tiles.sort();
wall = ctx.db.wall().lobby_id().update(wall);
let hand = ctx.db.hand().insert(Hand {
id: 0,
owner: PlayerOrBot::Bot { id: bot.id },
sort: true,
tiles,
});
bot.hand_id = hand.id;
ctx.db.bot().id().update(bot);
}
}
#[view(name = view_player_hand, public)]
pub fn view_player_hand(ctx: &ViewContext) -> Option<Hand> {
ctx.db
.player()
.identity()
.find(ctx.sender)
.map(|p| ctx.db.hand().id().find(p.hand_id))?
}
// #[reducer]
// pub fn sort_hand(ctx: &ReducerContext) {
// todo!()
// }

View file

@ -0,0 +1,36 @@
use log::debug;
use spacetimedb::{ReducerContext, Table, rand::seq::SliceRandom, reducer};
use super::hand::deal_hands;
use crate::tables::*;
use jong_types::*;
#[reducer]
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);
let tiles = new_shuffled_wall(ctx);
ctx.db.wall().insert(Wall {
// id: 0,
lobby_id,
tiles,
});
deal_hands(ctx, lobby_id);
lobby.game_state = GameState::Play;
ctx.db.lobby().id().update(lobby);
}
pub fn new_shuffled_wall(ctx: &ReducerContext) -> Vec<Tile> {
let mut rng = ctx.rng();
let mut wall = tiles();
wall.shuffle(&mut rng);
wall
}

View file

@ -1,83 +1,13 @@
use log::{debug, info};
use spacetimedb::{
Identity, ReducerContext, Table, ViewContext, rand::seq::SliceRandom, reducer, table, view,
ReducerContext, Table, ViewContext, rand::seq::SliceRandom, reducer, table, view,
};
use crate::tables::*;
use jong_types::*;
#[derive(Debug)]
#[table(name = player, public)]
pub struct Player {
#[primary_key]
identity: Identity,
#[auto_inc]
#[index(direct)]
#[unique]
id: u32,
name: Option<String>,
#[index(btree)]
lobby_id: u32,
}
#[table(name = bot)]
pub struct Bot {
#[primary_key]
#[auto_inc]
id: u32,
#[index(btree)]
lobby_id: u32,
}
#[derive(Debug, Clone, Copy)]
#[table(name = lobby, public)]
pub struct Lobby {
#[primary_key]
#[auto_inc]
id: u32,
#[index(direct)]
#[unique]
host_player_id: u32,
game_state: GameState,
}
#[table(name = wall)]
pub struct Wall {
// #[auto_inc]
// id: u32,
#[primary_key]
// #[index(direct)]
// #[unique]
lobby_id: u32,
tiles: Vec<Tile>,
}
#[table(name = hand)]
pub struct Hand {
#[primary_key]
player_identity: Identity,
tiles: Vec<Tile>,
}
#[table(name = bothand)]
pub struct BotHand {
#[primary_key]
bot_id: u32,
tiles: Vec<Tile>,
}
#[table(name = pond, public)]
pub struct Pond {
tiles: Vec<Tile>,
}
mod game;
mod tables;
#[reducer(client_connected)]
pub fn login_or_add_player(ctx: &ReducerContext) {
@ -89,6 +19,8 @@ pub fn login_or_add_player(ctx: &ReducerContext) {
id: 0,
name: None,
lobby_id: 0,
hand_id: 0,
pond_id: 0,
}) {
info!("added player: {:?}", player);
} else {
@ -97,117 +29,6 @@ pub fn login_or_add_player(ctx: &ReducerContext) {
}
}
#[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 {
let lobby = ctx.db.lobby().insert(Lobby {
id: 0,
host_player_id: player.id,
game_state: GameState::None,
});
info!("created lobby: {:?}", lobby);
lobby_id = lobby.id;
}
player.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(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 });
info!("added bot {} to lobby {}", bot.id, lobby_id);
Ok(())
} else {
Err("lobby doesn't exist".into())
}
}
#[reducer]
pub fn setup_game(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::Setup;
ctx.db.lobby().id().update(lobby);
let tiles = new_shuffled_wall(ctx);
ctx.db.wall().insert(Wall {
// id: 0,
lobby_id,
tiles,
});
lobby.game_state = GameState::Deal;
ctx.db.lobby().id().update(lobby);
deal_hands(ctx, lobby_id);
lobby.game_state = GameState::Play;
ctx.db.lobby().id().update(lobby);
}
pub fn new_shuffled_wall(ctx: &ReducerContext) -> Vec<Tile> {
let mut rng = ctx.rng();
let mut wall = tiles();
wall.shuffle(&mut rng);
wall
}
pub fn deal_hands(ctx: &ReducerContext, lobby_id: u32) {
let players = ctx.db.player().lobby_id().filter(lobby_id);
let bots = ctx.db.bot().lobby_id().filter(lobby_id);
let mut wall = ctx.db.wall().lobby_id().find(lobby_id).unwrap();
// FIXME rectify deal orders
for player in players {
let tiles = wall.tiles.split_off(wall.tiles.len() - 13);
wall = ctx.db.wall().lobby_id().update(wall);
ctx.db.hand().insert(Hand {
player_identity: player.identity,
tiles,
});
}
for bot in bots {
let tiles = wall.tiles.split_off(wall.tiles.len() - 13);
wall = ctx.db.wall().lobby_id().update(wall);
ctx.db.bothand().insert(BotHand {
bot_id: bot.id,
tiles,
});
}
}
#[view(name = view_player_hand, public)]
pub fn view_player_hand(ctx: &ViewContext) -> Option<Hand> {
ctx.db.hand().player_identity().find(ctx.sender)
}
#[reducer]
pub fn sort_hand(ctx: &ReducerContext) {
todo!()
}
// #[reducer(init)]
// pub fn init(_ctx: &ReducerContext) {
// // Called when the module is initially published

84
spacetimedb/src/tables.rs Normal file
View file

@ -0,0 +1,84 @@
use spacetimedb::{Identity, SpacetimeType, table};
use jong_types::*;
#[derive(Debug)]
#[table(name = player, public)]
pub struct Player {
#[primary_key]
pub identity: Identity,
#[unique]
#[auto_inc]
pub id: u32,
pub name: Option<String>,
#[index(btree)]
pub lobby_id: u32,
pub hand_id: u32,
pub pond_id: u32,
}
#[table(name = bot)]
pub struct Bot {
#[primary_key]
#[auto_inc]
pub id: u32,
#[index(btree)]
pub lobby_id: u32,
pub hand_id: u32,
pub pond_id: u32,
}
#[derive(Debug, Clone, SpacetimeType)]
pub enum PlayerOrBot {
Player { id: u32 },
Bot { id: u32 },
}
#[derive(Debug, Clone)]
#[table(name = lobby, public)]
pub struct Lobby {
#[primary_key]
#[auto_inc]
pub id: u32,
#[unique]
pub host_player_id: u32,
pub players: Vec<PlayerOrBot>,
pub game_state: GameState,
}
#[table(name = wall)]
pub struct Wall {
#[primary_key]
pub lobby_id: u32,
pub tiles: Vec<Tile>,
}
#[table(name = hand)]
pub struct Hand {
#[primary_key]
#[auto_inc]
pub id: u32,
pub owner: PlayerOrBot,
pub sort: bool,
pub tiles: Vec<Tile>,
}
#[table(name = pond, public)]
pub struct Pond {
#[primary_key]
#[auto_inc]
pub id: u32,
pub owner: PlayerOrBot,
pub tiles: Vec<Tile>,
}