commit ae7f57d3df2ae617b07c2791f94b00640795cb14 Author: Alex Mickelson Date: Wed Jan 21 20:37:17 2026 -0700 basic bot diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..557ab62 --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ +visualstudio/x64 +visualstudio/Win32 +visualstudio/.vs +starcraft/bwapi-data/* +starcraft/characters/* +starcraft/maps/* +starcraft/*.exe +starcraft/*.snp +starcraft/*.bat +starcraft/*.dll +starcraft/*.ini +starcraft/*.MPQ +starcraft/*.mpq +starcraft/Errors +starcraftfull +*.sdf +*.suo +*.opensdf +*.dll +*.o +*.pd_ +*.bwta +*.db +*.ipch +*.opendb +*.db-shm +*.db-wal +*.zip +*.iobj +*.ipdb +*.map +*.pdb +*.ilk +*.ERR +bin/StarterBot_d.exe +bin/StarterBot_d.exe +bin/ReplayData.txt +bin/ReplayParser.exe +bin/RunReplayParserAndStarcraft.bat +bin/replaydata +# Linux +bin_linux/src +!libgcc_s_dw2-1.dll +!libstdc++-6.dll + + +starcraft/ +starcraft +Starcraft.zip +.wine/ + +bin_linux/StarterBot.exe +bin_linux/ +# Nix +result +result-* +.direnv/ +.envrc.cache diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6f02be5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,59 @@ +{ + "files.exclude": { + "**/target/**": true, + "**/starcraft/**": true, + "**/starcraft": true, + "**/.wine/**": true, + "**/.wine": true, + "**/wine/**": true, + "**/bin_linux/**": true, + "**/bin_linux": true, + "**/.direnv/**": true, + "**/.direnv": true + }, + "files.watcherExclude": { + "**/target/**": true, + "**/node_modules/**": true, + "**/.git/**": true, + "**/wine/**": true, + "**/.wine/**": true, + "**/.wine": true, + "**/bin_linux/**": true, + "**/bin_linux": true, + "**/starcraft/**": true, + "**/starcraft": true, + "**/.direnv/**": true, + "**/.direnv": true + }, + "search.exclude": { + "**/target/**": true, + "**/node_modules/**": true, + "**/wine/**": true, + "**/.wine/**": true, + "**/bin_linux/**": true, + "**/starcraft/**": true, + "**/.direnv/**": true + }, + "rust-analyzer.files.exclude": [ + "starcraft", + ".wine", + "bin_linux", + "src", + ".direnv", + "wine" + ], + "rust-analyzer.linkedProjects": ["protossbot/Cargo.toml"], + "rust-analyzer.cargo.target": "x86_64-pc-windows-gnu", + "rust-analyzer.cargo.features": "all", + "rust-analyzer.check.allTargets": false, + "rust-analyzer.check.features": "all", + "cSpell.words": [ + "chokepoint", + "onframe", + "pathing", + "Protoss", + "rsbwapi", + "Zerg", + "Zergling" + ] +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..d26e2cd --- /dev/null +++ b/flake.lock @@ -0,0 +1,99 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1768886240, + "narHash": "sha256-C2TjvwYZ2VDxYWeqvvJ5XPPp6U7H66zeJlRaErJKoEM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "80e4adbcf8992d3fd27ad4964fbb84907f9478b0", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1751274312, + "narHash": "sha256-/bVBlRpECLVzjV19t5KMdMFWSwKLtb5RyXdjz3LJT+g=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "50ab793786d9de88ee30ec4e4c24fb4236fc2674", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "nixpkgs-stable": "nixpkgs-stable", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1769050281, + "narHash": "sha256-1H8DN4UZgEUqPUA5ecHOufLZMscJ4IlcGaEftaPtpBY=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "6deef0585c52d9e70f96b6121207e1496d4b0c49", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..b288e9b --- /dev/null +++ b/flake.nix @@ -0,0 +1,187 @@ +{ + description = "Broodwar Wine Bot - StarCraft Broodwar AI bot with Rust and BWAPI"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.11"; + flake-utils.url = "github:numtide/flake-utils"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = { self, nixpkgs, nixpkgs-stable, flake-utils, rust-overlay }: + flake-utils.lib.eachDefaultSystem (system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { + inherit system overlays; + }; + pkgs-stable = import nixpkgs-stable { + inherit system; + }; + + rustToolchain = pkgs.rust-bin.stable.latest.default.override { + targets = [ "x86_64-pc-windows-gnu" ]; + extensions = [ "rust-src" ]; + }; + + mingwPkgs = pkgs.pkgsCross.mingwW64; + mingwCC = mingwPkgs.stdenv.cc; + + # Get GCC version dynamically + gccVersion = mingwPkgs.stdenv.cc.cc.version; + + buildInputs = with pkgs; [ + rustToolchain + mingwCC + ]; + + nativeBuildInputs = with pkgs; [ + pkg-config + clang + llvmPackages.libclang + ]; + + shellEnv = { + CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = "${mingwCC}/bin/x86_64-w64-mingw32-gcc"; + CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUSTFLAGS = "-L ${mingwPkgs.windows.pthreads}/lib"; + CC_x86_64_pc_windows_gnu = "${mingwCC}/bin/x86_64-w64-mingw32-gcc"; + CXX_x86_64_pc_windows_gnu = "${mingwCC}/bin/x86_64-w64-mingw32-g++"; + AR_x86_64_pc_windows_gnu = "${mingwCC}/bin/x86_64-w64-mingw32-ar"; + + LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; + + # Bindgen configuration for MinGW cross-compilation + # Tell bindgen to use mingw headers, not Linux headers + BINDGEN_EXTRA_CLANG_ARGS = pkgs.lib.concatStringsSep " " [ + "--target=x86_64-w64-mingw32" + # Use -isystem to add includes with lower priority than -I + # This allows the mingw headers to find clang intrinsics + "-isystem${pkgs.llvmPackages.libclang.lib}/lib/clang/${pkgs.llvmPackages.libclang.version}/include" + "-isystem${mingwCC.cc}/include/c++/${gccVersion}" + "-isystem${mingwCC.cc}/include/c++/${gccVersion}/x86_64-w64-mingw32" + "-isystem${mingwCC.cc}/include/c++/${gccVersion}/backward" + "-isystem${mingwPkgs.windows.mingw_w64_headers}/include" + "-isystem${mingwPkgs.windows.pthreads}/include" + "-D_WIN32" + "-D_WIN64" + ]; + + # Set target for bindgen + TARGET = "x86_64-pc-windows-gnu"; + }; + + # Build script + buildScript = pkgs.writeShellScriptBin "build-protossbot" '' + set -e + cd protossbot + cargo build --target x86_64-pc-windows-gnu --release + ''; + + buildDebugScript = pkgs.writeShellScriptBin "build-protossbot-debug" '' + set -e + cd protossbot + cargo build --target x86_64-pc-windows-gnu + ''; + + cleanScript = pkgs.writeShellScriptBin "clean-protossbot" '' + cd protossbot + cargo clean + echo "✓ Cleaned build artifacts" + ''; + + checkScript = pkgs.writeShellScriptBin "check-protossbot" '' + cd protossbot + cargo check --target x86_64-pc-windows-gnu + ''; + + in + { + devShells.default = pkgs.mkShell (shellEnv // { + buildInputs = buildInputs ++ nativeBuildInputs ++ [ + buildScript + buildDebugScript + cleanScript + checkScript + + # Additional development tools + pkgs.cargo-watch + pkgs.cargo-edit + pkgs.rust-analyzer + + # Wine from stable nixpkgs + pkgs-stable.wineWowPackages.stable + + # Script dependencies + pkgs.unzip + pkgs.curl + pkgs.p7zip + pkgs.wget + pkgs.xorg.xorgserver + ]; + + shellHook = '' + echo "Available commands" + echo " build-protossbot - Build release version for Windows" + echo " build-protossbot-debug - Build debug version for Windows" + echo " check-protossbot - Quick check without building" + echo " clean-protossbot - Clean build artifacts" + ''; + }); + + packages = { + # Build the Windows executable + protossbot = pkgs.stdenv.mkDerivation { + pname = "protossbot"; + version = "0.1.0"; + src = ./protossbot; + + nativeBuildInputs = nativeBuildInputs ++ buildInputs; + + buildPhase = '' + export HOME=$TMPDIR + ${pkgs.lib.concatStringsSep "\n" + (pkgs.lib.mapAttrsToList + (name: value: "export ${name}=\"${value}\"") + shellEnv)} + + cargo build --release --target x86_64-pc-windows-gnu --locked + ''; + + installPhase = '' + mkdir -p $out/bin + cp target/x86_64-pc-windows-gnu/release/protossbot.exe $out/bin/ + ''; + }; + + default = self.packages.${system}.protossbot; + }; + + apps = { + build = { + type = "app"; + program = "${buildScript}/bin/build-protossbot"; + }; + + build-debug = { + type = "app"; + program = "${buildDebugScript}/bin/build-protossbot-debug"; + }; + + clean = { + type = "app"; + program = "${cleanScript}/bin/clean-protossbot"; + }; + + check = { + type = "app"; + program = "${checkScript}/bin/check-protossbot"; + }; + + default = self.apps.${system}.build; + }; + } + ); +} diff --git a/protossbot/.cargo/config.toml b/protossbot/.cargo/config.toml new file mode 100644 index 0000000..d0b561d --- /dev/null +++ b/protossbot/.cargo/config.toml @@ -0,0 +1,14 @@ +[build] +# Target 64-bit Windows for modern tournament compatibility +target = "x86_64-pc-windows-gnu" + +[target.x86_64-pc-windows-gnu] +# Linker and rustflags will be set by Nix flake via environment variables: +# - CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER +# - CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUSTFLAGS +# Falls back to system linker if not in Nix shell +linker = "x86_64-w64-mingw32-gcc" + +[env] +# TARGET environment variable helps bindgen know we're cross-compiling +TARGET = "x86_64-pc-windows-gnu" diff --git a/protossbot/.gitignore b/protossbot/.gitignore new file mode 100644 index 0000000..7cb8c2b --- /dev/null +++ b/protossbot/.gitignore @@ -0,0 +1,16 @@ +# Rust +/target/ +**/*.rs.bk +*.pdb +Cargo.lock + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db diff --git a/protossbot/Cargo.toml b/protossbot/Cargo.toml new file mode 100644 index 0000000..f2e7ad3 --- /dev/null +++ b/protossbot/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "rustbot" +version = "0.1.0" +edition = "2021" + +[dependencies] +rsbwapi = "3.6.3" +axum = { version = "0.7", features = ["ws"] } +tokio = { version = "1", features = ["full"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +serde_yaml = "0.9" +tokio-tungstenite = "0.24" +futures-util = "0.3" +tower-http = { version = "0.6", features = ["fs", "cors"] } +rand = "0.8" + +[profile.release] +opt-level = 3 +lto = true diff --git a/protossbot/build.sh b/protossbot/build.sh new file mode 100755 index 0000000..9fe4112 --- /dev/null +++ b/protossbot/build.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -e +# Set up environment for cross-compilation +export CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=x86_64-w64-mingw32-gcc +export CC_x86_64_pc_windows_gnu=x86_64-w64-mingw32-gcc +export CXX_x86_64_pc_windows_gnu=x86_64-w64-mingw32-g++ +export AR_x86_64_pc_windows_gnu=x86_64-w64-mingw32-ar + +# Set include path for bindgen - add C++ standard library and GCC include paths +export BINDGEN_EXTRA_CLANG_ARGS="-I/usr/lib/gcc/x86_64-w64-mingw32/13-posix/include/c++ -I/usr/lib/gcc/x86_64-w64-mingw32/13-posix/include/c++/x86_64-w64-mingw32 -I/usr/lib/gcc/x86_64-w64-mingw32/13-posix/include -I/usr/x86_64-w64-mingw32/include" + +# Build for Windows target +echo "Building..." +cargo build --target x86_64-pc-windows-gnu + +# Check if build was successful +if [ -f "target/x86_64-pc-windows-gnu/debug/rustbot.exe" ]; then + echo "Build successful: target/x86_64-pc-windows-gnu/debug/rustbot.exe" +else + echo "Build failed!" + exit 1 +fi diff --git a/protossbot/src/bot.rs b/protossbot/src/bot.rs new file mode 100644 index 0000000..0b24c33 --- /dev/null +++ b/protossbot/src/bot.rs @@ -0,0 +1,69 @@ +use std::sync::{Arc, Mutex}; + +use rsbwapi::*; + +use crate::game_state::GameState; + +impl AiModule for RustBot { + fn on_start(&mut self, game: &Game) { + // SAFETY: rsbwapi uses interior mutability (RefCell) for the command queue. + // enable_flag only adds a command to the queue. + // This cast is safe in the single-threaded BWAPI callback context. + unsafe { + let game_ptr = game as *const Game as *mut Game; + (*game_ptr).enable_flag(Flag::UserInput as i32); + } + + println!("Game started on map: {}", game.map_file_name()); + + } + + fn on_frame(&mut self, game: &Game) { + // println!("Frame {}", game.get_frame_count()); + let Ok(mut locked_state) = self.game_state.lock() else { + return; + }; + + } + + fn on_unit_create(&mut self, game: &Game, unit: Unit) { + if game.get_frame_count() < 1 { + return; + } + println!("unit created: {:?}", unit.get_type()); + } + + fn on_unit_morph(&mut self, game: &Game, unit: Unit) { + + } + + fn on_unit_destroy(&mut self, _game: &Game, unit: Unit) { + + } + + fn on_unit_complete(&mut self, game: &Game, unit: Unit) { + let Some(player) = game.self_() else { + return; + }; + + } + + fn on_end(&mut self, _game: &Game, is_winner: bool) { + if is_winner { + println!("Victory!"); + } else { + println!("Defeat!"); + } + } +} +pub struct RustBot { + game_state: Arc>, +} + +impl RustBot { + pub fn new(game_state: Arc>) -> Self { + Self { + game_state, + } + } +} \ No newline at end of file diff --git a/protossbot/src/game_state.rs b/protossbot/src/game_state.rs new file mode 100644 index 0000000..d988e57 --- /dev/null +++ b/protossbot/src/game_state.rs @@ -0,0 +1,14 @@ + + +pub struct GameState { + +} + + +impl Default for GameState { + fn default() -> Self { + Self { + + } + } +} \ No newline at end of file diff --git a/protossbot/src/main.rs b/protossbot/src/main.rs new file mode 100644 index 0000000..7cd52ed --- /dev/null +++ b/protossbot/src/main.rs @@ -0,0 +1,15 @@ +mod bot; +pub mod game_state; + +use bot::RustBot; +use std::sync::{Arc, Mutex}; +use game_state::GameState; + + +fn main() { + println!("Starting RustBot..."); + + let game_state = Arc::new(Mutex::new(GameState::default())); + + rsbwapi::start(move |_game| RustBot::new(game_state.clone() )); +} diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..f70af29 --- /dev/null +++ b/run.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCRIPTS_PATH="${SCRIPT_DIR}/scripts" + +export WINEPREFIX="$SCRIPT_DIR/.wine" +export WINEARCH=win64 +export DISPLAY=:0 +export WINEDLLOVERRIDES="mscoree,mshtml=" +export WINEDEBUG=-all + +# Cleanup function to ensure processes are killed on exit +cleanup() { + echo "" + echo "Cleaning up processes..." + if [ -n "$XVFB_PID" ] && kill -0 $XVFB_PID 2>/dev/null; then + echo "Stopping Xvfb..." + kill $XVFB_PID 2>/dev/null || true + fi + if [ -n "$BOT_PID" ] && kill -0 $BOT_PID 2>/dev/null; then + echo "Stopping protossbot..." + kill $BOT_PID 2>/dev/null || true + fi + killall StarCraft.exe + echo "Cleanup complete." +} + +# Register cleanup function to run on script exit (success or failure) +trap cleanup EXIT + +if [ ! -d "$WINEPREFIX" ]; then + wine wineboot --init +fi + +echo "Starting Xvfb virtual display..." +Xvfb :0 -auth ~/.Xauthority -screen 0 640x480x24 > /dev/null 2>&1 & +XVFB_PID=$! + +cd scripts + ./4-configure-bwapi.sh +cd .. + +echo "Building protossbot..." +# build-protossbot-debug +nix develop -c build-protossbot-debug +echo "Starting protossbot..." +cd "$SCRIPT_DIR/protossbot" + +RUST_BACKTRACE=1 RUST_BACKTRACE=full wine target/x86_64-pc-windows-gnu/debug/protossbot.exe & +BOT_PID=$! +echo "protossbot started (PID: $BOT_PID)" + + +echo "Launching StarCraft with BWAPI via Chaoslauncher..." +cd "$SCRIPT_DIR/starcraft/BWAPI/Chaoslauncher" +wine Chaoslauncher.exe + +echo "StarCraft closed." diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..b196eaa --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +tab_spaces = 2 diff --git a/scripts/1-download-starcraft.sh b/scripts/1-download-starcraft.sh new file mode 100755 index 0000000..11a4bad --- /dev/null +++ b/scripts/1-download-starcraft.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -e + +# Get workspace directory (parent of scripts directory) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +INSTALL_DIR="${PROJECT_DIR}/starcraft" + +STARCRAFT_URL="http://files.theabyss.ru/sc/starcraft.zip" +TEMP_ZIP="/tmp/starcraft.zip" + +echo "========================================" +echo "Step 1: Download StarCraft" +echo "========================================" + +if [ -f "${INSTALL_DIR}/StarCraft.exe" ]; then + echo "✓ StarCraft is already installed in ${INSTALL_DIR}!" + echo "Skipping download." + echo "" + exit 0 +else + if ! curl -L "${STARCRAFT_URL}" -o "${TEMP_ZIP}"; then + echo "ERROR: Download failed!" + echo "You may need to download manually from: ${STARCRAFT_URL}" + exit 1 + fi + + mkdir -p "${INSTALL_DIR}" + unzip -q "${TEMP_ZIP}" -d "${INSTALL_DIR}" + + rm "${TEMP_ZIP}" +fi diff --git a/scripts/2-install-bwapi.sh b/scripts/2-install-bwapi.sh new file mode 100755 index 0000000..0ff302f --- /dev/null +++ b/scripts/2-install-bwapi.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +set -euo pipefail + +echo "========================================" +echo "Step 2: Installing BWAPI" +echo "========================================" + +# Get workspace directory (parent of scripts directory) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +export SC_DIR="${PROJECT_DIR}/starcraft" +BWAPI_VERSION="4.4.0" +BWAPI_ARCHIVE="BWAPI.7z" +BWAPI_URL="https://github.com/bwapi/bwapi/releases/download/v${BWAPI_VERSION}/${BWAPI_ARCHIVE}" + +# Check if BWAPI is already installed +if [ -d "${SC_DIR}/BWAPI" ] && [ -f "${SC_DIR}/BWAPI/Chaoslauncher/Chaoslauncher.exe" ]; then + echo "✓ BWAPI is already installed!" + echo "Skipping installation." + exit 0 +fi + +if [ ! -d "${SC_DIR}" ]; then + echo "ERROR: StarCraft directory not found at ${SC_DIR}" + echo "Please install StarCraft first or set SC_DIR environment variable" + exit 1 +fi + +if [ ! -f "${SC_DIR}/StarCraft.exe" ]; then + echo "ERROR: StarCraft.exe not found in ${SC_DIR}" + echo "Please ensure StarCraft is properly installed" + exit 1 +fi + +TEMP_DIR=$(mktemp -d) +trap "rm -rf ${TEMP_DIR}" EXIT + +cd "${TEMP_DIR}" + +echo "Downloading BWAPI ${BWAPI_VERSION}..." +wget -q --show-progress "${BWAPI_URL}" || { + echo "ERROR: Failed to download BWAPI archive" + exit 1 +} + +7z x -y "${BWAPI_ARCHIVE}" -obwapi_extracted > /dev/null || { + echo "ERROR: Failed to extract BWAPI archive" + exit 1 +} + + +cd bwapi_extracted + +ls -alh Release_Binary + +cp -r Release_Binary "${SC_DIR}/BWAPI" + +cp -r Release_Binary/Starcraft/bwapi-data "${SC_DIR}/bwapi-data" + +cd .. + +# Create necessary subdirectories \ No newline at end of file diff --git a/scripts/3-download-standard-maps.sh b/scripts/3-download-standard-maps.sh new file mode 100755 index 0000000..e98b691 --- /dev/null +++ b/scripts/3-download-standard-maps.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +set -e + +# Get workspace directory (parent of scripts directory) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +MAPS_DIR="${PROJECT_DIR}/starcraft/maps/BroodWar" +TEMP_DIR="/tmp/sc_standard_maps" + +echo "========================================" +echo "Step 3: Download Standard Maps" +echo "========================================" + +# Create directories +mkdir -p "${MAPS_DIR}" +mkdir -p "${TEMP_DIR}" + +# Check if maps already exist +EXISTING_MAPS=$(find "${MAPS_DIR}" -maxdepth 1 -type f \( -name "*.scm" -o -name "*.scx" -o -name "*.SCM" -o -name "*.SCX" \) ! -name "ICCup*" 2>/dev/null | wc -l) + +if [ "$EXISTING_MAPS" -gt 10 ]; then + echo "✓ Found $EXISTING_MAPS standard maps already installed." + echo "Skipping download. Delete maps to re-download." + exit 0 +fi + +echo "Downloading standard StarCraft Broodwar maps..." + +echo "" +echo "Downloading SSCAIT map pack..." +ALT_MAPS_URL="https://sscaitournament.com/files/sscai_map_pack.zip" +TEMP_ZIP="${TEMP_DIR}/maps.zip" + +if curl -L -f "${ALT_MAPS_URL}" -o "${TEMP_ZIP}" 2>/dev/null; then + echo "Extracting maps..." + unzip -q -o "${TEMP_ZIP}" -d "${TEMP_DIR}" 2>/dev/null || true + + # Move extracted maps to the maps directory + find "${TEMP_DIR}" -type f \( -name "*.sc?" -o -name "*.SC?" \) | while read -r map; do + filename=$(basename "$map") + if [ ! -f "${MAPS_DIR}/${filename}" ]; then + cp "$map" "${MAPS_DIR}/" + echo " ✓ Extracted ${filename}" + fi + done +else + echo "SSCAIT map pack not available" +fi + +# Clean up +rm -rf "${TEMP_DIR}" diff --git a/scripts/4-configure-bwapi.sh b/scripts/4-configure-bwapi.sh new file mode 100755 index 0000000..d23e24a --- /dev/null +++ b/scripts/4-configure-bwapi.sh @@ -0,0 +1,402 @@ +#!/usr/bin/env bash + +set -e + +echo "========================================" +echo "Step 4: Configure BWAPI" +echo "========================================" + +# Paths +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +PREFERENCES_FILE="${PREFERENCES_FILE:-$SCRIPT_DIR/bwapi-preferences.yml}" +BWAPI_INI_PATH="${BWAPI_INI_PATH:-$PROJECT_DIR/starcraft/bwapi-data/bwapi.ini}" + +# Check if already configured (if bwapi.ini exists and preferences haven't changed) +if [ -f "$BWAPI_INI_PATH" ]; then + echo "✓ BWAPI configuration file already exists." + echo "Updating configuration from preferences..." +fi + +# Check if preferences file exists +if [ ! -f "$PREFERENCES_FILE" ]; then + echo "Error: Preferences file not found: $PREFERENCES_FILE" + exit 1 +fi + +# Function to read YAML value (simple parser for our use case) +read_yaml_value() { + local key="$1" + local default="${2:-}" + # Read value, ignoring comments and empty lines + local value=$(grep "^${key}:" "$PREFERENCES_FILE" | head -1 | sed 's/^[^:]*:[[:space:]]*//' | sed 's/^"\(.*\)"$/\1/') + echo "${value:-$default}" +} + +# Function to read YAML array values +read_yaml_array() { + local key="$1" + grep -A 20 "^${key}:" "$PREFERENCES_FILE" | grep '^[[:space:]]*-[[:space:]]' | sed 's/^[[:space:]]*-[[:space:]]*//' | grep -v '^#' +} + +echo "Reading preferences from: $PREFERENCES_FILE" + +# Read configuration values +AUTO_MENU=$(read_yaml_value "auto_menu" "SINGLE_PLAYER") +MAP=$(read_yaml_value "map" "maps/BroodWar/(2)Benzene.scm") +PLAYER_RACE=$(read_yaml_value "player_race" "Zerg") +ENEMY_COUNT=$(read_yaml_value "enemy_count" "1") +GAME_TYPE=$(read_yaml_value "game_type" "MELEE") +AUTO_RESTART=$(read_yaml_value "auto_restart" "OFF") +SAVE_REPLAY=$(read_yaml_value "save_replay" "maps/replays/%BOTNAME6%/\$Y \$b \$d/%MAP%_%BOTRACE%%ALLYRACES%vs%ENEMYRACES%_\$H\$M\$S.rep") +WINDOWED=$(read_yaml_value "windowed" "OFF") +WINDOW_LEFT=$(read_yaml_value "window_left" "1556") +WINDOW_TOP=$(read_yaml_value "window_top" "704") +WINDOW_WIDTH=$(read_yaml_value "window_width" "640") +WINDOW_HEIGHT=$(read_yaml_value "window_height" "480") +SOUND=$(read_yaml_value "sound" "ON") +SCREENSHOTS=$(read_yaml_value "screenshots" "gif") +DROP_PLAYERS=$(read_yaml_value "drop_players" "ON") +SHARED_MEMORY=$(read_yaml_value "shared_memory" "ON") +HOLIDAY=$(read_yaml_value "holiday" "ON") +AI_MODULE=$(read_yaml_value "ai_module" "bwapi-data/AI/ExampleAIModule.dll") +AI_MODULE_DEBUG=$(read_yaml_value "ai_module_debug" "bwapi-data/AI/ExampleAIModuled.dll") +TOURNAMENT_MODULE=$(read_yaml_value "tournament_module" "") + +# Optional settings +SPEED_OVERRIDE=$(read_yaml_value "speed_override" "") +SEED_OVERRIDE=$(read_yaml_value "seed_override" "") +CONSOLE_ATTACH_STARTUP=$(read_yaml_value "console_attach_on_startup" "FALSE") +CONSOLE_ALLOC_STARTUP=$(read_yaml_value "console_alloc_on_startup" "FALSE") +CONSOLE_ATTACH_AUTO=$(read_yaml_value "console_attach_auto" "TRUE") +CONSOLE_ALLOC_AUTO=$(read_yaml_value "console_alloc_auto" "TRUE") +WAIT_MIN_PLAYERS=$(read_yaml_value "wait_for_min_players" "2") +WAIT_MAX_PLAYERS=$(read_yaml_value "wait_for_max_players" "8") +WAIT_TIME=$(read_yaml_value "wait_for_time" "60000") +DOUBLE_SIZE=$(read_yaml_value "double_size" "ON") + +# Read computer races array +COMPUTER_RACES=() +while IFS= read -r race; do + [ -n "$race" ] && COMPUTER_RACES+=("$race") +done < <(read_yaml_array "computer_races") + +# Set enemy races with defaults +ENEMY_RACE="${COMPUTER_RACES[0]:-Terran}" +ENEMY_RACE_1="${COMPUTER_RACES[0]:-Default}" +ENEMY_RACE_2="${COMPUTER_RACES[1]:-Default}" +ENEMY_RACE_3="${COMPUTER_RACES[2]:-Default}" +ENEMY_RACE_4="${COMPUTER_RACES[3]:-Default}" +ENEMY_RACE_5="${COMPUTER_RACES[4]:-Default}" +ENEMY_RACE_6="${COMPUTER_RACES[5]:-Default}" +ENEMY_RACE_7="${COMPUTER_RACES[6]:-Default}" + +echo "Configuring BWAPI at: $BWAPI_INI_PATH" + +# Create directory if it doesn't exist +mkdir -p "$(dirname "$BWAPI_INI_PATH")" + +# Prepare conditional config lines +if [ -n "$SEED_OVERRIDE" ]; then + SEED_LINE="seed_override = $SEED_OVERRIDE" +else + SEED_LINE=";seed_override = 123456789" +fi + +if [ -n "$SPEED_OVERRIDE" ]; then + SPEED_LINE="speed_override = $SPEED_OVERRIDE" +else + SPEED_LINE=";speed_override = -1" +fi + +# Generate bwapi.ini content in one go +cat > "$BWAPI_INI_PATH" << EOF +[ai] +; Paths and revisions for AI +; - Use commas to specify AI for multiple instances. +; - If there are more instances than the amount of +; DLLs specified, then the last entry is used. +; - Example: SomeAI.dll, SecondInstance.dll, ThirdInstance.dll +; - Absolute paths are acceptable. +ai = $AI_MODULE +ai_dbg = $AI_MODULE_DEBUG + +; Used only for tournaments +; Tournaments can only be run in RELEASE mode +tournament = $TOURNAMENT_MODULE + +[auto_menu] +; auto_menu = OFF | SINGLE_PLAYER | LAN | BATTLE_NET +; for replays, just set the map to the path of the replay file +auto_menu = $AUTO_MENU + +; character_name = FIRST | WAIT | +; if FIRST (default), use the first character in the list +; if WAIT, stop at this screen +; else the character with the given value is used/created +character_name = FIRST + +; pause_dbg = ON | OFF +; This specifies if auto_menu will pause until a debugger is attached to the process. +; Only works in DEBUG mode. +pause_dbg = OFF + +; lan_mode = Same as the text that appears in the multiplayer connection list +; Examples: Local Area Network (UDP), Local PC, Direct IP +lan_mode = Local Area Network (UDP) + +; auto_restart = ON | OFF +; if ON, BWAPI will automate through the end of match screen and start the next match +; if OFF, BWAPI will pause at the end of match screen until you manually click OK, +; and then BWAPI resume menu automation and start the next match +auto_restart = $AUTO_RESTART + +; map = path to map to host relative to Starcraft folder, i.e. map = maps/(2)Boxer.scm +; leaving this field blank will join a game instead of creating it +; The filename(NOT the path) can also contain wildcards, example: maps/(?)*.sc? +; A ? is a wildcard for a single character and * is a wildcard for a string of characters +map = $MAP + +; game = name of the game to join | JOIN_FIRST +; i.e. game = BWAPI will join the game called "BWAPI" +; and game = JOIN_FIRST will join the first game in the list. +; If the game does not exist and the "map" entry is not blank, then the game will be created instead +; If this entry is blank, then it will follow the rules of the "map" entry +game = + +; mapiteration = RANDOM | SEQUENCE +; type of iteration that will be done on a map name with a wildcard +mapiteration = RANDOM + +; race = Terran | Protoss | Zerg | Random +; - Use commas to specify race for each AI module when running multiple instances. +; - If there are more instances than the amount of +; races specified, then the last entry is used. +; - To be used in conjunction with multiple AI modules +; - Example: Terran, Protoss, Terran, Zerg +race = $PLAYER_RACE + +; enemy_count = 1-7, for 1v1 games, set enemy_count = 1 +; only used in single player games +enemy_count = $ENEMY_COUNT + +; enemy_race = Terran | Protoss | Zerg | Random | RandomTP | RandomTZ | RandomPZ | RandomTPZ +; only used in single player games +enemy_race = $ENEMY_RACE + +; enemy_race_# = Default +; Values for enemy_race are acceptable, Default will use the value specified in enemy_race +enemy_race_1 = $ENEMY_RACE_1 +enemy_race_2 = $ENEMY_RACE_2 +enemy_race_3 = $ENEMY_RACE_3 +enemy_race_4 = $ENEMY_RACE_4 +enemy_race_5 = $ENEMY_RACE_5 +enemy_race_6 = $ENEMY_RACE_6 +enemy_race_7 = $ENEMY_RACE_7 + +;game_type = TOP_VS_BOTTOM | MELEE | FREE_FOR_ALL | ONE_ON_ONE | USE_MAP_SETTINGS | CAPTURE_THE_FLAG +; | GREED | SLAUGHTER | SUDDEN_DEATH | TEAM_MELEE | TEAM_FREE_FOR_ALL | TEAM_CAPTURE_THE_FLAG +game_type = $GAME_TYPE + +; game_type_extra = Text that appears in the drop-down list below the Game Type drop-down list. +; If empty, the Starcraft default will be used. +; The following are the game types that use this setting, and corresponding example values +; TOP_VS_BOTTOM 3 vs 1 | 2 vs 2 | 1 vs 3 | # vs # +; GREED 2500 | 5000 | 7500 | 10000 +; SLAUGHTER 15 | 30 | 45 | 60 +; TEAM_MELEE 2 | 3 | 4 | 5 | 6 | 7 | 8 +; TEAM_FREE_FOR_ALL 2 | 3 | 4 | 5 | 6 | 7 | 8 +; TEAM_CAPTURE_THE_FLAG 2 | 3 | 4 | 5 | 6 | 7 | 8 +game_type_extra = + +; save_replay = path to save replay to +; Accepts all environment variables including custom variables. See wiki for more info. +save_replay = $SAVE_REPLAY + +; wait_for_min_players = # +; # of players to wait for in a network game before starting. +; This includes the BWAPI player. The game will start immediately when it is full. +wait_for_min_players = $WAIT_MIN_PLAYERS + +; wait_for_max_players = # +; Start immediately when the game has reached # players. +; This includes the BWAPI player. The game will start immediately when it is full. +wait_for_max_players = $WAIT_MAX_PLAYERS + +; wait_for_time = # +; The time in milliseconds (ms) to wait after the game has met the min_players requirement. +; The game will start immediately when it is full. +wait_for_time = $WAIT_TIME + +[config] +; holiday = ON | OFF +; This will apply special easter eggs to the game when it comes time for a holiday. +holiday = $HOLIDAY + +; shared_memory = ON | OFF +; This is specifically used to disable shared memory (BWAPI Server) in the Windows Emulator "WINE" +; Setting this to OFF will disable the BWAPI Server, default is ON +; MUST be ON for client bots to connect +shared_memory = $SHARED_MEMORY + +; console_* = TRUE | FALSE +; Used for getting a console for displaying text written to stdout and stderr, and read from stdin. +; console_attach_* +; Allows BWAPI to attach to the parent process' console. i.e. if the parent +; has a console, output will be displayed on that console, and that console +; also kept open even if the parent dies. +; console_alloc_* +; Allows BWAPI to allocate it's own system console window. Not executed if +; corresponding console_attach_* is enabled and succeeds. +; console_*_on_startup +; Executes when BWAPI.dll is first attached to Starcraft. +; console_*_auto +; Executes when something is written to std::cout or std::cerr, +; and no console was successfully attached/allocated on startup. +console_attach_on_startup = $CONSOLE_ATTACH_STARTUP +console_alloc_on_startup = $CONSOLE_ALLOC_STARTUP +console_attach_auto = $CONSOLE_ATTACH_AUTO +console_alloc_auto = $CONSOLE_ALLOC_AUTO + +[window] +; These values are saved automatically when you move, resize, or toggle windowed mode + +; windowed = ON | OFF +; This causes BWAPI to enter windowed mode when it is injected. +windowed = $WINDOWED + +; left, top +; Determines the position of the window +left = $WINDOW_LEFT +top = $WINDOW_TOP + +; width, height +; Determines the width and height of the client area and not the window itself +width = $WINDOW_WIDTH +height = $WINDOW_HEIGHT + +[starcraft] +; Game sound engine = ON | OFF +sound = $SOUND +; Screenshot format = gif | pcx | tga | bmp +screenshots = $SCREENSHOTS + +; Random seed override. This uses a fixed seed at the start of the game so that if played out the exact same way, +; the same occurrences will happen every time. This value must be a decimal integer. +; +; When this key is commented out, Starcraft will use the system time as a seed. This is the default behaviour. +; +; Note: This option affects both single AND multi-player modes (for game hosts only). This means that hosting a multi-player +; game with this option enabled will distribute this fixed seed to all other players in the game. +$SEED_LINE + +; Speed override. This overrides the default game speed setting and prevents bots from changing the game speed. +; Enabling this option causes it to take effect. The value is the number of milliseconds per frame. A negative +; value uses the game's default speed value. +$SPEED_LINE + +; drop_players = ON | OFF +; This specifies if BWAPI should drop other players from the game when the timeout dialog reaches 0. Players +; usually time out when there are connection issues or their client is not responding. Setting this to OFF +; will cause BWAPI to wait an infinite amount of time until the player reconnects. +drop_players = $DROP_PLAYERS +EOF + + + + +# Configure W-MODE to enable/disable 2x view based on preferences +WMODE_INI="${PROJECT_DIR}/starcraft/wmode.ini" +if [ -f "$WMODE_INI" ]; then + if [ "$DOUBLE_SIZE" = "ON" ]; then + sed -i 's/^DblSizeMode=.*/DblSizeMode=1/' "$WMODE_INI" + else + sed -i 's/^DblSizeMode=.*/DblSizeMode=0/' "$WMODE_INI" + fi + echo "Configured W-MODE for 2x view" +else + echo "Creating wmode.ini with 2x view enabled" + cat > "$WMODE_INI" << 'EOF' +[W-MODE] + +; What settings do you want to save when you exit StarCraft? + +; Save WindowClientX? +; Default value: 1 +SaveWindowClientX=1 +; Save WindowClientY? +; Default value: 1 +SaveWindowClientY=1 +; Save WindowClientXDblSized? +; Default value: 1 +SaveWindowClientXDblSized=1 +; Save WindowClientYDblSized? +; Default value: 1 +SaveWindowClientYDblSized=1 +; Save ClipCursor? +; Default value: 0 +SaveClipCursor=0 +; Save doublesize mode? +; Default value: 1 +SaveDblSizeMode=1 +; Save EnableWindowMove? +; Default value: 1 +SaveEnableWindowMove=1 +; Save AlwaysOnTop? +; Default value: 1 +SaveAlwaysOnTop=1 +; Save DisableControls? +; Default value: 1 +SaveDisableControls=1 + +; X and Y coordinates of the StarCraft game screen. +; (Upper left corner of client area.) +; Default values: center the game screen on the desktop. +; If you don't specify the WindowClientX value then +; the window will be centered horizontally. +; Omitting WindowClientY will cause the window to +; be centered vertically. +WindowClientX=30 +WindowClientY=30 +; X and Y coordinates of the StarCraft game screen in +; doublesize mode. +WindowClientXDblSized=30 +WindowClientYDblSized=30 + +; Cursor clip (Toggle hotkey: ALT+F1) +; Default value: 0 +ClipCursor=0 +; Doublesize mode (Toggle hotkey: ALT+F9) +; Default value: 0 +DblSizeMode=1 +; Enable window move (Toggle hotkey: ALT+F10) +; Default value: 1 +EnableWindowMove=1 +; Enable always-on-top mode (Toggle hotkey: ALT+F11) +; Default value: 0 +AlwaysOnTop=0 +; Disable all controls in the caption of the StarCraft +; window. Disable the screensaver when the sc window is +; active. Window can not be closed with ALT+F4. +; (Toggle hotkey: ALT+F12) +; Default value: 0 +DisableControls=0 + +; Limit the maximum frame/sec to reach better performance. +; This is extremely useful because during replays with +; fastest x 4 speed the frame rate raises to the skies and +; MaxFps limits to 100 the number of blits that require +; 8bit -> desktop resolution conversion of the StarCraft +; screen image. +; Default and recommended value: 100 +; You can set it to higher value on faster machines. +; Minimum value: 30 (less than 100 isn't recommended) +MaxFps=100 + +; Enables StarCraft to mute all sound when the main window +; loses focus. +; Default value: 0 +MuteNotFocused=0 +EOF + echo "✓ Created wmode.ini" +fi diff --git a/scripts/5-configure-registry.sh b/scripts/5-configure-registry.sh new file mode 100755 index 0000000..d21dd19 --- /dev/null +++ b/scripts/5-configure-registry.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +echo "========================================" +echo "Step 5: Run StarCraft" +echo "========================================" + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +export WINEPREFIX="$PROJECT_DIR/.wine" +export WINEARCH=win64 +export DISPLAY=:0 +export WINEDLLOVERRIDES="mscoree,mshtml=" +export WINEDEBUG=-all + + +INSTALL_DIR="$PROJECT_DIR/starcraft" + +SC_WIN_PATH="$(winepath -w "$INSTALL_DIR" 2>/dev/null || echo "Z:${INSTALL_DIR}" | sed 's/\//\\\\/g')\\\\" + +# if wine REG QUERY "HKEY_LOCAL_MACHINE\\SOFTWARE\\Blizzard Entertainment\\Starcraft" /v InstallPath >/dev/null 2>&1; then +# echo "Registry already configured, skipping..." +# exit 0 +# fi + +echo "Configuring registry..." +# Core registry entries +wine REG ADD "HKEY_LOCAL_MACHINE\\SOFTWARE\\Blizzard Entertainment\\Starcraft" \ + /v InstallPath /t REG_EXPAND_SZ /d "${SC_WIN_PATH}" /f 2>/dev/null || true + +wine REG ADD "HKEY_LOCAL_MACHINE\\SOFTWARE\\Blizzard Entertainment\\Starcraft" \ + /v Program /t REG_EXPAND_SZ /d "${SC_WIN_PATH}StarCraft.exe" /f 2>/dev/null || true + +# Disable Intro +wine REG ADD "HKEY_CURRENT_USER\\Software\\Blizzard Entertainment\\Starcraft" /v "Intro" /t REG_SZ /d "0" /f 2>/dev/null || true +wine REG ADD "HKEY_CURRENT_USER\\Software\\Blizzard Entertainment\\Starcraft" /v "IntroX" /t REG_SZ /d "0" /f 2>/dev/null || true +wine REG ADD "HKEY_CURRENT_USER\\Software\\Blizzard Entertainment\\Starcraft" /v "Tip" /t REG_SZ /d "0" /f 2>/dev/null || true + +# Chaoslauncher configuration +SC_CHAOS_PATH=$(winepath -w "$INSTALL_DIR" | sed 's/\\/\\\\/g') +wine REG ADD "HKEY_CURRENT_USER\\Software\\Chaoslauncher\\Launcher" /v "ScPath" /t REG_SZ /d "${SC_CHAOS_PATH}" /f 2>/dev/null || true +wine REG ADD "HKEY_CURRENT_USER\\Software\\Chaoslauncher\\Launcher" /v "GameVersion" /t REG_SZ /d "Starcraft 1.16.1" /f 2>/dev/null || true +wine REG ADD "HKEY_CURRENT_USER\\Software\\Chaoslauncher\\Launcher" /v "RunScOnStartup" /t REG_SZ /d "1" /f 2>/dev/null || true + +# Enable BWAPI 4.4.0 Injector plugin by default +wine REG ADD "HKEY_CURRENT_USER\\Software\\Chaoslauncher\\PluginsEnabled" /v "BWAPI 4.4.0 Injector [RELEASE]" /t REG_SZ /d "1" /f 2>/dev/null || true +wine REG ADD "HKEY_CURRENT_USER\\Software\\Chaoslauncher\\PluginsEnabled" /v "W-MODE 1.02" /t REG_SZ /d "1" /f 2>/dev/null || true diff --git a/scripts/bwapi-preferences.yml b/scripts/bwapi-preferences.yml new file mode 100644 index 0000000..985b445 --- /dev/null +++ b/scripts/bwapi-preferences.yml @@ -0,0 +1,78 @@ +auto_menu: SINGLE_PLAYER +# auto_menu: OFF +# auto_menu: LAN +# auto_menu: BATTLE_NET + +map: maps/BroodWar/(2)Benzene.scx +# map: maps/BroodWar/IceHunter.scm +# map: maps/(2)Boxer.scm + +player_race: Zerg +# player_race: Terran +# player_race: Protoss +# player_race: Random + +enemy_count: 1 +enemy_count: 2 + +computer_races: + - Random + # - Terran + # - Zerg + # - Random + # - Default + # - Default + # - Default + +game_type: MELEE +# game_type: TEAM_MELEE + +auto_restart: OFF +# auto_restart: ON + +save_replay: "maps/replays/%BOTNAME6%/$Y $b $d/%MAP%_%BOTRACE%%ALLYRACES%vs%ENEMYRACES%_$H$M$S.rep" + +windowed: OFF +# windowed: ON + +window_left: 1556 +window_top: 704 +window_width: 640 +window_height: 480 + +# sound: ON +sound: OFF + +screenshots: gif + +drop_players: OFF + +shared_memory: ON + +holiday: ON + +# AI module paths +# ai_module: bwapi-data/AI/ExampleAIModule.dll +# ai_module_debug: bwapi-data/AI/ExampleAIModuled.dll +# Tournament module (only for tournaments in RELEASE mode) +# tournament_module: + +# Network game settings +# wait_for_min_players: 2 +# wait_for_max_players: 8 +# wait_for_time: 60000 + +# Console settings: TRUE | FALSE +# console_attach_on_startup: FALSE +# console_alloc_on_startup: FALSE +# console_attach_auto: TRUE +# console_alloc_auto: TRUE + +# Speed override (-1 for default, or milliseconds per frame) +# speed_override: -1 + +# Random seed override (decimal integer, commented = use system time) +# seed_override: 123456789 + +double_size: ON +# double_size: OFF diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..3dfb611 --- /dev/null +++ b/setup.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCRIPTS_PATH="${SCRIPT_DIR}/scripts" + +export WINEPREFIX="$SCRIPT_DIR/.wine" +export WINEARCH=win64 +export DISPLAY=:0 +export WINEDLLOVERRIDES="mscoree,mshtml=" +export WINEDEBUG=-all + +if [ ! -d "$WINEPREFIX" ]; then + wine wineboot --init +fi + +echo "Starting Xvfb virtual display..." +Xvfb :0 -auth ~/.Xauthority -screen 0 640x480x24 > /dev/null 2>&1 & +XVFB_PID=$! + + +for script in "${SCRIPTS_PATH}"/[0-9]-*.sh; do + if [ -f "$script" ]; then + script_name=$(basename "$script") + echo "" + echo "Running: $script_name" + echo "-----------------------------------------" + chmod +x "$script" + "$script" + exit_code=$? + if [ $exit_code -ne 0 ]; then + echo "" + echo "❌ Error: $script_name failed with exit code $exit_code" + exit $exit_code + fi + echo "" + fi +done + +echo "Setup Complete"