Skip to content

Commit de4bc82

Browse files
committed
PlayerESP and Breadcrumbs Improvements
1 parent 3389b43 commit de4bc82

File tree

4 files changed

+374
-33
lines changed

4 files changed

+374
-33
lines changed

README.md

622 Bytes

Breadcrumbs

  • Leaves a line trail behind you (toggle-able/pause-able).
  • Trail can be infinitely long
  • Trail can be applied to other players (toggleable unique colors for each player (shared with PlayerESP))
  • Settings: color, max sections, section length, thickness, targets, keep trails toggle, randomunique colors toggle.

BreadCrumbsBreadCrumbs

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, waypoint toggle.

X

PlayerESP Improvements

  • Added 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)

ESP

Nuker Improvements

  • Auto toggle AutoTool option (If it wasn't on already, it will be enabled when using Nuker then turned off with Nuker)

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

Lines changed: 121 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import java.util.UUID;
1818

1919
import net.minecraft.client.util.math.MatrixStack;
20-
import net.minecraft.util.math.MathHelper;
2120
import net.minecraft.util.math.Vec3d;
2221
import net.wurstclient.Category;
2322
import net.wurstclient.SearchTags;
@@ -46,19 +45,79 @@ private enum Target
4645
BOTH
4746
}
4847

48+
private boolean movedEnough(Vec3d a, Vec3d b, double minDist)
49+
{
50+
double dx = a.x - b.x;
51+
double dy = a.y - b.y;
52+
double dz = a.z - b.z;
53+
double sq = dx * dx + dy * dy + dz * dz;
54+
return sq >= minDist * minDist;
55+
}
56+
4957
private final EnumSetting<Target> target =
5058
new EnumSetting<>("Target", Target.values(), Target.YOU);
5159
private final ColorSetting otherColor = new ColorSetting("Other color",
52-
"Color for other players' trails.", new Color(64, 160, 255));
60+
"Color for other players' trails. Note: PlayerESP overrides Breadcrumbs'\n"
61+
+ "colors; if PlayerESP is using a static or unique color for a player,\n"
62+
+ "Breadcrumbs will show that color instead.",
63+
new Color(64, 160, 255));
5364
private final CheckboxSetting keepOthersOnLeave =
54-
new CheckboxSetting("Keep other trails when out of view", false);
65+
new CheckboxSetting("Keep trails when out of view/logout", false);
5566
// If enabled, assign bright random-ish colors to other players.
56-
private final CheckboxSetting randomBrightColors =
57-
new CheckboxSetting("Random bright colors for others", false);
58-
private final SliderSetting maxSections =
59-
new SliderSetting("Max sections", 1000, 100, MAX_SECTIONS_INFINITE, 50,
60-
net.wurstclient.settings.SliderSetting.ValueDisplay.INTEGER
61-
.withLabel(MAX_SECTIONS_INFINITE, "Infinite"));
67+
private final CheckboxSetting randomBrightColors = new CheckboxSetting(
68+
"Unique colors for others",
69+
"Assign bright deterministic colors per-player so other hacks\n"
70+
+ "(for example PlayerESP) can share the same color. If you turn\n"
71+
+ "this off, Breadcrumbs will remove colors it owns from the\n"
72+
+ "shared registry so other features may take over.",
73+
false);
74+
// Build a piecewise sections map: 0..100 (step 1), 200..1000 (step 100),
75+
// 1200..5000 (step 200), 6000..9000 (step 1000), then 9999 and Infinite.
76+
private static final int[] SECTIONS_MAP = buildSectionsMap();
77+
78+
private static int[] buildSectionsMap()
79+
{
80+
java.util.ArrayList<Integer> list = new java.util.ArrayList<>();
81+
for(int i = 0; i <= 100; i++)
82+
list.add(i);
83+
for(int v = 200; v <= 1000; v += 100)
84+
list.add(v);
85+
for(int v = 1200; v <= 5000; v += 200)
86+
list.add(v);
87+
for(int v = 6000; v <= 9000; v += 1000)
88+
list.add(v);
89+
list.add(9999);
90+
list.add(MAX_SECTIONS_INFINITE);
91+
int[] arr = new int[list.size()];
92+
for(int i = 0; i < list.size(); i++)
93+
arr[i] = list.get(i);
94+
return arr;
95+
}
96+
97+
private static int findIndexFor(int value)
98+
{
99+
for(int i = 0; i < SECTIONS_MAP.length; i++)
100+
if(SECTIONS_MAP[i] == value)
101+
return i;
102+
return 0;
103+
}
104+
105+
// Slider indexes into SECTIONS_MAP. Display the mapped value (actual
106+
// section count) instead of the raw index so users see values like
107+
// 2500 or "Infinite".
108+
private final SliderSetting maxSections = new SliderSetting("Max sections",
109+
findIndexFor(1000), 0, SECTIONS_MAP.length - 1, 1,
110+
new net.wurstclient.settings.SliderSetting.ValueDisplay()
111+
{
112+
@Override
113+
public String getValueString(double v)
114+
{
115+
int idx = (int)v;
116+
int mapped = computeMaxSections(idx);
117+
return mapped >= MAX_SECTIONS_INFINITE ? "Infinite"
118+
: Integer.toString(mapped);
119+
}
120+
});
62121
private final SliderSetting sectionLen =
63122
new SliderSetting("Section length", 0.5, 0.1, 5.0, 0.1,
64123
net.wurstclient.settings.SliderSetting.ValueDisplay.DECIMAL);
@@ -72,8 +131,9 @@ private enum Target
72131
private final Map<UUID, Deque<Vec3d>> otherPoints = new HashMap<>();
73132
// previous target selection to detect changes
74133
private Target prevTarget = null;
75-
// per-player assigned colors when randomBrightColors is enabled
76-
private final Map<UUID, Color> playerColors = new HashMap<>();
134+
// previous random toggle so we can clean up registry on toggle off
135+
private boolean prevRandom = false;
136+
// per-player colors are managed via PlayerColorRegistry
77137

