diff --git a/build.gradle b/build.gradle index 429771b..faedcaf 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,10 @@ base { group = project.maven_group } +loom { + accessWidenerPath = file("src/main/resources/genyo.accesswidener") +} + repositories { maven { name = "Meteor Dev Releases" diff --git a/src/main/java/com/genyo/addon/GenyoAddon.java b/src/main/java/com/genyo/addon/GenyoAddon.java index 7177e91..9d03740 100644 --- a/src/main/java/com/genyo/addon/GenyoAddon.java +++ b/src/main/java/com/genyo/addon/GenyoAddon.java @@ -2,7 +2,10 @@ import com.genyo.addon.gui.EnemiesTab; import com.genyo.addon.hud.PvPNeccessaryHud; +import com.genyo.addon.managers.Managers; +import com.genyo.addon.modules.AngelSexHulkenberg; import com.genyo.addon.modules.GenyoAutoEZ; +import com.genyo.addon.modules.TescoCrystal; import com.genyo.addon.systems.enemies.Enemies; import com.mojang.logging.LogUtils; import meteordevelopment.meteorclient.addons.GithubRepo; @@ -27,9 +30,13 @@ public void onInitialize() { Systems.add(new Enemies()); Modules.get().add(new GenyoAutoEZ()); + Modules.get().add(new TescoCrystal()); + Modules.get().add(new AngelSexHulkenberg()); Tabs.add(new EnemiesTab()); + Managers.subscribe(); + // HUD Hud.get().register(PvPNeccessaryHud.INFO); } diff --git a/src/main/java/com/genyo/addon/events/TotemPopEvent.java b/src/main/java/com/genyo/addon/events/TotemPopEvent.java new file mode 100644 index 0000000..c004f21 --- /dev/null +++ b/src/main/java/com/genyo/addon/events/TotemPopEvent.java @@ -0,0 +1,17 @@ +package com.genyo.addon.events; + +import net.minecraft.entity.player.PlayerEntity; + +public class TotemPopEvent { + private static final TotemPopEvent INSTANCE = new TotemPopEvent(); + + public PlayerEntity entity; + public int pops; + + public static TotemPopEvent get(PlayerEntity entity, int pops) { + INSTANCE.entity = entity; + INSTANCE.pops = pops; + + return INSTANCE; + } +} diff --git a/src/main/java/com/genyo/addon/hud/PvPNeccessaryHud.java b/src/main/java/com/genyo/addon/hud/PvPNeccessaryHud.java index 3436596..b1d4ae0 100644 --- a/src/main/java/com/genyo/addon/hud/PvPNeccessaryHud.java +++ b/src/main/java/com/genyo/addon/hud/PvPNeccessaryHud.java @@ -7,8 +7,6 @@ import meteordevelopment.meteorclient.systems.hud.HudElement; import meteordevelopment.meteorclient.systems.hud.HudElementInfo; import meteordevelopment.meteorclient.systems.hud.HudRenderer; -import meteordevelopment.meteorclient.utils.player.InvUtils; -import meteordevelopment.meteorclient.utils.render.color.Color; import meteordevelopment.meteorclient.utils.render.color.SettingColor; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -43,13 +41,13 @@ public class PvPNeccessaryHud extends HudElement { // Scale public final Setting margin = sgScale.add(new IntSetting.Builder() - .name("margin") - .description("Két dolog közötti hely") - .defaultValue(0) - .onChanged(aInt -> calculateSize()) - .min(0) - .sliderRange(0, 10) - .build() + .name("margin") + .description("Két dolog közötti hely") + .defaultValue(0) + .onChanged(aInt -> calculateSize()) + .min(0) + .sliderRange(0, 10) + .build() ); public final Setting customScale = sgScale.add(new BoolSetting.Builder() @@ -71,7 +69,7 @@ public class PvPNeccessaryHud extends HudElement { .build() ); - // Background + // Backgroundx public final Setting background = sgBackground.add(new BoolSetting.Builder() .name("background") diff --git a/src/main/java/com/genyo/addon/managers/CombatManager.java b/src/main/java/com/genyo/addon/managers/CombatManager.java new file mode 100644 index 0000000..09292cd --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/CombatManager.java @@ -0,0 +1,40 @@ +package com.genyo.addon.managers; + +import com.genyo.addon.events.TotemPopEvent; +import meteordevelopment.meteorclient.MeteorClient; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityStatuses; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket; + +import java.util.HashMap; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class CombatManager { + + public HashMap popList = new HashMap<>(); + + @EventHandler + public void onPacketReceive(PacketEvent.Receive event) { + + if (event.packet instanceof EntityStatusS2CPacket pac) { + if (pac.getStatus() == EntityStatuses.USE_TOTEM_OF_UNDYING) { + Entity ent = pac.getEntity(mc.world); + if (!(ent instanceof PlayerEntity)) return; + if (popList == null) { + popList = new HashMap<>(); + } + if (popList.get(ent.getName().getString()) == null) { + popList.put(ent.getName().getString(), 1); + } else if (popList.get(ent.getName().getString()) != null) { + popList.put(ent.getName().getString(), popList.get(ent.getName().getString()) + 1); + } + MeteorClient.EVENT_BUS.post(TotemPopEvent.get((PlayerEntity) ent, popList.get(ent.getName().getString()))); + } + } + } + +} diff --git a/src/main/java/com/genyo/addon/managers/Managers.java b/src/main/java/com/genyo/addon/managers/Managers.java new file mode 100644 index 0000000..492bd1a --- /dev/null +++ b/src/main/java/com/genyo/addon/managers/Managers.java @@ -0,0 +1,13 @@ +package com.genyo.addon.managers; + +import meteordevelopment.meteorclient.MeteorClient; + +public class Managers { + + public static final CombatManager COMBAT = new CombatManager(); + + public static void subscribe() { + MeteorClient.EVENT_BUS.subscribe(COMBAT); + } + +} diff --git a/src/main/java/com/genyo/addon/mixin/IEntity.java b/src/main/java/com/genyo/addon/mixin/IEntity.java new file mode 100644 index 0000000..668cc6f --- /dev/null +++ b/src/main/java/com/genyo/addon/mixin/IEntity.java @@ -0,0 +1,19 @@ +package com.genyo.addon.mixin; + +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Entity.class) +public interface IEntity { + @Mutable + @Accessor("pos") + void setPos(Vec3d pos); + + @Mutable + @Accessor("blockPos") + void setBlockPos(BlockPos blockPos); +} diff --git a/src/main/java/com/genyo/addon/mixin/PlayerUtilsMixin.java b/src/main/java/com/genyo/addon/mixin/PlayerUtilsMixin.java index f6220da..176915f 100644 --- a/src/main/java/com/genyo/addon/mixin/PlayerUtilsMixin.java +++ b/src/main/java/com/genyo/addon/mixin/PlayerUtilsMixin.java @@ -15,7 +15,6 @@ public class PlayerUtilsMixin { @Inject(at = @At("TAIL"), method = "getPlayerColor*", cancellable = true) private static void injectGetPlayerColor(PlayerEntity entity, Color defaultColor, CallbackInfoReturnable cir) { if (Enemies.get().isEnemy(entity)) { - //cir.setReturnValue(new Color(245, 133, 125, 255)); cir.setReturnValue(Enemies.get().getEnemyColor()); } } diff --git a/src/main/java/com/genyo/addon/modules/AngelSexHulkenberg.java b/src/main/java/com/genyo/addon/modules/AngelSexHulkenberg.java new file mode 100644 index 0000000..6540ef3 --- /dev/null +++ b/src/main/java/com/genyo/addon/modules/AngelSexHulkenberg.java @@ -0,0 +1,217 @@ +package com.genyo.addon.modules; + +import com.genyo.addon.GenyoAddon; +import com.genyo.addon.events.TotemPopEvent; +import com.genyo.addon.mixin.IEntity; +import com.genyo.addon.render.Render2DEngine; +import com.genyo.addon.render.Render3DEngine; +import com.genyo.addon.utils.MathUtil; +import com.mojang.authlib.GameProfile; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import meteordevelopment.meteorclient.events.render.Render3DEvent; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.render.color.Color; +import meteordevelopment.meteorclient.utils.render.color.SettingColor; +import meteordevelopment.orbit.EventHandler; +import net.minecraft.client.network.AbstractClientPlayerEntity; +import net.minecraft.client.render.*; +import net.minecraft.client.render.entity.PlayerEntityRenderer; +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.RotationAxis; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CopyOnWriteArrayList; + +public final class AngelSexHulkenberg extends Module { + + public AngelSexHulkenberg() { + super(GenyoAddon.GENYO, "angel-sex-hulkenberg", "Geci fasz csumi"); + } + + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + + private final Setting mode = sgGeneral.add(new EnumSetting.Builder() + .name("Mode") + .description("Genyo") + .defaultValue(Mode.Textured) + .build() + ); + + private final Setting secondLayer = sgGeneral.add(new BoolSetting.Builder() + .name("Second Layer") + .description("nemtom") + .defaultValue(true) + .build() + ); + + private final Setting color = sgGeneral.add(new ColorSetting.Builder() + .name("Color") + .description("színcápa színcápa mondj egy színt") + .defaultValue(new Color(53, 46, 46, 37)) + .build() + ); + + private final Setting ySpeed = sgGeneral.add(new IntSetting.Builder() + .name("Y Speed") + .description("y show speed") + .defaultValue(0) + .min(-10) + .max(10) + .build() + ); + + private final Setting aSpeed = sgGeneral.add(new IntSetting.Builder() + .name("Alpha Speed") + .description("alpha show speed") + .defaultValue(5) + .min(1) + .max(100) + .build() + ); + + private final Setting rotSpeed = sgGeneral.add(new DoubleSetting.Builder() + .name("Rotation Speed") + .description("rotációs kapa") + .defaultValue(0.25) + .min(0) + .max(6) + .build() + ); + + private final CopyOnWriteArrayList popList = new CopyOnWriteArrayList<>(); + + private enum Mode { + Simple, Textured + } + + @EventHandler + public void onUpdate() { + popList.forEach(person -> person.update(popList)); + } + + @EventHandler + public void onRender(Render3DEvent event) { + MatrixStack stack = event.matrices; + + RenderSystem.enableBlend(); + RenderSystem.disableDepthTest(); + if (mode.get().equals(Mode.Simple)) RenderSystem.defaultBlendFunc(); + else RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE); + popList.forEach(person -> renderEntity(stack, person.player, person.getTexture(), color.get().a)); + RenderSystem.enableDepthTest(); + RenderSystem.disableBlend(); + } + + @EventHandler + @SuppressWarnings("unused") + private void onTotemPop(@NotNull TotemPopEvent e) { + if (e.entity.equals(mc.player) || mc.world == null) return; + //if (mc.world == null) return; --------- for testing + + AbstractClientPlayerEntity entity = new AbstractClientPlayerEntity(mc.world, new GameProfile(e.entity.getUuid(), e.entity.getName().getString())) { + @Override public boolean isSpectator() {return false;} + @Override public boolean isCreative() {return false;} + }; + + entity.copyPositionAndRotation(e.entity); + entity.bodyYaw = e.entity.bodyYaw; + entity.headYaw = e.entity.headYaw; + entity.handSwingProgress = e.entity.handSwingProgress; + entity.handSwingTicks = e.entity.handSwingTicks; + entity.setSneaking(e.entity.isSneaking()); + entity.limbAnimator.setSpeed(e.entity.limbAnimator.getSpeed()); + entity.limbAnimator.pos = e.entity.limbAnimator.getPos(); + popList.add(new Person(entity, ((AbstractClientPlayerEntity) e.entity).getSkinTextures().texture())); + } + + private void renderEntity(@NotNull MatrixStack matrices, @NotNull LivingEntity entity, Identifier texture, int alpha) { + PlayerEntityRenderer entityRenderer = (PlayerEntityRenderer) mc.getEntityRenderDispatcher().getRenderer((AbstractClientPlayerEntity) entity); + PlayerEntityRenderState renderState = entityRenderer.createRenderState(); + + renderState.leftPantsLegVisible = secondLayer.get(); + renderState.rightPantsLegVisible = secondLayer.get(); + renderState.leftSleeveVisible = secondLayer.get(); + renderState.rightSleeveVisible = secondLayer.get(); + renderState.jacketVisible = secondLayer.get(); + renderState.hatVisible = secondLayer.get(); + + double x = entity.getX() - mc.getEntityRenderDispatcher().camera.getPos().getX(); + double y = entity.getY() - mc.getEntityRenderDispatcher().camera.getPos().getY(); + double z = entity.getZ() - mc.getEntityRenderDispatcher().camera.getPos().getZ(); + ((IEntity) entity).setPos(entity.getPos().add(0, (double) ySpeed.get() / 50., 0)); + + matrices.push(); + matrices.translate((float) x, (float) y, (float) z); + + float yRotYaw = ((alpha / 255f) * 360f * rotSpeed.get().floatValue()); + yRotYaw = yRotYaw == 0 ? 0 : Render2DEngine.interpolateFloat(yRotYaw, yRotYaw - (((aSpeed.get() / 255f) * 360f * rotSpeed.get().floatValue())), Render3DEngine.getTickDelta()); + + matrices.multiply(RotationAxis.POSITIVE_Y.rotation(MathUtil.rad(180 - entity.bodyYaw + yRotYaw))); + prepareScale(matrices); + + float limbSpeed = Math.min(entity.limbAnimator.getSpeed(), 1f); + + entityRenderer.updateRenderState((AbstractClientPlayerEntity) entity, renderState, limbSpeed); + + BufferBuilder buffer; + if (mode.get().equals(Mode.Textured)) { + RenderSystem.setShaderTexture(0, texture); + buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE); + } else { + buffer = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION); + } + + RenderSystem.setShaderColor(color.get().r, color.get().g, color.get().b, alpha / 255f); + + entityRenderer.render(renderState, matrices, mc.getBufferBuilders().getEntityVertexConsumers(), 1); + //modelBase.render(matrices, buffer, 10, 0); + endBuilding(buffer); + RenderSystem.setShaderColor(1f, 1f, 1f, 1f); + matrices.pop(); + } + + public static void endBuilding(BufferBuilder bb) { + BuiltBuffer builtBuffer = bb.endNullable(); + if (builtBuffer != null) + BufferRenderer.drawWithGlobalProgram(builtBuffer); + } + + private static void prepareScale(@NotNull MatrixStack matrixStack) { + matrixStack.scale(-1.0F, -1.0F, 1.0F); + matrixStack.scale(1.6f, 1.8f, 1.6f); + matrixStack.translate(0.0F, -1.501F, 0.0F); + } + + private class Person { + private final AbstractClientPlayerEntity player; + private Identifier texture; + private int alpha; + + public Person(AbstractClientPlayerEntity player, Identifier texture) { + this.player = player; + alpha = color.get().a; + this.texture = texture; + } + + public void update(CopyOnWriteArrayList arrayList) { + if (alpha <= 0) { + arrayList.remove(this); + player.kill(player.getServer().getWorld(player.getWorld().getRegistryKey())); + player.remove(Entity.RemovalReason.KILLED); + player.onRemoved(); + return; + } + alpha -= aSpeed.get(); + } + + public Identifier getTexture() { + return texture; + } + } +} diff --git a/src/main/java/com/genyo/addon/modules/GenyoAutoEZ.java b/src/main/java/com/genyo/addon/modules/GenyoAutoEZ.java index 45056e7..70d59ce 100644 --- a/src/main/java/com/genyo/addon/modules/GenyoAutoEZ.java +++ b/src/main/java/com/genyo/addon/modules/GenyoAutoEZ.java @@ -4,14 +4,10 @@ import meteordevelopment.meteorclient.events.packets.PacketEvent; import meteordevelopment.meteorclient.events.world.TickEvent; import meteordevelopment.meteorclient.settings.*; -import meteordevelopment.meteorclient.systems.friends.Friends; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.utils.player.ChatUtils; -import meteordevelopment.meteorclient.utils.player.PlayerUtils; import meteordevelopment.orbit.EventHandler; import meteordevelopment.orbit.EventPriority; -import net.minecraft.client.network.AbstractClientPlayerEntity; -import net.minecraft.client.network.PlayerListEntry; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.network.packet.s2c.play.EntityStatusS2CPacket; @@ -46,7 +42,7 @@ public GenyoAutoEZ() { private final Setting pop = sgGeneral.add(new BoolSetting.Builder() .name("Pop") - .description("Should we send a message when enemy pops a totem") + .description("nyugi ez nem csinál semmit, csak dísznek van XD") .defaultValue(true) .build() ); @@ -61,23 +57,16 @@ public GenyoAutoEZ() { private final Setting> popMessages = sgGeneral.add(new StringListSetting.Builder() .name("Pop Messages") .description("Messages to send when popping an enemy") - .defaultValue(List.of("ez pop ", "pop ", "i love kiwi pop ")) + .defaultValue(List.of("ez pop ", "pop ", "i love kiwi pop ")) .build() ); private final Random r = new Random(); private int lastPop; private final List messageQueue = new LinkedList<>(); - private HashMap taggedPlayers = new HashMap(); + private final HashMap taggedPlayers = new HashMap<>(); private int timer = 0; - - private AbstractClientPlayerEntity target; - - private String renderName = null; - private float renderHealth; - private float renderPing; - @Override public void onActivate() { super.onActivate(); @@ -94,58 +83,27 @@ private void onTick(TickEvent.Pre event) { timer = 0; if (msg.kill) messageQueue.clear(); - else messageQueue.remove(0); + else messageQueue.removeFirst(); } } } - private void updateTarget() { - target = null; - if (mc.world == null) {return;} - - AbstractClientPlayerEntity closest = null; - double distance = Double.MAX_VALUE; - - for (AbstractClientPlayerEntity player : mc.world.getPlayers()) { - if (player == mc.player) {continue;} - if (Friends.get().isFriend(player)) {continue;} - - double d = mc.player.distanceTo(player); - - if (d < distance) { - closest = player; - distance = d; - } - } - - target = closest; - - if (target != null) { - renderName = target.getName().getString(); - renderHealth = target.getHealth() + target.getAbsorptionAmount(); - - PlayerListEntry playerListEntry = mc.getNetworkHandler().getPlayerListEntry(target.getUuid()); - renderPing = playerListEntry == null ? -1 : playerListEntry.getLatency(); - } - } - @EventHandler private void onReceive(PacketEvent.Receive event) { if (event.packet instanceof EntityStatusS2CPacket packet) { // Pop if (packet.getStatus() == 35) { Entity entity = packet.getEntity(mc.world); - if (pop.get() && mc.player != null && mc.world != null && entity instanceof PlayerEntity playerEntity) { - if (entity != mc.player && !Friends.get().isFriend((PlayerEntity) entity) && - mc.player.getPos().distanceTo(entity.getPos()) <= range.get()) { + if (mc.player != null && mc.world != null && entity instanceof PlayerEntity playerEntity) { + if (entity != mc.player && mc.player.getPos().distanceTo(entity.getPos()) <= range.get()) { if (trackPlayers.get() && taggedPlayers.containsKey(playerEntity)) { - int count = taggedPlayers.get(entity) + 1; + int count = taggedPlayers.get(playerEntity) + 1; taggedPlayers.replace(playerEntity, count); - sendPopMessage(entity.getName().getString(), count); + sendPopMessage(playerEntity.getName().getString(), count); } else { - sendPopMessage(entity.getName().getString(), 0); + sendPopMessage(playerEntity.getName().getString(), 0); taggedPlayers.put(playerEntity, 1); } } @@ -156,15 +114,18 @@ private void onReceive(PacketEvent.Receive event) { private void sendPopMessage(String name, int count) { if (!popMessages.get().isEmpty()) { - int num = r.nextInt(0, popMessages.get().size() - 1); + int num = r.nextInt(0, popMessages.get().size()); if (num == lastPop) { num = num < popMessages.get().size() - 1 ? num + 1 : 0; } lastPop = num; String messageString = popMessages.get().get(num).replace("", name); + String countString = String.valueOf(count); if (count > 0) { - messageString += " +" + count; + messageString = messageString.replace("", "+" + countString); + } else { + messageString = messageString.replace("", "+1"); } Message message = new Message(messageString, false); diff --git a/src/main/java/com/genyo/addon/modules/TescoCrystal.java b/src/main/java/com/genyo/addon/modules/TescoCrystal.java new file mode 100644 index 0000000..36cec8d --- /dev/null +++ b/src/main/java/com/genyo/addon/modules/TescoCrystal.java @@ -0,0 +1,983 @@ +package com.genyo.addon.modules; + +import com.genyo.addon.GenyoAddon; +import com.google.common.util.concurrent.AtomicDouble; +import it.unimi.dsi.fastutil.ints.*; +import meteordevelopment.meteorclient.events.entity.EntityAddedEvent; +import meteordevelopment.meteorclient.events.entity.EntityRemovedEvent; +import meteordevelopment.meteorclient.events.packets.PacketEvent; +import meteordevelopment.meteorclient.events.render.Render2DEvent; +import meteordevelopment.meteorclient.events.render.Render3DEvent; +import meteordevelopment.meteorclient.events.world.TickEvent; +import meteordevelopment.meteorclient.mixininterface.IBox; +import meteordevelopment.meteorclient.mixininterface.IRaycastContext; +import meteordevelopment.meteorclient.mixininterface.IVec3d; +import meteordevelopment.meteorclient.renderer.ShapeMode; +import meteordevelopment.meteorclient.renderer.text.TextRenderer; +import meteordevelopment.meteorclient.settings.*; +import meteordevelopment.meteorclient.systems.friends.Friends; +import meteordevelopment.meteorclient.systems.modules.Categories; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.systems.modules.combat.BedAura; +import meteordevelopment.meteorclient.utils.entity.DamageUtils; +import meteordevelopment.meteorclient.utils.entity.EntityUtils; +import meteordevelopment.meteorclient.utils.entity.Target; +import meteordevelopment.meteorclient.utils.misc.Keybind; +import meteordevelopment.meteorclient.utils.player.FindItemResult; +import meteordevelopment.meteorclient.utils.player.InvUtils; +import meteordevelopment.meteorclient.utils.player.PlayerUtils; +import meteordevelopment.meteorclient.utils.player.Rotations; +import meteordevelopment.meteorclient.utils.render.NametagUtils; +import meteordevelopment.meteorclient.utils.render.RenderUtils; +import meteordevelopment.meteorclient.utils.render.color.Color; +import meteordevelopment.meteorclient.utils.render.color.SettingColor; +import meteordevelopment.meteorclient.utils.world.BlockIterator; +import meteordevelopment.meteorclient.utils.world.BlockUtils; +import meteordevelopment.meteorclient.utils.world.TickRate; +import meteordevelopment.orbit.EventHandler; +import meteordevelopment.orbit.EventPriority; +import net.minecraft.block.Blocks; +import net.minecraft.component.type.AttributeModifierSlot; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.decoration.EndCrystalEntity; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.network.packet.c2s.play.*; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.*; +import net.minecraft.world.RaycastContext; +import org.joml.Vector3d; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +public class TescoCrystal extends Module { + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + private final SettingGroup sgSwitch = settings.createGroup("Switch"); + private final SettingGroup sgPlace = settings.createGroup("Place"); + private final SettingGroup sgFacePlace = settings.createGroup("Face Place"); + private final SettingGroup sgBreak = settings.createGroup("Break"); + private final SettingGroup sgPause = settings.createGroup("Pause"); + private final SettingGroup sgRender = settings.createGroup("Render"); + + // General + + private final Setting targetRange = sgGeneral.add(new DoubleSetting.Builder().name("target-range").description("Range in which to target players.").defaultValue(10).min(0).sliderMax(16).build()); + private final Setting predictMovement = sgGeneral.add(new BoolSetting.Builder().name("predict-movement").description("Predicts target movement.").defaultValue(false).build()); + private final Setting minDamage = sgGeneral.add(new DoubleSetting.Builder().name("min-damage").description("Minimum damage the crystal needs to deal to your target.").defaultValue(6).min(0).build()); + private final Setting maxDamage = sgGeneral.add(new DoubleSetting.Builder().name("max-damage").description("Maximum damage crystals can deal to yourself.").defaultValue(6).range(0, 36).sliderMax(36).build()); + private final Setting antiSuicide = sgGeneral.add(new BoolSetting.Builder().name("anti-suicide").description("Will not place and break crystals if they will kill you.").defaultValue(true).build()); + private final Setting ignoreNakeds = sgGeneral.add(new BoolSetting.Builder().name("ignore-nakeds").description("Ignore players with no items.").defaultValue(false).build()); + private final Setting rotate = sgGeneral.add(new BoolSetting.Builder().name("rotate").description("Rotates server-side towards the crystals being hit/placed.").defaultValue(true).build()); + private final Setting yawStepMode = sgGeneral.add(new EnumSetting.Builder().name("yaw-steps-mode").description("When to run the yaw steps check.").defaultValue(YawStepMode.Break).visible(rotate::get).build()); + private final Setting yawSteps = sgGeneral.add(new DoubleSetting.Builder().name("yaw-steps").description("Maximum number of degrees its allowed to rotate in one tick.").defaultValue(180).range(1, 180).visible(rotate::get).build()); + private final Setting>> entities = sgGeneral.add(new EntityTypeListSetting.Builder().name("entities").description("Entities to attack.").onlyAttackable().defaultValue(EntityType.PLAYER, EntityType.WARDEN, EntityType.WITHER).build()); + + // Switch + private final Setting autoSwitch = sgSwitch.add(new EnumSetting.Builder().name("auto-switch").description("Switches to crystals in your hotbar once a target is found.").defaultValue(AutoSwitchMode.Normal).build()); + private final Setting switchDelay = sgSwitch.add(new IntSetting.Builder().name("switch-delay").description("The delay in ticks to wait to break a crystal after switching hotbar slot.").defaultValue(0).min(0).build()); + private final Setting noGapSwitch = sgSwitch.add(new BoolSetting.Builder().name("no-gap-switch").description("Won't auto switch if you're holding a gapple.").defaultValue(true).visible(() -> autoSwitch.get() == AutoSwitchMode.Normal).build()); + private final Setting noBowSwitch = sgSwitch.add(new BoolSetting.Builder().name("no-bow-switch").description("Won't auto switch if you're holding a bow.").defaultValue(true).build()); + private final Setting antiWeakness = sgSwitch.add(new BoolSetting.Builder().name("anti-weakness").description("Switches to tools with so you can break crystals with the weakness effect.").defaultValue(true).build()); + + // Place + private final Setting doPlace = sgPlace.add(new BoolSetting.Builder().name("place").description("If the CA should place crystals.").defaultValue(true).build()); + public final Setting placeDelay = sgPlace.add(new IntSetting.Builder().name("place-delay").description("The delay in ticks to wait to place a crystal after it's exploded.").defaultValue(0).min(0).sliderMax(20).build()); + private final Setting placeRange = sgPlace.add(new DoubleSetting.Builder().name("place-range").description("Range in which to place crystals.").defaultValue(4.5).min(0).sliderMax(6).build()); + private final Setting placeWallsRange = sgPlace.add(new DoubleSetting.Builder().name("walls-range").description("Range in which to place crystals when behind blocks.").defaultValue(4.5).min(0).sliderMax(6).build()); + private final Setting placement112 = sgPlace.add(new BoolSetting.Builder().name("1.12-placement").description("Uses 1.12 crystal placement.").defaultValue(false).build()); + private final Setting support = sgPlace.add(new EnumSetting.Builder().name("support").description("Places a support block in air if no other position have been found.").defaultValue(SupportMode.Disabled).build()); + private final Setting supportDelay = sgPlace.add(new IntSetting.Builder().name("support-delay").description("Delay in ticks after placing support block.").defaultValue(1).min(0).visible(() -> support.get() != SupportMode.Disabled).build()); + + // Face place + private final Setting facePlace = sgFacePlace.add(new BoolSetting.Builder().name("face-place").description("Will face-place when target is below a certain health or armor durability threshold.").defaultValue(true).build()); + private final Setting facePlaceHealth = sgFacePlace.add(new DoubleSetting.Builder().name("face-place-health").description("The health the target has to be at to start face placing.").defaultValue(8).min(1).sliderMin(1).sliderMax(36).visible(facePlace::get).build()); + private final Setting facePlaceDurability = sgFacePlace.add(new DoubleSetting.Builder().name("face-place-durability").description("The durability threshold percentage to be able to face-place.").defaultValue(2).min(1).sliderMin(1).sliderMax(100).visible(facePlace::get).build()); + private final Setting facePlaceArmor = sgFacePlace.add(new BoolSetting.Builder().name("face-place-missing-armor").description("Automatically starts face placing when a target misses a piece of armor.").defaultValue(false).visible(facePlace::get).build()); + private final Setting forceFacePlace = sgFacePlace.add(new KeybindSetting.Builder().name("force-face-place").description("Starts face place when this button is pressed.").defaultValue(Keybind.none()).build()); + + // Break + + private final Setting doBreak = sgBreak.add(new BoolSetting.Builder().name("break").description("If the CA should break crystals.").defaultValue(true).build()); + private final Setting breakDelay = sgBreak.add(new IntSetting.Builder().name("break-delay").description("The delay in ticks to wait to break a crystal after it's placed.").defaultValue(0).min(0).sliderMax(20).build()); + private final Setting smartDelay = sgBreak.add(new BoolSetting.Builder().name("smart-delay").description("Only breaks crystals when the target can receive damage.").defaultValue(false).build()); + private final Setting breakRange = sgBreak.add(new DoubleSetting.Builder().name("break-range").description("Range in which to break crystals.").defaultValue(4.5).min(0).sliderMax(6).build()); + private final Setting breakWallsRange = sgBreak.add(new DoubleSetting.Builder().name("walls-range").description("Range in which to break crystals when behind blocks.").defaultValue(4.5).min(0).sliderMax(6).build()); + private final Setting onlyBreakOwn = sgBreak.add(new BoolSetting.Builder().name("only-own").description("Only breaks own crystals.").defaultValue(false).build()); + private final Setting breakAttempts = sgBreak.add(new IntSetting.Builder().name("break-attempts").description("How many times to hit a crystal before stopping to target it.").defaultValue(2).sliderMin(1).sliderMax(5).build()); + private final Setting ticksExisted = sgBreak.add(new IntSetting.Builder().name("ticks-existed").description("Amount of ticks a crystal needs to have lived for it to be attacked by CrystalAura.").defaultValue(0).min(0).build()); + private final Setting attackFrequency = sgBreak.add(new IntSetting.Builder().name("attack-frequency").description("Maximum hits to do per second.").defaultValue(25).min(1).sliderRange(1, 30).build()); + private final Setting fastBreak = sgBreak.add(new BoolSetting.Builder().name("fast-break").description("Ignores break delay and tries to break the crystal as soon as it's spawned in the world.").defaultValue(true).build()); + + // Pause + public final Setting pauseOnUse = sgPause.add(new EnumSetting.Builder().name("pause-on-use").description("Which processes should be paused while using an item.").defaultValue(PauseMode.Place).build()); + public final Setting pauseOnMine = sgPause.add(new EnumSetting.Builder().name("pause-on-mine").description("Which processes should be paused while mining a block.").defaultValue(PauseMode.None).build()); + private final Setting pauseOnLag = sgPause.add(new BoolSetting.Builder().name("pause-on-lag").description("Whether to pause if the server is not responding.").defaultValue(true).build()); + public final Setting> pauseModules = sgPause.add(new ModuleListSetting.Builder().name("pause-modules").description("Pauses while any of the selected modules are active.").defaultValue(BedAura.class).build()); + public final Setting pauseHealth = sgPause.add(new DoubleSetting.Builder().name("pause-health").description("Pauses when you go below a certain health.").defaultValue(5).range(0,36).sliderRange(0,36).build()); + + // Render + public final Setting swingMode = sgRender.add(new EnumSetting.Builder().name("swing-mode").description("How to swing when placing.").defaultValue(SwingMode.Both).build()); + private final Setting renderMode = sgRender.add(new EnumSetting.Builder().name("render-mode").description("The mode to render in.").defaultValue(RenderMode.Normal).build()); + private final Setting renderPlace = sgRender.add(new BoolSetting.Builder().name("render-place").description("Renders a block overlay over the block the crystals are being placed on.").defaultValue(true).visible(() -> renderMode.get() == RenderMode.Normal).build()); + private final Setting placeRenderTime = sgRender.add(new IntSetting.Builder().name("place-time").description("How long to render placements.").defaultValue(10).min(0).sliderMax(20).visible(() -> renderMode.get() == RenderMode.Normal && renderPlace.get()).build()); + private final Setting renderBreak = sgRender.add(new BoolSetting.Builder().name("render-break").description("Renders a block overlay over the block the crystals are broken on.").defaultValue(false).visible(() -> renderMode.get() == RenderMode.Normal).build()); + private final Setting breakRenderTime = sgRender.add(new IntSetting.Builder().name("break-time").description("How long to render breaking for.").defaultValue(13).min(0).sliderMax(20).visible(() -> renderMode.get() == RenderMode.Normal && renderBreak.get()).build()); + private final Setting smoothness = sgRender.add(new IntSetting.Builder().name("smoothness").description("How smoothly the render should move around.").defaultValue(10).min(0).sliderMax(20).visible(() -> renderMode.get() == RenderMode.Smooth).build()); + private final Setting height = sgRender.add(new DoubleSetting.Builder().name("height").description("How tall the gradient should be.").defaultValue(0.7).min(0).sliderMax(1).visible(() -> renderMode.get() == RenderMode.Gradient).build()); + private final Setting renderTime = sgRender.add(new IntSetting.Builder().name("render-time").description("How long to render placements.").defaultValue(10).min(0).sliderMax(20).visible(() -> renderMode.get() == RenderMode.Smooth || renderMode.get() == RenderMode.Fading).build()); + private final Setting shapeMode = sgRender.add(new EnumSetting.Builder().name("shape-mode").description("How the shapes are rendered.").defaultValue(ShapeMode.Both).visible(() -> renderMode.get() != RenderMode.None).build()); + private final Setting sideColor = sgRender.add(new ColorSetting.Builder().name("side-color").description("The side color of the block overlay.").defaultValue(new SettingColor(255, 255, 255, 45)).visible(() -> shapeMode.get().sides() && renderMode.get() != RenderMode.None).build()); + private final Setting lineColor = sgRender.add(new ColorSetting.Builder().name("line-color").description("The line color of the block overlay.").defaultValue(new SettingColor(255, 255, 255)).visible(() -> shapeMode.get().lines() && renderMode.get() != RenderMode.None).build()); + private final Setting renderDamageText = sgRender.add(new BoolSetting.Builder().name("damage").description("Renders crystal damage text in the block overlay.").defaultValue(true).visible(() -> renderMode.get() != RenderMode.None).build()); + private final Setting damageColor = sgRender.add(new ColorSetting.Builder().name("damage-color").description("The color of the damage text.").defaultValue(new SettingColor(255, 255, 255)).visible(() -> renderMode.get() != RenderMode.None && renderDamageText.get()).build()); + private final Setting damageTextScale = sgRender.add(new DoubleSetting.Builder().name("damage-scale").description("How big the damage text should be.").defaultValue(1.25).min(1).sliderMax(4).visible(() -> renderMode.get() != RenderMode.None && renderDamageText.get()).build()); + + // Fields + + private Item mainItem, offItem; + + private int breakTimer, placeTimer, switchTimer, ticksPassed; + private final List targets = new ArrayList<>(); + + private final Vec3d vec3d = new Vec3d(0, 0, 0); + private final Vec3d playerEyePos = new Vec3d(0, 0, 0); + private final Vector3d vec3 = new Vector3d(); + private final BlockPos.Mutable blockPos = new BlockPos.Mutable(); + private final Box box = new Box(0, 0, 0, 0, 0, 0); + + private final Vec3d vec3dRayTraceEnd = new Vec3d(0, 0, 0); + private RaycastContext raycastContext; + + private final IntSet placedCrystals = new IntOpenHashSet(); + private boolean placing; + private int placingTimer; + public int kaTimer; + private final BlockPos.Mutable placingCrystalBlockPos = new BlockPos.Mutable(); + + private final IntSet removed = new IntOpenHashSet(); + private final Int2IntMap attemptedBreaks = new Int2IntOpenHashMap(); + private final Int2IntMap waitingToExplode = new Int2IntOpenHashMap(); + private int attacks; + + private double serverYaw; + + private LivingEntity bestTarget; + private double bestTargetDamage; + private int bestTargetTimer; + + private boolean didRotateThisTick; + private boolean isLastRotationPos; + private final Vec3d lastRotationPos = new Vec3d(0, 0 ,0); + private double lastYaw, lastPitch; + private int lastRotationTimer; + + private int placeRenderTimer, breakRenderTimer; + private final BlockPos.Mutable placeRenderPos = new BlockPos.Mutable(); + private final BlockPos.Mutable breakRenderPos = new BlockPos.Mutable(); + private Box renderBoxOne, renderBoxTwo; + + private double renderDamage; + + public TescoCrystal() { + super(GenyoAddon.GENYO, "tesco-crystal", "adasasdasdasdsadsadasdasdsadsad"); + } + + @Override + public void onActivate() { + breakTimer = 0; + placeTimer = 0; + ticksPassed = 0; + + raycastContext = new RaycastContext(new Vec3d(0, 0, 0), new Vec3d(0, 0, 0), RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player); + + placing = false; + placingTimer = 0; + kaTimer = 0; + + attacks = 0; + + serverYaw = mc.player.getYaw(); + + bestTargetDamage = 0; + bestTargetTimer = 0; + + lastRotationTimer = getLastRotationStopDelay(); + + placeRenderTimer = 0; + breakRenderTimer = 0; + } + + @Override + public void onDeactivate() { + targets.clear(); + + placedCrystals.clear(); + + attemptedBreaks.clear(); + waitingToExplode.clear(); + + removed.clear(); + + bestTarget = null; + } + + private int getLastRotationStopDelay() { + return Math.max(10, placeDelay.get() / 2 + breakDelay.get() / 2 + 10); + } + + @EventHandler(priority = EventPriority.HIGH) + private void onPreTick(TickEvent.Pre event) { + // Update last rotation + didRotateThisTick = false; + lastRotationTimer++; + + // Decrement placing timer + if (placing) { + if (placingTimer > 0) placingTimer--; + else placing = false; + } + + if (kaTimer > 0) kaTimer--; + + if (ticksPassed < 20) ticksPassed++; + else { + ticksPassed = 0; + attacks = 0; + } + + // Decrement best target timer + if (bestTargetTimer > 0) bestTargetTimer--; + bestTargetDamage = 0; + + // Decrement break, place and switch timers + if (breakTimer > 0) breakTimer--; + if (placeTimer > 0) placeTimer--; + if (switchTimer > 0) switchTimer--; + + // Decrement render timers + if (placeRenderTimer > 0) placeRenderTimer--; + if (breakRenderTimer > 0) breakRenderTimer--; + + mainItem = mc.player.getMainHandStack().getItem(); + offItem = mc.player.getOffHandStack().getItem(); + + // Update waiting to explode crystals and mark them as existing if reached threshold + for (IntIterator it = waitingToExplode.keySet().iterator(); it.hasNext();) { + int id = it.nextInt(); + int ticks = waitingToExplode.get(id); + + if (ticks > 3) { + it.remove(); + removed.remove(id); + } + else { + waitingToExplode.put(id, ticks + 1); + } + } + + // Set player eye pos + ((IVec3d) playerEyePos).meteor$set(mc.player.getPos().x, mc.player.getPos().y + mc.player.getEyeHeight(mc.player.getPose()), mc.player.getPos().z); + + // Find targets, break and place + findTargets(); + + if (!targets.isEmpty()) { + if (!didRotateThisTick) doBreak(); + if (!didRotateThisTick) doPlace(); + } + } + + @EventHandler(priority = EventPriority.LOWEST - 666) + private void onPreTickLast(TickEvent.Pre event) { + // Rotate to last rotation + if (rotate.get() && lastRotationTimer < getLastRotationStopDelay() && !didRotateThisTick) { + Rotations.rotate(isLastRotationPos ? Rotations.getYaw(lastRotationPos) : lastYaw, isLastRotationPos ? Rotations.getPitch(lastRotationPos) : lastPitch, -100, null); + } + } + + @EventHandler + private void onEntityAdded(EntityAddedEvent event) { + if (!(event.entity instanceof EndCrystalEntity)) return; + + if (placing && event.entity.getBlockPos().equals(placingCrystalBlockPos)) { + placing = false; + placingTimer = 0; + placedCrystals.add(event.entity.getId()); + } + + if (fastBreak.get() && !didRotateThisTick && attacks < attackFrequency.get()) { + float damage = getBreakDamage(event.entity, true); + if (damage > minDamage.get()) doBreak(event.entity); + } + } + + @EventHandler + private void onEntityRemoved(EntityRemovedEvent event) { + if (event.entity instanceof EndCrystalEntity) { + placedCrystals.remove(event.entity.getId()); + removed.remove(event.entity.getId()); + waitingToExplode.remove(event.entity.getId()); + } + } + + private void setRotation(boolean isPos, Vec3d pos, double yaw, double pitch) { + didRotateThisTick = true; + isLastRotationPos = isPos; + + if (isPos) ((IVec3d) lastRotationPos).meteor$set(pos.x, pos.y, pos.z); + else { + lastYaw = yaw; + lastPitch = pitch; + } + + lastRotationTimer = 0; + } + + // Break + + private void doBreak() { + if (!doBreak.get() || breakTimer > 0 || switchTimer > 0 || attacks >= attackFrequency.get()) return; + if (shouldPause(PauseMode.Break)) return; + + float bestDamage = 0; + Entity crystal = null; + + // Find best crystal to break + for (Entity entity : mc.world.getEntities()) { + float damage = getBreakDamage(entity, true); + + if (damage > bestDamage) { + bestDamage = damage; + crystal = entity; + } + } + + // Break the crystal + if (crystal != null) doBreak(crystal); + } + + private float getBreakDamage(Entity entity, boolean checkCrystalAge) { + if (!(entity instanceof EndCrystalEntity)) return 0; + + // Check only break own + if (onlyBreakOwn.get() && !placedCrystals.contains(entity.getId())) return 0; + + // Check if it should already be removed + if (removed.contains(entity.getId())) return 0; + + // Check attempted breaks + if (attemptedBreaks.get(entity.getId()) > breakAttempts.get()) return 0; + + // Check crystal age + if (checkCrystalAge && entity.age < ticksExisted.get()) return 0; + + // Check range + if (isOutOfRange(entity.getPos(), entity.getBlockPos(), false)) return 0; + + // Check damage to self and anti suicide + blockPos.set(entity.getBlockPos()).move(0, -1, 0); + float selfDamage = DamageUtils.crystalDamage(mc.player, entity.getPos(), predictMovement.get(), blockPos); + if (selfDamage > maxDamage.get() || (antiSuicide.get() && selfDamage >= EntityUtils.getTotalHealth(mc.player))) return 0; + + // Check damage to targets and face place + float damage = getDamageToTargets(entity.getPos(), blockPos, true, false); + double minimumDamage = minDamage.get(); + + if (damage < minimumDamage) return 0f; + + return damage; + } + + private void doBreak(Entity crystal) { + // Anti weakness + if (antiWeakness.get()) { + StatusEffectInstance weakness = mc.player.getStatusEffect(StatusEffects.WEAKNESS); + StatusEffectInstance strength = mc.player.getStatusEffect(StatusEffects.STRENGTH); + + // Check for strength + if (weakness != null && (strength == null || strength.getAmplifier() <= weakness.getAmplifier())) { + // Check if the item in your hand is already valid + if (!isValidWeaknessItem(mc.player.getMainHandStack(), crystal)) { + // Find valid item to break with + if (!InvUtils.swap(InvUtils.findInHotbar(stack -> isValidWeaknessItem(stack, crystal)).slot(), false)) return; + + switchTimer = 1; + return; + } + } + } + + // Rotate and attack + boolean attacked = true; + + if (rotate.get()) { + double yaw = Rotations.getYaw(crystal); + double pitch = Rotations.getPitch(crystal, Target.Feet); + + if (doYawSteps(yaw, pitch)) { + setRotation(true, crystal.getPos(), 0, 0); + Rotations.rotate(yaw, pitch, 50, () -> attackCrystal(crystal)); + + breakTimer = breakDelay.get(); + } + else { + attacked = false; + } + } + else { + attackCrystal(crystal); + breakTimer = breakDelay.get(); + } + + if (attacked) { + // Update state + removed.add(crystal.getId()); + attemptedBreaks.put(crystal.getId(), attemptedBreaks.get(crystal.getId()) + 1); + waitingToExplode.put(crystal.getId(), 0); + + // Break render + breakRenderPos.set(crystal.getBlockPos().down()); + breakRenderTimer = breakRenderTime.get(); + } + } + + private boolean isValidWeaknessItem(ItemStack itemStack, Entity crystal) { + return DamageUtils.getAttackDamage((LivingEntity) mc.player, (LivingEntity) crystal, itemStack) > 0; + } + + private void attackCrystal(Entity entity) { + // Attack + mc.player.networkHandler.sendPacket(PlayerInteractEntityC2SPacket.attack(entity, mc.player.isSneaking())); + + Hand hand = InvUtils.findInHotbar(Items.END_CRYSTAL).getHand(); + if (hand == null) hand = Hand.MAIN_HAND; + + if (swingMode.get().client()) mc.player.swingHand(hand); + if (swingMode.get().packet()) mc.getNetworkHandler().sendPacket(new HandSwingC2SPacket(hand)); + + attacks++; + } + + @EventHandler + private void onPacketSend(PacketEvent.Send event) { + if (event.packet instanceof UpdateSelectedSlotC2SPacket) { + switchTimer = switchDelay.get(); + } + } + + // Place + + private void doPlace() { + if (!doPlace.get() || placeTimer > 0) return; + if (shouldPause(PauseMode.Place)) return; + + // Return if there are no crystals in hotbar or offhand + if (!InvUtils.testInHotbar(Items.END_CRYSTAL)) return; + + // Return if there are no crystals in either hand and auto switch mode is none + if (autoSwitch.get() != AutoSwitchMode.None) { + if (noGapSwitch.get() && autoSwitch.get() == AutoSwitchMode.Normal && offItem != Items.END_CRYSTAL) { + if (mainItem == Items.ENCHANTED_GOLDEN_APPLE + || offItem == Items.ENCHANTED_GOLDEN_APPLE + || mainItem == Items.GOLDEN_APPLE + || offItem == Items.GOLDEN_APPLE) return; + } + if (noBowSwitch.get() && (mainItem == Items.BOW || offItem == Items.BOW)) return; + } else if (mainItem != Items.END_CRYSTAL && offItem != Items.END_CRYSTAL) return; + + // Check for multiplace + for (Entity entity : mc.world.getEntities()) { + if (getBreakDamage(entity, false) > 0) return; + } + + // Setup variables + AtomicDouble bestDamage = new AtomicDouble(0); + AtomicReference bestBlockPos = new AtomicReference<>(new BlockPos.Mutable()); + AtomicBoolean isSupport = new AtomicBoolean(support.get() != SupportMode.Disabled); + + // Find best position to place the crystal on + BlockIterator.register((int) Math.ceil(placeRange.get()), (int) Math.ceil(placeRange.get()), (bp, blockState) -> { + // Check if its bedrock or obsidian and return if isSupport is false + boolean hasBlock = blockState.isOf(Blocks.BEDROCK) || blockState.isOf(Blocks.OBSIDIAN); + if (!hasBlock && (!isSupport.get() || !blockState.isReplaceable())) return; + + // Check if there is air on top + blockPos.set(bp.getX(), bp.getY() + 1, bp.getZ()); + if (!mc.world.getBlockState(blockPos).isAir()) return; + + if (placement112.get()) { + blockPos.move(0, 1, 0); + if (!mc.world.getBlockState(blockPos).isAir()) return; + } + + // Check range + ((IVec3d) vec3d).meteor$set(bp.getX() + 0.5, bp.getY() + 1, bp.getZ() + 0.5); + blockPos.set(bp).move(0, 1, 0); + if (isOutOfRange(vec3d, blockPos, true)) return; + + // Check damage to self and anti suicide + float selfDamage = DamageUtils.crystalDamage(mc.player, vec3d, predictMovement.get(), bp); + if (selfDamage > maxDamage.get() || (antiSuicide.get() && selfDamage >= EntityUtils.getTotalHealth(mc.player))) return; + + // Check damage to targets and face place + float damage = getDamageToTargets(vec3d, bp, false, !hasBlock && support.get() == SupportMode.Fast); + + double minimumDamage = Math.min(minDamage.get(), minDamage.get()); + + if (damage < minimumDamage) return; + + // Check if it can be placed + double x = bp.getX(); + double y = bp.getY() + 1; + double z = bp.getZ(); + ((IBox) box).meteor$set(x, y, z, x + 1, y + (placement112.get() ? 1 : 2), z + 1); + + if (intersectsWithEntities(box)) return; + + // Compare damage + if (damage > bestDamage.get() || (isSupport.get() && hasBlock)) { + bestDamage.set(damage); + bestBlockPos.get().set(bp); + } + + if (hasBlock) isSupport.set(false); + }); + + // Place the crystal + BlockIterator.after(() -> { + if (bestDamage.get() == 0) return; + + BlockHitResult result = getPlaceInfo(bestBlockPos.get()); + + ((IVec3d) vec3d).meteor$set( + result.getBlockPos().getX() + 0.5 + result.getSide().getVector().getX() * 1.0 / 2.0, + result.getBlockPos().getY() + 0.5 + result.getSide().getVector().getY() * 1.0 / 2.0, + result.getBlockPos().getZ() + 0.5 + result.getSide().getVector().getZ() * 1.0 / 2.0 + ); + + if (rotate.get()) { + double yaw = Rotations.getYaw(vec3d); + double pitch = Rotations.getPitch(vec3d); + + if (yawStepMode.get() == YawStepMode.Break || doYawSteps(yaw, pitch)) { + setRotation(true, vec3d, 0, 0); + Rotations.rotate(yaw, pitch, 50, () -> placeCrystal(result, bestDamage.get(), isSupport.get() ? bestBlockPos.get() : null)); + + placeTimer += placeDelay.get(); + } + } + else { + placeCrystal(result, bestDamage.get(), isSupport.get() ? bestBlockPos.get() : null); + placeTimer += placeDelay.get(); + } + }); + } + + private BlockHitResult getPlaceInfo(BlockPos blockPos) { + ((IVec3d) vec3d).meteor$set(mc.player.getX(), mc.player.getY() + mc.player.getEyeHeight(mc.player.getPose()), mc.player.getZ()); + + for (Direction side : Direction.values()) { + ((IVec3d) vec3dRayTraceEnd).meteor$set( + blockPos.getX() + 0.5 + side.getVector().getX() * 0.5, + blockPos.getY() + 0.5 + side.getVector().getY() * 0.5, + blockPos.getZ() + 0.5 + side.getVector().getZ() * 0.5 + ); + + ((IRaycastContext) raycastContext).meteor$set(vec3d, vec3dRayTraceEnd, RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player); + BlockHitResult result = mc.world.raycast(raycastContext); + + if (result != null && result.getType() == HitResult.Type.BLOCK && result.getBlockPos().equals(blockPos)) { + return result; + } + } + + Direction side = blockPos.getY() > vec3d.y ? Direction.DOWN : Direction.UP; + return new BlockHitResult(vec3d, side, blockPos, false); + } + + private void placeCrystal(BlockHitResult result, double damage, BlockPos supportBlock) { + // Switch + Item targetItem = supportBlock == null ? Items.END_CRYSTAL : Items.OBSIDIAN; + + FindItemResult item = InvUtils.findInHotbar(targetItem); + if (!item.found()) return; + + int prevSlot = mc.player.getInventory().selectedSlot; + + if (autoSwitch.get() != AutoSwitchMode.None && !item.isOffhand()) InvUtils.swap(item.slot(), false); + + Hand hand = item.getHand(); + if (hand == null) return; + + // Place + if (supportBlock == null) { + // Place crystal + mc.player.networkHandler.sendPacket(new PlayerInteractBlockC2SPacket(hand, result, 0)); + + if (swingMode.get().client()) mc.player.swingHand(hand); + if (swingMode.get().packet()) mc.getNetworkHandler().sendPacket(new HandSwingC2SPacket(hand)); + + placing = true; + placingTimer = 4; + kaTimer = 8; + placingCrystalBlockPos.set(result.getBlockPos()).move(0, 1, 0); + + placeRenderPos.set(result.getBlockPos()); + renderDamage = damage; + + if (renderMode.get() == RenderMode.Normal) { + placeRenderTimer = placeRenderTime.get(); + } else { + placeRenderTimer = renderTime.get(); + if (renderMode.get() == RenderMode.Fading) { + RenderUtils.renderTickingBlock( + placeRenderPos, sideColor.get(), + lineColor.get(), shapeMode.get(), + 0, renderTime.get(), true, + false + ); + } + } + } + else { + // Place support block + BlockUtils.place(supportBlock, item, false, 0, swingMode.get().client(), true, false); + placeTimer += supportDelay.get(); + + if (supportDelay.get() == 0) placeCrystal(result, damage, null); + } + + // Switch back + if (autoSwitch.get() == AutoSwitchMode.Silent) InvUtils.swap(prevSlot, false); + } + + // Yaw steps + + @EventHandler + private void onPacketSent(PacketEvent.Sent event) { + if (event.packet instanceof PlayerMoveC2SPacket) { + serverYaw = ((PlayerMoveC2SPacket) event.packet).getYaw((float) serverYaw); + } + } + + public boolean doYawSteps(double targetYaw, double targetPitch) { + targetYaw = MathHelper.wrapDegrees(targetYaw) + 180; + double serverYaw = MathHelper.wrapDegrees(this.serverYaw) + 180; + + if (distanceBetweenAngles(serverYaw, targetYaw) <= yawSteps.get()) return true; + + double delta = Math.abs(targetYaw - serverYaw); + double yaw = this.serverYaw; + + if (serverYaw < targetYaw) { + if (delta < 180) yaw += yawSteps.get(); + else yaw -= yawSteps.get(); + } + else { + if (delta < 180) yaw -= yawSteps.get(); + else yaw += yawSteps.get(); + } + + setRotation(false, null, yaw, targetPitch); + Rotations.rotate(yaw, targetPitch, -100, null); // Priority -100 so it sends the packet as the last one, im pretty sure it doesn't matte but idc + return false; + } + + private static double distanceBetweenAngles(double alpha, double beta) { + double phi = Math.abs(beta - alpha) % 360; + return phi > 180 ? 360 - phi : phi; + } + + // Face place + + /*private boolean shouldFacePlace() { + if (!facePlace.get()) return false; + + if (forceFacePlace.get().isPressed()) return true; + + // Checks if the provided crystal position should face place to any target + for (LivingEntity target : targets) { + if (EntityUtils.getTotalHealth(target) <= facePlaceHealth.get()) return true; + + for (EquipmentSlot slot : AttributeModifierSlot.ARMOR) { + ItemStack itemStack = target.getEquippedStack(slot); + + if (itemStack == null || itemStack.isEmpty()) { + if (facePlaceArmor.get()) return true; + } + else { + if ((double) (itemStack.getMaxDamage() - itemStack.getDamage()) / itemStack.getMaxDamage() * 100 <= facePlaceDurability.get()) return true; + } + } + } + + return false; + }*/ + + // Others + + private boolean shouldPause(PauseMode process) { + if (mc.player.isUsingItem() || mc.options.useKey.isPressed()) { + if (pauseOnUse.get().equals(process)) return true; + } + + if (pauseOnLag.get() && TickRate.INSTANCE.getTimeSinceLastTick() >= 1.0f) return true; + for (Module module : pauseModules.get()) if (module.isActive()) return true; + if (pauseOnMine.get().equals(process) && mc.interactionManager.isBreakingBlock()) return true; + return (EntityUtils.getTotalHealth(mc.player) <= pauseHealth.get()); + } + + private boolean isOutOfRange(Vec3d vec3d, BlockPos blockPos, boolean place) { + ((IRaycastContext) raycastContext).meteor$set(playerEyePos, vec3d, RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player); + + BlockHitResult result = mc.world.raycast(raycastContext); + + if (result == null || !result.getBlockPos().equals(blockPos)) // Is behind wall + return !PlayerUtils.isWithin(vec3d, (place ? placeWallsRange : breakWallsRange).get()); + return !PlayerUtils.isWithin(vec3d, (place ? placeRange : breakRange).get()); + } + + private LivingEntity getNearestTarget() { + LivingEntity nearestTarget = null; + double nearestDistance = Double.MAX_VALUE; + + for (LivingEntity target : targets) { + double distance = PlayerUtils.squaredDistanceTo(target); + + if (distance < nearestDistance) { + nearestTarget = target; + nearestDistance = distance; + } + } + + return nearestTarget; + } + + private float getDamageToTargets(Vec3d vec3d, BlockPos obsidianPos, boolean breaking, boolean fast) { + float damage = 0; + + if (fast) { + LivingEntity target = getNearestTarget(); + if (!(smartDelay.get() && breaking && target.hurtTime > 0)) damage = DamageUtils.crystalDamage(target, vec3d, predictMovement.get(), obsidianPos); + } + else { + for (LivingEntity target : targets) { + if (smartDelay.get() && breaking && target.hurtTime > 0) continue; + + float dmg = DamageUtils.crystalDamage(target, vec3d, predictMovement.get(), obsidianPos); + + // Update best target + if (dmg > bestTargetDamage) { + bestTarget = target; + bestTargetDamage = dmg; + bestTargetTimer = 10; + } + + damage += dmg; + } + } + + return damage; + } + + @Override + public String getInfoString() { + return bestTarget != null && bestTargetTimer > 0 ? EntityUtils.getName(bestTarget) : null; + } + + private void findTargets() { + targets.clear(); + + // Living Entities + for (Entity entity : mc.world.getEntities()) { + // Ignore non-living + if (!(entity instanceof LivingEntity livingEntity)) continue; + + // Player + if (livingEntity instanceof PlayerEntity player) { + if (player.getAbilities().creativeMode || livingEntity == mc.player) continue; + if (!player.isAlive() || !Friends.get().shouldAttack(player)) continue; + + if (ignoreNakeds.get()) { + if (player.getOffHandStack().isEmpty() + && player.getMainHandStack().isEmpty() + && player.getEquippedStack(EquipmentSlot.FEET).isEmpty() + && player.getEquippedStack(EquipmentSlot.LEGS).isEmpty() + && player.getEquippedStack(EquipmentSlot.CHEST).isEmpty() + && player.getEquippedStack(EquipmentSlot.HEAD).isEmpty() + ) continue; + } + } + + // Animals, water animals, monsters, bats, misc + if (!(entities.get().contains(livingEntity.getType()))) continue; + + // Close enough to damage + if (livingEntity.squaredDistanceTo(mc.player) > targetRange.get() * targetRange.get()) continue; + + targets.add(livingEntity); + } + } + + private boolean intersectsWithEntities(Box box) { + return EntityUtils.intersectsWithEntity(box, entity -> !entity.isSpectator() && !removed.contains(entity.getId())); + } + + // Rendering + + @EventHandler + private void onRender(Render3DEvent event) { + if (renderMode.get() == RenderMode.None) return; + + switch (renderMode.get()) { + case Normal -> { + if (renderPlace.get() && placeRenderTimer > 0) { + event.renderer.box(placeRenderPos, sideColor.get(), lineColor.get(), shapeMode.get(), 0); + } + if (renderBreak.get() && breakRenderTimer > 0) { + event.renderer.box(breakRenderPos, sideColor.get(), lineColor.get(), shapeMode.get(), 0); + } + } + + case Smooth -> { + if (placeRenderTimer <= 0) return; + + if (renderBoxOne == null) renderBoxOne = new Box(placeRenderPos); + if (renderBoxTwo == null) renderBoxTwo = new Box(placeRenderPos); + else ((IBox) renderBoxTwo).meteor$set(placeRenderPos); + + double offsetX = (renderBoxTwo.minX - renderBoxOne.minX) / smoothness.get(); + double offsetY = (renderBoxTwo.minY - renderBoxOne.minY) / smoothness.get(); + double offsetZ = (renderBoxTwo.minZ - renderBoxOne.minZ) / smoothness.get(); + + ((IBox) renderBoxOne).meteor$set( + renderBoxOne.minX + offsetX, + renderBoxOne.minY + offsetY, + renderBoxOne.minZ + offsetZ, + renderBoxOne.maxX + offsetX, + renderBoxOne.maxY + offsetY, + renderBoxOne.maxZ + offsetZ + ); + + event.renderer.box(renderBoxOne, sideColor.get(), lineColor.get(), shapeMode.get(), 0); + } + + case Gradient -> { + if (placeRenderTimer <= 0) return; + + Color bottom = new Color(0, 0, 0, 0); + + int x = placeRenderPos.getX(); + int y = placeRenderPos.getY() + 1; + int z = placeRenderPos.getZ(); + + if (shapeMode.get().sides()) { + event.renderer.quadHorizontal(x, y, z, x + 1, z + 1, sideColor.get()); + event.renderer.gradientQuadVertical(x, y, z, x + 1, y - height.get(), z, bottom, sideColor.get()); + event.renderer.gradientQuadVertical(x, y, z, x, y - height.get(), z + 1, bottom, sideColor.get()); + event.renderer.gradientQuadVertical(x + 1, y, z, x + 1, y - height.get(), z + 1, bottom, sideColor.get()); + event.renderer.gradientQuadVertical(x, y, z + 1, x + 1, y - height.get(), z + 1, bottom, sideColor.get()); + } + + if (shapeMode.get().lines()) { + event.renderer.line(x, y, z, x + 1, y, z, lineColor.get()); + event.renderer.line(x, y, z, x, y, z + 1, lineColor.get()); + event.renderer.line(x + 1, y, z, x + 1, y, z + 1, lineColor.get()); + event.renderer.line(x, y, z + 1, x + 1, y, z + 1, lineColor.get()); + + event.renderer.line(x, y, z, x, y - height.get(), z, lineColor.get(), bottom); + event.renderer.line(x + 1, y, z, x + 1, y - height.get(), z, lineColor.get(), bottom); + event.renderer.line(x, y, z + 1, x, y - height.get(), z + 1, lineColor.get(), bottom); + event.renderer.line(x + 1, y, z + 1, x + 1, y - height.get(), z + 1, lineColor.get(), bottom); + } + } + } + } + + @EventHandler + private void onRender2D(Render2DEvent event) { + if (renderMode.get() == RenderMode.None || !renderDamageText.get()) return; + if (placeRenderTimer <= 0 && breakRenderTimer <= 0) return; + + if (renderMode.get() == RenderMode.Smooth) { + if (renderBoxOne == null) return; + vec3.set(renderBoxOne.minX + 0.5, renderBoxOne.minY + 0.5, renderBoxOne.minZ + 0.5); + } else vec3.set(placeRenderPos.getX() + 0.5, placeRenderPos.getY() + 0.5, placeRenderPos.getZ() + 0.5); + + if (NametagUtils.to2D(vec3, damageTextScale.get())) { + NametagUtils.begin(vec3); + TextRenderer.get().begin(1, false, true); + + String text = String.format("%.1f", renderDamage); + double w = TextRenderer.get().getWidth(text) / 2; + TextRenderer.get().render(text, -w, 0, damageColor.get(), true); + + TextRenderer.get().end(); + NametagUtils.end(); + } + } + + public enum YawStepMode { + Break, + All, + } + + public enum AutoSwitchMode { + Normal, + Silent, + None + } + + public enum SupportMode { + Disabled, + Accurate, + Fast + } + + public enum PauseMode { + Both, + Place, + Break, + None; + + public boolean equals(PauseMode process) { + return this == process || this == PauseMode.Both; + } + } + + public enum SwingMode { + Both, + Packet, + Client, + None; + + public boolean packet() { + return this == Packet || this == Both; + } + + public boolean client() { + return this == Client || this == Both; + } + } + + public enum RenderMode { + Normal, + Smooth, + Fading, + Gradient, + None + } +} diff --git a/src/main/java/com/genyo/addon/render/Render2DEngine.java b/src/main/java/com/genyo/addon/render/Render2DEngine.java new file mode 100644 index 0000000..238e02b --- /dev/null +++ b/src/main/java/com/genyo/addon/render/Render2DEngine.java @@ -0,0 +1,13 @@ +package com.genyo.addon.render; + +public class Render2DEngine { + + public static double interpolate(double oldValue, double newValue, double interpolationValue) { + return (oldValue + (newValue - oldValue) * interpolationValue); + } + + public static float interpolateFloat(float oldValue, float newValue, double interpolationValue) { + return (float) interpolate(oldValue, newValue, (float) interpolationValue); + } + +} diff --git a/src/main/java/com/genyo/addon/render/Render3DEngine.java b/src/main/java/com/genyo/addon/render/Render3DEngine.java new file mode 100644 index 0000000..1e4977d --- /dev/null +++ b/src/main/java/com/genyo/addon/render/Render3DEngine.java @@ -0,0 +1,11 @@ +package com.genyo.addon.render; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class Render3DEngine { + + public static float getTickDelta() { + return mc.getRenderTickCounter().getTickDelta(true); + } + +} diff --git a/src/main/java/com/genyo/addon/utils/MathUtil.java b/src/main/java/com/genyo/addon/utils/MathUtil.java new file mode 100644 index 0000000..3267b61 --- /dev/null +++ b/src/main/java/com/genyo/addon/utils/MathUtil.java @@ -0,0 +1,13 @@ +package com.genyo.addon.utils; + +public class MathUtil { + + public static int clamp(int num, int min, int max) { + return num < min ? min : Math.min(num, max); + } + + public static float rad(float angle) { + return (float) (angle * Math.PI / 180); + } + +} diff --git a/src/main/resources/assets/genyo/icon.png b/src/main/resources/assets/genyo/icon.png index 3fb2e7f..e5021a2 100644 Binary files a/src/main/resources/assets/genyo/icon.png and b/src/main/resources/assets/genyo/icon.png differ diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index f147bdb..8fd3b4f 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -12,6 +12,7 @@ "repo": "https://github.com/wuritz/genyo-addon" }, "icon": "assets/genyo/icon.png", + "accessWidener": "genyo.accesswidener", "environment": "client", "entrypoints": { "meteor": [ diff --git a/src/main/resources/genyo.accesswidener b/src/main/resources/genyo.accesswidener new file mode 100644 index 0000000..ace9554 --- /dev/null +++ b/src/main/resources/genyo.accesswidener @@ -0,0 +1,23 @@ +accessWidener v1 named + +accessible class net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractTypeHandler +accessible class net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractType +accessible class net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket +accessible field net/minecraft/client/network/ClientPlayerEntity lastSprinting Z +accessible field net/minecraft/client/render/chunk/ChunkBuilder$ChunkData nonEmptyLayers Ljava/util/Set; +accessible field net/minecraft/client/render/chunk/ChunkBuilder$ChunkData occlusionGraph Lnet/minecraft/client/render/chunk/ChunkOcclusionData; +accessible field net/minecraft/entity/projectile/FishingBobberEntity CAUGHT_FISH Lnet/minecraft/entity/data/TrackedData; +accessible field net/minecraft/network/packet/c2s/play/PlayerMoveC2SPacket onGround Z +accessible field net/minecraft/network/packet/c2s/play/PlayerMoveC2SPacket pitch F +accessible field net/minecraft/network/packet/c2s/play/ChatMessageC2SPacket chatMessage Ljava/lang/String; +accessible field net/minecraft/entity/LimbAnimator pos F +accessible field net/minecraft/network/packet/s2c/play/PlayerRemoveS2CPacket profileIds Ljava/util/List; +accessible field net/minecraft/client/network/ClientPlayerInteractionManager currentBreakingProgress F +accessible field net/minecraft/client/Mouse cursorDeltaY D +accessible field net/minecraft/client/Mouse cursorDeltaX D +accessible field net/minecraft/entity/Entity hasVisualFire Z +accessible field net/minecraft/network/packet/s2c/play/GameMessageS2CPacket content Lnet/minecraft/text/Text; +accessible field net/minecraft/block/spawner/MobSpawnerLogic spawnDelay I +accessible class net/minecraft/client/gui/hud/InGameHud$HeartType +accessible method net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket write (Lnet/minecraft/network/PacketByteBuf;)V +accessible method net/minecraft/client/world/ClientWorld getPendingUpdateManager ()Lnet/minecraft/client/network/PendingUpdateManager; diff --git a/src/main/resources/genyo.mixins.json b/src/main/resources/genyo.mixins.json index 61bb683..0514050 100644 --- a/src/main/resources/genyo.mixins.json +++ b/src/main/resources/genyo.mixins.json @@ -5,7 +5,8 @@ "client": [ "HudRendererAccessor", "PlayerUtilsMixin", - "FriendsInjector" + "FriendsInjector", + "IEntity" ], "injectors": { "defaultRequire": 1