refactor(cli)!: Moved CLI stuff to crate::cli
- Bump version to 0.4.0 - Added Config::try_load - Added Config.verbose field - Made Config.path public - Added -q/--quiet flag to CLI BREAKING CHANGE: Moved CLI-related objects to squad-quest-cli::cli
This commit is contained in:
parent
47f55105dd
commit
790fa88fe3
10 changed files with 529 additions and 453 deletions
|
|
@ -9,5 +9,5 @@ license.workspace = true
|
|||
chrono = "0.4.42"
|
||||
clap = { version = "4.5.53", features = ["derive"] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
squad-quest = { version = "0.3.0", path = ".." }
|
||||
squad-quest = { version = "0.4.0", path = ".." }
|
||||
toml = "0.9.8"
|
||||
|
|
|
|||
57
cli/src/cli/account.rs
Normal file
57
cli/src/cli/account.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use clap::{Args,Subcommand,ValueEnum};
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum AccountCommands {
|
||||
/// List accounts
|
||||
List,
|
||||
/// Create empty account
|
||||
Create(AccountCreateArgs),
|
||||
/// Update balance value
|
||||
Balance(AccountBalanceArgs),
|
||||
/// Approve account answer for quest
|
||||
Complete(AccountCompleteArgs),
|
||||
/// Delete account
|
||||
Delete(AccountDeleteArgs),
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct AccountCreateArgs {
|
||||
/// Account will be created with this id
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, ValueEnum)]
|
||||
pub enum AccountBalanceActions {
|
||||
Set,
|
||||
Add,
|
||||
Remove,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct AccountBalanceArgs {
|
||||
/// Account id
|
||||
pub id: String,
|
||||
/// What to do with the balance
|
||||
#[arg(value_enum)]
|
||||
pub action: AccountBalanceActions,
|
||||
/// Amount of doing
|
||||
pub value: u32,
|
||||
/// If action is remove, set balance to 0 if the result is negative instead of returning error
|
||||
#[arg(short,long)]
|
||||
pub negative_ok: bool,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct AccountCompleteArgs {
|
||||
/// Id of the account
|
||||
pub account: String,
|
||||
/// Id of the quest
|
||||
pub quest: u16,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct AccountDeleteArgs {
|
||||
/// Id of the account to delete
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
57
cli/src/cli/map.rs
Normal file
57
cli/src/cli/map.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use clap::{Args,Subcommand};
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum MapCommands {
|
||||
/// List all rooms with connections
|
||||
List,
|
||||
/// Add new room to map
|
||||
Add(MapAddArgs),
|
||||
/// Connect two rooms
|
||||
Connect(MapConnectArgs),
|
||||
/// Disconnect two rooms if they're connected
|
||||
Disconnect(MapConnectArgs),
|
||||
/// Remove all connections with the room
|
||||
Delete(MapDeleteArgs),
|
||||
/// Update room data
|
||||
Update(MapUpdateArgs),
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct MapAddArgs {
|
||||
/// Name of the room
|
||||
pub name: String,
|
||||
/// Price of the room
|
||||
pub value: u32,
|
||||
/// Optional description for the room
|
||||
#[arg(long,short)]
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct MapConnectArgs {
|
||||
/// First room ID
|
||||
pub first: u16,
|
||||
/// Second room ID
|
||||
pub second: u16,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct MapDeleteArgs {
|
||||
/// ID of the room to delete
|
||||
pub id: u16,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct MapUpdateArgs {
|
||||
/// ID of the room to update
|
||||
pub id: u16,
|
||||
/// Room name
|
||||
#[arg(short,long)]
|
||||
pub name: Option<String>,
|
||||
/// Room description
|
||||
#[arg(short,long)]
|
||||
pub description: Option<String>,
|
||||
/// Room price
|
||||
#[arg(short,long)]
|
||||
pub value: Option<u32>,
|
||||
}
|
||||
36
cli/src/cli/mod.rs
Normal file
36
cli/src/cli/mod.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Parser,Subcommand};
|
||||
|
||||
pub mod account;
|
||||
pub mod map;
|
||||
pub mod quest;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(version, about, long_about = None)]
|
||||
#[command(propagate_version = true)]
|
||||
pub struct Cli {
|
||||
/// Path to config
|
||||
#[arg(short, long)]
|
||||
pub config: PathBuf,
|
||||
/// Object to make operation on
|
||||
#[command(subcommand)]
|
||||
pub command: Objects,
|
||||
/// Suppress most output
|
||||
#[arg(short, long)]
|
||||
pub quiet: bool,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum Objects {
|
||||
/// Operations on the quests
|
||||
#[command(subcommand)]
|
||||
Quest(quest::QuestCommands),
|
||||
/// Operations on the accounts
|
||||
#[command(subcommand)]
|
||||
Account(account::AccountCommands),
|
||||
/// Operations on the map rooms
|
||||
#[command(subcommand)]
|
||||
Map(map::MapCommands),
|
||||
}
|
||||
|
||||
130
cli/src/cli/quest.rs
Normal file
130
cli/src/cli/quest.rs
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
use squad_quest::quest::QuestDifficulty as LibQuestDifficulty;
|
||||
use toml::value::Date;
|
||||
use serde::Deserialize;
|
||||
use clap::{Args,Subcommand,ValueEnum};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DateWrapper {
|
||||
date: Date,
|
||||
}
|
||||
|
||||
fn parse_date(arg: &str) -> Result<Date,toml::de::Error> {
|
||||
let toml_str = format!("date = {arg}");
|
||||
let wrapper: DateWrapper = toml::from_str(&toml_str)?;
|
||||
Ok(wrapper.date)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
|
||||
pub enum QuestDifficulty {
|
||||
/// Easy quest
|
||||
Easy,
|
||||
/// Normal quest
|
||||
Normal,
|
||||
/// Hard quest
|
||||
Hard,
|
||||
/// Special case of hard quests.
|
||||
Secret,
|
||||
}
|
||||
|
||||
impl From<QuestDifficulty> for LibQuestDifficulty {
|
||||
fn from(value: QuestDifficulty) -> Self {
|
||||
match value {
|
||||
QuestDifficulty::Easy => LibQuestDifficulty::Easy,
|
||||
QuestDifficulty::Normal => LibQuestDifficulty::Normal,
|
||||
QuestDifficulty::Hard => LibQuestDifficulty::Hard,
|
||||
QuestDifficulty::Secret => LibQuestDifficulty::Secret,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum QuestCommands {
|
||||
/// List available quests
|
||||
List(QuestListArgs),
|
||||
/// Create new quest and automatically assign it id
|
||||
Create(QuestCreateArgs),
|
||||
/// Update existing quest
|
||||
Update(QuestUpdateArgs),
|
||||
/// Delete quest
|
||||
Delete(QuestDeleteArgs),
|
||||
/// Make certain quests public
|
||||
Daily,
|
||||
/// Publish quest with specified id
|
||||
Publish(QuestPublishArgs),
|
||||
}
|
||||
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct QuestListArgs {
|
||||
/// Only list id and name of the quest
|
||||
#[arg(short, long)]
|
||||
pub short: bool,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct QuestCreateArgs {
|
||||
/// Difficulty of the quest #[arg(value_enum)]
|
||||
pub difficulty: QuestDifficulty,
|
||||
/// Reward for the quest
|
||||
pub reward: u32,
|
||||
/// Name of the quest
|
||||
pub name: String,
|
||||
/// Visible description of the quest
|
||||
pub description: String,
|
||||
/// Answer for the quest for admins
|
||||
pub answer: String,
|
||||
/// Create quest and make it public immediately
|
||||
#[arg(short,long)]
|
||||
pub public: bool,
|
||||
/// Make quest available on date (format = YYYY-MM-DD, ex. 2025-12-24)
|
||||
#[arg(short,long,value_parser = parse_date)]
|
||||
pub available: Option<Date>,
|
||||
/// Quest expiration date (format = YYYY-MM-DD, ex. 2025-12-24)
|
||||
#[arg(short,long,value_parser = parse_date)]
|
||||
pub deadline: Option<Date>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct QuestUpdateArgs {
|
||||
/// Id of the quest to update
|
||||
pub id: u16,
|
||||
/// Difficulty of the quest
|
||||
#[arg(value_enum,long)]
|
||||
pub difficulty: Option<QuestDifficulty>,
|
||||
/// Reward for the quest
|
||||
#[arg(long)]
|
||||
pub reward: Option<u32>,
|
||||
/// Name of the quest
|
||||
#[arg(long)]
|
||||
pub name: Option<String>,
|
||||
/// Visible description of the quest
|
||||
#[arg(long)]
|
||||
pub description: Option<String>,
|
||||
/// Answer for the quest for admins
|
||||
#[arg(long)]
|
||||
pub answer: Option<String>,
|
||||
/// Create quest and make it public immediately
|
||||
#[arg(long)]
|
||||
pub public: Option<bool>,
|
||||
/// Make quest available on date (format = YYYY-MM-DD, ex. 2025-12-24)
|
||||
#[arg(long,value_parser = parse_date)]
|
||||
pub available: Option<Date>,
|
||||
/// Quest expiration date (format = YYYY-MM-DD, ex. 2025-12-24)
|
||||
#[arg(long,value_parser = parse_date)]
|
||||
pub deadline: Option<Date>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct QuestDeleteArgs {
|
||||
/// Id of the quest to delete
|
||||
pub id: u16,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct QuestPublishArgs {
|
||||
/// Id of the quest to publish
|
||||
pub id: u16,
|
||||
/// Make it non-public instead
|
||||
#[arg(long,short)]
|
||||
pub reverse: bool,
|
||||
}
|
||||
1
cli/src/lib.rs
Normal file
1
cli/src/lib.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub mod cli;
|
||||
582
cli/src/main.rs
582
cli/src/main.rs
|
|
@ -1,272 +1,11 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
|
||||
use clap::{Parser,Subcommand,Args,ValueEnum};
|
||||
use serde::Deserialize;
|
||||
use squad_quest::{SquadObject, account::Account, config::Config, error::Error, map::{Map, Room}, quest::{Quest,QuestDifficulty as LibQuestDifficulty}};
|
||||
use clap::Parser;
|
||||
use squad_quest_cli::cli::{Cli,Objects,account::*,map::*,quest::*};
|
||||
use squad_quest::{SquadObject, account::Account, config::Config, map::{Map, Room}, quest::Quest};
|
||||
use toml::value::Date;
|
||||
use chrono::{Datelike, NaiveDate, Utc};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DateWrapper {
|
||||
date: Date,
|
||||
}
|
||||
|
||||
fn parse_date(arg: &str) -> Result<Date,toml::de::Error> {
|
||||
let toml_str = format!("date = {arg}");
|
||||
let wrapper: DateWrapper = toml::from_str(&toml_str)?;
|
||||
Ok(wrapper.date)
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(version, about, long_about = None)]
|
||||
#[command(propagate_version = true)]
|
||||
struct Cli {
|
||||
/// Path to config
|
||||
#[arg(short, long)]
|
||||
config: PathBuf,
|
||||
/// Object to make operation on
|
||||
#[command(subcommand)]
|
||||
command: Objects,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Objects {
|
||||
/// Operations on the quests
|
||||
#[command(subcommand)]
|
||||
Quest(QuestCommands),
|
||||
/// Operations on the accounts
|
||||
#[command(subcommand)]
|
||||
Account(AccountCommands),
|
||||
/// Operations on the map rooms
|
||||
#[command(subcommand)]
|
||||
Map(MapCommands),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
|
||||
enum QuestDifficulty {
|
||||
/// Easy quest
|
||||
Easy,
|
||||
/// Normal quest
|
||||
Normal,
|
||||
/// Hard quest
|
||||
Hard,
|
||||
/// Special case of hard quests.
|
||||
Secret,
|
||||
}
|
||||
|
||||
impl From<QuestDifficulty> for LibQuestDifficulty {
|
||||
fn from(value: QuestDifficulty) -> Self {
|
||||
match value {
|
||||
QuestDifficulty::Easy => LibQuestDifficulty::Easy,
|
||||
QuestDifficulty::Normal => LibQuestDifficulty::Normal,
|
||||
QuestDifficulty::Hard => LibQuestDifficulty::Hard,
|
||||
QuestDifficulty::Secret => LibQuestDifficulty::Secret,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum QuestCommands {
|
||||
/// List available quests
|
||||
List(QuestListArgs),
|
||||
/// Create new quest and automatically assign it id
|
||||
Create(QuestCreateArgs),
|
||||
/// Update existing quest
|
||||
Update(QuestUpdateArgs),
|
||||
/// Delete quest
|
||||
Delete(QuestDeleteArgs),
|
||||
/// Make certain quests public
|
||||
Daily,
|
||||
/// Publish quest with specified id
|
||||
Publish(QuestPublishArgs),
|
||||
}
|
||||
|
||||
|
||||
#[derive(Args)]
|
||||
struct QuestListArgs {
|
||||
/// Only list id and name of the quest
|
||||
#[arg(short, long)]
|
||||
short: bool,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct QuestCreateArgs { /// Difficulty of the quest #[arg(value_enum)]
|
||||
difficulty: QuestDifficulty,
|
||||
/// Reward for the quest
|
||||
reward: u32,
|
||||
/// Name of the quest
|
||||
name: String,
|
||||
/// Visible description of the quest
|
||||
description: String,
|
||||
/// Answer for the quest for admins
|
||||
answer: String,
|
||||
/// Create quest and make it public immediately
|
||||
#[arg(short,long)]
|
||||
public: bool,
|
||||
/// Make quest available on date (format = YYYY-MM-DD, ex. 2025-12-24)
|
||||
#[arg(short,long,value_parser = parse_date)]
|
||||
available: Option<Date>,
|
||||
/// Quest expiration date (format = YYYY-MM-DD, ex. 2025-12-24)
|
||||
#[arg(short,long,value_parser = parse_date)]
|
||||
deadline: Option<Date>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct QuestUpdateArgs {
|
||||
/// Id of the quest to update
|
||||
id: u16,
|
||||
/// Difficulty of the quest
|
||||
#[arg(value_enum,long)]
|
||||
difficulty: Option<QuestDifficulty>,
|
||||
/// Reward for the quest
|
||||
#[arg(long)]
|
||||
reward: Option<u32>,
|
||||
/// Name of the quest
|
||||
#[arg(long)]
|
||||
name: Option<String>,
|
||||
/// Visible description of the quest
|
||||
#[arg(long)]
|
||||
description: Option<String>,
|
||||
/// Answer for the quest for admins
|
||||
#[arg(long)]
|
||||
answer: Option<String>,
|
||||
/// Create quest and make it public immediately
|
||||
#[arg(long)]
|
||||
public: Option<bool>,
|
||||
/// Make quest available on date (format = YYYY-MM-DD, ex. 2025-12-24)
|
||||
#[arg(long,value_parser = parse_date)]
|
||||
available: Option<Date>,
|
||||
/// Quest expiration date (format = YYYY-MM-DD, ex. 2025-12-24)
|
||||
#[arg(long,value_parser = parse_date)]
|
||||
deadline: Option<Date>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct QuestDeleteArgs {
|
||||
/// Id of the quest to delete
|
||||
id: u16,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct QuestPublishArgs {
|
||||
/// Id of the quest to publish
|
||||
id: u16,
|
||||
/// Make it non-public instead
|
||||
#[arg(long,short)]
|
||||
reverse: bool,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum AccountCommands {
|
||||
/// List accounts
|
||||
List,
|
||||
/// Create empty account
|
||||
Create(AccountCreateArgs),
|
||||
/// Update balance value
|
||||
Balance(AccountBalanceArgs),
|
||||
/// Approve account answer for quest
|
||||
Complete(AccountCompleteArgs),
|
||||
/// Delete account
|
||||
Delete(AccountDeleteArgs),
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct AccountCreateArgs {
|
||||
/// Account will be created with this id
|
||||
id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, ValueEnum)]
|
||||
enum AccountBalanceActions {
|
||||
Set,
|
||||
Add,
|
||||
Remove,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct AccountBalanceArgs {
|
||||
/// Account id
|
||||
id: String,
|
||||
/// What to do with the balance
|
||||
#[arg(value_enum)]
|
||||
action: AccountBalanceActions,
|
||||
/// Amount of doing
|
||||
value: u32,
|
||||
/// If action is remove, set balance to 0 if the result is negative instead of returning error
|
||||
#[arg(short,long)]
|
||||
negative_ok: bool,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct AccountCompleteArgs {
|
||||
/// Id of the account
|
||||
account: String,
|
||||
/// Id of the quest
|
||||
quest: u16,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct AccountDeleteArgs {
|
||||
/// Id of the account to delete
|
||||
id: String,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum MapCommands {
|
||||
/// List all rooms with connections
|
||||
List,
|
||||
/// Add new room to map
|
||||
Add(MapAddArgs),
|
||||
/// Connect two rooms
|
||||
Connect(MapConnectArgs),
|
||||
/// Disconnect two rooms if they're connected
|
||||
Disconnect(MapConnectArgs),
|
||||
/// Remove all connections with the room
|
||||
Delete(MapDeleteArgs),
|
||||
/// Update room data
|
||||
Update(MapUpdateArgs),
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct MapAddArgs {
|
||||
/// Name of the room
|
||||
name: String,
|
||||
/// Price of the room
|
||||
value: u32,
|
||||
/// Optional description for the room
|
||||
#[arg(long,short)]
|
||||
description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct MapConnectArgs {
|
||||
/// First room ID
|
||||
first: u16,
|
||||
/// Second room ID
|
||||
second: u16,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct MapDeleteArgs {
|
||||
/// ID of the room to delete
|
||||
id: u16,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct MapUpdateArgs {
|
||||
/// ID of the room to update
|
||||
id: u16,
|
||||
/// Room name
|
||||
#[arg(short,long)]
|
||||
name: Option<String>,
|
||||
/// Room description
|
||||
#[arg(short,long)]
|
||||
description: Option<String>,
|
||||
/// Room price
|
||||
#[arg(short,long)]
|
||||
value: Option<u32>,
|
||||
}
|
||||
|
||||
fn print_quest_short(quest: &Quest) {
|
||||
println!("Quest #{}: {}", quest.id, quest.name);
|
||||
}
|
||||
|
|
@ -278,16 +17,36 @@ fn print_quest_long(quest: &Quest) {
|
|||
println!("Answer:\n{}", quest.answer);
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
|
||||
let config = Config::load(cli.config.clone());
|
||||
let config = match cli.quiet {
|
||||
false => Config::load(cli.config.clone()),
|
||||
true => {
|
||||
match Config::try_load(cli.config.clone()) {
|
||||
Ok(mut config) => {
|
||||
config.verbose = false;
|
||||
config
|
||||
},
|
||||
Err(_) => {
|
||||
let path = cli.config.clone().parent().unwrap_or(&Path::new(".")).to_owned();
|
||||
Config {
|
||||
verbose: false,
|
||||
path,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
match &cli.command {
|
||||
Objects::Quest(commands) => {
|
||||
let mut quests = config.load_quests();
|
||||
let mut path = config.full_quests_path();
|
||||
|
||||
match commands {
|
||||
QuestCommands::List(args) => {
|
||||
let quests = config.load_quests();
|
||||
for quest in quests {
|
||||
if args.short {
|
||||
print_quest_short(&quest);
|
||||
|
|
@ -297,24 +56,27 @@ fn main() -> Result<(), Error> {
|
|||
}
|
||||
},
|
||||
QuestCommands::Create(args) => {
|
||||
let mut quests = config.load_quests();
|
||||
quests.sort_by(|a,b| a.id.cmp(&b.id));
|
||||
let next_id = match quests.last() {
|
||||
Some(quest) => quest.id + 1u16,
|
||||
None => 0u16
|
||||
};
|
||||
|
||||
let path = config.full_quests_path();
|
||||
let mut quest_path = path.clone();
|
||||
quest_path.push(format!("{next_id}.toml"));
|
||||
match std::fs::exists(&quest_path) {
|
||||
path.push(format!("{next_id}.toml"));
|
||||
match std::fs::exists(&path) {
|
||||
Ok(exists) => {
|
||||
if exists {
|
||||
panic!("Error: {:?} is not empty.", quest_path);
|
||||
if !cli.quiet {
|
||||
eprintln!("Error: {:?} is not empty.", path);
|
||||
}
|
||||
return;
|
||||
}
|
||||
},
|
||||
Err(error) => {
|
||||
panic!("Error while retrieving {:?}: {}.", quest_path, error);
|
||||
if !cli.quiet {
|
||||
eprintln!("Error while retrieving {:?}: {}.", path, error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -329,16 +91,19 @@ fn main() -> Result<(), Error> {
|
|||
available_on: args.available.clone(),
|
||||
deadline: args.deadline.clone()
|
||||
};
|
||||
if let Err(error) = quest.save(path) {
|
||||
eprintln!("Error while saving quest: {error}.");
|
||||
} else {
|
||||
println!("Successfully saved quest #{}.", quest.id);
|
||||
|
||||
match quest.save(path) {
|
||||
Ok(_) if !cli.quiet => println!("Successfully saved quest #{}", quest.id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while saving quest: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
QuestCommands::Update(args) => {
|
||||
let quests = config.load_quests();
|
||||
let Some(quest) = quests.iter().find(|q| q.id == args.id) else {
|
||||
panic!("Error: Quest #{} not found.", args.id);
|
||||
if !cli.quiet {
|
||||
eprintln!("Error: Quest #{} not found.", args.id);
|
||||
}
|
||||
return;
|
||||
};
|
||||
let quest = Quest {
|
||||
id: args.id,
|
||||
|
|
@ -354,22 +119,20 @@ fn main() -> Result<(), Error> {
|
|||
available_on: args.available.clone().or(quest.available_on.clone()),
|
||||
deadline: args.deadline.clone().or(quest.deadline.clone())
|
||||
};
|
||||
let path = config.full_quests_path();
|
||||
match quest.save(path) {
|
||||
Ok(_) => println!("Updated quest #{}", quest.id),
|
||||
Err(error) => eprintln!("Error while updating quest: {error}")
|
||||
Ok(_) if !cli.quiet => println!("Updated quest #{}", quest.id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while updating quest: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
QuestCommands::Delete(args) => {
|
||||
let mut path = config.full_quests_path();
|
||||
path.push(format!("{}.toml", args.id));
|
||||
match Quest::delete(path) {
|
||||
Ok(_) => println!("Successfully deleted quest #{}", args.id),
|
||||
Err(error) => eprintln!("Error deleting quest #{}: {}", args.id, error),
|
||||
Ok(_) if !cli.quiet => println!("Successfully deleted quest #{}", args.id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error deleting quest #{}: {}", args.id, error),
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
QuestCommands::Daily => {
|
||||
let mut quests = config.load_quests();
|
||||
let today: NaiveDate = Utc::now().date_naive();
|
||||
let toml_today = Date {
|
||||
year: today.year() as u16,
|
||||
|
|
@ -377,46 +140,52 @@ fn main() -> Result<(), Error> {
|
|||
day: today.day() as u8
|
||||
};
|
||||
|
||||
let path = config.full_quests_path();
|
||||
|
||||
for quest in quests.iter_mut().filter(|q| !q.public && q.available_on.is_some_and(|date| date.le(&toml_today))) {
|
||||
println!("Quest #{} will be published.", quest.id);
|
||||
quest.public = true;
|
||||
if let Err(error) = quest.save(path.clone()) {
|
||||
eprintln!("Error while saving quest: {error}.");
|
||||
|
||||
match quest.save(path.clone()) {
|
||||
Ok(_) if !cli.quiet => println!("Published quest #{}", quest.id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while publishing quest: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
},
|
||||
QuestCommands::Publish(args) => {
|
||||
let mut quests = config.load_quests();
|
||||
let quest = quests.iter_mut().find(|q| q.id == args.id);
|
||||
|
||||
let path = config.full_quests_path();
|
||||
|
||||
match quest {
|
||||
Some(quest) => {
|
||||
let not_str = if args.reverse {" not "} else {" "};
|
||||
|
||||
if quest.public != args.reverse {
|
||||
panic!("Quest #{} is already{}public", quest.id, not_str);
|
||||
if !cli.quiet {
|
||||
eprintln!("Quest #{} is already{}public", quest.id, not_str);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
quest.public = !args.reverse;
|
||||
if let Err(error) = quest.save(path) {
|
||||
eprintln!("Error while saving quest: {error}.");
|
||||
};
|
||||
|
||||
match quest.save(path.clone()) {
|
||||
Ok(_) if !cli.quiet => println!("Published quest #{}", quest.id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while publishing quest: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
None => {
|
||||
None if !cli.quiet => {
|
||||
eprintln!("Error: couldn't find quest with id {}.", args.id);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
Objects::Account(commands) => {
|
||||
let mut accounts = config.load_accounts();
|
||||
let mut path = config.full_accounts_path();
|
||||
|
||||
match commands {
|
||||
AccountCommands::List => {
|
||||
let accounts = config.load_accounts();
|
||||
|
||||
for account in accounts {
|
||||
println!("\"{}\": Balance {}", account.id, account.balance);
|
||||
|
|
@ -428,30 +197,27 @@ fn main() -> Result<(), Error> {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let accounts = config.load_accounts();
|
||||
|
||||
if let Some(_) = accounts.iter().find(|a| a.id == account.id) {
|
||||
panic!("Error: account {} exists.", account.id);
|
||||
if !cli.quiet {
|
||||
eprintln!("Error: account {} exists.", account.id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let accounts_path = config.full_accounts_path();
|
||||
|
||||
match account.save(accounts_path) {
|
||||
Ok(_) => {
|
||||
println!("Successfully created account \"{}\"", account.id);
|
||||
},
|
||||
Err(error) => {
|
||||
eprintln!("Error while saving account: {error}");
|
||||
}
|
||||
match account.save(path) {
|
||||
Ok(_) if !cli.quiet => println!("Successfully created account \"{}\"", account.id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while saving account: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
AccountCommands::Balance(args) => {
|
||||
let mut accounts = config.load_accounts();
|
||||
|
||||
let account = match accounts.iter_mut().find(|a| a.id == args.id) {
|
||||
Some(acc) => acc,
|
||||
None => {
|
||||
panic!("Could not find account \"{}\"", args.id);
|
||||
if !cli.quiet {
|
||||
eprintln!("Could not find account \"{}\"", args.id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -467,7 +233,10 @@ fn main() -> Result<(), Error> {
|
|||
if args.negative_ok {
|
||||
account.balance = 0u32;
|
||||
} else {
|
||||
panic!("Error: balance ({}) is less than {}.", account.balance, args.value);
|
||||
if !cli.quiet {
|
||||
eprintln!("Error: balance ({}) is less than {}.", account.balance, args.value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
account.balance -= args.value;
|
||||
|
|
@ -475,69 +244,68 @@ fn main() -> Result<(), Error> {
|
|||
}
|
||||
}
|
||||
|
||||
let accounts_path = config.full_accounts_path();
|
||||
|
||||
match account.save(accounts_path) {
|
||||
Ok(_) => {
|
||||
println!("Successfully updated account \"{}\" balance.", account.id);
|
||||
},
|
||||
Err(error) => {
|
||||
eprintln!("Error while saving account: {error}");
|
||||
}
|
||||
};
|
||||
match account.save(path) {
|
||||
Ok(_) if !cli.quiet => println!("Successfully updated account \"{}\" balance", account.id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while saving account: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
AccountCommands::Complete(args) => {
|
||||
let mut accounts = config.load_accounts();
|
||||
|
||||
let account = match accounts.iter_mut().find(|a| a.id == args.account) {
|
||||
Some(acc) => acc,
|
||||
None => {
|
||||
panic!("Could not find account \"{}\"", args.account);
|
||||
if !cli.quiet {
|
||||
eprintln!("Could not find account \"{}\"", args.account);
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let quests = config.load_quests();
|
||||
|
||||
if let None = quests.iter().find(|q| q.id == args.quest) {
|
||||
panic!("Could not find quest #{}", args.quest);
|
||||
if !cli.quiet {
|
||||
eprintln!("Could not find quest #{}", args.quest);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
match account.quests_completed.iter().find(|qid| **qid == args.quest) {
|
||||
Some(_) => {
|
||||
Some(_) if !cli.quiet => {
|
||||
println!("Quest #{} is already completed on account \"{}\"", args.quest, args.account);
|
||||
},
|
||||
None => {
|
||||
account.quests_completed.push(args.quest);
|
||||
let accounts_path = config.full_accounts_path();
|
||||
match account.save(accounts_path) {
|
||||
Ok(_) => {
|
||||
println!("Account \"{}\" completed quest #{}.", args.account, args.quest);
|
||||
},
|
||||
Err(error) => {
|
||||
eprintln!("Error while saving account: {error}");
|
||||
}
|
||||
match account.save(path) {
|
||||
Ok(_) if !cli.quiet => println!("Successfully completed quest #{} on account \"{}\".", args.quest, account.id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while saving account: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
AccountCommands::Delete(args) => {
|
||||
let mut accounts_path = config.full_accounts_path();
|
||||
accounts_path.push(format!("{}.toml", args.id));
|
||||
match Account::delete(accounts_path) {
|
||||
Ok(_) => {
|
||||
println!("Successfully deleted account \"{}\".", args.id);
|
||||
},
|
||||
Err(error) => {
|
||||
eprintln!("Error deleting account: {error}");
|
||||
}
|
||||
path.push(format!("{}.toml", args.id));
|
||||
match Account::delete(path) {
|
||||
Ok(_) if !cli.quiet => println!("Successfully deleted account \"{}\".", args.id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while deleting account: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
Objects::Map(commands) => {
|
||||
let map_path = config.full_map_path();
|
||||
let mut map = Map::load(map_path.clone())?;
|
||||
map.room.sort_by(|a,b| a.id.cmp(&b.id));
|
||||
let mut map = match Map::load(map_path.clone()) {
|
||||
Ok(map) => map,
|
||||
Err(error) => {
|
||||
if !cli.quiet {
|
||||
eprintln!("Error while loading map: {error}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
match commands {
|
||||
MapCommands::List => {
|
||||
for room in map.room {
|
||||
|
|
@ -545,6 +313,7 @@ fn main() -> Result<(), Error> {
|
|||
}
|
||||
},
|
||||
MapCommands::Add(args) => {
|
||||
map.room.sort_by(|a,b| a.id.cmp(&b.id));
|
||||
let last_id = match map.room.last() {
|
||||
Some(r) => r.id + 1u16,
|
||||
None => 0u16
|
||||
|
|
@ -558,18 +327,17 @@ fn main() -> Result<(), Error> {
|
|||
let r_id = room.id;
|
||||
map.room.push(room);
|
||||
match map.save(map_path.parent().unwrap_or(Path::new("")).to_owned()) {
|
||||
Ok(_) => {
|
||||
println!("Created room #{}.", r_id);
|
||||
println!("Successfully saved map.");
|
||||
},
|
||||
Err(error) => {
|
||||
eprintln!("Error while saving map: {error}");
|
||||
}
|
||||
Ok(_) if !cli.quiet => println!("Created room #{}.", r_id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while saving map: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
MapCommands::Delete(args) => {
|
||||
let Some(room) = map.room.iter().find(|r| r.id == args.id) else {
|
||||
panic!("Error: Room #{} not found", args.id);
|
||||
if !cli.quiet {
|
||||
eprintln!("Error: Room #{} not found", args.id);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
let r_id = room.id;
|
||||
|
|
@ -584,18 +352,17 @@ fn main() -> Result<(), Error> {
|
|||
}
|
||||
|
||||
match map.save(map_path.parent().unwrap_or(Path::new("")).to_owned()) {
|
||||
Ok(_) => {
|
||||
println!("Removed room #{}.", r_id);
|
||||
println!("Successfully saved map.");
|
||||
},
|
||||
Err(error) => {
|
||||
eprintln!("Error while saving map: {error}");
|
||||
}
|
||||
Ok(_) if !cli.quiet => println!("Deleted room #{}.", r_id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while saving map: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
MapCommands::Update(args) => {
|
||||
let Some(room) = map.room.iter_mut().find(|r| r.id == args.id) else {
|
||||
panic!("Error: Room #{} not found", args.id);
|
||||
if !cli.quiet {
|
||||
eprintln!("Error: Room #{} not found", args.id);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(name) = &args.name {
|
||||
|
|
@ -611,71 +378,44 @@ fn main() -> Result<(), Error> {
|
|||
}
|
||||
|
||||
match map.save(map_path.parent().unwrap_or(Path::new("")).to_owned()) {
|
||||
Ok(_) => {
|
||||
println!("Updated room #{}.", args.id);
|
||||
println!("Successfully saved map.");
|
||||
},
|
||||
Err(error) => {
|
||||
eprintln!("Error while saving map: {error}");
|
||||
}
|
||||
Ok(_) if !cli.quiet => println!("Updated room #{}.", args.id),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while saving map: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
MapCommands::Connect(args) => {
|
||||
MapCommands::Connect(args) | MapCommands::Disconnect(args) => {
|
||||
let connect = match commands {
|
||||
MapCommands::Connect(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
// We iterate twice to make references first->second and second->first
|
||||
for (first, second) in [(args.first, args.second),(args.second, args.first)] {
|
||||
let Some(room) = map.room.iter_mut().find(|r| r.id == first) else {
|
||||
panic!("Error: Room #{} not found", first);
|
||||
};
|
||||
|
||||
match room.children.iter().find(|id| **id == second) {
|
||||
Some(_) => {
|
||||
println!("Room #{} already has reference to #{}", first, second);
|
||||
},
|
||||
None => {
|
||||
room.children.push(second);
|
||||
if !cli.quiet {
|
||||
eprintln!("Error: Room #{} not found", first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match map.save(map_path.parent().unwrap_or(Path::new("")).to_owned()) {
|
||||
Ok(_) => {
|
||||
println!("Connected rooms #{} <-> #{}.", args.first, args.second);
|
||||
println!("Successfully saved map.");
|
||||
},
|
||||
Err(error) => {
|
||||
eprintln!("Error while saving map: {error}");
|
||||
}
|
||||
}
|
||||
},
|
||||
MapCommands::Disconnect(args) => {
|
||||
// We iterate twice to make references first->second and second->first
|
||||
for (first, second) in [(args.first, args.second),(args.second, args.first)] {
|
||||
let Some(room) = map.room.iter_mut().find(|r| r.id == first) else {
|
||||
panic!("Error: Room #{} not found", first);
|
||||
return;
|
||||
};
|
||||
|
||||
match room.children.iter().position(|id| *id == second) {
|
||||
Some(id) => {
|
||||
room.children.remove(id as usize);
|
||||
},
|
||||
None => {
|
||||
println!("Room #{} has no reference to #{}", first, second);
|
||||
}
|
||||
Some(_) if connect && !cli.quiet => println!("Room #{} already has reference to #{}", first, second),
|
||||
None if connect => room.children.push(second),
|
||||
Some(id) if !connect => {room.children.remove(id as usize);},
|
||||
None if !connect && !cli.quiet => println!("Room #{} has no reference to #{}", first, second),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
let connected = if connect { "Connected" } else { "Disconnected" };
|
||||
|
||||
match map.save(map_path.parent().unwrap_or(Path::new("")).to_owned()) {
|
||||
Ok(_) => {
|
||||
println!("Disconnected rooms #{} </> #{}.", args.first, args.second);
|
||||
println!("Successfully saved map.");
|
||||
},
|
||||
Err(error) => {
|
||||
eprintln!("Error while saving map: {error}");
|
||||
}
|
||||
Ok(_) if !cli.quiet => println!("{connected} rooms #{} <-> #{}.", args.first, args.second),
|
||||
Err(error) if !cli.quiet => eprintln!("Error while saving map: {error}"),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue