DEVELOPMENT ENVIRONMENT

~liljamo/deck-builder

7981ec061606d1d1fa65617ebc1173a7bc79c9eb — Jonni Liljamo 1 year, 7 months ago 7ce88fa
feat(client): revamp log system
M client/src/game_status/mod.rs => client/src/game_status/mod.rs +30 -0
@@ 68,6 68,8 @@ pub struct PlayerStatus {
/// constructed from a vector of [`Action`]s
#[derive(Clone)]
pub struct GameStatus {
    /// log entries, filled in one at a time when parsing actions
    pub log: Vec<LogEntry>,
    /// a modifiable Actions Vector, will be modified when parsing actions,
    /// used for showing the log
    pub actions: Vec<Action>,


@@ 84,3 86,31 @@ impl GameStatus {
        }
    }
}

#[derive(Clone)]
pub struct LogEntry {
    pub sections: Vec<LogSection>,
}

impl LogEntry {
    pub fn from_sections(sections: impl IntoIterator<Item = LogSection>) -> Self {
        Self {
            sections: sections.into_iter().collect(),
        }
    }
}

#[derive(Clone)]
pub enum LogSection {
    Normal(String),
    Bold(String),
}

impl LogSection {
    pub fn normal(value: &str) -> LogSection {
        LogSection::Normal(value.to_string())
    }
    pub fn bold(value: &str) -> LogSection {
        LogSection::Bold(value.to_string())
    }
}

M client/src/game_status/parser.rs => client/src/game_status/parser.rs +4 -1
@@ 12,7 12,7 @@ use fastrand::Rng;

use crate::{
    api::game::{Action, Command, Game},
    game_status::SupplyPile,
    game_status::SupplyPile, util::action_to_log,
};

use super::{GameStatus, PlayerState, PlayerStatus};


@@ 43,6 43,7 @@ where

pub fn parse(game: &Game) -> Result<GameStatus, ()> {
    let mut game_status = GameStatus {
        log: vec![],
        actions: game.actions.as_ref().unwrap().to_vec(),
        supply_piles: vec![],
        players: HashMap::new(),


@@ 94,6 95,8 @@ macro_rules! current_seed {
}

fn parse_action(action: &Action, game: &Game, game_status: &mut GameStatus) {
    game_status.log.push(action_to_log(action, game_status));

    // invoker: the one who invoked the action
    // target: the one who the action affects, may also be the invoker, e.g. draw
    let (invoker, target) =

M client/src/plugins/game/ui/log.rs => client/src/plugins/game/ui/log.rs +24 -4
@@ 8,7 8,7 @@

use bevy::{prelude::*, input::mouse::{MouseScrollUnit, MouseWheel}, a11y::{AccessibilityNode, accesskit::NodeBuilder}};

use crate::{AppState, plugins::GameData, util::action_to_log};
use crate::{AppState, plugins::GameData, game_status::LogSection};

pub struct LogPlugin;



@@ 222,7 222,7 @@ fn update_log(

        let index_spaces = status.actions.len().to_string().len();

        for (i, action) in status.actions.iter().enumerate() {
        for (i, _action) in status.actions.iter().enumerate() {
            let spaces = " ".repeat(index_spaces - i.to_string().len());
            let index_text = TextSection {
                value: format!("{}{}. ", spaces, i),


@@ 232,8 232,28 @@ fn update_log(
                },
            };

            let mut sections = action_to_log(action, (font.clone(), font_bold.clone()), style.clone());
            sections.insert(0, index_text);
            let mut sections = vec![index_text];

            let log = status.log.get(i).unwrap();
            for section in &log.sections {
                match section {
                    LogSection::Normal(value) => {
                        sections.push(TextSection {
                            value: value.to_string(),
                            style: style.clone(),
                        });
                    }
                    LogSection::Bold(value) => {
                        sections.push(TextSection {
                            value: value.to_string(),
                            style: TextStyle {
                                font: font_bold.clone(),
                                ..style.clone()
                            },
                        });
                    }
                }
            }

            commands.spawn((
                TextBundle::from_sections(sections)

M client/src/util/action_to_log.rs => client/src/util/action_to_log.rs +49 -45
@@ 6,58 6,62 @@
 * See LICENSE for licensing information.
 */

use bevy::prelude::*;

use crate::api::game::{Action, Command};

macro_rules! section {
    ($value:expr, $style:ident) => {
        TextSection {
            value: $value,
            style: $style.clone(),
        }
    };

    ($value:expr, $style:expr) => {
        TextSection {
            value: $value,
            style: $style,
        }
    };
}
use crate::{api::game::{Action, Command}, game_status::{GameStatus, LogEntry, LogSection}};

pub fn action_to_log(
    action: &Action,
    (font, font_bold): (Handle<Font>, Handle<Font>),
    style: TextStyle,
) -> Vec<TextSection> {
    game_status: &GameStatus,
) -> LogEntry {
    let invoker_name = &game_status.players.get(&action.invoker).unwrap().display_name;

    match &action.command {
        Command::InitSupplyPile { card, amount } => {
            vec![
                section!(format!("Created supply pile of "), style),
                section!(format!("{}", card.name), TextStyle {
                    font: font_bold.clone(),
                    ..style.clone()
                }),
                section!(format!(" with "), style),
                section!(format!("{}", amount), TextStyle {
                    font: font_bold.clone(),
                    ..style.clone()
                }),
                section!(format!(" cards."), TextStyle {
                    ..style.clone()
                }),
            ]
            LogEntry::from_sections(vec![
                LogSection::normal("Created supply pile of "),
                LogSection::bold(&card.name),
                LogSection::normal(" with "),
                LogSection::bold(&amount.to_string()),
                LogSection::normal(" cards"),
            ])
        }
        Command::TakeFromPile { index, for_cost: _ } => {
            let card_name = &game_status.supply_piles.get(*index).unwrap().card.name;
            LogEntry::from_sections(vec![
                LogSection::bold(invoker_name),
                LogSection::normal(" bought "),
                LogSection::bold(card_name),
            ])
        }
        Command::PlayCard { index } => {
            let card_name = &game_status.players.get(&action.invoker).unwrap().hand.get(*index).unwrap().name;
            LogEntry::from_sections(vec![
                LogSection::bold(invoker_name),
                LogSection::normal(" played "),
                LogSection::bold(card_name),
            ])
        }
        Command::Draw { amount } => {
            LogEntry::from_sections(vec![
                LogSection::bold(invoker_name),
                LogSection::normal(" drew "),
                LogSection::bold(&amount.to_string()),
                LogSection::normal(" cards"),
            ])
        }
        Command::Discard { index } => {
            let card_name = &game_status.players.get(&action.invoker).unwrap().hand.get(*index).unwrap().name;
            LogEntry::from_sections(vec![
                LogSection::bold(invoker_name),
                LogSection::normal(" discarded "),
                LogSection::bold(card_name),
            ])
        }
        _ => {
            vec![
                TextSection {
                    value: format!("No log configuration for this command"),
                    style: TextStyle {
                        ..style
                    },
                },
            ]
            LogEntry {
                sections: vec![
                    LogSection::normal("No log configuration for this command"),
                ]
            }
        }
    }
}