Skip to content

Commit 1f8e1f6

Browse files
committed
Added Line of Sight Feature to PlayerESP, Fixed LogoutSpots
1 parent 9ec6cb0 commit 1f8e1f6

File tree

6 files changed

+496
-45
lines changed

6 files changed

+496
-45
lines changed

README.md

440 Bytes

LogoutSpots

  • Records where players log out.
  • Removes spots when they rejoin.
  • Rendering: solid box + outline, optional tracers, name labels with adjustable scale.
  • Settings: side color, line color, name scale, tracers toggle, spot lifetime, waypoint toggle.

Logout

PlayerESP Improvements

  • Added toggle for unique colors for each player (shared with Breadcrumbs)
  • Added box fill with transparency slider
  • Added static color option
  • Improved coloring for default close/far red to green (when all above off)
  • Added Line of Sight Detection (LOS)
    • When you're spotted ESP and tracer will turn a bold red regardless of distance or color settings
    • Adjustable FOV and range
  • Improved coloring for default distance based rendering, close (red) to far (green) (when all above off)
  • Able to ignore NPCs

ESP

src/main/java/net/wurstclient/WurstRenderLayers.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,22 @@ public static RenderLayer.MultiPhase getLines(boolean depthTest)
101101
return depthTest ? LINES : ESP_LINES;
102102
}
103103

