diff --git a/README.md b/README.md index 6185616..0b2035c 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Public edition of FumoUtils - AutoDump - ChatNotifier - DoujinDupe +- ItemESP - MapHighlighter - QuartzFarmer - RegionFileHighlighter diff --git a/src/main/java/moe/kyuunex/fumo_utils/FumoUtils.java b/src/main/java/moe/kyuunex/fumo_utils/FumoUtils.java index 1be6efa..66b06d1 100644 --- a/src/main/java/moe/kyuunex/fumo_utils/FumoUtils.java +++ b/src/main/java/moe/kyuunex/fumo_utils/FumoUtils.java @@ -25,6 +25,7 @@ public void onInitialize() { Modules.get().add(new AutoDump()); Modules.get().add(new ChatNotifier()); Modules.get().add(new DoujinDupe()); + Modules.get().add(new ItemESP()); Modules.get().add(new MapHighlighter()); Modules.get().add(new QuartzFarmer()); Modules.get().add(new RegionFileHighlighter()); diff --git a/src/main/java/moe/kyuunex/fumo_utils/modules/ItemESP.java b/src/main/java/moe/kyuunex/fumo_utils/modules/ItemESP.java new file mode 100644 index 0000000..17e0678 --- /dev/null +++ b/src/main/java/moe/kyuunex/fumo_utils/modules/ItemESP.java @@ -0,0 +1,298 @@ +package moe.kyuunex.fumo_utils.modules; + +import meteordevelopment.meteorclient.events.render.Render2DEvent; +import meteordevelopment.meteorclient.events.render.Render3DEvent; +import meteordevelopment.meteorclient.renderer.Renderer2D; +import meteordevelopment.meteorclient.renderer.ShapeMode; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.entity.EntityUtils; +import meteordevelopment.meteorclient.utils.player.PlayerUtils; +import meteordevelopment.meteorclient.utils.render.NametagUtils; +import meteordevelopment.meteorclient.utils.render.WireframeEntityRenderer; +import meteordevelopment.meteorclient.utils.render.color.Color; +import meteordevelopment.meteorclient.utils.render.color.SettingColor; +import meteordevelopment.orbit.EventHandler; +import moe.kyuunex.fumo_utils.FumoUtils; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.ItemEntity; +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.MathHelper; +import org.joml.Vector3d; + +import java.util.List; + +public class ItemESP extends Module { + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + + // General + + public final Setting> targetItems = sgGeneral.add(new ItemListSetting.Builder() + .name("target-items") + .description("Items to look for") + .defaultValue(Items.ELYTRA) + .build() + ); + + public final Setting mode = sgGeneral.add(new EnumSetting.Builder() + .name("mode") + .description("Rendering mode.") + .defaultValue(Mode.Box) + .build() + ); + + public final Setting outlineWidth = sgGeneral.add(new IntSetting.Builder() + .name("outline-width") + .description("The width of the shader outline.") + .visible(() -> mode.get() == Mode.Shader) + .defaultValue(2) + .range(1, 10) + .sliderRange(1, 5) + .build() + ); + + public final Setting glowMultiplier = sgGeneral.add(new DoubleSetting.Builder() + .name("glow-multiplier") + .description("Multiplier for glow effect") + .visible(() -> mode.get() == Mode.Shader) + .decimalPlaces(3) + .defaultValue(3.5) + .min(0) + .sliderMax(10) + .build() + ); + + public final Setting shapeMode = sgGeneral.add(new EnumSetting.Builder() + .name("shape-mode") + .description("How the shapes are rendered.") + .visible(() -> mode.get() != Mode.Glow) + .defaultValue(ShapeMode.Both) + .build() + ); + + public final Setting fillOpacity = sgGeneral.add(new DoubleSetting.Builder() + .name("fill-opacity") + .description("The opacity of the shape fill.") + .visible(() -> shapeMode.get() != ShapeMode.Lines && mode.get() != Mode.Glow) + .defaultValue(0.4) + .range(0, 1) + .sliderMax(1) + .build() + ); + + private final Setting fadeDistance = sgGeneral.add(new DoubleSetting.Builder() + .name("fade-distance") + .description("The distance from an entity where the color begins to fade.") + .defaultValue(1) + .min(0) + .sliderMax(12) + .build() + ); + + // Colors + + public final Setting distance = sgGeneral.add(new BoolSetting.Builder() + .name("distance-colors") + .description("Changes the color of tracers depending on distance.") + .defaultValue(false) + .build() + ); + + private final Setting miscColor = sgGeneral.add(new ColorSetting.Builder() + .name("misc-color") + .description("The misc color.") + .defaultValue(new SettingColor(255, 0, 0, 255)) + .visible(() -> !distance.get()) + .build() + ); + + private final Color lineColor = new Color(); + private final Color sideColor = new Color(); + private final Color baseColor = new Color(); + + private final Vector3d pos1 = new Vector3d(); + private final Vector3d pos2 = new Vector3d(); + private final Vector3d pos = new Vector3d(); + + private int count; + + public ItemESP() { + super(FumoUtils.CATEGORY, "item-esp", "Renders specific dropped items through walls."); + } + + // Box + + @EventHandler + private void onRender3D(Render3DEvent event) { + if (mode.get() == Mode._2D) return; + + count = 0; + + for (Entity entity : mc.world.getEntities()) { + if (shouldSkip(entity)) continue; + + if (mode.get() == Mode.Box || mode.get() == Mode.Wireframe) drawBoundingBox(event, entity); + count++; + } + } + + private void drawBoundingBox(Render3DEvent event, Entity entity) { + Color color = getColor(entity); + if (color != null) { + lineColor.set(color); + sideColor.set(color).a((int) (sideColor.a * fillOpacity.get())); + } + + if (mode.get() == Mode.Box) { + double x = MathHelper.lerp(event.tickDelta, entity.lastRenderX, entity.getX()) - entity.getX(); + double y = MathHelper.lerp(event.tickDelta, entity.lastRenderY, entity.getY()) - entity.getY(); + double z = MathHelper.lerp(event.tickDelta, entity.lastRenderZ, entity.getZ()) - entity.getZ(); + + Box box = entity.getBoundingBox(); + event.renderer.box(x + box.minX, y + box.minY, z + box.minZ, x + box.maxX, y + box.maxY, z + box.maxZ, sideColor, lineColor, shapeMode.get(), 0); + } else { + WireframeEntityRenderer.render(event, entity, 1, sideColor, lineColor, shapeMode.get()); + } + } + + // 2D + + @EventHandler + private void onRender2D(Render2DEvent event) { + if (mode.get() != Mode._2D) return; + + Renderer2D.COLOR.begin(); + count = 0; + + for (Entity entity : mc.world.getEntities()) { + if (shouldSkip(entity)) continue; + + Box box = entity.getBoundingBox(); + + double x = MathHelper.lerp(event.tickDelta, entity.lastRenderX, entity.getX()) - entity.getX(); + double y = MathHelper.lerp(event.tickDelta, entity.lastRenderY, entity.getY()) - entity.getY(); + double z = MathHelper.lerp(event.tickDelta, entity.lastRenderZ, entity.getZ()) - entity.getZ(); + + // Check corners + pos1.set(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE); + pos2.set(0, 0, 0); + + // Bottom + if (checkCorner(box.minX + x, box.minY + y, box.minZ + z, pos1, pos2)) continue; + if (checkCorner(box.maxX + x, box.minY + y, box.minZ + z, pos1, pos2)) continue; + if (checkCorner(box.minX + x, box.minY + y, box.maxZ + z, pos1, pos2)) continue; + if (checkCorner(box.maxX + x, box.minY + y, box.maxZ + z, pos1, pos2)) continue; + + // Top + if (checkCorner(box.minX + x, box.maxY + y, box.minZ + z, pos1, pos2)) continue; + if (checkCorner(box.maxX + x, box.maxY + y, box.minZ + z, pos1, pos2)) continue; + if (checkCorner(box.minX + x, box.maxY + y, box.maxZ + z, pos1, pos2)) continue; + if (checkCorner(box.maxX + x, box.maxY + y, box.maxZ + z, pos1, pos2)) continue; + + // Setup color + Color color = getColor(entity); + if (color != null) { + lineColor.set(color); + sideColor.set(color).a((int) (sideColor.a * fillOpacity.get())); + } + + // Render + if (shapeMode.get() != ShapeMode.Lines && sideColor.a > 0) { + Renderer2D.COLOR.quad(pos1.x, pos1.y, pos2.x - pos1.x, pos2.y - pos1.y, sideColor); + } + + if (shapeMode.get() != ShapeMode.Sides) { + Renderer2D.COLOR.line(pos1.x, pos1.y, pos1.x, pos2.y, lineColor); + Renderer2D.COLOR.line(pos2.x, pos1.y, pos2.x, pos2.y, lineColor); + Renderer2D.COLOR.line(pos1.x, pos1.y, pos2.x, pos1.y, lineColor); + Renderer2D.COLOR.line(pos1.x, pos2.y, pos2.x, pos2.y, lineColor); + } + + count++; + } + + Renderer2D.COLOR.render(null); + } + + private boolean checkCorner(double x, double y, double z, Vector3d min, Vector3d max) { + pos.set(x, y, z); + if (!NametagUtils.to2D(pos, 1)) return true; + + // Check Min + if (pos.x < min.x) min.x = pos.x; + if (pos.y < min.y) min.y = pos.y; + if (pos.z < min.z) min.z = pos.z; + + // Check Max + if (pos.x > max.x) max.x = pos.x; + if (pos.y > max.y) max.y = pos.y; + if (pos.z > max.z) max.z = pos.z; + + return false; + } + + // Utils + + public boolean shouldSkip(Entity entity) { + if (entity.getType() != EntityType.ITEM) return true; + if (!(entity instanceof ItemEntity itemEntity)) return true; + if (!targetItems.get().contains(itemEntity.getStack().getItem())) return true; + if (entity == mc.cameraEntity && mc.options.getPerspective().isFirstPerson()) return true; + return !EntityUtils.isInRenderDistance(entity); + } + + public Color getColor(Entity entity) { + double alpha = getFadeAlpha(entity); + if (alpha == 0) return null; + + Color color = getEntityTypeColor(entity); + return baseColor.set(color.r, color.g, color.b, (int) (color.a * alpha)); + } + + private double getFadeAlpha(Entity entity) { + double dist = PlayerUtils.squaredDistanceToCamera(entity.getX() + entity.getWidth() / 2, entity.getY() + entity.getEyeHeight(entity.getPose()), entity.getZ() + entity.getWidth() / 2); + double fadeDist = Math.pow(fadeDistance.get(), 2); + double alpha = 1; + if (dist <= fadeDist * fadeDist) alpha = (float) (Math.sqrt(dist) / fadeDist); + if (alpha <= 0.075) alpha = 0; + return alpha; + } + + public Color getEntityTypeColor(Entity entity) { + if (distance.get()) { + return EntityUtils.getColorFromDistance(entity); + } else { + entity.getType().getSpawnGroup(); + return miscColor.get(); + } + } + + @Override + public String getInfoString() { + return Integer.toString(count); + } + + public boolean isShader() { + return isActive() && mode.get() == Mode.Shader; + } + + public boolean isGlow() { + return isActive() && mode.get() == Mode.Glow; + } + + public enum Mode { + Box, + Wireframe, + _2D, + Shader, + Glow; + + @Override + public String toString() { + return this == _2D ? "2D" : super.toString(); + } + } +}