package dev.crucifixbeta.mod.modules.impl.render;

import asm.accessors.IEntity;
import dev.crucifixbeta.CrucifixBeta;
import dev.crucifixbeta.api.events.eventbus.EventListener;
import dev.crucifixbeta.api.events.impl.EntitySpawnedEvent;
import dev.crucifixbeta.api.utils.math.MathUtil;
import dev.crucifixbeta.api.utils.render.Render2DUtil;
import dev.crucifixbeta.api.utils.render.Render3DUtil;
import dev.crucifixbeta.api.utils.render.TextUtil;
import dev.crucifixbeta.api.utils.world.BlockUtil;
import dev.crucifixbeta.mod.modules.Module;
import dev.crucifixbeta.mod.modules.settings.impl.BooleanSetting;
import dev.crucifixbeta.mod.modules.settings.impl.ColorSetting;
import dev.crucifixbeta.mod.modules.settings.impl.EnumSetting;
import dev.crucifixbeta.mod.modules.settings.impl.SliderSetting;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Comparator;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.block.entity.EndPortalBlockEntity;
import net.minecraft.block.entity.EnderChestBlockEntity;
import net.minecraft.block.entity.ShulkerBoxBlockEntity;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.thrown.EnderPearlEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;

@Environment(EnvType.CLIENT)
public class ESP extends HoleESP {
   public static ESP INSTANCE;
   private final EnumSetting<ESP.Page> page = this.add(new EnumSetting<>("Page", ESP.Page.ESP));
   public final EnumSetting<ESP.RenderMode> mode = this.add(
      new EnumSetting<>("Mode", ESP.RenderMode.ThreeD, () -> this.page.is(ESP.Page.ESP))
   );
   private final BooleanSetting twoDOutline = this.add(
      new BooleanSetting("2DOutline", true, () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() == ESP.RenderMode.TwoD)
   );
   private final BooleanSetting twoDHealth = this.add(
      new BooleanSetting("2DHealth", true, () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() == ESP.RenderMode.TwoD)
   );
   private final ColorSetting hHealth = this.add(
      new ColorSetting("HighHealth", new Color(0, 255, 0, 255), () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() == ESP.RenderMode.TwoD)
   );
   private final ColorSetting mHealth = this.add(
      new ColorSetting("MidHealth", new Color(255, 255, 0, 255), () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() == ESP.RenderMode.TwoD)
   );
   private final ColorSetting lHealth = this.add(
      new ColorSetting("LowHealth", new Color(255, 0, 0, 255), () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() == ESP.RenderMode.TwoD)
   );
   private final BooleanSetting twoDArmorDura = this.add(
      new BooleanSetting("2DArmorDura", true, () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() == ESP.RenderMode.TwoD)
   );
   private final ColorSetting armorDuraColor = this.add(
      new ColorSetting(
         "ArmorDuraColor",
         new Color(3145472),
         () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() == ESP.RenderMode.TwoD && this.twoDArmorDura.getValue()
      )
   );
   private final SliderSetting duraScale = this.add(
      new SliderSetting(
         "DuraScale",
         1.0,
         0.0,
         2.0,
         0.1,
         () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() == ESP.RenderMode.TwoD && this.twoDArmorDura.getValue()
      )
   );
   public final BooleanSetting target = this.add(new BooleanSetting("Target", true, () -> this.page.is(ESP.Page.ESP)).setParent());
   public final BooleanSetting self = this.add(new BooleanSetting("Self", false, () -> this.page.is(ESP.Page.ESP) && this.target.isOpen()));
   private final ColorSetting endPortalFill = this.add(
      new ColorSetting(
            "EndPortalFill",
            new Color(255, 243, 129, 100),
            () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() != ESP.RenderMode.TwoD && this.target.isOpen()
         )
         .injectBoolean(false)
   );
   private final ColorSetting endPortalOutline = this.add(
      new ColorSetting(
            "EndPortalOutline",
            new Color(255, 243, 129, 100),
            () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() != ESP.RenderMode.TwoD && this.target.isOpen()
         )
         .injectBoolean(false)
   );
   private final ColorSetting itemFill = this.add(
      new ColorSetting("ItemFill", new Color(255, 255, 255, 100), () -> this.page.is(ESP.Page.ESP) && this.target.isOpen())
         .injectBoolean(true)
   );
   private final ColorSetting itemOutline = this.add(
      new ColorSetting("ItemOutline", new Color(255, 255, 255, 100), () -> this.page.is(ESP.Page.ESP) && this.target.isOpen()).injectBoolean(true)
   );
   private final ColorSetting playerFill = this.add(
      new ColorSetting("PlayerFill", new Color(255, 255, 255, 100), () -> this.page.is(ESP.Page.ESP) && this.target.isOpen())
         .injectBoolean(true)
   );
   private final ColorSetting playerOutline = this.add(
      new ColorSetting("PlayerOutline", new Color(255, 255, 255, 100), () -> this.page.is(ESP.Page.ESP) && this.target.isOpen())
         .injectBoolean(true)
   );
   private final ColorSetting chestFill = this.add(
      new ColorSetting(
            "ChestFill",
            new Color(255, 198, 123, 100),
            () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() != ESP.RenderMode.TwoD && this.target.isOpen()
         )
         .injectBoolean(false)
   );
   private final ColorSetting chestOutline = this.add(
      new ColorSetting(
            "ChestOutline",
            new Color(255, 198, 123, 100),
            () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() != ESP.RenderMode.TwoD && this.target.isOpen()
         )
         .injectBoolean(false)
   );
   private final ColorSetting enderChestFill = this.add(
      new ColorSetting(
            "EnderChestFill",
            new Color(255, 100, 255, 100),
            () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() != ESP.RenderMode.TwoD && this.target.isOpen()
         )
         .injectBoolean(false)
   );
   private final ColorSetting enderChestOutline = this.add(
      new ColorSetting(
            "EnderChestOutline",
            new Color(255, 100, 255, 100),
            () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() != ESP.RenderMode.TwoD && this.target.isOpen()
         )
         .injectBoolean(false)
   );
   private final ColorSetting shulkerBoxFill = this.add(
      new ColorSetting(
            "ShulkerBoxFill",
            new Color(15, 255, 255, 100),
            () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() != ESP.RenderMode.TwoD && this.target.isOpen()
         )
         .injectBoolean(false)
   );
   private final ColorSetting shulkerBoxOutline = this.add(
      new ColorSetting(
            "ShulkerBoxOutline",
            new Color(15, 255, 255, 100),
            () -> this.page.is(ESP.Page.ESP) && this.mode.getValue() != ESP.RenderMode.TwoD && this.target.isOpen()
         )
         .injectBoolean(false)
   );
   public final BooleanSetting item = this.add(new BooleanSetting("ItemName", false, () -> this.page.is(ESP.Page.ESP)).setParent());
   public final BooleanSetting customName = this.add(
      new BooleanSetting("CustomName", false, () -> this.page.is(ESP.Page.ESP) && this.item.isOpen())
   );
   public final BooleanSetting count = this.add(new BooleanSetting("Count", true, () -> this.page.is(ESP.Page.ESP) && this.item.isOpen()));
   private final ColorSetting text = this.add(
      new ColorSetting("Text", new Color(255, 255, 255, 255), () -> this.page.is(ESP.Page.ESP) && this.item.isOpen())
   );
   public final BooleanSetting pearl = this.add(new BooleanSetting("PearlOwner", true, () -> this.page.is(ESP.Page.ESP)));

