Skip to content

Commit 5b6bb69

Browse files
committed
Updated Waypoints
1 parent 463c56b commit 5b6bb69

5 files changed

Lines changed: 508 additions & 7 deletions

File tree

README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ I did not, nor could I copy their code directly as most are Meteor based mods. S
174174

175175
### Waypoints
176176
- Create and save waypoints, with optional automatic death waypoints for all players.
177-
- Manager UI (`.waypoints` or apostrophe key).
177+
- Manager UI (`.waypoints` or apostrophe key) which sorts, highlights and filters waypoints.
178178
- Compass overlay: Show a bar at the top of the screen that shows the waypoint icons in your field of view
179179
- Shows names of waypoints when you're directly facing them
180180
- Adjustable position and transparency
@@ -190,6 +190,27 @@ I did not, nor could I copy their code directly as most are Meteor based mods. S
190190
- Adjustable Tri-state Beacon Mode on waypoints (On/Off/ESP) that matches the waypoint's color.
191191
- Toggleable automatic portal logging, logs numerically each portal you enter and matches it in the opposite dimension with the same number.
192192

193+
194+
#### Waypoint Commands
195+
196+
Create a waypoint at the given coords (player position used when coords omitted).
197+
198+
Set color, icon, visibility, line/beacon behavior, auto-action when near, max visible distance and label scale.
199+
200+
```.waypoint add <name> [x=<int>] [y=<int>] [z=<int>] [dim=<overworld|nether|end>] [color=<#RRGGBB|#AARRGGBB>] [icon=<square|circle|triangle|star|diamond|skull|heart|check|x|arrow_down|sun|snowflake>] [visible=<true|false>] [lines=<true|false>] [opposite=<true|false>] [beacon=<off|solid|esp>] [action=<disabled|hide|delete>] [actiondist=<int>] [maxvisible=<int>] [scale=<decimal>]```
201+
202+
#### Radius command
203+
204+
Modify or remove waypoints within <radius> blocks of the player (current dimension only).
205+
206+
```.waypoint radius <radius> [key=value ...] (alias: setradius)```
207+
208+
Common keys: delete/remove, clear, color=<hex>, visible=<bool>, lines=<bool>, beacon=<mode>, maxvisible=<int>, icon=<name>.
209+
210+
Booleans: true/false/1/0/yes/no/on/off. Color accepts leading # or 0x; 6‑digit -> opaque.
211+
212+
Reports number of waypoints changed.
213+
193214
![WayPoints](https://i.imgur.com/dxFc17N.png) ![Waypoint Manager](https://i.imgur.com/K2xGVqc.png) ![Waypoint Editor](https://i.imgur.com/23i14s1.png)
194215

195216
### Chest Search

src/main/java/net/wurstclient/clickgui/screens/WaypointsScreen.java

Lines changed: 192 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ public final class WaypointsScreen extends Screen
4646
// Dimension filter (null = show all)
4747
private net.wurstclient.waypoints.WaypointDimension filterDim = null;
4848

49+
private static enum SortMode
50+
{
51+
DATE,
52+
NEAREST,
53+
FURTHEST,
54+
NAME
55+
}
56+
57+
private SortMode sortMode = SortMode.DATE;
58+
4959
// One row = 4 buttons. We keep references so we can reposition & toggle
5060
// visibility.
5161
private static final class RowWidgets
@@ -62,6 +72,7 @@ private static final class RowWidgets
6272
// Persisted scroll per-world+dimension so returning keeps the same
6373
// position even if a new screen instance was created.
6474
private static final Map<String, Integer> savedScrolls = new HashMap<>();
75+
private static final Map<String, SortMode> savedSortModes = new HashMap<>();
6576

6677
private void saveScrollState()
6778
{
@@ -70,6 +81,7 @@ private void saveScrollState()
7081
String key = resolveWorldId() + ":"
7182
+ (filterDim == null ? "ALL" : filterDim.name());
7283
savedScrolls.put(key, scroll);
84+
savedSortModes.put(key, sortMode);
7385
}catch(Exception ignored)
7486
{}
7587
}
@@ -172,6 +184,39 @@ protected void init()
172184
if(filterDim == null || w.getDimension() == filterDim)
173185
cachedList.add(w);
174186
}
187+
188+
// Apply sorting
189+
switch(sortMode)
190+
{
191+
case DATE -> cachedList.sort(
192+
(a, b) -> Long.compare(b.getCreatedAt(), a.getCreatedAt()));
193+
case NAME -> cachedList
194+
.sort((a, b) -> a.getName().compareToIgnoreCase(b.getName()));
195+
case NEAREST ->
196+
{
197+
if(minecraft.player != null)
198+
{
199+
BlockPos playerPos =
200+
BlockPos.containing(minecraft.player.getX(),
201+
minecraft.player.getY(), minecraft.player.getZ());
202+
cachedList.sort(
203+
(a, b) -> Double.compare(a.getPos().distSqr(playerPos),
204+
b.getPos().distSqr(playerPos)));
205+
}
206+
}
207+
case FURTHEST ->
208+
{
209+
if(minecraft.player != null)
210+
{
211+
BlockPos playerPos =
212+
BlockPos.containing(minecraft.player.getX(),
213+
minecraft.player.getY(), minecraft.player.getZ());
214+
cachedList.sort(
215+
(a, b) -> Double.compare(b.getPos().distSqr(playerPos),
216+
a.getPos().distSqr(playerPos)));
217+
}
218+
}
219+
}
175220
listStartY = y;
176221

