Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions .github/workflows/e2e-linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: E2E OpenBW Linux

on:
- pull_request

jobs:
e2e:
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- uses: actions/checkout@v4

- name: Set up JDK 8
uses: actions/setup-java@v4
with:
java-version: '8'
distribution: 'temurin'
cache: maven

- name: Cache OpenBW runtime and MPQs
id: cache-openbw
uses: actions/cache@v4
with:
path: openbw-runtime
key: openbw-linux-v2

- name: Build OpenBW and fetch MPQs
if: steps.cache-openbw.outputs.cache-hit != 'true'
run: |
sudo apt-get update
sudo apt-get install -y clang libsdl2-dev libsdl2-mixer-dev

git clone --depth 1 https://github.com/basil-ladder/openbw
git clone --depth 1 -b linux-client-support https://github.com/basil-ladder/bwapi
sed -i 's/switch *(command\.type)/switch ((UnitCommandType) command.type)/g' bwapi/bwapi/include/BWAPI/Client/CommandTemp.h
cmake -S bwapi -B bwapi/build \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_CXX_FLAGS="-include cstdint" \
-DCMAKE_BUILD_TYPE=Release \
-DOPENBW_DIR="$PWD/openbw" \
-DOPENBW_ENABLE_UI=1 \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
cmake --build bwapi/build --target BWAPILauncher -j$(nproc)