   public ESP() {
      super("ESP", Module.Category.Render);
      this.setChinese("\u900f\u89c6");
      INSTANCE = this;
      HoleESP.INSTANCE = this;
   }

   @Override
   public void onRender3D(MatrixStack matrixStack) {
      super.onRender3D(matrixStack);
      if (this.mode.getValue() != ESP.RenderMode.TwoD) {
         if (this.item.getValue()) {
            for (Entity var3 : CrucifixBeta.THREAD.getEntities()) {
               if (var3 instanceof ItemEntity var4) {
                  int var5 = var4.getStack().getCount();
                  String var6 = this.count.getValue() && var5 > 1 ? " x" + var5 : "";
                  String var7 = (this.customName.getValue() ? var4.getStack().getName() : var4.getStack().getItem().getName()).getString();
                  Render3DUtil.drawText3D(
                     var7 + var6,
                     ((IEntity)var4)
                        .getDimensions()
                        .getBoxAt(
                           new Vec3d(
                              MathUtil.interpolate(var4.lastRenderX, var4.getX(), (double)mc.getRenderTickCounter().getTickDelta(true)),
                              MathUtil.interpolate(var4.lastRenderY, var4.getY(), (double)mc.getRenderTickCounter().getTickDelta(true)),
                              MathUtil.interpolate(var4.lastRenderZ, var4.getZ(), (double)mc.getRenderTickCounter().getTickDelta(true))
                           )
                        )
                        .expand(0.0, 0.1, 0.0)
                        .getCenter()
                        .add(0.0, 0.5, 0.0),
                     this.text.getValue()
                  );
               }
            }
         }

         if (this.target.getValue()) {
            if (this.itemFill.booleanValue || this.playerFill.booleanValue) {
               for (Entity var10 : CrucifixBeta.THREAD.getEntities()) {
                  if (!(var10 instanceof ItemEntity) || !this.itemFill.booleanValue && !this.itemOutline.booleanValue) {
                     if ((var10 != mc.player || this.self.getValue() && !mc.options.getPerspective().isFirstPerson())
                        && var10 instanceof PlayerEntity
                        && (this.playerFill.booleanValue || this.playerOutline.booleanValue)) {
                        Color var13 = this.playerFill.getValue();
                        Render3DUtil.draw3DBox(
                           matrixStack,
                           ((IEntity)var10)
                              .getDimensions()
                              .getBoxAt(
                                 new Vec3d(
                                    MathUtil.interpolate(var10.lastRenderX, var10.getX(), (double)mc.getRenderTickCounter().getTickDelta(true)),
                                    MathUtil.interpolate(var10.lastRenderY, var10.getY(), (double)mc.getRenderTickCounter().getTickDelta(true)),
                                    MathUtil.interpolate(var10.lastRenderZ, var10.getZ(), (double)mc.getRenderTickCounter().getTickDelta(true))
                                 )
                              )
                              .expand(0.0, 0.1, 0.0),
                           var13,
                           this.playerOutline.getValue(),
                           this.playerOutline.booleanValue,
                           this.playerFill.booleanValue
                        );
                     }
                  } else {
                     Color var12 = this.itemFill.getValue();
                     Render3DUtil.draw3DBox(
                        matrixStack,
                        ((IEntity)var10)
                           .getDimensions()
                           .getBoxAt(
                              new Vec3d(
                                 MathUtil.interpolate(var10.lastRenderX, var10.getX(), (double)mc.getRenderTickCounter().getTickDelta(true)),
                                 MathUtil.interpolate(var10.lastRenderY, var10.getY(), (double)mc.getRenderTickCounter().getTickDelta(true)),
                                 MathUtil.interpolate(var10.lastRenderZ, var10.getZ(), (double)mc.getRenderTickCounter().getTickDelta(true))
                              )
                           ),
                        var12,
                        this.itemOutline.getValue(),
                        this.itemOutline.booleanValue,
                        this.itemFill.booleanValue
                     );
                  }
               }
            }

            for (BlockEntity var14 : BlockUtil.getTileEntities()) {
               if (!(var14 instanceof ChestBlockEntity) || !this.chestFill.booleanValue && !this.chestOutline.booleanValue) {
                  if (!(var14 instanceof EnderChestBlockEntity) || !this.enderChestFill.booleanValue && !this.enderChestOutline.booleanValue) {
                     if (!(var14 instanceof ShulkerBoxBlockEntity) || !this.shulkerBoxFill.booleanValue && !this.shulkerBoxOutline.booleanValue) {
                        if (var14 instanceof EndPortalBlockEntity && (this.endPortalFill.booleanValue || this.endPortalOutline.booleanValue)) {
                           Box var18 = new Box(var14.getPos());
                           Render3DUtil.draw3DBox(
                              matrixStack,
                              var18,
                              this.endPortalFill.getValue(),
                              this.endPortalOutline.getValue(),
                              this.endPortalOutline.booleanValue,
                              this.endPortalFill.booleanValue
                           );
                        }
                     } else {
                        Box var17 = new Box(var14.getPos());
                        Render3DUtil.draw3DBox(
                           matrixStack,
                           var17,
                           this.shulkerBoxFill.getValue(),
                           this.shulkerBoxOutline.getValue(),
                           this.shulkerBoxOutline.booleanValue,
                           this.shulkerBoxFill.booleanValue
                        );
                     }
                  } else {
                     Box var16 = new Box(var14.getPos());
                     Render3DUtil.draw3DBox(
                        matrixStack,
                        var16,
                        this.enderChestFill.getValue(),
                        this.enderChestOutline.getValue(),
                        this.enderChestOutline.booleanValue,
                        this.enderChestFill.booleanValue
                     );
                  }
               } else {
                  Box var15 = new Box(var14.getPos());
                  Render3DUtil.draw3DBox(
                     matrixStack, var15, this.chestFill.getValue(), this.chestOutline.getValue(), this.chestOutline.booleanValue, this.chestFill.booleanValue
                  );
               }
            }
         }
      }
   }

