1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use crate::context::Context;
use crate::repl::{Error, Subcommand};
use factorio_bot_core::miette::{IntoDiagnostic, Result};
use factorio_bot_core::paris::error;
use reedline_repl_rs::clap::{
builder::PossibleValuesParser, Arg, ArgMatches, Command, PossibleValue,
};
use reedline_repl_rs::Repl;
use std::str::FromStr;
use strum::{EnumIter, EnumMessage, EnumString, IntoEnumIterator, IntoStaticStr};
async fn run(matches: ArgMatches, context: &mut Context) -> Result<Option<String>, Error> {
let command =
DumpType::from_str(matches.value_of("type").expect("Has default value")).into_diagnostic()?;
let save_path = match matches.value_of("save").expect("Has default value") {
"" => None,
save_path => Some(save_path),
};
let instance_state = context.instance_state.read().await;
if let Some(instance_state) = instance_state.as_ref() {
match command {
DumpType::World => {
if let Some(world) = instance_state.world.as_ref() {
world.dump(save_path)?;
} else {
error!("no factorio world found??");
}
}
DumpType::EntityPrototypes => {
if let Some(world) = instance_state.world.as_ref() {
world.dump_entitiy_prototypes(save_path)?;
} else {
error!("no factorio world found??");
}
}
DumpType::ItemPrototypes => {
if let Some(world) = instance_state.world.as_ref() {
world.dump_item_prototypes(save_path)?;
} else {
error!("no factorio world found??");
}
}
DumpType::Recipes => {
if let Some(world) = instance_state.world.as_ref() {
world.dump_recipes(save_path)?;
} else {
error!("no factorio world found??");
}
}
}
} else {
error!("no factorio instance running");
}
Ok(None)
}
#[derive(EnumString, EnumMessage, EnumIter, IntoStaticStr)]
#[strum(serialize_all = "kebab-case")]
enum DumpType {
#[strum(message = "dump complete internal factorio world representation (very big)")]
World,
#[strum(message = "dump entity prototypes")]
EntityPrototypes,
#[strum(message = "dump item prototypes")]
ItemPrototypes,
#[strum(message = "dump recipes")]
Recipes,
}
impl Subcommand for ThisCommand {
fn name(&self) -> &str {
"dump"
}
fn build_command(&self, repl: Repl<Context, Error>) -> Repl<Context, Error> {
repl.with_command_async(
Command::new(self.name())
.about("dump information")
.arg(
Arg::new("type")
.required(true)
.value_parser(PossibleValuesParser::new(DumpType::iter().map(|action| {
let message = action.get_message().unwrap();
PossibleValue::new(action.into()).help(message)
})))
.help("type of information to dump"),
)
.arg(
Arg::new("save")
.default_value("")
.long("save")
.required(false)
.help("path to save at"),
),
|args, context| Box::pin(run(args, context)),
)
}
}
struct ThisCommand {}
pub fn build() -> Box<dyn Subcommand> {
Box::new(ThisCommand {})
}