177222
// Determine viewport for the list (space until the Back button line)
@@ -186,6 +231,9 @@ protected void init()
186231
Integer s = savedScrolls.get(key);
187232
if(s != null)
188233
scroll = s;
234+
SortMode sm = savedSortModes.get(key);
235+
if(sm != null)
236+
sortMode = sm;
189237
}catch(Exception ignored)
190238
{}
191239

@@ -263,9 +311,26 @@ protected void init()
263311
scrollToBottom();
264312
}).bounds(arrowX + 20, viewportBottom, 20, 20).build());
265313

314+
// Back button (smaller) and Sort button on same line
315+
int backWidth = 200;
316+
int sortWidth = 90;
317+
addRenderableWidget(
318+
Button.builder(Component.literal("Sort: " + sortMode.name()), b -> {
319+
// cycle sort modes
320+
sortMode = switch(sortMode)
321+
{
322+
case DATE -> SortMode.NEAREST;
323+
case NEAREST -> SortMode.FURTHEST;
324+
case FURTHEST -> SortMode.NAME;
325+
default -> SortMode.DATE;
326+
};
327+
saveScrollState();
328+
minecraft.setScreen(this);
329+
}).bounds(x, this.height - 28, sortWidth, 20).build());
266330
addRenderableWidget(Button
267331
.builder(Component.literal("Back"), b -> minecraft.setScreen(prev))
268-
.bounds(x, this.height - 28, 300, 20).build());
332+
.bounds(x + sortWidth + 10, this.height - 28, backWidth, 20)
333+
.build());
269334
}
270335

271336
private void scrollBy(int dy)
@@ -412,12 +477,58 @@ public void render(GuiGraphics context, int mouseX, int mouseY, float delta)
412477
rw.copyBtn.visible = visible;
413478
}
414479

480+
// Hide default button labels for name buttons so we can draw a single
481+
// centered/scrolling label later and avoid duplicate text (built-in
482+
// rendering + our custom rendering causing two copies).
483+
java.util.Map<RowWidgets, Component> _savedLabels =
484+
new java.util.HashMap<>();
485+
for(RowWidgets _rw : rows)
486+
{
487+
if(_rw == null || _rw.nameBtn == null || !_rw.nameBtn.visible)
488+
continue;
489+
_savedLabels.put(_rw, _rw.nameBtn.getMessage());
490+
_rw.nameBtn.setMessage(Component.literal(""));
491+
}
492+
415493
super.render(context, mouseX, mouseY, delta);
416494

