Skip to content

Commit c5a56a0

Browse files
committed
Shelf Support in ItemESP & ItemHandler, New Preset
1 parent 2aed46c commit c5a56a0

11 files changed

Lines changed: 1240 additions & 361 deletions

File tree

src/main/java/net/wurstclient/clickgui/ClickGui.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,10 +2043,10 @@ private void sortFavoritesWindow(Window window)
20432043
// sort by feature name when possible
20442044
all.sort((c1, c2) -> {
20452045
String n1 = c1 instanceof FeatureButton
2046-
? ((FeatureButton)c1).getFeature().getName()
2046+
? getFeatureSortName(((FeatureButton)c1).getFeature())
20472047
: c1.getClass().getName();
20482048
String n2 = c2 instanceof FeatureButton
2049-
? ((FeatureButton)c2).getFeature().getName()
2049+
? getFeatureSortName(((FeatureButton)c2).getFeature())
20502050
: c2.getClass().getName();
20512051
return n1.compareToIgnoreCase(n2);
20522052
});
@@ -2073,10 +2073,10 @@ private void sortWindowByFeatureName(Window window)
20732073

20742074
all.sort((c1, c2) -> {
20752075
String n1 = c1 instanceof FeatureButton
2076-
? ((FeatureButton)c1).getFeature().getName()
2076+
? getFeatureSortName(((FeatureButton)c1).getFeature())
20772077
: c1.getClass().getName();
20782078
String n2 = c2 instanceof FeatureButton
2079-
? ((FeatureButton)c2).getFeature().getName()
2079+
? getFeatureSortName(((FeatureButton)c2).getFeature())
20802080
: c2.getClass().getName();
20812081
return n1.compareToIgnoreCase(n2);
20822082
});
@@ -2088,4 +2088,13 @@ private void sortWindowByFeatureName(Window window)
20882088

20892089
window.pack();
20902090
}
2091+
2092+
private static String getFeatureSortName(Feature feature)
2093+
{
2094+
String name = feature.getName();
2095+
if(name != null && name.startsWith("."))
2096+
return name.substring(1);
2097+
2098+
return name;
2099+
}
20912100
}

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ public final class MapaCmd extends Command
2222
{
2323
public MapaCmd()
2424
{
25-
super("mapa", "Controls the integrated Mapa minimap.", ".mapa",
26-
".mapa open", ".mapa reset", ".mapa toggle",
27-
".mapa enabled <true|false>", ".mapa size <72-256>",
25+
super("mapa",
26+
"Controls the integrated Mapa minimap.\nBare .mapa toggles it.",
27+
".mapa", ".mapa show", ".mapa status", ".mapa open", ".mapa reset",
28+
".mapa toggle", ".mapa enabled <true|false>", ".mapa size <72-256>",
2829
".mapa zoom <0.25-10>", ".mapa samples <32-512>",
2930
".mapa textScale <0.5-4>", ".mapa pos <x> <y>",
3031
".mapa rotate <true|false>", ".mapa underground <true|false>",
@@ -47,7 +48,14 @@ public void call(String[] args) throws CmdException
4748
{
4849
MapaHack mapa = WURST.getHax().mapaHack;
4950

50-
if(args.length == 0 || equalsAny(args[0], "show", "status"))
51+
if(args.length == 0)
52+
{
53+
mapa.setEnabled(!mapa.isEnabled());
54+
ChatUtils.message("Mapa enabled set to " + mapa.isEnabled() + ".");
55+
return;
56+
}
57+
58+
if(equalsAny(args[0], "show", "status"))
5159
{
5260
ChatUtils.message(statusLine(mapa));
5361
return;

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

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.util.ArrayList;
1313
import java.util.Arrays;
1414
import java.util.HashSet;
15+
import java.util.List;
1516
import java.util.Locale;
1617
import net.minecraft.client.gui.Font;
1718
import net.minecraft.client.gui.GuiGraphicsExtractor;
@@ -30,6 +31,7 @@
3031
import net.minecraft.world.entity.player.Player;
3132
import net.minecraft.world.item.Item;
3233
import net.minecraft.world.item.ItemStack;
34+
import net.minecraft.world.level.block.entity.ShelfBlockEntity;
3335
import net.minecraft.world.phys.AABB;
3436
import net.minecraft.world.phys.Vec3;
3537
import net.wurstclient.Category;
@@ -49,6 +51,8 @@
4951
import net.wurstclient.util.EntityUtils;
5052
import net.wurstclient.util.EspLimitUtils;
5153
import net.wurstclient.util.RenderUtils;
54+
import net.wurstclient.util.ShelfUtils;
55+
import net.wurstclient.util.chunk.ChunkUtils;
5256

5357
@SearchTags({"item esp", "ItemTracers", "item tracers"})
5458
public final class ItemEspHack extends Hack implements UpdateListener,
@@ -144,9 +148,10 @@ private enum XpMode
144148
XpMode.values(), XpMode.NORMAL);
145149

146150
// New: include item frames holding special items
147-
private final CheckboxSetting includeItemFrames =
148-
new CheckboxSetting("Highlight frames with special",
149-
"Also highlight item frames if the item inside is special.", true);
151+
private final CheckboxSetting includeItemFrames = new CheckboxSetting(
152+
"Highlight frames with special",
153+
"Also highlight item frames and shelves if the displayed item is special.",
154+
true);
150155

151156
// New: optionally show detected count in HackList
152157
private final CheckboxSetting showCountInHackList = new CheckboxSetting(
@@ -666,12 +671,7 @@ public void onRender(PoseStack matrixStack, float partialTicks)
666671
}
667672
}
668673

669-
// update count for HackList from final filtered/drawn data only
670-
int displayedCount =
671-
normalBoxes.size() + specialBoxes.size() + tracedBoxes.size();
672-
foundCount = Math.min(displayedCount, 999);
673-
674-
// Item frames holding special items
674+
// Item frames and shelves holding special items
675675
if(includeItemFrames.isChecked())
676676
{
677677
for(Entity ent : MC.level.entitiesForRendering())
@@ -693,6 +693,36 @@ public void onRender(PoseStack matrixStack, float partialTicks)
693693
specialBoxes.add(fbox);
694694
specialEnds.add(fbox.getCenter());
695695
}
696+
697+
ChunkUtils.getLoadedBlockEntities().forEach(be -> {
698+
if(!(be instanceof ShelfBlockEntity shelf))
699+
return;
700+
701+
List<ItemStack> shelfItems = shelf.getItems();
702+
for(int slot = 0; slot < shelfItems.size(); slot++)
703+
{
704+
ItemStack shelfStack = shelfItems.get(slot);
705+
if(shelfStack == null || shelfStack.isEmpty())
706+
continue;
707+
if(isIgnored(shelfStack))
708+
continue;
709+
if(!isSpecial(shelfStack))
710+
continue;
711+
712+
Vec3 itemPos = ShelfUtils.getItemPosition(shelf, slot);
713+
if(itemPos == null)
714+
continue;
715+
if(onlyAboveGround.isChecked()
716+
&& itemPos.y < aboveGroundY.getValue())
717+
continue;
718+
719+
AABB box = smallBoxAt(itemPos);
720+
if(box == null)
721+
continue;
722+
specialBoxes.add(box);
723+
specialEnds.add(box.getCenter());
724+
}
725+
});
696726
}
697727

698728
// Equipped specials (held or head) on entities
@@ -764,6 +794,10 @@ && isSpecial(head))
764794
}
765795
}
766796