   @Override
   public void onRender2D(DrawContext drawContext, float tickDelta) {
      if (this.mode.getValue() == ESP.RenderMode.TwoD) {
         if (!nullCheck()) {
            if (this.target.getValue()) {
               for (Entity var4 : CrucifixBeta.THREAD.getEntities()) {
                  if (var4 instanceof ItemEntity) {
                     boolean var5 = this.itemOutline.booleanValue;
                     boolean var6 = this.itemFill.booleanValue;
                     if (var5 || var6) {
                        this.draw2DForEntity(
                           drawContext.getMatrices(), var4, this.itemOutline.getValue(), this.itemFill.getValue(), var5, var6, tickDelta, false
                        );
                     }
                  } else if ((var4 != mc.player || this.self.getValue() && !mc.options.getPerspective().isFirstPerson()) && var4 instanceof PlayerEntity) {
                     boolean var9 = this.playerOutline.booleanValue;
                     boolean var10 = this.playerFill.booleanValue;
                     if (var9 || var10) {
                        this.draw2DForEntity(
                           drawContext.getMatrices(), var4, this.playerOutline.getValue(), this.playerFill.getValue(), var9, var10, tickDelta, true
                        );
                     }
                  }
               }
            }

            if (this.item.getValue()) {
               for (Entity var8 : CrucifixBeta.THREAD.getEntities()) {
                  if (var8 instanceof ItemEntity) {
                     this.draw2DItemText(drawContext, (ItemEntity)var8, tickDelta);
                  }
               }
            }
         }
      }
   }

