Skip to content

Commit 7b0609f

Browse files
committed
Updated PlayerESP
1 parent 65ad2db commit 7b0609f

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ Examples:
258258
- Adjustable FOV and range
259259
- Improved coloring for default distance based rendering, close (red) to far (green) (when all above off)
260260
- Able to ignore NPCs
261+
- Enter/Leave area notification option in chat with name, co-ordinates and block distance
261262

262263
![ESP](https://i.imgur.com/1F7zU31.png)
263264

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

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import java.util.Map;
1313
import java.util.Optional;
1414
import java.util.UUID;
15+
import java.util.Set;
16+
import java.util.HashSet;
1517
import java.util.stream.Collectors;
1618
import java.util.stream.Stream;
1719

@@ -23,6 +25,10 @@
2325
import net.minecraft.util.math.Vec3d;
2426
import net.minecraft.util.Util;
2527
import net.minecraft.util.hit.HitResult;
28+
import net.minecraft.text.Text;
29+
import net.minecraft.text.MutableText;
30+
import net.minecraft.text.TextColor;
31+
import net.minecraft.util.Formatting;
2632
import net.wurstclient.Category;
2733
import net.wurstclient.SearchTags;
2834
import net.wurstclient.events.CameraTransformViewBobbingListener;
@@ -42,6 +48,7 @@
4248
import net.wurstclient.util.EntityUtils;
4349
import net.wurstclient.util.FakePlayerEntity;
4450
import net.wurstclient.util.RenderUtils;
51+
import net.wurstclient.util.ChatUtils;
4552
import net.wurstclient.util.RenderUtils.ColoredBox;
4653
import net.wurstclient.util.RenderUtils.ColoredPoint;
4754
import net.minecraft.world.RaycastContext;
@@ -62,6 +69,19 @@ public final class PlayerEspHack extends Hack implements UpdateListener,
6269
new FilterInvisibleSetting("Won't show invisible players.", false));
6370

6471
private final ArrayList<PlayerEntity> players = new ArrayList<>();
72+
// Alert settings & tracking for enter/exit notifications
73+
private final CheckboxSetting enterAlert = new CheckboxSetting(
74+
"Enter alert",
75+
"When enabled, notifies in chat when a player first becomes visible\n"
76+
+ "to PlayerESP, showing distance and XYZ.",
77+
false);
78+
private final CheckboxSetting exitAlert = new CheckboxSetting("Exit alert",
79+
"When enabled, notifies in chat when a player leaves PlayerESP\n"
80+
+ "visibility, showing distance and XYZ at which they left.",
81+
false);
82+
private final Set<UUID> prevVisible = new HashSet<>();
83+
private final Map<UUID, Vec3d> lastPositions = new HashMap<>();
84+
private final Map<UUID, String> lastNames = new HashMap<>();
6585
private final CheckboxSetting randomBrightColors = new CheckboxSetting(
6686
"Unique colors for players",
6787
"When enabled, assigns each player a bright color from a shared\n"
@@ -127,6 +147,10 @@ public PlayerEspHack()
127147
addSetting(useStaticPlayerColor);
128148
addSetting(playerColor);
129149
addSetting(boxSize);
150+
151+
// Alerts when players enter/leave PlayerESP visibility
152+
addSetting(enterAlert);
153+
addSetting(exitAlert);
130154
entityFilters.forEach(this::addSetting);
131155
addSetting(ignoreNpcs);
132156
}
@@ -146,6 +170,9 @@ protected void onDisable()
146170
EVENTS.remove(CameraTransformViewBobbingListener.class, this);
147171
EVENTS.remove(RenderListener.class, this);
148172
losStates.clear();
173+
prevVisible.clear();
174+
lastPositions.clear();
175+
lastNames.clear();
149176
}
150177

151178
@Override
@@ -175,12 +202,125 @@ public void onUpdate()
175202

176203
players.addAll(stream.collect(Collectors.toList()));
177204

205+
// detect enter / exit visibility changes
206+
handleVisibilityChanges();
207+
178208
if(losThreatDetection.isChecked())
179209
updateLosStates(Util.getMeasuringTimeMs());
180210
else
181211
losStates.clear();
182212
}
183213