797+
int displayedCount =
798+
normalBoxes.size() + specialBoxes.size() + tracedBoxes.size();
799+
foundCount = Math.min(displayedCount, 999);
800+
767801
if(style.hasBoxes())
768802
{
769803
// Normal items: always draw with base color

src/main/java/net/wurstclient/hacks/itemhandler/ItemHandlerHack.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.Set;
2323
import java.util.UUID;
2424
import java.util.LinkedHashSet;
25+
import java.nio.charset.StandardCharsets;
2526
import java.lang.reflect.Method;
2627
import net.minecraft.client.gui.screens.Screen;
2728
import net.minecraft.client.player.LocalPlayer;
@@ -46,6 +47,7 @@
4647
import net.minecraft.world.item.enchantment.Enchantment;
4748
import net.minecraft.world.item.enchantment.ItemEnchantments;
4849
import net.minecraft.world.level.block.entity.BlockEntity;
50+
import net.minecraft.world.level.block.entity.ShelfBlockEntity;
4951
import net.minecraft.world.level.block.entity.SignBlockEntity;
5052
import net.minecraft.world.level.block.entity.SignText;
5153
import net.minecraft.world.phys.Vec3;
@@ -69,6 +71,7 @@
6971
import it.unimi.dsi.fastutil.objects.Object2IntMap;
7072
// no screen import needed; we embed ItemESP's editor component directly
7173
import net.wurstclient.util.InventoryUtils;
74+
import net.wurstclient.util.ShelfUtils;
7275
import net.wurstclient.util.chunk.ChunkUtils;
7376

7477
public class ItemHandlerHack extends Hack
@@ -591,6 +594,8 @@ private void scanNearbyItems()
591594
distance, frame.position(), SourceType.ITEM_FRAME, null));
592595
}
593596

597+
addTrackedShelfItems(player, scanRadius);
598+
594599
if(includeMobEquipment.isChecked())
595600
addMobEquipmentItems(player, scanRadius);
596601

@@ -600,6 +605,43 @@ private void scanNearbyItems()
600605
// manual toggling should untrace.)
601606
}
602607

