diff --git a/Cargo.lock b/Cargo.lock index 2255836..e249184 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,17 @@ version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -22,9 +33,10 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bwaishotgun" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", + "clap", "registry", "retry", "serde", @@ -44,6 +56,36 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "3.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "getrandom" version = "0.2.5" @@ -55,6 +97,43 @@ dependencies = [ "wasi", ] +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indexmap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.119" @@ -70,6 +149,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + [[package]] name = "memoffset" version = "0.6.5" @@ -92,12 +177,45 @@ dependencies = [ "memoffset", ] +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + [[package]] name = "ppv-lite86" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.36" @@ -201,6 +319,12 @@ dependencies = [ "win-sys", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "1.0.86" @@ -212,6 +336,21 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + [[package]] name = "thiserror" version = "1.0.30" @@ -253,6 +392,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "133bf74f01486773317ddfcde8e2e20d2933cc3b68ab797e5d718bef996a81de" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -284,6 +429,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index f2f9a18..23fd078 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bwaishotgun" -version = "0.1.0" +version = "0.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -12,6 +12,7 @@ registry = "1.2" anyhow = "1.0" shared_memory = "0.12" retry = "1.3" +clap = { version = "3.1", features = ["derive"]} [profile.release] lto = true \ No newline at end of file diff --git a/build.bat b/build.bat index 136f3d3..ef8bc2a 100644 --- a/build.bat +++ b/build.bat @@ -1,4 +1,3 @@ -bitsadmin.exe /transfer "Nitekat" "https://www.sscaitournament.com/bot_binary.php?bot=NiteKatT" blub.zip cargo build --release releng\7za a -pshotgun -- bwaishotgun.7z target/release/bwaishotgun.exe bots SNP_DirectIP.snp bwheadless.exe game.toml shotgun.toml releng\7za rn -pshotgun -- bwaishotgun.7z target/release/bwaishotgun.exe BWAIShotgun.exe diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..015aa0b --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,63 @@ +use crate::{BotConfig, GameConfig}; +use clap::{ErrorKind, Parser, Subcommand}; + +#[derive(Subcommand, Debug)] +enum GameType { + /// Host a melee game + Melee { + /// Names of bots to play + bots: Vec, + }, + /// You will host a game the bots can join (make sure to select Local PC network) + Human { + /// Names of bots to play + bots: Vec, + }, +} + +#[derive(Parser, Debug)] +pub struct Cli { + /// Absolute path of map to host + #[clap(short, long)] + map: Option, + #[clap(subcommand)] + game_type: Option, +} + +pub enum Error { + NoArguments, + ClapError(clap::Error), +} + +impl TryFrom for GameConfig { + type Error = Error; + + fn try_from(cli: Cli) -> Result { + if cli.map.is_none() && cli.game_type.is_none() { + Err(Error::NoArguments) + } else if cli.map.is_some() != cli.game_type.is_some() { + Err(Error::ClapError(clap::Error::raw( + ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand, + "Either no or all arguments are required. Use '-h' to get help.\n", + ))) + } else { + let game_type = match cli.game_type.as_ref().expect("Game Type not set") { + GameType::Melee { bots } | GameType::Human { bots } => crate::GameType::Melee( + bots.iter() + .map(|name| BotConfig { + name: name.to_string(), + player_name: None, + race: None, + }) + .collect(), + ), + }; + Ok(GameConfig { + map: cli.map.unwrap(), + game_name: None, + game_type, + human_host: matches!(cli.game_type.unwrap(), GameType::Human { .. }), + }) + } + } +} diff --git a/src/main.rs b/src/main.rs index 7d30f1c..898dced 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ mod bwapi; +mod cli; use anyhow::bail; +use clap::Parser; use std::collections::HashSet; use std::error::Error; use std::fmt::{Debug, Display, Formatter}; @@ -12,6 +14,7 @@ use std::process::{Child, Command}; use std::time::Duration; use crate::bwapi::GameTableAccess; +use crate::cli::Cli; use registry::{Hive, Security}; use retry::delay::Fixed; use retry::retry; @@ -39,28 +42,28 @@ impl ShotgunConfig { } #[derive(Deserialize, Debug)] -struct BotConfig { - name: String, - player_name: Option, - race: Option, +pub struct BotConfig { + pub name: String, + pub player_name: Option, + pub race: Option, } #[derive(Deserialize, Debug)] -enum GameType { +pub enum GameType { Melee(Vec), } #[derive(Deserialize, Debug)] -struct GameConfig { - map: String, - game_name: Option, - game_type: GameType, +pub struct GameConfig { + pub map: String, + pub game_name: Option, + pub game_type: GameType, #[serde(default)] - human_host: bool, + pub human_host: bool, } impl GameConfig { - fn new(config: &ShotgunConfig) -> Result { + fn load(config: &ShotgunConfig) -> Result { let result: GameConfig = toml::from_slice( read(base_folder().join("game.toml")) .map_err(|e| e.to_string()) @@ -91,7 +94,7 @@ struct BotDefinition { } #[derive(Debug, Copy, Clone, Eq, PartialEq)] -enum Race { +pub enum Race { Protoss, Terran, Zerg, @@ -371,10 +374,17 @@ fn main() { ShotgunConfig::default() }); - let game_config = GameConfig::new(&config).expect("Could not load 'game.toml'"); + let cli = Cli::parse(); + + let game_config: Result = cli.try_into(); + let game_config = match game_config { + Ok(game_config) => game_config, + Err(cli::Error::NoArguments) => { + GameConfig::load(&config).expect("Could not load 'game.toml'") + } + Err(cli::Error::ClapError(err)) => err.exit(), + }; - // let config: BotDefinition = toml::from_slice(read("bots/template/bot.toml")?.as_slice())?; - // println!("{config:?}"); let starcraft_path = config .get_starcraft_path() .expect("Could not find StarCraft installation");