Skip to content

Commit

Permalink
Readme pimping, make bots and bwheadless log instead of polluting std…
Browse files Browse the repository at this point in the history
…out (or not printing anything), check for duplicate bots in the game config - but still run
  • Loading branch information
Bytekeeper committed Mar 7, 2022
1 parent 8b262b3 commit 9aa498b
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 4 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,33 @@
Utility to quickly setup Starcraft Broodwar matches between 2 *or more* bots

Be aware that all bots will be executed directly, without any layer of isolation. If you need a more secure environment, either use sc-docker or setup BWAIShotgun in a VM.

# Usage
Have an installation of StarCraft Broodwar 1.16 (or get it [here](http://www.cs.mun.ca/~dchurchill/startcraft/scbw_bwapi440.zip)).


Download the latest release of `bwaishotgun.z7` and unpack it.
Since Virus Scanners might interfere with download, it is password protected with the password `shotgun`.
The `bwheadless` file inside might trigger your Virus Scanner directly or indirectly (when bwaishotgun is started).

I built the binary using a [fork](https://github.com/Bytekeeper/bwheadless) of the origin [bwheadless](https://github.com/tscmoo/bwheadless),
feel free to check the code. It certainly does fishy things, which is to be expected as it heavily modifies StarCraft to run without UI etc.

Copy the `SNP_DirectIP.snp` (Local PC network inside the game) - the modified version of BWAIshotgun allows for 8 bots to play in a single game.

Edit the `shotgun.toml` file. Many newer Java bots should run with any odd Java you have installed.
In that case, just leave the java setting open, and try the version on the `PATH`.

Download bots of your choice (only BWAPI 4.2+ bots were tested) from https://www.sscaitournament.com/index.php?action=scores.
Inside the bots directory, copy the `template` directory and rename it to the bot.
Place the `BWAPI.dll` inside, and the bot binary inside the `bwapi-data\AI` folder.

To setup a game, edit the `game.toml` file. Add the absolute path of the map you want, and setup the bots.
The description of the `game_type` variable should be sufficient.

Finally, run `bwaishotgun.exe` - it should show some info output of bots being started.
There is currently no timeout mechanism.
If the game does not stop after a few minutes, kill it and check the `logs` folder inside each bot folder for errors.

If a bot fails to work, feel free to open an issue - please include a zipped up version of that bots directory.
Bots older that BWAPI 4.2 might need some more setup, please make sure that it can run without `bwaishotgun`, before opening a ticket.
4 changes: 2 additions & 2 deletions build.bat
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
cargo build --release
releng\7za a -pnone -- bwaishotgun.7z target/release/bwaishotgun.exe bots SNP_DirectIP.snp bwheadless.exe game.toml shotgun.toml
releng\7za rn -pnone -- bwaishotgun.7z target/release/bwaishotgun.exe BWAIShotgun.exe
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
31 changes: 29 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod bwapi;

use anyhow::bail;
use std::collections::HashSet;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fs::{create_dir_all, metadata, read, read_dir, File};
Expand Down Expand Up @@ -305,6 +306,7 @@ pub struct PreparedBot {
name: String,
bwapi_dll: PathBuf,
working_dir: PathBuf,
log_dir: PathBuf,
}

impl PreparedBot {
Expand All @@ -316,9 +318,11 @@ impl PreparedBot {
let ai_module_path = ai_module_path.as_path().join("AI");
let read_path = bwapi_data_path.join("read");
let write_path = bwapi_data_path.join("write");
let log_dir = path.join("logs");
let bwapi_ini_path = bwapi_data_path.join("bwapi.ini");
create_dir_all(read_path).expect("Could not create read folder");
create_dir_all(write_path).expect("Could not create write folder");
create_dir_all(&log_dir).expect("Colud not create log folder");
let mut bwapi_ini = File::create(bwapi_ini_path).expect("Could not create 'bwapi.ini'");

let bot_binary = definition
Expand Down Expand Up @@ -348,6 +352,7 @@ impl PreparedBot {
.unwrap_or_else(|| config.name.clone()),
bwapi_dll: bwapi_data_path.join("BWAPI.dll"),
working_dir: path.to_path_buf(),
log_dir,
}
}
}
Expand Down Expand Up @@ -420,7 +425,7 @@ fn main() {
.expect("Could not read 'bot.toml'");
if let Some(race) = &cfg.race {
if bot_definition.race != Race::Random && &bot_definition.race != race {
eprintln!(
println!(
"Bot '{}' is configured to play as {}, but its default race is {}!",
cfg.name, race, bot_definition.race
);
Expand All @@ -442,6 +447,12 @@ fn main() {
0
}
});
let mut bot_names = HashSet::new();
for bot in prepared_bots.iter().map(|it| &it.name) {
if !bot_names.insert(bot) {
println!("'{}' was added multiple times. All instances will use the same read/write/log folders and could fail to work properly.", bot);
}
}
let mut instances = vec![];
for bot in prepared_bots {
let mut cmd = if !host {
Expand Down Expand Up @@ -477,11 +488,23 @@ fn main() {
} else {
0
};
println!("Firing up {} {}", bot.name, old_connected_client_count);
cmd.stdout(
File::create(bot.log_dir.join("game_out.log"))
.expect("Could not create game output log"),
);
cmd.stderr(
File::create(bot.log_dir.join("game_err.log"))
.expect("Could not create game error log"),
);
println!("Firing up {}", bot.name);
let bwheadless = cmd
.spawn()
.expect("Could not run bwheadless (maybe deleted/blocked by a Virus Scanner?)");

let bot_out_log = File::create(bot.log_dir.join("bot_out.log"))
.expect("Could not create bot output log");
let bot_err_log = File::create(bot.log_dir.join("bot_err.log"))
.expect("Could not create bot error log");
let mut bot_process = None;
match bot.binary {
Binary::Dll(_) => (), // Loaded by BWAPI
Expand All @@ -490,6 +513,8 @@ fn main() {
Command::new(config.java_path.as_deref().unwrap_or("java.exe"));
cmd.current_dir(Path::new(bot.working_dir.to_string_lossy().deref()));
cmd.arg("-jar").arg(jar);
cmd.stdout(bot_out_log);
cmd.stderr(bot_err_log);

let child = cmd.spawn().expect("Could not execute bot binary");

Expand Down Expand Up @@ -517,6 +542,8 @@ fn main() {
Binary::Exe(exe) => {
let mut cmd = Command::new(exe);
cmd.current_dir(Path::new(bot.working_dir.to_string_lossy().deref()));
cmd.stdout(bot_out_log);
cmd.stderr(bot_err_log);

let child = cmd.spawn().expect("Could not execute bot binary");

Expand Down

0 comments on commit 9aa498b

Please sign in to comment.