Skip to content

Commit 9948e3f

Browse files
committed
Shelf Support in ItemESP & ItemHandler
1 parent bcf465e commit 9948e3f

12 files changed

Lines changed: 1239 additions & 362 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
@@ -2034,10 +2034,10 @@ private void sortFavoritesWindow(Window window)
20342034
// sort by feature name when possible
20352035
all.sort((c1, c2) -> {
20362036
String n1 = c1 instanceof FeatureButton
2037-
? ((FeatureButton)c1).getFeature().getName()
2037+
? getFeatureSortName(((FeatureButton)c1).getFeature())
20382038
: c1.getClass().getName();
20392039
String n2 = c2 instanceof FeatureButton
2040-
? ((FeatureButton)c2).getFeature().getName()
2040+
? getFeatureSortName(((FeatureButton)c2).getFeature())
20412041
: c2.getClass().getName();
20422042
return n1.compareToIgnoreCase(n2);
20432043
});
@@ -2064,10 +2064,10 @@ private void sortWindowByFeatureName(Window window)
20642064

20652065
all.sort((c1, c2) -> {
20662066
String n1 = c1 instanceof FeatureButton
2067-
? ((FeatureButton)c1).getFeature().getName()
2067+
? getFeatureSortName(((FeatureButton)c1).getFeature())
20682068
: c1.getClass().getName();
20692069
String n2 = c2 instanceof FeatureButton
2070-
? ((FeatureButton)c2).getFeature().getName()
2070+
? getFeatureSortName(((FeatureButton)c2).getFeature())
20712071
: c2.getClass().getName();
20722072
return n1.compareToIgnoreCase(n2);
20732073
});
@@ -2079,4 +2079,13 @@ private void sortWindowByFeatureName(Window window)
20792079

20802080
window.pack();
20812081
}
2082+
2083+
private static String getFeatureSortName(Feature feature)
2084+
{
2085+
String name = feature.getName();
2086+
if(name != null && name.startsWith("."))
2087+
return name.substring(1);
2088+
2089+
return name;
2090+
}
20822091
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public AutoBuildCmd()
2323
super("autobuild",
2424
"Selects an AutoBuild template by file name and enables AutoBuild.",
2525
".autobuild <template>");
26-
setCategory(Category.OTHER);
26+
setCategory(Category.BLOCKS);
2727
}
2828

2929
@Override

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(
@@ -687,12 +692,7 @@ public void onRender(PoseStack matrixStack, float partialTicks)
687692
}
688693
}
689694

690-
// update count for HackList from final filtered/drawn data only
691-
int displayedCount =
692-
normalBoxes.size() + specialBoxes.size() + tracedBoxes.size();
693-
foundCount = Math.min(displayedCount, 999);
694-
695-
// Item frames holding special items
695+
// Item frames and shelves holding special items
696696
if(includeItemFrames.isChecked())
697697
{
698698
for(Entity ent : MC.level.entitiesForRendering())
@@ -714,6 +714,36 @@ public void onRender(PoseStack matrixStack, float partialTicks)
714714
specialBoxes.add(fbox);
715715
specialEnds.add(fbox.getCenter());
716716
}
717+
718+
ChunkUtils.getLoadedBlockEntities().forEach(be -> {
719+
if(!(be instanceof ShelfBlockEntity shelf))
720+
return;
721+
722+
List<ItemStack> shelfItems = shelf.getItems();
723+
for(int slot = 0; slot < shelfItems.size(); slot++)
724+
{
725+
ItemStack shelfStack = shelfItems.get(slot);
726+
if(shelfStack == null || shelfStack.isEmpty())
727+
continue;
728+
if(isIgnored(shelfStack))
729+
continue;
730+
if(!isSpecial(shelfStack))
731+
continue;
732+
733+
Vec3 itemPos = ShelfUtils.getItemPosition(shelf, slot);
734+
if(itemPos == null)
735+
continue;
736+
if(onlyAboveGround.isChecked()
737+
&& itemPos.y < aboveGroundY.getValue())
738+
continue;
739+
740+
AABB box = smallBoxAt(itemPos);
741+
if(box == null)
742+
continue;
743+
specialBoxes.add(box);
744+
specialEnds.add(box.getCenter());
745+
}
746+
});
717747
}
718748

719749
// Equipped specials (held or head) on entities
@@ -785,6 +815,10 @@ && isSpecial(head))
785815
}
786816
}
787817

818+
int displayedCount =
819+
normalBoxes.size() + specialBoxes.size() + tracedBoxes.size();
820+
foundCount = Math.min(displayedCount, 999);
821+
788822
if(style.hasBoxes())
789823
{
790824
// 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.gui.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)