diff --git a/.helix/ignore b/.helix/ignore deleted file mode 100644 index 25da40d..0000000 --- a/.helix/ignore +++ /dev/null @@ -1 +0,0 @@ -jong-db diff --git a/.helix/languages.toml b/.helix/languages.toml index a35a590..3b9df02 100644 --- a/.helix/languages.toml +++ b/.helix/languages.toml @@ -1,6 +1,6 @@ -[language-server.lspmux] -command = "lspmux" +# [language-server.lspmux] +# command = "lspmux" -[[language]] -name = "rust" -language-servers = ["lspmux"] +# [[language]] +# name = "rust" +# language-servers = ["lspmux"] diff --git a/devenv.nix b/devenv.nix index af52a59..ea36f0b 100644 --- a/devenv.nix +++ b/devenv.nix @@ -4,10 +4,10 @@ ... }: rec { # https://devenv.sh/processes/ - processes.lspmux.exec = "lspmux server"; + # processes.lspmux.exec = "lspmux server"; processes.spacetimedb_start.exec = "spacetime start"; processes.spacetimedb_dev = { - exec = "just spacetime_dev"; + exec = "spacetime dev --module-bindings-path jong-db/src/db jong-line --delete-data=always"; # notify.enable = true; # TODO features not yet supp??? # restart = "always"; diff --git a/jong-db/src/lib.rs b/jong-db/src/lib.rs index 0d2a8d5..c6f9297 100644 --- a/jong-db/src/lib.rs +++ b/jong-db/src/lib.rs @@ -1,56 +1,54 @@ pub mod db; pub use db::*; -mod conversions { - impl From for jong_types::states::GameState { - fn from(value: crate::db::GameState) -> Self { - Self::from_repr(value as usize).unwrap() - } +impl From for jong_types::GameState { + fn from(value: GameState) -> Self { + Self::from_repr(value as usize).unwrap() } +} - impl From for jong_types::states::TurnState { - fn from(value: crate::db::TurnState) -> Self { - Self::from_repr(value as usize).unwrap() - } +impl From for jong_types::TurnState { + fn from(value: TurnState) -> Self { + Self::from_repr(value as usize).unwrap() } +} - impl From<&crate::db::Tile> for jong_types::tiles::Tile { - fn from(value: &crate::db::Tile) -> Self { - Self { - suit: value.suit.clone().into(), - } - } - } - - impl From for jong_types::tiles::Suit { - fn from(value: crate::db::Suit) -> Self { - match value { - crate::db::Suit::Man(rank) => Self::Man(rank.into()), - crate::db::Suit::Pin(rank) => Self::Pin(rank.into()), - crate::db::Suit::Sou(rank) => Self::Sou(rank.into()), - crate::db::Suit::Wind(wind) => Self::Wind(wind.into()), - crate::db::Suit::Dragon(dragon) => Self::Dragon(dragon.into()), - } - } - } - - impl From for jong_types::tiles::Rank { - fn from(value: crate::db::Rank) -> Self { - Self { - number: value.number, - } - } - } - - impl From for jong_types::tiles::Wind { - fn from(value: crate::db::Wind) -> Self { - Self::from_repr(value as usize).unwrap() - } - } - - impl From for jong_types::tiles::Dragon { - fn from(value: crate::db::Dragon) -> Self { - Self::from_repr(value as usize).unwrap() +impl From<&Tile> for jong_types::Tile { + fn from(value: &tile_type::Tile) -> Self { + Self { + suit: value.suit.clone().into(), } } } + +impl From for jong_types::Suit { + fn from(value: Suit) -> Self { + match value { + Suit::Man(rank) => Self::Man(rank.into()), + Suit::Pin(rank) => Self::Pin(rank.into()), + Suit::Sou(rank) => Self::Sou(rank.into()), + Suit::Wind(wind) => Self::Wind(wind.into()), + Suit::Dragon(dragon) => Self::Dragon(dragon.into()), + } + } +} + +impl From for jong_types::Rank { + fn from(value: Rank) -> Self { + Self { + number: value.number, + } + } +} + +impl From for jong_types::Wind { + fn from(value: Wind) -> Self { + Self::from_repr(value as usize).unwrap() + } +} + +impl From for jong_types::Dragon { + fn from(value: Dragon) -> Self { + Self::from_repr(value as usize).unwrap() + } +} diff --git a/jong-line/src/lib.rs b/jong-line/src/lib.rs index b626822..4a1b889 100644 --- a/jong-line/src/lib.rs +++ b/jong-line/src/lib.rs @@ -4,9 +4,7 @@ use spacetimedb::{ReducerContext, Table, reducer}; use crate::tables::{player::player, *}; mod reducers { - mod deal; - mod hand; - mod lobby; + mod game; } mod tables; @@ -15,18 +13,6 @@ pub fn clear_all(ctx: &ReducerContext) { for row in ctx.db.player().iter() { ctx.db.player().delete(row); } - for row in ctx.db.lobby().iter() { - ctx.db.lobby().delete(row); - } - for row in ctx.db.bot().iter() { - ctx.db.bot().delete(row); - } - for row in ctx.db.wall().iter() { - ctx.db.wall().delete(row); - } - for row in ctx.db.tile().iter() { - ctx.db.tile().delete(row); - } } #[reducer(client_connected)] diff --git a/jong-line/src/reducers/lobby.rs b/jong-line/src/reducers/game.rs similarity index 91% rename from jong-line/src/reducers/lobby.rs rename to jong-line/src/reducers/game.rs index 1a4df28..0519bd2 100644 --- a/jong-line/src/reducers/lobby.rs +++ b/jong-line/src/reducers/game.rs @@ -2,6 +2,10 @@ use log::info; use spacetimedb::{ReducerContext, Table, rand::seq::SliceRandom, reducer}; use crate::tables::{player::player, *}; +use jong_types::*; + +mod deal; +mod hand; #[reducer] pub fn join_or_create_lobby(ctx: &ReducerContext, mut lobby_id: u32) -> Result<(), String> { @@ -18,12 +22,12 @@ pub fn join_or_create_lobby(ctx: &ReducerContext, mut lobby_id: u32) -> Result<( id: 0, host_player_id: player.id, players: vec![PlayerOrBot::Player { id: player.id }], - game_state: jong_types::states::GameState::Lobby, - turn_state: jong_types::states::TurnState::None, + game_state: GameState::Lobby, + turn_state: TurnState::None, dealer_idx: 0, current_idx: 0, }); - info!("created lobby: {}", lobby.id); + info!("created lobby: {:?}", lobby); lobby_id = lobby.id; } @@ -79,7 +83,7 @@ pub fn start_game(ctx: &ReducerContext) { PlayerOrBot::Bot { id } => ctx.db.bot().id().find(id).is_some(), }) { - lobby.game_state = jong_types::states::GameState::Setup; + lobby.game_state = GameState::Setup; lobby.players.shuffle(&mut ctx.rng()); lobby.dealer_idx += 1; if lobby.dealer_idx > 3 { diff --git a/jong-line/src/reducers/bot.rs b/jong-line/src/reducers/game/bot.rs similarity index 100% rename from jong-line/src/reducers/bot.rs rename to jong-line/src/reducers/game/bot.rs diff --git a/jong-line/src/reducers/deal.rs b/jong-line/src/reducers/game/deal.rs similarity index 73% rename from jong-line/src/reducers/deal.rs rename to jong-line/src/reducers/game/deal.rs index e6e280f..99069f6 100644 --- a/jong-line/src/reducers/deal.rs +++ b/jong-line/src/reducers/game/deal.rs @@ -3,14 +3,15 @@ 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(); - if lobby.game_state == jong_types::states::GameState::Setup { - lobby.game_state = jong_types::states::GameState::Deal; + if lobby.game_state == GameState::Setup { + lobby.game_state = GameState::Deal; lobby = ctx.db.lobby().id().update(lobby); let tiles = new_shuffled_wall(ctx); @@ -23,15 +24,15 @@ pub fn shuffle_deal(ctx: &ReducerContext, lobby_id: u32) { deal_hands(ctx, lobby_id); - lobby.game_state = jong_types::states::GameState::Play; - lobby.turn_state = jong_types::states::TurnState::Tsumo; + lobby.game_state = GameState::Play; + lobby.turn_state = TurnState::Tsumo; ctx.db.lobby().id().update(lobby); } } pub fn new_shuffled_wall(ctx: &ReducerContext) -> Vec { let mut rng = ctx.rng(); - let mut wall: Vec<_> = jong_types::tiles::tiles() + let mut wall: Vec<_> = tiles() .into_iter() .map(|tile| ctx.db.tile().insert(DbTile { id: 0, tile })) .collect(); diff --git a/jong-line/src/reducers/hand.rs b/jong-line/src/reducers/game/hand.rs similarity index 77% rename from jong-line/src/reducers/hand.rs rename to jong-line/src/reducers/game/hand.rs index 1e3f18a..96fedb2 100644 --- a/jong-line/src/reducers/hand.rs +++ b/jong-line/src/reducers/game/hand.rs @@ -1,8 +1,8 @@ use log::{debug, trace}; -use spacetimedb::{ReducerContext, reducer}; +use spacetimedb::{ReducerContext, Table, reducer}; use crate::tables::{player::player, *}; -use jong_types::states::TurnState; +use jong_types::*; pub fn deal_hands(ctx: &ReducerContext, lobby_id: u32) { let players = ctx.db.player().lobby_id().filter(lobby_id); @@ -46,33 +46,17 @@ pub fn discard_tile(ctx: &ReducerContext, tile_id: u32) -> Result<(), String> { let mut player = ctx.db.player().identity().find(ctx.sender).unwrap(); let mut lobby = ctx.db.lobby().id().find(player.lobby_id).unwrap(); - let dealt_tile = if let Some(dealt) = ctx.db.tile().id().find(tile_id) { - if let Some(drawn) = player.drawn_tile { - if drawn.id == dealt.id { - dealt - } else if let Some((i, _)) = player - .hand - .iter() - .enumerate() - .find(|(_, t)| t.id == tile_id) - { - let dealt = player.hand.remove(i); - player.hand.push(drawn); - player.hand.sort_by_key(|t| t.tile); - - dealt - } else { - return Err(format!( - "player {} attempted to deal tile {} not in hand or drawn", - player.id, tile_id - )); - } - } else { - return Err(format!( - "player {} attempted to deal tile {} without having drawn", - player.id, tile_id - )); - } + let dealt_tile = if let Some(drawn) = player.drawn_tile + && drawn.id == tile_id + { + drawn + } else if let Some((i, _)) = player + .hand + .iter() + .enumerate() + .find(|(_, t)| t.id == tile_id) + { + player.hand.remove(i) } else { return Err(format!( "player {} attempted to deal nonexistant tile {}", @@ -95,7 +79,7 @@ pub fn discard_tile(ctx: &ReducerContext, tile_id: u32) -> Result<(), String> { #[reducer] pub fn skip_call(ctx: &ReducerContext) { trace!("skip_call"); - + let player = ctx.db.player().identity().find(ctx.sender).unwrap(); let mut lobby = ctx.db.lobby().id().find(player.lobby_id).unwrap(); diff --git a/jong-line/src/tables.rs b/jong-line/src/tables.rs index 17ec267..4295811 100644 --- a/jong-line/src/tables.rs +++ b/jong-line/src/tables.rs @@ -1,9 +1,6 @@ -use spacetimedb::{SpacetimeType, table}; +use spacetimedb::table; -use jong_types::{ - tiles::Tile, - states::{GameState, TurnState}, -}; +use jong_types::*; pub mod player; pub use player::*; @@ -17,7 +14,7 @@ pub struct Lobby { #[unique] pub host_player_id: u32, - pub players: Vec, + pub players: Vec, pub dealer_idx: u8, pub current_idx: u8, @@ -40,11 +37,5 @@ pub struct DbTile { #[auto_inc] pub id: u32, - pub tile: Tile, -} - -#[derive(Debug, Clone, SpacetimeType)] -pub enum PlayerOrBot { - Player { id: u32 }, - Bot { id: u32 }, + pub tile: jong_types::Tile, } diff --git a/jong-line/src/tables/player.rs b/jong-line/src/tables/player.rs index c3bf342..1767758 100644 --- a/jong-line/src/tables/player.rs +++ b/jong-line/src/tables/player.rs @@ -42,3 +42,9 @@ pub struct Bot { pub drawn_tile: Option, } + +#[derive(Debug, Clone, SpacetimeType)] +pub enum PlayerOrBot { + Player { id: u32 }, + Bot { id: u32 }, +} diff --git a/jong-types/src/lib.rs b/jong-types/src/lib.rs index e8c26f3..27b8fc5 100644 --- a/jong-types/src/lib.rs +++ b/jong-types/src/lib.rs @@ -9,8 +9,127 @@ mod derive_alias { } use derive_aliases::derive; -pub mod states; -pub mod tiles; +use bevy::prelude::*; +use spacetimedb::SpacetimeType; +use strum::{EnumCount, FromRepr}; -pub use states::*; -pub use tiles::*; +#[derive(..Base, Hash, Default, FromRepr)] +#[derive(States, SpacetimeType)] +pub enum GameState { + #[default] + None, + Lobby, + Setup, + Deal, + Play, + Exit, +} + +#[derive(..Base)] +#[derive(Component, SpacetimeType)] +pub struct Tile { + pub suit: Suit, +} + +#[derive(..Base)] +#[derive(SpacetimeType)] +pub enum Suit { + Man(Rank), + Pin(Rank), + Sou(Rank), + Wind(Wind), + Dragon(Dragon), +} + +impl Suit { + pub fn rank(&self) -> Option { + match self { + Suit::Man(rank) => Some(*rank), + Suit::Pin(rank) => Some(*rank), + Suit::Sou(rank) => Some(*rank), + // Suit::Wind(wind) | Suit::Dragon(dragon) => None, + _ => None, + } + } +} + +#[derive( + ..Base, + Deref, + DerefMut, +)] +#[derive(SpacetimeType)] +pub struct Rank { + pub number: u8, +} + +#[derive( + ..Base, + FromRepr, +)] +#[derive(SpacetimeType)] +pub enum Wind { + Ton, + Nan, + Shaa, + Pei, +} + +#[derive( + ..Base, + FromRepr, +)] +#[derive(SpacetimeType)] +pub enum Dragon { + Haku, + Hatsu, + Chun, +} + +pub fn tiles() -> Vec { + let mut tiles = vec![]; + for _ in 0..4 { + for i in 1..=9 { + tiles.push(Tile { + suit: Suit::Pin(Rank { number: i }), + }); + tiles.push(Tile { + suit: Suit::Sou(Rank { number: i }), + }); + tiles.push(Tile { + suit: Suit::Man(Rank { number: i }), + }); + } + for i in 0..4 { + tiles.push(Tile { + suit: Suit::Wind(Wind::from_repr(i).unwrap()), + }); + } + for i in 0..3 { + tiles.push(Tile { + suit: Suit::Dragon(Dragon::from_repr(i).unwrap()), + }); + } + } + tiles +} + +#[derive( + Default, + ..Copy, + PartialEq, + Eq, + Hash, + Debug, +)] +#[derive(SubStates, FromRepr, EnumCount, SpacetimeType)] +#[source(GameState = GameState::Play)] +pub enum TurnState { + #[default] + None, + Tsumo, + Menzen, + RiichiKan, + RonChiiPonKan, + End, +} diff --git a/jong-types/src/states.rs b/jong-types/src/states.rs deleted file mode 100644 index ccf0c5f..0000000 --- a/jong-types/src/states.rs +++ /dev/null @@ -1,37 +0,0 @@ -use bevy::prelude::*; -use spacetimedb::SpacetimeType; -use strum::{EnumCount, FromRepr}; - -use super::derive; - -#[derive(..Base, Hash, Default, FromRepr)] -#[derive(States, SpacetimeType)] -pub enum GameState { - #[default] - None, - Lobby, - Setup, - Deal, - Play, - Exit, -} - -#[derive( - Default, - ..Copy, - PartialEq, - Eq, - Hash, - Debug, -)] -#[derive(SubStates, FromRepr, EnumCount, SpacetimeType)] -#[source(GameState = GameState::Play)] -pub enum TurnState { - #[default] - None, - Tsumo, - Menzen, - RiichiKan, - RonChiiPonKan, - End, -} diff --git a/jong-types/src/tiles.rs b/jong-types/src/tiles.rs deleted file mode 100644 index c70ee29..0000000 --- a/jong-types/src/tiles.rs +++ /dev/null @@ -1,94 +0,0 @@ -use bevy::prelude::*; -use spacetimedb::SpacetimeType; -use strum::{EnumCount, FromRepr}; - -use super::derive; - -#[derive(..Base)] -#[derive(Component, SpacetimeType)] -pub struct Tile { - pub suit: Suit, -} - -#[derive(..Base)] -#[derive(SpacetimeType)] -pub enum Suit { - Man(Rank), - Pin(Rank), - Sou(Rank), - Wind(Wind), - Dragon(Dragon), -} - -impl Suit { - pub fn rank(&self) -> Option { - match self { - Suit::Man(rank) => Some(*rank), - Suit::Pin(rank) => Some(*rank), - Suit::Sou(rank) => Some(*rank), - // Suit::Wind(wind) | Suit::Dragon(dragon) => None, - _ => None, - } - } -} - -#[derive( - ..Base, - Deref, - DerefMut, -)] -#[derive(SpacetimeType)] -pub struct Rank { - pub number: u8, -} - -#[derive( - ..Base, - FromRepr, -)] -#[derive(SpacetimeType)] -pub enum Wind { - Ton, - Nan, - Shaa, - Pei, -} - -#[derive( - ..Base, - FromRepr, -)] -#[derive(SpacetimeType)] -pub enum Dragon { - Haku, - Hatsu, - Chun, -} - -pub fn tiles() -> Vec { - let mut tiles = vec![]; - for _ in 0..4 { - for i in 1..=9 { - tiles.push(Tile { - suit: Suit::Pin(Rank { number: i }), - }); - tiles.push(Tile { - suit: Suit::Sou(Rank { number: i }), - }); - tiles.push(Tile { - suit: Suit::Man(Rank { number: i }), - }); - } - for i in 0..4 { - tiles.push(Tile { - suit: Suit::Wind(Wind::from_repr(i).unwrap()), - }); - } - for i in 0..3 { - tiles.push(Tile { - suit: Suit::Dragon(Dragon::from_repr(i).unwrap()), - }); - } - } - tiles -} diff --git a/jong/src/riichi.rs b/jong/src/game.rs similarity index 71% rename from jong/src/riichi.rs rename to jong/src/game.rs index 0cd9eb9..344d5f3 100644 --- a/jong/src/riichi.rs +++ b/jong/src/game.rs @@ -2,22 +2,27 @@ use bevy::prelude::*; use bevy_spacetimedb::{ ReadInsertUpdateMessage, ReadStdbConnectedMessage, ReadStdbDisconnectedMessage, StdbPlugin, }; +use spacetimedb_sdk::{DbContext, Table}; +use crate::{ + SpacetimeDB, creds_store, + game::hand::{Drawn, Hand, Pond}, +}; use jong_db::{self, DbConnection, LobbyTableAccess, PlayerTableAccess, RemoteTables}; use jong_db::{add_bot, draw_tile, set_ready, shuffle_deal, skip_call, start_game}; use jong_types::*; +pub mod hand; pub mod player; -use crate::riichi::player::*; -use crate::{SpacetimeDB, creds_store}; -// pub mod round; +pub mod round; +pub mod wall; pub struct Riichi; impl Plugin for Riichi { fn build(&self, app: &mut App) { let plugins = StdbPlugin::default() .with_uri("http://localhost:3000") - .with_module_name("jong-line") + .with_module_name("jongline") .with_run_fn(DbConnection::run_threaded) // TODO why don't I need to call add_reducer? @@ -36,8 +41,8 @@ impl Plugin for Riichi { }; app.add_plugins(plugins) - .init_state::() - .add_sub_state::() + .init_state::() + .add_sub_state::() // .init_resource::() // .init_resource::() // .add_systems(Startup, tile::init_tiles) @@ -65,7 +70,6 @@ fn on_connect(stdb: SpacetimeDB, mut messages: ReadStdbConnectedMessage, _comman for msg in messages.read() { info!("you're now jongline"); - // FIXME hack that doesn't work for startup crash? while stdb.try_identity().is_none() {} debug!("with identity: {}", stdb.identity()); @@ -87,7 +91,6 @@ fn subscriptions(stdb: SpacetimeDB) { .on_applied(|_| trace!("made all subs!")) .on_error(|_, err| error!("sub failed: {err}")) .subscribe([ - // TODO until views work format!( "SELECT * FROM player p WHERE p.identity = '{}'", stdb.identity() @@ -97,40 +100,61 @@ fn subscriptions(stdb: SpacetimeDB) { // .subscribe_to_all_tables(); } +#[derive(Component)] +pub struct TileId(pub u32); + fn on_player_insert_update( + _stdb: SpacetimeDB, mut messages: ReadInsertUpdateMessage, + mut commands: Commands, - hand: Option>>, - tiles: Query<(Entity, &TileId)>, + tiles: Query<(&Tile, &TileId, Entity)>, + player: Option>, + hand_ent: Option>>, ) { - let hand = if hand.is_none() { - let hand = commands.spawn(Hand).id(); - hand - } else { - *hand.unwrap() - }; + use player::*; for msg in messages.read() { - 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(); - - debug!("hand_tiles: {hand_tiles:?}"); - - commands.entity(hand).replace_children(&hand_tiles); - - if let Some(dbt) = &msg.new.drawn_tile { - commands.spawn((Tile::from(&dbt.tile), TileId(dbt.id), Drawn)); + // 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 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); } } } @@ -139,9 +163,9 @@ fn on_lobby_insert_update( stdb: SpacetimeDB, mut messages: ReadInsertUpdateMessage, - commands: Commands, - mut next_gamestate: ResMut>, - mut next_turnstate: ResMut>, + _commands: Commands, + mut next_gamestate: ResMut>, + mut next_turnstate: ResMut>, ) { for msg in messages.read() { // trace!("on_lobby_insert_update msg:\n{:#?}", msg.new); @@ -188,6 +212,7 @@ fn on_lobby_insert_update( stdb.reducers().skip_call().unwrap(); } jong_db::TurnState::End => todo!(), + // _ => todo!(), } next_turnstate.set(msg.new.turn_state.into()); } diff --git a/jong/src/game/hand.rs b/jong/src/game/hand.rs new file mode 100644 index 0000000..2387f4a --- /dev/null +++ b/jong/src/game/hand.rs @@ -0,0 +1,41 @@ + +use bevy::prelude::*; + +use jong_types::*; + +#[derive(Component)] +pub struct Hand; + +#[derive(Component)] +pub struct Pond; + +#[derive(Component)] +pub struct Drawn; + +#[derive(Component)] +pub struct Discarded; + +// #[derive(Component, Default)] +// enum SortHand { +// #[default] +// Unsorted, +// Sort, +// Manual, +// } + +/// assumes hand is sorted +pub(crate) fn check_wincon(_hand: &[Tile; 14], _melds: &[&[Tile]]) -> bool { + // 4x3 + pair + // assume sorted + // + // let melds = hand.iter().array_chunks::<3>().all(|tiles| { + // let suit = discriminant(&tiles[0].suit); + // let starting_rank = tiles[0].suit + // // tiles.iter().all(|t| discriminant(&t.suit) == suit) && tiles.iter().zip(tiles[0].suit.rank()) + // }) && melds.iter().all(|meld| todo!()); + // let eyeball = todo!(); + + todo!(); + + // melds && eyeball +} diff --git a/jong/src/game/player.rs b/jong/src/game/player.rs new file mode 100644 index 0000000..32a531f --- /dev/null +++ b/jong/src/game/player.rs @@ -0,0 +1,21 @@ +use bevy::prelude::*; + +#[derive(Component, Debug, PartialEq)] +pub struct Player { + pub name: String, +} + +#[derive(Component)] +pub struct Points(pub isize); + +#[derive(Component)] +pub struct MainPlayer; + +#[derive(Component)] +pub struct CurrentPlayer; + +#[derive(Component)] +pub struct Dealer; + +#[derive(Component)] +pub struct Tsumo; diff --git a/jong/src/game/round.rs b/jong/src/game/round.rs new file mode 100644 index 0000000..031e8ed --- /dev/null +++ b/jong/src/game/round.rs @@ -0,0 +1,232 @@ + +use bevy::{platform::collections::HashMap, prelude::*}; +use strum::{EnumCount, FromRepr}; + +use crate::EnumNextCycle; +use jong_types::TurnState; + +// #[derive(Resource)] +// pub struct CurrentPlayer(pub Entity); + +#[derive(Resource)] +pub(crate) struct MatchSettings { + pub(crate) starting_points: isize, + pub(crate) player_count: u8, +} + +#[derive(Component)] +pub(crate) struct Dice(u8, u8); + +#[derive(Resource)] +pub(crate) struct Compass { + pub(crate) prevalent_wind: Wind, + pub(crate) round: u8, + pub(crate) dealer_wind: Wind, + pub(crate) riichi: usize, + pub(crate) honba: usize, +} + +#[derive(Component, Clone, Copy, FromRepr, EnumCount, PartialEq)] +pub enum Wind { + Ton, + Nan, + Shaa, + Pei, +} + +pub enum WindRelation { + Shimocha, + Toimen, + Kamicha, +} + +#[derive(Component, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) enum CallType { + Skip, + Ron, + Chii, + Pon, + Kan, +} + +impl Default for MatchSettings { + fn default() -> Self { + Self { + starting_points: 25000, + player_count: 4, + } + } +} + +impl Default for Compass { + fn default() -> Self { + Self { + prevalent_wind: Wind::Ton, + round: 1, + dealer_wind: Wind::Ton, + riichi: 0, + honba: 0, + } + } +} + +impl EnumNextCycle for Wind { + fn next(&self) -> Self { + if (*self as usize + 1) >= Self::COUNT { + Self::from_repr(0).unwrap() + } else { + Self::from_repr(*self as usize + 1).unwrap() + } + } +} + +impl Wind { + pub fn relate(&self, other: &Self) -> WindRelation { + if self.next() == *other { + WindRelation::Shimocha + } else if other.next() == *self { + WindRelation::Kamicha + } else { + WindRelation::Toimen + } + } +} + +impl EnumNextCycle for TurnState { + fn next(&self) -> Self { + if (*self as usize + 1) >= Self::COUNT { + Self::from_repr(0).unwrap() + } else { + Self::from_repr(*self as usize + 1).unwrap() + } + } +} + +// pub(crate) fn tsumo( +// mut commands: Commands, + +// // curr_player: Res, +// curr_player: Single>, +// wall: Single>, +// walltiles: Single<&Children, With>, + +// curr_turnstate: Res>, +// mut next_turnstate: ResMut>, +// ) { +// let drawn = walltiles.last().unwrap(); +// commands.entity(*wall).remove_child(*drawn); + +// let drawn = commands.entity(*drawn).insert(Drawn).id(); +// commands.entity(*curr_player).add_child(drawn); + +// debug!("tsumo for: {:?}, tile: {:?}", *curr_player, drawn); +// next_turnstate.set(curr_turnstate.next()); +// } + +// pub(crate) fn menzen( +// curr_turnstate: Res>, +// mut next_turnstate: ResMut>, +// ) { +// trace!("menzen check"); +// next_turnstate.set(curr_turnstate.next()); +// } + +// pub(crate) fn riichi_kan( +// curr_turnstate: Res>, +// mut next_turnstate: ResMut>, +// ) { +// trace!("riichi_kan"); +// next_turnstate.set(curr_turnstate.next()); +// } + +// #[allow(clippy::too_many_arguments, irrefutable_let_patterns)] +// pub(crate) fn discard( +// mut commands: Commands, +// mut reader: MessageReader, + +// curr_player: Single>, +// players: Query<&Children, With>, +// mut hands: Query<(&Children, Entity), (With, Without)>, +// drawn: Single>, + +// curr_turnstate: Res>, +// mut next_turnstate: ResMut>, +// ) -> Result { +// // trace!("discard"); +// let (handtiles, hand) = hands.get_mut(players.get(*curr_player)?.iter().next().unwrap())?; + +// let mut done = false; +// while let Some(message) = reader.read().next() { +// if let GameMessage::Discarded(discarded) = message { +// debug!("discarded: {discarded:?}"); +// if *discarded == *drawn { +// } else if handtiles.contains(discarded) { +// commands +// .entity(hand) +// .remove_child(*discarded) +// .add_child(*drawn); +// } else { +// panic!("current hand nor drawn tile contains discarded tile") +// } +// commands.entity(*drawn).remove::(); +// commands.entity(*discarded).insert(Discarded); + +// done = true; +// break; +// } +// } + +// if done { +// next_turnstate.set(curr_turnstate.next()); +// } +// Ok(()) +// } + +#[derive(Resource)] +pub struct PendingCalls { + eligible: Vec, + calls: HashMap, +} + +// pub(crate) fn notify_callable() {} + +// pub(crate) fn ron_chi_pon_kan( +// mut commands: Commands, +// mut reader: MessageReader, + +// discarded: Single>, +// mut ponds: Query<(&Children, Entity), (With, Without)>, +// calls: Query<&CallType>, + +// curr_turnstate: Res>, +// mut next_turnstate: ResMut>, +// ) { +// // check if can call? +// // message players? +// // collect then prioritize + +// // let mut received = vec![]; +// let mut received: Vec<_> = reader +// .read() +// .filter_map(|m| { +// if let GameMessage::Called { player, calltype } = m +// && let Ok(calltype) = calls.get(*calltype) +// { +// Some((calltype, player)) +// } else { +// None +// } +// }) +// .collect(); +// // received.sort_unstable_by_key(|(c, t)| c); +// // received.sort_unstable_by_key(|m| m.); + +// next_turnstate.set(curr_turnstate.next()); +// } + +// pub(crate) fn end( +// curr_turnstate: Res>, +// mut next_turnstate: ResMut>, +// ) { +// next_turnstate.set(curr_turnstate.next()); +// } diff --git a/jong/src/game/wall.rs b/jong/src/game/wall.rs new file mode 100644 index 0000000..e382cf6 --- /dev/null +++ b/jong/src/game/wall.rs @@ -0,0 +1,7 @@ +use bevy::prelude::*; + +#[derive(Component)] +pub struct Wall; + +#[derive(Component)] +pub struct Dead; diff --git a/jong/src/gui/mod.rs b/jong/src/gui/mod.rs new file mode 100644 index 0000000..36ea966 --- /dev/null +++ b/jong/src/gui/mod.rs @@ -0,0 +1,29 @@ +use bevy::{color::palettes::css::GREEN, prelude::*}; + +pub(crate) fn init_environment(mut commands: Commands) { + commands.spawn(( + DirectionalLight { + shadows_enabled: true, + ..default() + }, + // Transform::from_xyz(), + )); + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(-200.5, 100., 0.).looking_at(Vec3::ZERO, Vec3::Y), + )); +} + +pub(crate) fn init_table( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + let green: Color = GREEN.into(); + let table = Cuboid::new(1000., 5., 1000.); + + commands.spawn(( + Mesh3d(meshes.add(table)), + MeshMaterial3d(materials.add(green)), + )); +} diff --git a/jong/src/lib.rs b/jong/src/lib.rs index 9dcaa70..1d548af 100644 --- a/jong/src/lib.rs +++ b/jong/src/lib.rs @@ -4,7 +4,9 @@ use bevy::prelude::*; use bevy_spacetimedb::StdbConnection; use spacetimedb_sdk::credentials; -pub mod riichi; +pub mod game; +pub mod tile; +pub mod yakus; trait EnumNextCycle { fn next(&self) -> Self; @@ -13,5 +15,6 @@ trait EnumNextCycle { pub type SpacetimeDB<'a> = Res<'a, StdbConnection>; fn creds_store() -> credentials::File { - credentials::File::new("jong-line") + credentials::File::new("jongline") } + diff --git a/jong/src/main.rs b/jong/src/main.rs index 137cbff..66cb09b 100644 --- a/jong/src/main.rs +++ b/jong/src/main.rs @@ -3,7 +3,7 @@ use clap::{Parser, Subcommand}; use tracing::Level; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; -// mod gui; +mod gui; mod tui; #[derive(Parser)] @@ -25,11 +25,15 @@ fn main() { let mut app = App::new(); let app = match args.mode { - Mode::RunGui => app.add_plugins(DefaultPlugins.set(LogPlugin { - filter: FILTERSTRING.into(), - level: Level::TRACE, - ..Default::default() - })), + Mode::RunGui => { + app.add_plugins(DefaultPlugins.set(LogPlugin { + filter: FILTERSTRING.into(), + level: Level::TRACE, + // custom_layer: todo!(), + // fmt_layer: todo!(), + ..Default::default() + })) + } Mode::RunTui => { tracing_subscriber::registry() .with(tui_logger::TuiTracingSubscriberLayer) @@ -41,7 +45,7 @@ fn main() { } }; - app.add_plugins(jong::riichi::Riichi); + app.add_plugins(jong::game::Riichi); app.run(); } diff --git a/jong/src/riichi/player.rs b/jong/src/riichi/player.rs deleted file mode 100644 index 8c7ee4c..0000000 --- a/jong/src/riichi/player.rs +++ /dev/null @@ -1,25 +0,0 @@ -use bevy::prelude::*; - -#[derive(Component)] -pub struct Player; - -#[derive(Component)] -pub struct MainPlayer; - -#[derive(Component)] -pub struct CurrentPlayer; - -#[derive(Component, PartialEq, Eq)] -pub struct TileId(pub u32); - -#[derive(Component)] -pub struct Hand; - -#[derive(Component)] -pub struct Pond; - -#[derive(Component)] -pub struct Drawn; - -#[derive(Component)] -pub struct Discarded; diff --git a/jong/src/riichi/round.rs b/jong/src/riichi/round.rs deleted file mode 100644 index a538679..0000000 --- a/jong/src/riichi/round.rs +++ /dev/null @@ -1,100 +0,0 @@ -use bevy::{platform::collections::HashMap, prelude::*}; -use strum::{EnumCount, FromRepr}; - -use crate::EnumNextCycle; -use jong_types::states::TurnState; - -// #[derive(Resource)] -// pub struct CurrentPlayer(pub Entity); - -#[derive(Resource)] -pub(crate) struct MatchSettings { - pub(crate) starting_points: isize, - pub(crate) player_count: u8, -} - -#[derive(Component)] -pub(crate) struct Dice(u8, u8); - -#[derive(Resource)] -pub(crate) struct Compass { - pub(crate) prevalent_wind: Wind, - pub(crate) round: u8, - pub(crate) dealer_wind: Wind, - pub(crate) riichi: usize, - pub(crate) honba: usize, -} - -pub enum WindRelation { - Shimocha, - Toimen, - Kamicha, -} - -#[derive(Component, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) enum CallType { - Skip, - Ron, - Chii, - Pon, - Kan, -} - -impl Default for MatchSettings { - fn default() -> Self { - Self { - starting_points: 25000, - player_count: 4, - } - } -} - -impl Default for Compass { - fn default() -> Self { - Self { - prevalent_wind: Wind::Ton, - round: 1, - dealer_wind: Wind::Ton, - riichi: 0, - honba: 0, - } - } -} - -impl EnumNextCycle for Wind { - fn next(&self) -> Self { - if (*self as usize + 1) >= Self::COUNT { - Self::from_repr(0).unwrap() - } else { - Self::from_repr(*self as usize + 1).unwrap() - } - } -} - -impl Wind { - pub fn relate(&self, other: &Self) -> WindRelation { - if self.next() == *other { - WindRelation::Shimocha - } else if other.next() == *self { - WindRelation::Kamicha - } else { - WindRelation::Toimen - } - } -} - -impl EnumNextCycle for TurnState { - fn next(&self) -> Self { - if (*self as usize + 1) >= Self::COUNT { - Self::from_repr(0).unwrap() - } else { - Self::from_repr(*self as usize + 1).unwrap() - } - } -} - -#[derive(Resource)] -pub struct PendingCalls { - eligible: Vec, - calls: HashMap, -} diff --git a/jong/src/tile.rs b/jong/src/tile.rs new file mode 100644 index 0000000..3c4267c --- /dev/null +++ b/jong/src/tile.rs @@ -0,0 +1,11 @@ +use bevy::prelude::*; + +use jong_types::*; + +#[derive(Component)] +pub struct Dora; + +pub fn init_tiles(mut commands: Commands) { + let tiles = tiles(); + commands.spawn_batch(tiles); +} diff --git a/jong/src/tui.rs b/jong/src/tui.rs index 18b994c..f58fb51 100644 --- a/jong/src/tui.rs +++ b/jong/src/tui.rs @@ -4,17 +4,35 @@ use std::time::Duration; use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin}; use bevy_ratatui::RatatuiPlugins; +use jong::game::TileId; +use jong::game::player::MainPlayer; use tui_logger::TuiWidgetState; -use jong::{SpacetimeDB, riichi::player::*}; +use crate::tui::{input::ConfirmSelect, states::ConsoleWidget}; +use jong::{ + SpacetimeDB, + game::{ + hand::{Drawn, Hand}, + player::{CurrentPlayer, Player}, + }, +}; use jong_db::{self, discard_tile as _}; -use jong_types::states::{GameState, TurnState}; +use jong_types::{GameState, TurnState}; mod input; mod layout; mod render; -use input::ConfirmSelect; -use states::ConsoleWidget; + +#[derive(Default)] +pub struct TuiPlugin; + +#[derive(Clone, Debug, Eq, Hash, PartialEq, SystemSet)] +pub enum TuiSet { + Input, + Layout, + Render, +} + mod states { use bevy::prelude::*; use tui_logger::TuiWidgetState; @@ -41,16 +59,6 @@ mod states { // } } -#[derive(Default)] -pub struct TuiPlugin; - -#[derive(Clone, Debug, Eq, Hash, PartialEq, SystemSet)] -pub enum TuiSet { - Input, - Layout, - Render, -} - impl Plugin for TuiPlugin { fn build(&self, app: &mut App) { app.add_plugins(( @@ -85,7 +93,7 @@ impl Plugin for TuiPlugin { .add_systems( Update, ( - render::render_hand.run_if(in_state(GameState::Play)), + render::render_hands.run_if(in_state(GameState::Play)), render::render, ) .chain() @@ -101,9 +109,20 @@ fn discard_tile( mut commands: Commands, drawn: Single<(Entity, &TileId), With>, + // curr_player: Single>, + // player_hands: Populated<(&Player, &Children), With>, + // hands: Populated<&Children, (With, Without)>, + main_player: Single<(&Player, Entity), With>, + hands: Query<(&Children, Entity), With>, tiles: Query<&TileId>, ) { - while let Some(message) = selected.read().next() { + // trace!("discard_tile"); + + let (hand, hand_ent) = hands.iter().next().unwrap(); + + while let Some(message) = selected.read().next() + // && (message.0 == drawn.0 || hand.contains(&message.0)) + { if let Ok(tile_id) = tiles.get(message.0) { stdb.reducers().discard_tile(tile_id.0).unwrap(); commands.get_entity(drawn.0).unwrap().despawn(); diff --git a/jong/src/tui/input/keyboard.rs b/jong/src/tui/input/keyboard.rs index be09002..3e75e64 100644 --- a/jong/src/tui/input/keyboard.rs +++ b/jong/src/tui/input/keyboard.rs @@ -7,6 +7,7 @@ use jong_db::start_game; use tui_logger::TuiWidgetEvent; use jong::SpacetimeDB; +use jong_types::GameState; use crate::tui::layout::Overlays; use crate::tui::states::ConsoleWidget; @@ -20,9 +21,9 @@ pub(crate) fn keyboard( mut consolewidget: ResMut, mut exit: MessageWriter, - curr_gamestate: Res>, + curr_gamestate: Res>, curr_tuistate: Res>, - mut next_gamestate: ResMut>, + mut next_gamestate: ResMut>, mut next_tuistate: ResMut>, ) { 'message: for message in messages.read() { diff --git a/jong/src/tui/render.rs b/jong/src/tui/render.rs index f1a243c..5fe828b 100644 --- a/jong/src/tui/render.rs +++ b/jong/src/tui/render.rs @@ -6,9 +6,9 @@ use ratatui::layout::{Constraint, Flex, Layout, Offset, Rect, Size}; use ratatui::style::{Modifier, Stylize}; use ratatui::widgets::{Block, Borders, Clear, Paragraph}; -use jong::riichi::player::{CurrentPlayer, MainPlayer, Player}; -use jong::riichi::player::{Drawn, Hand}; -// use jong::riichi::round::Wind; +use jong::game::hand::{Drawn, Hand}; +use jong::game::player::{CurrentPlayer, MainPlayer, Player}; +use jong::game::round::Wind; // use jong_types::*; use crate::tui::input::Hovered; @@ -95,9 +95,26 @@ pub(crate) fn render( Ok(()) } +// pub(crate) fn render_arg_check( +// mut commands: Commands, +// mut tui: ResMut, + +// hovered: Query>, +// layouts: Res, + +// tiles: Query<&jong_types::Tile>, +// // main_player: Single<(&Player, Entity, &Wind), With>, +// curr_player: Single>, +// players: Query<(&Player, Entity, &Children)>, +// hands: Query<(&Children, Entity), (With, Without)>, +// // drawn_tile: Single>, +// ) { +// // trace!("arg!"); +// } + // FIXME we don't care about other players atm #[allow(clippy::too_many_arguments, clippy::type_complexity)] -pub(crate) fn render_hand( +pub(crate) fn render_hands( mut commands: Commands, mut tui: ResMut, @@ -105,67 +122,80 @@ pub(crate) fn render_hand( layouts: Res, tiles: Query<&jong_types::Tile>, - // main_player: Single<(&Player, Entity /* , &Wind */), With>, - hand: Single<(&Children, Entity), With>, - drawn_tile: Option>>, + main_player: Single<(&Player, Entity /* , &Wind */), With>, + curr_player: Single>, + players: Query<(&Player, Entity, &Children)>, + hands: Query<(&Children, Entity), With>, + drawn_tile: Single>, ) -> Result { let mut frame = tui.get_frame(); debug_blocks(*layouts, &mut frame); - let hand: Vec<_> = hand - .0 - .iter() - .map(|entity| -> Result<_> { - let tile = tiles.get(entity).unwrap_or_else(|_| panic!("{entity:?}")); - let hovered = hovered.contains(entity); - let widget = render_tile(tile, hovered); + for (hand, hand_ent) in hands { + // debug!("{hand:?}"); + // let (player, player_ent, _) = players + // .iter() + // .find(|(_, e, c)| c.contains(&hand_ent)) + // .unwrap(); + let hand: Vec<_> = hand + .iter() + .map(|entity| -> Result<_> { + let tile = tiles.get(entity).unwrap_or_else(|_| panic!("{entity:?}")); + let hovered = hovered.contains(entity); + let widget = render_tile(tile, hovered); - Ok((entity, widget, hovered)) - }) - .collect::>()?; + Ok((entity, widget, hovered)) + }) + .collect::>()?; - // let (player, player_ent) = *main_player; - // split main box into thirds - let mut this_hand = layouts.this_hand; - let tile_drawn = if drawn_tile.is_some() { 7 } else { 0 }; - let hand_draw_meld = Layout::horizontal([ - Constraint::Max(hand.len() as u16 * 5), - Constraint::Max(tile_drawn), - Constraint::Fill(1), - ]) - .flex(Flex::SpaceBetween); - this_hand = this_hand.offset(Offset { - x: 0, - y: this_hand.height.abs_diff(5) as i32 + 1, - }); - this_hand = this_hand.resize(Size { - width: this_hand.width, - height: 4, - }); - let [hand_area, drawn_area, meld_area] = hand_draw_meld.areas::<3>(this_hand); + let (player, player_ent) = *main_player; + // if player == main_player.0 { + // split main box into thirds + let mut this_hand = layouts.this_hand; + // let this_drawer = drawn_tile..is_some_and(|dt| dt.0 == player); + let this_drawer = player_ent == *curr_player; + let tile_drawn = if this_drawer { 7 } else { 0 }; + let hand_draw_meld = Layout::horizontal([ + Constraint::Max(hand.len() as u16 * 5), + Constraint::Max(tile_drawn), + Constraint::Fill(1), + ]) + .flex(Flex::SpaceBetween); + this_hand = this_hand.offset(Offset { + x: 0, + y: this_hand.height.abs_diff(5) as i32 + 1, + }); + this_hand = this_hand.resize(Size { + width: this_hand.width, + height: 4, + }); + let [hand_area, drawn_area, meld_area] = hand_draw_meld.areas::<3>(this_hand); - // split hand area into tile areas - let mut constraints = vec![Constraint::Max(5); hand.len()]; - constraints.push(Constraint::Fill(1)); - let layout = Layout::horizontal(constraints).flex(Flex::Start); - let tile_areas = layout.split(hand_area); + // split hand area into tile areas + let mut constraints = vec![Constraint::Max(5); hand.len()]; + constraints.push(Constraint::Fill(1)); + let layout = Layout::horizontal(constraints).flex(Flex::Start); + let tile_areas = layout.split(hand_area); - for ((entity, widget, hovered), mut area) in hand.into_iter().zip(tile_areas.iter().copied()) { - if hovered { - area = area.offset(Offset { x: 0, y: -1 }); - let mut hitbox = area.as_size(); - hitbox.height += 1; - commands.entity(entity).insert(PickRegion { - area: area.resize(hitbox), - }); - } else { - commands.entity(entity).insert(PickRegion { area }); + for ((entity, widget, hovered), mut area) in + hand.into_iter().zip(tile_areas.iter().copied()) + { + if hovered { + area = area.offset(Offset { x: 0, y: -1 }); + let mut hitbox = area.as_size(); + hitbox.height += 1; + commands.entity(entity).insert(PickRegion { + area: area.resize(hitbox), + }); + } else { + commands.entity(entity).insert(PickRegion { area }); + } + frame.render_widget(widget, area); } - frame.render_widget(widget, area); - } - // tsumo tile - if let Some(drawn_tile) = drawn_tile { + // tsumo tile + // if this_drawer { + // // trace!("this_drawer"); let mut area = drawn_area.resize(Size { width: 5, height: 4, @@ -184,16 +214,16 @@ pub(crate) fn render_hand( commands.entity(*drawn_tile).insert(PickRegion { area }); } frame.render_widget(widget, area); + // } + // TODO draw melds + // } else { + // match mainplayer.1.relate(wind) { + // jong::game::round::WindRelation::Shimocha => todo!(), + // jong::game::round::WindRelation::Toimen => todo!(), + // jong::game::round::WindRelation::Kamicha => todo!(), + // } + // } } - // TODO draw melds - // } else { - // match mainplayer.1.relate(wind) { - // jong::game::round::WindRelation::Shimocha => todo!(), - // jong::game::round::WindRelation::Toimen => todo!(), - // jong::game::round::WindRelation::Kamicha => todo!(), - // } - // } - Ok(()) } diff --git a/jong/src/yakus.rs b/jong/src/yakus.rs new file mode 100644 index 0000000..5a84fab --- /dev/null +++ b/jong/src/yakus.rs @@ -0,0 +1 @@ +// const TSUMO; diff --git a/justfile b/justfile index 8f51801..1e14034 100644 --- a/justfile +++ b/justfile @@ -8,8 +8,7 @@ default: just --list run-tui: - just spacetime_restart_dev - sleep 3sec + spacetime call jong-line "clear_all" cargo run -- run-tui update: @@ -20,10 +19,16 @@ spacetime: devenv up spacetime_dev: - spacetime dev --module-project-path jong-line --module-bindings-path jong-db/src/db jong-line --delete-data=always + spacetime dev --module-bindings-path jong-db/src/db jong-line --delete-data=always spacetime_generate-bindings: spacetime generate --lang rust --out-dir jong-db/src/db --project-path jong-line spacetime_restart_dev: mprocs -s localhost:4050 --ctl $"({c: restart-proc, name: spacetimedb_dev} | to yaml)" + +rrt: + just spacetime_restart_dev + sleep 3sec + just run-tui +