@@ -107,10 +107,19 @@ void enqueueFrame() {
107107 performanceMetrics .intentionallyBlocking .stopTiming ();
108108 } finally { lockSize .unlock (); };
109109
110- performanceMetrics .copyingToBuffer .time (() -> {
111- ByteBuffer dataTarget = dataBuffer .get (indexGame ());
112- copyBuffer (liveData , dataTarget );
113- });
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 (ByteBuffer frameBuffer : dataBuffer ) {
115+ copyBuffer (liveData , frameBuffer , true );
116+ }
117+ } else {
118+ performanceMetrics .copyingToBuffer .time (() -> {
119+ ByteBuffer dataTarget = dataBuffer .get (indexGame ());
120+ copyBuffer (liveData , dataTarget , false );
121+ });
122+ }
114123
115124 lockSize .lock ();
116125 try {
@@ -144,31 +153,63 @@ void dequeue() {
144153 } finally { lockSize .unlock (); }
145154 }
146155
147- void copyBuffer (ByteBuffer source , ByteBuffer destination ) {
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+ * @return True if the copy succeeded
162+ */
163+ private boolean tryMemcpyBuffer (ByteBuffer source , ByteBuffer destination , long offset , int size ) {
164+ long addressSource = ((DirectBuffer ) source ).address () + offset ;
165+ long addressDestination = ((DirectBuffer ) destination ).address () + offset ;
166+ try {
167+ if (Platform .isWindows ()) {
168+ if (Platform .is64Bit ()) {
169+ MSVCRT .INSTANCE .memcpy (addressDestination , addressSource , size );
170+ return true ;
171+ } else {
172+ MSVCRT .INSTANCE .memcpy ((int ) addressDestination , (int ) addressSource , size );
173+ return true ;
174+ }
175+ }
176+ }
177+ catch (Exception ignored ) {}
178+ return false ;
179+ }
180+
181+ void copyBuffer (ByteBuffer source , ByteBuffer destination , boolean copyEverything ) {
148182 /*
149183 The speed at which we copy data into the frame buffer is a major cost of JBWAPI's asynchronous operation.
150- Copy times observed in the wild range from 2.6ms - 12ms .
184+ Copy times observed in the wild usually range from 2.6ms - 19ms but are prone to large amounts of variance .
151185
152186 The normal Java way to execute this copy is via ByteBuffer.put(), which has reasonably good performance characteristics.
153187 Some experiments in 64-bit JRE have shown that using a native memcpy achieves a 35% speedup.
154188 Some experiments in 32-bit JRE show no difference in performance.
155189
156190 So, speculatively, we attempt to do a native memcpy.
157- */
158- long addressSource = ((DirectBuffer ) source ).address ();
159- long addressDestination = ((DirectBuffer ) destination ).address ();
160- try {
161- if (Platform .isWindows ()) {
162- if (Platform .is64Bit ()) {
163- MSVCRT .INSTANCE .memcpy (addressDestination , addressSource , FrameBuffer .BUFFER_SIZE );
164- return ;
165- } else {
166- MSVCRT .INSTANCE .memcpy ((int ) addressDestination , (int ) addressSource , FrameBuffer .BUFFER_SIZE );
167- return ;
168- }
191+ */
192+
193+ if (copyEverything ) {
194+ if (tryMemcpyBuffer (source , destination , 0 , FrameBuffer .BUFFER_SIZE )) {
195+ return ;
196+ }
197+ } else {
198+ int STATICTILES_START = 3447004 ; // getGroundHeight, isWalkable, isBuildable
199+ int STATICTILES_END = 4823260 ;
200+ int REGION_START = 5085404 ; // getMapTileRegionId, ..., getRegions
201+ int REGION_END = 10586480 ;
202+ int STRINGSSHAPES_START = 10962632 ; // getStringCount, ... getShapes
203+ int STRINGSHAPES_END = 32242636 ;
204+ int UNITFINDER_START = 32962644 ;
205+ if (
206+ tryMemcpyBuffer (source , destination , 0 , STATICTILES_START )
207+ && tryMemcpyBuffer (source , destination , STATICTILES_END , REGION_START - STATICTILES_END )
208+ && tryMemcpyBuffer (source , destination , REGION_END , STRINGSSHAPES_START - REGION_END )
209+ && tryMemcpyBuffer (source , destination , STRINGSHAPES_END , UNITFINDER_START - STRINGSHAPES_END )) {
210+ return ;
169211 }
170212 }
171- catch (Exception ignored ) {}
172213
173214 // There's no specific case where we expect to fail above,
174215 // but this is a safe fallback regardless,
0 commit comments