diff --git a/Cargo.lock b/Cargo.lock index 02ab506..49cf5ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3274,10 +3274,8 @@ dependencies = [ "bevy_ratatui", "clap", "log", - "rand 0.9.2", "ratatui", "strum", - "tracing", "tracing-subscriber", "tui-logger", ] diff --git a/Cargo.toml b/Cargo.toml index 8ba3c20..fe51bfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,10 +18,8 @@ log = { version = "0.4.29", features = [ "release_max_level_error", "max_level_trace", ] } -rand = "0.9.2" ratatui = "0.30.0" strum = { version = "0.27.2", features = ["derive"] } -tracing = "0.1.44" tracing-subscriber = "0.3.22" tui-logger = { version = "0.18.0", features = ["tracing-support", "crossterm"] } diff --git a/src/game/hand.rs b/src/game/hand.rs deleted file mode 100644 index 4daa915..0000000 --- a/src/game/hand.rs +++ /dev/null @@ -1,54 +0,0 @@ -use bevy::prelude::*; - -use crate::{game::wall::WallTiles, tiles::Tile}; - -#[derive(Component)] -pub struct Hand; - -#[derive(Component)] -#[relationship(relationship_target = HandTiles)] -pub struct InHand(pub Entity); - -#[derive(Component)] -#[relationship_target(relationship = InHand, linked_spawn)] -pub struct HandTiles(Vec); - -pub(crate) fn deal_hands( - mut commands: Commands, - walltiles: Single<&WallTiles>, - walltiles_entity: Single>, -) -> Result { - let hand = walltiles.iter().collect::>(); - - commands - .get_entity(*walltiles_entity)? - .remove_children(hand.last_chunk::<13>().unwrap()); - - commands.spawn((Hand, HandTiles(hand))); - - trace!("dealt hands"); - Ok(()) -} - -pub(crate) fn sort_hand( - mut commands: Commands, - tiles: Populated<&Tile>, - handtiles_entity: Single>, - handtiles: Single<&HandTiles, Changed>, -) -> Result { - let mut hand: Vec<_> = handtiles - .iter() - .map(|e| -> Result<(_, _)> { Ok((tiles.get(e)?, e)) }) - .collect::>()?; - - hand.sort_by_key(|(t, _)| t.suit); - - let hand: Vec<_> = hand.iter().map(|(_, e)| *e).collect(); - - commands - .get_entity(*handtiles_entity)? - .replace_children(&hand); - - trace!("sort_hand"); - Ok(()) -} diff --git a/src/game/mod.rs b/src/game/mod.rs index b099460..14eeaf2 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -1,40 +1,22 @@ + use bevy::prelude::*; use crate::tiles::{self, *}; -pub mod hand; -pub mod player; -pub mod wall; - -#[derive(States, Default, Hash, Clone, Eq, Debug, PartialEq, Copy)] -pub enum GameState { - #[default] - None, - Setup, - // Deal, - Play, - Score, -} +mod player; +pub(crate) mod wall; pub struct Riichi; + impl Plugin for Riichi { fn build(&self, app: &mut App) { app.init_resource::() .add_systems(Startup, init_match) .add_systems(Startup, tiles::init_tiles) - .init_state::() - .add_systems(OnEnter(GameState::Setup), (wall::build_wall, hand::deal_hands, setup_done).chain()) - .add_systems(Update, (hand::sort_hand).run_if(in_state(GameState::Play))) - // semicolon stopper - ; + .add_systems(Startup, wall::build_wall); } } -fn setup_done(mut next: ResMut>) { - next.set(GameState::Play); - trace!("setup_done"); -} - #[derive(Component)] pub(crate) struct Dice(u8, u8); diff --git a/src/game/player.rs b/src/game/player.rs index e4e3323..45d3c04 100644 --- a/src/game/player.rs +++ b/src/game/player.rs @@ -1,17 +1,9 @@ use bevy::prelude::*; -use crate::{ - game::wall::{InWall, Wall}, - tiles::Tile, -}; - #[derive(Component)] pub(crate) struct Player { pub(crate) name: String, } -fn spawn_players(mut commands: Commands) {} - #[derive(Component)] pub(crate) struct Points(pub isize); - diff --git a/src/game/wall.rs b/src/game/wall.rs index 69e4fd7..2692952 100644 --- a/src/game/wall.rs +++ b/src/game/wall.rs @@ -1,26 +1,11 @@ + use bevy::prelude::*; -use rand::seq::SliceRandom; use crate::tiles::Tile; #[derive(Component)] -pub struct Wall; +pub(crate) struct Wall(Vec); -#[derive(Component)] -#[relationship_target(relationship = InWall, linked_spawn)] -pub struct WallTiles(Vec); - -#[derive(Component)] -#[relationship(relationship_target = WallTiles)] -pub struct InWall(pub Entity); - -pub(crate) fn build_wall(mut commands: Commands, tiles: Query>) { - let mut rng = rand::rng(); - - let mut shuffled = tiles.iter().collect::>(); - shuffled.shuffle(&mut rng); - - commands.spawn((Wall, WallTiles(shuffled))); - - trace!("build_wall"); +pub(crate) fn build_wall(_tiles: Query<&Tile>) { + info!("built a wall!") } diff --git a/src/lib.rs b/src/lib.rs index 45412c3..8a1fb07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,4 @@ -#![allow(unused)] - -pub mod game; pub mod tiles; pub mod yakus; + +pub mod game; diff --git a/src/main.rs b/src/main.rs index 0481b30..641d6df 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,6 @@ -#![allow(unused)] - -use bevy::{log::LogPlugin, prelude::*}; +use bevy::prelude::*; use clap::{Parser, Subcommand}; -use tracing::Level; -use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; +use tracing_subscriber::{layer::SubscriberExt, registry::LookupSpan, util::SubscriberInitExt}; mod gui; mod tui; @@ -20,30 +17,25 @@ enum Mode { RunTui, } -const FILTERSTRING: &str = "warn,jong=trace"; - fn main() { + // tracing_subscriber::fmt() + // .with_writer(std::io::stderr) + // .with_env_filter("warn,jong=trace") + // .init(); + let args = Args::parse(); let mut app = App::new(); let app = match args.mode { - Mode::RunGui => { - app.add_plugins(DefaultPlugins.set(LogPlugin { - filter: FILTERSTRING.into(), - level: Level::TRACE, - // custom_layer: todo!(), - // fmt_layer: todo!(), - ..Default::default() - })) - } + Mode::RunGui => app.add_plugins(DefaultPlugins), Mode::RunTui => { tracing_subscriber::registry() .with(tui_logger::TuiTracingSubscriberLayer) .init(); tui_logger::init_logger(tui_logger::LevelFilter::Trace).unwrap(); - tui_logger::set_env_filter_from_string(FILTERSTRING); + tui_logger::set_env_filter_from_string("warn,jong=trace"); - app.add_plugins(tui::RiichiTui::default()) + app.add_plugins(tui::RiichiTui) } }; diff --git a/src/tiles.rs b/src/tiles.rs index 5147233..c00ef9c 100644 --- a/src/tiles.rs +++ b/src/tiles.rs @@ -1,24 +1,36 @@ use bevy::{ecs::entity::MapEntities, prelude::*}; use strum::FromRepr; -#[derive(Component, Debug)] + +// #[derive(Component)] +// #[derive(relasionship(re))] +// pub struct TileEntity { +// #[relationship] +// pub parent: Entity, + +// r#type: Tile, +// } + +struct Hand; + +#[derive(Component)] pub struct Tile { - pub suit: Suit, + suit: Suit, } -#[derive(MapEntities, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)] +#[derive(MapEntities)] pub enum Suit { - Man(Rank), Pin(Rank), Sou(Rank), + Man(Rank), Wind(Wind), Dragon(Dragon), } -#[derive(Deref, DerefMut, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)] -pub struct Rank(pub u8); +#[derive(Deref, DerefMut)] +pub struct Rank(u8); -#[derive(FromRepr, Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)] +#[derive(FromRepr)] pub enum Wind { Ton, Nan, @@ -26,7 +38,7 @@ pub enum Wind { Pei, } -#[derive(Debug, FromRepr, PartialEq, PartialOrd, Eq, Ord, Clone, Copy)] +#[derive(FromRepr)] pub enum Dragon { Haku, Hatsu, diff --git a/src/tui/console.rs b/src/tui/console.rs index f668331..db20cf8 100644 --- a/src/tui/console.rs +++ b/src/tui/console.rs @@ -1,13 +1,14 @@ -use bevy::prelude::*; -use bevy_ratatui::RatatuiContext; -use ratatui::widgets::Block; use tui_logger::TuiLoggerWidget; +use bevy_ratatui::RatatuiContext; + +use bevy::input::keyboard::Key; + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)] pub(crate) enum ConsoleState { + Open, #[default] Closed, - Open, } impl std::ops::Not for ConsoleState { @@ -21,10 +22,20 @@ impl std::ops::Not for ConsoleState { } } +pub(crate) fn toggle_console( + input: Res>, + curr_state: Res>, + mut next_state: ResMut>, +) { + if input.just_pressed(Key::Character("`".into())) { + trace!("toggled"); + next_state.set(!*curr_state.get()); + } +} + pub(crate) fn draw_console(mut tui_ctx: ResMut) -> Result { tui_ctx.draw(|frame| { - let block = Block::bordered().title("console"); - frame.render_widget(TuiLoggerWidget::default().block(block), frame.area()); + frame.render_widget(TuiLoggerWidget::default(), frame.area()); })?; Ok(()) diff --git a/src/tui/input.rs b/src/tui/input.rs new file mode 100644 index 0000000..6d0d6e4 --- /dev/null +++ b/src/tui/input.rs @@ -0,0 +1,22 @@ +// use bevy::ecs::message::MessageReader; +use bevy::app::AppExit; +use bevy::input::keyboard::{Key, KeyboardInput}; +use bevy::prelude::*; + +use crate::tui::console::ConsoleState; + +pub(crate) fn keyboard_input_system( + // keycode_input: Option>>, + // key_input: Option>>, + // mut next_state: ResMut>, + mut keyboard_events: MessageReader, +) { + // if let Some(keycode_input) = keycode_input { + // if keycode_input.just_pressed(KeyCode::Backquote) { + // // console_state.set; + // } + // } + for keyboard_input in keyboard_events.read() { + trace!("{:?}", keyboard_input); + } +} diff --git a/src/tui/menu.rs b/src/tui/menu.rs deleted file mode 100644 index 3ee27e5..0000000 --- a/src/tui/menu.rs +++ /dev/null @@ -1,29 +0,0 @@ -use bevy::prelude::*; -use bevy_ratatui::RatatuiContext; -use bevy_ratatui::event::KeyMessage; -use ratatui::crossterm::event::KeyCode; -use ratatui::layout::Constraint; -use ratatui::layout::Layout; - -use jong::game::GameState; - -use crate::tui::TuiState; - -const MAINMENU_OPTIONS: [&str; 2] = ["(p)lay", "(q)uit"]; -// const MAINMENU_INPUTS: [char;2] = ['p', 'q']; - -pub(crate) fn draw_mainmenu( - mut tui_ctx: ResMut, - // mut tui_state: ResMut>, - // mut game_state: ResMut>, -) { - let options = MAINMENU_OPTIONS; - let layout = Layout::vertical(vec![Constraint::Min(1); options.len()]); - - tui_ctx.draw(|frame| { - let areas = layout.split(frame.area()); - for (opt, area) in options.into_iter().zip(areas.iter()) { - frame.render_widget(opt, *area) - } - }); -} diff --git a/src/tui/mod.rs b/src/tui/mod.rs index e90a87f..d797779 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -1,42 +1,15 @@ use std::time::Duration; -use bevy::{app::ScheduleRunnerPlugin, prelude::*, state::app::StatesPlugin}; -use bevy_ratatui::RatatuiPlugins; -use bevy_ratatui::event::KeyMessage; -use ratatui::{text::ToSpan, widgets::Paragraph}; - -use jong::game::GameState; -use jong::game::wall::InWall; - -use crate::tui::console::ConsoleState; +use bevy::{app::ScheduleRunnerPlugin, input::keyboard::Key, prelude::*, state::app::StatesPlugin}; +use bevy_ratatui::{RatatuiContext, RatatuiPlugins}; +use jong::tiles::Tile; +use tui_logger::TuiLoggerSmartWidget; mod console; -mod menu; -mod render; +mod input; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, States, Default)] -pub(crate) enum TuiState { - #[default] - MainMenu, - InGame, -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -struct InGame; - -impl ComputedStates for InGame { - type SourceStates = TuiState; - - fn compute(sources: Self::SourceStates) -> Option { - match sources { - TuiState::MainMenu => None, - TuiState::InGame => Some(Self), - } - } -} - -#[derive(Default)] pub struct RiichiTui; + impl Plugin for RiichiTui { fn build(&self, app: &mut App) { app.add_plugins(( @@ -45,78 +18,33 @@ impl Plugin for RiichiTui { ))), RatatuiPlugins { // enable_kitty_protocol: todo!(), - enable_mouse_capture: true, + // enable_mouse_capture: todo!(), enable_input_forwarding: true, ..Default::default() }, )) .add_plugins(StatesPlugin) - - // console .init_state::() + .add_systems(Update, console::toggle_console) .add_systems(Update, console::draw_console.run_if(in_state(console::ConsoleState::Open))) - - // general setup - .init_state::() - .add_computed_state::() - .add_systems(Update, input_system) - - // main menu - .add_systems(Update, menu::draw_mainmenu.run_if(in_state(TuiState::MainMenu))) - - // gaming - .init_resource::() - .add_systems(Update, render::ingame::draw_ingame.run_if(in_state(InGame))) - .add_systems(Update, render::hand::render_changed_hand.run_if(in_state(InGame).and(in_state(GameState::Play)))) - + .add_systems(Update, input::keyboard_input_system) + .add_systems(Update, draw_system) // semicolon stopper ; } } -#[allow(clippy::too_many_arguments)] -pub(crate) fn input_system( - mut messages: MessageReader, +// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, States)] +// enum TuiState { +// MainMenu, +// InGame, +// } - curr_tuistate: Res>, - curr_consolestate: Res>, - curr_gamestate: Res>, +pub(crate) fn draw_system(mut tui_ctx: ResMut, query: Query<&Tile>) -> Result { + tui_ctx.draw(|frame| { + let text = ratatui::text::Text::raw("tiny riichi"); + frame.render_widget(text, frame.area()); + })?; - mut next_tuistate: ResMut>, - mut next_consolestate: ResMut>, - mut next_gamestate: ResMut>, - - mut exit: MessageWriter, -) { - use bevy_ratatui::crossterm::event::KeyCode; - - let (ts, cs, gs) = (curr_tuistate.get(), curr_consolestate.get(), curr_gamestate.get()); - - for message in messages.read() { - if let KeyCode::Char('`') = message.code { - next_consolestate.set(!*curr_consolestate.get()); - continue - } - - match ts { - TuiState::MainMenu => match message.code { - KeyCode::Char('p') => { - next_tuistate.set(TuiState::InGame); - next_gamestate.set(GameState::Setup); - } - KeyCode::Char('q') => { - exit.write_default(); - } - _ => {} - }, - TuiState::InGame => match gs { - // GameState::None => todo!(), - GameState::Setup => todo!(), - GameState::Play => todo!(), - GameState::Score => todo!(), - _ => todo!() - }, - } - } + Ok(()) } - diff --git a/src/tui/render/hand.rs b/src/tui/render/hand.rs deleted file mode 100644 index 9c76106..0000000 --- a/src/tui/render/hand.rs +++ /dev/null @@ -1,38 +0,0 @@ -use bevy::prelude::*; -use ratatui::widgets::Paragraph; - -use jong::game::hand::HandTiles; -use jong::tiles::Tile; - -use crate::tui::render::tiles; - -#[derive(Resource, Default)] -pub(crate) struct RenderedHand(pub(crate) Vec>); - -pub(crate) fn render_changed_hand( - hand: Single<&HandTiles, Changed>, - tiles: Populated<&Tile>, - mut target: ResMut, -) -> Result { - trace!("render_changed_hand"); - - render_hand(hand, tiles, target)?; - - Ok(()) -} - -pub(crate) fn render_hand( - hand: Single<&HandTiles, Changed>, - tiles: Populated<&Tile>, - mut target: ResMut, -) -> Result { - trace!("render_hand"); - - let hand_tiles = hand - .iter() - .map(|inhand| -> Result<_> { Ok(tiles.get(inhand).map(tiles::draw_tile)?) }) - .collect::>>()?; - target.0 = hand_tiles; - - Ok(()) -} diff --git a/src/tui/render/ingame.rs b/src/tui/render/ingame.rs deleted file mode 100644 index 6a30d4e..0000000 --- a/src/tui/render/ingame.rs +++ /dev/null @@ -1,26 +0,0 @@ -use bevy::prelude::*; -use bevy_ratatui::RatatuiContext; - -use crate::tui::render::hand; - -pub(crate) fn draw_ingame( - rendered_hand: Res, - mut tui_ctx: ResMut, -) -> Result { - use ratatui::layout::Flex; - use ratatui::prelude::*; - - tui_ctx.draw(|frame| { - // debug!("{}", frame.area()); - - let layout = Layout::horizontal(vec![Constraint::Max(5); 13]).flex(Flex::Start); - let mut area = frame.area(); - area.height = 4; - let areas = layout.areas::<13>(area); - for (tile, area) in rendered_hand.0.iter().zip(areas.iter()) { - frame.render_widget(tile, *area); - } - })?; - - Ok(()) -} diff --git a/src/tui/render/mod.rs b/src/tui/render/mod.rs deleted file mode 100644 index fc6612a..0000000 --- a/src/tui/render/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub(crate) mod hand; -pub(crate) mod ingame; -mod tiles; diff --git a/src/tui/render/tiles.rs b/src/tui/render/tiles.rs deleted file mode 100644 index 620a2d1..0000000 --- a/src/tui/render/tiles.rs +++ /dev/null @@ -1,30 +0,0 @@ -use ratatui::widgets::Paragraph; - -use jong::tiles::Tile; - -pub(crate) fn draw_tile(tile: &Tile) -> Paragraph<'static> { - use ratatui::prelude::*; - - let block = ratatui::widgets::Block::bordered(); - - Paragraph::new(match &tile.suit { - jong::tiles::Suit::Pin(rank) => format!("{}\np", rank.0), - jong::tiles::Suit::Sou(rank) => format!("{}\ns", rank.0), - jong::tiles::Suit::Man(rank) => format!("{}\nm", rank.0), - jong::tiles::Suit::Wind(wind) => (match wind { - jong::tiles::Wind::Ton => "e\nw", - jong::tiles::Wind::Nan => "s\nw", - jong::tiles::Wind::Shaa => "w\nw", - jong::tiles::Wind::Pei => "n\nw", - }) - .into(), - jong::tiles::Suit::Dragon(dragon) => (match dragon { - jong::tiles::Dragon::Haku => "w\nd", - jong::tiles::Dragon::Hatsu => "g\nd", - jong::tiles::Dragon::Chun => "r\nd", - }) - .into(), - }) - .block(block) - .centered() -}