1212 */
1313class FrameBuffer {
1414 static final int BUFFER_SIZE = PackedWrappedBuffer .BUFFER_SIZE ;
15+
16+ static final int INITIAL_UNIT_COUNT_OFFSET = 69648 ;
17+ static final int UNITS_START = 69656 ;
18+ static final int MAX_UNITS = 10000 ;
19+ static final int UNITS_END = UNITS_START + MAX_UNITS * ClientData .UnitData .SIZE ;
20+
21+ static final int EVENT_COUNT_OFFSET = 10586620 ;
22+ static final int EVENTS_START = 10586624 ;
23+ static final int MAX_EVENTS = 10000 ;
24+
1525 private static final Unsafe unsafe = UnsafeTools .getUnsafe ();
1626
1727 private WrappedBuffer liveData ;
@@ -20,6 +30,7 @@ class FrameBuffer {
2030 private final int capacity ;
2131 private int stepGame = 0 ;
2232 private int stepBot = 0 ;
33+ private int maxUnitCount = 0 ;
2334 private final ArrayList <WrappedBuffer > dataBuffer = new ArrayList <>();
2435
2536 private final Lock lockWrite = new ReentrantLock ();
@@ -42,6 +53,7 @@ void initialize(WrappedBuffer liveData, PerformanceMetrics performanceMetrics) {
4253 this .performanceMetrics = performanceMetrics ;
4354 stepGame = 0 ;
4455 stepBot = 0 ;
56+ maxUnitCount = 0 ;
4557 }
4658
4759 /**
@@ -151,9 +163,46 @@ void dequeue() {
151163 } finally { lockSize .unlock (); }
152164 }
153165
166+ int getMaxUnitCount () {
167+ return maxUnitCount ;
168+ }
169+
170+ private static int clamp (int value , int min , int max ) {
171+ return Math .max (min , Math .min (max , value ));
172+ }
173+
174+ private int updateMaxUnitCount (WrappedBuffer source ) {
175+ int initialUnits = clamp (source .getInt (INITIAL_UNIT_COUNT_OFFSET ), 0 , MAX_UNITS );
176+ if (initialUnits > maxUnitCount ) {
177+ maxUnitCount = initialUnits ;
178+ }
179+
180+ int eventCount = clamp (source .getInt (EVENT_COUNT_OFFSET ), 0 , MAX_EVENTS );
181+ for (int i = 0 ; i < eventCount ; i ++) {
182+ int eventOffset = EVENTS_START + i * ClientData .Event .SIZE ;
183+ if (source .getInt (eventOffset ) == EventType .UnitDiscover .id ) {
184+ int unitId = source .getInt (eventOffset + 4 );
185+ if (unitId >= 0 && unitId < MAX_UNITS && unitId + 1 > maxUnitCount ) {
186+ maxUnitCount = unitId + 1 ;
187+ }
188+ }
189+ }
190+ return maxUnitCount ;
191+ }
192+
154193 void copyBuffer (WrappedBuffer source , WrappedBuffer destination ) {
155- unsafe .copyMemory (source .getAddress () + 0 , destination .getAddress () + PackedWrappedBuffer .DEST_SLICE1_OFFSET , PackedWrappedBuffer .DYNAMIC_SLICE1_SIZE );
156- unsafe .copyMemory (source .getAddress () + PackedWrappedBuffer .STATICTILES_END , destination .getAddress () + PackedWrappedBuffer .DEST_SLICE2_OFFSET , PackedWrappedBuffer .DYNAMIC_SLICE2_SIZE );
157- unsafe .copyMemory (source .getAddress () + PackedWrappedBuffer .REGION_END , destination .getAddress () + PackedWrappedBuffer .DEST_SLICE3_OFFSET , PackedWrappedBuffer .DYNAMIC_SLICE3_SIZE );
194+ long srcAddr = source .getAddress ();
195+ long dstAddr = destination .getAddress ();
196+ int activeUnits = updateMaxUnitCount (source );
197+
198+ // Slice 1a: header, forces, players, initialUnitCount, and active units [0 .. maxUnitCount)
199+ int slice1ActiveUnitsEnd = UNITS_START + activeUnits * ClientData .UnitData .SIZE ;
200+ unsafe .copyMemory (srcAddr , dstAddr + PackedWrappedBuffer .DEST_SLICE1_OFFSET , slice1ActiveUnitsEnd );
201+ // Slice 1b: unitArray, bullets, nukeDots, frameCount, and other post-unit Slice 1 fields
202+ unsafe .copyMemory (srcAddr + UNITS_END , dstAddr + PackedWrappedBuffer .DEST_SLICE1_OFFSET + UNITS_END , PackedWrappedBuffer .STATICTILES_START - UNITS_END );
203+ // Slice 2: dynamic tile flags
204+ unsafe .copyMemory (srcAddr + PackedWrappedBuffer .STATICTILES_END , dstAddr + PackedWrappedBuffer .DEST_SLICE2_OFFSET , PackedWrappedBuffer .DYNAMIC_SLICE2_SIZE );
205+ // Slice 3: dynamic game state, events, and eventStrings
206+ unsafe .copyMemory (srcAddr + PackedWrappedBuffer .REGION_END , dstAddr + PackedWrappedBuffer .DEST_SLICE3_OFFSET , PackedWrappedBuffer .DYNAMIC_SLICE3_SIZE );
158207 }
159208}
0 commit comments