78138
public BreadcrumbsHack()
79139
{
@@ -102,6 +162,7 @@ protected void onEnable()
102162
points.clear();
103163
otherPoints.clear();
104164
prevTarget = target.getSelected();
165+
prevRandom = randomBrightColors.isChecked();
105166
EVENTS.add(UpdateListener.class, this);
106167
EVENTS.add(RenderListener.class, this);
107168
}
@@ -152,7 +213,7 @@ public void onUpdate()
152213
if(movedEnough(last, here, sectionLen.getValue()))
153214
{
154215
points.add(here);
155-
int limit = maxSections.getValueI();
216+
int limit = computeMaxSections(maxSections.getValueI());
156217
boolean infinite = limit >= MAX_SECTIONS_INFINITE;
157218
while(!infinite && points.size() > limit)
158219
points.pollFirst();
@@ -161,17 +222,24 @@ public void onUpdate()
161222
// Track other players if enabled
162223
if(sel == Target.OTHERS || sel == Target.BOTH)
163224
{
225+
int nextIndex = 0;
164226
for(var p : MC.world.getPlayers())
165227
{
166228
if(p == MC.player)
167229
continue;
168230
UUID id = p.getUuid();
169-
// assign a color if needed
170-
if(randomBrightColors.isChecked()
171-
&& !playerColors.containsKey(id))
231+
// assign a color if needed via central registry
232+
if(randomBrightColors.isChecked())
172233
{
173-
playerColors.put(id,
174-
generateBrightColor(playerColors.size()));
234+
java.awt.Color assigned =
235+
net.wurstclient.util.PlayerColorRegistry.get(id);
236+
if(assigned == null)
237+
{
238+
// assign deterministically so all features agree on
239+
// the color for this player
240+
net.wurstclient.util.PlayerColorRegistry
241+
.assignDeterministic(id, "Breadcrumbs");
242+
}
175243
}
176244
Deque<Vec3d> dq =
177245
otherPoints.computeIfAbsent(id, k -> new ArrayDeque<>());
@@ -185,7 +253,7 @@ public void onUpdate()
185253
if(movedEnough(lastp, pos, sectionLen.getValue()))
186254
{
187255
dq.add(pos);
188-
int limit = maxSections.getValueI();
256+
int limit = computeMaxSections(maxSections.getValueI());
189257
boolean infinite = limit >= MAX_SECTIONS_INFINITE;
190258
while(!infinite && dq.size() > limit)
191259
dq.pollFirst();
@@ -194,14 +262,40 @@ public void onUpdate()
194262
// Remove trails for players that left, unless user chose to keep
195263
if(!keepOthersOnLeave.isChecked())
196264
{
197-
otherPoints.keySet().removeIf(uuid -> {
198-
boolean gone = MC.world.getPlayerByUuid(uuid) == null;
199-
if(gone)
200-
playerColors.remove(uuid);
201-
return gone;
265+
otherPoints.keySet()
266+
.removeIf(uuid -> MC.world.getPlayerByUuid(uuid) == null);
267+
// If not keeping trails we also remove registry entries
268+
otherPoints.keySet().forEach(uuid -> {
269+
if(MC.world.getPlayerByUuid(uuid) == null)
270+
net.wurstclient.util.PlayerColorRegistry.remove(uuid);
202271
});
203272
}
204273
}
274+
275+
// If the random toggle was turned off, remove Breadcrumbs-owned
276+
// registry
277+
// entries so other hacks can take over colors.
278+
boolean curRandom = randomBrightColors.isChecked();
279+
if(prevRandom && !curRandom)
280+
{
281+
net.wurstclient.util.PlayerColorRegistry
282+
.removeByOwner("Breadcrumbs");
283+
}
284+
prevRandom = curRandom;
285+
}
286+
287+
/**
288+
* Map the slider value to an actual max sections value. Values up to
289+
* 1000 are linear; values above 1000 scale up exponentially to allow
290+
* very large values without losing slider precision.
291+
*/
292+
private int computeMaxSections(int sliderIndex)
293+
{
294+
if(sliderIndex < 0)
295+
return SECTIONS_MAP[0];
296+
if(sliderIndex >= SECTIONS_MAP.length)
297+
return SECTIONS_MAP[SECTIONS_MAP.length - 1];
298+
return SECTIONS_MAP[sliderIndex];
205299
}
206300

207301
@Override
@@ -230,8 +324,10 @@ public void onRender(MatrixStack matrixStack, float partialTicks)
230324
int oc;
231325
if(randomBrightColors.isChecked())
232326
{
233-
Color col =
234-
playerColors.getOrDefault(id, otherColor.getColor());
327+
java.awt.Color col =
328+
net.wurstclient.util.PlayerColorRegistry.get(id);
329+
if(col == null)
330+
col = otherColor.getColor();
235331
oc = RenderUtils
236332
.toIntColor(
237333
new float[]{col.getRed() / 255f,
@@ -281,10 +377,4 @@ private Color generateBrightColor(int index)
281377
return new Color(r, g, bl);
282378
}
283379

284-
private boolean movedEnough(Vec3d a, Vec3d b, double min)
285-
{
286-
return MathHelper.abs((float)(a.x - b.x)) >= min
287-
|| MathHelper.abs((float)(a.y - b.y)) >= min
288-
|| MathHelper.abs((float)(a.z - b.z)) >= min;
289-
}
290380
}

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

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
import net.wurstclient.settings.filterlists.EntityFilterList;
3030
import net.wurstclient.settings.filters.FilterInvisibleSetting;
3131
import net.wurstclient.settings.filters.FilterSleepingSetting;
32+
import net.wurstclient.settings.ColorSetting;
33+
import java.awt.Color;
34+
import net.wurstclient.settings.CheckboxSetting;
3235
import net.wurstclient.util.EntityUtils;
3336
import net.wurstclient.util.FakePlayerEntity;
3437
import net.wurstclient.util.RenderUtils;
@@ -51,12 +54,40 @@ public final class PlayerEspHack extends Hack implements UpdateListener,
5154
new FilterInvisibleSetting("Won't show invisible players.", false));
5255

5356
private final ArrayList<PlayerEntity> players = new ArrayList<>();
57+
private final CheckboxSetting randomBrightColors = new CheckboxSetting(
58+
"Unique colors for players",
59+
"When enabled, assigns each player a bright color from a shared\n"
60+
+ "palette and forces it into the shared color registry.\n"
61+
+ "PlayerESP takes ownership of these colors (overrides Breadcrumbs).",
62+
false);
63+
private final CheckboxSetting filledBoxes = new CheckboxSetting(
64+
"Filled boxes",
65+
"When enabled, renders solid filled boxes instead of outlined boxes.",
66+
false);
67+
private final CheckboxSetting useStaticPlayerColor = new CheckboxSetting(
68+
"Use static player color",
69+
"When enabled, uses the selected static color for all players and\n"
70+
+ "forces it into the shared color registry. PlayerESP owns the\n"
71+
+ "assignment while this is enabled (will override Breadcrumbs).",
72+
false);
73+
private final ColorSetting playerColor = new ColorSetting("Player color",
74+
"Static color used when 'Use static player color' is enabled.",
75+
new Color(255, 196, 64));
76+
private final net.wurstclient.settings.SliderSetting filledAlpha =
77+
new net.wurstclient.settings.SliderSetting("Filled box alpha", 35, 0,
78+
100, 1,
79+
net.wurstclient.settings.SliderSetting.ValueDisplay.INTEGER);
5480

5581
public PlayerEspHack()
5682
{
5783
super("PlayerESP");
5884
setCategory(Category.RENDER);
5985
addSetting(style);
86+
addSetting(randomBrightColors);
87+
addSetting(filledBoxes);
88+
addSetting(filledAlpha);
89+
addSetting(useStaticPlayerColor);
90+
addSetting(playerColor);
6091
addSetting(boxSize);
6192
entityFilters.forEach(this::addSetting);
6293
}
@@ -113,10 +144,32 @@ public void onRender(MatrixStack matrixStack, float partialTicks)
113144
{
114145
Box box = EntityUtils.getLerpedBox(e, partialTicks)
115146
.offset(0, extraSize, 0).expand(extraSize);
116-
boxes.add(new ColoredBox(box, getColor(e)));
147+
int col = getColor(e);
148+
boxes.add(new ColoredBox(box, col));
117149
}
118150

119-
RenderUtils.drawOutlinedBoxes(matrixStack, boxes, false);
151+
if(filledBoxes.isChecked())
152+
{
153+
// Draw semi-transparent filled boxes, then draw opaque
154+
// outlines on top
155+
ArrayList<ColoredBox> solid = new ArrayList<>(boxes.size());
156+
ArrayList<ColoredBox> outline = new ArrayList<>(boxes.size());
157+
for(ColoredBox cb : boxes)
158+
{
159+
int base = cb.color();
160+
int solidAlpha =
161+
(int)((filledAlpha.getValue() / 100f) * 255) << 24;
162+
int solidColor = (base & 0x00FFFFFF) | solidAlpha;
163+
solid.add(new ColoredBox(cb.box(), solidColor));
164+
int outlineColor = (base & 0x00FFFFFF) | (0xFF << 24);
165+
outline.add(new ColoredBox(cb.box(), outlineColor));
166+
}
167+
RenderUtils.drawSolidBoxes(matrixStack, solid, false);
168+
RenderUtils.drawOutlinedBoxes(matrixStack, outline, false);
169+
}else
170+
{
171+
RenderUtils.drawOutlinedBoxes(matrixStack, boxes, false);
172+
}
120173
}
121174

122175
if(style.hasLines())
@@ -137,6 +190,59 @@ private int getColor(PlayerEntity e)
137190
{
138191
if(WURST.getFriends().contains(e.getName().getString()))
139192
return 0x800000FF;
193+
// If PlayerESP enforces a static color, force it into the registry so
194+
// PlayerESP always overrides Breadcrumbs. Return that color.
195+
if(useStaticPlayerColor.isChecked())
196+
{
197+
java.awt.Color pc = playerColor.getColor();
198+
net.wurstclient.util.PlayerColorRegistry.forceAssign(e.getUuid(),
199+
pc, "PlayerESP");
200+
return RenderUtils.toIntColor(new float[]{pc.getRed() / 255f,
201+
pc.getGreen() / 255f, pc.getBlue() / 255f}, 0.85F);
202+
}
203+
204+
// If PlayerESP requests random bright colors, generate one
205+
// deterministically and force-assign it so PlayerESP overrides
206+
// Breadcrumbs.
207+
if(randomBrightColors.isChecked())
208+
{
209+
int idx = Math.abs(e.getUuid().hashCode());
210+
java.awt.Color gen = net.wurstclient.util.PlayerColorRegistry
211+
.generateBrightColor(idx);
212+
net.wurstclient.util.PlayerColorRegistry.forceAssign(e.getUuid(),
213+
gen, "PlayerESP");
214+
return RenderUtils.toIntColor(new float[]{gen.getRed() / 255f,
215+
gen.getGreen() / 255f, gen.getBlue() / 255f}, 0.9F);
216+
}
217+
218+
// If neither static nor random are enabled, remove any PlayerESP-owned
219+
// registry entries so other hacks' colors can show. Then fall back to
220+
// dynamic distance-based coloring.
221+
if(!useStaticPlayerColor.isChecked() && !randomBrightColors.isChecked())
222+
{
223+
// remove all registry assignments owned by PlayerESP
224+
net.wurstclient.util.PlayerColorRegistry.removeByOwner("PlayerESP");
225+
// Continue to distance-based dynamic coloring below
226+
}
227+
228+
// Only consult the shared registry when PlayerESP has explicitly opted
229+
// into owning colors. This prevents Breadcrumbs (or other hacks)
230+
// changing PlayerESP colors unexpectedly.
231+
if(useStaticPlayerColor.isChecked() || randomBrightColors.isChecked())
232+
{
233+
java.awt.Color reg2 =
234+
net.wurstclient.util.PlayerColorRegistry.get(e.getUuid());
235+
if(reg2 != null)
236+
{
237+
return RenderUtils
238+
.toIntColor(
239+
new float[]{reg2.getRed() / 255f,
240+
reg2.getGreen() / 255f, reg2.getBlue() / 255f},
241+
0.9F);
242+
}
243+
}
244+
245+
// Otherwise fall back to the dynamic distance-based coloring (default).
140246

141247
float f = MC.player.distanceTo(e) / 20F;
142248
float r = MathHelper.clamp(2 - f, 0, 1);

0 commit comments

Comments
 (0)