   private void draw2DForEntity(
      MatrixStack matrices, Entity entity, Color outlineColor, Color fillColor, boolean outline, boolean fill, float tickDelta, boolean isPlayer
   ) {
      double[] var9 = this.getEntity2DBox(entity, tickDelta);
      if (var9 != null) {
         float var10 = (float)var9[0];
         float var11 = (float)var9[1];
         float var12 = (float)var9[2];
         float var13 = (float)var9[3];
         if (!(var12 - var10 <= 0.0F) && !(var13 - var11 <= 0.0F)) {
            if (fill) {
               Render2DUtil.drawRect(matrices, var10, var11, var12 - var10, var13 - var11, fillColor);
            }

            if (outline) {
               this.draw2DBox(matrices, var10, var11, var12, var13, outlineColor);
            }

            if (this.twoDHealth.getValue() && entity instanceof LivingEntity var14 && var14.getMaxHealth() > 0.0F && var14.getHealth() > 0.0F) {
               this.draw2DHealthBar(matrices, var10, var11, var13, var14);
            }

            if (isPlayer && this.twoDArmorDura.getValue() && entity instanceof PlayerEntity) {
               this.draw2DArmorDura(matrices, var12, var11, var13, (PlayerEntity)entity);
            }
         }
      }
   }

   private void draw2DBox(MatrixStack matrices, float posX, float posY, float endPosX, float endPosY, Color col) {
      if (this.twoDOutline.getValue()) {
         Render2DUtil.drawRect(matrices, posX - 1.0F, posY, 1.5F, endPosY - posY + 0.5F, Color.BLACK);
         Render2DUtil.drawRect(matrices, posX - 1.0F, posY - 0.5F, endPosX - posX + 1.5F, 1.5F, Color.BLACK);
         Render2DUtil.drawRect(matrices, endPosX - 1.0F, posY, 1.5F, endPosY - posY + 0.5F, Color.BLACK);
         Render2DUtil.drawRect(matrices, posX - 1.0F, endPosY - 1.0F, endPosX - posX + 1.5F, 1.5F, Color.BLACK);
      }

      Render2DUtil.drawRect(matrices, posX - 0.5F, posY, 0.5F, endPosY - posY, col);
      Render2DUtil.drawRect(matrices, posX, endPosY - 0.5F, endPosX - posX, 0.5F, col);
      Render2DUtil.drawRect(matrices, posX - 0.5F, posY, endPosX - posX + 0.5F, 0.5F, col);
      Render2DUtil.drawRect(matrices, endPosX - 0.5F, posY, 0.5F, endPosY - posY, col);
   }

