/* * Copyright (C) 2017 - 2019 | Wurst-Imperium | All rights reserved. * * This source code is subject to the terms of the GNU General Public * License, version 3. If a copy of the GPL was not distributed with this * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt */ package net.wurstclient.forge.hacks; import java.util.ArrayList; import org.lwjgl.opengl.GL11; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityMinecartChest; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityChest; import net.minecraft.tileentity.TileEntityEnderChest; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.wurstclient.fmlevents.WCameraTransformViewBobbingEvent; import net.wurstclient.fmlevents.WUpdateEvent; import net.wurstclient.forge.Category; import net.wurstclient.forge.Hack; import net.wurstclient.forge.compatibility.WMinecraft; import net.wurstclient.forge.compatibility.WPlayer; import net.wurstclient.forge.compatibility.WVec3d; import net.wurstclient.forge.settings.EnumSetting; import net.wurstclient.forge.utils.BlockUtils; import net.wurstclient.forge.utils.RenderUtils; import net.wurstclient.forge.utils.RotationUtils; public final class ChestEspHack extends Hack { private final EnumSetting<Style> style = new EnumSetting<>("Style", Style.values(), Style.BOXES); private final ArrayList<AxisAlignedBB> basicChests = new ArrayList<>(); private final ArrayList<AxisAlignedBB> trappedChests = new ArrayList<>(); private final ArrayList<AxisAlignedBB> enderChests = new ArrayList<>(); private final ArrayList<Entity> minecarts = new ArrayList<>(); private int greenBox; private int orangeBox; private int cyanBox; private int normalChests; public ChestEspHack() { super("ChestESP", "Highlights nearby chests.\n" + "\u00a7agreen\u00a7r - normal chests\n" + "\u00a76orange\u00a7r - trapped chests\n" + "\u00a7bcyan\u00a7r - ender chests"); setCategory(Category.RENDER); addSetting(style); } @Override protected void onEnable() { MinecraftForge.EVENT_BUS.register(this); AxisAlignedBB bb = new AxisAlignedBB(BlockPos.ORIGIN); greenBox = GL11.glGenLists(1); GL11.glNewList(greenBox, GL11.GL_COMPILE); GL11.glColor4f(0, 1, 0, 0.25F); GL11.glBegin(GL11.GL_QUADS); RenderUtils.drawSolidBox(bb); GL11.glEnd(); GL11.glColor4f(0, 1, 0, 0.5F); GL11.glBegin(GL11.GL_LINES); RenderUtils.drawOutlinedBox(bb); GL11.glEnd(); GL11.glEndList(); orangeBox = GL11.glGenLists(1); GL11.glNewList(orangeBox, GL11.GL_COMPILE); GL11.glColor4f(1, 0.5F, 0, 0.25F); GL11.glBegin(GL11.GL_QUADS); RenderUtils.drawSolidBox(bb); GL11.glEnd(); GL11.glColor4f(1, 0.5F, 0, 0.5F); GL11.glBegin(GL11.GL_LINES); RenderUtils.drawOutlinedBox(bb); GL11.glEnd(); GL11.glEndList(); cyanBox = GL11.glGenLists(1); GL11.glNewList(cyanBox, GL11.GL_COMPILE); GL11.glColor4f(0, 1, 1, 0.25F); GL11.glBegin(GL11.GL_QUADS); RenderUtils.drawSolidBox(bb); GL11.glEnd(); GL11.glColor4f(0, 1, 1, 0.5F); GL11.glBegin(GL11.GL_LINES); RenderUtils.drawOutlinedBox(bb); GL11.glEnd(); GL11.glEndList(); normalChests = GL11.glGenLists(1); } @Override protected void onDisable() { MinecraftForge.EVENT_BUS.unregister(this); GL11.glDeleteLists(greenBox, 1); greenBox = 0; GL11.glDeleteLists(orangeBox, 1); orangeBox = 0; GL11.glDeleteLists(cyanBox, 1); cyanBox = 0; GL11.glDeleteLists(normalChests, 1); normalChests = 0; } @SubscribeEvent public void onUpdate(WUpdateEvent event) { World world = WPlayer.getWorld(event.getPlayer()); basicChests.clear(); trappedChests.clear(); enderChests.clear(); for(TileEntity tileEntity : world.loadedTileEntityList) if(tileEntity instanceof TileEntityChest) { // ignore other block in double chest TileEntityChest chest = (TileEntityChest)tileEntity; if(chest.adjacentChestXPos != null || chest.adjacentChestZPos != null) continue; // get hitbox BlockPos pos = chest.getPos(); AxisAlignedBB bb = BlockUtils.getBoundingBox(pos); // larger box for double chest if(chest.adjacentChestXNeg != null) { BlockPos pos2 = chest.adjacentChestXNeg.getPos(); AxisAlignedBB bb2 = BlockUtils.getBoundingBox(pos2); bb = bb.union(bb2); }else if(chest.adjacentChestZNeg != null) { BlockPos pos2 = chest.adjacentChestZNeg.getPos(); AxisAlignedBB bb2 = BlockUtils.getBoundingBox(pos2); bb = bb.union(bb2); } // add to appropriate list switch(chest.getChestType()) { case BASIC: basicChests.add(bb); break; case TRAP: trappedChests.add(bb); break; } }else if(tileEntity instanceof TileEntityEnderChest) { BlockPos pos = ((TileEntityEnderChest)tileEntity).getPos(); AxisAlignedBB bb = BlockUtils.getBoundingBox(pos); enderChests.add(bb); } GL11.glNewList(normalChests, GL11.GL_COMPILE); renderBoxes(basicChests, greenBox); renderBoxes(trappedChests, orangeBox); renderBoxes(enderChests, cyanBox); GL11.glEndList(); // minecarts minecarts.clear(); for(Entity entity : world.loadedEntityList) if(entity instanceof EntityMinecartChest) minecarts.add(entity); } @SubscribeEvent public void onCameraTransformViewBobbing( WCameraTransformViewBobbingEvent event) { if(style.getSelected().lines) event.setCanceled(true); } @SubscribeEvent public void onRenderWorldLast(RenderWorldLastEvent event) { // GL settings GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GL11.glEnable(GL11.GL_LINE_SMOOTH); GL11.glLineWidth(2); GL11.glDisable(GL11.GL_TEXTURE_2D); GL11.glEnable(GL11.GL_CULL_FACE); GL11.glDisable(GL11.GL_DEPTH_TEST); GL11.glPushMatrix(); GL11.glTranslated(-TileEntityRendererDispatcher.staticPlayerX, -TileEntityRendererDispatcher.staticPlayerY, -TileEntityRendererDispatcher.staticPlayerZ); // minecart interpolation double partialTicks = event.getPartialTicks(); ArrayList<AxisAlignedBB> minecartBoxes = new ArrayList<>(minecarts.size()); minecarts.forEach(e -> { double offsetX = -(e.posX - e.lastTickPosX) + (e.posX - e.lastTickPosX) * partialTicks; double offsetY = -(e.posY - e.lastTickPosY) + (e.posY - e.lastTickPosY) * partialTicks; double offsetZ = -(e.posZ - e.lastTickPosZ) + (e.posZ - e.lastTickPosZ) * partialTicks; minecartBoxes.add( e.getRenderBoundingBox().offset(offsetX, offsetY, offsetZ)); }); if(style.getSelected().boxes) { GL11.glCallList(normalChests); renderBoxes(minecartBoxes, greenBox); } if(style.getSelected().lines) { Vec3d start = RotationUtils.getClientLookVec() .addVector(0, WMinecraft.getPlayer().getEyeHeight(), 0) .addVector(TileEntityRendererDispatcher.staticPlayerX, TileEntityRendererDispatcher.staticPlayerY, TileEntityRendererDispatcher.staticPlayerZ); GL11.glBegin(GL11.GL_LINES); GL11.glColor4f(0, 1, 0, 0.5F); renderLines(start, basicChests); renderLines(start, minecartBoxes); GL11.glColor4f(1, 0.5F, 0, 0.5F); renderLines(start, trappedChests); GL11.glColor4f(0, 1, 1, 0.5F); renderLines(start, enderChests); GL11.glEnd(); } GL11.glPopMatrix(); // GL resets GL11.glColor4f(1, 1, 1, 1); GL11.glEnable(GL11.GL_DEPTH_TEST); GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glDisable(GL11.GL_BLEND); GL11.glDisable(GL11.GL_LINE_SMOOTH); } private void renderBoxes(ArrayList<AxisAlignedBB> boxes, int displayList) { for(AxisAlignedBB bb : boxes) { GL11.glPushMatrix(); GL11.glTranslated(bb.minX, bb.minY, bb.minZ); GL11.glScaled(bb.maxX - bb.minX, bb.maxY - bb.minY, bb.maxZ - bb.minZ); GL11.glCallList(displayList); GL11.glPopMatrix(); } } private void renderLines(Vec3d start, ArrayList<AxisAlignedBB> boxes) { for(AxisAlignedBB bb : boxes) { Vec3d end = bb.getCenter(); GL11.glVertex3d(WVec3d.getX(start), WVec3d.getY(start), WVec3d.getZ(start)); GL11.glVertex3d(WVec3d.getX(end), WVec3d.getY(end), WVec3d.getZ(end)); } } private enum Style { BOXES("Boxes only", true, false), LINES("Lines only", false, true), LINES_AND_BOXES("Lines and boxes", true, true); private final String name; private final boolean boxes; private final boolean lines; private Style(String name, boolean boxes, boolean lines) { this.name = name; this.boxes = boxes; this.lines = lines; } @Override public String toString() { return name; } } }