495+
// Restore messages so our custom drawing can read them
496+
for(java.util.Map.Entry<RowWidgets, Component> e : _savedLabels
497+
.entrySet())
498+
{
499+
RowWidgets _rw = e.getKey();
500+
if(_rw != null && _rw.nameBtn != null)
501+
_rw.nameBtn.setMessage(e.getValue());
502+
}
503+
417504
// Title
418505
context.drawCenteredString(minecraft.font, "Waypoints", this.width / 2,
419506
12, 0xFFFFFFFF);
420507

508+
// Draw beacon button backgrounds (overlay) and collect line outlines
509+
java.util.List<RowWidgets> lineOutlineRows =
510+
new java.util.ArrayList<>();
511+
for(RowWidgets rw : rows)
512+
{
513+
if(rw == null || rw.nameBtn == null || !rw.nameBtn.visible)
514+
continue;
515+
if(rw.w.hasBeacon())
516+
{
517+
int nameLeft = x; // name button left
518+
int nameTop = rw.nameBtn.getY();
519+
int nameRight = nameLeft + 140; // name button width
520+
int nameBottom = nameTop + 20;
521+
int baseColor = rw.w.getColor();
522+
// overlay with ~40% opacity so button shading remains visible
523+
int overlay = (baseColor & 0x00FFFFFF) | 0x66000000; //
524+
context.fill(nameLeft, nameTop, nameRight, nameBottom, overlay);
525+
// label will be drawn later (consistent scrolling/clip)
526+
{}
527+
}
528+
if(rw.w.isLines())
529+
lineOutlineRows.add(rw);
530+
}
531+
421532
// Draw small color boxes for each saved waypoint next to the name
422533
// Use the same filtered list as the rows to render color boxes and clip
423534
// to viewport
@@ -458,10 +569,90 @@ public void render(GuiGraphics context, int mouseX, int mouseY, float delta)
458569
0xFF333333);
459570
// fill
460571
context.fill(boxLeft, boxY, boxLeft + 16, boxY + 16, color);
572+
461573
}
462574

463575
context.disableScissor();
464576

577+
// Draw line outlines collected earlier (use waypoint color and clamp to
578+
// screen to avoid cut-off)
579+
for(RowWidgets rw : lineOutlineRows)
580+
{
581+
if(rw == null || rw.nameBtn == null || !rw.nameBtn.visible)
582+
continue;
583+
int nameLeft = x;
584+
int nameTop = rw.nameBtn.getY();
585+
int nameRight = nameLeft + 140;
586+
int nameBottom = nameTop + 20;
587+
int stroke = rw.w.getColor();
588+
int top = Math.max(0, nameTop - 1);
589+
int bottom = Math.min(this.height, nameBottom + 1);
590+
if(top >= bottom)
591+
continue;
592+
// top
593+
context.fill(nameLeft - 1, top, nameRight + 1,
594+
Math.min(bottom, nameTop), stroke);
595+
// bottom
596+
context.fill(nameLeft - 1, Math.max(top, nameBottom), nameRight + 1,
597+
bottom, stroke);
598+
// left
599+
context.fill(nameLeft - 1, top, nameLeft, bottom, stroke);
600+
// right
601+
context.fill(nameRight, top, nameRight + 1, bottom, stroke);
602+
}
603+
604+
// Draw labels for all visible name buttons with clipping and centered
605+
// scrolling
606+
for(RowWidgets rw : rows)
607+
{
608+
if(rw == null || rw.nameBtn == null || !rw.nameBtn.visible)
609+
continue;
610+
int nameLeft = x;
611+
int nameTop = rw.nameBtn.getY();
612+
int nameRight = nameLeft + 140;
613+
int nameBottom = nameTop + 20;
614+
String label = rw.nameBtn.getMessage().getString();
615+
int textWidth = minecraft.font.width(label);
616+
int centerX = (nameLeft + nameRight) / 2;
617+
int maxTextWidth = nameRight - nameLeft - 8; // padding both sides
618+
if(maxTextWidth < 0)
619+
maxTextWidth = 0;
620+
context.enableScissor(nameLeft, nameTop, nameRight, nameBottom);
621+
if(textWidth <= maxTextWidth || maxTextWidth == 0)
622+
{
623+
// draw centered
624+
context.drawCenteredString(minecraft.font, label, centerX,
625+
nameTop + 6, 0xFFFFFFFF);
626+
}else
627+
{
628+
int gap = 20;
629+
int period = textWidth + gap;
630+
long t = System.currentTimeMillis();
631+
int speed = 90; // text scroll, ms pixel
632+
int offset = (int)((t / (long)speed) % period);
633+
int x1 = centerX - textWidth / 2 - offset;
634+
context.drawString(minecraft.font, label, x1, nameTop + 6,
635+
0xFFFFFFFF);
636+
context.drawString(minecraft.font, label, x1 + textWidth + gap,
637+
nameTop + 6, 0xFFFFFFFF);
638+
}
639+
context.disableScissor();
640+
}
641+
642+
// Darken the "Hide" buttons for hidden waypoints with a 25% black
643+
// overlay so they appear darker.
644+
for(RowWidgets _rw : rows)
645+
{
646+
if(_rw == null || _rw.visBtn == null || !_rw.visBtn.visible)
647+
continue;
648+
if(!_rw.w.isVisible())
649+
{
650+
int vx = x + 145;
651+
int vy = _rw.visBtn.getY();
652+
context.fill(vx, vy, vx + 55, vy + 20, 0x66000000);
653+
}
654+
}
655+
465656
// Draw scrollbar track & thumb (to the right of the list area)
466657
int contentHeight = rows.size() * ROW_HEIGHT;
467658
int trackWidth = 8;

