Skip to content

Commit 0cae24e

Browse files
committed
Extracted portions of Client to GameDataUtils. Removed the bot loop entirely for reinsertion via BotWrapper, so this revision is in a non-working state.
1 parent 3808f73 commit 0cae24e

File tree

11 files changed

+1159
-955
lines changed

11 files changed

+1159
-955
lines changed

src/main/java/bwapi/BWClient.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public void startGame(boolean autoContinue) {
4444
* @param configuration Settings for playing games with this client.
4545
*/
4646
public void startGame(BWClientConfiguration configuration) {
47+
configuration.validate();
4748
Client client = new Client(configuration);
4849
client.reconnect();
4950
handler = new EventHandler(eventListener, client);
@@ -53,10 +54,10 @@ public void startGame(BWClientConfiguration configuration) {
5354
if (!client.isConnected()) {
5455
return;
5556
}
56-
client.update(handler);
57+
client.update();
5758
}
5859
while (getGame().isInGame()) {
59-
client.update(handler);
60+
client.update();
6061
if (!client.isConnected()) {
6162
System.out.println("Reconnecting...");
6263
client.reconnect();

src/main/java/bwapi/BWClientConfiguration.java

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
*/
66
public class BWClientConfiguration {
77

8+
/**
9+
* Set to `true` for more explicit error messages (which might spam the terminal).
10+
*/
11+
public boolean debugConnection;
12+
813
/**
914
* When true, restarts the client loop when a game ends, allowing the client to play multiple games without restarting.
1015
*/
@@ -24,18 +29,19 @@ public class BWClientConfiguration {
2429
public boolean async = false;
2530

2631
/**
27-
* If JBWAPI detects that this much time (in nanoseconds) has passed since a bot's event handlers began, returns control back to BWAPI.
28-
* Real-time human play typically uses the "fastest" game speed, which has 42.86ms (42,860ns) between frames.
32+
* How frequently (in nanoseconds) to poll for the bot's event handlers completing. Acts as a floor on the bot's frame duration.
2933
*/
30-
public int asyncFrameDurationNanosMax = 40000;
34+
public int asyncFrameDurationNanosMin = 500;
3135

3236
/**
33-
* How frequently (in nanoseconds) to poll for the bot's event handlers completing. Acts as a floor on the bot's frame duration.
37+
* If JBWAPI detects that this much time (in nanoseconds) has passed since a bot's event handlers began, returns control back to BWAPI.
38+
* Real-time human play typically uses the "fastest" game speed, which has 42.86ms (42,860ns) between frames.
3439
*/
35-
public int asyncFrameDurationNanosMin = 500;
40+
public int asyncFrameDurationNanosMax = 40000;
3641

3742
/**
38-
* The maximum number of frames to buffer while waiting on a bot
43+
* The maximum number of frames to buffer while waiting on a bot.
44+
* Each frame buffered adds about 33 megabytes to JBWAPI's memory footprint.
3945
*/
4046
public int asyncFrameBufferSize = 10;
4147

@@ -49,7 +55,17 @@ public class BWClientConfiguration {
4955
public boolean asyncWaitOnFrameZero = true;
5056

5157
/**
52-
* Set to `true` for more explicit error messages (which might spam the terminal).
58+
* Checks that the configuration is in a valid state. Throws an IllegalArgumentException if it isn't.
5359
*/
54-
public boolean debugConnection;
60+
public void validate() {
61+
if (async && asyncFrameDurationNanosMin <= 0) {
62+
throw new IllegalArgumentException("asyncFrameDurationNanosMin needs to be a positive number (it's how long JBWAPI waits to poll for a completed frame.");
63+
}
64+
if (async && asyncFrameDurationNanosMax < 0) {
65+
throw new IllegalArgumentException("asyncFrameDurationNanosMax needs to be a non-negative number (it's how long JBWAPI waits for a bot response before returning control to BWAPI).");
66+
}
67+
if (async && asyncFrameBufferSize < 1) {
68+
throw new IllegalArgumentException("asyncFrameBufferSize needs to be a positive number (There needs to be at least one frame buffer).");
69+
}
70+
}
5571
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
MIT License
3+
4+
Copyright (c) 2018 Hannes Bredberg
5+
Modified work Copyright (c) 2018 Jasper
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
SOFTWARE.
24+
*/
25+
26+
package bwapi;
27+
28+
import java.nio.ByteBuffer;
29+
30+
/**
31+
* Manages invocation of bot event handlers
32+
*/
33+
public class BotWrapper {
34+
private EventHandler eventHandler;
35+
private ByteBuffer sharedMemory;
36+
private BWClientConfiguration configuration;
37+
38+
private FrameBuffer frameBuffer;
39+
40+
public BotWrapper(ByteBuffer sharedMemory, EventHandler eventHandler, BWClientConfiguration configuration) {
41+
this.sharedMemory = sharedMemory;
42+
this.eventHandler = eventHandler;
43+
this.configuration = configuration;
44+
45+
if (configuration.async) {
46+
frameBuffer = new FrameBuffer(configuration.asyncFrameBufferSize);
47+
}
48+
}
49+
50+
public void run() {
51+
if (configuration.async) {
52+
// TODO: Synchronize
53+
frameBuffer.enqueueFrame();
54+
} else {
55+
/*
56+
for (int i = 0; i < gameData.getEventCount(); i++) {
57+
eventHandler.operation(gameData.getEvents(i));
58+
}
59+
*/
60+
}
61+
}
62+
}

src/main/java/bwapi/Client.java

Lines changed: 11 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@ of this software and associated documentation files (the "Software"), to deal
2525

2626
package bwapi;
2727

28-
import bwapi.ClientData.Command;
2928
import bwapi.ClientData.GameData;
30-
import bwapi.ClientData.Shape;
3129
import com.sun.jna.Native;
3230
import com.sun.jna.platform.win32.Kernel32;
3331
import com.sun.jna.win32.W32APIOptions;
@@ -48,17 +46,14 @@ public interface EventHandler {
4846
}
4947

5048
private static final int READ_WRITE = 0x1 | 0x2 | 0x4;
51-
5249
private static final int SUPPORTED_BWAPI_VERSION = 10003;
53-
static final int MAX_COUNT = 19999;
54-
static final int MAX_STRING_SIZE = 1024;
5550

5651
private ClientData clientData;
5752
private ClientData.GameData gameData;
5853
private boolean connected = false;
5954
private RandomAccessFile pipeObjectHandle = null;
60-
private ByteBuffer mapFileHandle = null;
6155
private ByteBuffer gameTableFileHandle = null;
56+
private ByteBuffer mapFileHandle = null;
6257

6358
private BWClientConfiguration configuration = new BWClientConfiguration();
6459

@@ -70,7 +65,8 @@ public interface EventHandler {
7065
* For test purposes only
7166
*/
7267
Client(ByteBuffer buffer) {
73-
clientData = new ClientData(buffer);
68+
clientData = new ClientData();
69+
clientData.setBuffer(buffer);
7470
gameData = clientData.new GameData(0);
7571
}
7672

@@ -86,7 +82,7 @@ boolean isConnected() {
8682
return connected;
8783
}
8884

89-
void reconnect(){
85+
void reconnect() {
9086
while (!connect()) {
9187
sleep(1000);
9288
}
@@ -111,8 +107,8 @@ void disconnect() {
111107
pipeObjectHandle = null;
112108
}
113109

114-
mapFileHandle = null;
115110
gameTableFileHandle = null;
111+
mapFileHandle = null;
116112
gameData = null;
117113
connected = false;
118114
}
@@ -126,6 +122,7 @@ boolean connect() {
126122
int serverProcID = -1;
127123
int gameTableIndex = -1;
128124

125+
// Expose the BWAPI list of games from shared memory via a ByteBuffer
129126
try {
130127
gameTableFileHandle = Kernel32.INSTANCE.MapViewOfFile(
131128
MappingKernel.INSTANCE.OpenFileMapping(READ_WRITE, false, "Local\\bwapi_shared_memory_game_list"), READ_WRITE, 0, 0, GameTable.SIZE)
@@ -185,6 +182,7 @@ boolean connect() {
185182
}
186183
System.out.println("Connected");
187184

185+
// Expose the raw game data from shared memory via a ByteBuffer
188186
try {
189187
mapFileHandle = Kernel32.INSTANCE.MapViewOfFile(MappingKernel.INSTANCE
190188
.OpenFileMapping(READ_WRITE, false, sharedMemoryName), READ_WRITE,
@@ -200,7 +198,8 @@ boolean connect() {
200198
return false;
201199
}
202200
try {
203-
clientData = new ClientData(mapFileHandle);
201+
clientData = new ClientData();
202+
clientData.setBuffer(mapFileHandle);
204203
gameData = clientData.new GameData(0);
205204
}
206205
catch (Exception e) {
@@ -239,7 +238,7 @@ boolean connect() {
239238
return true;
240239
}
241240

242-
void update(final EventHandler handler) {
241+
void update() {
243242
byte code = 1;
244243
try {
245244
pipeObjectHandle.writeByte(code);
@@ -265,60 +264,10 @@ void update(final EventHandler handler) {
265264
return;
266265
}
267266
}
268-
for (int i = 0; i < gameData.getEventCount(); i++) {
269-
handler.operation(gameData.getEvents(i));
270-
}
271-
}
272-
273-
String eventString(final int s) {
274-
return gameData.getEventStrings(s);
275-
}
276-
277-
int addString(final String string) {
278-
int stringCount = gameData.getStringCount();
279-
if (stringCount >= MAX_COUNT) {
280-
throw new IllegalStateException("Too many strings!");
281-
}
282-
283-
//truncate string if its size equals or exceeds 1024
284-
final String stringTruncated = string.length() >= MAX_STRING_SIZE
285-
? string.substring(0, MAX_STRING_SIZE - 1)
286-
: string;
287-
288-
gameData.setStringCount(stringCount + 1);
289-
gameData.setStrings(stringCount, stringTruncated);
290-
return stringCount;
291-
}
292-
293-
Shape addShape() {
294-
int shapeCount = gameData.getShapeCount();
295-
if (shapeCount >= MAX_COUNT) {
296-
throw new IllegalStateException("Too many shapes!");
297-
}
298-
gameData.setShapeCount(shapeCount + 1);
299-
return gameData.getShapes(shapeCount);
300-
}
301-
302-
Command addCommand() {
303-
final int commandCount = gameData.getCommandCount();
304-
if (commandCount >= MAX_COUNT) {
305-
throw new IllegalStateException("Too many commands!");
306-
}
307-
gameData.setCommandCount(commandCount + 1);
308-
return gameData.getCommands(commandCount);
309-
}
310-
311-
ClientData.UnitCommand addUnitCommand() {
312-
int unitCommandCount = gameData.getUnitCommandCount();
313-
if (unitCommandCount >= MAX_COUNT) {
314-
throw new IllegalStateException("Too many unit commands!");
315-
}
316-
gameData.setUnitCommandCount(unitCommandCount + 1);
317-
return gameData.getUnitCommands(unitCommandCount);
318267
}
319268

320269
private void sleep(final int millis) {
321-
try{
270+
try {
322271
Thread.sleep(millis);
323272
}
324273
catch (Exception ignored) {

0 commit comments

Comments
 (0)