608+
private void addTrackedShelfItems(LocalPlayer player, double scanRadius)
609+
{
610+
Vec3 playerPos = player.position();
611+
double scanRadiusSq =
612+
scanRadius >= INFINITE_SCAN_RADIUS ? -1 : scanRadius * scanRadius;
613+
614+
ChunkUtils.getLoadedBlockEntities().forEach(be -> {
615+
if(!(be instanceof ShelfBlockEntity shelf))
616+
return;
617+
618+
Vec3 shelfCenter = shelf.position();
619+
if(scanRadiusSq >= 0
620+
&& shelfCenter.distanceToSqr(playerPos) > scanRadiusSq)
621+
return;
622+
623+
BlockPos shelfPos = shelf.getBlockPos();
624+
List<ItemStack> shelfItems = shelf.getItems();
625+
for(int slot = 0; slot < shelfItems.size(); slot++)
626+
{
627+
ItemStack stack = shelfItems.get(slot);
628+
if(stack == null || stack.isEmpty())
629+
continue;
630+
if(isIgnoredByItemEsp(stack))
631+
continue;
632+
633+
Vec3 itemPos = ShelfUtils.getItemPosition(shelf, slot);
634+
if(itemPos == null)
635+
itemPos = shelfCenter;
636+
double distance = itemPos.distanceTo(playerPos);
637+
trackedItems
638+
.add(new GroundItem(getShelfSlotEntityId(shelfPos, slot),
639+
getShelfSlotUuid(shelfPos, slot), stack.copy(),
640+
distance, itemPos, SourceType.SHELF, null));
641+
}
642+
});
643+
}
644+
603645
private void scanNearbySigns()
604646
{
605647
boolean guiOpen = MC.screen instanceof ItemHandlerScreen;
@@ -1348,6 +1390,8 @@ public String traceId()
13481390
}
13491391
if(sourceType == SourceType.ITEM_FRAME)
13501392
return baseId + ":item_frame";
1393+
if(sourceType == SourceType.SHELF)
1394+
return baseId + ":shelf";
13511395
return baseId;
13521396
}
13531397

@@ -1359,6 +1403,8 @@ public String sourceLabel()
13591403
return "worn by " + (sourceName != null ? sourceName : "mob");
13601404
if(sourceType == SourceType.ITEM_FRAME)
13611405
return "in item frame";
1406+
if(sourceType == SourceType.SHELF)
1407+
return "in shelf";
13621408
return "";
13631409
}
13641410

@@ -1541,10 +1587,26 @@ public enum SourceType
15411587
GROUND,
15421588
XP_ORB,
15431589
ITEM_FRAME,
1590+
SHELF,
15441591
MOB_HELD,
15451592
MOB_WORN
15461593
}
15471594

1595+
private static int getShelfSlotEntityId(BlockPos pos, int slot)
1596+
{
1597+
int hash = Long
1598+
.hashCode(pos.asLong() ^ ((long)slot + 1L) * 0x9E3779B97F4A7C15L);
1599+
if(hash == 0)
1600+
return Integer.MIN_VALUE;
1601+
return hash > 0 ? -hash : hash;
1602+
}
1603+
1604+
private static UUID getShelfSlotUuid(BlockPos pos, int slot)
1605+
{
1606+
String key = "shelf:" + pos.asLong() + ":" + slot;
1607+
return UUID.nameUUIDFromBytes(key.getBytes(StandardCharsets.UTF_8));
1608+
}
1609+
15481610
private static String getCraftedEntityTraceId(UUID uuid)
15491611
{
15501612
if(uuid == null)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) 2014-2026 Wurst-Imperium and contributors.
3+
*
4+
* This source code is subject to the terms of the GNU General Public
5+
* License, version 3. If a copy of the GPL was not distributed with this
6+
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
7+
*/
8+
package net.wurstclient.util;
9+
10+
import net.minecraft.core.Direction;
11+
import net.minecraft.world.level.block.ShelfBlock;
12+
import net.minecraft.world.level.block.entity.ShelfBlockEntity;
13+
import net.minecraft.world.phys.Vec3;
14+
15+
public enum ShelfUtils
16+
{
17+
;
18+
19+
public static Vec3 getItemPosition(ShelfBlockEntity shelf, int slot)
20+
{
21+
if(shelf == null)
22+
return null;
23+
24+
double itemSlotPosition = (slot - 1) * 0.3125;
25+
Vec3 itemOffset = new Vec3(itemSlotPosition,
26+
shelf.getAlignItemsToBottom() ? -0.25 : 0.0, -0.25);
27+
Direction facing =
28+
(Direction)shelf.getBlockState().getValue(ShelfBlock.FACING);
29+
float yRot =
30+
facing.getAxis().isHorizontal() ? -facing.toYRot() : 180.0F;
31+
return shelf.position().add(rotateY(itemOffset, yRot));
32+
}
33+
34+
private static Vec3 rotateY(Vec3 offset, float degrees)
35+
{
36+
double radians = Math.toRadians(degrees);
37+
double sin = Math.sin(radians);
38+
double cos = Math.cos(radians);
39+
return new Vec3(offset.x * cos + offset.z * sin, offset.y,
40+
offset.z * cos - offset.x * sin);
41+
}
42+
}

0 commit comments

Comments
 (0)