1212
1313public class FakeChunkPlannerService {
1414
15+ private final ConcurrentHashMap <Long , long []> sortedOffsetsCache = new ConcurrentHashMap <>();
16+
1517 public record PlanInput (
1618 int chunkX ,
1719 int chunkZ ,
@@ -39,20 +41,21 @@ public PlanResult build(PlanInput input) {
3941 int safeSquareRadius = (int ) Math .floor (input .serverDistance () * input .safeSquareFactor ());
4042 if (safeSquareRadius < 2 ) safeSquareRadius = 2 ;
4143
42- Set <Long > neededChunks = new HashSet <>();
43- for (int dx = -effectiveRadius ; dx <= effectiveRadius ; dx ++) {
44- for (int dz = -effectiveRadius ; dz <= effectiveRadius ; dz ++) {
45- int cx = chunkX + dx ;
46- int cz = chunkZ + dz ;
47- int chebyshev = Math .max (Math .abs (dx ), Math .abs (dz ));
48- if (chebyshev <= safeSquareRadius ) continue ;
49- if (dx * dx + dz * dz > effectiveRadius * effectiveRadius ) continue ;
50- neededChunks .add (ChunkPos .asLong (cx , cz ));
51- }
44+ long [] sortedOffsets = getSortedOffsets (effectiveRadius , safeSquareRadius );
45+ int offsetCount = sortedOffsets .length ;
46+ Set <Long > neededChunks = new HashSet <>(Math .max (16 , offsetCount * 2 ));
47+ for (long packedOffset : sortedOffsets ) {
48+ int dx = unpackX (packedOffset );
49+ int dz = unpackZ (packedOffset );
50+ neededChunks .add (ChunkPos .asLong (chunkX + dx , chunkZ + dz ));
5251 }
5352
53+ Set <Long > sentChunks = input .sentChunksSnapshot ();
54+ Set <Long > queuedSet = input .queuedSet ();
55+ Set <Long > inflightSet = input .inflightSet ();
56+
5457 Set <Long > chunksToUnload = new HashSet <>();
55- for (Long chunkKey : input . sentChunksSnapshot () ) {
58+ for (Long chunkKey : sentChunks ) {
5659 if (!neededChunks .contains (chunkKey )) {
5760 chunksToUnload .add (chunkKey );
5861 }
@@ -63,32 +66,25 @@ public PlanResult build(PlanInput input) {
6366 int kept = 0 ;
6467 for (Long existing : input .currentQueue ()) {
6568 if (!neededChunks .contains (existing )) continue ;
66- if (input . sentChunksSnapshot () .contains (existing )) continue ;
67- if (input . inflightSet () .contains (existing )) continue ;
69+ if (sentChunks .contains (existing )) continue ;
70+ if (inflightSet .contains (existing )) continue ;
6871 rebuiltQueue .addLast (existing );
6972 rebuiltQueuedSet .add (existing );
7073 kept ++;
7174 }
7275
73- List <Long > toAdd = new ArrayList <>();
74- for (Long chunkKey : neededChunks ) {
75- if (input .sentChunksSnapshot ().contains (chunkKey )) continue ;
76- if (input .queuedSet ().contains (chunkKey )) continue ;
77- if (input .inflightSet ().contains (chunkKey )) continue ;
76+ List <Long > toAdd = new ArrayList <>(offsetCount );
77+ for (long packedOffset : sortedOffsets ) {
78+ int dx = unpackX (packedOffset );
79+ int dz = unpackZ (packedOffset );
80+ long chunkKey = ChunkPos .asLong (chunkX + dx , chunkZ + dz );
81+ if (sentChunks .contains (chunkKey )) continue ;
82+ if (queuedSet .contains (chunkKey )) continue ;
83+ if (inflightSet .contains (chunkKey )) continue ;
7884 if (rebuiltQueuedSet .contains (chunkKey )) continue ;
7985 toAdd .add (chunkKey );
8086 }
8187
82- toAdd .sort (
83- Comparator .comparingInt (
84- key -> {
85- int cx = ChunkPos .getX (key );
86- int cz = ChunkPos .getZ (key );
87- int dx = cx - chunkX ;
88- int dz = cz - chunkZ ;
89- return dx * dx + dz * dz ;
90- }));
91-
9288 return new PlanResult (
9389 safeSquareRadius ,
9490 neededChunks ,
@@ -98,4 +94,40 @@ public PlanResult build(PlanInput input) {
9894 toAdd ,
9995 kept );
10096 }
97+
98+ private long [] getSortedOffsets (int effectiveRadius , int safeSquareRadius ) {
99+ long cacheKey = (((long ) effectiveRadius ) << 32 ) | (safeSquareRadius & 0xFFFFFFFFL );
100+ return sortedOffsetsCache .computeIfAbsent (cacheKey , k -> buildSortedOffsets (effectiveRadius , safeSquareRadius ));
101+ }
102+
103+ private long [] buildSortedOffsets (int effectiveRadius , int safeSquareRadius ) {
104+ List <long []> sortable = new ArrayList <>();
105+ for (int dx = -effectiveRadius ; dx <= effectiveRadius ; dx ++) {
106+ for (int dz = -effectiveRadius ; dz <= effectiveRadius ; dz ++) {
107+ int chebyshev = Math .max (Math .abs (dx ), Math .abs (dz ));
108+ if (chebyshev <= safeSquareRadius ) continue ;
109+ int distSq = dx * dx + dz * dz ;
110+ if (distSq > effectiveRadius * effectiveRadius ) continue ;
111+ sortable .add (new long [] {pack (dx , dz ), distSq });
112+ }
113+ }
114+ sortable .sort (Comparator .comparingLong (v -> v [1 ]));
115+ long [] offsets = new long [sortable .size ()];
116+ for (int i = 0 ; i < sortable .size (); i ++) {
117+ offsets [i ] = sortable .get (i )[0 ];
118+ }
119+ return offsets ;
120+ }
121+
122+ private static long pack (int x , int z ) {
123+ return (((long ) x ) << 32 ) | (z & 0xFFFFFFFFL );
124+ }
125+
126+ private static int unpackX (long packed ) {
127+ return (int ) (packed >> 32 );
128+ }
129+
130+ private static int unpackZ (long packed ) {
131+ return (int ) packed ;
132+ }
101133}
0 commit comments