@@ -43,6 +43,11 @@ 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 ;
50+
4651 private List <Unit > allUnits ;
4752 private final ClientData clientData ;
4853
@@ -146,6 +151,10 @@ private static boolean hasPower(final int x, final int y, final UnitType unitTyp
146151 */
147152 void init () {
148153 visibleUnits .clear ();
154+ connectedUnits .clear ();
155+ lastConnectedUnitsUpdate = -1 ;
156+ loadedUnits .clear ();
157+ lastLoadedUnitsUpdate = -1 ;
149158
150159 final int forceCount = gameData ().getForceCount ();
151160 forces = new Force [forceCount ];
@@ -310,6 +319,60 @@ void onFrame(final int frame) {
310319 getAllUnits ().forEach (u -> u .updatePosition (frame ));
311320 }
312321
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+
313376 /**
314377 * Retrieves the set of all teams/forces. Forces are commonly seen in @UMS
315378 * game types and some others such as @TvB and the team versions of game types.
0 commit comments