@@ -198,6 +198,7 @@ public class ChestEspHack extends Hack implements UpdateListener,
198198 new ArrayDeque <>();
199199 private final HashSet <Long > queuedChunkScans = new HashSet <>();
200200 private final HashMap <String , Long > antiEspCooldowns = new HashMap <>();
201+ private final Object antiEspLock = new Object ();
201202 private long lastContainerBePacketMs ;
202203 private long burstStartMs = -1L ;
203204 private boolean antiEspSuspicious ;
@@ -991,7 +992,10 @@ private void handleBlockUpdate(BlockPos pos, BlockState newState)
991992 boolean newContainer = isContainerBlock (newState );
992993
993994 if (oldContainer || newContainer )
994- lastBlockUpdateAt .put (pos .immutable (), now );
995+ synchronized (antiEspLock )
996+ {
997+ lastBlockUpdateAt .put (pos .immutable (), now );
998+ }
995999
9961000 if (!oldContainer && newContainer )
9971001 {
@@ -1016,35 +1020,46 @@ private void handleBlockEntityDataPacket(ClientboundBlockEntityDataPacket p)
10161020 if (!isContainerBlock (state ))
10171021 return ;
10181022
1019- Long missingAt = missingContainerAt .get (pos );
1020- Long updatedAt = lastBlockUpdateAt .get (pos );
1021- boolean missingRecently =
1022- missingAt != null && now - missingAt <= CHUNK_SCAN_EXPIRY_MS ;
1023- boolean noRecentUpdate =
1024- updatedAt == null || now - updatedAt > BLOCK_UPDATE_GRACE_MS ;
1025- if (missingRecently && noRecentUpdate )
1026- flagAntiEsp ("late-block-entity" , "Block entity for container at "
1027- + formatPos (pos ) + " arrived later without a block change" );
1028-
1029- long sinceLast = now - lastContainerBePacketMs ;
1030- if (lastContainerBePacketMs > 0 && sinceLast > BURST_QUIET_MS )
1023+ boolean lateWithoutUpdate ;
1024+ boolean burstDetected ;
1025+ int burstSize ;
1026+ synchronized (antiEspLock )
10311027 {
1032- burstStartMs = now ;
1033- blockEntityBurstTimes .clear ();
1028+ Long missingAt = missingContainerAt .get (pos );
1029+ Long updatedAt = lastBlockUpdateAt .get (pos );
1030+ boolean missingRecently =
1031+ missingAt != null && now - missingAt <= CHUNK_SCAN_EXPIRY_MS ;
1032+ boolean noRecentUpdate =
1033+ updatedAt == null || now - updatedAt > BLOCK_UPDATE_GRACE_MS ;
1034+ lateWithoutUpdate = missingRecently && noRecentUpdate ;
1035+
1036+ long sinceLast = now - lastContainerBePacketMs ;
1037+ if (lastContainerBePacketMs > 0 && sinceLast > BURST_QUIET_MS )
1038+ {
1039+ burstStartMs = now ;
1040+ blockEntityBurstTimes .clear ();
1041+ }
1042+ lastContainerBePacketMs = now ;
1043+
1044+ blockEntityBurstTimes .addLast (now );
1045+ while (!blockEntityBurstTimes .isEmpty ()
1046+ && now - blockEntityBurstTimes .peekFirst () > BURST_WINDOW_MS )
1047+ blockEntityBurstTimes .removeFirst ();
1048+
1049+ burstSize = blockEntityBurstTimes .size ();
1050+ burstDetected =
1051+ burstStartMs > 0 && now - burstStartMs <= BURST_WINDOW_MS
1052+ && burstSize >= BURST_THRESHOLD ;
10341053 }
1035- lastContainerBePacketMs = now ;
10361054
1037- blockEntityBurstTimes .addLast (now );
1038- while (!blockEntityBurstTimes .isEmpty ()
1039- && now - blockEntityBurstTimes .peekFirst () > BURST_WINDOW_MS )
1040- blockEntityBurstTimes .removeFirst ();
1055+ if (lateWithoutUpdate )
1056+ flagAntiEsp ("late-block-entity" , "Block entity for container at "
1057+ + formatPos (pos ) + " arrived later without a block change" );
10411058
1042- if (burstStartMs > 0 && now - burstStartMs <= BURST_WINDOW_MS
1043- && blockEntityBurstTimes .size () >= BURST_THRESHOLD )
1059+ if (burstDetected )
10441060 flagAntiEsp ("be-burst" ,
1045- "Burst of " + blockEntityBurstTimes .size ()
1046- + " block-entity packets in " + (BURST_WINDOW_MS / 1000 )
1047- + "s after a quiet period" );
1061+ "Burst of " + burstSize + " block-entity packets in "
1062+ + (BURST_WINDOW_MS / 1000 ) + "s after a quiet period" );
10481063 }
10491064
10501065 private void queueChunkScan (ChunkPos chunkPos )
@@ -1053,11 +1068,14 @@ private void queueChunkScan(ChunkPos chunkPos)
10531068 return ;
10541069
10551070 long key = chunkKey (chunkPos );
1056- if (!queuedChunkScans .add (key ))
1057- return ;
1058-
1059- chunkScanQueue .addLast (
1060- new ChunkScanRequest (chunkPos , key , System .currentTimeMillis ()));
1071+ synchronized (antiEspLock )
1072+ {
1073+ if (!queuedChunkScans .add (key ))
1074+ return ;
1075+
1076+ chunkScanQueue .addLast (new ChunkScanRequest (chunkPos , key ,
1077+ System .currentTimeMillis ()));
1078+ }
10611079 }
10621080
10631081 private void processQueuedChunkScans (int maxPerTick )
@@ -1068,11 +1086,16 @@ private void processQueuedChunkScans(int maxPerTick)
10681086 long now = System .currentTimeMillis ();
10691087 for (int i = 0 ; i < maxPerTick ; i ++)
10701088 {
1071- ChunkScanRequest request = chunkScanQueue .pollFirst ();
1089+ ChunkScanRequest request ;
1090+ synchronized (antiEspLock )
1091+ {
1092+ request = chunkScanQueue .pollFirst ();
1093+ if (request != null )
1094+ queuedChunkScans .remove (request .key ());
1095+ }
10721096 if (request == null )
10731097 return ;
10741098
1075- queuedChunkScans .remove (request .key ());
10761099 if (now - request .queuedAt () > CHUNK_SCAN_EXPIRY_MS )
10771100 continue ;
10781101
@@ -1089,6 +1112,7 @@ private void scanChunk(ChunkPos chunkPos)
10891112 if (chunk == null )
10901113 return ;
10911114
1115+ long now = System .currentTimeMillis ();
10921116 int minY = chunk .getMinY ();
10931117 int minSectionY = minY >> 4 ;
10941118 int containerBlocks = 0 ;
@@ -1121,8 +1145,10 @@ private void scanChunk(ChunkPos chunkPos)
11211145 if (be == null )
11221146 {
11231147 withoutBlockEntity ++;
1124- missingContainerAt .put (pos .immutable (),
1125- System .currentTimeMillis ());
1148+ synchronized (antiEspLock )
1149+ {
1150+ missingContainerAt .put (pos .immutable (), now );
1151+ }
11261152 }else
11271153 withBlockEntity ++;
11281154 }
@@ -1147,33 +1173,42 @@ private void recordContainerDiscovery(BlockEntity be)
11471173 return ;
11481174
11491175 BlockPos pos = be .getBlockPos ().immutable ();
1150- if (!discoveredContainers .add (pos ))
1151- return ;
1152-
11531176 double distance = MC .player .position ().distanceTo (Vec3 .atCenterOf (pos ));
1154- revealSamples
1155- .addLast (new RevealSample (distance , System .currentTimeMillis ()));
1156- while (revealSamples .size () > 64 )
1157- revealSamples .removeFirst ();
1177+ synchronized (antiEspLock )
1178+ {
1179+ if (!discoveredContainers .add (pos ))
1180+ return ;
1181+
1182+ revealSamples .addLast (
1183+ new RevealSample (distance , System .currentTimeMillis ()));
1184+ while (revealSamples .size () > 64 )
1185+ revealSamples .removeFirst ();
1186+ }
11581187 }
11591188
11601189 private void checkRevealPattern ()
11611190 {
1162- if (revealSamples .size () < REVEAL_MIN_SAMPLES )
1163- return ;
1191+ ArrayList <RevealSample > samples ;
1192+ synchronized (antiEspLock )
1193+ {
1194+ if (revealSamples .size () < REVEAL_MIN_SAMPLES )
1195+ return ;
1196+
1197+ samples = new ArrayList <>(revealSamples );
1198+ }
11641199
11651200 double sum = 0 ;
1166- for (RevealSample sample : revealSamples )
1201+ for (RevealSample sample : samples )
11671202 sum += sample .distance ();
11681203
1169- double mean = sum / revealSamples .size ();
1204+ double mean = sum / samples .size ();
11701205 double variance = 0 ;
1171- for (RevealSample sample : revealSamples )
1206+ for (RevealSample sample : samples )
11721207 {
11731208 double d = sample .distance () - mean ;
11741209 variance += d * d ;
11751210 }
1176- double stddev = Math .sqrt (variance / revealSamples .size ());
1211+ double stddev = Math .sqrt (variance / samples .size ());
11771212
11781213 boolean suspiciousRadius = mean >= 12 && mean <= 32 && stddev <= 2.8 ;
11791214 if (suspiciousRadius )
@@ -1188,42 +1223,54 @@ private void checkRevealPattern()
11881223 private void pruneAntiEspState ()
11891224 {
11901225 long now = System .currentTimeMillis ();
1191- missingContainerAt .entrySet ()
1192- .removeIf (e -> now - e .getValue () > CHUNK_SCAN_EXPIRY_MS );
1193- lastBlockUpdateAt .entrySet ()
1194- .removeIf (e -> now - e .getValue () > CHUNK_SCAN_EXPIRY_MS );
1195- revealSamples .removeIf (
1196- sample -> now - sample .timestamp () > REVEAL_SAMPLE_EXPIRY_MS );
1226+ synchronized (antiEspLock )
1227+ {
1228+ missingContainerAt .entrySet ()
1229+ .removeIf (e -> now - e .getValue () > CHUNK_SCAN_EXPIRY_MS );
1230+ lastBlockUpdateAt .entrySet ()
1231+ .removeIf (e -> now - e .getValue () > CHUNK_SCAN_EXPIRY_MS );
1232+ revealSamples .removeIf (
1233+ sample -> now - sample .timestamp () > REVEAL_SAMPLE_EXPIRY_MS );
1234+ }
11971235 }
11981236
11991237 private void flagAntiEsp (String key , String message )
12001238 {
1201- long now = System .currentTimeMillis ();
1202- Long cooldown = antiEspCooldowns .get (key );
1203- if (cooldown != null && now - cooldown < 8000 )
1204- return ;
1239+ boolean showAlert ;
1240+ synchronized (antiEspLock )
1241+ {
1242+ long now = System .currentTimeMillis ();
1243+ Long cooldown = antiEspCooldowns .get (key );
1244+ if (cooldown != null && now - cooldown < 8000 )
1245+ return ;
1246+
1247+ antiEspCooldowns .put (key , now );
1248+ antiEspSuspicious = true ;
1249+ antiEspSignals = Math .min (antiEspSignals + 1 , 999 );
1250+ showAlert = antiEspAlerts .isChecked ();
1251+ }
12051252
1206- antiEspCooldowns .put (key , now );
1207- antiEspSuspicious = true ;
1208- antiEspSignals = Math .min (antiEspSignals + 1 , 999 );
1209- if (antiEspAlerts .isChecked ())
1253+ if (showAlert )
12101254 ChatUtils .warning ("ChestESP Anti-ESP: " + message );
12111255 }
12121256
12131257 private void resetAntiEspState ()
12141258 {
1215- missingContainerAt .clear ();
1216- lastBlockUpdateAt .clear ();
1217- discoveredContainers .clear ();
1218- revealSamples .clear ();
1219- blockEntityBurstTimes .clear ();
1220- chunkScanQueue .clear ();
1221- queuedChunkScans .clear ();
1222- antiEspCooldowns .clear ();
1223- lastContainerBePacketMs = 0L ;
1224- burstStartMs = -1L ;
1225- antiEspSuspicious = false ;
1226- antiEspSignals = 0 ;
1259+ synchronized (antiEspLock )
1260+ {
1261+ missingContainerAt .clear ();
1262+ lastBlockUpdateAt .clear ();
1263+ discoveredContainers .clear ();
1264+ revealSamples .clear ();
1265+ blockEntityBurstTimes .clear ();
1266+ chunkScanQueue .clear ();
1267+ queuedChunkScans .clear ();
1268+ antiEspCooldowns .clear ();
1269+ lastContainerBePacketMs = 0L ;
1270+ burstStartMs = -1L ;
1271+ antiEspSuspicious = false ;
1272+ antiEspSignals = 0 ;
1273+ }
12271274 }
12281275
12291276 private boolean isContainerBlockEntity (BlockEntity be )
@@ -1275,8 +1322,19 @@ private static String formatBlock(BlockState state)
12751322 public String getRenderName ()
12761323 {
12771324 String base = getName ();
1278- if (antiEspDetection .isChecked () && antiEspSuspicious )
1279- base += " [AntiESP:" + antiEspSignals + "]" ;
1325+ if (antiEspDetection .isChecked ())
1326+ {
1327+ boolean suspicious ;
1328+ int signals ;
1329+ synchronized (antiEspLock )
1330+ {
1331+ suspicious = antiEspSuspicious ;
1332+ signals = antiEspSignals ;
1333+ }
1334+
1335+ if (suspicious )
1336+ base += " [AntiESP:" + signals + "]" ;
1337+ }
12801338 if (showCountInHackList .isChecked () && foundCount > 0 )
12811339 return base + " [" + foundCount + "]" ;
12821340 return base ;
0 commit comments