@@ -107,10 +107,19 @@ void enqueueFrame() {
107
107
performanceMetrics .intentionallyBlocking .stopTiming ();
108
108
} finally { lockSize .unlock (); };
109
109
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
+ }
114
123
115
124
lockSize .lock ();
116
125
try {
@@ -144,31 +153,63 @@ void dequeue() {
144
153
} finally { lockSize .unlock (); }
145
154
}
146
155
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 ) {
148
182
/*
149
183
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 .
151
185
152
186
The normal Java way to execute this copy is via ByteBuffer.put(), which has reasonably good performance characteristics.
153
187
Some experiments in 64-bit JRE have shown that using a native memcpy achieves a 35% speedup.
154
188
Some experiments in 32-bit JRE show no difference in performance.
155
189
156
190
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 ;
169
211
}
170
212
}
171
- catch (Exception ignored ) {}
172
213
173
214
// There's no specific case where we expect to fail above,
174
215
// but this is a safe fallback regardless,
0 commit comments