Skip to content

Commit a157404

Browse files
author
Jasper Geurtz
committed
Reduce Async FrameBuffer memory usage from ~33MB to ~4.8MB per slot (#90)
- Add packed buffer support to WrappedBuffer - In FrameBuffer, pack only dynamic game data (4 slices totaling ~4.8MB) instead of copying the full 33MB buffer, and remove frame-0 loop that copied 33MB to all buffers - Auto-generate AsyncClientData via DumpToClient: - Route dynamic game state reads/writes through offset deltas - Route static map/region data reads to the live shared memory buffer - Centralize slice boundaries and buffer constants in AsyncClientData as single source of truth for FrameBuffer - Keep synchronous mode fully backward-compatible using ClientData directly - Wire AsyncClientData in BotWrapperAsync - Add AsyncClientDataTest to verify memory size reduction and correct reading of static vs dynamic data
1 parent 484be45 commit a157404

9 files changed

Lines changed: 872 additions & 243 deletions
Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
package bwapi;
2+
3+
/**
4+
* Asynchronous client data that routes static information to the main/static shared buffer
5+
* and dynamic information to the packed dynamic buffer.
6+
* Automatically generated by DumpToClient.
7+
*/
8+
class AsyncClientData extends ClientData {
9+
static final int STATICTILES_START = 3447004;
10+
static final int STATICTILES_END = 4823260;
11+
static final int REGION_START = 5085404;
12+
static final int REGION_END = 10586480;
13+
static final int STRINGSSHAPES_START = 10962632;
14+
static final int STRINGSHAPES_END = 32242636;
15+
static final int UNITFINDER_START = 32962644;
16+
17+
static final int DYNAMIC_SLICE1_SIZE = STATICTILES_START;
18+
static final int DYNAMIC_SLICE2_SIZE = REGION_START - STATICTILES_END;
19+
static final int DYNAMIC_SLICE3_SIZE = STRINGSSHAPES_START - REGION_END;
20+
static final int DYNAMIC_SLICE4_SIZE = UNITFINDER_START - STRINGSHAPES_END;
21+
22+
static final int DEST_SLICE1_OFFSET = 0;
23+
static final int DEST_SLICE2_OFFSET = DYNAMIC_SLICE1_SIZE;
24+
static final int DEST_SLICE3_OFFSET = DEST_SLICE2_OFFSET + DYNAMIC_SLICE2_SIZE;
25+
static final int DEST_SLICE4_OFFSET = DEST_SLICE3_OFFSET + DYNAMIC_SLICE3_SIZE;
26+
27+
static final int BUFFER_SIZE = DEST_SLICE4_OFFSET + DYNAMIC_SLICE4_SIZE;
28+
29+
static final int DELTA_RANGE2 = STATICTILES_END - STATICTILES_START;
30+
static final int DELTA_RANGE3 = DELTA_RANGE2 + (REGION_END - REGION_START);
31+
static final int DELTA_RANGE4 = DELTA_RANGE3 + (STRINGSHAPES_END - STRINGSSHAPES_START);
32+
33+
private WrappedBuffer staticBuffer;
34+
35+
AsyncClientData() {
36+
super();
37+
}
38+
39+
AsyncClientData(WrappedBuffer staticBuffer) {
40+
super();
41+
this.staticBuffer = staticBuffer;
42+
}
43+
44+
void setStaticBuffer(WrappedBuffer staticBuffer) {
45+
this.staticBuffer = staticBuffer;
46+
}
47+
48+
@Override
49+
WrappedBuffer getStaticBuffer() {
50+
return staticBuffer != null ? staticBuffer : buffer;
51+
}
52+
53+
@Override
54+
GameData createGameData(int offset) {
55+
return new AsyncGameData(offset);
56+
}
57+
58+
class AsyncGameData extends GameData {
59+
AsyncGameData(int myOffset) {
60+
super(myOffset);
61+
}
62+
63+
private int deltaRange2() {
64+
return buffer != null && buffer.isPacked() ? DELTA_RANGE2 : 0;
65+
}
66+
67+
private int deltaRange3() {
68+
return buffer != null && buffer.isPacked() ? DELTA_RANGE3 : 0;
69+
}
70+
71+
private int deltaRange4() {
72+
return buffer != null && buffer.isPacked() ? DELTA_RANGE4 : 0;
73+
}
74+
75+
@Override
76+
int getGroundHeight(int i, int j) {
77+
int offset = myOffset + 3447004 + 4 * 1 * j + 4 * 256 * i;
78+
return getStaticBuffer().getInt(offset);
79+
}
80+
@Override
81+
void setGetGroundHeight(int i, int j, int value) {
82+
getStaticBuffer().putInt(myOffset + 3447004 + 4 * 1 * j + 4 * 256 * i, value);
83+
}
84+
@Override
85+
boolean isWalkable(int i, int j) {
86+
int offset = myOffset + 3709148 + 1 * 1 * j + 1 * 1024 * i;
87+
return getStaticBuffer().getByte(offset) != 0;
88+
}
89+
@Override
90+
void setIsWalkable(int i, int j, boolean value) {
91+
getStaticBuffer().putByte(myOffset + 3709148 + 1 * 1 * j + 1 * 1024 * i, (byte) (value ? 1 : 0));
92+
}
93+
@Override
94+
boolean isBuildable(int i, int j) {
95+
int offset = myOffset + 4757724 + 1 * 1 * j + 1 * 256 * i;
96+
return getStaticBuffer().getByte(offset) != 0;
97+
}
98+
@Override
99+
void setIsBuildable(int i, int j, boolean value) {
100+
getStaticBuffer().putByte(myOffset + 4757724 + 1 * 1 * j + 1 * 256 * i, (byte) (value ? 1 : 0));
101+
}
102+
@Override
103+
boolean isVisible(int i, int j) {
104+
int offset = myOffset + 4823260 - deltaRange2() + 1 * 1 * j + 1 * 256 * i;
105+
return buffer.getByte(offset) != 0;
106+
}
107+
@Override
108+
void setIsVisible(int i, int j, boolean value) {
109+
buffer.putByte(myOffset + 4823260 - deltaRange2() + 1 * 1 * j + 1 * 256 * i, (byte) (value ? 1 : 0));
110+
}
111+
@Override
112+
boolean isExplored(int i, int j) {
113+
int offset = myOffset + 4888796 - deltaRange2() + 1 * 1 * j + 1 * 256 * i;
114+
return buffer.getByte(offset) != 0;
115+
}
116+
@Override
117+
void setIsExplored(int i, int j, boolean value) {
118+
buffer.putByte(myOffset + 4888796 - deltaRange2() + 1 * 1 * j + 1 * 256 * i, (byte) (value ? 1 : 0));
119+
}
120+
@Override
121+
boolean getHasCreep(int i, int j) {
122+
int offset = myOffset + 4954332 - deltaRange2() + 1 * 1 * j + 1 * 256 * i;
123+
return buffer.getByte(offset) != 0;
124+
}
125+
@Override
126+
void setHasCreep(int i, int j, boolean value) {
127+
buffer.putByte(myOffset + 4954332 - deltaRange2() + 1 * 1 * j + 1 * 256 * i, (byte) (value ? 1 : 0));
128+
}
129+
@Override
130+
boolean isOccupied(int i, int j) {
131+
int offset = myOffset + 5019868 - deltaRange2() + 1 * 1 * j + 1 * 256 * i;
132+
return buffer.getByte(offset) != 0;
133+
}
134+
@Override
135+
void setIsOccupied(int i, int j, boolean value) {
136+
buffer.putByte(myOffset + 5019868 - deltaRange2() + 1 * 1 * j + 1 * 256 * i, (byte) (value ? 1 : 0));
137+
}
138+
@Override
139+
short getMapTileRegionId(int i, int j) {
140+
int offset = myOffset + 5085404 + 2 * 1 * j + 2 * 256 * i;
141+
return getStaticBuffer().getShort(offset);
142+
}
143+
@Override
144+
void setMapTileRegionId(int i, int j, short value) {
145+
getStaticBuffer().putShort(myOffset + 5085404 + 2 * 1 * j + 2 * 256 * i, value);
146+
}
147+
@Override
148+
short getMapSplitTilesMiniTileMask(int i) {
149+
int offset = myOffset + 5216476 + 2 * 1 * i;
150+
return getStaticBuffer().getShort(offset);
151+
}
152+
@Override
153+
void setMapSplitTilesMiniTileMask(int i, short value) {
154+
getStaticBuffer().putShort(myOffset + 5216476 + 2 * 1 * i, value);
155+
}
156+
@Override
157+
short getMapSplitTilesRegion1(int i) {
158+
int offset = myOffset + 5226476 + 2 * 1 * i;
159+
return getStaticBuffer().getShort(offset);
160+
}
161+
@Override
162+
void setMapSplitTilesRegion1(int i, short value) {
163+
getStaticBuffer().putShort(myOffset + 5226476 + 2 * 1 * i, value);
164+
}
165+
@Override
166+
short getMapSplitTilesRegion2(int i) {
167+
int offset = myOffset + 5236476 + 2 * 1 * i;
168+
return getStaticBuffer().getShort(offset);
169+
}
170+
@Override
171+
void setMapSplitTilesRegion2(int i, short value) {
172+
getStaticBuffer().putShort(myOffset + 5236476 + 2 * 1 * i, value);
173+
}
174+
@Override
175+
int getRegionCount() {
176+
int offset = myOffset + 5246476;
177+
return getStaticBuffer().getInt(offset);
178+
}
179+
@Override
180+
void setRegionCount(int value) {
181+
getStaticBuffer().putInt(myOffset + 5246476, value);
182+
}
183+
@Override
184+
RegionData getRegions(int i) {
185+
int offset = myOffset + 5246480 + 1068 * 1 * i;
186+
return new RegionData(offset);
187+
}
188+
@Override
189+
int getStartLocationCount() {
190+
int offset = myOffset + 10586480 - deltaRange3();
191+
return buffer.getInt(offset);
192+
}
193+
@Override
194+
void setStartLocationCount(int value) {
195+
buffer.putInt(myOffset + 10586480 - deltaRange3(), value);
196+
}
197+
@Override
198+
Position getStartLocations(int i) {
199+
int offset = myOffset + 10586484 - deltaRange3() + 8 * 1 * i;
200+
return new Position(offset);
201+
}
202+
@Override
203+
boolean isInGame() {
204+
int offset = myOffset + 10586548 - deltaRange3();
205+
return buffer.getByte(offset) != 0;
206+
}
207+
@Override
208+
void setIsInGame(boolean value) {
209+
buffer.putByte(myOffset + 10586548 - deltaRange3(), (byte) (value ? 1 : 0));
210+
}
211+
@Override
212+
boolean isMultiplayer() {
213+
int offset = myOffset + 10586549 - deltaRange3();
214+
return buffer.getByte(offset) != 0;
215+
}
216+
@Override
217+
void setIsMultiplayer(boolean value) {
218+
buffer.putByte(myOffset + 10586549 - deltaRange3(), (byte) (value ? 1 : 0));
219+
}
220+
@Override
221+
boolean isBattleNet() {
222+
int offset = myOffset + 10586550 - deltaRange3();
223+
return buffer.getByte(offset) != 0;
224+
}
225+
@Override
226+
void setIsBattleNet(boolean value) {
227+
buffer.putByte(myOffset + 10586550 - deltaRange3(), (byte) (value ? 1 : 0));
228+
}
229+
@Override
230+
boolean isPaused() {
231+
int offset = myOffset + 10586551 - deltaRange3();
232+
return buffer.getByte(offset) != 0;
233+
}
234+
@Override
235+
void setIsPaused(boolean value) {
236+
buffer.putByte(myOffset + 10586551 - deltaRange3(), (byte) (value ? 1 : 0));
237+
}
238+
@Override
239+
boolean isReplay() {
240+
int offset = myOffset + 10586552 - deltaRange3();
241+
return buffer.getByte(offset) != 0;
242+
}
243+
@Override
244+
void setIsReplay(boolean value) {
245+
buffer.putByte(myOffset + 10586552 - deltaRange3(), (byte) (value ? 1 : 0));
246+
}
247+
@Override
248+
int getSelectedUnitCount() {
249+
int offset = myOffset + 10586556 - deltaRange3();
250+
return buffer.getInt(offset);
251+
}
252+
@Override
253+
void setSelectedUnitCount(int value) {
254+
buffer.putInt(myOffset + 10586556 - deltaRange3(), value);
255+
}
256+
@Override
257+
int getSelectedUnits(int i) {
258+
int offset = myOffset + 10586560 - deltaRange3() + 4 * 1 * i;
259+
return buffer.getInt(offset);
260+
}
261+
@Override
262+
void setSelectedUnits(int i, int value) {
263+
buffer.putInt(myOffset + 10586560 - deltaRange3() + 4 * 1 * i, value);
264+
}
265+
@Override
266+
int getSelf() {
267+
int offset = myOffset + 10586608 - deltaRange3();
268+
return buffer.getInt(offset);
269+
}
270+
@Override
271+
void setSelf(int value) {
272+
buffer.putInt(myOffset + 10586608 - deltaRange3(), value);
273+
}
274+
@Override
275+
int getEnemy() {
276+
int offset = myOffset + 10586612 - deltaRange3();
277+
return buffer.getInt(offset);
278+
}
279+
@Override
280+
void setEnemy(int value) {
281+
buffer.putInt(myOffset + 10586612 - deltaRange3(), value);
282+
}
283+
@Override
284+
int getNeutral() {
285+
int offset = myOffset + 10586616 - deltaRange3();
286+
return buffer.getInt(offset);
287+
}
288+
@Override
289+
void setNeutral(int value) {
290+
buffer.putInt(myOffset + 10586616 - deltaRange3(), value);
291+
}
292+
@Override
293+
int getEventCount() {
294+
int offset = myOffset + 10586620 - deltaRange3();
295+
return buffer.getInt(offset);
296+
}
297+
@Override
298+
void setEventCount(int value) {
299+
buffer.putInt(myOffset + 10586620 - deltaRange3(), value);
300+
}
301+
@Override
302+
Event getEvents(int i) {
303+
int offset = myOffset + 10586624 - deltaRange3() + 12 * 1 * i;
304+
return new Event(offset);
305+
}
306+
@Override
307+
int getEventStringCount() {
308+
int offset = myOffset + 10706624 - deltaRange3();
309+
return buffer.getInt(offset);
310+
}
311+
@Override
312+
void setEventStringCount(int value) {
313+
buffer.putInt(myOffset + 10706624 - deltaRange3(), value);
314+
}
315+
@Override
316+
String getEventStrings(int i) {
317+
int offset = myOffset + 10706628 - deltaRange3() + 1 * 256 * i;
318+
return buffer.getString(offset, 256);
319+
}
320+
@Override
321+
void setEventStrings(int i, String value) {
322+
buffer.putString(myOffset + 10706628 - deltaRange3() + 1 * 256 * i, 256, value);
323+
}
324+
@Override
325+
int getStringCount() {
326+
int offset = myOffset + 10962628 - deltaRange3();
327+
return buffer.getInt(offset);
328+
}
329+
@Override
330+
void setStringCount(int value) {
331+
buffer.putInt(myOffset + 10962628 - deltaRange3(), value);
332+
}
333+
@Override
334+
int getCommandCount() {
335+
int offset = myOffset + 32242636 - deltaRange4();
336+
return buffer.getInt(offset);
337+
}
338+
@Override
339+
void setCommandCount(int value) {
340+
buffer.putInt(myOffset + 32242636 - deltaRange4(), value);
341+
}
342+
@Override
343+
Command getCommands(int i) {
344+
int offset = myOffset + 32242640 - deltaRange4() + 12 * 1 * i;
345+
return new Command(offset);
346+
}
347+
@Override
348+
int getUnitCommandCount() {
349+
int offset = myOffset + 32482640 - deltaRange4();
350+
return buffer.getInt(offset);
351+
}
352+
@Override
353+
void setUnitCommandCount(int value) {
354+
buffer.putInt(myOffset + 32482640 - deltaRange4(), value);
355+
}
356+
@Override
357+
UnitCommand getUnitCommands(int i) {
358+
int offset = myOffset + 32482644 - deltaRange4() + 24 * 1 * i;
359+
return new UnitCommand(offset);
360+
}
361+
}
362+
}

‎src/main/java/bwapi/BotWrapperAsync.java‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ class BotWrapperAsync extends BotWrapper {
2929
void startNewGame(WrappedBuffer liveData, PerformanceMetrics performanceMetrics) {
3030
frameBuffer.initialize(liveData, performanceMetrics);
3131

32-
super.startNewGame(liveData, performanceMetrics);
32+
this.performanceMetrics = performanceMetrics;
33+
AsyncClientData asyncClientData = new AsyncClientData(liveData);
34+
botGame = new Game(asyncClientData);
35+
botGame.setConfiguration(configuration);
36+
botGame.botClientData().setBuffer(liveData);
37+
gameOver = false;
3338

3439
liveClientData.setBuffer(liveData);
3540
this.liveData = liveData;

0 commit comments

Comments
 (0)