Skip to content

Commit 87f56eb

Browse files
committed
Anti-ESP Detection Fix
1 parent 439a5c3 commit 87f56eb

2 files changed

Lines changed: 142 additions & 75 deletions

File tree

src/main/java/net/wurstclient/hacks/AntiCheatDetectHack.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,10 @@ private boolean isSuppressedNaturalTransition(String oldId, String newId)
321321
if(oldId == null || newId == null || oldId.equals(newId))
322322
return true;
323323

324+
// Fire spread and burning are common natural updates.
325+
if(isFireId(oldId) || isFireId(newId))
326+
return true;
327+
324328
if(isAirOrFluidId(oldId) || isAirOrFluidId(newId))
325329
return true;
326330

@@ -342,6 +346,11 @@ private boolean isSuppressedNaturalTransition(String oldId, String newId)
342346
return false;
343347
}
344348

349+
private boolean isFireId(String id)
350+
{
351+
return "minecraft:fire".equals(id) || "minecraft:soul_fire".equals(id);
352+
}
353+
345354
private boolean isAirOrFluidId(String id)
346355
{
347356
return "minecraft:air".equals(id) || "minecraft:cave_air".equals(id)

src/main/java/net/wurstclient/hacks/ChestEspHack.java

Lines changed: 133 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)