Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 114 additions & 70 deletions common/src/main/java/com/github/epsilon/modules/impl/render/ESP.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.epsilon.modules.impl.render;

import com.github.epsilon.events.bus.EventHandler;
import com.github.epsilon.events.impl.PlayerTickEvent;
import com.github.epsilon.events.impl.Render3DEvent;
import com.github.epsilon.managers.Managers;
import com.github.epsilon.modules.Category;
Expand All @@ -9,21 +10,25 @@
import com.github.epsilon.settings.impl.BoolSetting;
import com.github.epsilon.settings.impl.ColorSetting;
import com.github.epsilon.settings.impl.DoubleSetting;
import com.github.epsilon.utils.timer.TimerUtils;
import com.google.common.collect.Lists;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.util.Mth;
import net.minecraft.util.Util;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.ChestType;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.phys.AABB;

import java.awt.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ESP extends Module {

Expand All @@ -33,11 +38,19 @@ private ESP() {
super("ESP", Category.RENDER);
}

private final BoolSetting blocks = boolSetting("Blocks", true);
private final BlockListSetting blockList = blockListSetting("Block List",
private final BoolSetting blocksValue = boolSetting("Blocks", true);
private final BlockListSetting blockListValue = blockListSetting("Block List",
List.of(
Blocks.CHEST,
Blocks.TRAPPED_CHEST,
Blocks.COPPER_CHEST,
Blocks.EXPOSED_COPPER_CHEST,
Blocks.WEATHERED_COPPER_CHEST,
Blocks.OXIDIZED_COPPER_CHEST,
Blocks.WAXED_COPPER_CHEST,
Blocks.WAXED_EXPOSED_COPPER_CHEST,
Blocks.WAXED_WEATHERED_COPPER_CHEST,
Blocks.WAXED_OXIDIZED_COPPER_CHEST,
Blocks.ENDER_CHEST,
Blocks.BARREL,
Blocks.SHULKER_BOX,
Expand All @@ -57,94 +70,125 @@ private ESP() {
Blocks.GREEN_SHULKER_BOX,
Blocks.RED_SHULKER_BOX,
Blocks.BLACK_SHULKER_BOX
), blocks::getValue);
), blocksValue::getValue);
private final BoolSetting illegals = boolSetting("Illegals", true);
private final DoubleSetting range = doubleSetting("Range", 64.0, 1.0, 128.0, 1.0);
private final ColorSetting color = colorSetting("Color", new Color(160, 210, 255, 30));
private final ColorSetting sideColor = colorSetting("Side Color", new Color(160, 210, 255, 30));
private final ColorSetting lineColor = colorSetting("Line Color", new Color(160, 210, 255, 180));
private final BoolSetting blur = boolSetting("Blur", true);
private final DoubleSetting blurStrength = doubleSetting("Blur Strength", 5.0, 0.0, 16.0, 0.5, blur::getValue);

@EventHandler
private void onRender3D(Render3DEvent event) {
if (blocks.getValue()) {
double maxRange = range.getValue();
int renderDistance = mc.options.renderDistance().get();
private final ExecutorService searchThread = Executors.newSingleThreadExecutor();
private final TimerUtils searchTimer = new TimerUtils();
private boolean canContinue;

BlockPos playerPos = mc.player.blockPosition();
ChunkPos playerChunk = mc.player.chunkPosition();
Set<Block> selectedBlocks = blockList.asSet();
Set<BlockPos> renderedBlocks = new HashSet<>();
public static List<AABB> boxes = new ArrayList<>();

if (selectedBlocks.isEmpty()) {
return;
}
@Override
protected void onEnable() {
boxes.clear();
canContinue = true;
}

for (int x = -renderDistance; x <= renderDistance; x++) {
for (int z = -renderDistance; z <= renderDistance; z++) {
int chunkX = playerChunk.x() + x;
int chunkZ = playerChunk.z() + z;
if (!mc.level.hasChunk(chunkX, chunkZ)) {
continue;
}
@EventHandler
private void onPlayerTick(PlayerTickEvent.Pre event) {
if (searchTimer.every(1000) && canContinue) {
CompletableFuture.supplyAsync(this::scan, searchThread).thenAcceptAsync(newAABBList -> {
boxes = newAABBList;
canContinue = true;
}, Util.backgroundExecutor());
canContinue = false;
}
}

LevelChunk chunk = mc.level.getChunkSource().getChunkNow(chunkX, chunkZ);
if (chunk == null) {
continue;
}
@EventHandler
private void onRender3D(Render3DEvent event) {
if (!boxes.isEmpty()) {
for (AABB aabb : Lists.newArrayList(boxes)) {
if (blur.getValue()) Managers.RENDER.addBlurredBox(aabb, blurStrength.getValue());
Managers.RENDER.addFilledBox(aabb, sideColor.getValue());
Managers.RENDER.addOutlineBox(aabb, lineColor.getValue());
}
}
}

for (BlockEntity entity : chunk.getBlockEntities().values()) {
BlockPos blockPos = entity.getBlockPos();
BlockState state = mc.level.getBlockState(blockPos);
if (!selectedBlocks.contains(state.getBlock())) {
continue;
private List<AABB> scan() {
List<AABB> boxes = new ArrayList<>();
Set<BlockPos> processed = new HashSet<>();

int startX = Mth.floor(mc.player.getX() - range.getValue());
int endX = Mth.ceil(mc.player.getX() + range.getValue());
int startY = mc.level.getMinY() + 1;
int endY = mc.level.getMaxY();
int startZ = Mth.floor(mc.player.getZ() - range.getValue());
int endZ = Mth.ceil(mc.player.getZ() + range.getValue());

for (int x = startX; x <= endX; x++) {
for (int y = startY; y <= endY; y++) {
for (int z = startZ; z <= endZ; z++) {
BlockPos blockPos = new BlockPos(x, y, z);
if (!processed.contains(blockPos)) {
BlockState blockState = mc.level.getBlockState(blockPos);
if (shouldAdd(blockState.getBlock(), blockPos)) {
boxes.add(getConnectedShapeAABB(blockPos, blockState, processed));
}
renderBlock(blockPos, state, selectedBlocks, renderedBlocks, playerPos, maxRange);
}
}
}
}
return boxes;
}

int blockRange = (int) Math.ceil(maxRange);
int minY = mc.level.getMinY();
int maxY = mc.level.getMaxY();
BlockPos min = new BlockPos(playerPos.getX() - blockRange, Math.max(minY, playerPos.getY() - blockRange), playerPos.getZ() - blockRange);
BlockPos max = new BlockPos(playerPos.getX() + blockRange, Math.min(maxY, playerPos.getY() + blockRange), playerPos.getZ() + blockRange);
for (BlockPos pos : BlockPos.betweenClosed(min, max)) {
if (!mc.level.isLoaded(pos) || renderedBlocks.contains(pos)) {
continue;
}
BlockState state = mc.level.getBlockState(pos);
if (selectedBlocks.contains(state.getBlock())) {
renderBlock(pos.immutable(), state, selectedBlocks, renderedBlocks, playerPos, maxRange);
}
private boolean shouldAdd(Block block, BlockPos pos) {
if (block instanceof AirBlock) return false;
if (blockListValue.getValue().contains(block)) return true;
if (illegals.getValue()) return isIllegal(block, pos);
return false;
}

private boolean isIllegal(Block block, BlockPos pos) {
if (block instanceof CommandBlock || block instanceof BarrierBlock) return true;

if (block == Blocks.BEDROCK) {
if (!Level.NETHER.equals(mc.level.dimension())) {
return pos.getY() > 4;
} else {
return pos.getY() > 127 || (pos.getY() < 123 && pos.getY() > 4);
}
}
return false;
}

private void renderBlock(BlockPos blockPos, BlockState state, Set<Block> selectedBlocks, Set<BlockPos> renderedBlocks, BlockPos playerPos, double maxRange) {
if (blockPos.distSqr(playerPos) > maxRange * maxRange || !renderedBlocks.add(blockPos)) {
return;
}
private AABB getConnectedShapeAABB(BlockPos blockPos, BlockState state, Set<BlockPos> processed) {
processed.add(blockPos);
AABB box = getShapeAABB(blockPos, state);

AABB box = getAABB(blockPos);
if (state.getBlock() instanceof ChestBlock && state.getValue(ChestBlock.TYPE) != ChestType.SINGLE) {
BlockPos connectedPos = ChestBlock.getConnectedBlockPos(blockPos, state);
if (mc.level.isLoaded(connectedPos)) {
BlockState connectedState = mc.level.getBlockState(connectedPos);
if (selectedBlocks.contains(connectedState.getBlock())
&& connectedState.getBlock() == state.getBlock()
&& connectedState.getValue(ChestBlock.TYPE) == state.getValue(ChestBlock.TYPE).getOpposite()
&& connectedState.getValue(ChestBlock.FACING) == state.getValue(ChestBlock.FACING)) {
box = box.minmax(getAABB(connectedPos));
renderedBlocks.add(connectedPos);
}
BlockState connectedState = mc.level.getBlockState(connectedPos);
if (isConnectedChestPart(blockPos, state, connectedState, connectedPos)) {
processed.add(connectedPos);
box = box.minmax(getShapeAABB(connectedPos, connectedState));
}
}

if (blur.getValue()) Managers.RENDER.addBlurredBox(box, blurStrength.getValue());
Managers.RENDER.addFilledBox(box, color.getValue());
return box;
}

private boolean isConnectedChestPart(BlockPos blockPos, BlockState state, BlockState connectedState, BlockPos connectedPos) {
if (!(state.getBlock() instanceof ChestBlock chestBlock)) return false;
if (!chestBlock.chestCanConnectTo(connectedState)) return false;
if (!connectedState.hasProperty(ChestBlock.TYPE) || !connectedState.hasProperty(ChestBlock.FACING))
return false;
if (connectedState.getValue(ChestBlock.TYPE) == ChestType.SINGLE) return false;
if (connectedState.getValue(ChestBlock.FACING) != state.getValue(ChestBlock.FACING)) return false;
if (!ChestBlock.getConnectedBlockPos(connectedPos, connectedState).equals(blockPos)) return false;

return shouldAdd(connectedState.getBlock(), connectedPos);
}

private AABB getAABB(BlockPos blockPos) {
return mc.level.getBlockState(blockPos).getShape(mc.level, blockPos).bounds().move(blockPos);
private AABB getShapeAABB(BlockPos blockPos, BlockState state) {
return state.getShape(mc.level, blockPos).bounds().move(blockPos);
}

}
Loading