From f8fb17ecabbeed4bcdbf0ea45a791117fc3e28f5 Mon Sep 17 00:00:00 2001 From: Bruno Gustke Date: Sat, 13 Dec 2025 20:04:20 +0100 Subject: [PATCH 1/2] TheElenium: BLockESP: Added support for NBT-Data filtering --- .../modules/render/blockesp/BlockESP.java | 167 ++++++++++++++---- .../modules/render/blockesp/ESPBlock.java | 5 +- .../modules/render/blockesp/ESPBlockData.java | 29 ++- .../render/blockesp/ESPBlockDataScreen.java | 17 ++ .../modules/render/blockesp/ESPChunk.java | 4 +- 5 files changed, 179 insertions(+), 43 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/BlockESP.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/BlockESP.java index 8cfe86c072..04cd04da3c 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/BlockESP.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/BlockESP.java @@ -25,6 +25,8 @@ import net.minecraft.util.math.ChunkPos; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.dimension.DimensionType; +import net.minecraft.block.BlockState; +import net.minecraft.state.property.Property; import java.util.Iterator; import java.util.List; @@ -32,61 +34,97 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.HashMap; +import java.util.Optional; public class BlockESP extends Module { private final SettingGroup sgGeneral = settings.getDefaultGroup(); // General - private final Setting> blocks = sgGeneral.add(new BlockListSetting.Builder() - .name("blocks") - .description("Blocks to search for.") - .onChanged(blocks1 -> { - if (isActive() && Utils.canUpdate()) onActivate(); - }) - .build() + private final Setting> blocks = sgGeneral.add( + new BlockListSetting.Builder() + .name("blocks") + .description("Blocks to search for.") + .onChanged(blocks1 -> { + if (isActive() && Utils.canUpdate()) onActivate(); + }) + .build() ); - - private final Setting defaultBlockConfig = sgGeneral.add(new GenericSetting.Builder() - .name("default-block-config") - .description("Default block config.") - .defaultValue( - new ESPBlockData( - ShapeMode.Lines, - new SettingColor(0, 255, 200), - new SettingColor(0, 255, 200, 25), - true, - new SettingColor(0, 255, 200, 125) + + // uncomment if NBT-Data should apply to all blocks !!! UNTESTED !!! + + /* + private final Setting> customFilters = sgGeneral.add( + new StringListSetting.Builder() + .name("NTB-Data") + .description( + "Filters with ntbdata (e.g. 'waterlogged=true')." ) - ) - .build() + .defaultValue(new ArrayList<>()) + .onChanged(this::parseFilters) + .build() ); - - private final Setting> blockConfigs = sgGeneral.add(new BlockDataSetting.Builder() - .name("block-configs") - .description("Config for each block.") - .defaultData(defaultBlockConfig) - .build() + */ + + private final Setting defaultBlockConfig = sgGeneral.add( + new GenericSetting.Builder() + .name("default-block-config") + .description("Default block config.") + .defaultValue( + new ESPBlockData( + ShapeMode.Lines, + new SettingColor(0, 255, 200), + new SettingColor(0, 255, 200, 25), + true, + new SettingColor(0, 255, 200, 125) + ) + ) + .build() ); - private final Setting tracers = sgGeneral.add(new BoolSetting.Builder() - .name("tracers") - .description("Render tracer lines.") - .defaultValue(false) - .build() + private final Setting> blockConfigs = + sgGeneral.add( + new BlockDataSetting.Builder() + .name("block-configs") + .description("Config for each block.") + .defaultData(defaultBlockConfig) + .onChanged(configs -> { + if (isActive() && Utils.canUpdate()) onActivate(); + }) + .build() + ); + + private final Setting tracers = sgGeneral.add( + new BoolSetting.Builder() + .name("tracers") + .description("Render tracer lines.") + .defaultValue(false) + .build() ); private final BlockPos.Mutable blockPos = new BlockPos.Mutable(); - private final Long2ObjectMap chunks = new Long2ObjectOpenHashMap<>(); + private final Map< + Block, + Map, Comparable> + > activeFilterCache = new HashMap<>(); + + private final Long2ObjectMap chunks = + new Long2ObjectOpenHashMap<>(); private final Set groups = new ReferenceOpenHashSet<>(); - private final ExecutorService workerThread = Executors.newSingleThreadExecutor(); + private final ExecutorService workerThread = + Executors.newSingleThreadExecutor(); private DimensionType lastDimension; public BlockESP() { - super(Categories.Render, "block-esp", "Renders specified blocks through walls.", "search"); - + super( + Categories.Render, + "block-esp", + "Renders specified blocks through walls.", + "search" + ); RainbowColors.register(this::onTickRainbow); } @@ -161,8 +199,7 @@ private void onChunkData(ChunkDataEvent event) { private void searchChunk(Chunk chunk) { workerThread.submit(() -> { if (!isActive()) return; - ESPChunk schunk = ESPChunk.searchChunk(chunk, blocks.get()); - + ESPChunk schunk = ESPChunk.searchChunk(chunk, this); if (schunk.size() > 0) { synchronized (chunks) { chunks.put(chunk.getPos().toLong(), schunk); @@ -189,8 +226,8 @@ private void onBlockUpdate(BlockUpdateEvent event) { int chunkZ = bz >> 4; long key = ChunkPos.toLong(chunkX, chunkZ); - boolean added = blocks.get().contains(event.newState.getBlock()) && !blocks.get().contains(event.oldState.getBlock()); - boolean removed = !added && !blocks.get().contains(event.newState.getBlock()) && blocks.get().contains(event.oldState.getBlock()); + boolean added = shouldRender(event.newState) && !shouldRender(event.oldState); + boolean removed = !added && !shouldRender(event.newState) && shouldRender(event.oldState); if (added || removed) { workerThread.submit(() -> { @@ -263,4 +300,56 @@ private void onRender(Render3DEvent event) { public String getInfoString() { return "%s groups".formatted(groups.size()); } + + + public boolean shouldRender(BlockState state) { + Block block = state.getBlock(); + + if (blocks.get().contains(block)) { + ESPBlockData blockData = blockConfigs.get().get(block); + if (blockData != null && !blockData.stateFilters.isEmpty()) { + return matchesStateFilters(state, block, blockData.stateFilters); + } + return true; + } + + // Check global state filters + if (activeFilterCache.containsKey(block)) { + Map, Comparable> requiredProps = activeFilterCache.get(block); + for (Map.Entry,Comparable> entry : requiredProps.entrySet()) { + if (!state.get(entry.getKey()).equals(entry.getValue())) { + return false; + } + } + return true; + } + return false; + } + + private boolean matchesStateFilters(BlockState state, Block block, List filters) { + for (String filter : filters) { + try { + // Parse "key=value" format + String[] kv = filter.split("="); + if (kv.length != 2) continue; + + String propertyName = kv[0].trim(); + String expectedValue = kv[1].trim(); + + Property property = block.getStateManager().getProperty(propertyName); + if (property == null) continue; + + Optional parsedValue = property.parse(expectedValue); + if (parsedValue.isEmpty()) continue; + + if (!state.get(property).equals(parsedValue.get())) { + return false; + } + } catch (Exception e) { + // Invalid filter format + } + } + + return true; + } } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlock.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlock.java index 809ea49ed5..fccd22a1de 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlock.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlock.java @@ -127,6 +127,8 @@ private boolean isNeighbour(Direction dir) { if (neighbourState.getBlock() != state.getBlock()) return false; + if (!blockEsp.shouldRender(neighbourState)) return false; + VoxelShape cube = VoxelShapes.fullCube(); VoxelShape shape = state.getOutlineShape(mc.world, blockPos); VoxelShape neighbourShape = neighbourState.getOutlineShape(mc.world, blockPos); @@ -165,7 +167,8 @@ private boolean isNeighbour(Direction dir) { private boolean isNeighbourDiagonal(double x, double y, double z) { blockPos.set(this.x + x, this.y + y, this.z + z); - return state.getBlock() == mc.world.getBlockState(blockPos).getBlock(); + BlockState neighbourState = mc.world.getBlockState(blockPos); + return state.getBlock() == neighbourState.getBlock() && blockEsp.shouldRender(neighbourState); } public void render(Render3DEvent event) { diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockData.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockData.java index 1979cd3922..d8de9a4343 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockData.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockData.java @@ -5,6 +5,10 @@ package meteordevelopment.meteorclient.systems.modules.render.blockesp; +import java.util.ArrayList; +import java.util.List; + + import meteordevelopment.meteorclient.gui.GuiTheme; import meteordevelopment.meteorclient.gui.WidgetScreen; import meteordevelopment.meteorclient.renderer.ShapeMode; @@ -16,6 +20,8 @@ import meteordevelopment.meteorclient.utils.render.color.SettingColor; import net.minecraft.block.Block; import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtList; +import net.minecraft.nbt.NbtString; public class ESPBlockData implements IGeneric, IChangeable, IBlockData { public ShapeMode shapeMode; @@ -25,6 +31,8 @@ public class ESPBlockData implements IGeneric, IChangeable, IBlock public boolean tracer; public SettingColor tracerColor; + public List stateFilters = new ArrayList<>(); + private boolean changed; public ESPBlockData(ShapeMode shapeMode, SettingColor lineColor, SettingColor sideColor, boolean tracer, SettingColor tracerColor) { @@ -70,6 +78,9 @@ public ESPBlockData set(ESPBlockData value) { tracer = value.tracer; tracerColor.set(value.tracerColor); + stateFilters.clear(); + stateFilters.addAll(value.stateFilters); + changed = value.changed; return this; @@ -77,7 +88,9 @@ public ESPBlockData set(ESPBlockData value) { @Override public ESPBlockData copy() { - return new ESPBlockData(shapeMode, new SettingColor(lineColor), new SettingColor(sideColor), tracer, new SettingColor(tracerColor)); + ESPBlockData copy = new ESPBlockData(shapeMode, new SettingColor(lineColor), new SettingColor(sideColor), tracer, new SettingColor(tracerColor)); + copy.stateFilters.addAll(stateFilters); + return copy; } @Override @@ -91,6 +104,12 @@ public NbtCompound toTag() { tag.putBoolean("tracer", tracer); tag.put("tracerColor", tracerColor.toTag()); + NbtList filtersList = new NbtList(); + for (String filter : stateFilters) { + filtersList.add(NbtString.of(filter)); + } + tag.put("NBT-Data", filtersList); + tag.putBoolean("changed", changed); return tag; @@ -105,6 +124,14 @@ public ESPBlockData fromTag(NbtCompound tag) { tracer = tag.getBoolean("tracer", false); tracerColor.fromTag(tag.getCompoundOrEmpty("tracerColor")); + stateFilters.clear(); + tag.getList("NBT-Data").ifPresent(filtersList -> { + for (int i = 0; i < filtersList.size(); i++) { + filtersList.getString(i).ifPresent(stateFilters::add); + } + }); + + changed = tag.getBoolean("changed", false); return this; diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockDataScreen.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockDataScreen.java index 6854d2a89a..eed55684d6 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockDataScreen.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockDataScreen.java @@ -13,6 +13,8 @@ import net.minecraft.block.Block; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; + public class ESPBlockDataScreen extends WindowScreen { private final ESPBlockData blockData; private final Setting setting; @@ -39,6 +41,7 @@ public void initWidgets() { Settings settings = new Settings(); SettingGroup sgGeneral = settings.getDefaultGroup(); SettingGroup sgTracer = settings.createGroup("Tracer"); + SettingGroup sgFilters = settings.createGroup("NBT-Data"); sgGeneral.add(new EnumSetting.Builder() .name("shape-mode") @@ -110,6 +113,20 @@ public void initWidgets() { .build() ); + // Add state filters setting + sgFilters.add(new StringListSetting.Builder() + .name("NBT-Data") + .description("Filters with states (e.g. 'waterlogged=false', 'facing=north', 'ominous=true'). Only blocks matching ALL filters will be shown.") + .defaultValue(new ArrayList<>()) + .onModuleActivated(stringSetting -> stringSetting.set(blockData.stateFilters)) + .onChanged(filters -> { + blockData.stateFilters.clear(); + blockData.stateFilters.addAll(filters); + onChanged(); + }) + .build() + ); + settings.onActivated(); add(theme.settings(settings)).expandX(); } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPChunk.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPChunk.java index 0fac693cf3..dd1ad74dd9 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPChunk.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPChunk.java @@ -86,7 +86,7 @@ public void render(Render3DEvent event) { } - public static ESPChunk searchChunk(Chunk chunk, List blocks) { + public static ESPChunk searchChunk(Chunk chunk, BlockESP module) { ESPChunk schunk = new ESPChunk(chunk.getPos().x, chunk.getPos().z); if (schunk.shouldBeDeleted()) return schunk; @@ -100,7 +100,7 @@ public static ESPChunk searchChunk(Chunk chunk, List blocks) { blockPos.set(x, y, z); BlockState bs = chunk.getBlockState(blockPos); - if (blocks.contains(bs.getBlock())) schunk.add(blockPos, false); + if (module.shouldRender(bs)) schunk.add(blockPos, false); } } } From f8d21e719ab15861377f385f3ded4a0dc3d9f95c Mon Sep 17 00:00:00 2001 From: Bruno Gustke Date: Sat, 20 Dec 2025 20:20:48 +0100 Subject: [PATCH 2/2] reverting logically unchanged lines, renaming to stateFilters --- .../modules/render/blockesp/BlockESP.java | 107 +++++++----------- .../modules/render/blockesp/ESPBlockData.java | 6 +- .../render/blockesp/ESPBlockDataScreen.java | 4 +- 3 files changed, 44 insertions(+), 73 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/BlockESP.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/BlockESP.java index 04cd04da3c..a4bf9f2755 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/BlockESP.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/BlockESP.java @@ -42,89 +42,60 @@ public class BlockESP extends Module { // General - private final Setting> blocks = sgGeneral.add( - new BlockListSetting.Builder() - .name("blocks") - .description("Blocks to search for.") - .onChanged(blocks1 -> { - if (isActive() && Utils.canUpdate()) onActivate(); - }) - .build() + private final Setting> blocks = sgGeneral.add(new BlockListSetting.Builder() + .name("blocks") + .description("Blocks to search for.") + .onChanged(blocks1 -> { + if (isActive() && Utils.canUpdate()) onActivate(); + }) + .build() ); - - // uncomment if NBT-Data should apply to all blocks !!! UNTESTED !!! - - /* - private final Setting> customFilters = sgGeneral.add( - new StringListSetting.Builder() - .name("NTB-Data") - .description( - "Filters with ntbdata (e.g. 'waterlogged=true')." + + private final Setting defaultBlockConfig = sgGeneral.add(new GenericSetting.Builder() + .name("default-block-config") + .description("Default block config.") + .defaultValue( + new ESPBlockData( + ShapeMode.Lines, + new SettingColor(0, 255, 200), + new SettingColor(0, 255, 200, 25), + true, + new SettingColor(0, 255, 200, 125) ) - .defaultValue(new ArrayList<>()) - .onChanged(this::parseFilters) - .build() + ) + .build() ); - */ - - private final Setting defaultBlockConfig = sgGeneral.add( - new GenericSetting.Builder() - .name("default-block-config") - .description("Default block config.") - .defaultValue( - new ESPBlockData( - ShapeMode.Lines, - new SettingColor(0, 255, 200), - new SettingColor(0, 255, 200, 25), - true, - new SettingColor(0, 255, 200, 125) - ) - ) - .build() + + private final Setting> blockConfigs = sgGeneral.add(new BlockDataSetting.Builder() + .name("block-configs") + .description("Config for each block.") + .defaultData(defaultBlockConfig) + .onChanged(configs -> { + if (isActive() && Utils.canUpdate()) onActivate(); + }) + .build() ); - private final Setting> blockConfigs = - sgGeneral.add( - new BlockDataSetting.Builder() - .name("block-configs") - .description("Config for each block.") - .defaultData(defaultBlockConfig) - .onChanged(configs -> { - if (isActive() && Utils.canUpdate()) onActivate(); - }) - .build() - ); - - private final Setting tracers = sgGeneral.add( - new BoolSetting.Builder() - .name("tracers") - .description("Render tracer lines.") - .defaultValue(false) - .build() + private final Setting tracers = sgGeneral.add(new BoolSetting.Builder() + .name("tracers") + .description("Render tracer lines.") + .defaultValue(false) + .build() ); private final BlockPos.Mutable blockPos = new BlockPos.Mutable(); - private final Map< - Block, - Map, Comparable> - > activeFilterCache = new HashMap<>(); + private final Map, Comparable>> activeFilterCache = new HashMap<>(); - private final Long2ObjectMap chunks = - new Long2ObjectOpenHashMap<>(); + private final Long2ObjectMap chunks = new Long2ObjectOpenHashMap<>(); private final Set groups = new ReferenceOpenHashSet<>(); - private final ExecutorService workerThread = - Executors.newSingleThreadExecutor(); + private final ExecutorService workerThread = Executors.newSingleThreadExecutor(); private DimensionType lastDimension; public BlockESP() { - super( - Categories.Render, - "block-esp", - "Renders specified blocks through walls.", - "search" - ); + super(Categories.Render, "block-esp", "Renders specified blocks through walls.", "search"); + RainbowColors.register(this::onTickRainbow); } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockData.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockData.java index d8de9a4343..a6dd4bef3d 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockData.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockData.java @@ -31,7 +31,7 @@ public class ESPBlockData implements IGeneric, IChangeable, IBlock public boolean tracer; public SettingColor tracerColor; - public List stateFilters = new ArrayList<>(); + public final List stateFilters = new ArrayList<>(); private boolean changed; @@ -108,7 +108,7 @@ public NbtCompound toTag() { for (String filter : stateFilters) { filtersList.add(NbtString.of(filter)); } - tag.put("NBT-Data", filtersList); + tag.put("stateFilters", filtersList); tag.putBoolean("changed", changed); @@ -125,7 +125,7 @@ public ESPBlockData fromTag(NbtCompound tag) { tracerColor.fromTag(tag.getCompoundOrEmpty("tracerColor")); stateFilters.clear(); - tag.getList("NBT-Data").ifPresent(filtersList -> { + tag.getList("stateFilters").ifPresent(filtersList -> { for (int i = 0; i < filtersList.size(); i++) { filtersList.getString(i).ifPresent(stateFilters::add); } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockDataScreen.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockDataScreen.java index eed55684d6..68271babf6 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockDataScreen.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/blockesp/ESPBlockDataScreen.java @@ -41,7 +41,7 @@ public void initWidgets() { Settings settings = new Settings(); SettingGroup sgGeneral = settings.getDefaultGroup(); SettingGroup sgTracer = settings.createGroup("Tracer"); - SettingGroup sgFilters = settings.createGroup("NBT-Data"); + SettingGroup sgFilters = settings.createGroup("stateFilters"); sgGeneral.add(new EnumSetting.Builder() .name("shape-mode") @@ -115,7 +115,7 @@ public void initWidgets() { // Add state filters setting sgFilters.add(new StringListSetting.Builder() - .name("NBT-Data") + .name("stateFilters") .description("Filters with states (e.g. 'waterlogged=false', 'facing=north', 'ominous=true'). Only blocks matching ALL filters will be shown.") .defaultValue(new ArrayList<>()) .onModuleActivated(stringSetting -> stringSetting.set(blockData.stateFilters))