DEVELOPMENT ENVIRONMENT

~liljamo/deck-builder

db0a37d143388ebc04fc6605ba1aba288b0ebe96 — Jonni Liljamo 1 year, 5 months ago b8bd27d
chore(client): fmt, clippy, cleanup
M client/build.rs => client/build.rs +1 -1
@@ 11,5 11,5 @@ fn main() {
    options.set_encryption_key(key);
    options.encode_file_names = true;
    options.enabled_on_debug_build = true;
    AssetBundler::from(options).build();
    _ = AssetBundler::from(options).build();
}

M client/src/game_status/parser.rs => client/src/game_status/parser.rs +1 -0
@@ 146,6 146,7 @@ pub fn parse(game: &Game) -> Result<GameStatus, ()> {
            Command::ChangePlayerState { state } => {
                target.state = *state;
            }
            #[allow(unreachable_patterns)]
            _ => todo!(),
        }
    }

M client/src/main.rs => client/src/main.rs +8 -2
@@ 8,9 8,13 @@

#![allow(clippy::too_many_arguments)]
#![allow(clippy::derivable_impls)]
#![allow(clippy::type_complexity)]

use api::user::User;
use bevy::{prelude::*, input::mouse::{MouseWheel, MouseScrollUnit}};
use bevy::{
    input::mouse::{MouseScrollUnit, MouseWheel},
    prelude::*,
};
use bevy_assets_bundler::*;
use bevy_editor_pls::EditorPlugin;
use bevy_egui::EguiPlugin;


