Skip to content

Commit 137254e

Browse files
authored
Merge pull request #63 from JavaBWAPI/support-jdk9+
Support jdk9+
2 parents 1289a23 + abcb689 commit 137254e

File tree

10 files changed

+97
-113
lines changed

10 files changed

+97
-113
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ target/
88
.classpath
99
.project
1010

11+
# logging
12+
*.log

src/main/java/bwapi/Client.java

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,11 @@ of this software and associated documentation files (the "Software"), to deal
2929
import bwapi.ClientData.GameData;
3030
import bwapi.ClientData.Shape;
3131
import com.sun.jna.Native;
32+
import com.sun.jna.Pointer;
3233
import com.sun.jna.platform.win32.Kernel32;
3334
import com.sun.jna.win32.W32APIOptions;
3435

3536
import java.io.RandomAccessFile;
36-
import java.nio.ByteBuffer;
37-
import java.nio.ByteOrder;
3837

3938
class Client {
4039
interface MappingKernel extends Kernel32 {
@@ -51,14 +50,13 @@ public interface EventHandler {
5150

5251
private static final int SUPPORTED_BWAPI_VERSION = 10003;
5352
static final int MAX_COUNT = 19999;
54-
static final int MAX_STRING_SIZE = 1024;
5553

5654
private ClientData clientData;
5755
private ClientData.GameData gameData;
5856
private boolean connected = false;
5957
private RandomAccessFile pipeObjectHandle = null;
60-
private ByteBuffer mapFileHandle = null;
61-
private ByteBuffer gameTableFileHandle = null;
58+
private WrappedBuffer mapFileHandle = null;
59+
private WrappedBuffer gameTableFileHandle = null;
6260

6361
private boolean debugConnection = false;
6462

@@ -69,7 +67,7 @@ public interface EventHandler {
6967
/**
7068
* For test purposes only
7169
*/
72-
Client(ByteBuffer buffer) {
70+
Client(final WrappedBuffer buffer) {
7371
clientData = new ClientData(buffer);
7472
gameData = clientData.new GameData(0);
7573
}
@@ -86,7 +84,7 @@ boolean isConnected() {
8684
return connected;
8785
}
8886

89-
void reconnect(){
87+
void reconnect() {
9088
while (!connect()) {
9189
sleep(1000);
9290
}
@@ -101,11 +99,10 @@ void disconnect() {
10199
return;
102100
}
103101

104-
if (pipeObjectHandle != null ) {
102+
if (pipeObjectHandle != null) {
105103
try {
106104
pipeObjectHandle.close();
107-
}
108-
catch (Exception e) {
105+
} catch (Exception e) {
109106
e.printStackTrace();
110107
}
111108
pipeObjectHandle = null;
@@ -127,21 +124,19 @@ boolean connect() {
127124
int gameTableIndex = -1;
128125

129126
try {
130-
gameTableFileHandle = Kernel32.INSTANCE.MapViewOfFile(
131-
MappingKernel.INSTANCE.OpenFileMapping(READ_WRITE, false, "Local\\bwapi_shared_memory_game_list"), READ_WRITE, 0, 0, GameTable.SIZE)
132-
.getByteBuffer(0, GameTable.SIZE);
133-
gameTableFileHandle.order(ByteOrder.LITTLE_ENDIAN);
134-
}
135-
catch (Exception e) {
127+
final Pointer gameTableView = Kernel32.INSTANCE.MapViewOfFile(MappingKernel.INSTANCE
128+
.OpenFileMapping(READ_WRITE, false, "Local\\bwapi_shared_memory_game_list"), READ_WRITE,
129+
0, 0, GameTable.SIZE);
130+
gameTableFileHandle = new WrappedBuffer(gameTableView, GameTable.SIZE);
131+
} catch (Exception e) {
136132
System.err.println("Game table mapping not found.");
137133
return false;
138134
}
139135

140136
GameTable gameTable;
141137
try {
142138
gameTable = new GameTable(gameTableFileHandle);
143-
}
144-
catch (Exception e) {
139+
} catch (Exception e) {
145140
System.err.println("Unable to map Game table.");
146141
if (debugConnection) {
147142
e.printStackTrace();
@@ -150,11 +145,11 @@ boolean connect() {
150145
}
151146

152147
int latest = 0;
153-
for(int i = 0; i < GameTable.MAX_GAME_INSTANCES; i++) {
148+
for (int i = 0; i < GameTable.MAX_GAME_INSTANCES; i++) {
154149
GameInstance gameInstance = gameTable.gameInstances[i];
155150
System.out.println(i + " | " + gameInstance.serverProcessID + " | " + (gameInstance.isConnected ? 1 : 0) + " | " + gameInstance.lastKeepAliveTime);
156151
if (gameInstance.serverProcessID != 0 && !gameInstance.isConnected) {
157-
if ( gameTableIndex == -1 || latest == 0 || gameInstance.lastKeepAliveTime < latest ) {
152+
if (gameTableIndex == -1 || latest == 0 || gameInstance.lastKeepAliveTime < latest) {
158153
latest = gameInstance.lastKeepAliveTime;
159154
gameTableIndex = i;
160155
}
@@ -173,9 +168,8 @@ boolean connect() {
173168
final String sharedMemoryName = "Local\\bwapi_shared_memory_" + serverProcID;
174169
final String communicationPipe = "\\\\.\\pipe\\bwapi_pipe_" + serverProcID;
175170
try {
176-
pipeObjectHandle = new RandomAccessFile(communicationPipe, "rw");
177-
}
178-
catch (Exception e) {
171+
pipeObjectHandle = new RandomAccessFile(communicationPipe, "rw");
172+
} catch (Exception e) {
179173
System.err.println("Unable to open communications pipe: " + communicationPipe);
180174
if (debugConnection) {
181175
e.printStackTrace();
@@ -186,11 +180,11 @@ boolean connect() {
186180
System.out.println("Connected");
187181

188182
try {
189-
mapFileHandle = Kernel32.INSTANCE.MapViewOfFile(MappingKernel.INSTANCE
183+
final Pointer mapFileView = Kernel32.INSTANCE.MapViewOfFile(MappingKernel.INSTANCE
190184
.OpenFileMapping(READ_WRITE, false, sharedMemoryName), READ_WRITE,
191-
0, 0, GameData.SIZE).getByteBuffer(0, GameData.SIZE);
192-
}
193-
catch (Exception e) {
185+
0, 0, GameData.SIZE);
186+
mapFileHandle = new WrappedBuffer(mapFileView, GameData.SIZE);
187+
} catch (Exception e) {
194188
System.err.println("Unable to open shared memory mapping: " + sharedMemoryName);
195189
if (debugConnection) {
196190
e.printStackTrace();
@@ -202,8 +196,7 @@ boolean connect() {
202196
try {
203197
clientData = new ClientData(mapFileHandle);
204198
gameData = clientData.new GameData(0);
205-
}
206-
catch (Exception e) {
199+
} catch (Exception e) {
207200
System.err.println("Unable to map game data.");
208201
if (debugConnection) {
209202
e.printStackTrace();
@@ -223,8 +216,7 @@ boolean connect() {
223216
while (code != 2) {
224217
try {
225218
code = pipeObjectHandle.readByte();
226-
}
227-
catch (Exception e) {
219+
} catch (Exception e) {
228220
System.err.println("Unable to read pipe object.");
229221
if (debugConnection) {
230222
e.printStackTrace();
@@ -243,8 +235,7 @@ void update(final EventHandler handler) {
243235
byte code = 1;
244236
try {
245237
pipeObjectHandle.writeByte(code);
246-
}
247-
catch (Exception e) {
238+
} catch (Exception e) {
248239
System.err.println("failed, disconnecting");
249240
if (debugConnection) {
250241
e.printStackTrace();
@@ -255,8 +246,7 @@ void update(final EventHandler handler) {
255246
while (code != 2) {
256247
try {
257248
code = pipeObjectHandle.readByte();
258-
}
259-
catch (Exception e) {
249+
} catch (Exception e) {
260250
System.err.println("failed, disconnecting");
261251
if (debugConnection) {
262252
e.printStackTrace();
@@ -280,13 +270,8 @@ int addString(final String string) {
280270
throw new IllegalStateException("Too many strings!");
281271
}
282272

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-
288273
gameData.setStringCount(stringCount + 1);
289-
gameData.setStrings(stringCount, stringTruncated);
274+
gameData.setStrings(stringCount, string);
290275
return stringCount;
291276
}
292277

@@ -318,10 +303,9 @@ ClientData.UnitCommand addUnitCommand() {
318303
}
319304

320305
private void sleep(final int millis) {
321-
try{
306+
try {
322307
Thread.sleep(millis);
323-
}
324-
catch (Exception ignored) {
308+
} catch (Exception ignored) {
325309
}
326310
}
327311
}

src/main/java/bwapi/ClientData.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package bwapi;
2-
import java.nio.ByteBuffer;
2+
33
final class ClientData {
44
final WrappedBuffer buffer;
5-
ClientData(final ByteBuffer buffer) {
6-
this.buffer = new WrappedBuffer(buffer);
5+
6+
ClientData(final WrappedBuffer buffer) {
7+
this.buffer = buffer;
78
}
89
class UnitCommand {
910
static final int SIZE = 24;

src/main/java/bwapi/GameTable.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package bwapi;
22

3-
import java.nio.ByteBuffer;
4-
53
/**
64
* https://github.com/bwapi/bwapi/blob/456ad612abc84da4103162ba0bf8ec4f053a4b1d/bwapi/include/BWAPI/Client/GameTable.h
75
*/
@@ -29,12 +27,12 @@ class GameTable {
2927

3028
final GameInstance[] gameInstances;
3129

32-
GameTable(final ByteBuffer gameTableFileHandle) {
30+
GameTable(final WrappedBuffer gameTableFileHandle) {
3331
gameInstances = new GameInstance[MAX_GAME_INSTANCES];
3432

3533
for (int i = 0; i < MAX_GAME_INSTANCES; i++) {
3634
int serverProcessID = gameTableFileHandle.getInt(GameInstance.SIZE * i);
37-
boolean isConnected = gameTableFileHandle.get(GameInstance.SIZE * i + 4) != 0;
35+
boolean isConnected = gameTableFileHandle.getByte(GameInstance.SIZE * i + 4) != 0;
3836
int lastKeepAliveTime = gameTableFileHandle.getInt(GameInstance.SIZE * i + 4 + 4);
3937
gameInstances[i] = new GameInstance(serverProcessID, isConnected, lastKeepAliveTime);
4038
}

src/main/java/bwapi/WrappedBuffer.java

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,42 @@
11
package bwapi;
22

3+
import com.sun.jna.Memory;
4+
import com.sun.jna.Pointer;
35
import sun.misc.Unsafe;
4-
import sun.nio.ch.DirectBuffer;
56

67
import java.lang.reflect.Field;
78
import java.nio.ByteBuffer;
89

910
/**
10-
* Wrapper around ByteBuffer that makes use of sun.misc.Unsafe if available.
11+
* Wrapper around offheap memory that uses sun.misc.Unsafe for fast access.
1112
*/
1213
class WrappedBuffer {
1314
private final ByteBuffer buffer;
1415
private final long address;
15-
private final Unsafe unsafe;
1616

17-
WrappedBuffer(final ByteBuffer byteBuffer) {
18-
unsafe = getTheUnsafe();
19-
buffer = byteBuffer;
20-
address = ((DirectBuffer) buffer).address();
21-
}
17+
private static Unsafe unsafe;
2218

23-
private static Unsafe getTheUnsafe() {
19+
static {
2420
try {
2521
final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
2622
theUnsafe.setAccessible(true);
27-
return (Unsafe) theUnsafe.get(null);
23+
unsafe = (Unsafe) theUnsafe.get(null);
24+
2825
} catch (final Exception e) {
2926
e.printStackTrace();
30-
return null;
27+
System.exit(-1);
3128
}
3229
}
3330

31+
WrappedBuffer(final int size) {
32+
this(new Memory(size), size);
33+
}
34+
35+
WrappedBuffer(final Pointer pointer, final int size) {
36+
this.buffer = pointer.getByteBuffer(0, size);
37+
this.address = Pointer.nativeValue(pointer);
38+
}
39+
3440
byte getByte(final int offset) {
3541
return unsafe.getByte(address + offset);
3642
}
@@ -64,7 +70,7 @@ void putDouble(final int offset, final double value) {
6470
}
6571

6672
String getString(final int offset, final int maxLen) {
67-
char[] buf = new char[maxLen];
73+
final char[] buf = new char[maxLen];
6874
long pos = offset + address;
6975
for (int i = 0; i < maxLen; i++) {
7076
byte b = unsafe.getByte(pos);
@@ -76,11 +82,8 @@ String getString(final int offset, final int maxLen) {
7682
}
7783

7884
void putString(final int offset, final int maxLen, final String string) {
79-
if (string.length() >= maxLen) {
80-
throw new StringIndexOutOfBoundsException();
81-
}
8285
long pos = offset + address;
83-
for (int i = 0; i < string.length(); i++) {
86+
for (int i = 0; i < Math.min(string.length(), maxLen - 1); i++) {
8487
unsafe.putByte(pos, (byte) string.charAt(i));
8588
pos++;
8689
}

src/test/java/DumpToClient.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,12 @@ public static void main(String[] args) throws IOException {
9090
StringWriter sw = new StringWriter();
9191
try (PrintWriter out = new PrintWriter(sw)) {
9292
out.println("package bwapi;");
93-
out.println("import java.nio.ByteBuffer;");
93+
out.println("");
9494
out.println("final class ClientData {");
9595
out.println(" final WrappedBuffer buffer;");
96-
out.println(" ClientData(final ByteBuffer buffer) {");
97-
out.println(" this.buffer = new WrappedBuffer(buffer);");
96+
out.println("");
97+
out.println(" ClientData(final WrappedBuffer buffer) {");
98+
out.println(" this.buffer = buffer;");
9899
out.println(" }");
99100
structs.values().forEach(s -> {
100101
out.printf(" class %s {\n", s.name);

src/test/java/bwapi/ClientDataBenchmark.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import org.openjdk.jmh.annotations.*;
44
import org.openjdk.jmh.infra.Blackhole;
55

6-
import java.nio.ByteBuffer;
76
import java.util.SplittableRandom;
87
import java.util.stream.Collectors;
98

@@ -19,7 +18,7 @@ public static class EmptyState {
1918

2019
@Setup(Level.Invocation)
2120
public void setup() {
22-
client = new Client(ByteBuffer.allocateDirect(ClientData.GameData.SIZE));
21+
client = new Client(new WrappedBuffer(ClientData.GameData.SIZE));
2322
game = new Game(client);
2423
strings = buildStrings();
2524
}
@@ -34,7 +33,7 @@ public static class FilledWithStrings {
3433

3534
@Setup(Level.Invocation)
3635
public void setup() {
37-
client = new Client(ByteBuffer.allocateDirect(ClientData.GameData.SIZE));
36+
client = new Client(new WrappedBuffer(ClientData.GameData.SIZE));
3837
data = client.gameData();
3938
game = new Game(client);
4039
String[] strings = buildStrings();

src/test/java/bwapi/GameBuilder.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import java.io.ByteArrayOutputStream;
44
import java.io.IOException;
5-
import java.nio.Buffer;
6-
import java.nio.ByteBuffer;
75
import java.nio.file.Files;
86
import java.nio.file.Paths;
97
import java.util.zip.InflaterOutputStream;
@@ -15,20 +13,20 @@ public static Game createGame() throws IOException {
1513
}
1614

1715
public static Game createGame(String mapName) throws IOException {
18-
final ByteBuffer buffer = binToBuffer("src/test/resources/" + mapName + "_frame0_buffer.bin");
16+
final WrappedBuffer buffer = binToBuffer("src/test/resources/" + mapName + "_frame0_buffer.bin");
1917
return createGame(new Client(buffer));
2018
}
2119

22-
public static ByteBuffer binToBuffer(String binLocation) throws IOException {
20+
public static WrappedBuffer binToBuffer(String binLocation) throws IOException {
2321
final byte[] compressedBytes = Files.readAllBytes(Paths.get(binLocation));
2422
final ByteArrayOutputStream out = new ByteArrayOutputStream();
2523
final InflaterOutputStream zin = new InflaterOutputStream(out);
2624
zin.write(compressedBytes);
2725
zin.flush();
2826
zin.close();
2927
final byte[] bytes = out.toByteArray();
30-
final ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length);
31-
buffer.put(bytes);
28+
final WrappedBuffer buffer = new WrappedBuffer(bytes.length);
29+
buffer.getBuffer().put(bytes);
3230
return buffer;
3331
}
3432

0 commit comments

Comments
 (0)