   private void draw2DHealthBar(MatrixStack matrices, float minX, float minY, float maxY, LivingEntity living) {
      float var6 = maxY - minY;
      float var7 = living.getHealth();
      float var8 = living.getMaxHealth();
      float var9 = Math.max(0.0F, Math.min(1.0F, var7 / var8));
      Render2DUtil.drawRect(matrices, minX - 4.0F, minY, 1.0F, var6, Color.BLACK);
      Render2DUtil.drawRect(matrices, minX - 4.0F, maxY - var6 * var9, 1.0F, var6 * var9, this.getHealthColor(var7));
   }

   private Color getHealthColor(float health) {
      if (health >= 20.0F) {
         return this.hHealth.getValue();
      } else {
         return health > 10.0F ? this.mHealth.getValue() : this.lHealth.getValue();
      }
   }

   private void draw2DArmorDura(MatrixStack matrices, float maxX, float minY, float maxY, PlayerEntity player) {
      float var6 = maxY - minY;
      float var7 = var6 / 4.0F;
      ArrayList var8 = new ArrayList();
      var8.add(player.getInventory().armor.get(3));
      var8.add(player.getInventory().armor.get(2));
      var8.add(player.getInventory().armor.get(1));
      var8.add(player.getInventory().armor.get(0));

      for (int var9 = 0; var9 < var8.size(); var9++) {
         ItemStack var10 = (ItemStack)var8.get(var9);
         if (!var10.isEmpty() && var10.getMaxDamage() > 0) {
            float var11 = (float)(var10.getMaxDamage() - var10.getDamage()) / (float)var10.getMaxDamage();
            var11 = Math.max(0.0F, Math.min(1.0F, var11));
            float var12 = minY + var7 * (float)var9;
            float var13 = var12 + var7;
            float var14 = var7 * var11 * this.duraScale.getValueFloat();
            var14 = Math.min(var7, var14);
            Render2DUtil.drawRect(matrices, maxX + 1.5F, var13 - var14, 1.5F, var14, this.armorDuraColor.getValue());
         }
      }
   }

