Skip to content

Commit b1d185b

Browse files
author
Jasper Geurtz
committed
Only copy active units, events, and eventStrings in FrameBuffer
1 parent e7fea36 commit b1d185b

2 files changed

Lines changed: 107 additions & 3 deletions

File tree

‎src/main/java/bwapi/FrameBuffer.java‎

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@
1212
*/
1313
class FrameBuffer {
1414
static final int BUFFER_SIZE = PackedWrappedBuffer.BUFFER_SIZE;
15+
16+
static final int INITIAL_UNIT_COUNT_OFFSET = 69648;
17+
static final int UNITS_START = 69656;
18+
static final int MAX_UNITS = 10000;
19+
static final int UNITS_END = UNITS_START + MAX_UNITS * ClientData.UnitData.SIZE;
20+
21+
static final int EVENT_COUNT_OFFSET = 10586620;
22+
static final int EVENTS_START = 10586624;
23+
static final int MAX_EVENTS = 10000;
24+
static final int EVENTS_HEADER_SIZE = EVENTS_START - PackedWrappedBuffer.REGION_END;
25+
26+
static final int EVENT_STRING_COUNT_OFFSET = 10706624;
27+
static final int EVENT_STRING_SIZE = 256;
28+
static final int MAX_EVENT_STRINGS = 1000;
29+
1530
private static final Unsafe unsafe = UnsafeTools.getUnsafe();
1631

1732
private WrappedBuffer liveData;
@@ -20,6 +35,7 @@ class FrameBuffer {
2035
private final int capacity;
2136
private int stepGame = 0;
2237
private int stepBot = 0;
38+
private int maxUnitCount = 0;
2339
private final ArrayList<WrappedBuffer> dataBuffer = new ArrayList<>();
2440

2541
private final Lock lockWrite = new ReentrantLock();
@@ -42,6 +58,7 @@ void initialize(WrappedBuffer liveData, PerformanceMetrics performanceMetrics) {
4258
this.performanceMetrics = performanceMetrics;
4359
stepGame = 0;
4460
stepBot = 0;
61+
maxUnitCount = 0;
4562
}
4663

4764
/**
@@ -151,9 +168,53 @@ void dequeue() {
151168
} finally { lockSize.unlock(); }
152169
}
153170

171+
int getMaxUnitCount() {
172+
return maxUnitCount;
173+
}
174+
175+
private static int clamp(int value, int min, int max) {
176+
return Math.max(min, Math.min(max, value));
177+
}
178+
179+
private int updateMaxUnitCount(WrappedBuffer source, int eventCount) {
180+
int initialUnits = clamp(source.getInt(INITIAL_UNIT_COUNT_OFFSET), 0, MAX_UNITS);
181+
if (initialUnits > maxUnitCount) {
182+
maxUnitCount = initialUnits;
183+
}
184+
185+
for (int i = 0; i < eventCount; i++) {
186+
int eventOffset = EVENTS_START + i * ClientData.Event.SIZE;
187+
if (source.getInt(eventOffset) == EventType.UnitDiscover.id) {
188+
int unitId = source.getInt(eventOffset + 4);
189+
if (unitId >= 0 && unitId < MAX_UNITS && unitId + 1 > maxUnitCount) {
190+
maxUnitCount = unitId + 1;
191+
}
192+
}
193+
}
194+
return maxUnitCount;
195+
}
196+
197+
private static void copySlice(long srcAddr, long dstAddr, int srcOffset, int delta, int length) {
198+
unsafe.copyMemory(srcAddr + srcOffset, dstAddr + srcOffset - delta, length);
199+
}
200+
154201
void copyBuffer(WrappedBuffer source, WrappedBuffer destination) {
155-
unsafe.copyMemory(source.getAddress() + 0, destination.getAddress() + PackedWrappedBuffer.DEST_SLICE1_OFFSET, PackedWrappedBuffer.DYNAMIC_SLICE1_SIZE);
156-
unsafe.copyMemory(source.getAddress() + PackedWrappedBuffer.STATICTILES_END, destination.getAddress() + PackedWrappedBuffer.DEST_SLICE2_OFFSET, PackedWrappedBuffer.DYNAMIC_SLICE2_SIZE);
157-
unsafe.copyMemory(source.getAddress() + PackedWrappedBuffer.REGION_END, destination.getAddress() + PackedWrappedBuffer.DEST_SLICE3_OFFSET, PackedWrappedBuffer.DYNAMIC_SLICE3_SIZE);
202+
long srcAddr = source.getAddress();
203+
long dstAddr = destination.getAddress();
204+
205+
int eventCount = clamp(source.getInt(EVENT_COUNT_OFFSET), 0, MAX_EVENTS);
206+
int eventStringCount = clamp(source.getInt(EVENT_STRING_COUNT_OFFSET), 0, MAX_EVENT_STRINGS);
207+
int activeUnits = updateMaxUnitCount(source, eventCount);
208+
209+
// Slice 1a (dynamic size): header, forces, players, initialUnitCount, and active units [0 .. activeUnits)
210+
copySlice(srcAddr, dstAddr, 0, 0, UNITS_START + activeUnits * ClientData.UnitData.SIZE);
211+
// Slice 1b (static size): unitArray, bullets, nukeDots, frameCount, and other post-unit Slice 1 fields
212+
copySlice(srcAddr, dstAddr, UNITS_END, 0, PackedWrappedBuffer.STATICTILES_START - UNITS_END);
213+
// Slice 2 (static size): tile visibility, exploration, creep, and occupation flags
214+
copySlice(srcAddr, dstAddr, PackedWrappedBuffer.STATICTILES_END, PackedWrappedBuffer.DELTA_RANGE2, PackedWrappedBuffer.DYNAMIC_SLICE2_SIZE);
215+
// Slice 3a (dynamic size): startLocations, game state flags, selectedUnits, self/enemy/neutral, eventCount, and active events [0 .. eventCount)
216+
copySlice(srcAddr, dstAddr, PackedWrappedBuffer.REGION_END, PackedWrappedBuffer.DELTA_RANGE3, EVENTS_HEADER_SIZE + eventCount * ClientData.Event.SIZE);
217+
// Slice 3b (dynamic size): eventStringCount and active eventStrings [0 .. eventStringCount)
218+
copySlice(srcAddr, dstAddr, EVENT_STRING_COUNT_OFFSET, PackedWrappedBuffer.DELTA_RANGE3, 4 + eventStringCount * EVENT_STRING_SIZE);
158219
}
159220
}

‎src/test/java/bwapi/AsyncClientDataTest.java‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public void retainedViewsSurviveLiveAndPackedHandoffs() {
1212
PackedWrappedBuffer packed = new PackedWrappedBuffer(ClientData.GameData.SIZE);
1313
ClientData source = new ClientData();
1414
source.setBuffer(live);
15+
source.gameData().setEventCount(1);
1516
source.gameData().getEvents(0).setType(EventType.MatchFrame);
1617
source.gameData().getStartLocations(0).setX(123);
1718
new FrameBuffer(new BWClientConfiguration.Builder().withAsyncFrameBufferCapacity(1).build())
@@ -213,4 +214,46 @@ public void asyncClientDataWorksWithFullUnpackedBuffer() {
213214
assertTrue(asyncData.gameData().isVisible(10, 20));
214215
assertTrue(asyncData.gameData().isInGame());
215216
}
217+
218+
@Test
219+
public void copyBufferTracksMaxUnitsAndOnlyCopiesActiveUnitsAndEvents() {
220+
WrappedBuffer mainBuffer = new WrappedBuffer(ClientData.GameData.SIZE);
221+
PackedWrappedBuffer packedBuffer = new PackedWrappedBuffer();
222+
223+
ClientData mainData = new ClientData();
224+
mainData.setBuffer(mainBuffer);
225+
226+
// Set initialUnitCount = 3 and populate unit #2 and unit #50 (beyond initialUnitCount)
227+
mainData.gameData().setInitialUnitCount(3);
228+
mainData.gameData().getUnits(2).setHitPoints(100);
229+
mainData.gameData().getUnits(50).setHitPoints(250);
230+
231+
// Populate event #0 (active) and event #5 (beyond eventCount = 1)
232+
mainData.gameData().setEventCount(1);
233+
mainData.gameData().getEvents(0).setType(EventType.MatchFrame);
234+
mainData.gameData().getEvents(5).setType(EventType.MatchEnd);
235+
236+
FrameBuffer frameBuffer = new FrameBuffer(
237+
new BWClientConfiguration.Builder().withAsyncFrameBufferCapacity(1).build());
238+
frameBuffer.copyBuffer(mainBuffer, packedBuffer);
239+
240+
AsyncClientData asyncData = new AsyncClientData(mainBuffer);
241+
asyncData.setBuffer(packedBuffer);
242+
243+
assertEquals(3, frameBuffer.getMaxUnitCount());
244+
assertEquals(100, asyncData.gameData().getUnits(2).getHitPoints());
245+
// Unit #50 and Event #5 were beyond active counts, so they were skipped
246+
assertEquals(0, asyncData.gameData().getUnits(50).getHitPoints());
247+
assertEquals(EventType.MatchFrame, asyncData.gameData().getEvents(0).getType());
248+
assertEquals(EventType.MatchStart, asyncData.gameData().getEvents(5).getType());
249+
250+
// Now fire UnitDiscover for unit #50 on the next frame
251+
mainData.gameData().setEventCount(1);
252+
mainData.gameData().getEvents(0).setType(EventType.UnitDiscover);
253+
mainData.gameData().getEvents(0).setV1(50);
254+
frameBuffer.copyBuffer(mainBuffer, packedBuffer);
255+
256+
assertEquals(51, frameBuffer.getMaxUnitCount());
257+
assertEquals(250, asyncData.gameData().getUnits(50).getHitPoints());
258+
}
216259
}

0 commit comments

Comments
 (0)