Skip to content

Commit e021d19

Browse files
committed
Put configuration properties behind getters and chain-setters
1 parent dcaaa12 commit e021d19

File tree

8 files changed

+135
-67
lines changed

8 files changed

+135
-67
lines changed

src/main/java/bwapi/BWClient.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public BWClientConfiguration getConfiguration() {
4747
* @return Whether the current frame should be subject to timing.
4848
*/
4949
boolean doTime() {
50-
return ! configuration.unlimitedFrameZero || (client.isConnected() && client.clientData().gameData().getFrameCount() > 0);
50+
return ! configuration.getUnlimitedFrameZero() || (client.isConnected() && client.clientData().gameData().getFrameCount() > 0);
5151
}
5252

5353
/**
@@ -81,7 +81,7 @@ public void startGame() {
8181
@Deprecated
8282
public void startGame(boolean autoContinue) {
8383
BWClientConfiguration configuration = new BWClientConfiguration();
84-
configuration.autoContinue = autoContinue;
84+
configuration.withAutoContinue(autoContinue);
8585
startGame(configuration);
8686
}
8787

@@ -99,7 +99,7 @@ public void startGame(BWClientConfiguration gameConfiguration) {
9999
// Use reduced priority to encourage Windows to give priority to StarCraft.exe/BWAPI.
100100
// If BWAPI doesn't get priority, it may not detect completion of a frame on our end in timely fashion.
101101
Thread.currentThread().setName("JBWAPI Client");
102-
if (configuration.async) {
102+
if (configuration.getAsync()) {
103103
Thread.currentThread().setPriority(4);
104104
}
105105

@@ -135,7 +135,7 @@ public void startGame(BWClientConfiguration gameConfiguration) {
135135
}
136136
}
137137
botWrapper.endGame();
138-
} while (configuration.autoContinue);
138+
} while (configuration.getAutoContinue());
139139
}
140140

141141
/**

src/main/java/bwapi/BWClientConfiguration.java

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,26 @@ public class BWClientConfiguration {
88
/**
99
* Set to `true` for more explicit error messages (which might spam the terminal).
1010
*/
11-
public boolean debugConnection;
11+
public BWClientConfiguration withDebugConnection(boolean value) {
12+
debugConnection = value;
13+
return this;
14+
}
15+
boolean getDebugConnection() {
16+
return debugConnection;
17+
}
18+
private boolean debugConnection;
1219

1320
/**
1421
* When true, restarts the client loop when a game ends, allowing the client to play multiple games without restarting.
1522
*/
16-
public boolean autoContinue = false;
23+
public BWClientConfiguration withAutoContinue(boolean value) {
24+
autoContinue = value;
25+
return this;
26+
}
27+
boolean getAutoContinue() {
28+
return autoContinue;
29+
}
30+
private boolean autoContinue = false;
1731

1832
/**
1933
* Most bot tournaments allow bots to take an indefinite amount of time on frame #0 (the first frame of the game) to analyze the map and load data,
@@ -23,15 +37,29 @@ public class BWClientConfiguration {
2337
* Performance metrics omit the frame as an outlier.
2438
* Asynchronous operation will block until the bot's event handlers are complete.
2539
*/
26-
public boolean unlimitedFrameZero = true;
40+
public BWClientConfiguration withUnlimitedFrameZero(boolean value) {
41+
unlimitedFrameZero = value;
42+
return this;
43+
}
44+
boolean getUnlimitedFrameZero() {
45+
return unlimitedFrameZero;
46+
}
47+
private boolean unlimitedFrameZero = true;
2748

2849
/**
2950
* The maximum amount of time the bot is supposed to spend on a single frame.
3051
* In asynchronous mode, JBWAPI will attempt to let the bot use up to this much time to process all frames before returning control to BWAPI.
3152
* In synchronous mode, JBWAPI is not empowered to prevent the bot to exceed this amount, but will record overruns in performance metrics.
3253
* Real-time human play typically uses the "fastest" game speed, which has 42.86ms (42,860ns) between frames.
3354
*/
34-
public int maxFrameDurationMs = 40;
55+
public BWClientConfiguration withMaxFrameDurationMs(int value) {
56+
maxFrameDurationMs = value;
57+
return this;
58+
}
59+
int getMaxFrameDurationMs() {
60+
return maxFrameDurationMs;
61+
}
62+
private int maxFrameDurationMs = 40;
3563

3664
/**
3765
* Runs the bot in asynchronous mode. Asynchronous mode helps attempt to ensure that the bot adheres to real-time performance constraints.
@@ -44,13 +72,27 @@ public class BWClientConfiguration {
4472
* real-time performance requirements, while not fully guaranteeing it (subject to the whims of the JVM thread scheduler), at a cost of the bot possibly
4573
* issuing commands later than intended, and a marginally larger memory footprint.
4674
*/
47-
public boolean async = false;
75+
public BWClientConfiguration withAsync(boolean value) {
76+
async = value;
77+
return this;
78+
}
79+
boolean getAsync() {
80+
return async;
81+
}
82+
private boolean async = false;
4883

4984
/**
5085
* The maximum number of frames to buffer while waiting on a bot.
5186
* Each frame buffered adds about 33 megabytes to JBWAPI's memory footprint.
5287
*/
53-
public int asyncFrameBufferCapacity = 10;
88+
public BWClientConfiguration withAsyncFrameBufferCapacity(int size) {
89+
asyncFrameBufferCapacity = size;
90+
return this;
91+
}
92+
int getAsyncFrameBufferCapacity() {
93+
return asyncFrameBufferCapacity;
94+
}
95+
private int asyncFrameBufferCapacity = 10;
5496

5597
/**
5698
* Enables thread-unsafe async mode.
@@ -59,17 +101,34 @@ public class BWClientConfiguration {
59101
* This should enhance performance by allowing the bot to act while the frame is copied, but poses unidentified risk due to
60102
* the non-thread-safe switc from shared memory reads to frame buffer reads.
61103
*/
62-
public boolean asyncUnsafe = false;
104+
public BWClientConfiguration withAsyncUnsafe(boolean value) {
105+
asyncUnsafe = value;
106+
return this;
107+
}
108+
boolean getAsyncUnsafe() {
109+
return asyncUnsafe;
110+
}
111+
private boolean asyncUnsafe = false;
63112

64113
/**
65114
* Toggles verbose logging, particularly of synchronization steps.
66115
*/
67-
public boolean logVerbosely = false;
116+
public BWClientConfiguration withLogVerbosely(boolean value) {
117+
logVerbosely = value;
118+
return this;
119+
}
120+
boolean getLogVerbosely() {
121+
return logVerbosely;
122+
}
123+
private boolean logVerbosely = false;
68124

69125
/**
70126
* Checks that the configuration is in a valid state. Throws an IllegalArgumentException if it isn't.
71127
*/
72128
void validate() {
129+
if (asyncUnsafe && ! async) {
130+
throw new IllegalArgumentException("asyncUnsafe mode needs async mode.");
131+
}
73132
if (async && maxFrameDurationMs < 0) {
74133
throw new IllegalArgumentException("maxFrameDurationMs needs to be a non-negative number (it's how long JBWAPI waits for a bot response before returning control to BWAPI).");
75134
}

src/main/java/bwapi/BotWrapper.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ class BotWrapper {
2424
BotWrapper(BWClientConfiguration configuration, BWEventListener eventListener) {
2525
this.configuration = configuration;
2626
this.eventListener = eventListener;
27-
frameBuffer = configuration.async ? new FrameBuffer(configuration) : null;
27+
frameBuffer = configuration.getAsync() ? new FrameBuffer(configuration) : null;
2828
}
2929

3030
/**
3131
* Resets the BotWrapper for a new botGame.
3232
*/
3333
void startNewGame(ByteBuffer liveData, PerformanceMetrics performanceMetrics) {
34-
if (configuration.async) {
34+
if (configuration.getAsync()) {
3535
frameBuffer.initialize(liveData, performanceMetrics);
3636
}
3737
this.performanceMetrics = performanceMetrics;
@@ -73,10 +73,10 @@ private void setUnsafeReadReady(boolean value) {
7373
* Handles the arrival of a new frame from BWAPI
7474
*/
7575
void onFrame() {
76-
if (configuration.async) {
76+
if (configuration.getAsync()) {
7777
configuration.log("Main: onFrame asynchronous start");
7878
long startNanos = System.nanoTime();
79-
long endNanos = startNanos + configuration.maxFrameDurationMs * 1000000;
79+
long endNanos = startNanos + configuration.getMaxFrameDurationMs() * 1000000;
8080
if (botThread == null) {
8181
configuration.log("Main: Starting bot thread");
8282
botThread = createBotThread();
@@ -89,7 +89,7 @@ void onFrame() {
8989
// Unsafe mode:
9090
// If the frame buffer is empty (meaning the bot must be idle)
9191
// allow the bot to read directly from shared memory while we copy it over
92-
if (configuration.asyncUnsafe) {
92+
if (configuration.getAsyncUnsafe()) {
9393
frameBuffer.lockSize.lock();
9494
try {
9595
if (frameBuffer.empty()) {
@@ -123,7 +123,7 @@ void onFrame() {
123123
// We don't synchronize on calls which access the buffer
124124
// (to avoid tens of thousands of synchronized calls per frame)
125125
// so there's no guarantee of safety here.
126-
if (configuration.asyncUnsafe && frameBuffer.size() == 1) {
126+
if (configuration.getAsyncUnsafe() && frameBuffer.size() == 1) {
127127
configuration.log("Main: Weaning bot off live data");
128128
botGame.clientData().setBuffer(frameBuffer.peek());
129129
}
@@ -135,7 +135,7 @@ void onFrame() {
135135
throw new RuntimeException(lastThrow);
136136
}
137137

138-
if (configuration.unlimitedFrameZero && frame == 0) {
138+
if (configuration.getUnlimitedFrameZero() && frame == 0) {
139139
configuration.log("Main: Waiting indefinitely on frame #" + frame);
140140
frameBuffer.conditionSize.await();
141141
} else {
@@ -242,12 +242,12 @@ private void handleEvents() {
242242
gameOver = gameOver || gameData.getEvents(i).getType() == EventType.MatchEnd;
243243
}
244244

245-
if (configuration.async) {
245+
if (configuration.getAsync()) {
246246
performanceMetrics.getFramesBehind().record(Math.max(1, frameBuffer.framesBuffered()) - 1);
247247
}
248248

249249
performanceMetrics.getBotResponse().timeIf(
250-
! gameOver && (gameData.getFrameCount() > 0 || ! configuration.unlimitedFrameZero),
250+
! gameOver && (gameData.getFrameCount() > 0 || ! configuration.getUnlimitedFrameZero()),
251251
() -> {
252252
for (int i = 0; i < gameData.getEventCount(); i++) {
253253
EventHandler.operation(eventListener, botGame, gameData.getEvents(i));

src/main/java/bwapi/Client.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ void reconnect() {
8282
}
8383

8484
private void disconnect() {
85-
if (bwClient.getConfiguration().debugConnection) {
85+
if (bwClient.getConfiguration().getDebugConnection()) {
8686
System.err.print("Disconnect called by: ");
8787
System.err.println(Thread.currentThread().getStackTrace()[2]);
8888
}
@@ -133,7 +133,7 @@ boolean connect() {
133133
}
134134
catch (Exception e) {
135135
System.err.println("Unable to map Game table.");
136-
if (bwClient.getConfiguration().debugConnection) {
136+
if (bwClient.getConfiguration().getDebugConnection()) {
137137
e.printStackTrace();
138138
}
139139
return false;
@@ -167,7 +167,7 @@ boolean connect() {
167167
}
168168
catch (Exception e) {
169169
System.err.println("Unable to open communications pipe: " + communicationPipe);
170-
if (bwClient.getConfiguration().debugConnection) {
170+
if (bwClient.getConfiguration().getDebugConnection()) {
171171
e.printStackTrace();
172172
}
173173
gameTableFileHandle = null;
@@ -183,7 +183,7 @@ boolean connect() {
183183
}
184184
catch (Exception e) {
185185
System.err.println("Unable to open shared memory mapping: " + sharedMemoryName);
186-
if (bwClient.getConfiguration().debugConnection) {
186+
if (bwClient.getConfiguration().getDebugConnection()) {
187187
e.printStackTrace();
188188
}
189189
pipeObjectHandle = null;
@@ -196,7 +196,7 @@ boolean connect() {
196196
}
197197
catch (Exception e) {
198198
System.err.println("Unable to map game data.");
199-
if (bwClient.getConfiguration().debugConnection) {
199+
if (bwClient.getConfiguration().getDebugConnection()) {
200200
e.printStackTrace();
201201
}
202202
return false;
@@ -217,7 +217,7 @@ boolean connect() {
217217
}
218218
catch (Exception e) {
219219
System.err.println("Unable to read pipe object.");
220-
if (bwClient.getConfiguration().debugConnection) {
220+
if (bwClient.getConfiguration().getDebugConnection()) {
221221
e.printStackTrace();
222222
}
223223
disconnect();
@@ -245,7 +245,7 @@ void sendFrameReceiveFrame() {
245245
}
246246
catch (Exception e) {
247247
System.err.println("failed, disconnecting");
248-
if (bwClient.getConfiguration().debugConnection) {
248+
if (bwClient.getConfiguration().getDebugConnection()) {
249249
e.printStackTrace();
250250
}
251251
disconnect();
@@ -272,7 +272,7 @@ void sendFrameReceiveFrame() {
272272
frameReady = pipeObjectHandle.readByte() == 2;
273273
} catch (Exception e) {
274274
System.err.println("failed, disconnecting");
275-
if (bwClient.getConfiguration().debugConnection) {
275+
if (bwClient.getConfiguration().getDebugConnection()) {
276276
e.printStackTrace();
277277
}
278278
disconnect();

src/main/java/bwapi/FrameBuffer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class FrameBuffer {
2727
final Condition conditionSize = lockSize.newCondition();
2828

2929
FrameBuffer(BWClientConfiguration configuration) {
30-
this.capacity = configuration.asyncFrameBufferCapacity;
30+
this.capacity = configuration.getAsyncFrameBufferCapacity();
3131
this.configuration = configuration;
3232
while(dataBuffer.size() < capacity) {
3333
dataBuffer.add(ByteBuffer.allocateDirect(BUFFER_SIZE));

src/main/java/bwapi/PerformanceMetrics.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ public void reset() {
229229
flushSideEffects = new PerformanceMetric(this, "Time flushing side effects", 1, 3, 5);
230230
botResponse = new PerformanceMetric(this, "Duration of bot event handlers", 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 85);
231231
botIdle = new PerformanceMetric(this, "Time bot spent idle", Long.MAX_VALUE);
232-
clientIdle = new PerformanceMetric(this, "Time client spent waiting for bot", configuration.maxFrameDurationMs);
232+
clientIdle = new PerformanceMetric(this, "Time client spent waiting for bot", configuration.getMaxFrameDurationMs());
233233
excessSleep = new PerformanceMetric(this, "Excess duration of client sleep", 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 85);
234234
numberOfEvents = new PerformanceMetric(this, "Number of events received from BWAPI", 1, 2, 3, 4, 5, 6, 8, 10, 15, 20);
235235
numberOfEventsTimesDurationReceiveToSent = new PerformanceMetric(this, "Number of events received from BWAPI, multiplied by the receive-to-sent duration of that frame", 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 85);

src/test/java/bwapi/SynchronizationEnvironment.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ void runGame() {
8484

8585
void runGame(int onEndFrame) {
8686
this.onEndFrame = onEndFrame;
87-
if (configuration.async) {
87+
if (configuration.getAsync()) {
8888
final long MEGABYTE = 1024 * 1024;
8989
long memoryFree = Runtime.getRuntime().freeMemory() / MEGABYTE;
90-
long memoryRequired = configuration.asyncFrameBufferCapacity * ClientData.GameData.SIZE / MEGABYTE;
90+
long memoryRequired = configuration.getAsyncFrameBufferCapacity() * ClientData.GameData.SIZE / MEGABYTE;
9191
assertTrue(
9292
"Unit test needs to be run with sufficient memory to allocate frame buffer. Has "
9393
+ memoryFree

0 commit comments

Comments
 (0)