Files
broodwarBot/flake.nix
2026-01-21 22:13:49 -07:00

257 lines
8.3 KiB
Nix

{
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 -C link-args=-static-libgcc -C link-args=-static-libstdc++";
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
'';
startScript = pkgs.writeShellScriptBin "start" ''
set -e
SCRIPT_DIR="$(pwd)"
SCRIPTS_PATH="$SCRIPT_DIR/scripts"
export WINEPREFIX="$SCRIPT_DIR/.wine"
export WINEARCH=win64
export DISPLAY=:0
export WINEDLLOVERRIDES="mscoree,mshtml="
export WINEDEBUG=-all
# Add MinGW DLLs to Wine's search path
export WINEDLLPATH="${mingwPkgs.windows.pthreads}/bin:${mingwCC.cc}/x86_64-w64-mingw32/lib"
# 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 2>/dev/null || true
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
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."
'';
in
{
devShells.default = pkgs.mkShell (shellEnv // {
buildInputs = buildInputs ++ nativeBuildInputs ++ [
buildScript
buildDebugScript
cleanScript
checkScript
startScript
# 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"
echo " start - Run the bot with StarCraft"
'';
});
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";
};
start = {
type = "app";
program = "${startScript}/bin/start";
};
default = self.apps.${system}.build;
};
}
);
}