Skip to content

Commit 79f6fe0

Browse files
committed
Corrected copying of shared memory to FrameBuffer. Corrected measurement of bot idleness and frame buffer size.
1 parent 165db79 commit 79f6fe0

File tree

4 files changed

+62
-52
lines changed

4 files changed

+62
-52
lines changed

src/main/java/bwapi/BWClient.java

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,42 +50,47 @@ public void startGame(BWClientConfiguration configuration) {
5050
client.reconnect();
5151

5252
do {
53+
ClientData.GameData gameData = client.clientData().gameData();
5354
long lastUpdateTimestampMillis = 0;
54-
System.out.println("Client: Starting game");
55-
while (!getGame().isInGame()) {
56-
if (!client.isConnected()) {
55+
System.out.println("Client: Beginning game loop");
56+
while (!gameData.isInGame()) {
57+
botWrapper = null;
58+
if (client.isConnected()) {
59+
System.out.println("Client: Not in game; Connected.");
60+
} else {
61+
System.out.println("Client: Not in game; Not connected.");
5762
return;
5863
}
59-
System.out.println("Client: connected.");
6064
lastUpdateTimestampMillis = System.currentTimeMillis();
6165
client.update();
6266
}
63-
64-
System.out.println("Client: Creating bot wrapper");
65-
BotWrapper botWrapper = new BotWrapper(configuration, eventListener, client.mapFile());
66-
67-
while (getGame().isInGame()) {
68-
System.out.println("Client: Stepping bot wrapper");
67+
while (gameData.isInGame()) {
68+
System.out.println("Client: In game on frame " + gameData.getFrameCount());
69+
if (botWrapper == null) {
70+
botWrapper = new BotWrapper(configuration, eventListener, client.mapFile());
71+
}
6972
botWrapper.step();
70-
System.out.println("Client: Waiting for idle bot or frame duration");
7173

7274
// Proceed immediately once framebuffer is empty
7375
// Otherwise, wait for bot to catch up
7476
// TODO: Replace with a wait instead of a sleep
75-
// TODO: Respect configuration.asyncWaitOnFrameZero
76-
while ( ! botWrapper.botIdle()) {
77-
long frameDuration = System.currentTimeMillis() - lastUpdateTimestampMillis;
78-
if (frameDuration > configuration.asyncFrameDurationMillis && (client.clientData().gameData().getFrameCount() > 0 || ! configuration.asyncWaitOnFrameZero)) {
79-
System.out.println("Client: Exceeded frame duration while waiting for bot: " + frameDuration + "ms on frame " + client.clientData().gameData().getFrameCount());
77+
while(true) {
78+
if (botWrapper.botIdle()) {
79+
System.out.println("Client: Proceeding because bot is idle.");
8080
break;
8181
}
82-
try {
83-
Thread.sleep(1);
84-
} catch (InterruptedException ignored) {}
82+
long frameDurationMillis = System.currentTimeMillis() - lastUpdateTimestampMillis;
83+
if (frameDurationMillis > configuration.asyncFrameDurationMillis && (client.clientData().gameData().getFrameCount() > 0 || ! configuration.asyncWaitOnFrameZero)) {
84+
System.out.println("Client: Proceeding because frame " + botWrapper.getGame().getFrameCount() + " lasted " + frameDurationMillis + "ms");
85+
break;
86+
}
87+
try { Thread.sleep(1); } catch (InterruptedException ignored) {}
8588
}
8689

87-
System.out.println("Client: Ending frame. Frames buffered: ");
88-
lastUpdateTimestampMillis = System.currentTimeMillis();
90+
long currentTimeMillis = System.currentTimeMillis();
91+
long frameDurationMillis = currentTimeMillis - lastUpdateTimestampMillis;
92+
lastUpdateTimestampMillis = currentTimeMillis;
93+
System.out.println("Client: Ending frame after " + frameDurationMillis + "ms");
8994
client.update();
9095
if (!client.isConnected()) {
9196
System.out.println("Reconnecting...");

src/main/java/bwapi/BWClientConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class BWClientConfiguration {
3232
* If JBWAPI detects that this much time (in milliseconds) has passed since a bot's event handlers began, returns control back to BWAPI.
3333
* Real-time human play typically uses the "fastest" game speed, which has 42.86ms (42,860ns) between frames.
3434
*/
35-
public int asyncFrameDurationMillis = 40000;
35+
public int asyncFrameDurationMillis = 40;
3636

3737
/**
3838
* The maximum number of frames to buffer while waiting on a bot.

src/main/java/bwapi/BotWrapper.java

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ of this software and associated documentation files (the "Software"), to deal
2626
package bwapi;
2727

2828
import java.nio.ByteBuffer;
29-
import java.util.EventListener;
3029

3130
/**
3231
* Manages invocation of bot event handlers
@@ -35,8 +34,9 @@ class BotWrapper {
3534
private final BWClientConfiguration configuration;
3635
private final BWEventListener eventListener;
3736
private final Game game;
38-
private final FrameBuffer frameBuffer;
39-
private final Thread botThread;
37+
private FrameBuffer frameBuffer = null;
38+
private Thread botThread = null;
39+
private volatile boolean idle = false;
4040

4141
BotWrapper(BWClientConfiguration configuration, BWEventListener eventListener, ByteBuffer dataSource) {
4242
this.configuration = configuration;
@@ -48,43 +48,47 @@ class BotWrapper {
4848

4949
if (configuration.async) {
5050
frameBuffer = new FrameBuffer(configuration.asyncFrameBufferSize, dataSource);
51-
botThread = new Thread(() -> {
52-
while(true) {
53-
while(frameBuffer.empty()) try { Thread.sleep(0, 100); } catch (InterruptedException ignored) {}
54-
55-
System.out.println("Bot thread: Dequeuing frame. There are " + frameBuffer.framesBuffered() + " frames buffered.");
56-
game.clientData().setBuffer(frameBuffer.dequeueFrame());
51+
}
52+
}
5753

58-
System.out.println("Bot thread: Handling events.");
59-
handleEvents();
60-
if (!game.clientData().gameData().isInGame()) {
61-
System.out.println("Bot thread: Exiting.");
62-
return;
63-
} else {
64-
System.out.println("Bot thread: Handled events.");
65-
}
66-
}
67-
});
68-
botThread.setName("JBWAPI Bot");
54+
void startBot() {
55+
if (configuration.async) {
6956
botThread.start();
70-
} else {
71-
frameBuffer = null;
72-
botThread = null;
7357
}
7458
}
7559

7660
Game getGame() {
7761
return game;
7862
}
7963

64+
/**
65+
* True if the bot has handled all enqueued frames and is waiting for a new frame from StarCraft.
66+
*/
8067
boolean botIdle() {
81-
// TODO: This returns true if the bot is still processing the newest frame, leaving the bot permanently one frame behind
82-
return frameBuffer.empty();
68+
return idle || ! configuration.async;
8369
}
8470

8571
void step() {
8672
if (configuration.async) {
8773
frameBuffer.enqueueFrame();
74+
if (botThread == null) {
75+
botThread = new Thread(() -> {
76+
//noinspection InfiniteLoopStatement
77+
while(true) {
78+
while(frameBuffer.empty()) try {
79+
idle = true;
80+
Thread.sleep(0, 100);
81+
} catch (InterruptedException ignored) {}
82+
idle = false;
83+
System.out.println("Bot thread: Dequeuing frame. There are " + frameBuffer.framesBuffered() + " frames buffered.");
84+
game.clientData().setBuffer(frameBuffer.dequeueFrame());
85+
System.out.println("Bot thread: Handling events.");
86+
handleEvents();
87+
System.out.println("Bot thread: Handled events.");
88+
}});
89+
botThread.setName("JBWAPI Bot");
90+
botThread.start();
91+
}
8892
} else {
8993
handleEvents();
9094
}

src/main/java/bwapi/FrameBuffer.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ class FrameBuffer {
3737
private int size;
3838
private int stepGame = 0;
3939
private int stepBot = 0;
40-
private ClientData clientData = new ClientData();
4140
private ArrayList<ByteBuffer> dataBuffer = new ArrayList<>();
4241

4342
// Synchronization locks
@@ -86,9 +85,11 @@ synchronized private int indexBot() {
8685
*/
8786
void enqueueFrame() {
8887
while(full()) try { Thread.sleep(0, 100); } catch (InterruptedException ignored) {}
89-
int indexGame = indexGame();
90-
System.out.println("FrameBuffer: Moving game to " + indexGame);
91-
dataBuffer.get(indexGame).put(dataSource);
88+
System.out.println("FrameBuffer: Enqueuing buffer " + indexGame() + " on game step #" + stepGame + " with " + framesBuffered() + " frames buffered.");
89+
ByteBuffer dataTarget = dataBuffer.get(indexGame());
90+
dataSource.rewind();
91+
dataTarget.rewind();
92+
dataTarget.put(dataSource);
9293
++stepGame;
9394
}
9495

@@ -97,7 +98,7 @@ void enqueueFrame() {
9798
*/
9899
ByteBuffer dequeueFrame() {
99100
while(empty()) try { Thread.sleep(0, 100); } catch (InterruptedException ignored) {}
100-
System.out.println("FrameBuffer: Moving bot to " + indexBot());
101+
System.out.println("FrameBuffer: Dequeuing buffer " + indexBot() + " on bot step #" + stepBot);
101102
ByteBuffer output = dataBuffer.get(indexBot());
102103
++stepBot;
103104
return output;

0 commit comments

Comments
 (0)