Skip to content

Commit 69e4222

Browse files
committed
Updated ChestESP, SpawnRadius, BedESP
1 parent 87e7516 commit 69e4222

File tree

3 files changed

+228
-21
lines changed

3 files changed

+228
-21
lines changed

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ private void addToGroupBoxes(Result result)
281281
&& headPos.getY() < aboveGroundY.getValue())
282282
return;
283283

284-
if(filterTrialChambers.isChecked() && isTrialChamberBed(headPos))
284+
if(filterTrialChambers.isChecked() && isInTrialChamberArea(headPos))
285285
return;
286286

287287
if(filterVillageBeds.isChecked() && isLikelyVillageBed(headPos))
@@ -348,16 +348,15 @@ private <T extends Entity> List<Vec3> collectEntityPositions(Class<T> type)
348348
.collect(Collectors.toList());
349349
}
350350

351-
private boolean isTrialChamberBed(BlockPos headPos)
351+
private boolean isInTrialChamberArea(BlockPos pos)
352352
{
353-
int y = headPos.getY();
354-
if(y < -38 || y > 10)
353+
int y = pos.getY();
354+
// Trial chambers are underground; keep broad window to prevent misses
355+
if(y < -64 || y > 48)
355356
return false;
356357

357-
if(!isNearWaxedCopper(headPos, 5))
358-
return false;
359-
360-
return isNearTrialSpawner(headPos, 100);
358+
// Rely on proximity to Trial Spawners (unique to Trial Chambers)
359+
return isNearTrialSpawner(pos, 128);
361360
}
362361

363362
private boolean isNearWaxedCopper(BlockPos center, int range)

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

Lines changed: 212 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@
2525
import net.minecraft.world.level.block.ChestBlock;
2626
import net.minecraft.world.level.block.DoorBlock;
2727
import net.minecraft.world.level.block.HopperBlock;
28+
import net.minecraft.world.level.block.DispenserBlock;
2829
import net.minecraft.world.level.block.ShulkerBoxBlock;
2930
import net.minecraft.world.level.block.state.BlockState;
3031
import net.minecraft.world.level.block.state.properties.ChestType;
3132
import net.minecraft.world.level.block.entity.BlockEntity;
3233
import net.minecraft.world.level.block.entity.ChestBlockEntity;
34+
import net.minecraft.world.level.block.entity.BarrelBlockEntity;
35+
import net.minecraft.world.level.block.entity.HopperBlockEntity;
36+
import net.minecraft.world.level.block.entity.DispenserBlockEntity;
3337
import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity;
3438
import net.minecraft.world.phys.AABB;
3539
import net.minecraft.world.phys.Vec3;
@@ -81,6 +85,7 @@ public class ChestEspHack extends Hack implements UpdateListener,
8185
"Opacity for tracers (0 = fully transparent, 255 = opaque).", 128,
8286
0, 255, 1, SliderSetting.ValueDisplay.INTEGER);
8387
private int foundCount;
88+
private boolean preFilteredEnv;
8489

8590
private final CheckboxSetting onlyAboveGround =
8691
new CheckboxSetting("Above ground only",
@@ -111,7 +116,7 @@ public class ChestEspHack extends Hack implements UpdateListener,
111116

112117
private final CheckboxSetting filterTrialChambers = new CheckboxSetting(
113118
"Filter trial chambers",
114-
"Hides single chests and barrels that match common trial chamber layouts. Does not affect double chests or shulkers.",
119+
"Hides single chests, barrels, hoppers, and dispensers that match common trial chamber layouts. Does not affect double chests or shulkers.",
115120
false);
116121

117122
private final CheckboxSetting doubleChestsOnly =
@@ -175,20 +180,31 @@ protected void onDisable()
175180
cachedTrialSpawners = List.of();
176181
cachedVillagerPositions = List.of();
177182
cachedGolemPositions = List.of();
183+
preFilteredEnv = false;
178184
}
179185