@@ 146,7 150,9 @@ fn move_camera(
        let y_modifier = 3.;
        for ev in mouse_wheel_ev_r.iter() {
            match ev.unit {
                MouseScrollUnit::Line => direction.y -= 20.0 * ev.y.signum() * y_modifier * time.delta_seconds(),
                MouseScrollUnit::Line => {
                    direction.y -= 20.0 * ev.y.signum() * y_modifier * time.delta_seconds()
                }
                MouseScrollUnit::Pixel => direction.y -= ev.y * y_modifier * time.delta_seconds(),
            }
        }

M client/src/plugins/async_tasks/parse_game_status.rs => client/src/plugins/async_tasks/parse_game_status.rs +5 -1
@@ 6,7 6,11 @@
 * See LICENSE for licensing information.
 */

use crate::{api::game::Game, game_status::GameStatus, plugins::{game::GameData, FinishedRefreshGameEvent}};
use crate::{
    api::game::Game,
    game_status::GameStatus,
    plugins::{game::GameData, FinishedRefreshGameEvent},
};

use bevy::{
    prelude::*,

M client/src/plugins/async_tasks/req_game_action_create.rs => client/src/plugins/async_tasks/req_game_action_create.rs +6 -8
@@ 36,13 36,11 @@ async_task_start_call!(GameActionCreateCallEvent, GameActionCreateCall, |ev, no|
    api::game::create_action(&no, &ev.action)
});

async_task_handle_call_refresh!(
    GameActionCreateCall, |response, _game_data, _u2| {
        match response {
            Err(_err) => panic!("login failed, handle me"),
            Ok(resp) => {
                info!("created action {}", resp.id);
            }
async_task_handle_call_refresh!(GameActionCreateCall, |response, _game_data, _u2| {
    match response {
        Err(_err) => panic!("login failed, handle me"),
        Ok(resp) => {
            info!("created action {}", resp.id);
        }
    }
);
});

M client/src/plugins/game/card/mod.rs => client/src/plugins/game/card/mod.rs +12 -16
@@ 145,25 145,21 @@ fn on_spawn_card(
    new_cards: Query<(Entity, &VisualCard), Added<VisualCard>>,
) {
    for (entity, card) in &new_cards {
        commands.entity(entity).insert(
            (
                PickableBundle::default(),
                RapierPickTarget::default(),
                OnPointer::<Click>::target_insert(ClickedCard),
            )
        );
        commands.entity(entity).insert((
            PickableBundle::default(),
            RapierPickTarget::default(),
            OnPointer::<Click>::target_insert(ClickedCard),
        ));
        commands.entity(entity).with_children(|parent| {
            parent.spawn((
                PbrBundle {
                    material: card_data.card_background.clone(),
                    mesh: card_data.mesh.clone(),
                    transform: Transform {
                        scale: Vec3::new(2., 2., 1.),
                        ..Default::default()
                    },
            parent.spawn((PbrBundle {
                material: card_data.card_background.clone(),
                mesh: card_data.mesh.clone(),
                transform: Transform {
                    scale: Vec3::new(2., 2., 1.),
                    ..Default::default()
                },
            ));
                ..Default::default()
            },));

            // card name
            parent.spawn(TextMeshBundle {

M client/src/plugins/game/hand/mod.rs => client/src/plugins/game/hand/mod.rs +13 -11
@@ 9,10 9,10 @@
use bevy::prelude::*;
use bevy_rapier3d::prelude::*;

use crate::{plugins::GameActionCreateCallEvent, api::game::{Action, Command}, Global};
use crate::Global;

use super::{
    card::{visual_card_kind, VisualCard, VisualCardBundle, ClickedCard},
    card::{visual_card_kind, VisualCard, VisualCardBundle},
    GameData,
};



@@ 23,8 23,7 @@ impl Plugin for HandPlugin {
        app.add_event::<SpawnHandEvent>()
            .add_event::<PositionHandEvent>()
            .add_system(spawn_hand.run_if(on_event::<SpawnHandEvent>()))
            .add_system(position_hand.run_if(on_event::<PositionHandEvent>()))
            ;//.add_system(handle_clicked_hand_card);
            .add_system(position_hand.run_if(on_event::<PositionHandEvent>())); //.add_system(handle_clicked_hand_card);
    }
}



@@ 35,7 34,7 @@ fn spawn_hand(
    game_data: Res<GameData>,
    global: Res<Global>,
    mut ph_ev_w: EventWriter<PositionHandEvent>,
    mut hand_query: Query<Entity, With<visual_card_kind::Hand>>,
    hand_query: Query<Entity, With<visual_card_kind::Hand>>,
) {
    let Some(status) = &game_data.game_status else {
        warn!("game_status was none");


@@ 47,14 46,17 @@ fn spawn_hand(
        commands.entity(entity).despawn_recursive();
    }

    for (index, card) in status.players
        .get(&global.user.as_ref().unwrap().id).unwrap()
        .hand.iter().enumerate() {
    for (index, card) in status
        .players
        .get(&global.user.as_ref().unwrap().id)
        .unwrap()
        .hand
        .iter()
        .enumerate()
    {
        commands
            .spawn(VisualCardBundle {
                visual_card: VisualCard {
                    card: card.clone(),
                },
                visual_card: VisualCard { card: card.clone() },
                rigid_body: RigidBody::Fixed,
                ..Default::default()
            })

M client/src/plugins/game/mod.rs => client/src/plugins/game/mod.rs +5 -8
@@ 33,7 33,9 @@ impl Plugin for GamePlugin {
            .add_event::<FinishedRefreshGameEvent>()
            .add_system(game_setup.in_schedule(OnEnter(AppState::InGame)))
            .add_system(handle_refresh_game_event.run_if(on_event::<RefreshGameEvent>()))
            .add_system(handle_finished_refresh_game_event.run_if(on_event::<FinishedRefreshGameEvent>()));
            .add_system(
                handle_finished_refresh_game_event.run_if(on_event::<FinishedRefreshGameEvent>()),
            );
    }
}



@@ 56,10 58,7 @@ impl Default for GameData {
    }
}

fn game_setup(
    mut commands: Commands,
    mut rg_ev_w: EventWriter<RefreshGameEvent>,
) {
fn game_setup(mut commands: Commands, mut rg_ev_w: EventWriter<RefreshGameEvent>) {
    rg_ev_w.send(RefreshGameEvent);

    // create the playing surface


@@ 86,8 85,6 @@ fn handle_refresh_game_event(

pub struct FinishedRefreshGameEvent;

fn handle_finished_refresh_game_event(
    mut ssp_ev_w: EventWriter<SpawnSupplyPilesEvent>,
) {
fn handle_finished_refresh_game_event(mut ssp_ev_w: EventWriter<SpawnSupplyPilesEvent>) {
    ssp_ev_w.send(SpawnSupplyPilesEvent);
}

M client/src/plugins/game/supply/mod.rs => client/src/plugins/game/supply/mod.rs +43 -16
@@ 10,10 10,15 @@ use bevy::prelude::*;
use bevy_mod_picking::prelude::*;
use bevy_rapier3d::prelude::*;

use crate::{plugins::GameActionCreateCallEvent, api::game::{Action, Command}, Global, game_status::PlayerState, seed_gen};
use crate::{
    api::game::{Action, Command},
    game_status::PlayerState,
    plugins::GameActionCreateCallEvent,
    seed_gen, Global,
};

use super::{
    card::{visual_card_kind, VisualCard, VisualCardBundle, ClickedCard},
    card::{visual_card_kind, ClickedCard, VisualCard, VisualCardBundle},
    GameData,
};



@@ 27,8 32,9 @@ impl Plugin for SupplyPlugin {
                (
                    spawn_supply_piles.run_if(on_event::<SpawnSupplyPilesEvent>()),
                    apply_system_buffers,
                    position_supply_piles.run_if(on_event::<PositionSupplyPilesEvent>())
                ).chain()
                    position_supply_piles.run_if(on_event::<PositionSupplyPilesEvent>()),
                )
                    .chain(),
            )
            .add_system(handle_clicked_supply_pile);
    }


@@ 40,7 46,7 @@ fn spawn_supply_piles(
    mut commands: Commands,
    game_data: Res<GameData>,
    mut psp_ev_w: EventWriter<PositionSupplyPilesEvent>,
    mut pile_query: Query<Entity, With<visual_card_kind::Supply>>,
    pile_query: Query<Entity, With<visual_card_kind::Supply>>,
) {
    let Some(status) = &game_data.game_status else {
        warn!("game_status was none");


@@ 62,12 68,16 @@ fn spawn_supply_piles(
                ..Default::default()
            })
            .insert(visual_card_kind::Supply(index))
            .insert(OnPointer::<Over>::target_component_mut::<Transform>(|_over, transform| {
                transform.translation.y += 0.2;
            }))
            .insert(OnPointer::<Out>::target_component_mut::<Transform>(|_over, transform| {
                transform.translation.y -= 0.2;
            }));
            .insert(OnPointer::<Over>::target_component_mut::<Transform>(
                |_over, transform| {
                    transform.translation.y += 0.2;
                },
            ))
            .insert(OnPointer::<Out>::target_component_mut::<Transform>(
                |_over, transform| {
                    transform.translation.y -= 0.2;
                },
            ));
    }

    psp_ev_w.send(PositionSupplyPilesEvent);


@@ 109,7 119,10 @@ fn position_supply_piles(

fn handle_clicked_supply_pile(
    mut commands: Commands,
    mut card_query: Query<(Entity, &VisualCard, &visual_card_kind::Supply), (With<visual_card_kind::Supply>, With<ClickedCard>)>,
    card_query: Query<
        (Entity, &VisualCard, &visual_card_kind::Supply),
        (With<visual_card_kind::Supply>, With<ClickedCard>),
    >,
    mut gac_ev_w: EventWriter<GameActionCreateCallEvent>,
    mut game_data: ResMut<GameData>,
    global: Res<Global>,


@@ 124,17 137,31 @@ fn handle_clicked_supply_pile(

    commands.entity(entity).remove::<ClickedCard>();

    let player = game_data.game_status.as_ref().unwrap()
        .players.get(&global.user.as_ref().unwrap().id).unwrap();
    let player = game_data
        .game_status
        .as_ref()
        .unwrap()
        .players
        .get(&global.user.as_ref().unwrap().id)
        .unwrap();

    #[allow(clippy::if_same_then_else)]
    if player.state != PlayerState::BuyPhase {
        // we ain't buying rn
        return;
    } else if player.currency < card.card.cost {
        // not enough currency
        return;
    } else if game_data.game_status.as_ref().unwrap()
        .supply_piles.get(card_kind.0).unwrap().amount <= 0 {
    } else if game_data
        .game_status
        .as_ref()
        .unwrap()
        .supply_piles
        .get(card_kind.0)
        .unwrap()
        .amount
        == 0
    {
        // no cards in supply
        return;
    }

M client/src/plugins/game/ui/mod.rs => client/src/plugins/game/ui/mod.rs +24 -49
@@ 13,10 13,10 @@ use crate::{
    api::game::{Action, Command, Game},
    game_status::{Card, PlayerState},
    plugins::GameActionCreateCallEvent,
    AppState, Global, seed_gen,
    seed_gen, AppState, Global,
};

use super::{supply::{SpawnSupplyPilesEvent, PositionSupplyPilesEvent}, GameData, RefreshGameEvent};
use super::{GameData, RefreshGameEvent};

mod state_button;



@@ 27,17 27,15 @@ impl Plugin for GameUIPlugin {
        app.add_plugin(state_button::StateButtonPlugin)
            .add_system(dev_details_ui.run_if(in_state(AppState::InGame)))
            .add_system(setup_details.in_schedule(OnEnter(AppState::InGame)))
            .add_systems(
                (
                    update_game_state_text,
                    update_currency_text,
                    update_deck_text,
                    update_discard_text,
                    update_plays_text,
                    update_buys_text,
                    update_vp_text,
                )
            );
            .add_systems((
                update_game_state_text,
                update_currency_text,
                update_deck_text,
                update_discard_text,
                update_plays_text,
                update_buys_text,
                update_vp_text,
            ));
    }
}



@@ 62,14 60,11 @@ struct BuysText;
#[derive(Component)]
struct VPText;

fn setup_details(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
) {
fn setup_details(mut commands: Commands, asset_server: Res<AssetServer>) {
    let font = asset_server.load("fonts/FiraMono-Bold.ttf");
    let font_size = 40.;
    let text_style = TextStyle {
        font: font.clone(),
        font,
        font_size,
        color: Color::WHITE,
    };


@@ 77,10 72,7 @@ fn setup_details(
    // game state
    commands.spawn((
        TextBundle::from_sections([
            TextSection::new(
                "State: ",
                text_style.clone(),
            ),
            TextSection::new("State: ", text_style.clone()),
            TextSection::from_style(text_style.clone()),
        ])
        .with_text_alignment(TextAlignment::Center)


@@ 99,10 91,7 @@ fn setup_details(
    // plays
    commands.spawn((
        TextBundle::from_sections([
            TextSection::new(
                "Plays: ",
                text_style.clone(),
            ),
            TextSection::new("Plays: ", text_style.clone()),
            TextSection::from_style(text_style.clone()),
        ])
        .with_text_alignment(TextAlignment::Center)


@@ 121,10 110,7 @@ fn setup_details(
    // buys
    commands.spawn((
        TextBundle::from_sections([
            TextSection::new(
                "Buys: ",
                text_style.clone(),
            ),
            TextSection::new("Buys: ", text_style.clone()),
            TextSection::from_style(text_style.clone()),
        ])
        .with_text_alignment(TextAlignment::Center)


@@ 143,10 129,7 @@ fn setup_details(
    // currency
    commands.spawn((
        TextBundle::from_sections([
            TextSection::new(
                "Currency: ",
                text_style.clone(),
            ),
            TextSection::new("Currency: ", text_style.clone()),
            TextSection::from_style(TextStyle {
                color: Color::GOLD,
                ..text_style.clone()


@@ 168,10 151,7 @@ fn setup_details(
    // deck
    commands.spawn((
        TextBundle::from_sections([
            TextSection::new(
                "Deck: ",
                text_style.clone(),
            ),
            TextSection::new("Deck: ", text_style.clone()),
            TextSection::from_style(text_style.clone()),
        ])
        .with_text_alignment(TextAlignment::Center)


@@ 190,10 170,7 @@ fn setup_details(
    // discard
    commands.spawn((
        TextBundle::from_sections([
            TextSection::new(
                "Discard: ",
                text_style.clone(),
            ),
            TextSection::new("Discard: ", text_style.clone()),
            TextSection::from_style(text_style.clone()),
        ])
        .with_text_alignment(TextAlignment::Center)


@@ 212,11 189,8 @@ fn setup_details(
    // vp
    commands.spawn((
        TextBundle::from_sections([
            TextSection::new(
                "VP: ",
                text_style.clone(),
            ),
            TextSection::from_style(text_style.clone()),
            TextSection::new("VP: ", text_style.clone()),
            TextSection::from_style(text_style),
        ])
        .with_text_alignment(TextAlignment::Center)
        .with_style(Style {


@@ 240,7 214,7 @@ fn update_game_state_text(
        let Some(status) = &game_data.game_status else {
            return;
        };
        let Some(player) = status.players.values().filter(|p| p.state != PlayerState::Idle).next() else {
        let Some(player) = status.players.values().find(|p| p.state != PlayerState::Idle) else {
            return;
        };
        text.sections[1].value = format!("{} - {:?}", player.display_name, player.state);


@@ 375,6 349,7 @@ pub fn dev_details_ui(
            };

        ui.add_enabled_ui(!game_data.locked, |ui| {
            #[allow(clippy::collapsible_if)]
            if status.actions.is_empty() && game.host_id == global.user.as_ref().unwrap().id {
                if ui.button("Init Game").clicked() {
                    // NOTE/FIXME: hardcoded game init


@@ 384,7 359,7 @@ pub fn dev_details_ui(
            }

            if ui.button("Force Refresh").clicked() {
                    rg_ev_w.send(RefreshGameEvent);
                rg_ev_w.send(RefreshGameEvent);
            }
        });


M client/src/plugins/game/ui/state_button.rs => client/src/plugins/game/ui/state_button.rs +47 -40
@@ 8,7 8,12 @@

use bevy::prelude::*;

use crate::{AppState, plugins::{GameData, GameActionCreateCallEvent}, Global, game_status::PlayerState, api::game::{Action, Command}, seed_gen};
use crate::{
    api::game::{Action, Command},
    game_status::PlayerState,
    plugins::{GameActionCreateCallEvent, GameData},
    seed_gen, AppState, Global,
};

pub struct StateButtonPlugin;



@@ 29,12 34,9 @@ struct StateButton;
#[derive(Component)]
struct StateButtonText;

fn setup_state_button(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
) {
    commands.spawn((
        NodeBundle {
fn setup_state_button(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands
        .spawn((NodeBundle {
            style: Style {
                position_type: PositionType::Absolute,
                position: UiRect {


@@ 45,43 47,48 @@ fn setup_state_button(
                ..Default::default()
            },
            ..Default::default()
        },
    ))
    .with_children(|parent| {
        parent
            .spawn((ButtonBundle {
                style: Style {
                    size: Size::new(Val::Px(150.), Val::Px(65.)),
                    // center child text
                    justify_content: JustifyContent::Center,
                    align_items: AlignItems::Center,
                    ..Default::default()
                },
                background_color: NORMAL_BUTTON.into(),
                ..Default::default()
            }, StateButton
            ))
            .with_children(|parent| {
                parent.spawn((
                    TextBundle::from_section(
                        "Pass",
                        TextStyle {
                            font: asset_server.load("fonts/FiraMono-Bold.ttf"),
                            font_size: 40.,
                            color: Color::WHITE,
        },))
        .with_children(|parent| {
            parent
                .spawn((
                    ButtonBundle {
                        style: Style {
                            size: Size::new(Val::Px(150.), Val::Px(65.)),
                            // center child text
                            justify_content: JustifyContent::Center,
                            align_items: AlignItems::Center,
                            ..Default::default()
                        },
                    ),
                    StateButtonText,
                ));
            });

    });
                        background_color: NORMAL_BUTTON.into(),
                        ..Default::default()
                    },
                    StateButton,
                ))
                .with_children(|parent| {
                    parent.spawn((
                        TextBundle::from_section(
                            "Pass",
                            TextStyle {
                                font: asset_server.load("fonts/FiraMono-Bold.ttf"),
                                font_size: 40.,
                                color: Color::WHITE,
                            },
                        ),
                        StateButtonText,
                    ));
                });
        });
}

fn update_state_button(
    mut interaction_query: Query<
        (&Interaction, &mut BackgroundColor, &mut Visibility, &Children),
        (Changed<Interaction>, With<StateButton>)
        (
            &Interaction,
            &mut BackgroundColor,
            &mut Visibility,
            &Children,
        ),
        (Changed<Interaction>, With<StateButton>),
    >,
    mut text_query: Query<&mut Text>,
    mut game_data: ResMut<GameData>,


@@ 147,7 154,7 @@ fn update_state_button(
                                &game.id,
                                &user.id,
                                &user.id,
                                &Command::EndTurn { },
                                &Command::EndTurn {},
                                seed_gen!(),
                            ),
                        });