   private double[] getEntity2DBox(Entity ent, float tickDelta) {
      double var3 = MathUtil.interpolate(ent.lastRenderX, ent.getX(), (double)tickDelta);
      double var5 = MathUtil.interpolate(ent.lastRenderY, ent.getY(), (double)tickDelta);
      double var7 = MathUtil.interpolate(ent.lastRenderZ, ent.getZ(), (double)tickDelta);
      Box var9 = ent.getBoundingBox();
      Box var10 = new Box(
         var9.minX - ent.getX() + var3 - 0.05,
         var9.minY - ent.getY() + var5,
         var9.minZ - ent.getZ() + var7 - 0.05,
         var9.maxX - ent.getX() + var3 + 0.05,
         var9.maxY - ent.getY() + var5 + 0.15,
         var9.maxZ - ent.getZ() + var7 + 0.05
      );
      Vec3d[] var11 = new Vec3d[]{
         new Vec3d(var10.minX, var10.minY, var10.minZ),
         new Vec3d(var10.minX, var10.maxY, var10.minZ),
         new Vec3d(var10.maxX, var10.minY, var10.minZ),
         new Vec3d(var10.maxX, var10.maxY, var10.minZ),
         new Vec3d(var10.minX, var10.minY, var10.maxZ),
         new Vec3d(var10.minX, var10.maxY, var10.maxZ),
         new Vec3d(var10.maxX, var10.minY, var10.maxZ),
         new Vec3d(var10.maxX, var10.maxY, var10.maxZ)
      };
      double var12 = Double.POSITIVE_INFINITY;
      double var14 = Double.POSITIVE_INFINITY;
      double var16 = Double.NEGATIVE_INFINITY;
      double var18 = Double.NEGATIVE_INFINITY;
      boolean var20 = false;

      for (Vec3d var24 : var11) {
         Vec3d var25 = TextUtil.worldSpaceToScreenSpace(new Vec3d(var24.x, var24.y, var24.z));
         if (var25.z > 0.0 && var25.z < 1.0) {
            var20 = true;
            var12 = Math.min(var25.x, var12);
            var14 = Math.min(var25.y, var14);
            var16 = Math.max(var25.x, var16);
            var18 = Math.max(var25.y, var18);
         }
      }

      return !var20 ? null : new double[]{var12, var14, var16, var18};
   }

   private void draw2DItemText(DrawContext drawContext, ItemEntity itemEntity, float tickDelta) {
      double[] var4 = this.getEntity2DBox(itemEntity, tickDelta);
      if (var4 != null) {
         int var5 = itemEntity.getStack().getCount();
         String var6 = this.count.getValue() && var5 > 1 ? " x" + var5 : "";
         String var7 = (this.customName.getValue() ? itemEntity.getStack().getName() : itemEntity.getStack().getItem().getName()).getString();
         String var8 = var7 + var6;
         int var9 = mc.textRenderer.getWidth(var8);
         float var10 = (float)(var4[0] + (var4[2] - var4[0]) / 2.0 - (double)var9 / 2.0);
         drawContext.drawText(mc.textRenderer, var8, (int)var10, (int)(var4[1] - 10.0), this.text.getValue().getRGB(), false);
      }
   }

   @Override
   protected boolean holeSettingsVisible() {
      return this.page.is(ESP.Page.Hole);
   }

   @EventListener
   public void onReceivePacket(EntitySpawnedEvent event) {
      if (!nullCheck()) {
         Entity var2;
         if (this.pearl.getValue() && (var2 = event.getEntity()) instanceof EnderPearlEntity) {
            EnderPearlEntity var3 = (EnderPearlEntity)var2;
            if (var3.getOwner() != null) {
               var3.setCustomName(var3.getOwner().getName());
               var3.setCustomNameVisible(true);
            } else {
               mc.world
                  .getPlayers()
                  .stream()
                  .min(Comparator.comparingDouble(p -> p.getPos().distanceTo(new Vec3d(var3.getX(), var3.getY(), var3.getZ()))))
                  .ifPresent(player -> {
                     var3.setCustomName(player.getName());
                     var3.setCustomNameVisible(true);
                  });
            }
         }
      }
   }
@Environment(EnvType.CLIENT)
   private static enum Page {
      ESP,
      Hole;

}

   @Environment(EnvType.CLIENT)
   private static enum RenderMode {
      ThreeD,
      TwoD;

}
}