180186
@Override
181187
public void onUpdate()
182188
{
183189
groups.allGroups.forEach(ChestEspGroup::clear);
184190

191+
// Build environmental caches first so we can pre-filter before adding
192+
refreshEnvironmentalCaches();
193+
preFilteredEnv = MC.level != null && (filterNearSpawners.isChecked()
194+
|| filterTrialChambers.isChecked() || filterVillages.isChecked());
195+
185196
double yLimit = aboveGroundY.getValue();
186197
boolean enforceAboveGround = onlyAboveGround.isChecked();
187198

188199
ChunkUtils.getLoadedBlockEntities().forEach(be -> {
189200
if(enforceAboveGround && be.getBlockPos().getY() < yLimit)
190201
return;
191202

203+
// Pre-filter by environment to avoid flicker and wasted work
204+
if(preFilteredEnv && shouldFilterBlockEntityByEnvironment(be))
205+
return;
206+
207+
// Respect double-chest-only suppression
192208
if(shouldSkipSingleChest(be))
193209
return;
194210

@@ -207,8 +223,6 @@ public void onUpdate()
207223
}
208224
}
209225

210-
refreshEnvironmentalCaches();
211-
212226
int total = groups.allGroups.stream().filter(ChestEspGroup::isEnabled)
213227
.mapToInt(g -> g.getBoxes().size()).sum();
214228
foundCount = Math.min(total, 999);
@@ -289,8 +303,8 @@ private void renderBoxes(PoseStack matrixStack)
289303
String curDim = MC.level == null ? "overworld"
290304
: MC.level.dimension().identifier().getPath();
291305

292-
boolean applyEnvFilters =
293-
MC.level != null && (filterNearSpawners.isChecked()
306+
boolean applyEnvFilters = MC.level != null && !preFilteredEnv
307+
&& (filterNearSpawners.isChecked()
294308
|| filterTrialChambers.isChecked()
295309
|| filterVillages.isChecked());
296310

@@ -647,8 +661,8 @@ private void renderTracers(PoseStack matrixStack, float partialTicks)
647661
: MC.level.dimension().identifier().getPath();
648662
}
649663

650-
boolean applyEnvFilters =
651-
MC.level != null && (filterNearSpawners.isChecked()
664+
boolean applyEnvFilters = MC.level != null && !preFilteredEnv
665+
&& (filterNearSpawners.isChecked()
652666
|| filterTrialChambers.isChecked()
653667
|| filterVillages.isChecked());
654668

@@ -802,12 +816,35 @@ private List<AABB> filterBoxesByEnvironment(List<AABB> boxes)
802816
BlockPos barrelPos = getSingleBarrelPosIfApplicable(box);
803817
if(barrelPos == null)
804818
{
819+
// Trial chamber ignore for hoppers
820+
BlockPos hopperPos = getSingleHopperPosIfApplicable(box);
821+
if(hopperPos != null)
822+
{
823+
if(filterTrialChambers.isChecked()
824+
&& isInTrialChamberArea(hopperPos))
825+
continue;
826+
out.add(box);
827+
continue;
828+
}
829+
830+
// Trial chamber ignore for dispensers
831+
BlockPos dispenserPos =
832+
getSingleDispenserPosIfApplicable(box);
833+
if(dispenserPos != null)
834+
{
835+
if(filterTrialChambers.isChecked()
836+
&& isInTrialChamberArea(dispenserPos))
837+
continue;
838+
out.add(box);
839+
continue;
840+
}
841+
805842
out.add(box);
806843
continue;
807844
}
808845

809846
if(filterTrialChambers.isChecked()
810-
&& isTrialChamberChest(barrelPos))
847+
&& isInTrialChamberArea(barrelPos))
811848
continue;
812849

813850
out.add(box);
@@ -819,7 +856,7 @@ && isNearSpawner(singleChestPos, 7))
819856
continue;
820857

821858
if(filterTrialChambers.isChecked()
822-
&& isTrialChamberChest(singleChestPos))
859+
&& isInTrialChamberArea(singleChestPos))
823860
continue;
824861

825862
if(filterVillages.isChecked()
@@ -832,6 +869,63 @@ && isLikelyVillageChest(singleChestPos))
832869
return out;
833870
}
834871