214+
/**
215+
* Detect which players entered or left the PlayerESP-visible list since
216+
* the last update and send chat alerts if configured.
217+
*/
218+
private void handleVisibilityChanges()
219+
{
220+
// Build a set of currently visible *non-bot* players. Use the same
221+
// bot/NPC checks PlayerESP already uses: FakePlayerEntity and
222+
// (when enabled) players missing from the client's tab-list.
223+
Set<UUID> currentNonBot = new HashSet<>();
224+
225+
// Added players (only non-bots)
226+
for(PlayerEntity p : players)
227+
{
228+
// skip known fake players
229+
if(p instanceof FakePlayerEntity)
230+
continue;
231+
232+
UUID id = p.getUuid();
233+
234+
// If ignoreNpcs is enabled, treat players not on the client
235+
// player list as bots/NPCs and ignore them for alerts.
236+
if(ignoreNpcs.isChecked() && MC.getNetworkHandler() != null
237+
&& MC.getNetworkHandler().getPlayerListEntry(id) == null)
238+
{
239+
continue;
240+
}
241+
242+
currentNonBot.add(id);
243+
lastPositions.put(id, new Vec3d(p.getX(), p.getY(), p.getZ()));
244+
lastNames.put(id, p.getName().getString());
245+
if(!prevVisible.contains(id) && enterAlert.isChecked())
246+
sendEnterMessage(p);
247+
}
248+
249+
// Removed players (only consider previously tracked non-bot IDs)
250+
for(UUID id : new HashSet<>(prevVisible))
251+
{
252+
if(!currentNonBot.contains(id))
253+
{
254+
Vec3d pos = lastPositions.get(id);
255+
String name = lastNames.getOrDefault(id, "<unknown>");
256+
if(exitAlert.isChecked())
257+
sendExitMessage(id, name, pos);
258+
lastPositions.remove(id);
259+
lastNames.remove(id);
260+
prevVisible.remove(id);
261+
}
262+
}
263+
264+
prevVisible.clear();
265+
prevVisible.addAll(currentNonBot);
266+
}
267+
268+
private void sendEnterMessage(PlayerEntity p)
269+
{
270+
if(MC.player == null)
271+
return;
272+
UUID id = p.getUuid();
273+
double dist = Math.round(MC.player.distanceTo(p) * 10.0) / 10.0;
274+
int x = (int)Math.round(p.getX());
275+
int y = (int)Math.round(p.getY());
276+
int z = (int)Math.round(p.getZ());
277+
MutableText nameText =
278+
MutableText.of(Text.literal(p.getName().getString()).getContent());
279+
if(randomBrightColors.isChecked())
280+
{
281+
int idx = Math.abs(id.hashCode());
282+
java.awt.Color gen = net.wurstclient.util.PlayerColorRegistry
283+
.generateBrightColor(idx);
284+
nameText.setStyle(nameText.getStyle().withColor(TextColor.fromRgb(
285+
(gen.getRed() << 16) | (gen.getGreen() << 8) | gen.getBlue())));
286+
}
287+
Text msg = nameText.append(Text
288+
.literal(" entered range (" + dist + " blocks) at " + x + ", " + y
289+
+ ", " + z + ".")
290+
.styled(
291+
s -> s.withColor(TextColor.fromFormatting(Formatting.WHITE))));
292+
ChatUtils.component(msg);
293+
}
294+
295+
private void sendExitMessage(UUID id, String name, Vec3d pos)
296+
{
297+
if(MC.player == null)
298+
return;
299+
double dist = pos == null ? -1.0
300+
: Math.round(pos.distanceTo(
301+
new Vec3d(MC.player.getX(), MC.player.getY(), MC.player.getZ()))
302+
* 10.0) / 10.0;
303+
int x = pos == null ? 0 : (int)Math.round(pos.x);
304+
int y = pos == null ? 0 : (int)Math.round(pos.y);
305+
int z = pos == null ? 0 : (int)Math.round(pos.z);
306+
MutableText nameText = MutableText.of(Text.literal(name).getContent());
307+
if(randomBrightColors.isChecked())
308+
{
309+
int idx = Math.abs(id.hashCode());
310+
java.awt.Color gen = net.wurstclient.util.PlayerColorRegistry
311+
.generateBrightColor(idx);
312+
nameText.setStyle(nameText.getStyle().withColor(TextColor.fromRgb(
313+
(gen.getRed() << 16) | (gen.getGreen() << 8) | gen.getBlue())));
314+
}
315+
String distStr = dist < 0 ? "unknown" : (dist + " blocks");
316+
Text msg = nameText.append(Text
317+
.literal(" left range (" + distStr + ") at " + x + ", " + y + ", "
318+
+ z + ".")
319+
.styled(
320+
s -> s.withColor(TextColor.fromFormatting(Formatting.WHITE))));
321+
ChatUtils.component(msg);
322+
}
323+
184324
@Override
185325
public void onCameraTransformViewBobbing(
186326
CameraTransformViewBobbingEvent event)

0 commit comments

Comments
 (0)