src/main/java/net/wurstclient/commands/WaypointCmd.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ public WaypointCmd()
3737
+ ">] [visible=<true|false>] [lines=<true|false>]"
3838
+ " [opposite=<true|false>] [beacon=<off|solid|esp>]"
3939
+ " [action=<disabled|hide|delete>] [actiondist=<int>]"
40-
+ " [maxvisible=<int>] [scale=<decimal>]");
40+
+ " [maxvisible=<int>] [scale=<decimal>]"
41+
+ "\n.waypoint radius <radius> [key=value ...] — modify/remove waypoints within radius around player");
4142
}
4243

4344
@Override
@@ -53,6 +54,11 @@ public void call(String[] args) throws CmdException
5354
handleAdd(Arrays.copyOfRange(args, 1, args.length));
5455
break;
5556

57+
case "setradius":
58+
case "radius":
59+
handleSetRadius(Arrays.copyOfRange(args, 1, args.length));
60+
break;
61+
5662
default:
5763
throw new CmdSyntaxError("Unknown subcommand: " + sub);
5864
}
@@ -142,6 +148,40 @@ private void handleAdd(String[] args) throws CmdException
142148
name, x, y, z, dim.name()));
143149
}
144150

151+
private void handleSetRadius(String[] args) throws CmdException
152+
{
153+
if(args.length == 0)
154+
throw new CmdSyntaxError("Missing radius.");
155+
int radius;
156+
try
157+
{
158+
radius = Integer.parseInt(args[0]);
159+
if(radius < 0)
160+
throw new NumberFormatException();
161+
}catch(NumberFormatException e)
162+
{
163+
throw new CmdError("Invalid radius: " + args[0]);
164+
}
165+
Map<String, String> options = new LinkedHashMap<>();
166+
for(int i = 1; i < args.length; i++)
167+
{
168+
String arg = args[i];
169+
int eq = arg.indexOf('=');
170+
if(eq < 0)
171+
options.put(arg.toLowerCase(Locale.ROOT), "");
172+
else
173+
{
174+
String key = arg.substring(0, eq).toLowerCase(Locale.ROOT);
175+
String value = arg.substring(eq + 1);
176+
options.put(key, value);
177+
}
178+
}
179+
int changed =
180+
WURST.getHax().waypointsHack.applyRadiusCommand(radius, options);
181+
ChatUtils.message("Modified " + changed + " waypoint(s) within radius "
182+
+ radius + ".");
183+
}
184+
145185
private int parseInt(String raw, String key, Integer fallback)
146186
throws CmdException
147187
{

0 commit comments

Comments
 (0)