mkdir -p openbw-runtime/bin openbw-runtime/lib
cp bwapi/build/bin/BWAPILauncher openbw-runtime/bin/
cp bwapi/build/lib/*.so openbw-runtime/lib/
ldd bwapi/build/lib/libOpenBWData.so | awk '/=> \// {print $3}' | grep -vE '/(libc|libm|libmvec|libdl|libpthread|librt|libgcc_s|libstdc\+\+|ld-linux)(\.so|-)' | xargs -r cp -L -t openbw-runtime/lib/

git clone --depth 1 https://github.com/dgant/mpqs
cp mpqs/STARDAT.MPQ openbw-runtime/StarDat.mpq
cp mpqs/BROODAT.MPQ openbw-runtime/BrooDat.mpq
cp mpqs/patch_rt.mpq openbw-runtime/Patch_rt.mpq

- name: Compile JBWAPI and test bots
run: |
mvn -B test-compile dependency:build-classpath -Dmdep.outputFile=cp.txt --file pom.xml
javac -cp "target/classes:$(cat cp.txt)" -d target/test-classes it/bots/SittingDuck/src/main/java/SittingDuck.java

- name: Run MarineHell vs SittingDuck match
run: |
mkdir -p openbw-runtime/maps openbw-runtime/bwapi-data
cp "it/(2)Destination.scx" "openbw-runtime/maps/(2)Destination.scx"

cat << 'EOF' > openbw-runtime/bwapi-data/bwapi.ini
[ai]
ai = NULL
ai_dbg = NULL

[auto_menu]
auto_menu = LAN
pause_dbg = OFF
lan_mode = Local Area Network (UDP)
auto_restart = OFF
map = maps/(2)Destination.scx
mapiteration = Random
race = Terran
enemy_count = 1
enemy_race = Terran
game_type = MELEE
wait_for_min_players = 2
wait_for_max_players = 2
wait_for_time = 60000

[config]
holiday = OFF
shared_memory = ON
show_warnings = YES
EOF

BOT_CP="$PWD/target/classes:$PWD/target/test-classes:$(cat cp.txt)"

cd openbw-runtime
export LD_LIBRARY_PATH="$PWD/lib:${LD_LIBRARY_PATH:-}"
rm -rf /tmp/openbw /tmp/bwapi_socket_* /dev/shm/bwapi_shared_memory_* /tmp/launcher1.log /tmp/launcher2.log /tmp/duck.log /tmp/marinehell.log

BWAPI_CONFIG_AUTO_MENU__CHARACTER_NAME="SittingDuck" OPENBW_ENABLE_UI=0 ./bin/BWAPILauncher > /tmp/launcher1.log 2>&1 &
L1_PID=$!

java -cp "$BOT_CP" SittingDuck > /tmp/duck.log 2>&1 &
B1_PID=$!

for i in $(seq 1 30); do
if grep -q "Connected" /tmp/duck.log 2>/dev/null; then
echo "SittingDuck connected!"
break
fi
sleep 0.5
done

BWAPI_CONFIG_AUTO_MENU__CHARACTER_NAME="MarineHell" OPENBW_ENABLE_UI=0 ./bin/BWAPILauncher > /tmp/launcher2.log 2>&1 &
L2_PID=$!

timeout 60 java -cp "$BOT_CP" marinehell.MarineHell | tee /tmp/marinehell.log || true
kill $L1_PID $L2_PID $B1_PID 2>/dev/null || true

if ! grep -q "Hello from JBWAPI!" /tmp/launcher1.log /tmp/launcher2.log || ! grep -q "Game ended! Winner: true" /tmp/marinehell.log; then
echo "=== launcher1.log ===" && cat /tmp/launcher1.log || true
echo "=== launcher2.log ===" && cat /tmp/launcher2.log || true
echo "=== duck.log ===" && cat /tmp/duck.log || true
exit 1
fi
50 changes: 0 additions & 50 deletions .github/workflows/e2e-linux.yml.disabled

This file was deleted.

35 changes: 23 additions & 12 deletions build_with_openbw.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,32 @@ cmake .. -DCMAKE_BUILD_TYPE=Release -DOPENBW_DIR=../../openbw -DOPENBW_ENABLE_UI
make -j4

# Download runtime deps
curl http://www.cs.mun.ca/~dchurchill/starcraftaicomp/files/Starcraft_1161.zip -o starcraft.zip
unzip starcraft.zip patch_rt.mpq BROODAT.MPQ STARDAT.MPQ
mv patch_rt.mpq Patch_rt.mpq && mv BROODAT.MPQ BrooDat.mpq && mv STARDAT.MPQ StarDat.mpq
git clone --depth 1 https://github.com/dgant/mpqs
cp mpqs/patch_rt.mpq Patch_rt.mpq && cp mpqs/BROODAT.MPQ BrooDat.mpq && cp mpqs/STARDAT.MPQ StarDat.mpq

# Run openbw using the map: Destination 1.1.scx
unzip starcraft.zip "maps/BroodWar/ICCup/ICCup Destination 1.1.scx"

BWAPI_CONFIG_AUTO_MENU__RACE=Terran BWAPI_CONFIG_AUTO_MENU__MAP="maps/BroodWar/ICCup/ICCup Destination 1.1.scx" ./bin/BWAPILauncher
# Run openbw using the map: (2)Destination.scx
BWAPI_CONFIG_AUTO_MENU__RACE=Terran BWAPI_CONFIG_AUTO_MENU__MAP="it/(2)Destination.scx" ./bin/BWAPILauncher
```

Compiling and running openbw on macos with client support (not working):
Compiling and running openbw on macos with client support:

```bash
brew install cmake sdl2 sdl2_mixer gcc
# Download build deps
brew install cmake sdl2 sdl2_mixer

cmake .. -D CMAKE_C_COMPILER=gcc-11 -D CMAKE_CXX_COMPILER=g++-11 -DCMAKE_BUILD_TYPE=Release -DOPENBW_DIR=../../openbw -DOPENBW_ENABLE_UI=1
make -j4
```
# Build openbw with client support
git clone https://github.com/basil-ladder/openbw
git clone -b linux-client-support https://github.com/basil-ladder/bwapi
cd bwapi
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DOPENBW_DIR=../../openbw -DOPENBW_ENABLE_UI=1 -DCMAKE_POLICY_VERSION_MINIMUM=3.5
make -j4

# Download runtime deps
git clone --depth 1 https://github.com/dgant/mpqs
cp mpqs/patch_rt.mpq Patch_rt.mpq && cp mpqs/BROODAT.MPQ BrooDat.mpq && cp mpqs/STARDAT.MPQ StarDat.mpq

# Run openbw using the map: (2)Destination.scx
BWAPI_CONFIG_AUTO_MENU__RACE=Terran BWAPI_CONFIG_AUTO_MENU__MAP="it/(2)Destination.scx" OPENBW_ENABLE_UI=1 ./bin/BWAPILauncher
```
Binary file added it/(2)Destination.scx
Binary file not shown.
8 changes: 4 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,14 @@
</profiles>
<dependencies>
<dependency>
<groupId>no.fiken.oss.junixsocket</groupId>
<groupId>com.kohlschutter.junixsocket</groupId>
<artifactId>junixsocket-common</artifactId>
<version>1.0.2</version>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>no.fiken.oss.junixsocket</groupId>
<groupId>com.kohlschutter.junixsocket</groupId>
<artifactId>junixsocket-native-common</artifactId>
<version>1.0.2</version>
<version>2.10.1</version>
</dependency>

<dependency>
Expand Down
22 changes: 16 additions & 6 deletions src/main/java/bwapi/ClientConnectionPosix.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.sun.jna.LastErrorException;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.platform.linux.Fcntl;
import com.sun.jna.platform.linux.LibRT;
Expand All @@ -24,7 +25,7 @@ class ClientConnectionPosix implements ClientConnection {
interface LibCExt extends LibC {
LibCExt INSTANCE = Native.load(LibCExt.class);

Pointer mmap(Pointer addr, int length, int prot, int flags, int fd, int offset) throws LastErrorException;
Pointer mmap(Pointer addr, NativeLong length, int prot, int flags, int fd, NativeLong offset) throws LastErrorException;
}

interface PosixShm extends Library {
Expand Down Expand Up @@ -57,17 +58,26 @@ public void disconnect() {
public WrappedBuffer getGameTable() {
int fd = PosixShm.INSTANCE.shm_open("/bwapi_shared_memory_game_list", Fcntl.O_RDWR, 0);
if (fd < 0) throw new IllegalStateException("SHM not found");
Pointer gameTableView = LibCExt.INSTANCE.mmap(Pointer.NULL, GameTable.SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
return new WrappedBuffer(gameTableView, GameTable.SIZE);
try {
Pointer gameTableView = LibCExt.INSTANCE.mmap(Pointer.NULL, new NativeLong(GameTable.SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, fd, new NativeLong(0));
return new WrappedBuffer(gameTableView, GameTable.SIZE);
} finally {
LibCExt.INSTANCE.close(fd);
}
}

@Override
public WrappedBuffer getSharedMemory(int serverProcID) {
String sharedMemoryName = "/bwapi_shared_memory_" + serverProcID;
try {
Pointer mapFileView = LibCExt.INSTANCE.mmap(Pointer.NULL, ClientData.GameData.SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, LibRT.INSTANCE.shm_open(sharedMemoryName, Fcntl.O_RDWR, 0),
0);
return new WrappedBuffer(mapFileView, ClientData.GameData.SIZE);
int fd = PosixShm.INSTANCE.shm_open(sharedMemoryName, Fcntl.O_RDWR, 0);
if (fd < 0) throw new IllegalStateException("SHM not found");
try {
Pointer mapFileView = LibCExt.INSTANCE.mmap(Pointer.NULL, new NativeLong(ClientData.GameData.SIZE), PROT_READ | PROT_WRITE, MAP_SHARED, fd, new NativeLong(0));
return new WrappedBuffer(mapFileView, ClientData.GameData.SIZE);
} finally {
LibCExt.INSTANCE.close(fd);
}
} catch (Exception e) {
throw new SharedMemoryConnectionException(sharedMemoryName, e);
}
Expand Down
14 changes: 10 additions & 4 deletions src/test/java/marinehell/MarineHell.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public void onStart() {
BWTA.analyze();

int i = 0;
System.out.printf("Map name: %s; Map file name: %s\n", game.mapName(), game.mapFileName());
System.out.printf("Map name: %s; Map file name: %s; Race: %s; Units: %d\n", game.mapName(), game.mapFileName(), self.getRace(), self.getUnits().size());

// Add a DrawShape call to ensure this doesn't block
game.drawCircleScreen(new Position(200, 200), 3, Color.Black);
Expand Down Expand Up @@ -170,8 +170,9 @@ public void onFrame() {
// patch
if (myUnit.getType().isWorker() && myUnit.isIdle()) {
boolean skip = false;
if (bunker == null && bunkerBuilder != null && myUnit.equals(bunkerBuilder)
&& barracks.isEmpty() == false) {
if ((bunker == null && bunkerBuilder != null && myUnit.equals(bunkerBuilder)
&& barracks.isEmpty() == false)
|| (myUnit.equals(searcher) && searchingScv > 0)) {
skip = true;
}

Expand Down Expand Up @@ -283,7 +284,7 @@ public void onFrame() {

for (BaseLocation b : BWTA.getBaseLocations()) {
// If this is a possible start location,
if (b.isStartLocation()) {
if (b.isStartLocation() && !b.getTilePosition().equals(self.getStartLocation())) {
baseLocations.add(b);
}

Expand Down Expand Up @@ -399,6 +400,11 @@ public void onFrame() {
// game.drawTextScreen(10, 25, units.toString());
}

@Override
public void onEnd(boolean isWinner) {
System.out.println("Game ended! Winner: " + isWinner);
}

public static void main(String[] args) {
new MarineHell().run();
}
Expand Down
Loading