Skip to content
Closed
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
31 changes: 23 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
dist: trusty
language: python
python:
- "3.6"
dist: bionic
language: java
jdk: openjdk8
python: 3.6
addons:
apt:
packages:
- python3-pip
- python3-setuptools
services:
- docker
cache:
directories:
- /tmp/sc-docker
before_install:
- jdk_switcher use oraclejdk8
before_script:
- git clone https://github.com/Bytekeeper/sc-docker.git
- cp it/sc-docker-support/*.dockerfile sc-docker/docker/dockerfiles
- pushd sc-docker
- pip3 install numpy==1.16.6
- python3 setup.py bdist_wheel
Expand All @@ -22,8 +24,21 @@ before_script:
- popd
- "[ -f /tmp/sc-docker/starcraft.zip ] || cp sc-docker/scbw/local_docker/starcraft.zip /tmp/sc-docker/starcraft.zip"
- scbw.play --install
- unzip sc-docker/scbw/local_docker/starcraft.zip -d it/openbw/

script:
- sh mvnw clean install
- sh mvnw -f it/bots/pom.xml package
- for bot in $(ls -d it/bots/*/); do BOTNAME=$(basename $bot); echo "Setting up $BOTNAME"; mkdir -p "$HOME/.scbw/bots/$BOTNAME/AI" "$HOME/.scbw/bots/$BOTNAME/read" "$HOME/.scbw/bots/$BOTNAME/write"; cp it/sc-docker-support/BWAPI.dll "$HOME/.scbw/bots/$BOTNAME"; cp "$bot/target/"*-with-dependencies.jar "$HOME/.scbw/bots/$BOTNAME/AI"; cp "$bot/bot.json" "$HOME/.scbw/bots/$BOTNAME"; done
- scbw.play --headless --bots jbwapibot SittingDuck --timeout 180 --docker_image starcraft:game 2>&1 | grep 'Winner is BotPlayer:jbwapibot:T' || (cat $HOME/.scbw/games/*/logs_0/* && false)
- set -e
- scbw.play --headless --bots jbwapibot SittingDuck --timeout 180 --docker_image starcraft:game 2>&1 | grep 'Winner is BotPlayer:jbwapibot:T' || (cat $HOME/.scbw/games/*/logs_0/* && exit 1)
- pushd it/openbw
- mv BROODAT.MPQ BrooDat.mpq
- mv patch_rt.mpq Patch_rt.mpq
- mv STARDAT.MPQ StarDat.mpq
- chmod u+x BWAPILauncher
- BWAPI_CONFIG_AUTO_MENU__RACE=Terran BWAPI_CONFIG_AUTO_MENU__MAP=~/.scbw/maps/sscai/\(3\)Neo\ Moon\ Glaive.scx ./BWAPILauncher&
- BWAPI_CONFIG_AUTO_MENU__RACE=Terran BWAPI_CONFIG_AUTO_MENU__MAP=~/.scbw/maps/sscai/\(3\)Neo\ Moon\ Glaive.scx ./BWAPILauncher&
- sleep 1
- java -cp ../bots/SittingDuck/target/SittingDuck-*-jar-with-dependencies.jar SittingDuck &
- java -jar ../bots/jbwapibot/target/MarineHell-*-jar-with-dependencies.jar | grep "Hello from JBWAPI!" || exit 1
4 changes: 4 additions & 0 deletions it/bots/SittingDuck/src/main/java/SittingDuck.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import bwapi.BWClient;
import bwapi.DefaultBWListener;

public class SittingDuck extends DefaultBWListener {
public static void main(String[] args) {
new BWClient(new SittingDuck()).startGame();
}
}
Binary file added it/openbw/BWAPILauncher
Binary file not shown.
17 changes: 0 additions & 17 deletions it/sc-docker-support/java.dockerfile

This file was deleted.

11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,17 @@
</reporting>

<dependencies>
<dependency>
<groupId>no.fiken.oss.junixsocket</groupId>
<artifactId>junixsocket-common</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>no.fiken.oss.junixsocket</groupId>
<artifactId>junixsocket-native-common</artifactId>
<version>1.0.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna -->
<dependency>
<groupId>net.java.dev.jna</groupId>
Expand Down
2 changes: 0 additions & 2 deletions src/main/java/bwapi/BWClient.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package bwapi;

import com.sun.jna.platform.win32.Kernel32;

import java.util.Objects;

/**
Expand Down
141 changes: 53 additions & 88 deletions src/main/java/bwapi/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,20 @@ of this software and associated documentation files (the "Software"), to deal

package bwapi;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.win32.W32APIOptions;

import java.io.RandomAccessFile;

class Client {
interface MappingKernel extends Kernel32 {
MappingKernel INSTANCE = Native.load(MappingKernel.class, W32APIOptions.DEFAULT_OPTIONS);

HANDLE OpenFileMapping(int desiredAccess, boolean inherit, String name);
}

private static final int READ_WRITE = 0x1 | 0x2 | 0x4;
private static final int SUPPORTED_BWAPI_VERSION = 10003;

private ClientData clientData;
private BWClient bwClient;
private boolean connected = false;
private RandomAccessFile pipeObjectHandle = null;
private WrappedBuffer gameTableFileHandle = null;
private WrappedBuffer mapFileHandle = null;
private WrappedBuffer mapShm = null;
private WrappedBuffer gameTableShm = null;
private final ClientConnection clientConnector;

Client(BWClient bwClient) {
this.bwClient = bwClient;
boolean windowsOs = System.getProperty("os.name").toLowerCase().contains("win");
clientConnector = windowsOs ? new ClientConnectionW32() : new ClientConnectionPosix();
}

/**
Expand All @@ -59,14 +47,15 @@ interface MappingKernel extends Kernel32 {
Client(final WrappedBuffer buffer) {
clientData = new ClientData();
clientData.setBuffer(buffer);
clientConnector = null;
}

ClientData liveClientData() {
return clientData;
}

WrappedBuffer mapFile() {
return mapFileHandle;
return mapShm;
}

boolean isConnected() {
Expand All @@ -87,18 +76,9 @@ private void disconnect() {
if (!connected) {
return;
}

if (pipeObjectHandle != null) {
try {
pipeObjectHandle.close();
} catch (Exception e) {
e.printStackTrace();
}
pipeObjectHandle = null;
}

gameTableFileHandle = null;
mapFileHandle = null;
clientConnector.disconnect();
mapShm = null;
gameTableShm = null;
clientData = null;
connected = false;
}
Expand All @@ -114,18 +94,16 @@ boolean connect() {

// Expose the BWAPI list of games from shared memory via a ByteBuffer
try {
final Pointer gameTableView = Kernel32.INSTANCE.MapViewOfFile(MappingKernel.INSTANCE
.OpenFileMapping(READ_WRITE, false, "Local\\bwapi_shared_memory_game_list"), READ_WRITE,
0, 0, GameTable.SIZE);
gameTableFileHandle = new WrappedBuffer(gameTableView, GameTable.SIZE);
} catch (Exception e) {
gameTableShm = clientConnector.getGameTable();
}
catch (Exception e) {
System.err.println("Game table mapping not found.");
return false;
}

GameTable gameTable;
try {
gameTable = new GameTable(gameTableFileHandle);
gameTable = new GameTable(this.gameTableShm);
} catch (Exception e) {
System.err.println("Unable to map Game table.");
if (bwClient.getConfiguration().getDebugConnection()) {
Expand All @@ -134,13 +112,13 @@ boolean connect() {
return false;
}

int latest = 0;
int oldest = Integer.MAX_VALUE;
for (int i = 0; i < GameTable.MAX_GAME_INSTANCES; i++) {
GameInstance gameInstance = gameTable.gameInstances[i];
System.out.println(i + " | " + gameInstance.serverProcessID + " | " + (gameInstance.isConnected ? 1 : 0) + " | " + gameInstance.lastKeepAliveTime);
if (gameInstance.serverProcessID != 0 && !gameInstance.isConnected) {
if (gameTableIndex == -1 || latest == 0 || gameInstance.lastKeepAliveTime < latest) {
latest = gameInstance.lastKeepAliveTime;
if (gameTableIndex == -1 || gameInstance.lastKeepAliveTime < oldest) {
oldest = gameInstance.lastKeepAliveTime;
gameTableIndex = i;
}
}
Expand All @@ -155,46 +133,40 @@ boolean connect() {
return false;
}

final String sharedMemoryName = "Local\\bwapi_shared_memory_" + serverProcID;
final String communicationPipe = "\\\\.\\pipe\\bwapi_pipe_" + serverProcID;
try {
pipeObjectHandle = new RandomAccessFile(communicationPipe, "rw");
} catch (Exception e) {
System.err.println("Unable to open communications pipe: " + communicationPipe);
mapShm = clientConnector.getSharedMemory(serverProcID);
}
catch (Exception e) {
System.err.println("Unable to open shared memory mapping: " + e.getMessage());
if (bwClient.getConfiguration().getDebugConnection()) {
e.printStackTrace();
}
gameTableFileHandle = null;
this.gameTableShm = null;
return false;
}
System.out.println("Connected");

// Expose the raw game data from shared memory via a ByteBuffer
try {
final Pointer mapFileView = Kernel32.INSTANCE.MapViewOfFile(MappingKernel.INSTANCE
.OpenFileMapping(READ_WRITE, false, sharedMemoryName), READ_WRITE,
0, 0, ClientData.GameData.SIZE);
mapFileHandle = new WrappedBuffer(mapFileView, ClientData.GameData.SIZE);
clientData = new ClientData();
clientData.setBuffer(mapShm);
} catch (Exception e) {
System.err.println("Unable to open shared memory mapping: " + sharedMemoryName);
System.err.println("Unable to map game data.");
if (bwClient.getConfiguration().getDebugConnection()) {
e.printStackTrace();
}
pipeObjectHandle = null;
gameTableFileHandle = null;
return false;
}


try {
clientData = new ClientData();
clientData.setBuffer(mapFileHandle);
}
catch (Exception e) {
System.err.println("Unable to map game data.");
clientConnector.connectSharedLock(serverProcID);
} catch (Exception e) {
System.err.println(e.getMessage());
if (bwClient.getConfiguration().getDebugConnection()) {
e.printStackTrace();
}
this.gameTableShm = null;
return false;
}
System.out.println("Connected");

if (SUPPORTED_BWAPI_VERSION != clientData.gameData().getClient_version()) {
System.err.println("Error: Client and Server are not compatible!");
Expand All @@ -204,18 +176,16 @@ boolean connect() {
sleep(2000);
return false;
}
byte code = 1;
while (code != 2) {
try {
code = pipeObjectHandle.readByte();
} catch (Exception e) {
System.err.println("Unable to read pipe object.");
if (bwClient.getConfiguration().getDebugConnection()) {
e.printStackTrace();
}
disconnect();
return false;

try {
clientConnector.waitForServerData();
} catch (Exception e) {
System.err.println(e.getMessage());
if (bwClient.getConfiguration().getDebugConnection()) {
e.printStackTrace();
}
disconnect();
return false;
}

System.out.println("Connection successful");
Expand All @@ -233,16 +203,13 @@ void sendFrameReceiveFrame() {
metrics.getCommunicationSendToSent().startTiming();
}
try {
// 1 is the "frame done" signal to BWAPI
pipeObjectHandle.writeByte(1);
}
catch (Exception e) {
clientConnector.submitClientData();
} catch (Exception e) {
System.err.println("failed, disconnecting");
if (bwClient.getConfiguration().getDebugConnection()) {
e.printStackTrace();
}
disconnect();
return;
}
metrics.getCommunicationSendToSent().stopTiming();
metrics.getFrameDurationReceiveToSent().stopTiming();
Expand All @@ -256,19 +223,16 @@ void sendFrameReceiveFrame() {
if (bwClient.doTime()) {
metrics.getCommunicationListenToReceive().startTiming();
}
boolean frameReady = false;
while (!frameReady) {
try {
// 2 is the "frame ready" signal from BWAPI
frameReady = pipeObjectHandle.readByte() == 2;
} catch (Exception e) {
System.err.println("failed, disconnecting");
if (bwClient.getConfiguration().getDebugConnection()) {
e.printStackTrace();
}
disconnect();
break;
try {
clientConnector.waitForServerData();
}
catch (Exception e) {
System.err.println("failed, disconnecting");
if (bwClient.getConfiguration().getDebugConnection()) {
e.printStackTrace();
}
disconnect();
return;
}

metrics.getCommunicationListenToReceive().stopTiming();
Expand All @@ -288,6 +252,7 @@ private void sleep(final int millis) {
try {
Thread.sleep(millis);
} catch (Exception ignored) {
// Not relevant
}
}
}
32 changes: 32 additions & 0 deletions src/main/java/bwapi/ClientConnection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package bwapi;

import java.io.IOException;

/**
* Client - Server connection abstraction
*/
interface ClientConnection {
void disconnect();

WrappedBuffer getGameTable();

WrappedBuffer getSharedMemory(int serverProcID);

void connectSharedLock(int serverProcID) throws IOException;

void waitForServerData() throws IOException;

void submitClientData() throws IOException;
}

class SharedMemoryConnectionException extends RuntimeException {
public SharedMemoryConnectionException(String message, Throwable cause) {
super(message, cause);
}
}

class SharedLockConnectionException extends RuntimeException {
public SharedLockConnectionException(String message, Throwable cause) {
super(message, cause);
}
}
Loading