243 lines
8.2 KiB
Rust
243 lines
8.2 KiB
Rust
#![allow(unused)]
|
|
|
|
use bevy::prelude::*;
|
|
use bevy_spacetimedb::{
|
|
ReadInsertUpdateMessage, ReadStdbConnectedMessage, ReadStdbDisconnectedMessage, StdbPlugin,
|
|
TableMessages,
|
|
};
|
|
use spacetimedb::Identity;
|
|
use spacetimedb_sdk::{DbContext, Table, credentials};
|
|
|
|
use crate::game::hand::Drawn;
|
|
use crate::stdb::{
|
|
self, DbConnection, LobbyTableAccess, PlayerTableAccess, RemoteTables, add_bot, draw_tile,
|
|
join_or_create_lobby, login_or_add_player, set_ready, shuffle_deal, start_game,
|
|
};
|
|
use crate::{
|
|
SpacetimeDB, creds_store,
|
|
game::{
|
|
self,
|
|
hand::{Hand, Pond},
|
|
player::{CurrentPlayer, MainPlayer, Player},
|
|
round::Wind,
|
|
wall::Wall,
|
|
},
|
|
tile::{self},
|
|
};
|
|
use jong_types::*;
|
|
|
|
pub mod hand;
|
|
pub mod player;
|
|
pub mod round;
|
|
pub mod wall;
|
|
|
|
#[derive(Message)]
|
|
pub enum GameMessage {
|
|
Discarded(Entity),
|
|
CallPending,
|
|
Called { player: Entity, calltype: Entity },
|
|
}
|
|
|
|
pub struct Riichi;
|
|
impl Plugin for Riichi {
|
|
fn build(&self, app: &mut App) {
|
|
let mut plugins = StdbPlugin::default()
|
|
.with_uri("http://localhost:3000")
|
|
.with_module_name("jongline")
|
|
.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)
|
|
|
|
// semicolon stopper
|
|
;
|
|
let plugins =
|
|
if let Some(token) = creds_store().load().expect("i/o error loading credentials") {
|
|
// FIXME patch plugin so this takes Option?
|
|
plugins.with_token(&token)
|
|
} else {
|
|
plugins
|
|
};
|
|
|
|
app.add_plugins(plugins)
|
|
.init_state::<GameState>()
|
|
.add_sub_state::<TurnState>()
|
|
// .init_resource::<round::MatchSettings>()
|
|
// .init_resource::<round::Compass>()
|
|
.add_message::<GameMessage>()
|
|
// .add_systems(Startup, tile::init_tiles)
|
|
// .add_systems(Update, hand::sort_hands.run_if(in_state(GameState::Play)))
|
|
// .add_systems(OnEnter(TurnState::Tsumo), round::tsumo)
|
|
// .add_systems(OnEnter(TurnState::Menzen), round::menzen)
|
|
// .add_systems(Update, round::riichi_kan.run_if(in_state(TurnState::RiichiKan)))
|
|
// .add_systems(Update, round::discard.run_if(in_state(TurnState::Discard)))
|
|
// .add_systems(OnEnter(TurnState::RonChiiPonKan), round::notify_callable)
|
|
// .add_systems(Update, round::ron_chi_pon_kan.run_if(in_state(TurnState::RonChiiPonKan)).after(round::notify_callable))
|
|
// .add_systems(OnEnter(TurnState::End), round::end)
|
|
// stdb
|
|
.add_systems(Startup, subscriptions)
|
|
.add_systems(Update, on_connect)
|
|
.add_systems(Update, on_disconnect)
|
|
.add_systems(Update, on_player_insert_update)
|
|
.add_systems(Update, on_lobby_insert_update)
|
|
// .add_systems(OnEnter(GameState::Lobby), join_or_create_lobby)
|
|
|
|
// semicolon stopper
|
|
;
|
|
}
|
|
}
|
|
fn on_connect(stdb: SpacetimeDB, mut messages: ReadStdbConnectedMessage, mut commands: Commands) {
|
|
for msg in messages.read() {
|
|
info!("you're now jongline");
|
|
debug!("with identity: {}", stdb.identity());
|
|
creds_store()
|
|
.save(&msg.access_token)
|
|
.expect("i/o error saving token");
|
|
}
|
|
}
|
|
|
|
// TODO how reconnect?
|
|
fn on_disconnect(stdb: SpacetimeDB, mut messages: ReadStdbDisconnectedMessage) {
|
|
for msg in messages.read() {
|
|
warn!("lost connection: {:#?}", msg.err);
|
|
}
|
|
}
|
|
|
|
fn subscriptions(stdb: SpacetimeDB) {
|
|
stdb.subscription_builder()
|
|
.on_applied(|_| trace!("made all subs!"))
|
|
.on_error(|_, err| error!("sub failed: {err}"))
|
|
.subscribe([
|
|
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(),
|
|
]);
|
|
// .subscribe_to_all_tables();
|
|
}
|
|
|
|
#[derive(Component)]
|
|
pub struct TileId(pub u32);
|
|
|
|
fn on_player_insert_update(
|
|
stdb: SpacetimeDB,
|
|
mut messages: ReadInsertUpdateMessage<stdb::Player>,
|
|
|
|
mut commands: Commands,
|
|
|
|
tiles: Query<(&Tile, &TileId, Entity)>,
|
|
mut player: Option<Single<&mut player::Player>>,
|
|
mut hand_ent: Option<Single<Entity, With<Hand>>>,
|
|
) {
|
|
use player::*;
|
|
|
|
for msg in messages.read() {
|
|
// debug!("player_insert_update msg:\n{:#?}", msg.new);
|
|
if let (Some(player), Some(hand_ent)) = (player.as_ref(), hand_ent.as_ref()) {
|
|
// if msg.old.as_ref().is_some_and(|m| !m.ready) && msg.new.ready {
|
|
// trace!("entered ready");
|
|
// // TODO add a start game button in the future
|
|
// stdb.reducers().start_game().unwrap();
|
|
// }
|
|
let mut tiles: Vec<_> = msg
|
|
.new
|
|
.hand
|
|
.iter()
|
|
.map(|dbt| {
|
|
// TODO this seems a lil expensive
|
|
if let Some(ent) = tiles
|
|
.iter()
|
|
.find(|(_, id, _)| id.0 == dbt.id)
|
|
.map(|(_, _, e)| e)
|
|
{
|
|
ent
|
|
} else {
|
|
commands.spawn((Tile::from(&dbt.tile), TileId(dbt.id))).id()
|
|
}
|
|
})
|
|
.collect();
|
|
commands.entity(**hand_ent).replace_children(&tiles);
|
|
if let Some(dbt) = &msg.new.drawn_tile {
|
|
commands.spawn((Tile::from(&dbt.tile), TileId(dbt.id), Drawn));
|
|
}
|
|
} else {
|
|
let player = Player {
|
|
name: msg
|
|
.new
|
|
.name
|
|
.as_ref()
|
|
.unwrap_or(&"nameless".to_string())
|
|
.clone(),
|
|
};
|
|
let bundle = (player, Hand, Pond, MainPlayer, CurrentPlayer);
|
|
commands.spawn(bundle);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn on_lobby_insert_update(
|
|
stdb: SpacetimeDB,
|
|
mut messages: ReadInsertUpdateMessage<stdb::Lobby>,
|
|
|
|
mut commands: Commands,
|
|
mut next_gamestate: ResMut<NextState<GameState>>,
|
|
mut next_turnstate: ResMut<NextState<TurnState>>,
|
|
) {
|
|
for msg in messages.read() {
|
|
// trace!("on_lobby_insert_update msg:\n{:#?}", msg.new);
|
|
|
|
let player = stdb
|
|
.db()
|
|
.player()
|
|
.identity()
|
|
.find(&stdb.identity())
|
|
.unwrap();
|
|
|
|
next_gamestate.set(msg.new.game_state.into());
|
|
match msg.new.game_state {
|
|
stdb::GameState::None => {
|
|
trace!("game entered none");
|
|
}
|
|
stdb::GameState::Lobby => {
|
|
trace!("game entered lobby");
|
|
if !player.ready {
|
|
for _ in 0..3 {
|
|
stdb.reducers().add_bot(player.lobby_id).unwrap();
|
|
}
|
|
stdb.reducers().set_ready(true).unwrap();
|
|
stdb.reducers().start_game().unwrap();
|
|
}
|
|
}
|
|
stdb::GameState::Setup => {
|
|
trace!("game entered setup");
|
|
stdb.reducers().shuffle_deal(player.lobby_id).unwrap();
|
|
}
|
|
stdb::GameState::Deal => {
|
|
trace!("game entered deal");
|
|
}
|
|
stdb::GameState::Play => {
|
|
trace!("game entered play");
|
|
match msg.new.turn_state {
|
|
stdb::TurnState::None => {}
|
|
stdb::TurnState::Tsumo => {
|
|
stdb.reducers().draw_tile().unwrap();
|
|
}
|
|
stdb::TurnState::Menzen => todo!(),
|
|
stdb::TurnState::RiichiKan => todo!(),
|
|
stdb::TurnState::Discard => todo!(),
|
|
stdb::TurnState::RonChiiPonKan => todo!(),
|
|
stdb::TurnState::End => todo!(),
|
|
}
|
|
next_turnstate.set(msg.new.turn_state.into());
|
|
}
|
|
stdb::GameState::Exit => {
|
|
trace!("game enetered exit");
|
|
}
|
|
}
|
|
|
|
next_gamestate.set(msg.new.game_state.into());
|
|
}
|
|
}
|