This commit is contained in:
Tao Tien 2026-02-22 00:39:51 -08:00
parent d7b4221727
commit 2d3993452b
33 changed files with 920 additions and 143 deletions

View file

@ -3,7 +3,10 @@ use bevy_spacetimedb::{
ReadInsertUpdateMessage, ReadStdbConnectedMessage, ReadStdbDisconnectedMessage, StdbPlugin,
};
use jong_db::{self, DbConnection, LobbyTableAccess, PlayerTableAccess, RemoteTables};
use jong_db::{
self, DbConnection, LobbyTableAccess, PlayerHand, PlayerTableAccess, RemoteTables,
ViewHandTableAccess as _,
};
use jong_db::{add_bot, set_ready};
use jong_types::*;
@ -19,11 +22,10 @@ impl Plugin for Riichi {
.with_uri("http://localhost:3000")
.with_module_name("jong-line")
.with_run_fn(DbConnection::run_threaded)
// TODO why don't I need to call add_reducer?
// TODO do these need to be subscription & vice-versa?
.add_table(RemoteTables::player)
.add_table(RemoteTables::lobby)
// TODO check bevy_spacetimedb PR status
.add_view_with_pk(RemoteTables::view_hand, |p| p.id)
// semicolon stopper
;
@ -87,104 +89,70 @@ fn subscriptions(stdb: SpacetimeDB) {
.on_applied(|_| trace!("made all subs!"))
.on_error(|_, err| error!("sub failed: {err}"))
.subscribe([
// TODO until views work
// TODO change these to sub/unsub based on being in lobby and some such
format!(
"SELECT * FROM player p WHERE p.identity = '{}'",
stdb.identity()
),
"SELECT l.* FROM lobby l JOIN player p ON l.host_player_id = p.id".to_string(),
"SELECT l.* FROM lobby l JOIN player p ON l.id = p.lobby_id".to_string(),
"SELECT c.* FROM player_clock c JOIN player p ON c.player_id = p.id".to_string(),
"SELECT * FROM view_hand".to_string(),
"SELECT b.* FROM bot b JOIN lobby l ON l.id = b.lobby_id".to_string(),
]);
// .subscribe_to_all_tables();
}
fn on_player_insert_update(
mut messages: ReadInsertUpdateMessage<jong_db::Player>,
fn on_view_hand_insert_update(
stdb: SpacetimeDB,
mut messages: ReadInsertUpdateMessage<jong_db::PlayerHand>,
mut commands: Commands,
pond: Option<Single<Entity, With<Pond>>>,
hand: Option<Single<Entity, With<Hand>>>,
tiles: Query<(Entity, &TileId)>,
mut hand: Option<Single<&mut Children, With<Hand>>>,
tiles: Query<&Tile>,
mut next_turnstate: ResMut<NextState<jong_types::states::TurnState>>,
) {
let hand = if hand.is_none() {
let hand = commands.spawn(Hand).id();
commands.spawn(Pond);
hand
} else {
*hand.unwrap()
};
let pond = if pond.is_none() {
let pond = commands.spawn(Pond).id();
commands.spawn(Pond);
pond
} else {
*pond.unwrap()
};
for msg in messages.read() {
/* match msg.new.turn_state {
jong_db::TurnState::None => {}
jong_db::TurnState::Tsumo => {
stdb.reducers().draw_tile().unwrap();
}
jong_db::TurnState::Menzen => todo!(),
jong_db::TurnState::RiichiKan => todo!(),
jong_db::TurnState::RonChiiPonKan => {
stdb.reducers().skip_call().unwrap();
}
jong_db::TurnState::End => todo!(),
if hand.is_none() {
let hand_tiles: Vec<_> = msg
.new
.hand
.iter()
.map(|dbt| commands.spawn((Tile::from(&dbt.tile), TileId(dbt.id))).id())
.collect();
commands.spawn(Hand).add_children(&hand_tiles);
}
let hand_tiles: Vec<_> = msg
.new
.hand
.iter()
.map(|dbt| {
tiles
.iter()
.find_map(|(e, t)| if *t == TileId(dbt.id) { Some(e) } else { None })
.or_else(|| Some(commands.spawn((Tile::from(&dbt.tile), TileId(dbt.id))).id()))
.unwrap()
})
.collect();
let pond_tiles: Vec<_> = msg
.new
.pond
.iter()
.map(|dbt| {
tiles
.iter()
.find_map(|(e, t)| if *t == TileId(dbt.id) { Some(e) } else { None })
.expect(&format!(
"dealt tiles should still be around, couldn't find {:?}. Tiles: {:?}",
dbt,
tiles.iter().map(|(_, t)| t).collect::<Vec<_>>()
))
})
.collect();
// match msg.new.turn_state {
// jong_db::TurnState::None => todo!(),
// jong_db::TurnState::Tsumo => todo!(),
// jong_db::TurnState::Menzen => todo!(),
// jong_db::TurnState::RiichiKan => todo!(),
// jong_db::TurnState::RonChiiPonKan => todo!(),
// jong_db::TurnState::End => todo!(),
// }
debug!("hand_tiles: {hand_tiles:?}");
commands.entity(hand).replace_children(&hand_tiles);
commands.entity(pond).replace_children(&pond_tiles);
// drawn tile is always a new tile to us until wall isn't fake
if let Some(dbt) = &msg.new.drawn_tile {
debug!("drew tile with id: {}", dbt.id);
commands.spawn((Tile::from(&dbt.tile), TileId(dbt.id), Drawn));
} */
next_turnstate.set(msg.new.turn_state.into());
}
}
fn on_player_insert_update(
stdb: SpacetimeDB,
mut messages: ReadInsertUpdateMessage<jong_db::Player>,
mut commands: Commands,
) {
for msg in messages.read() {}
}
fn on_lobby_insert_update(
stdb: SpacetimeDB,
mut messages: ReadInsertUpdateMessage<jong_db::Lobby>,
commands: Commands,
mut next_gamestate: ResMut<NextState<jong_types::states::GameState>>,
mut next_turnstate: ResMut<NextState<jong_types::states::TurnState>>,
) {
for msg in messages.read() {
// trace!("on_lobby_insert_update msg:\n{:#?}", msg.new);
trace!("on_lobby_insert_update msg:\n{:#?}", msg.new);
let player = stdb
.db()
@ -205,12 +173,10 @@ fn on_lobby_insert_update(
stdb.reducers().add_bot(player.lobby_id).unwrap();
}
stdb.reducers().set_ready(true).unwrap();
// stdb.reducers().start_game().unwrap();
}
}
jong_db::GameState::Setup => {
trace!("game entered setup");
// stdb.reducers().shuffle_deal(player.lobby_id).unwrap();
}
jong_db::GameState::Deal => {
trace!("game entered deal");

View file

@ -97,9 +97,8 @@ impl Plugin for TuiPlugin {
fn discard_tile(
stdb: SpacetimeDB,
mut selected: MessageReader<ConfirmSelect>,
mut commands: Commands,
mut selected: MessageReader<ConfirmSelect>,
drawn: Single<(Entity, &TileId), With<Drawn>>,
tiles: Query<&TileId>,
) {