Skip to content

Commit d151857

Browse files
authored
Merge pull request #78 from JavaBWAPI/rework-connectedunits-cache
Give each unittype their own cache
2 parents 8192ea6 + 8e598f2 commit d151857

File tree

3 files changed

+58
-65
lines changed

3 files changed

+58
-65
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package bwapi;
2+
3+
import java.util.*;
4+
import java.util.function.Function;
5+
6+
class ConnectedUnitCache {
7+
private int lastUpdate = -1;
8+
private final Map<Unit, List<Unit>> connectedUnits = new HashMap<>();
9+
private final Function<Unit, Unit> condition;
10+
private final Game game;
11+
12+
ConnectedUnitCache(final Game game, final Function<Unit, Unit> condition) {
13+
this.game = game;
14+
this.condition = condition;
15+
}
16+
17+
/**
18+
* Lazily update connectedUnits. Only users of the calls pay for it, and only
19+
* pay once per frame.
20+
* Avoids previous O(n^2) implementation which would be costly for
21+
* lategame carrier fights
22+
*/
23+
List<Unit> getConnected(final Unit unit) {
24+
final int frame = game.getFrameCount();
25+
if (lastUpdate < frame) {
26+
connectedUnits.values().forEach(List::clear);
27+
for (final Unit u : game.getAllUnits()) {
28+
final Unit owner = condition.apply(u);
29+
if (owner != null) {
30+
if (!connectedUnits.containsKey(owner)) {
31+
connectedUnits.put(owner, new ArrayList<>());
32+
}
33+
connectedUnits.get(owner).add(u);
34+
}
35+
}
36+
lastUpdate = frame;
37+
}
38+
if (!connectedUnits.containsKey(unit)) {
39+
return Collections.emptyList();
40+
}
41+
return Collections.unmodifiableList(connectedUnits.get(unit));
42+
}
43+
void reset() {
44+
lastUpdate = -1;
45+
connectedUnits.clear();
46+
}
47+
}

src/main/java/bwapi/Game.java

Lines changed: 8 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ public final class Game {
4343
private static final int REGION_DATA_SIZE = 5000;
4444

4545
private final Set<Integer> visibleUnits = new HashSet<>();
46-
private final Map<Unit, List<Unit>> connectedUnits = new HashMap<>();
47-
private int lastConnectedUnitsUpdate = -1;
48-
private final Map<Unit, List<Unit>> loadedUnits = new HashMap<>();
49-
private int lastLoadedUnitsUpdate = -1;
5046

5147
private List<Unit> allUnits;
5248
private final ClientData clientData;
@@ -103,6 +99,10 @@ public final class Game {
10399
private BWClientConfiguration configuration = new BWClientConfiguration();
104100
private boolean latcom = true;
105101

102+
final ConnectedUnitCache loadedUnitsCache = new ConnectedUnitCache(this, Unit::getTransport);
103+
final ConnectedUnitCache interceptorsCache = new ConnectedUnitCache(this, Unit::getCarrier);
104+
final ConnectedUnitCache larvaCache = new ConnectedUnitCache(this, Unit::getHatchery);
105+
106106
final SideEffectQueue sideEffects = new SideEffectQueue();
107107

108108
Game() {
@@ -151,10 +151,10 @@ private static boolean hasPower(final int x, final int y, final UnitType unitTyp
151151
*/
152152
void init() {
153153
visibleUnits.clear();
154-
connectedUnits.clear();
155-
lastConnectedUnitsUpdate = -1;
156-
loadedUnits.clear();
157-
lastLoadedUnitsUpdate = -1;
154+
155+
loadedUnitsCache.reset();
156+
interceptorsCache.reset();
157+
larvaCache.reset();
158158

159159
final int forceCount = gameData().getForceCount();
160160
forces = new Force[forceCount];
@@ -319,60 +319,6 @@ void onFrame(final int frame) {
319319
getAllUnits().forEach(u -> u.updatePosition(frame));
320320
}
321321

322-
/**
323-
* Lazily update connectedUnits. Only users of the calls pay for it, and only
324-
* pay once per frame.
325-
* Avoids previous O(n^2) implementation which would be costly for
326-
* lategame carrier fights
327-
*/
328-
List<Unit> getConnected(final Unit unit) {
329-
final int frame = getFrameCount();
330-
if (lastConnectedUnitsUpdate < frame) {
331-
connectedUnits.values().forEach(List::clear);
332-
for (final Unit u : getAllUnits()) {
333-
Unit owner = u.getCarrier();
334-
if (owner == null) {
335-
owner = u.getHatchery();
336-
}
337-
if (owner != null) {
338-
if (!connectedUnits.containsKey(owner)) {
339-
connectedUnits.put(owner, new ArrayList<>());
340-
}
341-
connectedUnits.get(owner).add(u);
342-
}
343-
}
344-
lastConnectedUnitsUpdate = frame;
345-
}
346-
if (!connectedUnits.containsKey(unit)) {
347-
return Collections.emptyList();
348-
}
349-
return Collections.unmodifiableList(connectedUnits.get(unit));
350-
}
351-
352-
/**
353-
* @see #getConnected
354-
*/
355-
List<Unit> getLoadedUnits(final Unit unit) {
356-
final int frame = getFrameCount();
357-
if (lastLoadedUnitsUpdate < frame) {
358-
loadedUnits.values().forEach(List::clear);
359-
for (final Unit u : getAllUnits()) {
360-
final Unit owner = u.getTransport();
361-
if (owner != null) {
362-
if (!loadedUnits.containsKey(owner)) {
363-
loadedUnits.put(owner, new ArrayList<>());
364-
}
365-
loadedUnits.get(owner).add(u);
366-
}
367-
}
368-
lastLoadedUnitsUpdate = frame;
369-
}
370-
if (!loadedUnits.containsKey(unit)) {
371-
return Collections.emptyList();
372-
}
373-
return Collections.unmodifiableList(loadedUnits.get(unit));
374-
}
375-
376322
/**
377323
* Retrieves the set of all teams/forces. Forces are commonly seen in @UMS
378324
* game types and some others such as @TvB and the team versions of game types.

src/main/java/bwapi/Unit.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,7 +1172,7 @@ public List<Unit> getLoadedUnits() {
11721172
if (getType().spaceProvided() < 1) {
11731173
return Collections.emptyList();
11741174
}
1175-
return game.getLoadedUnits(this);
1175+
return game.loadedUnitsCache.getConnected(this);
11761176
}
11771177

11781178
/**
@@ -1212,7 +1212,7 @@ public List<Unit> getInterceptors() {
12121212
if (getType() != Protoss_Carrier && getType() != Hero_Gantrithor) {
12131213
return Collections.emptyList();
12141214
}
1215-
return game.getConnected(this);
1215+
return game.interceptorsCache.getConnected(this);
12161216
}
12171217

12181218
/**
@@ -1240,7 +1240,7 @@ public List<Unit> getLarva() {
12401240
if (!getType().producesLarva()) {
12411241
return Collections.emptyList();
12421242
}
1243-
return game.getConnected(this);
1243+
return game.larvaCache.getConnected(this);
12441244
}
12451245

12461246
public List<Unit> getUnitsInRadius(final int radius) {

0 commit comments

Comments
 (0)