11package bwapi ;
22
3- import sun .misc .Unsafe ;
4-
53import java .util .ArrayList ;
64import java .util .concurrent .locks .Condition ;
75import java .util .concurrent .locks .Lock ;
119 * Circular buffer of game states.
1210 */
1311class FrameBuffer {
14- private static final int BUFFER_SIZE = ClientData .GameData .SIZE ;
15- private static final Unsafe unsafe = UnsafeTools .getUnsafe ();
16-
17- private WrappedBuffer liveData ;
1812 private PerformanceMetrics performanceMetrics ;
1913 private final BWClientConfiguration configuration ;
2014 private final int capacity ;
2115 private int stepGame = 0 ;
2216 private int stepBot = 0 ;
23- private final ArrayList <WrappedBuffer > dataBuffer = new ArrayList <>();
17+ private final ArrayList <WrappedBufferOffset > dataBuffer = new ArrayList <>();
2418
2519 private final Lock lockWrite = new ReentrantLock ();
2620 final Lock lockSize = new ReentrantLock ();
@@ -30,18 +24,18 @@ class FrameBuffer {
3024 this .capacity = configuration .getAsyncFrameBufferCapacity ();
3125 this .configuration = configuration ;
3226 while (dataBuffer .size () < capacity ) {
33- dataBuffer .add (new WrappedBuffer ( BUFFER_SIZE ));
27+ dataBuffer .add (new WrappedBufferOffset ( ));
3428 }
3529 }
3630
3731 /**
3832 * Resets for a new game
3933 */
4034 void initialize (WrappedBuffer liveData , PerformanceMetrics performanceMetrics ) {
41- this .liveData = liveData ;
4235 this .performanceMetrics = performanceMetrics ;
4336 stepGame = 0 ;
4437 stepBot = 0 ;
38+ dataBuffer .forEach (b -> b .setSourceBuffer (liveData ));
4539 }
4640
4741 /**
@@ -107,19 +101,10 @@ void enqueueFrame() {
107101 performanceMetrics .getIntentionallyBlocking ().stopTiming ();
108102 } finally { lockSize .unlock (); };
109103
110- // For the first frame of the game, populate all buffers completely
111- // This is to ensure all buffers have access to immutable data like regions/walkability/buildability
112- // Afterwards, we want to shorten this process by only copying important and mutable data
113- if (stepGame == 0 ) {
114- for (WrappedBuffer frameBuffer : dataBuffer ) {
115- copyBuffer (liveData , frameBuffer , true );
116- }
117- } else {
118- performanceMetrics .getCopyingToBuffer ().time (() -> {
119- WrappedBuffer dataTarget = dataBuffer .get (indexGame ());
120- copyBuffer (liveData , dataTarget , false );
121- });
122- }
104+ performanceMetrics .getCopyingToBuffer ().time (() -> {
105+ WrappedBufferOffset dataTarget = dataBuffer .get (indexGame ());
106+ dataTarget .initialize ();
107+ });
123108
124109 lockSize .lock ();
125110 try {
@@ -152,46 +137,4 @@ void dequeue() {
152137 conditionSize .signalAll ();
153138 } finally { lockSize .unlock (); }
154139 }
155-
156- /**
157- *
158- * @param source Address to copy from
159- * @param destination Address to copy to
160- * @param size Number of bytes to copy
161- */
162- private void copyBuffer (WrappedBuffer source , WrappedBuffer destination , long offset , int size ) {
163- long addressSource = source .getAddress () + offset ;
164- long addressDestination = destination .getAddress () + offset ;
165- unsafe .copyMemory (addressSource , addressDestination , size );
166- }
167-
168- void copyBuffer (WrappedBuffer source , WrappedBuffer destination , boolean copyEverything ) {
169- /*
170- The speed at which we copy data into the frame buffer is a major cost of JBWAPI's asynchronous operation.
171- Copy times observed in the wild for the complete buffer usually range from 2.6ms - 19ms
172- but are prone to large amounts of variance.
173-
174- The normal Java way to execute this copy is via ByteBuffer.put(), which has reasonably good performance characteristics.
175- */
176-
177- if (copyEverything ) {
178- copyBuffer (source , destination , 0 , FrameBuffer .BUFFER_SIZE );
179- } else {
180- // After the buffer has been filled the first time,
181- // we can omit copying blocks of data which are unused or which don't change after game start.
182- // These blocks account for *most* of the 33MB shared memory,
183- // so omitting them drastically reduces the copy duration
184- final int STATICTILES_START = 3447004 ; // getGroundHeight, isWalkable, isBuildable
185- final int STATICTILES_END = 4823260 ;
186- final int REGION_START = 5085404 ; // getMapTileRegionId, ..., getRegions
187- final int REGION_END = 10586480 ;
188- final int STRINGSSHAPES_START = 10962632 ; // getStringCount, ... getShapes
189- final int STRINGSHAPES_END = 32242636 ;
190- final int UNITFINDER_START = 32962644 ;
191- copyBuffer (source , destination , 0 , STATICTILES_START );
192- copyBuffer (source , destination , STATICTILES_END , REGION_START - STATICTILES_END );
193- copyBuffer (source , destination , REGION_END , STRINGSSHAPES_START - REGION_END );
194- copyBuffer (source , destination , STRINGSHAPES_END , UNITFINDER_START - STRINGSHAPES_END );
195- }
196- }
197140}
0 commit comments