Skip to content

Commit 87c98cf

Browse files
committed
Updated PortalESP
1 parent d1ca3b1 commit 87c98cf

2 files changed

Lines changed: 177 additions & 22 deletions

File tree

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

Lines changed: 105 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,10 @@ public void onUpdate()
334334
|| e.getValue().untilMs() < now);
335335
offlineStasisLabels.entrySet()
336336
.removeIf(e -> seenPearls.contains(e.getKey())
337-
|| e.getValue() == null || e.getValue().untilMs() < now);
337+
|| e.getValue() == null || e.getValue().untilMs() < now
338+
|| isPositionOccupiedByVisiblePearl(
339+
e.getValue() != null ? e.getValue().pos() : null,
340+
seenPearls));
338341

339342
// Disconnect inference: pearls that disappeared since last frame
340343
if(inferOwnership.isChecked())
@@ -343,31 +346,36 @@ public void onUpdate()
343346
vanished.removeAll(seenPearls);
344347
for(UUID vanishedUuid : vanished)
345348
{
349+
Vec3 vanishedPos = lastPearlPositions.get(vanishedUuid);
350+
if(vanishedPos == null)
351+
continue;
352+
353+
// Skip if a currently visible pearl is at the same position
354+
// (UUID change due to server re-creating the entity)
355+
if(isPositionOccupiedByVisiblePearl(vanishedPos, seenPearls))
356+
continue;
357+
346358
UUID existingOwner = pearlOwnerUuids.get(vanishedUuid);
347359
if(existingOwner != null)
348360
{
349-
Vec3 pos = lastPearlPositions.get(vanishedUuid);
350-
if(pos != null)
351-
{
352-
String inferred = getOwnerUuidLabel(existingOwner);
353-
if(inferred != null)
354-
offlineStasisLabels.put(vanishedUuid,
355-
new StasisLabel(
356-
formatOfflineLabelText(vanishedUuid,
357-
inferred),
358-
pos, now + OFFLINE_STASIS_STICKY_MS));
359-
}
361+
// Never create offline labels for your own pearls. You
362+
// already know where they are and "Owner: You" is noise.
363+
if(MC.player != null
364+
&& existingOwner.equals(MC.player.getUUID()))
365+
continue;
366+
367+
String inferred = getOwnerUuidLabel(existingOwner);
368+
if(inferred != null)
369+
putOfflineStasisLabel(vanishedUuid,
370+
formatOfflineLabelText(vanishedUuid, inferred),
371+
vanishedPos, now);
360372
continue;
361373
}
362374

363375
String inferred = inferOwnerFromLeaveTiming(vanishedUuid);
364376
if(inferred != null)
365-
{
366-
Vec3 pos = lastPearlPositions.get(vanishedUuid);
367-
if(pos != null)
368-
offlineStasisLabels.put(vanishedUuid, new StasisLabel(
369-
inferred, pos, now + OFFLINE_STASIS_STICKY_MS));
370-
}
377+
putOfflineStasisLabel(vanishedUuid, inferred, vanishedPos,
378+
now);
371379
}
372380
}
373381
previousPearlUuids = seenPearls;
@@ -1314,6 +1322,10 @@ private String inferOwnerFromLeaveTiming(UUID pearlUuid)
13141322
if(candidateCount != 1 || bestCandidate == null)
13151323
return null;
13161324

1325+
// Never infer yourself — you know you didn't leave
1326+
if(MC.player != null && bestCandidate.equals(MC.player.getUUID()))
1327+
return null;
1328+
13171329
String label = getOwnerUuidLabel(bestCandidate);
13181330
if(label == null)
13191331
return null;
@@ -1338,6 +1350,12 @@ private void inferOwnersFromPlayerLeave(UUID playerUuid, long now)
13381350
{
13391351
if(playerUuid == null)
13401352
return;
1353+
1354+
// Ignore REMOVE_PLAYER info refreshes where the player is still
1355+
// visible in the world (common on servers that send remove+add
1356+
// cycles for tab-list/latency updates).
1357+
if(isPlayerVisibleInWorld(playerUuid))
1358+
return;
13411359

13421360
Integer playerEntityId = null;
13431361
PlayerIdentity identity = playerIdentities.get(playerUuid);
@@ -1389,9 +1407,8 @@ private void inferOwnersFromPlayerLeave(UUID playerUuid, long now)
13891407

13901408
Vec3 pos = lastPearlPositions.get(pearlUuid);
13911409
if(pos != null)
1392-
offlineStasisLabels.put(pearlUuid,
1393-
new StasisLabel(formatOfflineLabelText(pearlUuid, label),
1394-
pos, now + OFFLINE_STASIS_STICKY_MS));
1410+
putOfflineStasisLabel(pearlUuid,
1411+
formatOfflineLabelText(pearlUuid, label), pos, now);
13951412

13961413
inferredCount++;
13971414
}
@@ -1523,6 +1540,73 @@ private OwnerConfidence getPearlConfidence(UUID pearlUuid)
15231540
return pid != null ? pid.confidence() : null;
15241541
}
15251542

