2727import net .minecraft .core .BlockPos ;
2828import net .minecraft .core .Holder ;
2929import net .minecraft .core .component .DataComponents ;
30+ import net .minecraft .world .Nameable ;
3031import net .minecraft .world .entity .Entity ;
3132import net .minecraft .world .entity .item .ItemEntity ;
3233import net .minecraft .world .entity .ExperienceOrb ;
4142import net .minecraft .world .item .Items ;
4243import net .minecraft .world .item .enchantment .Enchantment ;
4344import net .minecraft .world .item .enchantment .ItemEnchantments ;
45+ import net .minecraft .world .level .block .entity .BlockEntity ;
4446import net .minecraft .world .level .block .entity .SignBlockEntity ;
4547import net .minecraft .world .level .block .entity .SignText ;
4648import net .minecraft .world .phys .Vec3 ;
@@ -99,7 +101,7 @@ public class ItemHandlerHack extends Hack
99101 "_pickaxe" , "_shovel" , "_hoe" , "_spear" };
100102
101103 private final List <GroundItem > trackedItems = new ArrayList <>();
102- private final List <NearbySign > trackedSigns = new ArrayList <>();
104+ private final List <NearbyLabel > trackedLabels = new ArrayList <>();
103105 private int signScanCooldown ;
104106 private final Int2IntOpenHashMap pickupWhitelist = new Int2IntOpenHashMap ();
105107 private final Deque <Integer > pickupQueue = new ArrayDeque <>();
@@ -142,6 +144,10 @@ public class ItemHandlerHack extends Hack
142144 new CheckboxSetting ("Show nearby signs" ,
143145 "Adds nearby sign text to the ItemHandler popup HUD." , false );
144146
147+ private final CheckboxSetting detectNamedEntities =
148+ new CheckboxSetting ("Detect named entities" ,
149+ "Detects custom-named entities (e.g. pets and mobs)." , false );
150+
145151 private final SliderSetting signRange = new SliderSetting ("Sign range" ,
146152 "How far to scan for signs when 'Show nearby signs' is enabled.\n "
147153 + "∞ = all loaded chunks around you (limited by render distance)." ,
@@ -206,6 +212,7 @@ public ItemHandlerHack()
206212 addSetting (popupMaxItems );
207213 addSetting (pinSpecialItemsTop );
208214 addSetting (showSignsInHud );
215+ addSetting (detectNamedEntities );
209216 addSetting (signRange );
210217 addSetting (signMax );
211218 addSetting (hudOffsetX );
@@ -218,7 +225,7 @@ protected void onEnable()
218225 EVENTS .add (UpdateListener .class , this );
219226 EVENTS .add (RenderListener .class , this );
220227 trackedItems .clear ();
221- trackedSigns .clear ();
228+ trackedLabels .clear ();
222229 pickupWhitelist .clear ();
223230 pickupQueue .clear ();
224231 }
@@ -229,7 +236,7 @@ protected void onDisable()
229236 EVENTS .remove (UpdateListener .class , this );
230237 EVENTS .remove (RenderListener .class , this );
231238 trackedItems .clear ();
232- trackedSigns .clear ();
239+ trackedLabels .clear ();
233240 pickupWhitelist .clear ();
234241 pickupQueue .clear ();
235242 stopAutoWalk ();
@@ -246,7 +253,7 @@ public void onUpdate()
246253 if (MC .level == null || MC .player == null )
247254 {
248255 trackedItems .clear ();
249- trackedSigns .clear ();
256+ trackedLabels .clear ();
250257 pickupWhitelist .clear ();
251258 pickupQueue .clear ();
252259 stopAutoWalk ();
@@ -574,15 +581,17 @@ private void scanNearbyItems()
574581 private void scanNearbySigns ()
575582 {
576583 boolean guiOpen = MC .screen instanceof ItemHandlerScreen ;
577- if (!showSignsInHud .isChecked () && !guiOpen )
584+ boolean detectSigns = showSignsInHud .isChecked () || guiOpen ;
585+ boolean detectNamed = detectNamedEntities .isChecked () || guiOpen ;
586+ if (!detectSigns && !detectNamed )
578587 {
579- trackedSigns .clear ();
588+ trackedLabels .clear ();
580589 return ;
581590 }
582591
583592 if (MC .level == null || MC .player == null )
584593 {
585- trackedSigns .clear ();
594+ trackedLabels .clear ();
586595 return ;
587596 }
588597
@@ -591,45 +600,120 @@ private void scanNearbySigns()
591600 return ;
592601 signScanCooldown = 10 ;
593602
594- trackedSigns .clear ();
603+ trackedLabels .clear ();
595604
596605 double range = signRange .getValue ();
597606 boolean infinite = range >= INFINITE_SCAN_RADIUS ;
598607 double rangeSq = range * range ;
599608 Vec3 centerVec = MC .player .position ();
600609
601- ChunkUtils .getLoadedBlockEntities ().forEach (be -> {
602- if (!(be instanceof SignBlockEntity sign ))
603- return ;
604-
605- BlockPos pos = sign .getBlockPos ();
606- if (pos == null )
607- return ;
608-
609- Vec3 p = Vec3 .atCenterOf (pos );
610- double distSq = p .distanceToSqr (centerVec );
611- if (!infinite && distSq > rangeSq )
612- return ;
613-
614- String text = readSignText (sign );
615- if (text .isEmpty ())
616- return ;
617-
618- ItemStack icon =
619- new ItemStack (MC .level .getBlockState (pos ).getBlock ().asItem ());
620- if (icon .isEmpty ())
621- icon = new ItemStack (Items .OAK_SIGN );
610+ if (detectSigns )
611+ ChunkUtils .getLoadedBlockEntities ().forEach (be -> {
612+ if (!(be instanceof SignBlockEntity sign ))
613+ return ;
614+ BlockPos pos = sign .getBlockPos ();
615+ if (pos == null )
616+ return ;
617+ Vec3 p = Vec3 .atCenterOf (pos );
618+ double distSq = p .distanceToSqr (centerVec );
619+ if (!infinite && distSq > rangeSq )
620+ return ;
621+
622+ String text = readSignText (sign );
623+ if (text .isEmpty ())
624+ return ;
625+ ItemStack icon =
626+ iconForBlockEntity (be , new ItemStack (Items .OAK_SIGN ));
627+ trackedLabels .add (new NearbyLabel (p , new AABB (pos ), icon ,
628+ "Sign: " + text , Math .sqrt (distSq ), getSignTraceId (pos )));
629+ });
630+
631+ if (detectNamed )
632+ {
633+ AABB scanBox = MC .player .getBoundingBox ().inflate (range );
634+ List <Entity > namedEntities =
635+ MC .level .getEntities (MC .player , scanBox , e -> e != null
636+ && e .isAlive () && !e .isRemoved () && e .hasCustomName ());
622637
623- trackedSigns
624- .add (new NearbySign (pos , icon , text , Math .sqrt (distSq )));
625- });
638+ for (Entity entity : namedEntities )
639+ {
640+ String customName = readCustomName (entity );
641+ if (customName .isEmpty ())
642+ continue ;
643+ if (isIgnoredNamedEntityByItemEsp (customName ))
644+ continue ;
645+ Vec3 p = entity .position ();
646+ double distSq = p .distanceToSqr (centerVec );
647+ if (!infinite && distSq > rangeSq )
648+ continue ;
649+
650+ trackedLabels .add (new NearbyLabel (p , entity .getBoundingBox (),
651+ new ItemStack (Items .NAME_TAG ),
652+ "Named entity: " + customName , Math .sqrt (distSq ),
653+ getNamedEntityTraceId (entity .getUUID ())));
654+ }
655+ }
626656
627- trackedSigns
628- .sort (java .util .Comparator .comparingDouble (NearbySign ::distance ));
657+ trackedLabels
658+ .sort (java .util .Comparator .comparingDouble (NearbyLabel ::distance ));
629659
630660 int max = signMax .getValueI ();
631- if (trackedSigns .size () > max )
632- trackedSigns .subList (max , trackedSigns .size ()).clear ();
661+ if (trackedLabels .size () > max )
662+ trackedLabels .subList (max , trackedLabels .size ()).clear ();
663+ }
664+
665+ private ItemStack iconForBlockEntity (BlockEntity be , ItemStack fallback )
666+ {
667+ try
668+ {
669+ BlockPos pos = be .getBlockPos ();
670+ if (pos != null )
671+ {
672+ ItemStack icon = new ItemStack (
673+ MC .level .getBlockState (pos ).getBlock ().asItem ());
674+ if (!icon .isEmpty ())
675+ return icon ;
676+ }
677+ }catch (Throwable ignored )
678+ {}
679+
680+ return fallback .copy ();
681+ }
682+
683+ private static String readCustomName (Object object )
684+ {
685+ if (!(object instanceof Nameable nameable ))
686+ return "" ;
687+
688+ try
689+ {
690+ if (!nameable .hasCustomName ())
691+ return "" ;
692+ net .minecraft .network .chat .Component customName =
693+ nameable .getCustomName ();
694+ if (customName == null )
695+ return "" ;
696+ return readNameText (customName );
697+ }catch (Throwable ignored )
698+ {
699+ return "" ;
700+ }
701+ }
702+
703+ private static String readNameText (
704+ net .minecraft .network .chat .Component customName )
705+ {
706+ if (customName == null )
707+ return "" ;
708+ String text = customName .getString ();
709+ if (text == null )
710+ return "" ;
711+ String trimmed = text .trim ();
712+ if (trimmed .isEmpty ())
713+ return "" ;
714+ if (trimmed .length () > 80 )
715+ return trimmed .substring (0 , 77 ) + "..." ;
716+ return trimmed ;
633717 }
634718
635719 private static String readSignText (SignBlockEntity sign )
@@ -993,9 +1077,9 @@ public java.util.Set<String> getTracedItems()
9931077 return java .util .Set .copyOf (tracedItems );
9941078 }
9951079
996- public List <NearbySign > getTrackedSigns ()
1080+ public List <NearbyLabel > getTrackedLabels ()
9971081 {
998- return List .copyOf (trackedSigns );
1082+ return List .copyOf (trackedLabels );
9991083 }
10001084
10011085 public static String getSignTraceId (BlockPos pos )
@@ -1005,20 +1089,22 @@ public static String getSignTraceId(BlockPos pos)
10051089 return "sign:" + pos .asLong ();
10061090 }
10071091
1008- public boolean isShowSignsInHud ( )
1092+ public static String getNamedEntityTraceId ( UUID uuid )
10091093 {
1010- return showSignsInHud .isChecked ();
1094+ if (uuid == null )
1095+ return null ;
1096+ return "named_entity:" + uuid ;
10111097 }
10121098
1013- public record NearbySign (BlockPos pos , ItemStack icon , String text ,
1014- double distance )
1099+ public boolean isShowSignsInHud ()
10151100 {
1016- public String traceId ()
1017- {
1018- return getSignTraceId (pos );
1019- }
1101+ return showSignsInHud .isChecked ();
10201102 }
10211103
1104+ public record NearbyLabel (Vec3 position , AABB box , ItemStack icon ,
1105+ String text , double distance , String traceId )
1106+ {}
1107+
10221108 public boolean isHudEnabled ()
10231109 {
10241110 return hudEnabled .isChecked ();
@@ -1197,18 +1283,17 @@ public void onRender(PoseStack matrixStack, float partialTicks)
11971283 ends .add (new RenderUtils .ColoredPoint (p , 0 ));
11981284 }
11991285
1200- for (NearbySign sign : trackedSigns )
1286+ for (NearbyLabel label : trackedLabels )
12011287 {
1202- if (sign == null || sign . pos () == null )
1288+ if (label == null || label . box () == null )
12031289 continue ;
1204- String traceId = sign .traceId ();
1290+ String traceId = label .traceId ();
12051291 boolean traced = traceId != null && isTraced (traceId );
12061292 if (!traced )
12071293 continue ;
1208- BlockPos pos = sign .pos ();
1209- Vec3 p = Vec3 .atCenterOf (pos );
1294+ Vec3 p = label .position ();
12101295 if (shouldDrawBoxes )
1211- boxes .add (new AABB ( pos ));
1296+ boxes .add (label . box ( ));
12121297 if (shouldDrawTracers )
12131298 ends .add (new RenderUtils .ColoredPoint (p , 0 ));
12141299 }
@@ -1249,6 +1334,53 @@ private boolean isIgnoredByItemEsp(ItemStack stack)
12491334 return esp .isIgnoredId (id );
12501335 }
12511336
1337+ private boolean isIgnoredNamedEntityByItemEsp (String customName )
1338+ {
1339+ if (!respectItemEspIgnores .isChecked ())
1340+ return false ;
1341+ if (customName == null || customName .isBlank ())
1342+ return false ;
1343+
1344+ net .wurstclient .hacks .ItemEspHack esp =
1345+ net .wurstclient .WurstClient .INSTANCE .getHax ().itemEspHack ;
1346+ if (esp == null )
1347+ return false ;
1348+
1349+ net .wurstclient .settings .ItemListSetting list =
1350+ esp .getIgnoredListSetting ();
1351+ if (list == null )
1352+ return false ;
1353+
1354+ String normalizedName = normalizeForContains (customName );
1355+ if (normalizedName .isEmpty ())
1356+ return false ;
1357+
1358+ for (String entry : list .getItemNames ())
1359+ {
1360+ if (entry == null )
1361+ continue ;
1362+ String trimmed = entry .trim ();
1363+ if (trimmed .isEmpty ())
1364+ continue ;
1365+ String normalizedEntry = normalizeForContains (trimmed );
1366+ if (normalizedEntry .isEmpty ())
1367+ continue ;
1368+ if (normalizedName .equals (normalizedEntry )
1369+ || normalizedName .contains (normalizedEntry ))
1370+ return true ;
1371+ }
1372+
1373+ return false ;
1374+ }
1375+
1376+ private static String normalizeForContains (String value )
1377+ {
1378+ if (value == null )
1379+ return "" ;
1380+ return value .toLowerCase (Locale .ROOT ).replace ('_' , ' ' )
1381+ .replaceAll ("\\ s+" , " " ).trim ();
1382+ }
1383+
12521384 public boolean isSpecialByItemEsp (ItemStack stack )
12531385 {
12541386 net .wurstclient .hacks .ItemEspHack esp =
0 commit comments