Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend CLI functionality #91

Merged
merged 19 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 33 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ Raphael is a crafting rotation solver for the online game Final Fantasy XIV.
* Produces optimal solutions.
* Short solve time (20-60 seconds) and reasonable memory usage (300-1000 MB) for most configurations.

## Contents <!-- omit in toc -->

* [How does it work?](#how-does-it-work)
* [Building from source](#building-from-source)
* [Native app](#native-app)
* [Web app (WASM)](#web-app-wasm)
* [Native CLI](#native-cli)

## How does it work?

* Short answer: [A* search](https://en.wikipedia.org/wiki/A*_search_algorithm) + [Pareto optimization](https://en.wikipedia.org/wiki/Multi-objective_optimization) + [Dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming).
Expand All @@ -23,32 +31,45 @@ To build and run the application:
cargo run --release
```

### Native CLI
### Web app (WASM)

To build and run the command-line interface (CLI):
[Trunk](https://trunkrs.dev/) is required to bundle and host the website and can be installed via the Rust toolchain:

```
cargo run --release --package raphael-cli -- <cli-args>
cargo install --locked trunk
```

The CLI can also be installed so that it can be called from anywhere:
To build and host the application locally:

```
cargo install --path raphael-cli
export RANDOM_SUFFIX=""
export RUSTFLAGS="--cfg=web_sys_unstable_apis"
trunk serve --release --dist distrib
```

### Web app (WASM)
### Native CLI

[Trunk](https://trunkrs.dev/) is required to bundle and host the website and can be installed via the Rust toolchain:
To build and run the command-line interface (CLI):

```
cargo install --locked trunk
cargo run --release --package raphael-cli -- <cli-args>
```

To build and host the application locally:
The CLI currently supports searching for items and solving for crafting rotations. Run the following to see the relevant help messages:
```
cargo run --release --package raphael-cli -- --help
cargo run --release --package raphael-cli -- search --help
cargo run --release --package raphael-cli -- solve --help
```

Some basic examples:
```
export RANDOM_SUFFIX=""
export RUSTFLAGS="--cfg=web_sys_unstable_apis"
trunk serve --release --dist distrib
cargo run --release --package raphael-cli -- search "Archeo Fending"
cargo run --release --package raphael-cli -- solve --item-id 8548 --stats 5000 4000 500
```

The CLI can also be installed so that it can be called from anywhere:

```
cargo install --path raphael-cli
```
2 changes: 1 addition & 1 deletion raphael-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ simulator = { path = "../simulator" }
solvers = { path = "../solvers" }
game-data = { path = "../game_data" }

clap = { version = "4.4.11", features = ["derive", "wrap_help"] }
clap = { version = "4.4.11", features = ["derive", "wrap_help", "env"] }

log = "0.4"
env_logger = "0.11.5"
2 changes: 2 additions & 0 deletions raphael-cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod search;
pub mod solve;
67 changes: 67 additions & 0 deletions raphael-cli/src/commands/search.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use clap::{Args, ValueEnum};
use game_data::{get_item_name, Locale, RECIPES};

#[derive(Args, Debug)]
pub struct SearchArgs {
/// Search pattern, <PATTERN> can be a string or an item ID
pub pattern: String,

/// The delimiter the output uses between fields
#[arg(long, alias = "OFS", default_value = " ", env = "OFS")]
output_field_separator: String,

/// The language the input pattern and output use
#[arg(short, long, alias = "locale", value_enum, ignore_case = true, default_value_t = SearchLanguage::EN)]
language: SearchLanguage,
}

#[derive(Copy, Clone, ValueEnum, Debug)]
pub enum SearchLanguage {
EN,
DE,
FR,
JP,
}

impl Into<Locale> for SearchLanguage {
fn into(self) -> Locale {
match self {
SearchLanguage::EN => Locale::EN,
SearchLanguage::DE => Locale::DE,
SearchLanguage::FR => Locale::FR,
SearchLanguage::JP => Locale::JP,
}
}
}

pub fn execute(args: &SearchArgs) {
let locale = args.language.into();
let matches: Vec<usize>;
if let Ok(item_id) = u32::from_str_radix(&args.pattern, 10) {
match &RECIPES
.iter()
.enumerate()
.find(|(_, recipe)| recipe.item_id == item_id)
{
Some((index, _)) => matches = Vec::from([*index]),
None => matches = Vec::new(),
}
} else {
matches = game_data::find_recipes(&args.pattern, locale);
}
if matches.is_empty() {
println!("No matches found");
return;
}

for recipe_idx in matches {
let recipe = &RECIPES[recipe_idx];
let name = get_item_name(recipe.item_id, false, locale);
println!(
"{item_id}{separator}{name}",
item_id = recipe.item_id,
separator = args.output_field_separator,
name = name.trim_end_matches(&[' ', game_data::CL_ICON_CHAR])
);
}
}
Loading
Loading