872+
// Fast pre-filter used in onUpdate() to keep filtered blocks from ever
873+
// entering render lists. Mirrors the logic of filterBoxesByEnvironment
874+
// but operates directly on BlockEntity types for speed.
875+
private boolean shouldFilterBlockEntityByEnvironment(BlockEntity be)
876+
{
877+
if(MC.level == null)
878+
return false;
879+
880+
BlockPos pos = be.getBlockPos();
881+
BlockState state = be.getBlockState();
882+
883+
// Chest-specific single/double handling
884+
if(be instanceof ChestBlockEntity)
885+
{
886+
boolean isSingle = true;
887+
if(state != null && state.hasProperty(ChestBlock.TYPE))
888+
isSingle = state.getValue(ChestBlock.TYPE) == ChestType.SINGLE;
889+
890+
if(isSingle)
891+
{
892+
if(filterNearSpawners.isChecked() && isNearSpawner(pos, 7))
893+
return true;
894+
if(filterTrialChambers.isChecked() && isInTrialChamberArea(pos))
895+
return true;
896+
if(filterVillages.isChecked() && isLikelyVillageChest(pos))
897+
return true;
898+
}
899+
return false;
900+
}
901+
902+
// Barrels in Trial Chambers
903+
if(be instanceof BarrelBlockEntity)
904+
{
905+
if(filterTrialChambers.isChecked() && isInTrialChamberArea(pos))
906+
return true;
907+
return false;
908+
}
909+
910+
// Hoppers in Trial Chambers
911+
if(be instanceof HopperBlockEntity)
912+
{
913+
if(filterTrialChambers.isChecked() && isInTrialChamberArea(pos))
914+
return true;
915+
return false;
916+
}
917+
918+
// Dispensers in Trial Chambers
919+
if(be instanceof DispenserBlockEntity)
920+
{
921+
if(filterTrialChambers.isChecked() && isInTrialChamberArea(pos))
922+
return true;
923+
return false;
924+
}
925+
926+
return false;
927+
}
928+
835929
private BlockPos getSingleChestPosIfApplicable(AABB box)
836930
{
837931
if(MC.level == null || box == null)
@@ -945,16 +1039,121 @@ private boolean isNearSpawner(BlockPos center, int range)
9451039
.anyMatch(pos -> BlockUtils.getBlock(pos) == Blocks.SPAWNER);
9461040
}
9471041

948-
private boolean isTrialChamberChest(BlockPos pos)
1042+
private boolean isInTrialChamberArea(BlockPos pos)
9491043
{
9501044
int y = pos.getY();
951-
if(y < -38 || y > 10)
1045+
// Trial chambers typically generate underground; keep a broad sanity
1046+
// window
1047+
if(y < -64 || y > 48)
9521048
return false;
9531049

954-
if(!isNearWaxedCopper(pos, 5))
1050+
// Rely on proximity to Trial Spawners when available
1051+
if(isNearTrialSpawner(pos, 128))
1052+
return true;
1053+
1054+
// Fallback heuristic: look for characteristic Trial Chamber blocks
1055+
// nearby
1056+
return isNearLikelyTrialBlocks(pos, 6);
1057+
}
1058+
1059+
private boolean isNearLikelyTrialBlocks(BlockPos center, int range)
1060+
{
1061+
if(MC.level == null)
9551062
return false;
9561063

957-
return isNearTrialSpawner(pos, 100);
1064+
return BlockUtils.getAllInBoxStream(center, range).anyMatch(pos -> {
1065+
Block b = BlockUtils.getBlock(pos);
1066+
if(b == null)
1067+
return false;
1068+
String path = BuiltInRegistries.BLOCK.getKey(b).getPath();
1069+
// Strong signals of Trial Chambers
1070+
if(path.contains("trial_spawner") || path.contains("vault"))
1071+
return true;
1072+
// Common building blocks in Trial Chambers (heuristic)
1073+
return path.contains("tuff_bricks")
1074+
|| path.contains("chiseled_tuff")
1075+
|| path.contains("polished_tuff")
1076+
|| path.contains("copper_bulb");
1077+
});
1078+
}
1079+
1080+
// Backward-compatibility alias for any callers still using the old name
1081+
@Deprecated
1082+
private boolean isTrialChamberChest(BlockPos pos)
1083+
{
1084+
return isInTrialChamberArea(pos);
1085+
}
1086+
1087+
private BlockPos getSingleHopperPosIfApplicable(AABB box)
1088+
{
1089+
if(MC.level == null || box == null)
1090+
return null;
1091+
1092+
int boxMinX = (int)Math.floor(box.minX + 1e-6);
1093+
int boxMaxX = (int)Math.floor(box.maxX - 1e-6);
1094+
int boxMinY = (int)Math.floor(box.minY + 1e-6);
1095+
int boxMaxY = (int)Math.floor(box.maxY - 1e-6);
1096+
int boxMinZ = (int)Math.floor(box.minZ + 1e-6);
1097+
int boxMaxZ = (int)Math.floor(box.maxZ - 1e-6);
1098+
1099+
BlockPos found = null;
1100+
int count = 0;
1101+
1102+
for(int x = boxMinX; x <= boxMaxX; x++)
1103+
for(int y = boxMinY; y <= boxMaxY; y++)
1104+
for(int z = boxMinZ; z <= boxMaxZ; z++)
1105+
{
1106+
BlockPos pos = new BlockPos(x, y, z);
1107+
BlockState state = MC.level.getBlockState(pos);
1108+
if(state == null)
1109+
continue;
1110+
if(state.getBlock() instanceof HopperBlock)
1111+
{
1112+
count++;
1113+
if(found == null)
1114+
found = pos;
1115+
if(count > 1)
1116+
return null;
1117+
}
1118+
}
1119+
1120+
return found;
1121+
}
1122+
1123+
private BlockPos getSingleDispenserPosIfApplicable(AABB box)
1124+
{
1125+
if(MC.level == null || box == null)
1126+
return null;
1127+
1128+
int boxMinX = (int)Math.floor(box.minX + 1e-6);
1129+
int boxMaxX = (int)Math.floor(box.maxX - 1e-6);
1130+
int boxMinY = (int)Math.floor(box.minY + 1e-6);
1131+
int boxMaxY = (int)Math.floor(box.maxY - 1e-6);
1132+
int boxMinZ = (int)Math.floor(box.minZ + 1e-6);
1133+
int boxMaxZ = (int)Math.floor(box.maxZ - 1e-6);
1134+
1135+
BlockPos found = null;
1136+
int count = 0;
1137+
1138+
for(int x = boxMinX; x <= boxMaxX; x++)
1139+
for(int y = boxMinY; y <= boxMaxY; y++)
1140+
for(int z = boxMinZ; z <= boxMaxZ; z++)
1141+
{
1142+
BlockPos pos = new BlockPos(x, y, z);
1143+
BlockState state = MC.level.getBlockState(pos);
1144+
if(state == null)
1145+
continue;
1146+
if(state.getBlock() instanceof DispenserBlock)
1147+
{
1148+
count++;
1149+
if(found == null)
1150+
found = pos;
1151+
if(count > 1)
1152+
return null;
1153+
}
1154+
}
1155+
1156+
return found;
9581157
}
9591158