1543+
/**
1544+
* Checks whether any currently visible pearl is at approximately the
1545+
* same position as the given vanished position. This prevents creating
1546+
* duplicate offline labels when the server re-creates a pearl entity
1547+
* with a new UUID (common in bubble-column stasis chambers).
1548+
*/
1549+
private boolean isPositionOccupiedByVisiblePearl(Vec3 vanishedPos,
1550+
HashSet<UUID> seenPearls)
1551+
{
1552+
if(vanishedPos == null)
1553+
return false;
1554+
double threshold = 0.5;
1555+
for(UUID seenUuid : seenPearls)
1556+
{
1557+
Vec3 seenPos = lastPearlPositions.get(seenUuid);
1558+
if(seenPos != null
1559+
&& seenPos.distanceToSqr(vanishedPos) < threshold * threshold)
1560+
return true;
1561+
}
1562+
return false;
1563+
}
1564+
1565+
/**
1566+
* Checks whether a player with the given UUID is currently visible
1567+
* among the entities being rendered in the world.
1568+
*/
1569+
private boolean isPlayerVisibleInWorld(UUID playerUuid)
1570+
{
1571+
if(playerUuid == null || MC.level == null)
1572+
return false;
1573+
for(Entity entity : MC.level.entitiesForRendering())
1574+
{
1575+
if(entity instanceof Player && playerUuid.equals(entity.getUUID()))
1576+
return true;
1577+
}
1578+
return false;
1579+
}
1580+
1581+
/**
1582+
* Adds or refreshes an offline stasis label, de-duplicating by position.
1583+
* If an existing offline label exists at approximately the same position,
1584+
* its timestamp is refreshed instead of creating a duplicate.
1585+
*/
1586+
private void putOfflineStasisLabel(UUID vanishedUuid, String text, Vec3 pos,
1587+
long now)
1588+
{
1589+
double threshold = 0.5;
1590+
long untilMs = now + OFFLINE_STASIS_STICKY_MS;
1591+
1592+
// Check for an existing offline label at the same position
1593+
for(Map.Entry<UUID, StasisLabel> entry : offlineStasisLabels.entrySet())
1594+
{
1595+
StasisLabel existing = entry.getValue();
1596+
if(existing != null && existing.pos() != null
1597+
&& existing.pos().distanceToSqr(pos) < threshold * threshold)
1598+
{
1599+
// Refresh the existing entry instead of adding a duplicate
1600+
offlineStasisLabels.put(entry.getKey(),
1601+
new StasisLabel(existing.text(), existing.pos(), untilMs));
1602+
return;
1603+
}
1604+
}
1605+
1606+
offlineStasisLabels.put(vanishedUuid,
1607+
new StasisLabel(text, pos, untilMs));
1608+
}
1609+
15261610
private float computeDistanceScale(Vec3 labelPos, float baseScale)
15271611
{
15281612
if(MC.player == null)

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

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,18 @@ public final class PortalEspHack extends Hack implements UpdateListener,
181181
private final SliderSetting aboveGroundY = new SliderSetting(
182182
"Set ESP Y limit", 62, -65, 255, 1, SliderSetting.ValueDisplay.INTEGER);
183183

184+
private final CheckboxSetting disableTracersAlertsForWaypointPortals =
185+
new CheckboxSetting("Disable tracers/alerts for waypoint portals",
186+
"Disables tracers and alerts (sounds + text) for portals\n"
187+
+ "that already have a Wurst waypoint nearby.",
188+
false);
189+
190+
private final CheckboxSetting disableHighlightingForWaypointPortals =
191+
new CheckboxSetting("Disable highlighting for waypoint portals",
192+
"Disables ESP entirely for portals that already have\n"
193+
+ "a Wurst waypoint nearby.",
194+
false);
195+
184196
private final BiPredicate<BlockPos, BlockState> query =
185197
(pos, state) -> state.getBlock() == Blocks.NETHER_PORTAL
186198
|| state.getBlock() == Blocks.END_PORTAL
@@ -232,6 +244,8 @@ public PortalEspHack()
232244
addSetting(stickyArea);
233245
addSetting(onlyAboveGround);
234246
addSetting(aboveGroundY);
247+
addSetting(disableTracersAlertsForWaypointPortals);
248+
addSetting(disableHighlightingForWaypointPortals);
235249
}
236250

