Skip to content

Commit a08357e

Browse files
author
Jasper Geurtz
committed
Only copy active units in FrameBuffer
1 parent e7fea36 commit a08357e

2 files changed

Lines changed: 87 additions & 3 deletions

File tree

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

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@
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+
1525
private static final Unsafe unsafe = UnsafeTools.getUnsafe();
1626

1727
private WrappedBuffer liveData;
@@ -20,6 +30,7 @@ class FrameBuffer {
2030
private final int capacity;
2131
private int stepGame = 0;
2232
private int stepBot = 0;
33+
private int maxUnitCount = 0;
2334
private final ArrayList<WrappedBuffer> dataBuffer = new ArrayList<>();
2435

2536
private final Lock lockWrite = new ReentrantLock();
@@ -42,6 +53,7 @@ void initialize(WrappedBuffer liveData, PerformanceMetrics performanceMetrics) {
4253
this.performanceMetrics = performanceMetrics;
4354
stepGame = 0;
4455
stepBot = 0;
56+
maxUnitCount = 0;
4557
}
4658

4759
/**
@@ -151,9 +163,46 @@ void dequeue() {
151163
} finally { lockSize.unlock(); }
152164
}
153165

166+
int getMaxUnitCount() {
167+
return maxUnitCount;
168+
}
169+
170+
private static int clamp(int value, int min, int max) {
171+
return Math.max(min, Math.min(max, value));
172+
}
173+
174+
private int updateMaxUnitCount(WrappedBuffer source) {
175+
int initialUnits = clamp(source.getInt(INITIAL_UNIT_COUNT_OFFSET), 0, MAX_UNITS);
176+
if (initialUnits > maxUnitCount) {
177+
maxUnitCount = initialUnits;
178+
}
179+
180+
int eventCount = clamp(source.getInt(EVENT_COUNT_OFFSET), 0, MAX_EVENTS);
181+
for (int i = 0; i < eventCount; i++) {
182+
int eventOffset = EVENTS_START + i * ClientData.Event.SIZE;
183+
if (source.getInt(eventOffset) == EventType.UnitDiscover.id) {
184+
int unitId = source.getInt(eventOffset + 4);
185+
if (unitId >= 0 && unitId < MAX_UNITS && unitId + 1 > maxUnitCount) {
186+
maxUnitCount = unitId + 1;
187+
}
188+
}
189+
}
190+
return maxUnitCount;
191+
}
192+
154193
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);
194+
long srcAddr = source.getAddress();
195+
long dstAddr = destination.getAddress();
196+
int activeUnits = updateMaxUnitCount(source);
197+
198+
// Slice 1a: header, forces, players, initialUnitCount, and active units [0 .. maxUnitCount)
199+
int slice1ActiveUnitsEnd = UNITS_START + activeUnits * ClientData.UnitData.SIZE;
200+
unsafe.copyMemory(srcAddr, dstAddr + PackedWrappedBuffer.DEST_SLICE1_OFFSET, slice1ActiveUnitsEnd);
201+
// Slice 1b: unitArray, bullets, nukeDots, frameCount, and other post-unit Slice 1 fields
202+
unsafe.copyMemory(srcAddr + UNITS_END, dstAddr + PackedWrappedBuffer.DEST_SLICE1_OFFSET + UNITS_END, PackedWrappedBuffer.STATICTILES_START - UNITS_END);
203+
// Slice 2: dynamic tile flags
204+
unsafe.copyMemory(srcAddr + PackedWrappedBuffer.STATICTILES_END, dstAddr + PackedWrappedBuffer.DEST_SLICE2_OFFSET, PackedWrappedBuffer.DYNAMIC_SLICE2_SIZE);
205+
// Slice 3: dynamic game state, events, and eventStrings
206+
unsafe.copyMemory(srcAddr + PackedWrappedBuffer.REGION_END, dstAddr + PackedWrappedBuffer.DEST_SLICE3_OFFSET, PackedWrappedBuffer.DYNAMIC_SLICE3_SIZE);
158207
}
159208
}

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,39 @@ public void asyncClientDataWorksWithFullUnpackedBuffer() {
213213
assertTrue(asyncData.gameData().isVisible(10, 20));
214214
assertTrue(asyncData.gameData().isInGame());
215215
}
216+
217+
@Test
218+
public void copyBufferTracksMaxUnitsAndOnlyCopiesActiveUnits() {
219+
WrappedBuffer mainBuffer = new WrappedBuffer(ClientData.GameData.SIZE);
220+
PackedWrappedBuffer packedBuffer = new PackedWrappedBuffer();
221+
222+
ClientData mainData = new ClientData();
223+
mainData.setBuffer(mainBuffer);
224+
225+
// Set initialUnitCount = 3 and populate unit #2 and unit #50 (beyond initialUnitCount)
226+
mainData.gameData().setInitialUnitCount(3);
227+
mainData.gameData().getUnits(2).setHitPoints(100);
228+
mainData.gameData().getUnits(50).setHitPoints(250);
229+
230+
FrameBuffer frameBuffer = new FrameBuffer(
231+
new BWClientConfiguration.Builder().withAsyncFrameBufferCapacity(1).build());
232+
frameBuffer.copyBuffer(mainBuffer, packedBuffer);
233+
234+
AsyncClientData asyncData = new AsyncClientData(mainBuffer);
235+
asyncData.setBuffer(packedBuffer);
236+
237+
assertEquals(3, frameBuffer.getMaxUnitCount());
238+
assertEquals(100, asyncData.gameData().getUnits(2).getHitPoints());
239+
// Unit #50 was beyond maxUnitCount, so it was skipped
240+
assertEquals(0, asyncData.gameData().getUnits(50).getHitPoints());
241+
242+
// Now fire UnitDiscover for unit #50 on the next frame
243+
mainData.gameData().setEventCount(1);
244+
mainData.gameData().getEvents(0).setType(EventType.UnitDiscover);
245+
mainData.gameData().getEvents(0).setV1(50);
246+
frameBuffer.copyBuffer(mainBuffer, packedBuffer);
247+
248+
assertEquals(51, frameBuffer.getMaxUnitCount());
249+
assertEquals(250, asyncData.gameData().getUnits(50).getHitPoints());
250+
}
216251
}

0 commit comments

Comments
 (0)