9601159
private boolean isNearWaxedCopper(BlockPos center, int range)

src/main/java/net/wurstclient/hacks/spawnradius/SpawnRadiusHack.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@
1414
import net.minecraft.core.BlockPos;
1515
import net.minecraft.world.level.BaseSpawner;
1616
import net.minecraft.world.level.block.entity.SpawnerBlockEntity;
17+
import net.minecraft.world.phys.AABB;
1718
import net.minecraft.world.phys.Vec3;
1819
import net.wurstclient.Category;
1920
import net.wurstclient.hack.Hack;
2021
import net.wurstclient.events.RenderListener;
2122
import net.wurstclient.events.UpdateListener;
2223
import net.wurstclient.nicewurst.NiceWurstModule;
24+
import net.wurstclient.util.BlockUtils;
2325
import net.wurstclient.util.RenderUtils;
2426
import net.wurstclient.util.chunk.ChunkUtils;
2527

@@ -28,6 +30,7 @@ public final class SpawnRadiusHack extends Hack
2830
{
2931
private static final int COLOR_IDLE = 0xFFFFFFFF;
3032
private static final int COLOR_DETECTED = 0xFF00FF00;
33+
private static final int SPAWNER_BOX_COLOR = 0xFFFFFFFF;
3134
private static final float HEIGHT_OFFSET = 0.05F;
3235
private static final int DEFAULT_RADIUS = 16;
3336
private static final Method GET_REQUIRED_PLAYER_RANGE;
@@ -110,6 +113,12 @@ public void onRender(PoseStack matrices, float partialTicks)
110113
continue;
111114

112115
drawCircle(matrices, center, info.radius(), info.detected());
116+
// Draw a simple white ESP box on the spawner block itself
117+
AABB box = BlockUtils.getBoundingBox(info.pos());
118+
if(box != null)
119+
RenderUtils.drawOutlinedBoxes(matrices,
120+
java.util.Collections.singletonList(box), SPAWNER_BOX_COLOR,
121+
false);
113122
}
114123
}
115124

0 commit comments

Comments
 (0)