237251
public List<PortalEspBlockGroup> getMapaGroups()
@@ -345,7 +359,11 @@ private void renderBoxes(PoseStack matrixStack)
345359
if(!group.isEnabled())
346360
continue;
347361

348-
List<AABB> boxes = group.getBoxes();
362+
List<AABB> boxes = disableHighlightingForWaypointPortals.isChecked()
363+
? getBoxesFilteringWaypoints(group) : group.getBoxes();
364+
if(boxes.isEmpty())
365+
continue;
366+
349367
int quadsColor = group.getColorI(0x40);
350368
int linesColor = group.getColorI(0x80);
351369

@@ -355,6 +373,17 @@ private void renderBoxes(PoseStack matrixStack)
355373
}
356374
}
357375

376+
private List<AABB> getBoxesFilteringWaypoints(PortalEspBlockGroup group)
377+
{
378+
List<BlockPos> positions = group.getPositions();
379+
List<AABB> boxes = group.getBoxes();
380+
ArrayList<AABB> filtered = new ArrayList<>();
381+
for(int i = 0; i < positions.size(); i++)
382+
if(!isNearWaypoint(positions.get(i)))
383+
filtered.add(boxes.get(i));
384+
return filtered;
385+
}
386+
358387
private void renderTracers(PoseStack matrixStack, float partialTicks)
359388
{
360389
for(PortalEspBlockGroup group : groups)
@@ -369,6 +398,16 @@ private void renderTracers(PoseStack matrixStack, float partialTicks)
369398
if(ends.isEmpty())
370399
continue;
371400

401+
if(shouldSuppressAlertsAndTracers())
402+
ends =
403+
ends.stream()
404+
.filter(v -> !isNearWaypoint(
405+
new BlockPos((int)v.x, (int)v.y, (int)v.z)))
406+
.toList();
407+
408+
if(ends.isEmpty())
409+
continue;
410+
372411
int color = group.getColorI(0x80);
373412
if(tracerFlash.isChecked())
374413
color = RenderUtils.flashColor(color);
@@ -411,6 +450,9 @@ private void updateGroupBoxes()
411450
HashMap<PortalEspBlockGroup, ArrayList<BlockPos>> newBlocksByGroup =
412451
commitCandidates(candidatesByGroup);
413452

453+
if(shouldSuppressAlertsAndTracers())
454+
newBlocksByGroup = filterNewBlocksByWaypoint(newBlocksByGroup);
455+
414456
ArrayList<DiscoveryHit> discoveries =
415457
buildDiscoveries(newBlocksByGroup);
416458

@@ -1938,6 +1980,35 @@ BlockPos toPos(int primary, int y, int plane)
19381980
private record DiscoveryHit(String label, Vec3 pos)
19391981
{}
19401982

1983+
private boolean isNearWaypoint(BlockPos pos)
1984+
{
1985+
return WURST.getHax().waypointsHack != null
1986+
&& WURST.getHax().waypointsHack.hasWaypointNear(pos, 5.0);
1987+
}
1988+
1989+
private boolean shouldSuppressAlertsAndTracers()
1990+
{
1991+
return disableTracersAlertsForWaypointPortals.isChecked()
1992+
|| disableHighlightingForWaypointPortals.isChecked();
1993+
}
1994+
1995+
private HashMap<PortalEspBlockGroup, ArrayList<BlockPos>> filterNewBlocksByWaypoint(
1996+
HashMap<PortalEspBlockGroup, ArrayList<BlockPos>> newBlocksByGroup)
1997+
{
1998+
HashMap<PortalEspBlockGroup, ArrayList<BlockPos>> filtered =
1999+
new HashMap<>();
2000+
for(var entry : newBlocksByGroup.entrySet())
2001+
{
2002+
ArrayList<BlockPos> filteredBlocks = new ArrayList<>();
2003+
for(BlockPos pos : entry.getValue())
2004+
if(!isNearWaypoint(pos))
2005+
filteredBlocks.add(pos);
2006+
if(!filteredBlocks.isEmpty())
2007+
filtered.put(entry.getKey(), filteredBlocks);
2008+
}
2009+
return filtered;
2010+
}
2011+
19412012
private enum DetectionSound
19422013
{
19432014
NOTE_BLOCK_CHIME("Note Block Chime",

0 commit comments

Comments
 (0)