104+
/**
105+
* Returns a line render layer with a custom width.
106+
*/
107+
public static RenderLayer.MultiPhase getLines(boolean depthTest,
108+
double width)
109+
{
110+
return RenderLayer.of(
111+
depthTest ? "wurst:lines_custom" : "wurst:esp_lines_custom", 1536,
112+
depthTest ? WurstShaderPipelines.DEPTH_TEST_LINES
113+
: WurstShaderPipelines.ESP_LINES,
114+
RenderLayer.MultiPhaseParameters.builder()
115+
.lineWidth(new RenderPhase.LineWidth(OptionalDouble.of(width)))
116+
.layering(RenderLayer.VIEW_OFFSET_Z_LAYERING)
117+
.target(RenderLayer.ITEM_ENTITY_TARGET).build(false));
118+
}
119+
104120
/**
105121
* Returns either {@link #LINE_STRIP} or {@link #ESP_LINE_STRIP} depending
106122
* on the value of {@code depthTest}.

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

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
import java.awt.Color;
1111
import java.util.ArrayList;
1212
import java.util.HashMap;
13+
import java.util.Iterator;
1314
import java.util.List;
1415
import java.util.Map;
1516
import java.util.UUID;
1617

1718
import net.minecraft.client.network.PlayerListEntry;
19+
import net.minecraft.client.network.ServerInfo;
1820
import net.minecraft.client.font.TextRenderer;
1921
import net.minecraft.client.render.VertexConsumerProvider;
2022
import net.minecraft.client.util.math.MatrixStack;
@@ -40,12 +42,14 @@ private static final class Entry
4042
final String name;
4143
final Box box;
4244
final String dimKey;
45+
final long createdAtMs;
4346

44-
Entry(UUID u, String n, Box b, float h, String dim)
47+
Entry(String n, Box b, String dim, long createdAtMs)
4548
{
4649
name = n;
4750
box = b;
4851
dimKey = dim;
52+
this.createdAtMs = createdAtMs;
4953
}
5054
}
5155

@@ -61,11 +65,17 @@ private static final class Entry
6165
private final net.wurstclient.settings.CheckboxSetting addAsWaypoint =
6266
new net.wurstclient.settings.CheckboxSetting(
6367
"Add logout spot as waypoint", false);
68+
private static final int INFINITE_LIFETIME_MARKER = 121;
69+
private final SliderSetting spotLifetimeMinutes = new SliderSetting(
70+
"Spot lifetime (minutes)", 60, 1, INFINITE_LIFETIME_MARKER, 1,
71+
net.wurstclient.settings.SliderSetting.ValueDisplay.INTEGER
72+
.withLabel(INFINITE_LIFETIME_MARKER, "Infinite"));
6473

6574
private final Map<UUID, Entry> spots = new HashMap<>();
6675
private List<PlayerListEntry> lastList = List.of();
6776
private Map<UUID, PlayerEntity> lastPlayers = Map.of();
6877
private final Map<UUID, java.util.UUID> spotToWaypoint = new HashMap<>();
78+
private String lastServerKey = "unknown";
6979

7080
public LogoutSpotsHack()
7181
{
@@ -75,37 +85,40 @@ public LogoutSpotsHack()
7585
addSetting(lineColor);
7686
addSetting(scale);
7787
addSetting(showTracers);
88+
addSetting(spotLifetimeMinutes);
7889
addSetting(addAsWaypoint);
7990
}
8091

8192
@Override
8293
protected void onEnable()
8394
{
84-
spots.clear();
95+
clearAllSpots();
96+
lastServerKey = resolveServerKey();
8597
snapshot();
8698
EVENTS.add(UpdateListener.class, this);
8799
EVENTS.add(RenderListener.class, this);
88-
spotToWaypoint.clear();
89100
}
90101

91102
@Override
92103
protected void onDisable()
93104
{
94105
EVENTS.remove(UpdateListener.class, this);
95106
EVENTS.remove(RenderListener.class, this);
96-
spots.clear();
97-
// remove any temporary waypoints that we created
98-
if(WURST.getHax().waypointsHack != null)
99-
{
100-
for(java.util.UUID wp : new ArrayList<>(spotToWaypoint.values()))
101-
WURST.getHax().waypointsHack.removeTemporaryWaypoint(wp);
102-
}
103-
spotToWaypoint.clear();
107+
clearAllSpots();
104108
}
105109

106110
@Override
107111
public void onUpdate()
108112
{
113+
String serverKeyNow = resolveServerKey();
114+
if(!serverKeyNow.equals(lastServerKey))
115+
{
116+
clearAllSpots();
117+
lastList = List.of();
118+
lastPlayers = Map.of();
119+
lastServerKey = serverKeyNow;
120+
}
121+
109122
if(MC.getNetworkHandler() == null || MC.world == null)
110123
return;
111124
var nowList = MC.getNetworkHandler().getPlayerList();
@@ -125,18 +138,17 @@ public void onUpdate()
125138
if(p != null)
126139
{
127140
Box b = p.getBoundingBox();
128-
float h = p.getHealth();
129-
spots.put(id, new Entry(id, p.getName().getString(), b,
130-
h, currentDimKey()));
141+
long now = System.currentTimeMillis();
142+
spots.put(id, new Entry(p.getName().getString(), b,
143+
currentDimKey(), now));
131144
// Optionally add a temporary waypoint for this logout
132145
// spot
133146
if(addAsWaypoint.isChecked()
134147
&& WURST.getHax().waypointsHack != null
135148
&& WURST.getHax().waypointsHack.isEnabled())
136149
{
137150
Waypoint w =
138-
new Waypoint(java.util.UUID.randomUUID(),
139-
System.currentTimeMillis());
151+
new Waypoint(java.util.UUID.randomUUID(), now);
140152
w.setName("Logout: " + p.getName().getString());
141153
w.setIcon("skull");
142154
w.setColor(0xFF88CCFF);
@@ -163,10 +175,24 @@ public void onUpdate()
163175
for(PlayerEntity p : MC.world.getPlayers())
164176
{
165177
spots.remove(p.getUuid());
166-
// remove any temporary waypoint associated with this spot
167-
java.util.UUID wp = spotToWaypoint.remove(p.getUuid());
168-
if(wp != null && WURST.getHax().waypointsHack != null)
169-
WURST.getHax().waypointsHack.removeTemporaryWaypoint(wp);
178+
removeTemporaryWaypoint(p.getUuid());
179+
}
180+
}
181+
182+
int lifetimeMinutes = spotLifetimeMinutes.getValueI();
183+
if(lifetimeMinutes < INFINITE_LIFETIME_MARKER && !spots.isEmpty())
184+
{
185+
long lifetimeMs = lifetimeMinutes * 60_000L;
186+
long cutoff = System.currentTimeMillis() - lifetimeMs;
187+
Iterator<Map.Entry<UUID, Entry>> it = spots.entrySet().iterator();
188+
while(it.hasNext())
189+
{
190+
var entry = it.next();
191+
if(entry.getValue().createdAtMs <= cutoff)
192+
{
193+
removeTemporaryWaypoint(entry.getKey());
194+
it.remove();
195+
}
170196
}
171197
}
172198
}
@@ -192,6 +218,41 @@ private void snapshot()
192218
lastPlayers = map;
193219
}
194220

221+
private String resolveServerKey()
222+
{
223+
ServerInfo info = MC.getCurrentServerEntry();
224+
if(info != null)
225+
{
226+
if(info.address != null && !info.address.isEmpty())
227+
return info.address.replace(':', '_');
228+
if(info.isRealm())
229+
return "realms_" + (info.name == null ? "" : info.name);
230+
if(info.name != null && !info.name.isEmpty())
231+
return "server_" + info.name;
232+
}
233+
if(MC.isIntegratedServerRunning())
234+
return "singleplayer";
235+
return "unknown";
236+
}
237+
238+
private void clearAllSpots()
239+
{
240+
if(!spotToWaypoint.isEmpty() && WURST.getHax().waypointsHack != null)
241+
{
242+
for(java.util.UUID wp : new ArrayList<>(spotToWaypoint.values()))
243+
WURST.getHax().waypointsHack.removeTemporaryWaypoint(wp);
244+
}
245+
spotToWaypoint.clear();
246+
spots.clear();
247+
}
248+
249+
private void removeTemporaryWaypoint(UUID playerId)
250+
{
251+
java.util.UUID wp = spotToWaypoint.remove(playerId);
252+
if(wp != null && WURST.getHax().waypointsHack != null)
253+
WURST.getHax().waypointsHack.removeTemporaryWaypoint(wp);
254+
}
255+
195256
@Override
196257
public void onRender(MatrixStack matrices, float partialTicks)
197258
{

0 commit comments

Comments
 (0)