diff --git a/detekt.yml b/detekt.yml index bf51279ed..390562752 100644 --- a/detekt.yml +++ b/detekt.yml @@ -2,7 +2,7 @@ complexity: active: true ComplexMethod: active: true - threshold: 25 + threshold: 50 style: active: true diff --git a/src/main/java/me/zeroeightsix/kami/event/ForgeEventProcessor.kt b/src/main/java/me/zeroeightsix/kami/event/ForgeEventProcessor.kt index 9a57e107d..7fee257e8 100644 --- a/src/main/java/me/zeroeightsix/kami/event/ForgeEventProcessor.kt +++ b/src/main/java/me/zeroeightsix/kami/event/ForgeEventProcessor.kt @@ -34,6 +34,8 @@ object ForgeEventProcessor { @SubscribeEvent fun onTick(event: TickEvent.ClientTickEvent) { + KamiMod.EVENT_BUS.post(event) + if (mc.displayWidth != displayWidth || mc.displayHeight != displayHeight) { displayWidth = mc.displayWidth displayHeight = mc.displayHeight diff --git a/src/main/java/me/zeroeightsix/kami/event/KamiEvent.kt b/src/main/java/me/zeroeightsix/kami/event/KamiEvent.kt index 54796a871..1bc5b8da7 100644 --- a/src/main/java/me/zeroeightsix/kami/event/KamiEvent.kt +++ b/src/main/java/me/zeroeightsix/kami/event/KamiEvent.kt @@ -8,7 +8,7 @@ import me.zeroeightsix.kami.util.Wrapper.minecraft * Updated by Xiaro on 18/08/20 */ open class KamiEvent : Cancellable() { - val era = Era.PRE + var era: Era = Era.PRE open val partialTicks: Float = minecraft.renderPartialTicks enum class Era { diff --git a/src/main/java/me/zeroeightsix/kami/event/events/ClientPlayerAttackEvent.kt b/src/main/java/me/zeroeightsix/kami/event/events/ClientPlayerAttackEvent.kt index d9bffb144..fbdf12847 100644 --- a/src/main/java/me/zeroeightsix/kami/event/events/ClientPlayerAttackEvent.kt +++ b/src/main/java/me/zeroeightsix/kami/event/events/ClientPlayerAttackEvent.kt @@ -6,4 +6,4 @@ import net.minecraft.entity.Entity /** * Updated by Xiaro on 18/08/20 */ -class ClientPlayerAttackEvent(val targetEntity: Entity) : KamiEvent() \ No newline at end of file +class ClientPlayerAttackEvent(val entity: Entity) : KamiEvent() \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/event/events/RenderEntityEvent.kt b/src/main/java/me/zeroeightsix/kami/event/events/RenderEntityEvent.kt index 66b0054b7..1de8fc782 100644 --- a/src/main/java/me/zeroeightsix/kami/event/events/RenderEntityEvent.kt +++ b/src/main/java/me/zeroeightsix/kami/event/events/RenderEntityEvent.kt @@ -18,4 +18,5 @@ open class RenderEntityEvent( class Pre(entity: Entity?, x: Double, y: Double, z: Double, yaw: Float, partialTicks: Float, debug: Boolean) : RenderEntityEvent(entity, x, y, z, yaw, partialTicks, debug) class Post(entity: Entity?, x: Double, y: Double, z: Double, yaw: Float, partialTicks: Float, debug: Boolean) : RenderEntityEvent(entity, x, y, z, yaw, partialTicks, debug) + class Final(entity: Entity?, x: Double, y: Double, z: Double, yaw: Float, partialTicks: Float, debug: Boolean) : RenderEntityEvent(entity, x, y, z, yaw, partialTicks, debug) } \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/manager/mangers/CombatManager.kt b/src/main/java/me/zeroeightsix/kami/manager/mangers/CombatManager.kt new file mode 100644 index 000000000..610284c6e --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/manager/mangers/CombatManager.kt @@ -0,0 +1,53 @@ +package me.zeroeightsix.kami.manager.mangers + +import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.module.ModuleManager +import me.zeroeightsix.kami.util.MotionTracker +import net.minecraft.entity.EntityLivingBase +import java.util.* +import kotlin.collections.ArrayList + +/** + * @author Xiaro + * + * Created by Xiaro on 06/08/20 + */ +object CombatManager { + private val combatModules = ArrayList() + + var targetList = LinkedList() + var target: EntityLivingBase? = null + set(value) { + motionTracker.target = value + field = value + } + val motionTracker = MotionTracker(null) + + fun isActiveAndTopPriority(module: Module) = module.isActive() && isOnTopPriority(module) + + fun isOnTopPriority(module: Module): Boolean { + return getTopPriority() <= module.modulePriority + } + + fun getTopPriority(): Int { + return getTopModule()?.modulePriority ?: -1 + } + + fun getTopModule(): Module? { + var topModule: Module? = null + for (module in combatModules) { + if (!module.isActive()) continue + if (module.modulePriority < topModule?.modulePriority ?: 0) continue + topModule = module + } + return topModule + } + + init { + for (module in ModuleManager.getModules()) { + if (module.category != Module.Category.COMBAT) continue + if (module.modulePriority == -1) continue + combatModules.add(module) + } + } +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/manager/mangers/PlayerPacketManager.kt b/src/main/java/me/zeroeightsix/kami/manager/mangers/PlayerPacketManager.kt index fbbf7b93d..94d8c2277 100644 --- a/src/main/java/me/zeroeightsix/kami/manager/mangers/PlayerPacketManager.kt +++ b/src/main/java/me/zeroeightsix/kami/manager/mangers/PlayerPacketManager.kt @@ -3,10 +3,17 @@ package me.zeroeightsix.kami.manager.mangers import me.zero.alpine.listener.EventHandler import me.zero.alpine.listener.EventHook import me.zero.alpine.listener.Listener +import me.zeroeightsix.kami.event.KamiEvent import me.zeroeightsix.kami.event.events.OnUpdateWalkingPlayerEvent +import me.zeroeightsix.kami.event.events.PacketEvent +import me.zeroeightsix.kami.event.events.RenderEntityEvent import me.zeroeightsix.kami.manager.Manager import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.util.TimerUtils +import me.zeroeightsix.kami.util.Wrapper import me.zeroeightsix.kami.util.math.Vec2f +import net.minecraft.network.play.client.CPacketHeldItemChange +import net.minecraft.network.play.client.CPacketPlayer import net.minecraft.util.math.Vec3d import java.util.* @@ -15,11 +22,26 @@ object PlayerPacketManager : Manager() { /** TreeMap for all packets to be sent, sorted by their callers' priority */ private val packetList = TreeMap(compareByDescending { it.modulePriority }) + var serverSidePosition = Vec3d(0.0, 0.0, 0.0) + private set + var prevServerSideRotation = Vec2f(0f, 0f) + private set + var serverSideRotation = Vec2f(0f, 0f) + private var clientSidePitch = Vec2f(0f, 0f) + var serverSideHotbar = 0 + private set + + private var spoofingHotbar = false + private var hotbarResetTimer = TimerUtils.TickTimer(TimerUtils.TimeUnit.SECONDS) + @EventHandler private val onUpdateWalkingPlayerListener = Listener(EventHook { event: OnUpdateWalkingPlayerEvent -> - if (packetList.isEmpty()) return@EventHook - packetList.values.first().apply(event) // Apply the packet from the module that has the highest priority - packetList.clear() + if (event.era != KamiEvent.Era.PERI) return@EventHook + prevServerSideRotation = serverSideRotation + if (packetList.isNotEmpty()) { + packetList.values.first().apply(event) // Apply the packet from the module that has the highest priority + packetList.clear() + } }) /** @@ -32,6 +54,64 @@ object PlayerPacketManager : Manager() { packetList[caller] = packet } + @EventHandler + private val sendListener = Listener(EventHook { event: PacketEvent.Send -> + with(event.packet) { + if (this is CPacketPlayer) { + if (this.moving) serverSidePosition = Vec3d(this.x, this.y, this.z) + if (this.rotating) { + serverSideRotation = Vec2f(this.yaw, this.pitch) + Wrapper.player?.let { it.rotationYawHead = this.yaw } + } + } + if (this is CPacketHeldItemChange) { + if (spoofingHotbar && this.slotId != serverSideHotbar) { + if (hotbarResetTimer.tick(1L)) { + spoofingHotbar = false + serverSideHotbar = this.slotId + } else { + event.cancel() + } + } else { + serverSideHotbar = this.slotId + } + } + } + }) + + @EventHandler + private val preRenderListener = Listener(EventHook { event: RenderEntityEvent.Pre -> + if (event.entity == null || event.entity != Wrapper.player) return@EventHook + with(event.entity) { + clientSidePitch = Vec2f(prevRotationPitch, rotationPitch) + prevRotationPitch = prevServerSideRotation.y + rotationPitch = serverSideRotation.y + } + }) + + @EventHandler + private val postRenderListener = Listener(EventHook { event: RenderEntityEvent.Final -> + if (event.entity == null || event.entity != Wrapper.player) return@EventHook + with(event.entity) { + prevRotationPitch = clientSidePitch.x + rotationPitch = clientSidePitch.y + } + }) + + fun spoofHotbar(slot: Int) { + Wrapper.minecraft.connection?.let { + it.sendPacket(CPacketHeldItemChange(slot)) + serverSideHotbar = slot + spoofingHotbar = true + } + } + + fun resetHotbar() { + if (!spoofingHotbar) return + spoofingHotbar = false + Wrapper.minecraft.connection?.sendPacket(CPacketHeldItemChange(Wrapper.minecraft.playerController?.currentPlayerItem ?: 0)) + } + /** * Used for PlayerPacketManager. All constructor parameters are optional. * They are null by default. null values would not be used for modifying diff --git a/src/main/java/me/zeroeightsix/kami/mixin/client/MixinEntityPlayerSP.java b/src/main/java/me/zeroeightsix/kami/mixin/client/MixinEntityPlayerSP.java index 505ff132d..b2ab3b7cb 100644 --- a/src/main/java/me/zeroeightsix/kami/mixin/client/MixinEntityPlayerSP.java +++ b/src/main/java/me/zeroeightsix/kami/mixin/client/MixinEntityPlayerSP.java @@ -2,6 +2,7 @@ package me.zeroeightsix.kami.mixin.client; import com.mojang.authlib.GameProfile; import me.zeroeightsix.kami.KamiMod; +import me.zeroeightsix.kami.event.KamiEvent; import me.zeroeightsix.kami.event.events.OnUpdateWalkingPlayerEvent; import me.zeroeightsix.kami.event.events.PlayerMoveEvent; import me.zeroeightsix.kami.gui.mc.KamiGuiBeacon; @@ -117,6 +118,8 @@ public abstract class MixinEntityPlayerSP extends EntityPlayer { OnUpdateWalkingPlayerEvent event = new OnUpdateWalkingPlayerEvent(moving, rotating, sprinting, sneaking, onGround, pos, rotation); KamiMod.EVENT_BUS.post(event); + event.setEra(KamiEvent.Era.PERI); + KamiMod.EVENT_BUS.post(event); if (event.isCancelled()) { ci.cancel(); @@ -185,6 +188,8 @@ public abstract class MixinEntityPlayerSP extends EntityPlayer { } } + event.setEra(KamiEvent.Era.POST); + KamiMod.EVENT_BUS.post(event); } private boolean isMoving() { diff --git a/src/main/java/me/zeroeightsix/kami/mixin/client/MixinMinecraft.java b/src/main/java/me/zeroeightsix/kami/mixin/client/MixinMinecraft.java index 8c39d644a..2ef3a6917 100644 --- a/src/main/java/me/zeroeightsix/kami/mixin/client/MixinMinecraft.java +++ b/src/main/java/me/zeroeightsix/kami/mixin/client/MixinMinecraft.java @@ -2,6 +2,7 @@ package me.zeroeightsix.kami.mixin.client; import me.zeroeightsix.kami.KamiMod; import me.zeroeightsix.kami.event.events.GuiScreenEvent; +import me.zeroeightsix.kami.module.modules.combat.CrystalAura; import me.zeroeightsix.kami.module.modules.misc.DiscordRPC; import me.zeroeightsix.kami.util.ConfigUtils; import me.zeroeightsix.kami.util.Wrapper; @@ -9,9 +10,15 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.audio.SoundHandler; import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.gui.*; +import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.client.multiplayer.WorldClient; +import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.settings.GameSettings; import net.minecraft.client.settings.KeyBinding; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.spongepowered.asm.mixin.Mixin; @@ -33,6 +40,24 @@ public class MixinMinecraft { @Shadow public GuiIngame ingameGUI; @Shadow public boolean skipRenderWorld; @Shadow public SoundHandler soundHandler; + @Shadow public RayTraceResult objectMouseOver; + @Shadow public PlayerControllerMP playerController; + @Shadow public EntityRenderer entityRenderer; + + @Inject(method = "rightClickMouse", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/entity/EntityPlayerSP;getHeldItem(Lnet/minecraft/util/EnumHand;)Lnet/minecraft/item/ItemStack;"), cancellable = true) + public void processRightClickBlock(CallbackInfo ci) { + if (CrystalAura.INSTANCE.isActive()) { + ci.cancel(); + for (EnumHand enumhand : EnumHand.values()) { + ItemStack itemstack = this.player.getHeldItem(enumhand); + if (itemstack.isEmpty() && (this.objectMouseOver == null || this.objectMouseOver.typeOfHit == RayTraceResult.Type.MISS)) + net.minecraftforge.common.ForgeHooks.onEmptyClick(this.player, enumhand); + if (!itemstack.isEmpty() && this.playerController.processRightClick(this.player, this.world, enumhand) == EnumActionResult.SUCCESS) { + this.entityRenderer.itemRenderer.resetEquippedProgress(enumhand); + } + } + } + } @Inject(method = "displayGuiScreen", at = @At("HEAD"), cancellable = true) public void displayGuiScreen(GuiScreen guiScreenIn, CallbackInfo info) { diff --git a/src/main/java/me/zeroeightsix/kami/mixin/client/MixinPlayerControllerMP.java b/src/main/java/me/zeroeightsix/kami/mixin/client/MixinPlayerControllerMP.java index 193190b6e..d3a826325 100644 --- a/src/main/java/me/zeroeightsix/kami/mixin/client/MixinPlayerControllerMP.java +++ b/src/main/java/me/zeroeightsix/kami/mixin/client/MixinPlayerControllerMP.java @@ -5,7 +5,6 @@ import me.zeroeightsix.kami.event.events.ClientPlayerAttackEvent; import me.zeroeightsix.kami.module.modules.player.TpsSync; import me.zeroeightsix.kami.util.LagCompensator; import net.minecraft.block.state.IBlockState; -import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; @@ -28,12 +27,10 @@ public class MixinPlayerControllerMP { @Inject(method = "attackEntity", at = @At("HEAD"), cancellable = true) public void attackEntity(EntityPlayer playerIn, Entity targetEntity, CallbackInfo ci) { if (targetEntity == null) return; - if (targetEntity instanceof EntityPlayerSP) { - ClientPlayerAttackEvent e = new ClientPlayerAttackEvent(targetEntity); - KamiMod.EVENT_BUS.post(e); - if (e.isCancelled()) { - ci.cancel(); - } + ClientPlayerAttackEvent event = new ClientPlayerAttackEvent(targetEntity); + KamiMod.EVENT_BUS.post(event); + if (event.isCancelled()) { + ci.cancel(); } } } diff --git a/src/main/java/me/zeroeightsix/kami/mixin/client/MixinRenderManager.java b/src/main/java/me/zeroeightsix/kami/mixin/client/MixinRenderManager.java index aced21862..c6e2cf3ea 100644 --- a/src/main/java/me/zeroeightsix/kami/mixin/client/MixinRenderManager.java +++ b/src/main/java/me/zeroeightsix/kami/mixin/client/MixinRenderManager.java @@ -47,10 +47,13 @@ public class MixinRenderManager { @Inject(method = "renderEntity", at = @At("RETURN")) public void renderEntityPostReturn(Entity entity, double x, double y, double z, float yaw, float partialTicks, boolean debug, CallbackInfo ci) { + RenderEntityEvent.Final eventFinal = new RenderEntityEvent.Final(entity, x, y, z, yaw, partialTicks, debug); + KamiMod.EVENT_BUS.post(eventFinal); + if (!this.renderOutlines || (this.debugBoundingBox && !entity.isInvisible() && !debug && !Minecraft.getMinecraft().isReducedDebug())) return; - RenderEntityEvent.Post event2 = new RenderEntityEvent.Post(entity, x, y, z, yaw, partialTicks, debug); - KamiMod.EVENT_BUS.post(event2); + RenderEntityEvent.Post event = new RenderEntityEvent.Post(entity, x, y, z, yaw, partialTicks, debug); + KamiMod.EVENT_BUS.post(event); } } diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AimBot.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AimBot.kt index 6dbae934d..986c88f93 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AimBot.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AimBot.kt @@ -1,49 +1,29 @@ package me.zeroeightsix.kami.module.modules.combat +import me.zeroeightsix.kami.manager.mangers.CombatManager import me.zeroeightsix.kami.module.Module import me.zeroeightsix.kami.setting.Settings -import me.zeroeightsix.kami.util.EntityUtils.EntityPriority -import me.zeroeightsix.kami.util.EntityUtils.getPrioritizedTarget -import me.zeroeightsix.kami.util.EntityUtils.getTargetList -import me.zeroeightsix.kami.util.math.RotationUtils.faceEntity -import net.minecraft.item.ItemBow +import me.zeroeightsix.kami.util.InventoryUtils +import me.zeroeightsix.kami.util.math.RotationUtils.faceEntityClosest +import net.minecraft.init.Items @Module.Info( name = "AimBot", description = "Automatically aims at entities for you.", - category = Module.Category.COMBAT + category = Module.Category.COMBAT, + modulePriority = 20 ) object AimBot : Module() { - private val priority = register(Settings.e("Priority", EntityPriority.DISTANCE)) - private val range = register(Settings.floatBuilder("Range").withValue(16.0f).withMinimum(4.0f).withMaximum(24.0f).build()) - private val useBow = register(Settings.booleanBuilder("UseBow").withValue(true).build()) - private val ignoreWalls = register(Settings.booleanBuilder("IgnoreWalls").withValue(true).build()) - private val players = register(Settings.booleanBuilder("Players").withValue(true).build()) - private val friends = register(Settings.booleanBuilder("Friends").withValue(false).withVisibility { players.value == true }.build()) - private val sleeping = register(Settings.booleanBuilder("Sleeping").withValue(false).withVisibility { players.value == true }.build()) - private val mobs = register(Settings.b("Mobs", false)) - private val passive = register(Settings.booleanBuilder("PassiveMobs").withValue(false).withVisibility { mobs.value }.build()) - private val neutral = register(Settings.booleanBuilder("NeutralMobs").withValue(false).withVisibility { mobs.value }.build()) - private val hostile = register(Settings.booleanBuilder("HostileMobs").withValue(false).withVisibility { mobs.value }.build()) - private val invisible = register(Settings.b("Invisible", false)) + private val bowOnly = register(Settings.b("BowOnly", true)) + private val autoSwap = register(Settings.booleanBuilder("AutoSwap").withValue(false).withVisibility { bowOnly.value }) override fun onUpdate() { - if (Aura.isDisabled) return - - if (useBow.value) { - var bowSlot = 0 - while (bowSlot in 0..8 && mc.player.inventory.getStackInSlot(bowSlot).getItem() !is ItemBow) { - bowSlot++ - } - if (bowSlot != 9) { - mc.player.inventory.currentItem = bowSlot - mc.playerController.syncCurrentPlayItem() - } + if (bowOnly.value && mc.player.heldItemMainhand.getItem() != Items.BOW) { + if (autoSwap.value) InventoryUtils.swapSlotToItem(261) + return + } + CombatManager.target?.let { + faceEntityClosest(it) } - val player = arrayOf(players.value, friends.value, sleeping.value) - val mob = arrayOf(mobs.value, passive.value, neutral.value, hostile.value) - val targetList = getTargetList(player, mob, ignoreWalls.value, invisible.value, range.value) - if (targetList.isEmpty()) return - faceEntity(getPrioritizedTarget(targetList, priority.value)) } } \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AntiBot.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AntiBot.kt new file mode 100644 index 000000000..e8e53ee3c --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AntiBot.kt @@ -0,0 +1,65 @@ +package me.zeroeightsix.kami.module.modules.combat + +import me.zero.alpine.listener.EventHandler +import me.zero.alpine.listener.EventHook +import me.zero.alpine.listener.Listener +import me.zeroeightsix.kami.event.events.ClientPlayerAttackEvent +import me.zeroeightsix.kami.event.events.ConnectionEvent +import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.setting.Settings +import me.zeroeightsix.kami.util.graphics.font.TextComponent +import me.zeroeightsix.kami.util.math.Vec2d +import net.minecraft.entity.player.EntityPlayer +import kotlin.math.abs + +@Module.Info( + name = "AntiBot", + description = "Avoid attacking fake players", + category = Module.Category.COMBAT, + alwaysListening = true +) +object AntiBot : Module() { + private val tabList = register(Settings.b("TabList", true)) + private val ping = register(Settings.b("Ping", true)) + private val hp = register(Settings.b("HP", true)) + private val sleeping = register(Settings.b("Sleeping", false)) + private val hoverOnTop = register(Settings.b("HoverOnTop", true)) + private val ticksExists = register(Settings.integerBuilder("TicksExists").withValue(200).withRange(0, 500)) + + val botSet = HashSet() + private val textComponent = TextComponent().apply { addLine("BOT") } + + @EventHandler + private val disconnectListener = Listener(EventHook { event: ConnectionEvent.Disconnect -> + botSet.clear() + }) + + @EventHandler + private val listener = Listener(EventHook { event: ClientPlayerAttackEvent -> + if (isEnabled && botSet.contains(event.entity)) event.cancel() + }) + + override fun onUpdate() { + val cacheSet = HashSet() + for (entity in mc.world.loadedEntityList) { + if (entity !is EntityPlayer) continue + if (entity == mc.player) continue + if (!isBot(entity)) continue + cacheSet.add(entity) + } + botSet.removeIf { !cacheSet.contains(it) } + botSet.addAll(cacheSet) + } + + private fun isBot(entity: EntityPlayer) = tabList.value && mc.connection?.getPlayerInfo(entity.name) == null + || ping.value && mc.connection?.getPlayerInfo(entity.name)?.responseTime ?: -1 <= 0 + || hp.value && entity.health !in 0f..20f + || sleeping.value && entity.isPlayerSleeping && !entity.onGround + || hoverOnTop.value && hoverCheck(entity) + || entity.ticksExisted < ticksExists.value + + private fun hoverCheck(entity: EntityPlayer): Boolean { + val distXZ = Vec2d(entity.posX, entity.posZ).subtract(mc.player.posX, mc.player.posZ).lengthSquared() + return distXZ < 16 && entity.posY - mc.player.posY > 2.0 && abs(entity.posY - entity.prevPosY) < 0.1 + } +} diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AntiChainPop.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AntiChainPop.kt index 5bba01a85..1571e65c8 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AntiChainPop.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AntiChainPop.kt @@ -41,14 +41,12 @@ object AntiChainPop : Module() { private fun itemMode() { val old = totems if (InventoryUtils.countItemAll(449) < old) { - Surround.autoDisable.value = true Surround.enable() } totems = InventoryUtils.countItemAll(449) } private fun packetMode() { - Surround.autoDisable.value = true Surround.enable() } diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AntiFriendHit.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AntiFriendHit.kt index 5e985ed47..59638ab10 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AntiFriendHit.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AntiFriendHit.kt @@ -3,10 +3,11 @@ package me.zeroeightsix.kami.module.modules.combat import me.zero.alpine.listener.EventHandler import me.zero.alpine.listener.EventHook import me.zero.alpine.listener.Listener -import me.zeroeightsix.kami.event.events.ClientPlayerAttackEvent +import me.zeroeightsix.kami.event.events.PacketEvent import me.zeroeightsix.kami.module.Module import me.zeroeightsix.kami.util.Friends -import net.minecraft.client.entity.EntityOtherPlayerMP +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.network.play.client.CPacketUseEntity @Module.Info( name = "AntiFriendHit", @@ -15,11 +16,9 @@ import net.minecraft.client.entity.EntityOtherPlayerMP ) object AntiFriendHit : Module() { @EventHandler - private val listener = Listener(EventHook { event: ClientPlayerAttackEvent -> - if (mc.objectMouseOver == null) return@EventHook - val e = mc.objectMouseOver.entityHit - if (e is EntityOtherPlayerMP && Friends.isFriend(e.getName())) { - event.cancel() - } + private val sendListener = Listener(EventHook { event: PacketEvent.Send -> + if (event.packet !is CPacketUseEntity || event.packet.action != CPacketUseEntity.Action.ATTACK) return@EventHook + val entity = mc.world?.let { event.packet.getEntityFromWorld(it) } ?: return@EventHook + if (entity is EntityPlayer && Friends.isFriend(entity.name)) event.cancel() }) } \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/Aura.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/Aura.kt index 269d7b73e..5597ed146 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/Aura.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/Aura.kt @@ -1,21 +1,15 @@ package me.zeroeightsix.kami.module.modules.combat +import me.zeroeightsix.kami.manager.mangers.CombatManager import me.zeroeightsix.kami.manager.mangers.PlayerPacketManager import me.zeroeightsix.kami.module.Module -import me.zeroeightsix.kami.module.modules.misc.AutoTool -import me.zeroeightsix.kami.setting.Setting import me.zeroeightsix.kami.setting.Settings -import me.zeroeightsix.kami.util.BaritoneUtils.pause -import me.zeroeightsix.kami.util.BaritoneUtils.unpause -import me.zeroeightsix.kami.util.EntityUtils.EntityPriority -import me.zeroeightsix.kami.util.EntityUtils.getPrioritizedTarget -import me.zeroeightsix.kami.util.EntityUtils.getTargetList import me.zeroeightsix.kami.util.LagCompensator -import me.zeroeightsix.kami.util.math.RotationUtils.faceEntity -import me.zeroeightsix.kami.util.math.RotationUtils.getRotationToEntity +import me.zeroeightsix.kami.util.combat.CombatUtils +import me.zeroeightsix.kami.util.math.RotationUtils +import me.zeroeightsix.kami.util.math.RotationUtils.faceEntityClosest import me.zeroeightsix.kami.util.math.Vec2f import net.minecraft.entity.Entity -import net.minecraft.init.Items import net.minecraft.util.EnumHand @Module.Info( @@ -26,99 +20,59 @@ import net.minecraft.util.EnumHand ) object Aura : Module() { private val delayMode = register(Settings.e("Mode", WaitMode.DELAY)) - private val priority = register(Settings.e("Priority", EntityPriority.DISTANCE)) private val multi = register(Settings.b("Multi", false)) - private val spoofRotation = register(Settings.booleanBuilder("SpoofRotation").withValue(true).withVisibility { !multi.value }.build()) - private val lockView = register(Settings.booleanBuilder("LockView").withValue(false).withVisibility { !multi.value }.build()) - private val waitTick = register(Settings.floatBuilder("SpamDelay").withMinimum(0.1f).withValue(2.0f).withMaximum(40.0f).withVisibility { delayMode.value == WaitMode.SPAM }.build()) - private val eat = register(Settings.b("WhileEating", true)) - private val players = register(Settings.b("Players", true)) - private val friends = register(Settings.booleanBuilder("Friends").withValue(false).withVisibility { players.value }.build()) - private val sleeping = register(Settings.booleanBuilder("Sleeping").withValue(false).withVisibility { players.value }.build()) - private val mobs = register(Settings.b("Mobs", false)) - private val passive = register(Settings.booleanBuilder("PassiveMobs").withValue(false).withVisibility { mobs.value }.build()) - private val neutral = register(Settings.booleanBuilder("NeutralMobs").withValue(false).withVisibility { mobs.value }.build()) - private val hostile = register(Settings.booleanBuilder("HostileMobs").withValue(false).withVisibility { mobs.value }.build()) - private val invisible = register(Settings.b("Invisible", false)) - private val ignoreWalls = register(Settings.b("IgnoreWalls", true)) - private val minExistTime = register(Settings.integerBuilder("MinExistTime(s)").withValue(5).withRange(0, 20).build()) - private val range = register(Settings.f("Range", 5.5f)) - private val sync = register(Settings.b("TPSSync", false)) - private val pauseBaritone: Setting = register(Settings.b("PauseBaritone", true)) - private val timeAfterAttack = register(Settings.integerBuilder("ResumeDelay").withRange(1, 10).withValue(3).withVisibility { pauseBaritone.value }.build()) + private val lockView = register(Settings.booleanBuilder("LockView").withValue(false).withVisibility { !multi.value }) + private val spoofRotation = register(Settings.booleanBuilder("SpoofRotation").withValue(true).withVisibility { !multi.value && !lockView.value }) + private val waitTick = register(Settings.floatBuilder("SpamDelay").withMinimum(0.1f).withValue(2.0f).withMaximum(40.0f).withVisibility { delayMode.value == WaitMode.SPAM }) + val range = register(Settings.floatBuilder("Range").withValue(5f).withRange(0f, 10f)) + private val tpsSync = register(Settings.b("TPSSync", false)) private val autoTool = register(Settings.b("AutoWeapon", true)) - private val prefer = register(Settings.e("Prefer", HitMode.SWORD)) + private val prefer = register(Settings.enumBuilder(CombatUtils.PreferWeapon::class.java).withName("Prefer").withValue(CombatUtils.PreferWeapon.SWORD).withVisibility { autoTool.value }) private val disableOnDeath = register(Settings.b("DisableOnDeath", false)) - private var startTime: Long = 0 + private var inactiveTicks = 0 private var tickCount = 0 - var isAttacking = false // returned to AutoEat private enum class WaitMode { DELAY, SPAM } - enum class HitMode { - SWORD, AXE, NONE + override fun isActive(): Boolean { + return inactiveTicks <= 20 && isEnabled } override fun onUpdate() { + inactiveTicks++ if (mc.player.isDead) { if (mc.player.isDead && disableOnDeath.value) disable() return } + if (!CombatManager.isOnTopPriority(this) || CombatSetting.pause) return + val targetList = CombatManager.targetList + val target = CombatManager.target - val player = arrayOf(players.value, friends.value, sleeping.value) - val mob = arrayOf(mobs.value, passive.value, neutral.value, hostile.value) - val cacheList = getTargetList(player, mob, ignoreWalls.value, invisible.value, range.value) - val targetList = ArrayList() - for (target in cacheList) { - if (target.ticksExisted < minExistTime.value * 20) continue - targetList.add(target) - } - if (targetList.isNotEmpty()) { - /* Pausing baritone and other stuff */ - if (!isAttacking) { - isAttacking = true - if (pauseBaritone.value) { - startTime = 0L - pause() + if (multi.value && targetList.isNotEmpty()) { + inactiveTicks = 0 + if (canAttack()) { + for (entity in targetList) { + if (mc.player.getDistance(entity) > range.value) continue + attack(entity) } } - - if (autoTool.value) AutoTool.equipBestWeapon(prefer.value) - if (multi.value) { - if (canAttack()) for (target in targetList) { - attack(target) - } - } else { - val target = getPrioritizedTarget(targetList.toTypedArray(), priority.value) - if (spoofRotation.value) { - val rotation = getRotationToEntity(target) - val yaw = rotation.x.toFloat() - val pitch = rotation.y.toFloat() - val packet = PlayerPacketManager.PlayerPacket(rotating = true, rotation = Vec2f(yaw, pitch)) - PlayerPacketManager.addPacket(this, packet) - } - if (lockView.value) faceEntity(target) - if (canAttack()) attack(target) + } else if (target != null && mc.player.getDistance(target) < range.value) { + inactiveTicks = 0 + if (lockView.value) { + faceEntityClosest(target) + } else if (spoofRotation.value) { + val rotation = Vec2f(RotationUtils.getRotationToEntityClosest(target)) + PlayerPacketManager.addPacket(this, PlayerPacketManager.PlayerPacket(rotating = true, rotation = rotation)) } - } else if (isAttacking && canResume()) { - isAttacking = false - unpause() + if (canAttack()) attack(target) } } - override fun onDisable() { - unpause() - } - private fun canAttack(): Boolean { - if (!eat.value) { - val shield = mc.player.heldItemOffhand.getItem() == Items.SHIELD && mc.player.activeHand == EnumHand.OFF_HAND - if (mc.player.isHandActive && !shield) return false - } - val adjustTicks = if (!sync.value) 0f else (LagCompensator.adjustTicks) + val adjustTicks = if (!tpsSync.value) 0f else LagCompensator.adjustTicks return if (delayMode.value == WaitMode.DELAY) { (mc.player.getCooledAttackStrength(adjustTicks) >= 1f) } else { @@ -133,15 +87,8 @@ object Aura : Module() { } private fun attack(e: Entity) { + if (autoTool.value) CombatUtils.equipBestWeapon(prefer.value as CombatUtils.PreferWeapon) mc.playerController.attackEntity(mc.player, e) mc.player.swingArm(EnumHand.MAIN_HAND) } - - private fun canResume(): Boolean { - if (startTime == 0L) startTime = System.currentTimeMillis() - return if (startTime + timeAfterAttack.value * 1000 <= System.currentTimeMillis()) { // 1 timeout = 1 second = 1000 ms - startTime = System.currentTimeMillis() - true - } else false - } } \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoFeetPlace.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoFeetPlace.kt deleted file mode 100644 index 4ab8186e2..000000000 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoFeetPlace.kt +++ /dev/null @@ -1,258 +0,0 @@ -package me.zeroeightsix.kami.module.modules.combat - -import com.mojang.realmsclient.gui.ChatFormatting -import me.zeroeightsix.kami.module.Module -import me.zeroeightsix.kami.module.modules.player.NoBreakAnimation -import me.zeroeightsix.kami.setting.Settings -import me.zeroeightsix.kami.util.BlockUtils -import me.zeroeightsix.kami.util.text.MessageSendHelper -import net.minecraft.block.BlockAir -import net.minecraft.block.BlockLiquid -import net.minecraft.block.BlockObsidian -import net.minecraft.entity.item.EntityItem -import net.minecraft.entity.item.EntityXPOrb -import net.minecraft.item.ItemBlock -import net.minecraft.item.ItemStack -import net.minecraft.network.play.client.CPacketEntityAction -import net.minecraft.util.EnumFacing -import net.minecraft.util.EnumHand -import net.minecraft.util.math.AxisAlignedBB -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Vec3d - -@Module.Info( - name = "AutoFeetPlace", - category = Module.Category.COMBAT, - description = "Continually places obsidian around your feet" -) -object AutoFeetPlace : Module() { - private val mode = register(Settings.e("Mode", Mode.FULL)) - private val triggerable = register(Settings.b("Triggerable", true)) - private val disableNone = register(Settings.b("DisableNoObby", true)) - private val timeoutTicks = register(Settings.integerBuilder("TimeoutTicks").withMinimum(1).withValue(40).withMaximum(100).withVisibility { b: Int? -> triggerable.value }.build()) - private val blocksPerTick = register(Settings.integerBuilder("BlocksPerTick").withMinimum(1).withValue(4).withMaximum(9).build()) - private val tickDelay = register(Settings.integerBuilder("TickDelay").withMinimum(0).withValue(0).withMaximum(10).build()) - private val rotate = register(Settings.b("Rotate", true)) - private val infoMessage = register(Settings.b("InfoMessage", false)) - - private var offsetStep = 0 - private var delayStep = 0 - private var playerHotbarSlot = -1 - private var lastHotbarSlot = -1 - private var isSneaking = false - private var totalTicksRunning = 0 - private var firstRun = false - private var missingObiDisable = false - - override fun onEnable() { - if (mc.player == null) { - disable() - return - } - firstRun = true - - // save initial player hand - playerHotbarSlot = mc.player.inventory.currentItem - lastHotbarSlot = -1 - } - - override fun onDisable() { - if (mc.player == null) return - - // load initial player hand - if (lastHotbarSlot != playerHotbarSlot && playerHotbarSlot != -1) { - mc.player.inventory.currentItem = playerHotbarSlot - } - if (isSneaking) { - mc.player.connection.sendPacket(CPacketEntityAction(mc.player, CPacketEntityAction.Action.STOP_SNEAKING)) - isSneaking = false - } - playerHotbarSlot = -1 - lastHotbarSlot = -1 - missingObiDisable = false - } - - override fun onUpdate() { - if (triggerable.value && totalTicksRunning >= timeoutTicks.value) { - totalTicksRunning = 0 - disable() - return - } - - if (!firstRun) { - delayStep = if (delayStep < tickDelay.value) { - delayStep++ - return - } else { - 0 - } - } - - if (firstRun) { - firstRun = false - if (findObiInHotbar() == -1) { - missingObiDisable = true - } - } - - var offsetPattern = arrayOfNulls(0) - var maxSteps = 0 - - if (mode.value == Mode.FULL) { - offsetPattern = Offsets.FULL - maxSteps = Offsets.FULL.size - } - if (mode.value == Mode.SURROUND) { - offsetPattern = Offsets.SURROUND - maxSteps = Offsets.SURROUND.size - } - - var blocksPlaced = 0 - - while (blocksPlaced < blocksPerTick.value) { - if (offsetStep >= maxSteps) { - offsetStep = 0 - break - } - val offsetPos = BlockPos(offsetPattern[offsetStep]) - val targetPos = BlockPos(mc.player.positionVector).add(offsetPos.x, offsetPos.y, offsetPos.z) - if (placeBlock(targetPos)) { - blocksPlaced++ - } - offsetStep++ - } - - if (blocksPlaced > 0) { - if (lastHotbarSlot != playerHotbarSlot && playerHotbarSlot != -1) { - mc.player.inventory.currentItem = playerHotbarSlot - lastHotbarSlot = playerHotbarSlot - } - if (isSneaking) { - mc.player.connection.sendPacket(CPacketEntityAction(mc.player, CPacketEntityAction.Action.STOP_SNEAKING)) - isSneaking = false - } - } - - totalTicksRunning++ - - if (missingObiDisable && disableNone.value) { - missingObiDisable = false - if (infoMessage.value) { - MessageSendHelper.sendChatMessage("$chatName " + ChatFormatting.RED + "Disabled" + ChatFormatting.RESET + ", Obsidian missing!") - } - disable() - } - } - - private fun placeBlock(pos: BlockPos): Boolean { - // check if block is already placed - val block = mc.world.getBlockState(pos).block - if (block !is BlockAir && block !is BlockLiquid) { - return false - } - - // check if entity blocks placing - for (entity in mc.world.getEntitiesWithinAABBExcludingEntity(null, AxisAlignedBB(pos))) { - if (entity !is EntityItem && entity !is EntityXPOrb) { - return false - } - } - val side = getPlaceableSide(pos) ?: return false - - // check if we have a block adjacent to blockpos to click at - val neighbour = pos.offset(side) - val opposite = side.opposite - - // check if neighbor can be right clicked - if (!BlockUtils.canBeClicked(neighbour)) { - return false - } - - val hitVec = Vec3d(neighbour).add(0.5, 0.5, 0.5).add(Vec3d(opposite.directionVec).scale(0.5)) - val neighbourBlock = mc.world.getBlockState(neighbour).block - val obiSlot = findObiInHotbar() - - if (obiSlot == -1) { - missingObiDisable = true - return false - } - if (lastHotbarSlot != obiSlot) { - mc.player.inventory.currentItem = obiSlot - lastHotbarSlot = obiSlot - } - if (!isSneaking && BlockUtils.blackList.contains(neighbourBlock) || BlockUtils.shulkerList.contains(neighbourBlock)) { - mc.player.connection.sendPacket(CPacketEntityAction(mc.player, CPacketEntityAction.Action.START_SNEAKING)) - isSneaking = true - } - if (rotate.value) { - BlockUtils.faceVectorPacketInstant(hitVec) - } - - mc.playerController.processRightClickBlock(mc.player, mc.world, neighbour, opposite, hitVec, EnumHand.MAIN_HAND) - mc.player.swingArm(EnumHand.MAIN_HAND) - mc.rightClickDelayTimer = 4 - - if (NoBreakAnimation.isEnabled) NoBreakAnimation.resetMining() - return true - } - - private fun findObiInHotbar(): Int { - // search blocks in hotbar - var slot = -1 - for (i in 0..8) { - // filter out non-block items - val stack = mc.player.inventory.getStackInSlot(i) - if (stack == ItemStack.EMPTY || stack.getItem() !is ItemBlock) { - continue - } - val block = (stack.getItem() as ItemBlock).block - if (block is BlockObsidian) { - slot = i - break - } - } - return slot - } - - private enum class Mode { - SURROUND, FULL - } - - private object Offsets { - val SURROUND = arrayOf( - Vec3d(1.0, 0.0, 0.0), - Vec3d(0.0, 0.0, 1.0), - Vec3d(-1.0, 0.0, 0.0), - Vec3d(0.0, 0.0, -1.0), - Vec3d(1.0, -1.0, 0.0), - Vec3d(0.0, -1.0, 1.0), - Vec3d(-1.0, -1.0, 0.0), - Vec3d(0.0, -1.0, -1.0) - ) - val FULL = arrayOf( - Vec3d(1.0, 0.0, 0.0), - Vec3d(0.0, 0.0, 1.0), - Vec3d(-1.0, 0.0, 0.0), - Vec3d(0.0, 0.0, -1.0), - Vec3d(1.0, -1.0, 0.0), - Vec3d(0.0, -1.0, 1.0), - Vec3d(-1.0, -1.0, 0.0), - Vec3d(0.0, -1.0, -1.0), - Vec3d(0.0, -1.0, 0.0) - ) - } - - private fun getPlaceableSide(pos: BlockPos): EnumFacing? { - for (side in EnumFacing.values()) { - val neighbour = pos.offset(side) - if (!mc.world.getBlockState(neighbour).block.canCollideCheck(mc.world.getBlockState(neighbour), false)) { - continue - } - val blockState = mc.world.getBlockState(neighbour) - if (!blockState.material.isReplaceable) { - return side - } - } - return null - } -} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoLog.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoLog.kt index f1903ab58..668df7777 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoLog.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoLog.kt @@ -7,6 +7,7 @@ import me.zeroeightsix.kami.setting.Setting import me.zeroeightsix.kami.setting.Settings import me.zeroeightsix.kami.util.Friends import me.zeroeightsix.kami.util.InventoryUtils +import me.zeroeightsix.kami.util.combat.CrystalUtils import me.zeroeightsix.kami.util.math.MathUtils import net.minecraft.client.audio.PositionedSoundRecord import net.minecraft.client.gui.GuiMainMenu @@ -57,7 +58,7 @@ object AutoLog : Module() { for (entity in mc.world.loadedEntityList) { if (entity !is EntityEnderCrystal) continue if (mc.player.getDistance(entity) > 8f) continue - if (mc.player.health - CrystalAura.calculateDamage(entity, mc.player) > health.value) continue + if (mc.player.health - CrystalUtils.calcDamage(entity, mc.player) > health.value) continue log(END_CRYSTAL) return } diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoOffhand.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoOffhand.kt new file mode 100644 index 000000000..ae3ca9016 --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoOffhand.kt @@ -0,0 +1,130 @@ +package me.zeroeightsix.kami.module.modules.combat + +import me.zero.alpine.listener.EventHandler +import me.zero.alpine.listener.EventHook +import me.zero.alpine.listener.Listener +import me.zeroeightsix.kami.event.events.PacketEvent +import me.zeroeightsix.kami.manager.mangers.CombatManager +import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.setting.Settings +import me.zeroeightsix.kami.util.InventoryUtils +import me.zeroeightsix.kami.util.TimerUtils +import me.zeroeightsix.kami.util.combat.CombatUtils +import me.zeroeightsix.kami.util.combat.CrystalUtils +import net.minecraft.client.gui.inventory.GuiContainer +import net.minecraft.entity.item.EntityEnderCrystal +import net.minecraft.entity.monster.EntityMob +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.Item +import net.minecraft.item.ItemAxe +import net.minecraft.item.ItemSword +import net.minecraft.network.play.server.SPacketConfirmTransaction +import kotlin.math.max + +@Module.Info( + name = "AutoOffhand", + description = "Manages item in your offhand", + category = Module.Category.COMBAT +) +object AutoOffhand : Module() { + private val type = register(Settings.enumBuilder(Type::class.java, "Type").withValue(Type.TOTEM)) + + // Totem + private val hpThreshold = register(Settings.floatBuilder("HpThreshold").withValue(5f).withRange(1f, 20f).withVisibility { type.value == Type.TOTEM }) + private val checkDamage = register(Settings.booleanBuilder("CheckDamage").withValue(true).withVisibility { type.value == Type.TOTEM }) + private val mob = register(Settings.booleanBuilder("Mob").withValue(true).withVisibility { type.value == Type.TOTEM && checkDamage.value }) + private val player = register(Settings.booleanBuilder("Player").withValue(true).withVisibility { type.value == Type.TOTEM && checkDamage.value }) + private val crystal = register(Settings.booleanBuilder("Crystal").withValue(true).withVisibility { type.value == Type.TOTEM && checkDamage.value }) + + // Gapple + private val offhandGapple = register(Settings.booleanBuilder("OffhandGapple").withValue(false).withVisibility { type.value == Type.GAPPLE }) + private val checkAura = register(Settings.booleanBuilder("CheckAura").withValue(true).withVisibility { type.value == Type.GAPPLE && offhandGapple.value }) + private val checkWeapon = register(Settings.booleanBuilder("CheckWeapon").withValue(false).withVisibility { type.value == Type.GAPPLE && offhandGapple.value }) + private val checkCAGapple = register(Settings.booleanBuilder("CheckCrystalAura").withValue(true).withVisibility { type.value == Type.GAPPLE && offhandGapple.value && !offhandCrystal.value }) + + // Crystal + private val offhandCrystal = register(Settings.booleanBuilder("OffhandCrystal").withValue(false).withVisibility { type.value == Type.CRYSTAL }) + private val checkCACrystal = register(Settings.booleanBuilder("CheckCrystalAura").withValue(false).withVisibility { type.value == Type.CRYSTAL && offhandCrystal.value }) + + private enum class Type(val itemId: Int) { + TOTEM(449), + GAPPLE(322), + CRYSTAL(426) + } + + private val transactionLog = HashMap() + private val movingTimer = TimerUtils.TickTimer() + private var maxDamage = 0f + + @EventHandler + private val receiveListener = Listener(EventHook { event: PacketEvent.Receive -> + if (mc.player == null || event.packet !is SPacketConfirmTransaction || event.packet.windowId != 0 || !transactionLog.containsKey(event.packet.actionNumber)) return@EventHook + transactionLog[event.packet.actionNumber] = event.packet.wasAccepted() + if (!transactionLog.containsValue(false)) movingTimer.reset(-200L) // If all the click packets were accepted then we reset the timer for next moving + }) + + override fun onRender() { + if (mc.player == null || mc.player.isDead || !movingTimer.tick(200L, false)) return // Delay 4 ticks by default + if (!mc.player.inventory.getItemStack().isEmpty()) { // If player is holding an in inventory + if (mc.currentScreen is GuiContainer) {// If inventory is open (playing moving item) + movingTimer.reset(-150) // delay for 1 tick + } else { // If inventory is not open (ex. inventory desync) + InventoryUtils.removeHoldingItem() + } + } else { // If player is not holding an item in inventory + val type = when { + checkTotem() -> Type.TOTEM + checkCrystal() -> Type.CRYSTAL + checkGapple() -> Type.GAPPLE + mc.player.heldItemOffhand.isEmpty() -> Type.TOTEM + else -> null + } + if (type != null && !checkOffhandItem(type)) getItemSlot(type)?.let { slot -> + transactionLog.clear() + transactionLog.putAll(InventoryUtils.moveToSlot(0, slot, 45).associate { it to false }) + transactionLog[InventoryUtils.quickMoveSlot(0, slot)] = false + mc.playerController.updateController() + movingTimer.reset() + } ?: movingTimer.reset(-150) // Delay 1 tick if can't find an item + } + } + + override fun onUpdate() { + maxDamage = 0f + if (!checkDamage.value) return + for (entity in mc.world.loadedEntityList) { + if (entity.name == mc.player.name) continue + if (entity !is EntityMob && entity !is EntityPlayer && entity !is EntityEnderCrystal) continue + if (mc.player.getDistance(entity) > 10f) continue + if (mob.value && entity is EntityMob) { + maxDamage = max(CombatUtils.calcDamageFromMob(entity), maxDamage) + } + if (player.value && entity is EntityPlayer) { + maxDamage = max(CombatUtils.calcDamageFromPlayer(entity), maxDamage) + } + if (crystal.value && entity is EntityEnderCrystal) { + maxDamage = max(CrystalUtils.calcDamage(entity, mc.player), maxDamage) + } + } + } + + private fun checkTotem() = mc.player.health < hpThreshold.value + || (checkDamage.value && mc.player.absorptionAmount + mc.player.health - maxDamage < hpThreshold.value) + + private fun checkGapple(): Boolean { + val item = mc.player.heldItemMainhand.getItem() + return offhandGapple.value + && (checkAura.value && CombatManager.isActiveAndTopPriority(Aura) + || checkWeapon.value && (item is ItemSword || item is ItemAxe) + || (checkCAGapple.value && !offhandCrystal.value) && CombatManager.isActiveAndTopPriority(CrystalAura)) + } + + private fun checkCrystal() = offhandCrystal.value && checkCACrystal.value && CombatManager.isActiveAndTopPriority(CrystalAura) + + private fun checkOffhandItem(type: Type) = Item.getIdFromItem(mc.player.heldItemOffhand.getItem()) == type.itemId + + private fun getItemSlot(type: Type): Int? = InventoryUtils.getSlotsFullInv(itemId = type.itemId)?.get(0) + ?: if (type == Type.CRYSTAL) InventoryUtils.getSlotsFullInv(itemId = 449)?.get(0) else getItemSlot(getNextType(type)) + + private fun getNextType(type: Type) = with(Type.values()) { this[(type.ordinal + 1) % this.size] } +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoTotem.java b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoTotem.java deleted file mode 100644 index b86647c46..000000000 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoTotem.java +++ /dev/null @@ -1,112 +0,0 @@ -package me.zeroeightsix.kami.module.modules.combat; - -import me.zeroeightsix.kami.module.Module; -import me.zeroeightsix.kami.setting.Setting; -import me.zeroeightsix.kami.setting.Settings; -import me.zeroeightsix.kami.util.InventoryUtils; -import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.init.Items; -import net.minecraft.inventory.ClickType; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; - -@Module.Info( - name = "AutoTotem", - category = Module.Category.COMBAT, - description = "Refills your offhand with totems or other items" -) -public class AutoTotem extends Module { - - private final Setting modeSetting = register(Settings.e("Mode", Mode.REPLACE_OFFHAND)); - private final Setting smartOffhand = register(Settings.booleanBuilder("CustomItem").withValue(false).withVisibility(v -> modeSetting.getValue().equals(Mode.REPLACE_OFFHAND)).build()); - private final Setting healthSetting = register(Settings.doubleBuilder("CustomItemHealth").withValue(14.0).withVisibility(v -> smartOffhand.getValue() && modeSetting.getValue().equals(Mode.REPLACE_OFFHAND)).build()); - private final Setting smartItemSetting = register(Settings.enumBuilder(CustomItem.class).withName("Item").withValue(CustomItem.GAPPLE).withVisibility(v -> smartOffhand.getValue() && modeSetting.getValue().equals(Mode.REPLACE_OFFHAND)).build()); - - private enum Mode {NEITHER, REPLACE_OFFHAND, INVENTORY;} - - private enum CustomItem {CRYSTAL, GAPPLE} - - private int totems; - private boolean moving = false; - private boolean returnI = false; - - public static AutoTotem INSTANCE; - - public AutoTotem() { - super(); - INSTANCE = this; - } - - @Override - public void onUpdate() { - if (!modeSetting.getValue().equals(Mode.INVENTORY) && mc.currentScreen instanceof GuiContainer) - return; // this stops autototem from running if you're in a chest or something - if (returnI) { - int t = -1; - for (int i = 0; i < 45; i++) - if (mc.player.inventory.getStackInSlot(i).isEmpty) { - t = i; - break; - } - if (t == -1) return; - mc.playerController.windowClick(0, t < 9 ? t + 36 : t, 0, ClickType.PICKUP, mc.player); - returnI = false; - } - totems = mc.player.inventory.mainInventory.stream().filter(itemStack -> itemStack.getItem() == settingToItem()).mapToInt(ItemStack::getCount).sum(); - if (mc.player.getHeldItemOffhand().getItem() == settingToItem()) totems++; - else { - if (!modeSetting.getValue().equals(Mode.REPLACE_OFFHAND) && !mc.player.getHeldItemOffhand().isEmpty) - return; - if (moving) { - mc.playerController.windowClick(0, 45, 0, ClickType.PICKUP, mc.player); - moving = false; - if (!mc.player.inventory.itemStack.isEmpty()) returnI = true; - return; - } - if (mc.player.inventory.itemStack.isEmpty()) { - if (totems == 0) return; - int t = -1; - for (int i = 0; i < 45; i++) - if (mc.player.inventory.getStackInSlot(i).getItem() == settingToItem()) { - t = i; - break; - } - if (t == -1) return; // Should never happen! - mc.playerController.windowClick(0, t < 9 ? t + 36 : t, 0, ClickType.PICKUP, mc.player); - moving = true; - } else if (modeSetting.getValue().equals(Mode.REPLACE_OFFHAND)) { - int t = -1; - for (int i = 0; i < 45; i++) - if (mc.player.inventory.getStackInSlot(i).isEmpty) { - t = i; - break; - } - if (t == -1) return; - mc.playerController.windowClick(0, t < 9 ? t + 36 : t, 0, ClickType.PICKUP, mc.player); - } - } - } - - private Item settingToItem() { - if (!smartOffhand.getValue() || passHealthCheck()) return Items.TOTEM_OF_UNDYING; - switch (smartItemSetting.getValue()) { - case GAPPLE: - return Items.GOLDEN_APPLE; - case CRYSTAL: - return Items.END_CRYSTAL; - } - return null; - } - - private boolean passHealthCheck() { - if (modeSetting.getValue().equals(Mode.REPLACE_OFFHAND)) { - return mc.player.getHealth() + mc.player.getAbsorptionAmount() <= healthSetting.getValue(); - } - return true; - } - - @Override - public String getHudInfo() { - return "" + InventoryUtils.countItemAll(Item.getIdFromItem(settingToItem())); - } -} diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoTrap.java b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoTrap.java deleted file mode 100644 index 3033c13ea..000000000 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoTrap.java +++ /dev/null @@ -1,382 +0,0 @@ -package me.zeroeightsix.kami.module.modules.combat; - -import com.mojang.realmsclient.gui.ChatFormatting; -import me.zeroeightsix.kami.module.Module; -import me.zeroeightsix.kami.module.modules.player.NoBreakAnimation; -import me.zeroeightsix.kami.setting.Setting; -import me.zeroeightsix.kami.setting.Settings; -import me.zeroeightsix.kami.util.BlockUtils; -import me.zeroeightsix.kami.util.EntityUtils; -import me.zeroeightsix.kami.util.Friends; -import net.minecraft.block.Block; -import net.minecraft.block.BlockAir; -import net.minecraft.block.BlockLiquid; -import net.minecraft.block.BlockObsidian; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.Entity; -import net.minecraft.entity.item.EntityItem; -import net.minecraft.entity.item.EntityXPOrb; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemBlock; -import net.minecraft.item.ItemStack; -import net.minecraft.network.play.client.CPacketEntityAction; -import net.minecraft.network.play.client.CPacketPlayerDigging; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.GameType; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static me.zeroeightsix.kami.util.BlockUtils.canBeClicked; -import static me.zeroeightsix.kami.util.BlockUtils.faceVectorPacketInstant; -import static me.zeroeightsix.kami.util.text.MessageSendHelper.sendChatMessage; - -@Module.Info( - name = "AutoTrap", - category = Module.Category.COMBAT, - description = "Traps your enemies in obsidian" -) -public class AutoTrap extends Module { - private final Setting range = register(Settings.doubleBuilder("Range").withMinimum(3.5).withValue(5.5).withMaximum(10.0).build()); - private final Setting blocksPerTick = register(Settings.integerBuilder("BlocksPerTick").withMinimum(1).withValue(2).withMaximum(23).build()); - private final Setting tickDelay = register(Settings.integerBuilder("TickDelay").withMinimum(0).withValue(2).withMaximum(10).build()); - private final Setting cage = register(Settings.e("Cage", Cage.TRAP)); - private final Setting rotate = register(Settings.b("Rotate", false)); - private final Setting noGlitchBlocks = register(Settings.b("NoGlitchBlocks", true)); - private final Setting selfTrap = register(Settings.b("SelfTrap", false)); - private final Setting infoMessage = register(Settings.b("Debug", false)); - - private EntityPlayer closestTarget; - private String lastTargetName; - - private int playerHotbarSlot = -1; - private int lastHotbarSlot = -1; - private boolean isSneaking = false; - private int delayStep = 0; - private int offsetStep = 0; - private boolean firstRun; - private boolean missingObiDisable = false; - - public static AutoTrap INSTANCE; - - public AutoTrap() { - super(); - INSTANCE = this; - } - - private static EnumFacing getPlaceableSide(BlockPos pos) { - for (EnumFacing side : EnumFacing.values()) { - BlockPos neighbour = pos.offset(side); - if (!mc.world.getBlockState(neighbour).getBlock().canCollideCheck(mc.world.getBlockState(neighbour), false)) { - continue; - } - - IBlockState blockState = mc.world.getBlockState(neighbour); - if (!blockState.getMaterial().isReplaceable()) { - return side; - } - } - - return null; - } - - @Override - protected void onEnable() { - if (mc.player == null || mc.player.getHealth() <= 0) { - disable(); - return; - } - - firstRun = true; - - // save initial player hand - playerHotbarSlot = mc.player.inventory.currentItem; - lastHotbarSlot = -1; - - } - - @Override - protected void onDisable() { - if (mc.player == null || mc.player.getHealth() <= 0) return; - - if (lastHotbarSlot != playerHotbarSlot && playerHotbarSlot != -1) { - mc.player.inventory.currentItem = playerHotbarSlot; - } - - if (isSneaking) { - mc.player.connection.sendPacket(new CPacketEntityAction(mc.player, CPacketEntityAction.Action.STOP_SNEAKING)); - isSneaking = false; - } - - playerHotbarSlot = -1; - lastHotbarSlot = -1; - - missingObiDisable = false; - } - - @Override - public void onUpdate() { - if (mc.player.getHealth() <= 0) return; - - if (firstRun) { - if (findObiInHotbar() == -1) { - if (infoMessage.getValue()) { - sendChatMessage(getChatName() + " " + ChatFormatting.RED + "Disabled" + ChatFormatting.RESET + ", Obsidian missing!"); - } - disable(); - return; - } - } else { - if (delayStep < tickDelay.getValue()) { - delayStep++; - return; - } else { - delayStep = 0; - } - } - - findClosestTarget(); - - if (closestTarget == null) { - return; - } - - if (firstRun) { - firstRun = false; - lastTargetName = closestTarget.getName(); - } else if (!lastTargetName.equals(closestTarget.getName())) { - offsetStep = 0; - lastTargetName = closestTarget.getName(); - } - - List placeTargets = new ArrayList<>(); - - if (cage.getValue().equals(Cage.TRAP)) Collections.addAll(placeTargets, Offsets.TRAP); - - if (cage.getValue().equals(Cage.CRYSTALEXA)) Collections.addAll(placeTargets, Offsets.CRYSTALEXA); - - if (cage.getValue().equals(Cage.CRYSTALFULL)) Collections.addAll(placeTargets, Offsets.CRYSTALFULL); - - int blocksPlaced = 0; - - while (blocksPlaced < blocksPerTick.getValue()) { - if (offsetStep >= placeTargets.size()) { - offsetStep = 0; - break; - } - - BlockPos offsetPos = new BlockPos(placeTargets.get(offsetStep)); - BlockPos targetPos = new BlockPos(closestTarget.getPositionVector()).down().add(offsetPos.x, offsetPos.y, offsetPos.z); - - if (placeBlockInRange(targetPos, range.getValue())) { - blocksPlaced++; - } - offsetStep++; - } - - if (blocksPlaced > 0) { - if (lastHotbarSlot != playerHotbarSlot && playerHotbarSlot != -1) { - mc.player.inventory.currentItem = playerHotbarSlot; - lastHotbarSlot = playerHotbarSlot; - } - - if (isSneaking) { - mc.player.connection.sendPacket(new CPacketEntityAction(mc.player, CPacketEntityAction.Action.STOP_SNEAKING)); - isSneaking = false; - } - } - - if (missingObiDisable) { - missingObiDisable = false; - if (infoMessage.getValue()) { - sendChatMessage(getChatName() + " " + ChatFormatting.RED + "Disabled" + ChatFormatting.RESET + ", Obsidian missing!"); - } - disable(); - } - } - - private boolean placeBlockInRange(BlockPos pos, double range) { - // check if block is already placed - Block block = mc.world.getBlockState(pos).getBlock(); - if (!(block instanceof BlockAir) && !(block instanceof BlockLiquid)) { - return false; - } - - // check if entity blocks placing - for (Entity entity : mc.world.getEntitiesWithinAABBExcludingEntity(null, new AxisAlignedBB(pos))) { - if (!(entity instanceof EntityItem) && !(entity instanceof EntityXPOrb)) { - return false; - } - } - - EnumFacing side = getPlaceableSide(pos); - - // check if we have a block adjacent to blockpos to click at - if (side == null) { - return false; - } - - BlockPos neighbour = pos.offset(side); - EnumFacing opposite = side.getOpposite(); - - // check if neighbor can be right clicked - if (!canBeClicked(neighbour)) { - return false; - } - - Vec3d hitVec = new Vec3d(neighbour).add(0.5, 0.5, 0.5).add(new Vec3d(opposite.getDirectionVec()).scale(0.5)); - Block neighbourBlock = mc.world.getBlockState(neighbour).getBlock(); - - if (mc.player.getPositionVector().distanceTo(hitVec) > range) { - return false; - } - - int obiSlot = findObiInHotbar(); - - if (obiSlot == -1) { - missingObiDisable = true; - return false; - } - - if (lastHotbarSlot != obiSlot) { - mc.player.inventory.currentItem = obiSlot; - lastHotbarSlot = obiSlot; - } - - if (!isSneaking && BlockUtils.blackList.contains(neighbourBlock) || BlockUtils.shulkerList.contains(neighbourBlock)) { - mc.player.connection.sendPacket(new CPacketEntityAction(mc.player, CPacketEntityAction.Action.START_SNEAKING)); - isSneaking = true; - } - - if (rotate.getValue()) faceVectorPacketInstant(hitVec); - - mc.playerController.processRightClickBlock(mc.player, mc.world, neighbour, opposite, hitVec, EnumHand.MAIN_HAND); - mc.player.swingArm(EnumHand.MAIN_HAND); - mc.rightClickDelayTimer = 4; - - if (noGlitchBlocks.getValue() && !mc.playerController.getCurrentGameType().equals(GameType.CREATIVE)) { - mc.player.connection.sendPacket(new CPacketPlayerDigging(CPacketPlayerDigging.Action.START_DESTROY_BLOCK, neighbour, opposite)); - } - - if (NoBreakAnimation.INSTANCE.isEnabled()) NoBreakAnimation.INSTANCE.resetMining(); - return true; - } - - private int findObiInHotbar() { - // search blocks in hotbar - int slot = -1; - for (int i = 0; i < 9; i++) { - // filter out non-block items - ItemStack stack = mc.player.inventory.getStackInSlot(i); - - if (stack == ItemStack.EMPTY || !(stack.getItem() instanceof ItemBlock)) { - continue; - } - - Block block = ((ItemBlock) stack.getItem()).getBlock(); - if (block instanceof BlockObsidian) { - slot = i; - break; - } - } - return slot; - } - - private void findClosestTarget() { - List playerList = mc.world.playerEntities; - closestTarget = null; - - for (EntityPlayer target : playerList) { - if (target == mc.player && !selfTrap.getValue()) continue; - - if (mc.player.getDistance(target) > range.getValue() + 3) continue; - - if (!EntityUtils.isLiving(target)) continue; - - if ((target).getHealth() <= 0) continue; - - if (Friends.isFriend(target.getName())) continue; - - if (closestTarget == null) { - closestTarget = target; - continue; - } - - if (mc.player.getDistance(target) < mc.player.getDistance(closestTarget)) closestTarget = target; - } - } - - @Override - public String getHudInfo() { - if (closestTarget != null) { - return closestTarget.getName().toUpperCase(); - } - return "NO TARGET"; - } - - private enum Cage { - TRAP, CRYSTALEXA, CRYSTALFULL - } - - private static class Offsets { - private static final Vec3d[] TRAP = { - new Vec3d(0, 0, -1), - new Vec3d(1, 0, 0), - new Vec3d(0, 0, 1), - new Vec3d(-1, 0, 0), - new Vec3d(0, 1, -1), - new Vec3d(1, 1, 0), - new Vec3d(0, 1, 1), - new Vec3d(-1, 1, 0), - new Vec3d(0, 2, -1), - new Vec3d(1, 2, 0), - new Vec3d(0, 2, 1), - new Vec3d(-1, 2, 0), - new Vec3d(0, 3, -1), - new Vec3d(0, 3, 0) - }; - - private static final Vec3d[] CRYSTALEXA = { - new Vec3d(0, 0, -1), - new Vec3d(0, 1, -1), - new Vec3d(0, 2, -1), - new Vec3d(1, 2, 0), - new Vec3d(0, 2, 1), - new Vec3d(-1, 2, 0), - new Vec3d(-1, 2, -1), - new Vec3d(1, 2, 1), - new Vec3d(1, 2, -1), - new Vec3d(-1, 2, 1), - new Vec3d(0, 3, -1), - new Vec3d(0, 3, 0) - }; - - private static final Vec3d[] CRYSTALFULL = { - new Vec3d(0, 0, -1), - new Vec3d(1, 0, 0), - new Vec3d(0, 0, 1), - new Vec3d(-1, 0, 0), - new Vec3d(-1, 0, 1), - new Vec3d(1, 0, -1), - new Vec3d(-1, 0, -1), - new Vec3d(1, 0, 1), - new Vec3d(-1, 1, -1), - new Vec3d(1, 1, 1), - new Vec3d(-1, 1, 1), - new Vec3d(1, 1, -1), - new Vec3d(0, 2, -1), - new Vec3d(1, 2, 0), - new Vec3d(0, 2, 1), - new Vec3d(-1, 2, 0), - new Vec3d(-1, 2, 1), - new Vec3d(1, 2, -1), - new Vec3d(0, 3, -1), - new Vec3d(0, 3, 0) - }; - } -} diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoTrap.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoTrap.kt new file mode 100644 index 000000000..f7c7ea86b --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/AutoTrap.kt @@ -0,0 +1,108 @@ +package me.zeroeightsix.kami.module.modules.combat + +import me.zeroeightsix.kami.manager.mangers.CombatManager +import me.zeroeightsix.kami.manager.mangers.PlayerPacketManager +import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.setting.Settings +import me.zeroeightsix.kami.util.BlockUtils +import me.zeroeightsix.kami.util.InventoryUtils +import me.zeroeightsix.kami.util.math.VectorUtils.toBlockPos +import me.zeroeightsix.kami.util.text.MessageSendHelper +import net.minecraft.util.math.BlockPos +import java.util.concurrent.Executors +import java.util.concurrent.Future + +@Module.Info( + name = "AutoTrap", + category = Module.Category.COMBAT, + description = "Traps your enemies in obsidian", + modulePriority = 60 +) +object AutoTrap : Module() { + private val trapMode = register(Settings.e("TrapMode", TrapMode.FULL_TRAP)) + private val selfTrap = register(Settings.b("SelfTrap", false)) + private val autoDisable = register(Settings.b("AutoDisable", true)) + private val placeSpeed = register(Settings.floatBuilder("PlacesPerTick").withValue(4f).withRange(0.25f, 5f).withStep(0.25f)) + + private val placeThread = Thread { runAutoTrap() }.apply { name = "AutoTrap" } + private val threadPool = Executors.newSingleThreadExecutor() + private var future: Future<*>? = null + + override fun isActive(): Boolean { + return isEnabled && future?.isDone == false + } + + override fun onDisable() { + PlayerPacketManager.resetHotbar() + } + + override fun onUpdate() { + if (future?.isDone != false && isPlaceable()) future = threadPool.submit(placeThread) + + if (future?.isDone == false && future?.isCancelled == false) { + val slot = getObby() + if (slot != -1) PlayerPacketManager.spoofHotbar(getObby()) + PlayerPacketManager.addPacket(this, PlayerPacketManager.PlayerPacket(rotating = false)) + } else if (CombatManager.isOnTopPriority(this)) { + PlayerPacketManager.resetHotbar() + } + } + + private fun isPlaceable(): Boolean { + (if (selfTrap.value) mc.player else CombatManager.target)?.positionVector?.toBlockPos()?.let { + for (offset in trapMode.value.offset) { + if (!BlockUtils.isPlaceable(it.add(offset))) continue + return true + } + } + return false + } + + private fun getObby(): Int { + val slots = InventoryUtils.getSlotsHotbar(49) + if (slots == null) { // Obsidian check + MessageSendHelper.sendChatMessage("$chatName No obsidian in hotbar, disabling!") + disable() + return -1 + } + return slots[0] + } + + private fun runAutoTrap() { + BlockUtils.buildStructure(placeSpeed.value) { + if (isEnabled && CombatManager.isOnTopPriority(this)) { + val center = (if (selfTrap.value) mc.player else CombatManager.target)?.positionVector?.toBlockPos() + BlockUtils.getPlaceInfo(center, trapMode.value.offset, it, 3) + } else { + null + } + } + if (autoDisable.value) disable() + } + + @Suppress("UNUSED") + private enum class TrapMode(val offset: Array) { + FULL_TRAP(arrayOf( + BlockPos(1, 0, 0), + BlockPos(-1, 0, 0), + BlockPos(0, 0, 1), + BlockPos(0, 0, -1), + BlockPos(1, 1, 0), + BlockPos(-1, 1, 0), + BlockPos(0, 1, 1), + BlockPos(0, 1, -1), + BlockPos(0, 2, 0) + )), + CRYSTAL_TRAP(arrayOf( + BlockPos(1, 1, 1), + BlockPos(1, 1, 0), + BlockPos(1, 1, -1), + BlockPos(0, 1, -1), + BlockPos(-1, 1, -1), + BlockPos(-1, 1, 0), + BlockPos(-1, 1, 1), + BlockPos(0, 1, 1), + BlockPos(0, 2, 0) + )) + } +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/BedAura.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/BedAura.kt new file mode 100644 index 000000000..ebcce9c1c --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/BedAura.kt @@ -0,0 +1,216 @@ +package me.zeroeightsix.kami.module.modules.combat + +import me.zero.alpine.listener.EventHandler +import me.zero.alpine.listener.EventHook +import me.zero.alpine.listener.Listener +import me.zeroeightsix.kami.event.events.PacketEvent +import me.zeroeightsix.kami.manager.mangers.CombatManager +import me.zeroeightsix.kami.manager.mangers.PlayerPacketManager +import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.setting.Settings +import me.zeroeightsix.kami.util.BlockUtils +import me.zeroeightsix.kami.util.InventoryUtils +import me.zeroeightsix.kami.util.TimerUtils +import me.zeroeightsix.kami.util.combat.CrystalUtils +import me.zeroeightsix.kami.util.math.RotationUtils +import me.zeroeightsix.kami.util.math.Vec2d +import me.zeroeightsix.kami.util.math.Vec2f +import me.zeroeightsix.kami.util.math.VectorUtils +import net.minecraft.init.Blocks +import net.minecraft.init.Items +import net.minecraft.network.play.client.CPacketPlayer +import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock +import net.minecraft.tileentity.TileEntityBed +import net.minecraft.util.EnumFacing +import net.minecraft.util.EnumHand +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d +import java.util.* +import kotlin.collections.HashMap +import kotlin.math.pow +import kotlin.math.sqrt + +@Module.Info( + name = "BedAura", + description = "Place bed and kills enemies", + category = Module.Category.COMBAT, + modulePriority = 70 +) +object BedAura : Module() { + private val ignoreSecondBaseBlock = register(Settings.b("IgnoreSecondBaseBlock", false)) + private val suicideMode = register(Settings.b("SuicideMode", false)) + private val hitDelay = register(Settings.integerBuilder("HitDelay").withValue(5).withRange(1, 10)) + private val refillDelay = register(Settings.integerBuilder("RefillDelay").withValue(2).withRange(1, 5)) + private val minDamage = register(Settings.floatBuilder("MinDamage").withValue(10f).withRange(1f, 20f)) + private val maxSelfDamage = register(Settings.floatBuilder("MaxSelfDamage").withValue(4f).withRange(1f, 10f).withVisibility { !suicideMode.value }) + private val range = register(Settings.floatBuilder("Range").withValue(5f).withRange(1f, 5f)) + private val wallRange = register(Settings.floatBuilder("WallRange").withValue(2.5f).withRange(1f, 5f)) + + private val placeMap = TreeMap, BlockPos>(compareByDescending { it.first }) // <, BlockPos> + private val bedMap = TreeMap(compareBy { it }) // + private val refillTimer = TimerUtils.TickTimer(TimerUtils.TimeUnit.TICKS) + private var state = State.NONE + private var clickPos = BlockPos(0, -6969, 0) + private var lastRotation = Vec2d(0.0, 0.0) + private var hitTickCount = 0 + private var inactiveTicks = 0 + + private enum class State { + NONE, PLACE, EXPLODE + } + + override fun isActive(): Boolean { + return isEnabled && inactiveTicks <= 5 + } + + override fun onDisable() { + state = State.NONE + inactiveTicks = 6 + } + + @EventHandler + private val postSendListener = Listener(EventHook { event: PacketEvent.PostSend -> + if (!CombatManager.isOnTopPriority(this) || event.packet !is CPacketPlayer || state == State.NONE || CombatSetting.pause) return@EventHook + val hand = getBedHand() ?: EnumHand.MAIN_HAND + val facing = if (state == State.PLACE) EnumFacing.UP else BlockUtils.getHitSide(clickPos) + val hitVecOffset = BlockUtils.getHitVecOffset(facing) + val packet = CPacketPlayerTryUseItemOnBlock(clickPos, facing, hand, hitVecOffset.x.toFloat(), hitVecOffset.y.toFloat(), hitVecOffset.z.toFloat()) + mc.connection!!.sendPacket(packet) + mc.player.swingArm(hand) + state = State.NONE + }) + + override fun onUpdate() { + if (mc.player.dimension == 0 || !CombatManager.isOnTopPriority(this) || CombatSetting.pause) { + state = State.NONE + resetRotation() + inactiveTicks = 6 + return + } + + inactiveTicks++ + if (canRefill() && refillTimer.tick(refillDelay.value.toLong())) { + InventoryUtils.getSlotsFullInvNoHotbar(355)?.let { + InventoryUtils.quickMoveSlot(it[0]) + mc.playerController.syncCurrentPlayItem() + } + } + + updatePlaceMap() + updateBedMap() + + if (hitTickCount >= hitDelay.value) { + bedMap.values.firstOrNull()?.let { preExplode(it) } ?: getPlacePos()?.let { prePlace(it) } + } else { + hitTickCount++ + getPlacePos()?.let { prePlace(it) } + } + if (inactiveTicks <= 5) sendRotation() + else resetRotation() + } + + private fun canRefill(): Boolean { + return InventoryUtils.getSlotsHotbar(0) != null + && InventoryUtils.getSlotsNoHotbar(355) != null + } + + private fun updatePlaceMap() { + val cacheMap = CombatManager.target?.let { + val posList = VectorUtils.getBlockPosInSphere(mc.player.getPositionEyes(1f), range.value) + val damagePosMap = HashMap, BlockPos>() + for (pos in posList) { + val dist = sqrt(mc.player.getDistanceSqToCenter(pos)) + if (BlockUtils.rayTraceTo(pos) == null && dist > wallRange.value) continue + val topSideVec = Vec3d(pos).add(0.5, 1.0, 0.5) + val rotation = RotationUtils.getRotationTo(topSideVec, true) + val facing = EnumFacing.fromAngle(rotation.x) + if (!canPlaceBed(pos)) continue + val targetDamage = CrystalUtils.calcDamage(pos.offset(facing), it) + val selfDamage = CrystalUtils.calcDamage(pos.offset(facing), mc.player) + if (targetDamage < minDamage.value && (suicideMode.value || selfDamage > maxSelfDamage.value)) + damagePosMap[Pair(targetDamage, selfDamage)] = pos + } + damagePosMap + } + placeMap.clear() + if (cacheMap != null) placeMap.putAll(cacheMap) + } + + private fun canPlaceBed(pos: BlockPos): Boolean { + if (!mc.world.getBlockState(pos).isSideSolid(mc.world, pos, EnumFacing.UP)) return false + val bedPos1 = pos.up() + val bedPos2 = getSecondBedPos(bedPos1) + return (!ignoreSecondBaseBlock.value || mc.world.getBlockState(bedPos2.down()).isSideSolid(mc.world, bedPos2.down(), EnumFacing.UP)) + && !isFire(bedPos1) + && !isFire(bedPos2) + && mc.world.getBlockState(bedPos1).material.isReplaceable + && (!ignoreSecondBaseBlock.value || mc.world.getBlockState(bedPos2).material.isReplaceable) + } + + private fun isFire(pos: BlockPos): Boolean { + return mc.world.getBlockState(pos).block == Blocks.FIRE + } + + private fun updateBedMap() { + val cacheMap = CombatManager.target?.let { + val damagePosMap = HashMap() + for (tileEntity in mc.world.loadedTileEntityList) { + if (tileEntity !is TileEntityBed) continue + if (!tileEntity.isHeadPiece) continue + val dist = mc.player.getDistanceSqToCenter(tileEntity.pos).toFloat() + if (dist > range.value.pow(2)) continue + if (BlockUtils.rayTraceTo(tileEntity.pos) == null && dist > wallRange.value.pow(2)) continue + damagePosMap[dist] = tileEntity.pos + } + damagePosMap + } + bedMap.clear() + if (cacheMap != null) bedMap.putAll(cacheMap) + } + + private fun getPlacePos() = placeMap.values.firstOrNull() + + private fun prePlace(pos: BlockPos) { + if (getExplodePos() != null || InventoryUtils.countItemAll(355) == 0) return + if (getBedHand() == null) InventoryUtils.swapSlotToItem(355) + preClick(pos, Vec3d(0.5, 1.0, 0.5)) + state = State.PLACE + } + + private fun getExplodePos() = bedMap.values.firstOrNull() + + private fun preExplode(pos: BlockPos) { + hitTickCount = 0 + preClick(pos, Vec3d(0.5, 0.0, 0.5)) + state = State.EXPLODE + } + + private fun preClick(pos: BlockPos, hitOffset: Vec3d) { + inactiveTicks = 0 + clickPos = pos + lastRotation = RotationUtils.getRotationTo(Vec3d(pos).add(hitOffset), true) + } + + private fun getSecondBedPos(pos: BlockPos): BlockPos { + val vec3d = Vec3d(pos).add(0.5, 0.0, 0.5) + val rotation = RotationUtils.getRotationTo(vec3d, true) + val facing = EnumFacing.fromAngle(rotation.x) + return pos.offset(facing) + } + + private fun getBedHand(): EnumHand? { + return when (Items.BED) { + mc.player.heldItemMainhand.getItem() -> EnumHand.MAIN_HAND + mc.player.heldItemMainhand.getItem() -> EnumHand.OFF_HAND + else -> null + } + } + + private fun sendRotation() { + PlayerPacketManager.addPacket(this, PlayerPacketManager.PlayerPacket(rotating = true, rotation = Vec2f(lastRotation))) + } + + private fun resetRotation() { + lastRotation = Vec2d(RotationUtils.normalizeAngle(mc.player.rotationYaw.toDouble()), mc.player.rotationPitch.toDouble()) + } +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/CombatSetting.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/CombatSetting.kt new file mode 100644 index 000000000..6228505ab --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/CombatSetting.kt @@ -0,0 +1,232 @@ +package me.zeroeightsix.kami.module.modules.combat + +import me.zeroeightsix.kami.manager.mangers.CombatManager +import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.setting.Settings +import me.zeroeightsix.kami.util.BaritoneUtils +import me.zeroeightsix.kami.util.EntityUtils +import me.zeroeightsix.kami.util.InfoCalculator +import me.zeroeightsix.kami.util.TimerUtils +import me.zeroeightsix.kami.util.color.ColorHolder +import me.zeroeightsix.kami.util.combat.CombatUtils +import me.zeroeightsix.kami.util.graphics.* +import me.zeroeightsix.kami.util.math.RotationUtils +import me.zeroeightsix.kami.util.math.Vec2d +import net.minecraft.entity.Entity +import net.minecraft.entity.EntityLivingBase +import net.minecraft.item.ItemFood +import net.minecraft.item.ItemPickaxe +import net.minecraft.util.EnumHand +import org.lwjgl.opengl.GL11.* +import java.util.* +import kotlin.collections.HashSet +import kotlin.math.ceil + +@Module.Info( + name = "CombatSetting", + description = "Settings for combat module targeting", + category = Module.Category.COMBAT, + showOnArray = Module.ShowOnArray.OFF, + alwaysEnabled = true +) +object CombatSetting : Module() { + private val page = register(Settings.e("Page", Page.TARGETING)) + + /* Targeting */ + private val filter = register(Settings.enumBuilder(TargetFilter::class.java, "Filter").withValue(TargetFilter.ALL).withVisibility { page.value == Page.TARGETING }) + private val fov = register(Settings.floatBuilder("FOV").withValue(90f).withRange(0f, 180f).withVisibility { page.value == Page.TARGETING && filter.value == TargetFilter.FOV }) + private val priority = register(Settings.enumBuilder(TargetPriority::class.java, "Priority").withValue(TargetPriority.DISTANCE).withVisibility { page.value == Page.TARGETING }) + private val players = register(Settings.booleanBuilder("Players").withValue(true).withVisibility { page.value == Page.TARGETING }) + private val friends = register(Settings.booleanBuilder("Friends").withValue(false).withVisibility { page.value == Page.TARGETING && players.value }) + private val teammates = register(Settings.booleanBuilder("Teammates").withValue(false).withVisibility { page.value == Page.TARGETING && players.value }) + private val sleeping = register(Settings.booleanBuilder("Sleeping").withValue(false).withVisibility { page.value == Page.TARGETING && players.value }) + private val mobs = register(Settings.booleanBuilder("Mobs").withValue(true).withVisibility { page.value == Page.TARGETING }) + private val passive = register(Settings.booleanBuilder("PassiveMobs").withValue(false).withVisibility { page.value == Page.TARGETING && mobs.value }) + private val neutral = register(Settings.booleanBuilder("NeutralMobs").withValue(false).withVisibility { page.value == Page.TARGETING && mobs.value }) + private val hostile = register(Settings.booleanBuilder("HostileMobs").withValue(false).withVisibility { page.value == Page.TARGETING && mobs.value }) + private val invisible = register(Settings.booleanBuilder("Invisible").withValue(true).withVisibility { page.value == Page.TARGETING }) + private val ignoreWalls = register(Settings.booleanBuilder("IgnoreWalls").withValue(false).withVisibility { page.value == Page.TARGETING }) + private val range = register(Settings.floatBuilder("TargetRange").withValue(16.0f).withRange(2.0f, 64.0f).withVisibility { page.value == Page.TARGETING }) + + /* In Combat */ + private val pauseForDigging = register(Settings.booleanBuilder("PauseForDigging").withValue(true).withVisibility { page.value == Page.IN_COMBAT }) + private val pauseForEating = register(Settings.booleanBuilder("PauseForEating").withValue(true).withVisibility { page.value == Page.IN_COMBAT }) + private val ignoreOffhandEating = register(Settings.booleanBuilder("IgnoreOffhandEating").withValue(true).withVisibility { page.value == Page.IN_COMBAT && pauseForEating.value }) + private val pauseBaritone = register(Settings.booleanBuilder("PauseBaritone").withValue(true).withVisibility { page.value == Page.IN_COMBAT }) + private val resumeDelay = register(Settings.integerBuilder("ResumeDelay").withRange(1, 10).withValue(3).withVisibility { page.value == Page.IN_COMBAT && pauseBaritone.value }) + + /* Render */ + private val renderPredictedPos = register(Settings.booleanBuilder("RenderPredictedPosition").withValue(false).withVisibility { page.value == Page.RENDER }) + private val pingSync = register(Settings.booleanBuilder("PingSync").withValue(true).withVisibility { page.value == Page.RENDER && renderPredictedPos.value }) + private val ticksAhead = register(Settings.integerBuilder("TicksAhead").withValue(5).withRange(0, 20).withVisibility { page.value == Page.RENDER && renderPredictedPos.value && !pingSync.value }) + + private enum class Page { + TARGETING, IN_COMBAT, RENDER + } + + private enum class TargetFilter { + ALL, FOV, MANUAL + } + + private enum class TargetPriority { + DAMAGE, HEALTH, CROSS_HAIR, DISTANCE + } + + private var overrideRange = range.value + private var paused = false + private val resumeTimer = TimerUtils.TickTimer(TimerUtils.TimeUnit.SECONDS) + val pause + get() = pauseForDigging.value && mc.player.heldItemMainhand.getItem() is ItemPickaxe && mc.playerController.isHittingBlock + || pauseForEating.value && mc.player.isHandActive && mc.player.activeItemStack.getItem() is ItemFood && (mc.player.activeHand != EnumHand.OFF_HAND || !ignoreOffhandEating.value) + + + override fun isActive() = Aura.isActive() || BedAura.isActive() || CrystalAura.isActive() || Surround.isActive() + + override fun onRender() { + if (!renderPredictedPos.value) return + CombatManager.target?.let { + val ticks = if (pingSync.value) ceil(InfoCalculator.ping() / 25f).toInt() else ticksAhead.value + val posCurrent = EntityUtils.getInterpolatedPos(it, KamiTessellator.pTicks()) + val posAhead = CombatManager.motionTracker.calcPositionAhead(ticks, true) ?: return + val posAheadEye = posAhead.add(0.0, it.eyeHeight.toDouble(), 0.0) + val posCurrentScreen = Vec2d(ProjectionUtils.toScaledScreenPos(posCurrent)) + val posAheadScreen = Vec2d(ProjectionUtils.toScaledScreenPos(posAhead)) + val posAheadEyeScreen = Vec2d(ProjectionUtils.toScaledScreenPos(posAheadEye)) + val vertexHelper = VertexHelper(GlStateUtils.useVbo()) + val vertices = arrayOf(posCurrentScreen, posAheadScreen, posAheadEyeScreen) + glDisable(GL_TEXTURE_2D) + RenderUtils2D.drawLineStrip(vertexHelper, vertices, 2f, ColorHolder(80, 255, 80)) + glEnable(GL_TEXTURE_2D) + } + } + + override fun onUpdate() { + with(CombatManager.getTopModule()) { + overrideRange = if (this is Aura) this.range.value else range.value + } + + getTargetList().let { + CombatManager.targetList = it + CombatManager.target = getTarget(it) + } + if (pauseBaritone.value && !paused && isActive()) { + BaritoneUtils.pause() + paused = true + } else if (paused && resumeTimer.tick(resumeDelay.value.toLong())) { + BaritoneUtils.unpause() + paused = false + } + } + + private fun getTargetList(): LinkedList { + val player = arrayOf(players.value, friends.value, sleeping.value) + val mob = arrayOf(mobs.value, passive.value, neutral.value, hostile.value) + val targetList = LinkedList(EntityUtils.getTargetList(player, mob, invisible.value, overrideRange)) + if ((targetList.isEmpty() || getTarget(targetList) == null) && overrideRange != range.value) { + targetList.addAll(EntityUtils.getTargetList(player, mob, invisible.value, range.value)) + } + if (!shouldIgnoreWall()) targetList.removeIf { + !mc.player.canEntityBeSeen(it) && EntityUtils.canEntityFeetBeSeen(it) && EntityUtils.canEntityHitboxBeSeen(it) == null + } + if (!teammates.value) targetList.removeIf { + mc.player.isOnSameTeam(it) + } + if (AntiBot.isEnabled) targetList.removeIf { + AntiBot.botSet.contains(it) + } + return targetList + } + + private fun shouldIgnoreWall(): Boolean { + val module = CombatManager.getTopModule() + return if (module is Aura || module is AimBot) ignoreWalls.value + else true + } + + private fun getTarget(listIn: LinkedList): EntityLivingBase? { + val copiedList = LinkedList(listIn) + return filterTargetList(copiedList) ?: CombatManager.target?.let { entity -> + if (!entity.isDead && listIn.contains(entity)) entity else null + } + } + + private fun filterTargetList(listIn: LinkedList): EntityLivingBase? { + if (listIn.isEmpty()) return null + return filterByPriority(filterByFilter(listIn)) + } + + private fun filterByFilter(listIn: LinkedList): LinkedList { + when (filter.value) { + TargetFilter.FOV -> { + listIn.removeIf { RotationUtils.getRelativeRotation(it) > fov.value } + } + + TargetFilter.MANUAL -> { + if (!mc.gameSettings.keyBindAttack.isKeyDown && !mc.gameSettings.keyBindUseItem.isKeyDown) { + return LinkedList() + } + val eyePos = mc.player.getPositionEyes(KamiTessellator.pTicks()) + val lookVec = mc.player.lookVec.scale(range.value.toDouble()) + val sightEndPos = eyePos.add(lookVec) + listIn.removeIf { it.boundingBox.calculateIntercept(eyePos, sightEndPos) == null } + } + + else -> { } + } + return listIn + } + + private fun filterByPriority(listIn: LinkedList): EntityLivingBase? { + if (listIn.isEmpty()) return null + + if (priority.value == TargetPriority.DAMAGE) filterByDamage(listIn) + + if (priority.value == TargetPriority.HEALTH) filterByHealth(listIn) + + return if (priority.value == TargetPriority.CROSS_HAIR) filterByCrossHair(listIn) else filterByDistance(listIn) + } + + private fun filterByDamage(listIn: LinkedList) { + if (listIn.isEmpty()) return + var damage = Float.MIN_VALUE + val toKeep = HashSet() + for (entity in listIn) { + val currentDamage = CombatUtils.calcDamage(entity, roundDamage = true) + if (currentDamage >= damage) { + if (currentDamage > damage) { + damage = currentDamage + toKeep.clear() + } + toKeep.add(entity) + } + } + listIn.removeIf { !toKeep.contains(it) } + } + + private fun filterByHealth(listIn: LinkedList) { + if (listIn.isEmpty()) return + var health = Float.MAX_VALUE + val toKeep = HashSet() + for (e in listIn) { + val currentHealth = e.health + if (currentHealth <= health) { + if (currentHealth < health) { + health = currentHealth + toKeep.clear() + } + toKeep.add(e) + } + } + listIn.removeIf { !toKeep.contains(it) } + } + + private fun filterByCrossHair(listIn: LinkedList): EntityLivingBase? { + if (listIn.isEmpty()) return null + return listIn.sortedBy { RotationUtils.getRelativeRotation(it) }[0] + } + + private fun filterByDistance(listIn: LinkedList): EntityLivingBase? { + if (listIn.isEmpty()) return null + return listIn.sortedBy { it.getDistance(mc.player) }[0] + } +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/CrystalAura.java b/src/main/java/me/zeroeightsix/kami/module/modules/combat/CrystalAura.java deleted file mode 100644 index 787ad9475..000000000 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/CrystalAura.java +++ /dev/null @@ -1,624 +0,0 @@ -package me.zeroeightsix.kami.module.modules.combat; - -import me.zero.alpine.listener.EventHandler; -import me.zero.alpine.listener.Listener; -import me.zeroeightsix.kami.event.events.PacketEvent; -import me.zeroeightsix.kami.event.events.RenderEvent; -import me.zeroeightsix.kami.module.Module; -import me.zeroeightsix.kami.module.modules.render.PlayerModel; -import me.zeroeightsix.kami.setting.Setting; -import me.zeroeightsix.kami.setting.Settings; -import me.zeroeightsix.kami.util.EntityUtils; -import me.zeroeightsix.kami.util.Friends; -import me.zeroeightsix.kami.util.InfoCalculator; -import me.zeroeightsix.kami.util.InventoryUtils; -import me.zeroeightsix.kami.util.color.ColorHolder; -import me.zeroeightsix.kami.util.graphics.ESPRenderer; -import me.zeroeightsix.kami.util.math.Vec2d; -import net.minecraft.enchantment.EnchantmentHelper; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.entity.item.EntityEnderCrystal; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Blocks; -import net.minecraft.init.Items; -import net.minecraft.init.MobEffects; -import net.minecraft.item.ItemStack; -import net.minecraft.item.ItemSword; -import net.minecraft.item.ItemTool; -import net.minecraft.network.Packet; -import net.minecraft.network.play.client.CPacketPlayer; -import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock; -import net.minecraft.potion.Potion; -import net.minecraft.util.*; -import net.minecraft.util.math.*; -import net.minecraft.world.Explosion; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -import static me.zeroeightsix.kami.util.math.RotationUtils.getRotationTo; -import static me.zeroeightsix.kami.util.text.MessageSendHelper.sendChatMessage; - -/** - * Created by 086 on 28/12/2017. - * Updated 3 December 2019 by hub - * Updated 8 March 2020 by polymer - * Updated by qther on 27/03/20 - * Updated by l1ving on 27/03/20 - * Updated by Afel on 08/06/20 - */ -@Module.Info( - name = "CrystalAura", - category = Module.Category.COMBAT, - description = "Places End Crystals to kill enemies" -) -public class CrystalAura extends Module { - private Setting defaultSetting = register(Settings.b("Defaults", false)); - private Setting p = register(Settings.enumBuilder(Page.class).withName("Page").withValue(Page.ONE).build()); - /* Page One */ - private Setting explodeBehavior = register(Settings.enumBuilder(ExplodeBehavior.class).withName("ExplodeBehavior").withValue(ExplodeBehavior.ALWAYS).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - private Setting placeBehavior = register(Settings.enumBuilder(PlaceBehavior.class).withName("PlaceBehavior").withValue(PlaceBehavior.TRADITIONAL).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - private Setting autoSwitch = register(Settings.booleanBuilder("AutoSwitch").withValue(true).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - private Setting place = register(Settings.booleanBuilder("Place").withValue(false).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - private Setting explode = register(Settings.booleanBuilder("Explode").withValue(false).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - private Setting checkAbsorption = register(Settings.booleanBuilder("CheckAbsorption").withValue(true).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - public Setting range = register(Settings.doubleBuilder("Range").withMinimum(1.0).withValue(4.0).withMaximum(10.0).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - private Setting autoDelay = register(Settings.booleanBuilder("AutoDelay").withValue(false).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - private Setting delay = register(Settings.doubleBuilder("HitDelay").withMinimum(0.0).withValue(5.0).withMaximum(10.0).withVisibility(v -> !autoDelay.getValue() && p.getValue().equals(Page.ONE)).build()); - private Setting hitAttempts = register(Settings.integerBuilder("HitAttempts").withValue(-1).withMinimum(-1).withMaximum(20).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - private Setting minDmg = register(Settings.doubleBuilder("MinimumDamage").withMinimum(0.0).withValue(0.0).withMaximum(32.0).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - private Setting sneakEnable = register(Settings.booleanBuilder("SneakSurround").withValue(true).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - private Setting placePriority = register(Settings.booleanBuilder("PrioritizeManual").withValue(false).withVisibility(v -> p.getValue().equals(Page.ONE)).build()); - /* Page Two */ - private Setting antiWeakness = register(Settings.booleanBuilder("AntiWeakness").withValue(false).withVisibility(v -> p.getValue().equals(Page.TWO)).build()); - private Setting noToolExplode = register(Settings.booleanBuilder("NoToolExplode").withValue(true).withVisibility(v -> !antiWeakness.getValue() && p.getValue().equals(Page.TWO)).build()); - private Setting players = register(Settings.booleanBuilder("Players").withValue(true).withVisibility(v -> p.getValue().equals(Page.TWO)).build()); - private Setting mobs = register(Settings.booleanBuilder("Mobs").withValue(false).withVisibility(v -> p.getValue().equals(Page.TWO)).build()); - private Setting passive = register(Settings.booleanBuilder("PassiveMobs").withValue(false).withVisibility(v -> mobs.getValue() && p.getValue().equals(Page.TWO)).build()); - private Setting neutral = register(Settings.booleanBuilder("NeutralMobs").withValue(false).withVisibility(v -> mobs.getValue() && p.getValue().equals(Page.TWO)).build()); - private Setting hostile = register(Settings.booleanBuilder("HostileMobs").withValue(true).withVisibility(v -> mobs.getValue() && p.getValue().equals(Page.TWO)).build()); - private Setting tracer = register(Settings.booleanBuilder("Tracer").withValue(true).withVisibility(v -> p.getValue().equals(Page.TWO)).build()); - private Setting customColours = register(Settings.booleanBuilder("CustomColours").withValue(true).withVisibility(v -> p.getValue().equals(Page.TWO)).build()); - private Setting aBlock = register(Settings.integerBuilder("BlockTransparency").withMinimum(0).withValue(44).withMaximum(255).withVisibility(v -> p.getValue().equals(Page.TWO) && customColours.getValue()).build()); - private Setting aTracer = register(Settings.integerBuilder("TracerTransparency").withMinimum(0).withValue(200).withMaximum(255).withVisibility(v -> p.getValue().equals(Page.TWO) && customColours.getValue()).build()); - private Setting r = register(Settings.integerBuilder("Red").withMinimum(0).withValue(155).withMaximum(255).withVisibility(v -> p.getValue().equals(Page.TWO) && customColours.getValue()).build()); - private Setting g = register(Settings.integerBuilder("Green").withMinimum(0).withValue(144).withMaximum(255).withVisibility(v -> p.getValue().equals(Page.TWO) && customColours.getValue()).build()); - private Setting b = register(Settings.integerBuilder("Blue").withMinimum(0).withValue(255).withMaximum(255).withVisibility(v -> p.getValue().equals(Page.TWO) && customColours.getValue()).build()); - private Setting statusMessages = register(Settings.booleanBuilder("StatusMessages").withValue(false).withVisibility(v -> p.getValue().equals(Page.TWO)).build()); - - private enum ExplodeBehavior {HOLE_ONLY, PREVENT_SUICIDE, LEFT_CLICK_ONLY, ALWAYS} - - private enum PlaceBehavior {MULTI, TRADITIONAL} - - private enum Page {ONE, TWO} - - private BlockPos render; - private Entity renderEnt; - private long systemTime = -1; - // we need this cooldown to not place from old hotbar slot, before we have switched to crystals - private boolean switchCoolDown = false; - private boolean isAttacking = false; - private int oldSlot = -1; - - public static CrystalAura INSTANCE; - private static EntityEnderCrystal lastCrystal; - private static List ignoredCrystals = new ArrayList<>(); - private static int hitTries = 0; - private static boolean togglePitch = false; - - public CrystalAura() { - super(); - - defaultSetting.settingListener = setting -> { - if (defaultSetting.getValue()) defaults(); - }; - INSTANCE = this; - } - - public void onUpdate() { - if (mc.player == null) { - resetHitAttempts(); - return; - } - - resetHitAttempts(hitAttempts.getValue() == -1); - - int holeBlocks = 0; - - Vec3d[] holeOffset = { - mc.player.getPositionVector().add(1, 0, 0), - mc.player.getPositionVector().add(-1, 0, 0), - mc.player.getPositionVector().add(0, 0, 1), - mc.player.getPositionVector().add(0, 0, -1), - mc.player.getPositionVector().add(0, -1, 0) - }; - - EntityEnderCrystal crystal = mc.world.loadedEntityList.stream() - .filter(entity -> entity instanceof EntityEnderCrystal) - .filter(entity -> !ignored(entity)) - .map(entity -> (EntityEnderCrystal) entity) - .min(Comparator.comparing(c -> mc.player.getDistance(c))) - .orElse(null); - - - if (explode.getValue() && crystal != null && mc.player.getDistance(crystal) <= range.getValue() && passSwordCheck()) { - // Added delay to stop ncp from flagging "hitting too fast" - if (((System.nanoTime() / 1000000f) - systemTime) >= 25 * getDelay()) { - if (antiWeakness.getValue() && mc.player.isPotionActive(MobEffects.WEAKNESS)) { - if (!isAttacking) { - // save initial player hand - oldSlot = mc.player.inventory.currentItem; - isAttacking = true; - } - // search for sword and tools in hotbar - int newSlot = -1; - for (int i = 0; i < 9; i++) { - ItemStack stack = mc.player.inventory.getStackInSlot(i); - if (stack == ItemStack.EMPTY) { - continue; - } - if ((stack.getItem() instanceof ItemSword)) { - newSlot = i; - break; - } - if ((stack.getItem() instanceof ItemTool)) { - newSlot = i; - break; - } - } - // check if any swords or tools were found - if (newSlot != -1) { - mc.player.inventory.currentItem = newSlot; - switchCoolDown = true; - } - } - if (placePriority.getValue()) { - boolean wasPlacing = place.getValue(); - if (mc.gameSettings.keyBindUseItem.isKeyDown() && place.getValue()) { - place.setValue(false); - explode(crystal); - } - if (!place.getValue() && wasPlacing) place.setValue(true); - } - if (explodeBehavior.getValue() == ExplodeBehavior.ALWAYS) { - explode(crystal); - } - for (Vec3d vecOffset : holeOffset) { /* for placeholder offset for each BlockPos in the list holeOffset */ - BlockPos offset = new BlockPos(vecOffset.x, vecOffset.y, vecOffset.z); - if (mc.world.getBlockState(offset).getBlock() == Blocks.OBSIDIAN || mc.world.getBlockState(offset).getBlock() == Blocks.BEDROCK) { - holeBlocks++; - } - } - if (explodeBehavior.getValue() == ExplodeBehavior.HOLE_ONLY) { - if (holeBlocks == 5) { - explode(crystal); - } - } - if (explodeBehavior.getValue() == ExplodeBehavior.PREVENT_SUICIDE) { - if (mc.player.getPositionVector().distanceTo(crystal.getPositionVector()) <= 0.5 && mc.player.getPosition().getY() == crystal.getPosition().getY() || mc.player.getPositionVector().distanceTo(crystal.getPositionVector()) >= 2.3 && mc.player.getPosition().getY() == crystal.getPosition().getY() || mc.player.getPositionVector().distanceTo(crystal.getPositionVector()) >= 0.5 && mc.player.getPosition().getY() != crystal.getPosition().getY()) { - explode(crystal); - } - } - if (explodeBehavior.getValue() == ExplodeBehavior.LEFT_CLICK_ONLY && mc.gameSettings.keyBindAttack.isKeyDown()) { - explode(crystal); - } - if (sneakEnable.getValue() && mc.player.isSneaking() && holeBlocks != 5) { - Surround.INSTANCE.enable(); - } - return; - } - - } else { - resetRotation(); - if (oldSlot != -1) { - mc.player.inventory.currentItem = oldSlot; - oldSlot = -1; - } - isAttacking = false; - } - - int crystalSlot = mc.player.getHeldItemMainhand().getItem() == Items.END_CRYSTAL ? mc.player.inventory.currentItem : -1; - if (crystalSlot == -1) { - for (int l = 0; l < 9; ++l) { - if (mc.player.inventory.getStackInSlot(l).getItem() == Items.END_CRYSTAL) { - crystalSlot = l; - break; - } - } - } - - boolean offhand = false; - if (mc.player.getHeldItemOffhand().getItem() == Items.END_CRYSTAL) { - offhand = true; - } else if (crystalSlot == -1) { - return; - } - - List blocks = findCrystalBlocks(); - List entities = new ArrayList<>(); - if (players.getValue()) { - entities.addAll(mc.world.playerEntities.stream().filter(entityPlayer -> !Friends.isFriend(entityPlayer.getName())).collect(Collectors.toList())); - } - entities.addAll(mc.world.loadedEntityList.stream().filter(entity -> EntityUtils.isLiving(entity) && (EntityUtils.mobTypeSettings(entity, mobs.getValue(), passive.getValue(), neutral.getValue(), hostile.getValue()))).collect(Collectors.toList())); - - BlockPos q = null; - double damage = .5; - for (Entity entity : entities) { - // stop if the entities health is 0 or less then 0 (somehow) or if the entity is you, don't do excess calculation if multiplace is enabled - if (entity == mc.player || ((EntityLivingBase) entity).getHealth() <= 0 || placeBehavior.getValue() == PlaceBehavior.MULTI) { - continue; - } - for (BlockPos blockPos : blocks) { - double b = entity.getDistanceSq(blockPos); - if (b >= 169) { - continue; // If this block if further than 13 (3.6^2, less calc) blocks, ignore it. It'll take no or very little damage - } - double d = calculateDamage(blockPos.x + .5, blockPos.y + 1, blockPos.z + .5, entity); - if (d > damage) { - double self = calculateDamage(blockPos.x + .5, blockPos.y + 1, blockPos.z + .5, mc.player); - // Factor in absorption if wanted - float enemyAbsorption = 0.0f; - float playerAbsorption = 0.0f; - if (checkAbsorption.getValue()) { - enemyAbsorption = ((EntityLivingBase) entity).getAbsorptionAmount(); - playerAbsorption = mc.player.getAbsorptionAmount(); - } - // If this deals more damage to ourselves than it does to our target, continue. This is only ignored if the crystal is sure to kill our target but not us. - // Also continue if our crystal is going to hurt us.. alot - if ((self > d && !(d < ((EntityLivingBase) entity).getHealth() + enemyAbsorption)) || self - .5 > mc.player.getHealth() + playerAbsorption) { - continue; - } - damage = d; - q = blockPos; - renderEnt = entity; - PlayerModel.INSTANCE.setLastAttacked(System.currentTimeMillis()); - mc.player.setLastAttackedEntity(entity); - } - } - } - - if (place.getValue() && placeBehavior.getValue() == PlaceBehavior.MULTI) { - for (Entity entity : entities) { - - if (entity == mc.player || ((EntityLivingBase) entity).getHealth() <= 0) { - continue; - } - for (BlockPos blockPos : blocks) { - double b = entity.getDistanceSq(blockPos); - if (b > 75) { - continue; - } - double d = calculateDamage(blockPos.x + .5, blockPos.y + 1, blockPos.z + .5, entity); - double self = calculateDamage(blockPos.x + .5, blockPos.y + 1, blockPos.z + .5, mc.player); - if (self >= mc.player.getHealth() + mc.player.getAbsorptionAmount() || self > d) continue; - if (b < 10 && d >= 15 || d >= ((EntityLivingBase) entity).getHealth() + ((EntityLivingBase) entity).getAbsorptionAmount() || 6 >= ((EntityLivingBase) entity).getHealth() + ((EntityLivingBase) entity).getAbsorptionAmount() && b < 4 || b < 9 && d >= minDmg.getValue() && minDmg.getValue() > 0.0) { - q = blockPos; - damage = d; - renderEnt = entity; - PlayerModel.INSTANCE.setLastAttacked(System.currentTimeMillis()); - mc.player.setLastAttackedEntity(entity); - } - } - } - } - if (damage == .5) { - render = null; - renderEnt = null; - resetRotation(); - return; - } - // this sends a constant packet flow for default packets - if (place.getValue()) { - render = q; - if (!offhand && mc.player.inventory.currentItem != crystalSlot) { - if (autoSwitch.getValue()) { - mc.player.inventory.currentItem = crystalSlot; - resetRotation(); - switchCoolDown = true; - } - return; - } - lookAtPacket(new Vec3d(q.x + .5, q.y - .5, q.z + .5)); - RayTraceResult result = mc.world.rayTraceBlocks(new Vec3d(mc.player.posX, mc.player.posY + mc.player.getEyeHeight(), mc.player.posZ), new Vec3d(q.x + .5, q.y - .5d, q.z + .5)); - EnumFacing f; - if (result == null || result.sideHit == null) { - f = EnumFacing.UP; - } else { - f = result.sideHit; - } - // return after we did an autoswitch - if (switchCoolDown) { - switchCoolDown = false; - return; - } - //mc.playerController.processRightClickBlock(mc.player, mc.world, q, f, new Vec3d(0, 0, 0), EnumHand.MAIN_HAND); - mc.player.connection.sendPacket(new CPacketPlayerTryUseItemOnBlock(q, f, offhand ? EnumHand.OFF_HAND : EnumHand.MAIN_HAND, 0, 0, 0)); - } - if (isSpoofingAngles) { - if (togglePitch) { - mc.player.rotationPitch += 0.0004; - togglePitch = false; - } else { - mc.player.rotationPitch -= 0.0004; - togglePitch = true; - } - } - } - - @Override - public void onWorldRender(RenderEvent event) { - if (render != null) { - int tracerAlpha = 0; - if (tracer.getValue()) { - tracerAlpha = aTracer.getValue(); - } - ColorHolder colour = new ColorHolder(255, 255, 255); - if (customColours.getValue()) { - colour = new ColorHolder(r.getValue(), g.getValue(), b.getValue()); - } - ESPRenderer renderer = new ESPRenderer(); - renderer.setAFilled(aBlock.getValue()); - renderer.setATracer(tracerAlpha); - renderer.add(render, colour); - renderer.render(true); - } - } - - private void lookAtPacket(Vec3d pos) { - Vec2d lookAt = getRotationTo(pos, true); - setYawAndPitch((float) lookAt.getX(), (float) lookAt.getY()); - } - - private boolean canPlaceCrystal(BlockPos blockPos) { - BlockPos boost = blockPos.add(0, 1, 0); - BlockPos boost2 = blockPos.add(0, 2, 0); - return (mc.world.getBlockState(blockPos).getBlock() == Blocks.BEDROCK - || mc.world.getBlockState(blockPos).getBlock() == Blocks.OBSIDIAN) - && mc.world.getBlockState(boost).getBlock() == Blocks.AIR - && mc.world.getBlockState(boost2).getBlock() == Blocks.AIR - && mc.world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(boost)).isEmpty() - && mc.world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(boost2)).isEmpty(); - } - - public static BlockPos getPlayerPos() { - return new BlockPos(Math.floor(mc.player.posX), Math.floor(mc.player.posY), Math.floor(mc.player.posZ)); - } - - private List findCrystalBlocks() { - NonNullList positions = NonNullList.create(); - positions.addAll(getSphere(getPlayerPos(), range.getValue().floatValue(), range.getValue().intValue(), false, true, 0).stream().filter(this::canPlaceCrystal).collect(Collectors.toList())); - return positions; - } - - public List getSphere(BlockPos loc, float r, int h, boolean hollow, boolean sphere, int plus_y) { - List circleblocks = new ArrayList<>(); - int cx = loc.getX(); - int cy = loc.getY(); - int cz = loc.getZ(); - for (int x = cx - (int) r; x <= cx + r; x++) { - for (int z = cz - (int) r; z <= cz + r; z++) { - for (int y = (sphere ? cy - (int) r : cy); y < (sphere ? cy + r : cy + h); y++) { - double dist = (cx - x) * (cx - x) + (cz - z) * (cz - z) + (sphere ? (cy - y) * (cy - y) : 0); - if (dist < r * r && !(hollow && dist < (r - 1) * (r - 1))) { - BlockPos l = new BlockPos(x, y + plus_y, z); - circleblocks.add(l); - } - } - } - } - return circleblocks; - } - - public static float calculateDamage(double posX, double posY, double posZ, Entity entity) { - float doubleExplosionSize = 6.0F * 2.0F; - double distancedSize = entity.getDistance(posX, posY, posZ) / (double) doubleExplosionSize; - Vec3d vec3d = new Vec3d(posX, posY, posZ); - double blockDensity = entity.world.getBlockDensity(vec3d, entity.getEntityBoundingBox()); - double v = (1.0D - distancedSize) * blockDensity; - float damage = (float) ((int) ((v * v + v) / 2.0D * 7.0D * (double) doubleExplosionSize + 1.0D)); - double finalD = 1; - /*if (entity instanceof EntityLivingBase) - finalD = getBlastReduction((EntityLivingBase) entity,getDamageMultiplied(damage));*/ - if (entity instanceof EntityLivingBase) { - finalD = getBlastReduction((EntityLivingBase) entity, getDamageMultiplied(damage), new Explosion(mc.world, null, posX, posY, posZ, 6F, false, true)); - } - return (float) finalD; - } - - public static float getBlastReduction(EntityLivingBase entity, float damage, Explosion explosion) { - if (entity instanceof EntityPlayer) { - EntityPlayer ep = (EntityPlayer) entity; - DamageSource ds = DamageSource.causeExplosionDamage(explosion); - damage = CombatRules.getDamageAfterAbsorb(damage, (float) ep.getTotalArmorValue(), (float) ep.getEntityAttribute(SharedMonsterAttributes.ARMOR_TOUGHNESS).getAttributeValue()); - - int k = EnchantmentHelper.getEnchantmentModifierDamage(ep.getArmorInventoryList(), ds); - float f = MathHelper.clamp(k, 0.0F, 20.0F); - damage = damage * (1.0F - f / 25.0F); - - if (entity.isPotionActive(Objects.requireNonNull(Potion.getPotionById(11)))) { - damage = damage - (damage / 5); - } - - damage = Math.max(damage, 0.0F); - return damage; - } - damage = CombatRules.getDamageAfterAbsorb(damage, (float) entity.getTotalArmorValue(), (float) entity.getEntityAttribute(SharedMonsterAttributes.ARMOR_TOUGHNESS).getAttributeValue()); - return damage; - } - - private static float getDamageMultiplied(float damage) { - int diff = mc.world.getDifficulty().getId(); - return damage * (diff == 0 ? 0 : (diff == 2 ? 1 : (diff == 1 ? 0.5f : 1.5f))); - } - - public static float calculateDamage(EntityEnderCrystal crystal, Entity entity) { - return calculateDamage(crystal.posX, crystal.posY, crystal.posZ, entity); - } - - - //Better Rotation Spoofing System: - - private static boolean isSpoofingAngles; - private static double yaw; - private static double pitch; - - //this modifies packets being sent so no extra ones are made. NCP used to flag with "too many packets" - private static void setYawAndPitch(float yaw1, float pitch1) { - yaw = yaw1; - pitch = pitch1; - isSpoofingAngles = true; - } - - private static void resetRotation() { - if (isSpoofingAngles) { - yaw = mc.player.rotationYaw; - pitch = mc.player.rotationPitch; - isSpoofingAngles = false; - } - } - - - @EventHandler - private Listener cPacketListener = new Listener<>(event -> { - Packet packet = event.getPacket(); - if (packet instanceof CPacketPlayer) { - if (isSpoofingAngles) { - ((CPacketPlayer) packet).yaw = (float) yaw; - ((CPacketPlayer) packet).pitch = (float) pitch; - } - } - }); - - public void onEnable() { - sendMessage("&aENABLED&r"); - } - - public void onDisable() { - sendMessage("&cDISABLED&r"); - render = null; - renderEnt = null; - resetRotation(); - } - - public void explode(EntityEnderCrystal crystal) { - if (crystal == null) return; - - if (lastCrystal == crystal) hitTries++; - else { - lastCrystal = crystal; - hitTries = 0; - } - - try { - if (hitAttempts.getValue() != -1 && hitTries > hitAttempts.getValue()) { - ignoredCrystals.add(crystal); - hitTries = 0; - } else { - lookAtPacket(crystal.getPositionVector()); - mc.playerController.attackEntity(mc.player, crystal); - mc.player.swingArm(EnumHand.MAIN_HAND); - } - } catch (Throwable ignored) { - } - - systemTime = System.nanoTime() / 1000000L; - } - - private boolean passSwordCheck() { - if (!noToolExplode.getValue() || antiWeakness.getValue()) return true; - else - return !noToolExplode.getValue() || (!(mc.player.getHeldItemMainhand().getItem() instanceof ItemTool) && !(mc.player.getHeldItemMainhand().getItem() instanceof ItemSword)); - } - - @Override - public String getHudInfo() { - return "" + InventoryUtils.countItemAll(426); - } - - private boolean ignored(Entity e) { - if (ignoredCrystals == null) return false; - for (EntityEnderCrystal c : ignoredCrystals) if (e != null && e == c) return true; - return false; - } - - private void resetHitAttempts() { - sendMessage("&l&9Reset&r&9 hit attempts crystals"); - lastCrystal = null; - ignoredCrystals = null; - hitTries = 0; - } - - private void resetHitAttempts(boolean should) { - if (should) { - lastCrystal = null; - ignoredCrystals = null; - hitTries = 0; - } else if (resetTime()) { - sendMessage("&l&9Reset&r&9 hit attempts crystals"); - lastCrystal = null; - ignoredCrystals = null; - hitTries = 0; - } - } - - private static long startTime = 0; - - private boolean resetTime() { - if (startTime == 0) startTime = System.currentTimeMillis(); - if (startTime + 900000 <= System.currentTimeMillis()) { // 15 minutes in milliseconds - startTime = System.currentTimeMillis(); - return true; - } - return false; - } - - private void sendMessage(String message) { - if (statusMessages.getValue()) { - sendChatMessage(getChatName() + " " + message); - } - } - - private double getDelay() { - if (!autoDelay.getValue()) { - return delay.getValue(); - } - int ping = InfoCalculator.ping(); - return 2 * ping * (InfoCalculator.tps(2) / 20) + (ping / 10.0); - } - - private void defaults() { - explodeBehavior.setValue(ExplodeBehavior.ALWAYS); - placeBehavior.setValue(PlaceBehavior.TRADITIONAL); - autoSwitch.setValue(true); - place.setValue(false); - explode.setValue(false); - checkAbsorption.setValue(true); - range.setValue(4.0); - delay.setValue(5.0); - hitAttempts.setValue(-1); - minDmg.setValue(0.0); - sneakEnable.setValue(true); - placePriority.setValue(false); - - antiWeakness.setValue(false); - noToolExplode.setValue(true); - players.setValue(true); - mobs.setValue(false); - tracer.setValue(true); - customColours.setValue(true); - aBlock.setValue(44); - aTracer.setValue(200); - r.setValue(155); - g.setValue(144); - b.setValue(255); - statusMessages.setValue(false); - - defaultSetting.setValue(false); - sendChatMessage(getChatName() + " Set to defaults!"); - } -} diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/CrystalAura.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/CrystalAura.kt new file mode 100644 index 000000000..f807278a9 --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/CrystalAura.kt @@ -0,0 +1,376 @@ +package me.zeroeightsix.kami.module.modules.combat + +import me.zero.alpine.listener.EventHandler +import me.zero.alpine.listener.EventHook +import me.zero.alpine.listener.Listener +import me.zeroeightsix.kami.event.KamiEvent +import me.zeroeightsix.kami.event.events.OnUpdateWalkingPlayerEvent +import me.zeroeightsix.kami.event.events.PacketEvent +import me.zeroeightsix.kami.manager.mangers.CombatManager +import me.zeroeightsix.kami.manager.mangers.PlayerPacketManager +import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.setting.Settings +import me.zeroeightsix.kami.util.BlockUtils +import me.zeroeightsix.kami.util.EntityUtils +import me.zeroeightsix.kami.util.InfoCalculator +import me.zeroeightsix.kami.util.InventoryUtils +import me.zeroeightsix.kami.util.combat.CombatUtils +import me.zeroeightsix.kami.util.combat.CrystalUtils +import me.zeroeightsix.kami.util.math.RotationUtils +import me.zeroeightsix.kami.util.math.Vec2f +import net.minecraft.entity.item.EntityEnderCrystal +import net.minecraft.init.Items +import net.minecraft.init.MobEffects +import net.minecraft.init.SoundEvents +import net.minecraft.item.ItemSword +import net.minecraft.item.ItemTool +import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock +import net.minecraft.network.play.client.CPacketUseEntity +import net.minecraft.network.play.server.SPacketSoundEffect +import net.minecraft.util.EnumHand +import net.minecraft.util.SoundCategory +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d +import java.util.* +import kotlin.collections.HashSet +import kotlin.math.abs +import kotlin.math.ceil +import kotlin.math.max + +@Module.Info( + name = "CrystalAura", + description = "Places End Crystals to kill enemies", + category = Module.Category.COMBAT, + modulePriority = 80 +) +object CrystalAura : Module() { + /* Settings */ + private val page = register(Settings.e("Page", Page.GENERAL)) + + /* General */ + private val facePlaceThreshold = register(Settings.floatBuilder("FacePlace").withValue(5.0f).withRange(0.0f, 20.0f).withVisibility { page.value == Page.GENERAL }) + private val noSuicideThreshold = register(Settings.floatBuilder("NoSuicide").withValue(5.0f).withRange(0.0f, 20.0f).withVisibility { page.value == Page.GENERAL }) + private val maxYawRate = register(Settings.integerBuilder("MaxYawRate").withValue(50).withRange(10, 100).withVisibility { page.value == Page.GENERAL }) + private val motionPrediction = register(Settings.booleanBuilder("MotionPrediction").withValue(true).withVisibility { page.value == Page.GENERAL }) + private val pingSync = register(Settings.booleanBuilder("PingSync").withValue(true).withVisibility { page.value == Page.GENERAL && motionPrediction.value }) + private val ticksAhead = register(Settings.integerBuilder("TicksAhead").withValue(5).withRange(0, 20).withVisibility { page.value == Page.GENERAL && motionPrediction.value && !pingSync.value }) + + /* Place page one */ + private val doPlace = register(Settings.booleanBuilder("Place").withValue(true).withVisibility { page.value == Page.PLACE_ONE }) + private val forcePlace = register(Settings.booleanBuilder("RightClickForcePlace").withValue(false).withVisibility { page.value == Page.PLACE_ONE }) + private val autoSwap = register(Settings.booleanBuilder("AutoSwap").withValue(true).withVisibility { page.value == Page.PLACE_ONE }) + private val spoofHotbar = register(Settings.booleanBuilder("SpoofHotbar").withValue(true).withVisibility { page.value == Page.PLACE_ONE && autoSwap.value }) + private val placeSwing = register(Settings.booleanBuilder("PlaceSwing").withValue(false).withVisibility { page.value == Page.PLACE_ONE }) + + /* Place page two */ + private val minDamageP = register(Settings.integerBuilder("MinDamagePlace").withValue(4).withRange(0, 20).withVisibility { page.value == Page.PLACE_TWO }) + private val maxSelfDamageP = register(Settings.integerBuilder("MaxSelfDamagePlace").withValue(4).withRange(0, 20).withVisibility { page.value == Page.PLACE_TWO }) + private val placeOffset = register(Settings.floatBuilder("PlaceOffset").withValue(1.0f).withRange(0f, 1f).withStep(0.05f).withVisibility { page.value == Page.PLACE_TWO }) + private val maxCrystal = register(Settings.integerBuilder("MaxCrystal").withValue(2).withRange(1, 5).withVisibility { page.value == Page.PLACE_TWO }) + private val placeDelay = register(Settings.integerBuilder("PlaceDelay").withValue(1).withRange(1, 10).withVisibility { page.value == Page.PLACE_TWO }) + private val placeRange = register(Settings.floatBuilder("PlaceRange").withValue(4.0f).withRange(0.0f, 5.0f).withVisibility { page.value == Page.PLACE_TWO }) + private val wallPlaceRange = register(Settings.floatBuilder("WallPlaceRange").withValue(2.0f).withRange(0.0f, 5.0f).withVisibility { page.value == Page.PLACE_TWO }) + + /* Explode page one */ + private val doExplode = register(Settings.booleanBuilder("Explode").withValue(true).withVisibility { page.value == Page.EXPLODE_ONE }) + private val forceExplode = register(Settings.booleanBuilder("LeftClickForceExplode").withValue(false).withVisibility { page.value == Page.EXPLODE_ONE }) + private val autoForceExplode = register(Settings.booleanBuilder("AutoForceExplode").withValue(true).withVisibility { page.value == Page.EXPLODE_ONE }) + private val antiWeakness = register(Settings.booleanBuilder("AntiWeakness").withValue(true).withVisibility { page.value == Page.EXPLODE_ONE }) + + /* Explode page two */ + private val checkDamage = register(Settings.booleanBuilder("CheckDamage").withValue(true).withVisibility { page.value == Page.EXPLODE_TWO }) + private val minDamageE = register(Settings.integerBuilder("MinDamageExplode").withValue(8).withRange(0, 20).withVisibility { page.value == Page.EXPLODE_TWO && checkDamage.value }) + private val maxSelfDamageE = register(Settings.integerBuilder("MaxSelfDamageExplode").withValue(6).withRange(0, 20).withVisibility { page.value == Page.EXPLODE_TWO && checkDamage.value }) + private val hitDelay = register(Settings.integerBuilder("HitDelay").withValue(2).withRange(1, 10).withVisibility { page.value == Page.EXPLODE_TWO }) + private val hitAttempts = register(Settings.integerBuilder("HitAttempts").withValue(2).withRange(0, 5).withVisibility { page.value == Page.EXPLODE_TWO }) + private val explodeRange = register(Settings.floatBuilder("ExplodeRange").withValue(4.0f).withRange(0.0f, 5.0f).withVisibility { page.value == Page.EXPLODE_TWO }) + private val wallExplodeRange = register(Settings.floatBuilder("WallExplodeRange").withValue(2.0f).withRange(0.0f, 5.0f).withVisibility { page.value == Page.EXPLODE_TWO }) + /* End of settings */ + + private enum class Page { + GENERAL, PLACE_ONE, PLACE_TWO, EXPLODE_ONE, EXPLODE_TWO + } + + /* Variables */ + private val placeMap = TreeMap(Comparator.reverseOrder()) + private val crystalList = HashSet() + private val ignoredList = HashSet() + private var lastCrystal: EntityEnderCrystal? = null + private var lastLookAt = Vec3d.ZERO + private var targetPosition = Vec3d.ZERO + private var placeTimer = 0 + private var hitTimer = 0 + private var hitCount = 0 + private var inactiveTicks = 30 + + override fun isActive(): Boolean { + return isEnabled && InventoryUtils.countItemAll(426) > 0 && inactiveTicks <= 20 + } + + override fun onEnable() { + if (mc.player == null) disable() + else resetRotation() + } + + override fun onDisable() { + placeMap.clear() + crystalList.clear() + ignoredList.clear() + lastCrystal = null + lastLookAt = Vec3d.ZERO + targetPosition = Vec3d.ZERO + placeTimer = 0 + hitTimer = 0 + hitCount = 0 + inactiveTicks = 30 + PlayerPacketManager.resetHotbar() + } + + // Minecraft sends sounds packets a tick before removing the crystal lol + @EventHandler + private val receiveListener = Listener(EventHook { event: PacketEvent.Receive -> + if (!CombatManager.isOnTopPriority(this) || mc.player == null || event.packet !is SPacketSoundEffect) return@EventHook + if (event.packet.getCategory() == SoundCategory.BLOCKS && event.packet.getSound() == SoundEvents.ENTITY_GENERIC_EXPLODE) { + val crystalList = CrystalUtils.getCrystalList(Vec3d(event.packet.x, event.packet.y, event.packet.z), 5f) + for (crystal in crystalList) { + crystal.setDead() + mc.world.removeEntityFromWorld(crystal.entityId) + } + ignoredList.clear() + hitCount = 0 + } + }) + + @EventHandler + private val onUpdateWalkingPlayerListener = Listener(EventHook { event: OnUpdateWalkingPlayerEvent -> + if (inactiveTicks > 20 || event.era != KamiEvent.Era.PRE || lastLookAt == Vec3d.ZERO || CombatSetting.pause) return@EventHook + val packet = PlayerPacketManager.PlayerPacket(rotating = true, rotation = Vec2f(getLastRotation())) + PlayerPacketManager.addPacket(this, packet) + }) + + override fun onUpdate() { + if (!CombatManager.isOnTopPriority(this) || CombatSetting.pause) return + inactiveTicks++ + hitTimer++ + placeTimer++ + + updateMap() + if (canExplode()) explode() else if (canPlace()) place() + if (inactiveTicks > 5 || getHand() == EnumHand.OFF_HAND) PlayerPacketManager.resetHotbar() + if (inactiveTicks > 20) resetRotation() + } + + private fun updateMap() { + setPosition() + placeMap.clear() + placeMap.putAll(CrystalUtils.getPlacePos(CombatManager.target, mc.player, placeRange.value + 1f)) + resetPosition() + + crystalList.clear() + crystalList.addAll(CrystalUtils.getCrystalList(max(placeRange.value, explodeRange.value))) + + if (inactiveTicks > 10 && getExplodingCrystal() == null && ignoredList.isNotEmpty()) { + ignoredList.clear() + hitCount = 0 + } + } + + private fun place() { + if (autoSwap.value && getHand() == null) { + InventoryUtils.getSlotsHotbar(426)?.get(0)?.let { + if (spoofHotbar.value) PlayerPacketManager.spoofHotbar(it) + else InventoryUtils.swapSlot(it) + } + } + getPlacingPos()?.let { pos -> + getHand()?.let { hand -> + placeTimer = 0 + inactiveTicks = 0 + lastLookAt = Vec3d(pos).add(0.5, placeOffset.value.toDouble(), 0.5) + mc.player.connection.sendPacket(CPacketPlayerTryUseItemOnBlock(pos, BlockUtils.getHitSide(pos), hand, 0.5f, placeOffset.value, 0.5f)) + if (placeSwing.value) mc.player.swingArm(hand) + } + } + } + + private fun explode() { + if (antiWeakness.value && mc.player.isPotionActive(MobEffects.WEAKNESS) && !isHoldingTool()) { + CombatUtils.equipBestWeapon() + PlayerPacketManager.resetHotbar() + } + getExplodingCrystal()?.let { + hitTimer = 0 + inactiveTicks = 0 + lastLookAt = it.positionVector + + if (hitAttempts.value != 0 && it == lastCrystal) { + hitCount++ + if (hitCount >= hitAttempts.value) ignoredList.add(it) + } else { + hitCount = 0 + } + mc.connection!!.sendPacket(CPacketUseEntity(it)) + mc.player.swingArm(getHand() ?: EnumHand.OFF_HAND) + mc.player.setLastAttackedEntity(CombatManager.target!!) + lastCrystal = it + } + } + /* End of main functions */ + + /* Placing */ + private fun canPlace(): Boolean { + return doPlace.value + && placeTimer >= placeDelay.value + && InventoryUtils.countItemAll(426) > 0 + && getPlacingPos() != null + && countValidCrystal() < maxCrystal.value + } + + @Suppress("UnconditionalJumpStatementInLoop") // The linter is wrong here, it will continue until it's supposed to return + private fun getPlacingPos(): BlockPos? { + if (placeMap.isEmpty()) return null + for ((damage, pos) in placeMap) { + val hitVec = Vec3d(pos).add(0.5, 1.0, 0.5) + val dist = mc.player.getDistance(hitVec.x, hitVec.y, hitVec.z) + if (dist > placeRange.value) continue + if (!CrystalUtils.canPlaceCollide(pos)) continue + if (BlockUtils.rayTraceTo(pos) == null && dist > wallPlaceRange.value) continue + if (!shouldForcePlace()) { + val rotation = RotationUtils.getRotationTo(hitVec, true) + if (abs(rotation.x - getLastRotation().x) > maxYawRate.value + (inactiveTicks * 10f)) continue + val selfDamage = CrystalUtils.calcDamage(pos, mc.player) + if (!noSuicideCheck(selfDamage)) continue + if (!checkDamagePlace(damage, selfDamage)) continue + } + return pos + } + return null + } + + private fun shouldForcePlace(): Boolean { + return forcePlace.value && mc.gameSettings.keyBindUseItem.isKeyDown + && mc.player.heldItemMainhand.getItem() == Items.END_CRYSTAL + } + + /** + * @return True if passed placing damage check + */ + private fun checkDamagePlace(damage: Float, selfDamage: Float): Boolean { + return (damage >= minDamageP.value || shouldFacePlace()) && (selfDamage <= maxSelfDamageP.value) + } + /* End of placing */ + + /* Exploding */ + private fun canExplode(): Boolean { + return doExplode.value + && hitTimer >= hitDelay.value + && getExplodingCrystal() != null + && CombatManager.target?.let { target -> + if (checkDamage.value && !shouldForceExplode()) { + var maxDamage = 0f + var maxSelfDamage = 0f + setPosition() + for (crystal in crystalList) { + maxDamage = max(maxDamage, CrystalUtils.calcDamage(crystal, target)) + maxSelfDamage = max(maxSelfDamage, CrystalUtils.calcDamage(crystal, mc.player)) + } + resetPosition() + if (!noSuicideCheck(maxSelfDamage)) return false + if (!checkDamageExplode(maxDamage, maxSelfDamage)) return false + } + return true + } ?: false + } + + private fun getExplodingCrystal(): EntityEnderCrystal? { + if (crystalList.isEmpty()) return null + return crystalList.firstOrNull { + !ignoredList.contains(it) + && (mc.player.canEntityBeSeen(it) || EntityUtils.canEntityFeetBeSeen(it)) + && it.getDistance(mc.player) < explodeRange.value + && abs(RotationUtils.getRotationToEntity(it).x - getLastRotation().x) <= maxYawRate.value + (inactiveTicks * 10f) + } ?: crystalList.firstOrNull { + !ignoredList.contains(it) + && EntityUtils.canEntityHitboxBeSeen(it) != null + && it.getDistance(mc.player) < wallExplodeRange.value + } + } + + private fun shouldForceExplode(): Boolean { + return (autoForceExplode.value && placeMap.isNotEmpty() && placeMap.firstKey() > minDamageE.value) + || (forceExplode.value && mc.gameSettings.keyBindAttack.isKeyDown + && mc.player.heldItemMainhand.getItem() != Items.DIAMOND_PICKAXE + && mc.player.heldItemMainhand.getItem() != Items.GOLDEN_APPLE) + } + + private fun checkDamageExplode(damage: Float, selfDamage: Float): Boolean { + return (damage >= minDamageE.value || shouldFacePlace()) && (selfDamage <= maxSelfDamageE.value) + } + /* End of exploding */ + + /* General */ + private fun getHand(): EnumHand? { + val serverSideItem = if (spoofHotbar.value) mc.player.inventory.getStackInSlot(PlayerPacketManager.serverSideHotbar).getItem() else null + return when (Items.END_CRYSTAL) { + mc.player.heldItemOffhand.getItem() -> EnumHand.OFF_HAND + mc.player.heldItemMainhand.getItem() -> EnumHand.MAIN_HAND + serverSideItem -> EnumHand.MAIN_HAND + else -> null + } + } + + private fun noSuicideCheck(selfDamage: Float) = mc.player.health - selfDamage > noSuicideThreshold.value + + private fun isHoldingTool(): Boolean { + val item = mc.player.heldItemMainhand.getItem() + return item is ItemTool || item is ItemSword + } + + private fun shouldFacePlace() = facePlaceThreshold.value > 0f && CombatManager.target?.let { it.health <= facePlaceThreshold.value } ?: false + + private fun countValidCrystal(): Int { + var count = 0 + CombatManager.target?.let { target -> + setPosition() + for (crystal in crystalList) { + if (ignoredList.contains(crystal)) continue + if (crystal.getDistance(mc.player) > placeRange.value) continue + val rotation = RotationUtils.getRotationToEntity(crystal) + if (abs(rotation.x - getLastRotation().x) > maxYawRate.value) continue + val damage = CrystalUtils.calcDamage(crystal, target) + val selfDamage = CrystalUtils.calcDamage(crystal, mc.player) + if (!checkDamagePlace(damage, selfDamage)) continue + count++ + } + resetPosition() + } + return count + } + /* End of general */ + + /* Motion prediction */ + private fun setPosition() { + if (!motionPrediction.value) return + val ticks = if (pingSync.value) ceil(InfoCalculator.ping() / 25f).toInt() else ticksAhead.value + val posAhead = CombatManager.motionTracker.calcPositionAhead(ticks, true) ?: return + CombatManager.target?.let { + targetPosition = it.positionVector + it.setPosition(posAhead.x, posAhead.y, posAhead.z) + } + } + + private fun resetPosition() { + if (!motionPrediction.value) return + if (targetPosition == Vec3d.ZERO) return + CombatManager.target?.setPosition(targetPosition.x, targetPosition.y, targetPosition.z) + } + /* End of Motion prediction */ + + /* Rotation spoofing */ + private fun getLastRotation() = RotationUtils.getRotationTo(lastLookAt, true) + + private fun resetRotation() { + lastLookAt = CombatManager.target?.positionVector ?: Vec3d.ZERO + } + /* End of rotation spoofing */ +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/CrystalESP.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/CrystalESP.kt new file mode 100644 index 000000000..c13e41f69 --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/CrystalESP.kt @@ -0,0 +1,187 @@ +package me.zeroeightsix.kami.module.modules.combat + +import me.zeroeightsix.kami.event.events.RenderEvent +import me.zeroeightsix.kami.manager.mangers.CombatManager +import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.setting.Settings +import me.zeroeightsix.kami.util.color.ColorConverter +import me.zeroeightsix.kami.util.color.ColorHolder +import me.zeroeightsix.kami.util.combat.CrystalUtils +import me.zeroeightsix.kami.util.graphics.ESPRenderer +import me.zeroeightsix.kami.util.graphics.GlStateUtils +import me.zeroeightsix.kami.util.graphics.KamiTessellator +import me.zeroeightsix.kami.util.graphics.ProjectionUtils +import me.zeroeightsix.kami.util.math.MathUtils +import me.zeroeightsix.kami.util.math.Vec2f +import net.minecraft.entity.item.EntityEnderCrystal +import net.minecraft.util.math.AxisAlignedBB +import net.minecraft.util.math.BlockPos +import org.lwjgl.opengl.GL11.* +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.Executors +import kotlin.math.PI +import kotlin.math.abs +import kotlin.math.min +import kotlin.math.sin + +@Module.Info( + name = "CrystalESP", + description = "Renders ESP for End Crystals", + category = Module.Category.COMBAT +) +object CrystalESP : Module() { + private val page = register(Settings.e("Page", Page.DAMAGE_ESP)) + + private val damageESP = register(Settings.booleanBuilder("DamageESP").withValue(false).withVisibility { page.value == Page.DAMAGE_ESP }.build()) + private val minAlpha = register(Settings.integerBuilder("MinAlpha").withValue(0).withRange(0, 255).withVisibility { page.value == Page.DAMAGE_ESP }.build()) + private val maxAlpha = register(Settings.integerBuilder("MaxAlpha").withValue(63).withRange(0, 255).withVisibility { page.value == Page.DAMAGE_ESP }.build()) + private val damageRange = register(Settings.floatBuilder("DamageESPRange").withValue(4.0f).withRange(0.0f, 16.0f).withVisibility { page.value == Page.DAMAGE_ESP }.build()) + + private val crystalESP = register(Settings.booleanBuilder("CrystalESP").withValue(true).withVisibility { page.value == Page.CRYSTAL_ESP }.build()) + private val mode = register(Settings.enumBuilder(Mode::class.java).withName("Mode").withValue(Mode.BLOCK).withVisibility { page.value == Page.CRYSTAL_ESP && crystalESP.value }.build()) + private val filled = register(Settings.booleanBuilder("Filled").withValue(true).withVisibility { page.value == Page.CRYSTAL_ESP && crystalESP.value }.build()) + private val outline = register(Settings.booleanBuilder("Outline").withValue(true).withVisibility { page.value == Page.CRYSTAL_ESP && crystalESP.value }.build()) + private val tracer = register(Settings.booleanBuilder("Tracer").withValue(true).withVisibility { page.value == Page.CRYSTAL_ESP && crystalESP.value }.build()) + private val showDamage = register(Settings.booleanBuilder("Damage").withValue(true).withVisibility { page.value == Page.CRYSTAL_ESP && crystalESP.value }.build()) + private val showSelfDamage = register(Settings.booleanBuilder("SelfDamage").withValue(false).withVisibility { page.value == Page.CRYSTAL_ESP && crystalESP.value }.build()) + private val textScale = register(Settings.floatBuilder("TextScale").withValue(1.0f).withRange(0.0f, 4.0f).withVisibility { page.value == Page.CRYSTAL_ESP && crystalESP.value }) + private val animationScale = register(Settings.floatBuilder("AnimationScale").withValue(1.0f).withRange(0.0f, 2.0f).withVisibility { page.value == Page.CRYSTAL_ESP && crystalESP.value }) + private val crystalRange = register(Settings.floatBuilder("CrystalESPRange").withValue(16.0f).withRange(0.0f, 64.0f).withVisibility { page.value == Page.CRYSTAL_ESP }.build()) + + private val r = register(Settings.integerBuilder("Red").withValue(155).withRange(0, 255).withVisibility { page.value == Page.CRYSTAL_ESP_COLOR && crystalESP.value }.build()) + private val g = register(Settings.integerBuilder("Green").withValue(144).withRange(0, 255).withVisibility { page.value == Page.CRYSTAL_ESP_COLOR && crystalESP.value }.build()) + private val b = register(Settings.integerBuilder("Blue").withValue(255).withRange(0, 255).withVisibility { page.value == Page.CRYSTAL_ESP_COLOR && crystalESP.value }.build()) + private val aFilled = register(Settings.integerBuilder("FilledAlpha").withValue(47).withRange(0, 255).withVisibility { page.value == Page.CRYSTAL_ESP_COLOR && crystalESP.value && filled.value }.build()) + private val aOutline = register(Settings.integerBuilder("OutlineAlpha").withValue(127).withRange(0, 255).withVisibility { page.value == Page.CRYSTAL_ESP_COLOR && crystalESP.value && outline.value }.build()) + private val aTracer = register(Settings.integerBuilder("TracerAlpha").withValue(200).withRange(0, 255).withVisibility { page.value == Page.CRYSTAL_ESP_COLOR && crystalESP.value && tracer.value }.build()) + private val thickness = register(Settings.floatBuilder("Thickness").withValue(2.0f).withRange(0.0f, 4.0f).withVisibility { page.value == Page.CRYSTAL_ESP_COLOR && crystalESP.value && (outline.value || tracer.value) }.build()) + + private enum class Page { + DAMAGE_ESP, CRYSTAL_ESP, CRYSTAL_ESP_COLOR + } + + private enum class Mode { + BLOCK, CRYSTAL + } + + private val damageESPMap = ConcurrentHashMap() + private val crystalMap = ConcurrentHashMap, Vec2f>>() // , >> + private val threads = arrayOf(Thread { updateDamageESP() }, Thread { updateCrystalESP() }) + private val threadPool = Executors.newCachedThreadPool() + + override fun onUpdate() { + for (thread in threads) { + threadPool.execute(thread) + } + } + + private fun updateDamageESP() { + if (damageESP.value) { + val cacheMap = CrystalUtils.getPlacePos(CombatManager.target, CombatManager.target, damageRange.value) + damageESPMap.values.removeIf { !cacheMap.containsValue(it) } + damageESPMap.putAll(cacheMap) + } else { + damageESPMap.clear() + } + } + + private fun updateCrystalESP() { + if (crystalESP.value) { + val cacheMap = HashMap(CrystalUtils.getCrystalList(crystalRange.value).map { crystal -> + val damages = calcDamages(crystal) + crystal to Pair(damages, Vec2f(0f, 0f)) + }.toMap()) + + for ((crystal, pair) in crystalMap) { + val scale = 1f / animationScale.value + val damages = calcDamages(crystal) + cacheMap.computeIfPresent(crystal) { _, _ -> Pair(damages, Vec2f(pair.second.y, min(pair.second.y + 0.4f * scale, 1f))) } + cacheMap.computeIfAbsent(crystal) { Pair(damages, Vec2f(pair.second.y, min(pair.second.y + 0.2f * scale, 2f))) } + } + crystalMap.putAll(cacheMap) + crystalMap.values.removeIf { it.second.y >= 2.0f } + } else { + crystalMap.clear() + } + } + + private fun calcDamages(crystal: EntityEnderCrystal): Pair { + val damage = CombatManager.target?.let { CrystalUtils.calcDamage(crystal, it) } ?: -0.0f + val selfDamage = mc.player?.let { CrystalUtils.calcDamage(crystal, mc.player) } ?: -0.0f + return Pair(damage, selfDamage) + } + + override fun onWorldRender(event: RenderEvent) { + val renderer = ESPRenderer() + + /* Damage ESP */ + if (damageESP.value && damageESPMap.isNotEmpty()) { + renderer.aFilled = 255 + for ((damage, pos) in damageESPMap) { + val rgb = MathUtils.convertRange(damage.toInt(), 0, 20, 127, 255) + val a = MathUtils.convertRange(damage.toInt(), 0, 20, minAlpha.value, maxAlpha.value) + val rgba = ColorHolder(rgb, rgb, rgb, a) + renderer.add(pos, rgba) + } + renderer.render(true) + } + + /* Crystal ESP */ + if (crystalESP.value) { + renderer.aFilled = if (filled.value) aFilled.value else 0 + renderer.aOutline = if (outline.value) aOutline.value else 0 + renderer.aTracer = if (tracer.value) aTracer.value else 0 + renderer.thickness = thickness.value + for ((crystal, pair) in crystalMap) { + val progress = getAnimationProgress(pair.second) + val box = if (mode.value == Mode.CRYSTAL) { + crystal.boundingBox.shrink(1.0 - progress) + } else { + AxisAlignedBB(crystal.position.down()).shrink(0.5 - progress * 0.5) + } + val rgba = ColorHolder(r.value, g.value, b.value, (progress * 255f).toInt()) + renderer.add(box, rgba) + } + renderer.render(true) + } + } + + override fun onRender() { + if (!showDamage.value && !showSelfDamage.value) return + GlStateUtils.rescale(mc.displayWidth.toDouble(), mc.displayHeight.toDouble()) + val fontRenderer = mc.fontRenderer + for ((crystal, pair) in crystalMap) { + glPushMatrix() + val screenPos = ProjectionUtils.toScreenPos(if (mode.value == Mode.CRYSTAL) { + crystal.boundingBox.center + } else { + crystal.positionVector.subtract(0.0, 0.5, 0.0) + }) + glTranslated(screenPos.x, screenPos.y, 0.0) + glScalef(textScale.value * 2f, textScale.value * 2f, 1f) + + val damage = abs(MathUtils.round(pair.first.first, 1)) + val selfDamage = abs(MathUtils.round(pair.first.second, 1)) + val alpha = (getAnimationProgress(pair.second) * 255f).toInt() + val color = ColorConverter.rgbToInt(255, 255, 255, alpha) + if (showDamage.value) { + val text = "Target: $damage" + val halfWidth = fontRenderer.getStringWidth(text) / -2f + fontRenderer.drawStringWithShadow(text, halfWidth, 0f, color) + } + if (showSelfDamage.value) { + val text = "Self: $selfDamage" + val halfWidth = fontRenderer.getStringWidth(text) / -2f + fontRenderer.drawStringWithShadow(text, halfWidth, fontRenderer.FONT_HEIGHT + 2f, color) + } + + glPopMatrix() + } + GlStateUtils.rescaleMc() + } + + private fun getAnimationProgress(progressIn: Vec2f): Float { + val interpolated = progressIn.x + (progressIn.y - progressIn.x) * KamiTessellator.pTicks() + return sin(interpolated * 0.5 * PI).toFloat() + } +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/render/HoleESP.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleESP.kt similarity index 72% rename from src/main/java/me/zeroeightsix/kami/module/modules/render/HoleESP.kt rename to src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleESP.kt index 9310ac221..7f0d9e91a 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/render/HoleESP.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleESP.kt @@ -1,21 +1,19 @@ -package me.zeroeightsix.kami.module.modules.render +package me.zeroeightsix.kami.module.modules.combat import me.zeroeightsix.kami.event.events.RenderEvent import me.zeroeightsix.kami.module.Module import me.zeroeightsix.kami.setting.Settings -import me.zeroeightsix.kami.util.BlockUtils.surroundOffset import me.zeroeightsix.kami.util.color.ColorHolder +import me.zeroeightsix.kami.util.combat.SurroundUtils import me.zeroeightsix.kami.util.graphics.ESPRenderer import me.zeroeightsix.kami.util.graphics.GeometryMasks import me.zeroeightsix.kami.util.math.VectorUtils -import net.minecraft.init.Blocks import net.minecraft.util.math.BlockPos import java.util.concurrent.ConcurrentHashMap -import kotlin.math.ceil @Module.Info( name = "HoleESP", - category = Module.Category.RENDER, + category = Module.Category.COMBAT, description = "Show safe holes for crystal pvp" ) object HoleESP : Module() { @@ -55,30 +53,14 @@ object HoleESP : Module() { safeHoles.clear() val blockPosList = VectorUtils.getBlockPosInSphere(mc.player.positionVector, renderDistance.value) for (pos in blockPosList) { - if (mc.world.getBlockState(pos).block != Blocks.AIR// block gotta be air - || mc.world.getBlockState(pos.up()).block != Blocks.AIR // block 1 above gotta be air - || mc.world.getBlockState(pos.up().up()).block != Blocks.AIR) continue // block 2 above gotta be air + val holeType = SurroundUtils.checkHole(pos) + if (holeType == SurroundUtils.HoleType.NONE) continue - var isSafe = true - var isBedrock = true - for (offset in surroundOffset) { - val block = mc.world.getBlockState(pos.add(offset)).block - if (block !== Blocks.BEDROCK && block !== Blocks.OBSIDIAN && block !== Blocks.ENDER_CHEST && block !== Blocks.ANVIL) { - isSafe = false - break - } - if (block !== Blocks.BEDROCK) { - isBedrock = false - } + if (holeType == SurroundUtils.HoleType.OBBY && shouldAddObby()) { + safeHoles[pos] = ColorHolder(r1.value, g1.value, b1.value) } - - if (isSafe) { - if (!isBedrock && shouldAddObby()) { - safeHoles[pos] = ColorHolder(r1.value, g1.value, b1.value) - } - if (isBedrock && shouldAddBedrock()) { - safeHoles[pos] = ColorHolder(r2.value, g2.value, b2.value) - } + if (holeType == SurroundUtils.HoleType.BEDROCK && shouldAddBedrock()) { + safeHoles[pos] = ColorHolder(r2.value, g2.value, b2.value) } } } diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleMiner.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleMiner.kt new file mode 100644 index 000000000..10bad47f4 --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleMiner.kt @@ -0,0 +1,119 @@ +package me.zeroeightsix.kami.module.modules.combat + +import me.zeroeightsix.kami.manager.mangers.CombatManager +import me.zeroeightsix.kami.manager.mangers.PlayerPacketManager +import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.setting.Settings +import me.zeroeightsix.kami.util.InventoryUtils +import me.zeroeightsix.kami.util.combat.CrystalUtils +import me.zeroeightsix.kami.util.combat.SurroundUtils +import me.zeroeightsix.kami.util.math.RotationUtils +import me.zeroeightsix.kami.util.math.Vec2f +import me.zeroeightsix.kami.util.math.VectorUtils.toBlockPos +import me.zeroeightsix.kami.util.math.VectorUtils.toVec3d +import me.zeroeightsix.kami.util.text.MessageSendHelper +import net.minecraft.entity.Entity +import net.minecraft.init.Blocks +import net.minecraft.init.Items +import net.minecraft.network.play.client.CPacketPlayerDigging +import net.minecraft.util.EnumFacing +import net.minecraft.util.EnumHand +import net.minecraft.util.math.BlockPos +import kotlin.math.pow + +@Module.Info( + name = "HoleMiner", + category = Module.Category.COMBAT, + description = "Mines your opponent's hole", + modulePriority = 100 +) +object HoleMiner : Module() { + private val range = register(Settings.floatBuilder("Range").withValue(5.0f).withRange(0.0f, 10.0f)) + + private var miningPos: BlockPos? = null + private var start = true + + override fun getHudInfo() = "${CombatManager.target?.name}" + + override fun onDisable() { + miningPos = null + start = true + } + + override fun onEnable() { + if (mc.player == null) { + disable() + return + } + val target = CombatManager.target + if (target != null) { + if (SurroundUtils.checkHole(target) != SurroundUtils.HoleType.OBBY) { + MessageSendHelper.sendChatMessage("$chatName Target is not in a valid hole, disabling") + disable() + } else { + miningPos = findHoleBlock(target) + } + } else { + MessageSendHelper.sendChatMessage("$chatName No target found, disabling") + disable() + } + } + + override fun onUpdate() { + if (!CombatManager.isOnTopPriority(this)) return + if (mc.player.heldItemMainhand.getItem() != Items.DIAMOND_PICKAXE) { + val slot = InventoryUtils.getSlotsHotbar(278)?.get(0) + if (slot == null) { + MessageSendHelper.sendChatMessage("$chatName No pickaxe found, disabling") + disable() + return + } else { + InventoryUtils.swapSlot(slot) + } + } + val pos = miningPos + if (pos == null) { + MessageSendHelper.sendChatMessage("$chatName No hole block to mine, disabling") + disable() + } else if (mc.player.ticksExisted % 2 == 0) { + if (mc.world.isAirBlock(pos)) { + MessageSendHelper.sendChatMessage("$chatName Done mining") + disable() + return + } + val action = if (start) CPacketPlayerDigging.Action.START_DESTROY_BLOCK else CPacketPlayerDigging.Action.STOP_DESTROY_BLOCK + val rotation = Vec2f(RotationUtils.getRotationTo(pos.toVec3d(), true)) + val diff = mc.player.getPositionEyes(1f).subtract(pos.toVec3d()) + val normalizedVec = diff.scale(1.0 / diff.length()) + val facing = EnumFacing.getFacingFromVector(normalizedVec.x.toFloat(), normalizedVec.y.toFloat(), normalizedVec.z.toFloat()) + PlayerPacketManager.addPacket(this, PlayerPacketManager.PlayerPacket(rotating = true, rotation = rotation)) + mc.connection!!.sendPacket(CPacketPlayerDigging(action, pos, facing)) + mc.player.swingArm(EnumHand.MAIN_HAND) + start = false + } + } + + private fun findHoleBlock(entity: Entity): BlockPos? { + val pos = entity.positionVector.toBlockPos() + var closestPos = 114.514 to BlockPos.ORIGIN + for (facing in EnumFacing.HORIZONTALS) { + val offsetPos = pos.offset(facing) + val dist = mc.player.getDistanceSqToCenter(offsetPos) + if (dist > range.value.pow(2) || dist > closestPos.first) continue + if (mc.world.getBlockState(offsetPos).block == Blocks.BEDROCK) continue + if (!checkPos(offsetPos, facing)) continue + closestPos = dist to offsetPos + } + return if (closestPos.second != BlockPos.ORIGIN) closestPos.second else null + } + + private fun checkPos(pos: BlockPos, facingIn: EnumFacing): Boolean { + if (CrystalUtils.canPlaceOn(pos) && mc.world.isAirBlock(pos.up())) return true + for (facing in EnumFacing.HORIZONTALS) { + if (facing == facingIn.opposite) continue + if (!CrystalUtils.canPlace(pos.offset(facing))) continue + return true + } + return false + } +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleSnap.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleSnap.kt new file mode 100644 index 000000000..fb229b184 --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/HoleSnap.kt @@ -0,0 +1,61 @@ +package me.zeroeightsix.kami.module.modules.combat + +import me.zeroeightsix.kami.module.Module +import me.zeroeightsix.kami.module.modules.movement.Strafe +import me.zeroeightsix.kami.setting.Settings +import me.zeroeightsix.kami.util.combat.SurroundUtils +import me.zeroeightsix.kami.util.math.RotationUtils +import me.zeroeightsix.kami.util.math.VectorUtils +import me.zeroeightsix.kami.util.math.VectorUtils.toBlockPos +import me.zeroeightsix.kami.util.math.VectorUtils.toVec3d +import net.minecraft.util.math.BlockPos +import kotlin.math.* + +@Module.Info( + name = "HoleSnap", + description = "Move you into the hole nearby", + category = Module.Category.COMBAT +) +object HoleSnap : Module() { + private val disableStrafe = register(Settings.b("DisableStrafe",true)) + private val range = register(Settings.floatBuilder("Range").withValue(2.5f).withRange(0f, 5f)) + + override fun onEnable() { + if (mc.player == null) disable() + } + + override fun onUpdate() { + if (SurroundUtils.checkHole(mc.player) != SurroundUtils.HoleType.NONE) { + disable() + return + } + findHole()?.toVec3d()?.let { + if (disableStrafe.value) Strafe.disable() + if (mc.player.onGround) { + val yawRad = Math.toRadians(RotationUtils.getRotationTo(mc.player.positionVector, it).x) + val speed = min(0.25, mc.player.positionVector.distanceTo(it) / 4.0) + mc.player.motionX = -sin(yawRad) * speed + mc.player.motionZ = cos(yawRad) * speed + } + if (mc.player.motionY <= 0.01) mc.player.motionY = -0.5 + } + } + + private fun findHole(): BlockPos? { + var closestHole = Pair(69.69, BlockPos.ORIGIN) + val playerPos = mc.player.positionVector.toBlockPos() + val ceilRange = ceil(range.value).toInt() + val posList = VectorUtils.getBlockPositionsInArea(playerPos.add(ceilRange, -1, ceilRange), playerPos.add(-ceilRange, -1, -ceilRange)) + for (posXZ in posList) { + val dist = mc.player.getDistanceSqToCenter(posXZ) + if (dist > range.value.pow(2) || dist > closestHole.first) continue + for (posY in 0..5) { + val pos = posXZ.add(0, -posY, 0) + if (!mc.world.isAirBlock(pos.up())) break + if (SurroundUtils.checkHole(pos) == SurroundUtils.HoleType.NONE) continue + closestHole = dist to pos + } + } + return if (closestHole.second != BlockPos.ORIGIN) closestHole.second else null + } +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/OffhandGap.java b/src/main/java/me/zeroeightsix/kami/module/modules/combat/OffhandGap.java deleted file mode 100644 index 639195c5d..000000000 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/OffhandGap.java +++ /dev/null @@ -1,170 +0,0 @@ -package me.zeroeightsix.kami.module.modules.combat; - -import me.zero.alpine.listener.EventHandler; -import me.zero.alpine.listener.Listener; -import me.zeroeightsix.kami.event.events.GuiScreenEvent; -import me.zeroeightsix.kami.event.events.PacketEvent; -import me.zeroeightsix.kami.module.Module; -import me.zeroeightsix.kami.setting.Setting; -import me.zeroeightsix.kami.setting.Settings; -import me.zeroeightsix.kami.util.InventoryUtils; -import net.minecraft.entity.item.EntityEnderCrystal; -import net.minecraft.init.Items; -import net.minecraft.inventory.ClickType; -import net.minecraft.item.*; -import net.minecraft.network.play.client.CPacketPlayerTryUseItem; - -import java.util.Comparator; -import java.util.Objects; - -@Module.Info( - name = "OffhandGap", - category = Module.Category.COMBAT, - description = "Holds a God apple when right clicking your sword!" -) -public class OffhandGap extends Module { - private final Setting disableHealth = register(Settings.doubleBuilder("DisableHealth").withMinimum(0.0).withValue(4.0).withMaximum(20.0).build()); - private final Setting eatWhileAttacking = register(Settings.b("EatWhileAttacking", false)); - private final Setting swordOrAxeOnly = register(Settings.b("SwordAndAxeOnly", true)); - private final Setting preferBlocks = register(Settings.booleanBuilder("PreferPlacingBlocks").withValue(false).withVisibility(v -> !swordOrAxeOnly.getValue()).build()); - private final Setting crystalCheck = register(Settings.b("CrystalCheck", false)); - - private int gaps = -1; - private boolean autoTotemWasEnabled = false; - private boolean cancelled = false; - private boolean isGuiOpened = false; - private Item usedItem; - - public static OffhandGap INSTANCE; - - public OffhandGap() { - super(); - INSTANCE = this; - } - - @EventHandler - public Listener listener = new Listener<>(event -> - isGuiOpened = event.getScreen() != null - ); - - @EventHandler - private final Listener sendListener = new Listener<>(e -> { - if (e.getPacket() instanceof CPacketPlayerTryUseItem) { - if (cancelled) { - disableGaps(); - return; - } - if (mc.player.getHeldItemMainhand().getItem() instanceof ItemSword || mc.player.getHeldItemMainhand().getItem() instanceof ItemAxe || passItemCheck()) { - if (AutoTotem.INSTANCE.isEnabled()) { - autoTotemWasEnabled = true; - AutoTotem.INSTANCE.disable(); - } - if (!eatWhileAttacking.getValue()) { /* Save item for later when using preventDesync */ - usedItem = mc.player.getHeldItemMainhand().getItem(); - } - enableGaps(gaps); - } - } - try { - /* If you stop holding right click move totem back */ - if (!mc.gameSettings.keyBindUseItem.isKeyDown() && mc.player.getHeldItemOffhand().getItem() == Items.GOLDEN_APPLE) - disableGaps(); - /* In case you didn't stop right clicking but you switched items by scrolling or something */ - else if ((usedItem != mc.player.getHeldItemMainhand().getItem()) && mc.player.getHeldItemOffhand().getItem() == Items.GOLDEN_APPLE) { - if (!eatWhileAttacking.getValue()) { - usedItem = mc.player.getHeldItemMainhand().getItem(); - disableGaps(); - } - } - /* Force disable if under health limit */ - else if (mc.player.getHealth() + mc.player.getAbsorptionAmount() <= disableHealth.getValue()) { - disableGaps(); - } - /* Disable if there are crystals in the range of CrystalAura */ - if (crystalCheck.getValue() && CrystalAura.INSTANCE.isEnabled()) { - EntityEnderCrystal crystal = mc.world.loadedEntityList.stream() - .filter(entity -> entity instanceof EntityEnderCrystal) - .map(entity -> (EntityEnderCrystal) entity) - .min(Comparator.comparing(c -> mc.player.getDistance(c))) - .orElse(null); - if (Objects.requireNonNull(crystal).getPosition().distanceSq(mc.player.getPosition().x, mc.player.getPosition().y, mc.player.getPosition().z) <= CrystalAura.INSTANCE.range.getValue()) { - disableGaps(); - } - } - } catch (NullPointerException ignored) { } - }); - - @Override - public void onUpdate() { - if (mc.player == null) return; - - /* If your health doesn't meet the cutoff then set it to true */ - cancelled = mc.player.getHealth() + mc.player.getAbsorptionAmount() <= disableHealth.getValue(); - if (cancelled) { - disableGaps(); - return; - } - - if (mc.player.getHeldItemOffhand().getItem() != Items.GOLDEN_APPLE) { - for (int i = 0; i < 45; i++) { - if (mc.player.inventory.getStackInSlot(i).getItem() == Items.GOLDEN_APPLE) { - gaps = i; - break; - } - } - } - } - - /* If weaponCheck is disabled, check if they're not holding an item you'd want to use normally */ - private boolean passItemCheck() { - if (swordOrAxeOnly.getValue()) return false; - else { - Item item = mc.player.getHeldItemMainhand().getItem(); - if (item instanceof ItemBow) return false; - if (item instanceof ItemSnowball) return false; - if (item instanceof ItemEgg) return false; - if (item instanceof ItemPotion) return false; - if (item instanceof ItemEnderEye) return false; - if (item instanceof ItemEnderPearl) return false; - if (item instanceof ItemFood) return false; - if (item instanceof ItemShield) return false; - if (item instanceof ItemFlintAndSteel) return false; - if (item instanceof ItemFishingRod) return false; - if (item instanceof ItemArmor) return false; - if (item instanceof ItemExpBottle) return false; - return !preferBlocks.getValue() || !(item instanceof ItemBlock); - } - } - - private void disableGaps() { - if (autoTotemWasEnabled != AutoTotem.INSTANCE.isEnabled()) { - moveGapsWaitForNoGui(); - AutoTotem.INSTANCE.enable(); - autoTotemWasEnabled = false; - } - } - - private void enableGaps(int slot) { - if (mc.player.getHeldItemOffhand().getItem() != Items.GOLDEN_APPLE) { - mc.playerController.windowClick(0, slot < 9 ? slot + 36 : slot, 0, ClickType.PICKUP, mc.player); - mc.playerController.windowClick(0, 45, 0, ClickType.PICKUP, mc.player); - } - } - - private void moveGapsToInventory(int slot) { - if (mc.player.getHeldItemOffhand().getItem() == Items.GOLDEN_APPLE) { - mc.playerController.windowClick(0, 45, 0, ClickType.PICKUP, mc.player); - mc.playerController.windowClick(0, slot < 9 ? slot + 36 : slot, 0, ClickType.PICKUP, mc.player); - } - } - - private void moveGapsWaitForNoGui() { - if (isGuiOpened) return; - moveGapsToInventory(gaps); - } - - @Override - public String getHudInfo() { - return "" + InventoryUtils.countItemAll(322); - } -} diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/combat/Surround.kt b/src/main/java/me/zeroeightsix/kami/module/modules/combat/Surround.kt index 013a3efd5..82f666868 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/combat/Surround.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/combat/Surround.kt @@ -1,280 +1,215 @@ package me.zeroeightsix.kami.module.modules.combat +import me.zeroeightsix.kami.manager.mangers.CombatManager +import me.zeroeightsix.kami.manager.mangers.PlayerPacketManager import me.zeroeightsix.kami.module.Module -import me.zeroeightsix.kami.module.modules.player.NoBreakAnimation +import me.zeroeightsix.kami.module.modules.movement.Strafe import me.zeroeightsix.kami.setting.Setting import me.zeroeightsix.kami.setting.Settings import me.zeroeightsix.kami.util.BlockUtils -import me.zeroeightsix.kami.util.CenterPlayer +import me.zeroeightsix.kami.util.InventoryUtils +import me.zeroeightsix.kami.util.MovementUtils +import me.zeroeightsix.kami.util.TimerUtils +import me.zeroeightsix.kami.util.combat.SurroundUtils +import me.zeroeightsix.kami.util.math.VectorUtils.toBlockPos import me.zeroeightsix.kami.util.text.MessageSendHelper -import net.minecraft.block.Block -import net.minecraft.block.BlockObsidian -import net.minecraft.block.state.IBlockState -import net.minecraft.item.ItemBlock -import net.minecraft.item.ItemStack -import net.minecraft.network.play.client.CPacketAnimation -import net.minecraft.network.play.client.CPacketEntityAction -import net.minecraft.network.play.client.CPacketHeldItemChange -import net.minecraft.network.play.client.CPacketPlayer import net.minecraft.util.EnumFacing -import net.minecraft.util.EnumHand import net.minecraft.util.math.BlockPos import net.minecraft.util.math.MathHelper import net.minecraft.util.math.Vec3d -import kotlin.math.atan2 -import kotlin.math.floor -import kotlin.math.sqrt +import java.util.concurrent.Executors +import java.util.concurrent.Future +import kotlin.math.round @Module.Info( name = "Surround", category = Module.Category.COMBAT, - description = "Surrounds you with obsidian to take less damage" + description = "Surrounds you with obsidian to take less damage", + modulePriority = 200 ) object Surround : Module() { - val autoDisable: Setting = register(Settings.b("DisableOnPlace", true)) - private val spoofRotations = register(Settings.b("SpoofRotations", true)) - private val spoofHotbar = register(Settings.b("SpoofHotbar", false)) - private val blockPerTick = register(Settings.doubleBuilder("BlocksPerTick").withMinimum(1.0).withValue(4.0).withMaximum(10.0).build()) - private val debugMsgs = register(Settings.e("DebugMessages", DebugMsgs.IMPORTANT)) - private val autoCenter = register(Settings.b("AutoCenter", true)) - private val placeAnimation = register(Settings.b("PlaceAnimation", false)) + private val autoCenter = register(Settings.e("AutoCenter", AutoCenterMode.MOTION)) + private val placeSpeed = register(Settings.floatBuilder("PlacesPerTick").withValue(4f).withRange(0.25f, 5f).withStep(0.25f)) + private val autoDisable = register(Settings.e("AutoDisable", AutoDisableMode.OUT_OF_HOLE)) + private val outOfHoleTimeout = register(Settings.integerBuilder("OutOfHoleTimeout(t)").withValue(20).withRange(1, 50).withVisibility { autoDisable.value == AutoDisableMode.OUT_OF_HOLE }) + private val enableInHole = register(Settings.b("EnableInHole", true)) + private val inHoleTimeout = register(Settings.integerBuilder("InHoleTimeout(t)").withValue(50).withRange(1, 100).withVisibility { enableInHole.value }) + private val disableStrafe = register(Settings.b("DisableStrafe", true)) - private val surroundTargets = arrayOf(Vec3d(0.0, 0.0, 0.0), Vec3d(1.0, 1.0, 0.0), Vec3d(0.0, 1.0, 1.0), Vec3d(-1.0, 1.0, 0.0), Vec3d(0.0, 1.0, -1.0), Vec3d(1.0, 0.0, 0.0), Vec3d(0.0, 0.0, 1.0), Vec3d(-1.0, 0.0, 0.0), Vec3d(0.0, 0.0, -1.0), Vec3d(1.0, 1.0, 0.0), Vec3d(0.0, 1.0, 1.0), Vec3d(-1.0, 1.0, 0.0), Vec3d(0.0, 1.0, -1.0)) + enum class AutoCenterMode { + OFF, TP, MOTION + } - private var basePos: BlockPos? = null - private var offsetStep = 0 - private var playerHotbarSlot = -1 - private var lastHotbarSlot = -1 + enum class AutoDisableMode { + ONE_TIME, OUT_OF_HOLE + } - @Suppress("UNUSED") - private enum class DebugMsgs { - NONE, IMPORTANT, ALL + private var holePos: BlockPos? = null + private var toggleTimer = TimerUtils.StopTimer(TimerUtils.TimeUnit.TICKS) + private val placeThread = Thread { runSurround() }.apply { name = "Surround" } + private val threadPool = Executors.newSingleThreadExecutor() + private var future: Future<*>? = null + private var strafeEnabled = false + + override fun onEnable() { + toggleTimer.reset() + mc.player?.setVelocity(0.0, -5.0, 0.0) + } + + override fun onDisable() { + PlayerPacketManager.resetHotbar() + toggleTimer.reset() + holePos = null + if (strafeEnabled && disableStrafe.value) { + Strafe.enable() + strafeEnabled = false + } + } + + override fun isActive(): Boolean { + return isEnabled && future?.isDone == false + } + + // Runs the codes on rendering for more immediate reaction + override fun onRender() { + if (mc.world == null || mc.player == null) return + if (getObby() == -1) return + if (isDisabled) { + enableInHoleCheck() + return + } + + // Following codes will not run if disabled + if (!mc.player.onGround || mc.player.positionVector.toBlockPos() != holePos) { // Out of hole check + outOfHoleCheck() + return + } else { + toggleTimer.reset() + } + if (!isPlaceable() || !centerPlayer()) { // Placeable & Centered check + if (!isPlaceable() && autoDisable.value == AutoDisableMode.ONE_TIME) disable() + return + } + if (future?.isDone != false) future = threadPool.submit(placeThread) } override fun onUpdate() { - if (autoCenter.value && (mc.player.posX != CenterPlayer.getPosX(1.0f) || mc.player.posZ != CenterPlayer.getPosZ(1.0f))) { - CenterPlayer.centerPlayer(1.0f) - if (debugMsgs.value == DebugMsgs.ALL) MessageSendHelper.sendChatMessage("$chatName Auto centering. Player position is " + mc.player.positionVector.toString()) + if (isEnabled && holePos == null && centerPlayer()) holePos = mc.player.positionVector.toBlockPos() + if (future?.isDone == false && future?.isCancelled == false) { + val slot = getObby() + if (slot != -1) PlayerPacketManager.spoofHotbar(getObby()) + PlayerPacketManager.addPacket(this, PlayerPacketManager.PlayerPacket(rotating = false)) + } else if (isEnabled && CombatManager.isOnTopPriority(this)) { + PlayerPacketManager.resetHotbar() + } + } + + private fun enableInHoleCheck() { + if (enableInHole.value && mc.player.onGround && MovementUtils.getSpeed() < 0.15 && SurroundUtils.checkHole(mc.player) != SurroundUtils.HoleType.NONE) { + if (toggleTimer.stop() > inHoleTimeout.value) { + MessageSendHelper.sendChatMessage("$chatName You are in hole for longer than ${inHoleTimeout.value} ticks, enabling") + enable() + } } else { - if (offsetStep == 0) { - basePos = BlockPos(mc.player.positionVector).down() - playerHotbarSlot = mc.player.inventory.currentItem - if (debugMsgs.value == DebugMsgs.ALL) { - MessageSendHelper.sendChatMessage("$chatName Starting Loop, current Player Slot: $playerHotbarSlot") - } - if (!spoofHotbar.value) { - lastHotbarSlot = mc.player.inventory.currentItem - } - } - for (i in 0 until floor(blockPerTick.value).toInt()) { - if (debugMsgs.value == DebugMsgs.ALL) { - MessageSendHelper.sendChatMessage("$chatName Loop iteration: $offsetStep") - } - if (offsetStep >= surroundTargets.size) { - endLoop() - return - } - val offset = surroundTargets[offsetStep] - placeBlock(BlockPos(basePos!!.add(offset.x, offset.y, offset.z))) - ++offsetStep + toggleTimer.reset() + } + } + + private fun outOfHoleCheck() { + if (autoDisable.value == AutoDisableMode.OUT_OF_HOLE) { + if (toggleTimer.stop() > outOfHoleTimeout.value) { + MessageSendHelper.sendChatMessage("$chatName You are out of hole for longer than ${outOfHoleTimeout.value} ticks, disabling") + disable() } } } - public override fun onEnable() { - if (mc.player == null) return - - if (autoCenter.value) { - CenterPlayer.centerPlayer(0.5f) - if (debugMsgs.value == DebugMsgs.ALL) MessageSendHelper.sendChatMessage("$chatName Auto centering. Player position is " + mc.player.positionVector.toString()) - } - - playerHotbarSlot = mc.player.inventory.currentItem - lastHotbarSlot = -1 - - if (debugMsgs.value == DebugMsgs.ALL) { - MessageSendHelper.sendChatMessage("$chatName Saving initial Slot = $playerHotbarSlot") + private fun getObby(): Int { + val slots = InventoryUtils.getSlotsHotbar(49) + if (slots == null) { // Obsidian check + if (isEnabled) { + MessageSendHelper.sendChatMessage("$chatName No obsidian in hotbar, disabling!") + disable() + } + return -1 } + return slots[0] } - public override fun onDisable() { - if (mc.player != null) { - if (debugMsgs.value == DebugMsgs.ALL) { - MessageSendHelper.sendChatMessage("$chatName Disabling") - } + private fun isPlaceable(): Boolean { + val playerPos = mc.player.positionVector.toBlockPos() + for (offset in SurroundUtils.surroundOffset) { + val pos = playerPos.add(offset) + if (BlockUtils.isPlaceable(pos)) return true + } + return false + } - if (lastHotbarSlot != playerHotbarSlot && playerHotbarSlot != -1) { - if (spoofHotbar.value) { - mc.player.connection.sendPacket(CPacketHeldItemChange(playerHotbarSlot)) + private fun centerPlayer(): Boolean { + return if (autoCenter.value == AutoCenterMode.OFF) { + true + } else { + if (disableStrafe.value) { + strafeEnabled = Strafe.isEnabled + Strafe.disable() + } + val centerDiff = getCenterDiff() + val centered = isCentered() + if (!centered) { + mc.player.setVelocity(0.0, -5.0, 0.0) + if (autoCenter.value == AutoCenterMode.TP) { + val posX = mc.player.posX + MathHelper.clamp(centerDiff.x, -0.2, 0.2) + val posZ = mc.player.posZ + MathHelper.clamp(centerDiff.z, -0.2, 0.2) + mc.player.setPosition(posX, mc.player.posY, posZ) } else { - mc.player.inventory.currentItem = playerHotbarSlot + mc.player.motionX = MathHelper.clamp(centerDiff.x / 2.0, -0.2, 0.2) + mc.player.motionZ = MathHelper.clamp(centerDiff.z / 2.0, -0.2, 0.2) } } - - playerHotbarSlot = -1 - lastHotbarSlot = -1 + centered } } - private fun endLoop() { - offsetStep = 0 + private fun isCentered(): Boolean { + return getCenterDiff().length() < 0.2 + } - if (debugMsgs.value == DebugMsgs.ALL) { - MessageSendHelper.sendChatMessage("$chatName Ending Loop") - } + private fun getCenterDiff(): Vec3d { + return Vec3d(roundToCenter(mc.player.posX), mc.player.posY, roundToCenter(mc.player.posZ)).subtract(mc.player.positionVector) + } - if (lastHotbarSlot != playerHotbarSlot && playerHotbarSlot != -1) { - if (debugMsgs.value == DebugMsgs.ALL) { - MessageSendHelper.sendChatMessage("$chatName Setting Slot back to = $playerHotbarSlot") - } - if (spoofHotbar.value) { - mc.player.connection.sendPacket(CPacketHeldItemChange(playerHotbarSlot)) + private fun roundToCenter(doubleIn: Double): Double { + return round(doubleIn + 0.5) - 0.5 + } + + private fun runSurround() { + BlockUtils.buildStructure(placeSpeed.value) { + if (isEnabled && CombatManager.isOnTopPriority(this)) { + BlockUtils.getPlaceInfo(mc.player.positionVector.toBlockPos(), SurroundUtils.surroundOffset, it, 2) } else { - mc.player.inventory.currentItem = playerHotbarSlot - } - lastHotbarSlot = playerHotbarSlot - } - - if (autoDisable.value) { - disable() - } - } - - private fun placeBlock(blockPos: BlockPos) { - if (!mc.world.getBlockState(blockPos).material.isReplaceable) { - if (debugMsgs.value == DebugMsgs.ALL) { - MessageSendHelper.sendChatMessage("$chatName Block is already placed, skipping") - } - } else if (!BlockUtils.checkForNeighbours(blockPos) && debugMsgs.value == DebugMsgs.ALL) { - MessageSendHelper.sendChatMessage("$chatName !checkForNeighbours(blockPos), disabling! ") - } else { - if (placeAnimation.value) mc.player.connection.sendPacket(CPacketAnimation(mc.player.activeHand)) - placeBlockExecute(blockPos) - } - - if (NoBreakAnimation.isEnabled) NoBreakAnimation.resetMining() - } - - private fun findObiInHotbar(): Int { - var slot = -1 - for (i in 0..8) { - val stack = mc.player.inventory.getStackInSlot(i) - if (stack != ItemStack.EMPTY && stack.getItem() is ItemBlock) { - val block = (stack.getItem() as ItemBlock).block - if (block is BlockObsidian) { - slot = i - break - } - } - } - return slot - } - - private fun placeBlockExecute(pos: BlockPos) { - val eyesPos = Vec3d(mc.player.posX, mc.player.posY + mc.player.getEyeHeight().toDouble(), mc.player.posZ) - val var3 = EnumFacing.values() - for (side in var3) { - val neighbor = pos.offset(side) - val side2 = side.opposite - - if (!canBeClicked(neighbor)) { - if (debugMsgs.value == DebugMsgs.ALL) { - MessageSendHelper.sendChatMessage("$chatName No neighbor to click at!") - } - } else { - val hitVec = Vec3d(neighbor).add(0.5, 0.5, 0.5).add(Vec3d(side2.directionVec).scale(0.5)) - - if (eyesPos.squareDistanceTo(hitVec) <= 18.0625) { - if (spoofRotations.value) { - faceVectorPacketInstant(hitVec) - } - - var needSneak = false - val blockBelow = mc.world.getBlockState(neighbor).block - - if (BlockUtils.blackList.contains(blockBelow) || BlockUtils.shulkerList.contains(blockBelow)) { - if (debugMsgs.value == DebugMsgs.IMPORTANT) { - MessageSendHelper.sendChatMessage("$chatName Sneak enabled!") - } - needSneak = true - } - - if (needSneak) { - mc.player.connection.sendPacket(CPacketEntityAction(mc.player, CPacketEntityAction.Action.START_SNEAKING)) - } - - val obiSlot = findObiInHotbar() - - if (obiSlot == -1) { - if (debugMsgs.value == DebugMsgs.IMPORTANT) { - MessageSendHelper.sendChatMessage("$chatName No obsidian in hotbar, disabling!") - } - disable() - return - } - - if (lastHotbarSlot != obiSlot) { - if (debugMsgs.value == DebugMsgs.ALL) { - MessageSendHelper.sendChatMessage("$chatName Setting Slot to obsidian at = $obiSlot") - } - - if (spoofHotbar.value) { - mc.player.connection.sendPacket(CPacketHeldItemChange(obiSlot)) - } else { - mc.player.inventory.currentItem = obiSlot - } - lastHotbarSlot = obiSlot - } - - mc.playerController.processRightClickBlock(mc.player, mc.world, neighbor, side2, hitVec, EnumHand.MAIN_HAND) - mc.player.connection.sendPacket(CPacketAnimation(EnumHand.MAIN_HAND)) - - if (needSneak) { - if (debugMsgs.value == DebugMsgs.IMPORTANT) { - MessageSendHelper.sendChatMessage("$chatName Sneak disabled!") - } - mc.player.connection.sendPacket(CPacketEntityAction(mc.player, CPacketEntityAction.Action.STOP_SNEAKING)) - } - return - } - - if (debugMsgs.value == DebugMsgs.ALL) { - MessageSendHelper.sendChatMessage("$chatName Distance > 4.25 blocks!") - } + null } } } - private fun canBeClicked(pos: BlockPos): Boolean { - return getBlock(pos).canCollideCheck(getState(pos), false) + private fun getPlaceInfo(toIgnore: List, attempts: Int = 1): Pair? { + val playerPos = mc.player.positionVector.toBlockPos() + for (offset in SurroundUtils.surroundOffset) { + val pos = playerPos.add(offset) + if (toIgnore.contains(pos)) continue + if (!BlockUtils.isPlaceable(pos)) continue + return BlockUtils.getNeighbour(pos, attempts) ?: continue + } + if (attempts <= 2) { + return getPlaceInfo(toIgnore, attempts + 1) + } + return null } - fun getBlock(pos: BlockPos): Block { - return getState(pos).block + init { + alwaysListening = enableInHole.value + enableInHole.settingListener = Setting.SettingListeners { + alwaysListening = enableInHole.value + } } - - private fun getState(pos: BlockPos): IBlockState { - return mc.world.getBlockState(pos) - } - - private fun faceVectorPacketInstant(vec: Vec3d) { - val rotations = getLegitRotations(vec) - mc.player.connection.sendPacket(CPacketPlayer.Rotation(rotations[0], rotations[1], mc.player.onGround)) - } - - private fun getLegitRotations(vec: Vec3d): FloatArray { - val eyesPos = eyesPos - val diffX = vec.x - eyesPos.x - val diffY = vec.y - eyesPos.y - val diffZ = vec.z - eyesPos.z - - val diffXZ = sqrt(diffX * diffX + diffZ * diffZ) - val yaw = Math.toDegrees(atan2(diffZ, diffX)).toFloat() - 90.0f - val pitch = (-Math.toDegrees(atan2(diffY, diffXZ))).toFloat() - - return floatArrayOf(mc.player.rotationYaw + MathHelper.wrapDegrees(yaw - mc.player.rotationYaw), mc.player.rotationPitch + MathHelper.wrapDegrees(pitch - mc.player.rotationPitch)) - } - - private val eyesPos: Vec3d - get() = Vec3d(mc.player.posX, mc.player.posY + mc.player.getEyeHeight().toDouble(), mc.player.posZ) } \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/misc/AutoTool.kt b/src/main/java/me/zeroeightsix/kami/module/modules/misc/AutoTool.kt index ef7e876dd..3234bf118 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/misc/AutoTool.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/misc/AutoTool.kt @@ -4,17 +4,13 @@ import me.zero.alpine.listener.EventHandler import me.zero.alpine.listener.EventHook import me.zero.alpine.listener.Listener import me.zeroeightsix.kami.module.Module -import me.zeroeightsix.kami.module.modules.combat.Aura.HitMode import me.zeroeightsix.kami.setting.Setting import me.zeroeightsix.kami.setting.Settings +import me.zeroeightsix.kami.util.combat.CombatUtils import net.minecraft.block.state.IBlockState import net.minecraft.enchantment.EnchantmentHelper import net.minecraft.entity.EntityLivingBase -import net.minecraft.entity.EnumCreatureAttribute import net.minecraft.init.Enchantments -import net.minecraft.item.ItemAxe -import net.minecraft.item.ItemSword -import net.minecraft.item.ItemTool import net.minecraftforge.event.entity.player.AttackEntityEvent import net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock import org.lwjgl.input.Mouse @@ -29,7 +25,7 @@ object AutoTool : Module() { private val switchBack = register(Settings.b("SwitchBack", true)) private val timeout = register(Settings.integerBuilder("Timeout").withRange(1, 100).withValue(20).withVisibility { switchBack.value }.build()) private val swapWeapon = register(Settings.b("SwitchWeapon", false)) - private val preferWeapon = register(Settings.e("PreferWeapom", HitMode.SWORD)) + private val preferWeapon = register(Settings.e("Prefer", CombatUtils.PreferWeapon.SWORD)) private var shouldMoveBack = false private var lastSlot = 0 @@ -43,7 +39,7 @@ object AutoTool : Module() { @EventHandler private val attackListener = Listener(EventHook { event: AttackEntityEvent -> if (event.target !is EntityLivingBase) return@EventHook - if (swapWeapon.value) equipBestWeapon(preferWeapon.value) + if (swapWeapon.value) CombatUtils.equipBestWeapon(preferWeapon.value) }) override fun onUpdate() { @@ -83,39 +79,6 @@ object AutoTool : Module() { if (bestSlot != -1) equip(bestSlot) } - @JvmStatic - fun equipBestWeapon(hitMode: HitMode) { - var bestSlot = -1 - var maxDamage = 0.0 - for (i in 0..8) { - val stack = mc.player.inventory.getStackInSlot(i) - if (stack.isEmpty) continue - if (stack.getItem() !is ItemAxe && hitMode == HitMode.AXE) continue - if (stack.getItem() !is ItemSword && hitMode == HitMode.SWORD) continue - - if (stack.getItem() is ItemSword && (hitMode == HitMode.SWORD || hitMode == HitMode.NONE)) { - val damage = (stack.getItem() as ItemSword).attackDamage + EnchantmentHelper.getModifierForCreature(stack, EnumCreatureAttribute.UNDEFINED).toDouble() - if (damage > maxDamage) { - maxDamage = damage - bestSlot = i - } - } else if (stack.getItem() is ItemAxe && (hitMode == HitMode.AXE || hitMode == HitMode.NONE)) { - val damage = (stack.getItem() as ItemTool).attackDamage + EnchantmentHelper.getModifierForCreature(stack, EnumCreatureAttribute.UNDEFINED).toDouble() - if (damage > maxDamage) { - maxDamage = damage - bestSlot = i - } - } else if (stack.getItem() is ItemTool) { - val damage = (stack.getItem() as ItemTool).attackDamage + EnchantmentHelper.getModifierForCreature(stack, EnumCreatureAttribute.UNDEFINED).toDouble() - if (damage > maxDamage) { - maxDamage = damage - bestSlot = i - } - } - } - if (bestSlot != -1) equip(bestSlot) - } - private fun equip(slot: Int) { mc.player.inventory.currentItem = slot mc.playerController.syncCurrentPlayItem() diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/player/AutoEat.kt b/src/main/java/me/zeroeightsix/kami/module/modules/player/AutoEat.kt index f3caf0c49..829c5a48b 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/player/AutoEat.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/player/AutoEat.kt @@ -45,7 +45,7 @@ object AutoEat : Module() { } override fun onUpdate() { - if (Aura.isEnabled && Aura.isAttacking) return + if (Aura.isActive()) return if (eating && !mc.player.isHandActive) { if (lastSlot != -1) { diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/player/Scaffold.kt b/src/main/java/me/zeroeightsix/kami/module/modules/player/Scaffold.kt index d094770de..16876a46d 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/player/Scaffold.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/player/Scaffold.kt @@ -88,10 +88,10 @@ object Scaffold : Module() { setSlotToBlocks(belowBlockPos) /* check if we don't have a block adjacent to the blockPos */ - if (!BlockUtils.checkForNeighbours(blockPos)) return + val neighbor = BlockUtils.getNeighbour(blockPos, attempts = 1)?: return /* place the block */ - if (placeBlocks.value) BlockUtils.placeBlockScaffold(blockPos) + if (placeBlocks.value) BlockUtils.placeBlock(neighbor.second, neighbor.first) /* Reset the slot */ if (!holding) mc.player.inventory.currentItem = oldSlot diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/render/ESP.kt b/src/main/java/me/zeroeightsix/kami/module/modules/render/ESP.kt index 7c100b3ad..b3a4708db 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/render/ESP.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/render/ESP.kt @@ -114,7 +114,7 @@ object ESP : Module() { entityList.add(entity) } } else { - entityList.addAll(getTargetList(player, mob, true, invisible.value, range.value.toFloat())) + entityList.addAll(getTargetList(player, mob, invisible.value, range.value.toFloat())) for (entity in mc.world.loadedEntityList) { if (entity == mc.player) continue if (mc.player.getDistance(entity) > range.value) continue diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/render/EyeFinder.kt b/src/main/java/me/zeroeightsix/kami/module/modules/render/EyeFinder.kt index a573f0e2e..84f9b4e38 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/render/EyeFinder.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/render/EyeFinder.kt @@ -62,9 +62,9 @@ object EyeFinder : Module() { val player = arrayOf(players.value, friends.value, sleeping.value) val mob = arrayOf(mobs.value, passive.value, neutral.value, hostile.value) val entityList = if (isEnabled) { - getTargetList(player, mob, true, invisible.value, range.value.toFloat()) + getTargetList(player, mob, invisible.value, range.value.toFloat()) } else { - emptyArray() + ArrayList() } val cacheMap = HashMap>() for (entity in entityList) { diff --git a/src/main/java/me/zeroeightsix/kami/module/modules/render/Tracers.kt b/src/main/java/me/zeroeightsix/kami/module/modules/render/Tracers.kt index 4c88351b9..4612a4106 100644 --- a/src/main/java/me/zeroeightsix/kami/module/modules/render/Tracers.kt +++ b/src/main/java/me/zeroeightsix/kami/module/modules/render/Tracers.kt @@ -78,9 +78,9 @@ object Tracers : Module() { val player = arrayOf(players.value, friends.value, sleeping.value) val mob = arrayOf(mobs.value, passive.value, neutral.value, hostile.value) val entityList = if (isEnabled) { - getTargetList(player, mob, true, invisible.value, range.value.toFloat()) + getTargetList(player, mob, invisible.value, range.value.toFloat()) } else { - emptyArray() + ArrayList() } val cacheMap = HashMap>() diff --git a/src/main/java/me/zeroeightsix/kami/util/BlockUtils.kt b/src/main/java/me/zeroeightsix/kami/util/BlockUtils.kt index ae5e35527..de3aa8504 100644 --- a/src/main/java/me/zeroeightsix/kami/util/BlockUtils.kt +++ b/src/main/java/me/zeroeightsix/kami/util/BlockUtils.kt @@ -1,18 +1,17 @@ package me.zeroeightsix.kami.util -import net.minecraft.block.Block -import net.minecraft.block.state.IBlockState +import me.zeroeightsix.kami.util.math.RotationUtils import net.minecraft.client.Minecraft import net.minecraft.init.Blocks import net.minecraft.network.play.client.CPacketPlayer +import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock import net.minecraft.util.EnumFacing import net.minecraft.util.EnumHand +import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.MathHelper +import net.minecraft.util.math.RayTraceResult import net.minecraft.util.math.Vec3d -import kotlin.math.atan2 import kotlin.math.floor -import kotlin.math.sqrt /** * Created by hub on 15/06/19 @@ -20,7 +19,6 @@ import kotlin.math.sqrt * Updated by Xiaro on 22/08/20 */ object BlockUtils { - @JvmField val blackList = listOf( Blocks.ENDER_CHEST, Blocks.CHEST, @@ -35,7 +33,6 @@ object BlockUtils { Blocks.ENCHANTING_TABLE ) - @JvmField val shulkerList = listOf( Blocks.WHITE_SHULKER_BOX, Blocks.ORANGE_SHULKER_BOX, @@ -55,100 +52,22 @@ object BlockUtils { Blocks.BLACK_SHULKER_BOX ) - @JvmField - val surroundOffset = arrayOf( - BlockPos(0, -1, 0), // down - BlockPos(0, 0, -1), // north - BlockPos(1, 0, 0), // east - BlockPos(0, 0, 1), // south - BlockPos(-1, 0, 0) // west - ) - private val mc = Minecraft.getMinecraft() - fun placeBlockScaffold(pos: BlockPos) { - val eyesPos = Vec3d(mc.player.posX, - mc.player.posY + mc.player.getEyeHeight(), - mc.player.posZ) - for (side in EnumFacing.values()) { - val neighbor = pos.offset(side) - val side2 = side.opposite - - // check if neighbor can be right clicked - if (!canBeClicked(neighbor)) { - continue - } - val hitVec = Vec3d(neighbor).add(0.5, 0.5, 0.5) - .add(Vec3d(side2.directionVec).scale(0.5)) - - // check if hitVec is within range (4.25 blocks) - if (eyesPos.squareDistanceTo(hitVec) > 18.0625) { - continue - } - - // place block - faceVectorPacketInstant(hitVec) - processRightClickBlock(neighbor, side2, hitVec) - mc.player.swingArm(EnumHand.MAIN_HAND) - mc.rightClickDelayTimer = 4 - return - } + fun placeBlock(pos: BlockPos, facing: EnumFacing) { + val hitVecOffset = getHitVecOffset(facing) + val rotation = RotationUtils.getRotationTo(Vec3d(pos).add(hitVecOffset), true) + val rotationPacket = CPacketPlayer.PositionRotation(mc.player.posX, mc.player.posY, mc.player.posZ, rotation.x.toFloat(), rotation.y.toFloat(), mc.player.onGround) + val placePacket = CPacketPlayerTryUseItemOnBlock(pos, facing, EnumHand.MAIN_HAND, hitVecOffset.x.toFloat(), hitVecOffset.y.toFloat(), hitVecOffset.z.toFloat()) + mc.connection!!.sendPacket(rotationPacket) + mc.connection!!.sendPacket(placePacket) + mc.player.swingArm(EnumHand.MAIN_HAND) } - private fun getLegitRotations(vec: Vec3d): FloatArray { - val eyesPos = eyesPos - val diffX = vec.x - eyesPos.x - val diffY = vec.y - eyesPos.y - val diffZ = vec.z - eyesPos.z - val diffXZ = sqrt(diffX * diffX + diffZ * diffZ) - val yaw = Math.toDegrees(atan2(diffZ, diffX)).toFloat() - 90f - val pitch = (-Math.toDegrees(atan2(diffY, diffXZ))).toFloat() - return floatArrayOf(mc.player.rotationYaw - + MathHelper.wrapDegrees(yaw - mc.player.rotationYaw), - mc.player.rotationPitch + MathHelper - .wrapDegrees(pitch - mc.player.rotationPitch)) - } - - private val eyesPos = Vec3d(mc.player.posX, mc.player.posY + mc.player.getEyeHeight(), mc.player.posZ) - @JvmStatic fun faceVectorPacketInstant(vec: Vec3d) { - val rotations = getLegitRotations(vec) - mc.player.connection.sendPacket(CPacketPlayer.Rotation(rotations[0], - rotations[1], mc.player.onGround)) - } - - private fun processRightClickBlock(pos: BlockPos, side: EnumFacing, hitVec: Vec3d) { - mc.playerController.processRightClickBlock(mc.player, - mc.world, pos, side, hitVec, EnumHand.MAIN_HAND) - } - - @JvmStatic - fun canBeClicked(pos: BlockPos): Boolean { - return getBlock(pos).canCollideCheck(getState(pos), false) - } - - private fun getBlock(pos: BlockPos): Block { - return getState(pos).block - } - - private fun getState(pos: BlockPos): IBlockState { - return mc.world.getBlockState(pos) - } - - fun checkForNeighbours(blockPos: BlockPos): Boolean { - // check if we don't have a block adjacent to blockpos - if (!hasNeighbour(blockPos)) { - // find air adjacent to blockpos that does have a block adjacent to it, let's fill this first as to form a bridge between the player and the original blockpos. necessary if the player is going diagonal. - for (side in EnumFacing.values()) { - val neighbour = blockPos.offset(side) - if (hasNeighbour(neighbour)) { - return true - } - } - return false - } - return true + val rotation = RotationUtils.getRotationTo(vec, true) + mc.player.connection.sendPacket(CPacketPlayer.Rotation(rotation.x.toFloat(), rotation.y.toFloat(), mc.player.onGround)) } fun hasNeighbour(blockPos: BlockPos): Boolean { @@ -161,6 +80,13 @@ object BlockUtils { return false } + fun getHitSide(blockPos: BlockPos): EnumFacing { + return rayTraceTo(blockPos)?.sideHit ?: EnumFacing.UP + } + + fun getHitVecOffset(facing: EnumFacing): Vec3d { + return Vec3d(facing.directionVec).scale(0.5).add(0.5, 0.5, 0.5) + } /** * @return true if there is liquid below @@ -201,21 +127,16 @@ object BlockUtils { return mc.world.getBlockState(pos).block == Blocks.WATER } + fun rayTraceTo(blockPos: BlockPos): RayTraceResult? { + return mc.world.rayTraceBlocks(mc.player.getPositionEyes(1f), Vec3d(blockPos).add(0.5, 0.5, 0.5)) + } + /** * Checks if given [pos] is able to place block in it * * @return true playing is not colliding with [pos] and there is block below it */ - fun isPlaceable(pos: BlockPos): Boolean { - val bBox = mc.player.boundingBox - val xArray = arrayOf(floor(bBox.minX).toInt(), floor(bBox.maxX).toInt()) - val yArray = arrayOf(floor(bBox.minY).toInt(), floor(bBox.maxY).toInt()) - val zArray = arrayOf(floor(bBox.minZ).toInt(), floor(bBox.maxZ).toInt()) - for (x in 0..1) for (y in 0..1) for (z in 0..1) { - if (pos == BlockPos(xArray[x], yArray[y], zArray[z])) return false - } - return mc.world.isAirBlock(pos) && !mc.world.isAirBlock(pos.down()) - } + fun isPlaceable(pos: BlockPos) = mc.world.getBlockState(pos).material.isReplaceable && mc.world.checkNoEntityCollision(AxisAlignedBB(pos)) /** * Checks if given [pos] is able to chest (air above) block in it @@ -223,6 +144,70 @@ object BlockUtils { * @return true playing is not colliding with [pos] and there is block below it */ fun isPlaceableForChest(pos: BlockPos): Boolean { - return isPlaceable(pos) && mc.world.isAirBlock(pos.up()) + return isPlaceable(pos) && !mc.world.getBlockState(pos.down()).material.isReplaceable && mc.world.isAirBlock(pos.up()) + } + + fun buildStructure(placeSpeed: Float, getPlaceInfo: (HashSet) -> Pair?) { + val emptyHashSet = HashSet() + val placed = HashSet() + var placeCount = 0 + while (getPlaceInfo(emptyHashSet) != null) { + val placingInfo = getPlaceInfo(placed) ?: getPlaceInfo(emptyHashSet)?: break + placeCount++ + placed.add(placingInfo.second.offset(placingInfo.first)) + doPlace(placingInfo.second, placingInfo.first, placeSpeed) + if (placeCount >= 4) { + Thread.sleep(100L) + placeCount = 0 + placed.clear() + } + } + } + + fun getPlaceInfo(center: BlockPos?, structureOffset: Array, toIgnore: HashSet, maxAttempts: Int, attempts: Int = 1): Pair? { + center?.let { + for (offset in structureOffset) { + val pos = it.add(offset) + if (toIgnore.contains(pos)) continue + if (!isPlaceable(pos)) continue + return getNeighbour(pos, attempts) ?: continue + } + if (attempts <= maxAttempts) return getPlaceInfo(it, structureOffset, toIgnore, maxAttempts, attempts + 1) + } + return null + } + + fun getNeighbour(blockPos: BlockPos, attempts: Int = 3, range: Float = 4.25f, toIgnore: HashSet = HashSet()): Pair? { + for (side in EnumFacing.values()) { + val pos = blockPos.offset(side) + if (!toIgnore.add(pos)) continue + if (mc.world.getBlockState(pos).material.isReplaceable) continue + if (mc.player.getPositionEyes(1f).distanceTo(Vec3d(pos).add(getHitVecOffset(side))) > range) continue + return Pair(side.opposite, pos) + } + if (attempts > 1) { + toIgnore.add(blockPos) + for (side in EnumFacing.values()) { + val pos = blockPos.offset(side) + if (!isPlaceable(pos)) continue + return getNeighbour(pos, attempts - 1, range, toIgnore) ?: continue + } + } + return null + } + + /** + * Placing function for multithreading only + */ + fun doPlace(pos: BlockPos, facing: EnumFacing, placeSpeed: Float) { + val hitVecOffset = getHitVecOffset(facing) + val rotation = RotationUtils.getRotationTo(Vec3d(pos).add(hitVecOffset), true) + val rotationPacket = CPacketPlayer.PositionRotation(mc.player.posX, mc.player.posY, mc.player.posZ, rotation.x.toFloat(), rotation.y.toFloat(), mc.player.onGround) + val placePacket = CPacketPlayerTryUseItemOnBlock(pos, facing, EnumHand.MAIN_HAND, hitVecOffset.x.toFloat(), hitVecOffset.y.toFloat(), hitVecOffset.z.toFloat()) + mc.connection!!.sendPacket(rotationPacket) + Thread.sleep((40f / placeSpeed).toLong()) + mc.connection!!.sendPacket(placePacket) + mc.player.swingArm(EnumHand.MAIN_HAND) + Thread.sleep((10f / placeSpeed).toLong()) } } \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/util/CenterPlayer.kt b/src/main/java/me/zeroeightsix/kami/util/CenterPlayer.kt deleted file mode 100644 index fbf4dd5a3..000000000 --- a/src/main/java/me/zeroeightsix/kami/util/CenterPlayer.kt +++ /dev/null @@ -1,38 +0,0 @@ -package me.zeroeightsix.kami.util - -import net.minecraft.client.Minecraft -import net.minecraft.network.play.client.CPacketPlayer -import kotlin.math.round - -/** - * @author Xiaro - */ -object CenterPlayer { - private val mc = Minecraft.getMinecraft() - - /** - * @return the position x of the nearest block center - */ - fun getPosX(offsetMultiplier: Float): Double { - val offset = round(mc.player.posX + 0.5) - 0.5 - mc.player.posX - return mc.player.posX + offset * offsetMultiplier - } - - /** - * @return the position z of the nearest block center - */ - fun getPosZ(offsetMultiplier: Float): Double { - val offset = round(mc.player.posZ + 0.5) - 0.5 - mc.player.posZ - return mc.player.posZ + offset * offsetMultiplier - } - - /** - * Move player to the nearest block center - */ - fun centerPlayer(offsetMultiplier: Float) { - val posX = getPosX(offsetMultiplier) - val posZ = getPosZ(offsetMultiplier) - mc.player.connection.sendPacket(CPacketPlayer.Position(posX, mc.player.posY, posZ, mc.player.onGround)) - mc.player.setPosition(posX, mc.player.posY, posZ) - } -} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/util/EntityUtils.kt b/src/main/java/me/zeroeightsix/kami/util/EntityUtils.kt index a1b5ad790..358162f43 100644 --- a/src/main/java/me/zeroeightsix/kami/util/EntityUtils.kt +++ b/src/main/java/me/zeroeightsix/kami/util/EntityUtils.kt @@ -201,7 +201,7 @@ object EntityUtils { DISTANCE, HEALTH } - fun getPrioritizedTarget(targetList: Array, priority: EntityPriority): Entity { + fun getPrioritizedTarget(targetList: ArrayList, priority: EntityPriority): EntityLivingBase { var entity = targetList[0] when (priority) { EntityPriority.DISTANCE -> { @@ -215,9 +215,9 @@ object EntityUtils { } } EntityPriority.HEALTH -> { - var health = (targetList[0] as EntityLivingBase).health + var health = targetList[0].health for (i in targetList.indices) { - val currentHealth = (targetList[i] as EntityLivingBase).health + val currentHealth = targetList[i].health if (currentHealth < health) { health = currentHealth entity = targetList[i] @@ -228,12 +228,12 @@ object EntityUtils { return entity } - fun getTargetList(player: Array, mobs: Array, ignoreWalls: Boolean, invisible: Boolean, range: Float): Array { - if (mc.world.loadedEntityList == null) return emptyArray() - val entityList = ArrayList() + fun getTargetList(player: Array, mobs: Array, invisible: Boolean, range: Float): ArrayList { + if (mc.world.loadedEntityList == null) return ArrayList() + val entityList = ArrayList() for (entity in mc.world.loadedEntityList) { /* Entity type check */ - if (!isLiving(entity)) continue + if (entity !is EntityLivingBase) continue if (entity.name == mc.player.name) continue if (entity is EntityPlayer) { if (!player[0]) continue @@ -242,12 +242,11 @@ object EntityUtils { if (mc.player.isRiding && entity == mc.player.ridingEntity) continue // Riding entity check if (mc.player.getDistance(entity) > range) continue // Distance check - if ((entity as EntityLivingBase).health <= 0) continue // HP check - if (!ignoreWalls && !mc.player.canEntityBeSeen(entity) && !canEntityFeetBeSeen(entity)) continue // If walls is on & you can't see the feet or head of the target, skip. 2 raytraces needed + if (entity.health <= 0) continue // HP check if (!invisible && entity.isInvisible) continue entityList.add(entity) } - return entityList.toTypedArray() + return entityList } @JvmStatic @@ -263,9 +262,9 @@ object EntityUtils { fun canEntityHitboxBeSeen(entity: Entity): Vec3d? { val playerPos = mc.player.positionVector.add(0.0, mc.player.eyeHeight.toDouble(), 0.0) val box = entity.boundingBox - val xArray = arrayOf(box.minX, box.maxX) - val yArray = arrayOf(box.minY, box.maxY) - val zArray = arrayOf(box.minZ, box.maxZ) + val xArray = arrayOf(box.minX + 0.1, box.maxX - 0.1) + val yArray = arrayOf(box.minY + 0.1, box.maxY - 0.1) + val zArray = arrayOf(box.minZ + 0.1, box.maxZ - 0.1) for (x in xArray) for (y in yArray) for (z in zArray) { val vertex = Vec3d(x, y, z) diff --git a/src/main/java/me/zeroeightsix/kami/util/InventoryUtils.kt b/src/main/java/me/zeroeightsix/kami/util/InventoryUtils.kt index d4f768fb2..15a11b4ca 100644 --- a/src/main/java/me/zeroeightsix/kami/util/InventoryUtils.kt +++ b/src/main/java/me/zeroeightsix/kami/util/InventoryUtils.kt @@ -70,7 +70,7 @@ object InventoryUtils { * * @return Array contains full inventory slot index, null if no item found */ - fun getSlotsFullInv(min: Int, max: Int, itemId: Int): Array? { + fun getSlotsFullInv(min: Int = 9, max: Int = 44, itemId: Int): Array? { val slots = arrayListOf() for (i in min..max) { if (getIdFromItem(mc.player.inventoryContainer.inventory[i].getItem()) == itemId) { @@ -106,14 +106,7 @@ object InventoryUtils { * @return Number of item with given [itemId] in hotbar */ fun countItemHotbar(itemId: Int): Int { - val itemList = getSlots(0, 8, itemId) - var currentCount = 0 - if (itemList != null) { - for (i in itemList) { - currentCount += mc.player.inventory.getStackInSlot(i).count - } - } - return currentCount + return countItem(36, 44, itemId) } /** @@ -122,14 +115,7 @@ object InventoryUtils { * @return Number of item with given [itemId] in non hotbar */ fun countItemNoHotbar(itemId: Int): Int { - val itemList = getSlots(9, 35, itemId) - var currentCount = 0 - if (itemList != null) { - for (i in itemList) { - currentCount += mc.player.inventory.getStackInSlot(i).count - } - } - return currentCount + return countItem(0, 35, itemId) } /** @@ -139,14 +125,7 @@ object InventoryUtils { */ @JvmStatic fun countItemAll(itemId: Int): Int { - val itemList = getSlots(0, 35, itemId) - var currentCount = 0 - if (itemList != null) { - for (i in itemList) { - currentCount += mc.player.inventory.getStackInSlot(i).count - } - } - return currentCount + return countItem(0, 45, itemId) } /** @@ -155,12 +134,10 @@ object InventoryUtils { * @return Number of item with given [itemId] from slot [min] to slot [max] */ fun countItem(min: Int, max: Int, itemId: Int): Int { - val itemList = getSlots(min, max, itemId) + val itemList = getSlotsFullInv(min, max, itemId) var currentCount = 0 - if (itemList != null) { - for (i in itemList) { - currentCount += mc.player.inventory.getStackInSlot(i).count - } + if (itemList != null) for (i in itemList) { + currentCount += mc.player.inventoryContainer.inventory[i].count } return currentCount } @@ -209,18 +186,21 @@ object InventoryUtils { * Move the item in [slotFrom] to [slotTo] in player inventory, * if [slotTo] contains an item, then move it to [slotFrom] */ - fun moveToSlot(slotFrom: Int, slotTo: Int) { - moveToSlot(0, slotFrom, slotTo) + fun moveToSlot(slotFrom: Int, slotTo: Int): ShortArray { + val transactionIds = moveToSlot(0, slotFrom, slotTo) + return transactionIds } /** * Move the item in [slotFrom] to [slotTo] in [windowId], * if [slotTo] contains an item, then move it to [slotFrom] */ - fun moveToSlot(windowId: Int, slotFrom: Int, slotTo: Int) { - inventoryClick(windowId, slotFrom, type = ClickType.PICKUP) - inventoryClick(windowId, slotTo, type = ClickType.PICKUP) - inventoryClick(windowId, slotFrom, type = ClickType.PICKUP) + fun moveToSlot(windowId: Int, slotFrom: Int, slotTo: Int): ShortArray { + return shortArrayOf( + inventoryClick(windowId, slotFrom, type = ClickType.PICKUP), + inventoryClick(windowId, slotTo, type = ClickType.PICKUP), + inventoryClick(windowId, slotFrom, type = ClickType.PICKUP) + ) } /** @@ -234,16 +214,18 @@ object InventoryUtils { /** * Quick move (Shift + Click) the item in [slotFrom] in player inventory + * + * @return Transaction id */ - fun quickMoveSlot(slotFrom: Int) { - quickMoveSlot(0, slotFrom) + fun quickMoveSlot(slotFrom: Int): Short { + return quickMoveSlot(0, slotFrom) } /** * Quick move (Shift + Click) the item in [slotFrom] in specified [windowId] */ - fun quickMoveSlot(windowId: Int, slotFrom: Int) { - inventoryClick(windowId, slotFrom, type = ClickType.QUICK_MOVE) + fun quickMoveSlot(windowId: Int, slotFrom: Int): Short { + return inventoryClick(windowId, slotFrom, type = ClickType.QUICK_MOVE) } /** @@ -271,11 +253,17 @@ object InventoryUtils { inventoryClick(slot = slot, type = ClickType.PICKUP) } - private fun inventoryClick(windowId: Int = 0, slot: Int, mousedButton: Int = 0, type: ClickType) { + /** + * Performs inventory clicking in specific window, slot, mouseButton, add click type + * + * @return Transaction id + */ + fun inventoryClick(windowId: Int = 0, slot: Int, mouseButton: Int = 0, type: ClickType): Short { val container = if (windowId == 0) mc.player.inventoryContainer else mc.player.openContainer val transactionID = container.getNextTransactionID(mc.player.inventory) - val itemStack = container.slotClick(slot, mousedButton, type, mc.player) - mc.connection!!.sendPacket(CPacketClickWindow(windowId, slot, mousedButton, type, itemStack, transactionID)) + val itemStack = container.slotClick(slot, mouseButton, type, mc.player) + mc.connection!!.sendPacket(CPacketClickWindow(windowId, slot, mouseButton, type, itemStack, transactionID)) + return transactionID } /* End of inventory management */ } \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/util/MotionTracker.kt b/src/main/java/me/zeroeightsix/kami/util/MotionTracker.kt new file mode 100644 index 000000000..cbb6af1e9 --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/util/MotionTracker.kt @@ -0,0 +1,125 @@ +package me.zeroeightsix.kami.util + +import me.zero.alpine.listener.EventHandler +import me.zero.alpine.listener.EventHook +import me.zero.alpine.listener.Listener +import me.zeroeightsix.kami.KamiMod +import me.zeroeightsix.kami.util.graphics.KamiTessellator +import net.minecraft.entity.Entity +import net.minecraft.util.math.AxisAlignedBB +import net.minecraft.util.math.Vec3d +import net.minecraft.world.World +import net.minecraftforge.fml.common.gameevent.TickEvent +import java.util.* + +/** + * Tracking the motion of an Entity tick by tick + */ +class MotionTracker(targetIn: Entity?, private val trackLength: Int = 20) { + var target: Entity? = targetIn + set(value) { + if (value != field) { + reset() + field = value + } + } + private val motionLog = LinkedList() + private var prevMotion = Vec3d(0.0, 0.0, 0.0) + private var motion = Vec3d(0.0, 0.0, 0.0) + + @EventHandler + private val onUpdateListener = Listener(EventHook { event: TickEvent.ClientTickEvent -> + if (Wrapper.player == null || Wrapper.world == null) return@EventHook + target?.let { + motionLog.add(calcActualMotion(it)) + while (motionLog.size > trackLength) motionLog.pollFirst() + prevMotion = motion + motion = calcAverageMotion() + } + }) + + /** + * Calculate the actual motion of given entity + * + * @param entity The entity for motion calculation + * @return Actual motion vector + */ + private fun calcActualMotion(entity: Entity): Vec3d { + return entity.positionVector.subtract(entity.prevPosX, entity.prevPosY, entity.prevPosZ) + } + + /** + * Calculate the average motion of the target entity in [trackLength] + * + * @return Average motion vector + */ + private fun calcAverageMotion(): Vec3d { + var sumX = 0.0 + var sumY = 0.0 + var sumZ = 0.0 + for (motion in motionLog) { + sumX += motion.x + sumY += motion.y + sumZ += motion.z + } + return Vec3d(sumX, sumY, sumZ).scale(1.0 / motionLog.size) + } + + /** + * Calculate the predicted position of the target entity based on [calcAverageMotion] + * + * @param [ticksAhead] Amount of prediction ahead + * @param [interpolation] Whether to return interpolated position or not, default value is false (no interpolation) + * @return Predicted position of the target entity + */ + fun calcPositionAhead(ticksAhead: Int, interpolation: Boolean = false): Vec3d? { + return target?.let { target -> + calcMovedVectorAhead(ticksAhead, interpolation)?.let { + val partialTicks = if (interpolation) KamiTessellator.pTicks() else 1f + EntityUtils.getInterpolatedPos(target, partialTicks).add(it) + } + } + } + + /** + * Calculate the predicted moved vector of the target entity based on [calcAverageMotion] + * + * @param [ticksAhead] Amount of prediction ahead + * @param [interpolation] Whether to return interpolated position or not, default value is false (no interpolation) + * @return Predicted moved vector of the target entity + */ + fun calcMovedVectorAhead(ticksAhead: Int, interpolation: Boolean = false): Vec3d? { + return Wrapper.world?.let { world -> + target?.let { + val partialTicks = if (interpolation) KamiTessellator.pTicks() else 1f + val averageMotion = prevMotion.add(motion.subtract(prevMotion).scale(partialTicks.toDouble())) + var movedVec = Vec3d(0.0, 0.0, 0.0) + for (ticks in 0..ticksAhead) { + movedVec = if (canMove(world, it.boundingBox, movedVec.add(averageMotion))) { // Attempt to move with full motion + movedVec.add(averageMotion) + } else if (canMove(world, it.boundingBox, movedVec.add(averageMotion.x, 0.0, averageMotion.z))) { // Attempt to move horizontally + movedVec.add(averageMotion.x, 0.0, averageMotion.z) + } else break + } + movedVec + } + } + } + + private fun canMove(world: World, bbox: AxisAlignedBB, offset: Vec3d): Boolean { + return !world.collidesWithAnyBlock(bbox.offset(offset)) + } + + /** + * Reset motion tracker + */ + fun reset() { + motionLog.clear() + prevMotion = Vec3d(0.0, 0.0, 0.0) + motion = Vec3d(0.0, 0.0, 0.0) + } + + init { + KamiMod.EVENT_BUS.subscribe(this) + } +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/util/combat/CombatUtils.kt b/src/main/java/me/zeroeightsix/kami/util/combat/CombatUtils.kt new file mode 100644 index 000000000..cb69947ab --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/util/combat/CombatUtils.kt @@ -0,0 +1,127 @@ +package me.zeroeightsix.kami.util.combat + +import me.zeroeightsix.kami.util.InventoryUtils +import net.minecraft.client.Minecraft +import net.minecraft.enchantment.Enchantment +import net.minecraft.enchantment.EnchantmentHelper +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.EnumCreatureAttribute +import net.minecraft.entity.SharedMonsterAttributes +import net.minecraft.entity.monster.EntityMob +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.init.Enchantments +import net.minecraft.init.MobEffects +import net.minecraft.item.ItemAxe +import net.minecraft.item.ItemStack +import net.minecraft.item.ItemSword +import net.minecraft.item.ItemTool +import net.minecraft.util.CombatRules +import net.minecraft.util.DamageSource +import net.minecraft.util.math.MathHelper +import kotlin.concurrent.fixedRateTimer +import kotlin.math.max +import kotlin.math.round + +object CombatUtils { + private val mc: Minecraft = Minecraft.getMinecraft() + + @JvmStatic + fun calcDamageFromPlayer(entity: EntityPlayer, assumeCritical: Boolean = false): Float { + val itemStack = entity.heldItemMainhand + var damage = when (val item = itemStack.getItem()) { + is ItemSword -> item.attackDamage + is ItemTool -> item.attackDamage + else -> 1f + } + val sharpnessLevel = getEnchantmentLevel(itemStack, 16) // 16 is the id for Sharpness + damage += sharpnessLevel * 0.5f + 0.5f + if (assumeCritical) damage *= 1.5f + return damage + } + + @JvmStatic + fun calcDamageFromMob(entity: EntityMob): Float { + var damage = entity.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).attributeValue.toFloat() + damage += EnchantmentHelper.getModifierForCreature(entity.heldItemMainhand, mc.player.creatureAttribute) + return calcDamage(mc.player, damage) + } + + @JvmStatic + fun calcDamage(entity: EntityLivingBase, damageIn: Float = 100f, source: DamageSource = DamageSource.GENERIC, roundDamage: Boolean = false): Float { + if (entity is EntityPlayer && entity.isCreative) return 0.0f // Return 0 directly if entity is a player and in creative mode + var damage = CombatRules.getDamageAfterAbsorb(damageIn, entity.totalArmorValue.toFloat(), entity.getEntityAttribute(SharedMonsterAttributes.ARMOR_TOUGHNESS).attributeValue.toFloat()) + + if (source != DamageSource.OUT_OF_WORLD) { + entity.getActivePotionEffect(MobEffects.RESISTANCE)?.let { + damage *= max(1f - it.amplifier * 0.2f, 0f) + } + } + if (entity is EntityPlayer) { + damage *= getProtectionModifier(entity, source) + } + return if (roundDamage) round(damage) else damage + } + + @JvmStatic + fun getProtectionModifier(entity: EntityPlayer, damageSource: DamageSource): Float { + var modifier = 0 + for (armor in entity.armorInventoryList) { + if (armor.isEmpty()) continue // Skip if item stack is empty + val nbtTagList = armor.enchantmentTagList + for (i in 0 until nbtTagList.tagCount()) { + val id = nbtTagList.getCompoundTagAt(i).getShort("id").toInt() + val level = nbtTagList.getCompoundTagAt(i).getShort("lvl").toInt() + Enchantment.getEnchantmentByID(id)?.let { modifier += it.calcModifierDamage(level, damageSource) } + } + } + modifier = MathHelper.clamp(modifier, 0, 20) + return (1.0f - modifier / 25.0f) + } + + @JvmStatic + fun getEnchantmentLevel(itemStack: ItemStack, enchantmentId: Int): Int { + for (i in 0 until itemStack.enchantmentTagList.tagCount()) { + val id = itemStack.enchantmentTagList.getCompoundTagAt(i).getShort("id").toInt() + if (id != enchantmentId) continue + return itemStack.enchantmentTagList.getCompoundTagAt(i).getShort("lvl").toInt() + } + return 0 + } + + @JvmStatic + fun equipBestWeapon(hitMode: PreferWeapon = PreferWeapon.NONE) { + var bestSlot = -1 + var maxDamage = 0.0 + for (i in 0..8) { + val stack = mc.player.inventory.getStackInSlot(i) + if (stack.isEmpty) continue + if (stack.getItem() !is ItemAxe && hitMode == PreferWeapon.AXE) continue + if (stack.getItem() !is ItemSword && hitMode == PreferWeapon.SWORD) continue + + if (stack.getItem() is ItemSword && (hitMode == PreferWeapon.SWORD || hitMode == PreferWeapon.NONE)) { + val damage = (stack.getItem() as ItemSword).attackDamage + EnchantmentHelper.getModifierForCreature(stack, EnumCreatureAttribute.UNDEFINED).toDouble() + if (damage > maxDamage) { + maxDamage = damage + bestSlot = i + } + } else if (stack.getItem() is ItemAxe && (hitMode == PreferWeapon.AXE || hitMode == PreferWeapon.NONE)) { + val damage = (stack.getItem() as ItemTool).attackDamage + EnchantmentHelper.getModifierForCreature(stack, EnumCreatureAttribute.UNDEFINED).toDouble() + if (damage > maxDamage) { + maxDamage = damage + bestSlot = i + } + } else if (stack.getItem() is ItemTool) { + val damage = (stack.getItem() as ItemTool).attackDamage + EnchantmentHelper.getModifierForCreature(stack, EnumCreatureAttribute.UNDEFINED).toDouble() + if (damage > maxDamage) { + maxDamage = damage + bestSlot = i + } + } + } + if (bestSlot != -1) InventoryUtils.swapSlot(bestSlot) + } + + enum class PreferWeapon { + SWORD, AXE, NONE + } +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/util/combat/CrystalUtils.kt b/src/main/java/me/zeroeightsix/kami/util/combat/CrystalUtils.kt new file mode 100644 index 000000000..a298d27c1 --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/util/combat/CrystalUtils.kt @@ -0,0 +1,137 @@ +package me.zeroeightsix.kami.util.combat + +import me.zeroeightsix.kami.util.math.VectorUtils +import net.minecraft.client.Minecraft +import net.minecraft.entity.Entity +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.item.EntityEnderCrystal +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.init.Blocks +import net.minecraft.util.DamageSource +import net.minecraft.util.math.AxisAlignedBB +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d +import net.minecraft.world.Explosion +import kotlin.math.ceil +import kotlin.math.floor +import kotlin.math.max + +object CrystalUtils { + private val mc = Minecraft.getMinecraft() + + /* Position Finding */ + @JvmStatic + fun getPlacePos(target: EntityLivingBase?, center: Entity?, radius: Float): Map { + if (target == null || center == null) return emptyMap() + val centerPos = if (center == mc.player) center.getPositionEyes(1f) else center.positionVector + val posList = VectorUtils.getBlockPosInSphere(centerPos, radius) + val damagePosMap = HashMap() + for (pos in posList) { + if (!canPlace(pos, target)) continue + damagePosMap[calcDamage(pos, target)] = pos + } + return damagePosMap + } + + fun getAxisRange(d1: Double, d2: Float): IntRange { + return IntRange(floor(d1 - d2).toInt(), ceil(d1 + d2).toInt()) + } + + @JvmStatic + fun getCrystalList(range: Float): ArrayList { + return getCrystalList(mc.player.positionVector, range) + } + + @JvmStatic + fun getCrystalList(center: Vec3d, range: Float): ArrayList { + val crystalList = ArrayList() + val entityList = ArrayList() + synchronized(mc.world.loadedEntityList) { + entityList.addAll(mc.world.loadedEntityList) + } + for (entity in entityList) { + if (entity.isDead) continue + if (entity !is EntityEnderCrystal) continue + if (center.distanceTo(entity.positionVector) > range) continue + crystalList.add(entity) + } + return crystalList + } + + @JvmStatic + fun canPlace(blockPos: BlockPos): Boolean { + val placingBB = getCrystalPlacingBB(blockPos.up()) + return mc.world.checkNoEntityCollision(placingBB) + && (mc.world.getBlockState(blockPos).block == Blocks.BEDROCK + || mc.world.getBlockState(blockPos).block == Blocks.OBSIDIAN) + && !mc.world.checkBlockCollision(placingBB) + } + + /** Checks colliding with blocks and given entity only */ + @JvmStatic + fun canPlace(blockPos: BlockPos, entity: Entity): Boolean { + val entityBB = entity.boundingBox + val placingBB = getCrystalPlacingBB(blockPos.up()) + return !entityBB.intersects(placingBB) + && (mc.world.getBlockState(blockPos).block == Blocks.BEDROCK + || mc.world.getBlockState(blockPos).block == Blocks.OBSIDIAN) + && !mc.world.checkBlockCollision(placingBB) + } + + /** Checks if the block below is valid for placing crystal */ + @JvmStatic + fun canPlaceOn(blockPos: BlockPos) = mc.world.getBlockState(blockPos.down()).block == Blocks.BEDROCK || mc.world.getBlockState(blockPos.down()).block == Blocks.OBSIDIAN + + @JvmStatic + private fun getCrystalPlacingBB(blockPos: BlockPos): AxisAlignedBB { + return crystalPlacingBB.offset(Vec3d(blockPos).add(0.5, 0.0, 0.5)) + } + + private val crystalPlacingBB: AxisAlignedBB get() = AxisAlignedBB(-0.5, 0.0, -0.5, 0.5, 2.0, 0.5) + + /* Checks colliding with all entity */ + @JvmStatic + fun canPlaceCollide(blockPos: BlockPos): Boolean { + val placingBB = getCrystalPlacingBB(blockPos.up()) + return mc.world.checkNoEntityCollision(placingBB) + } + /* End of position finding */ + + /* Damage calculation */ + @JvmStatic + fun calcDamage(crystal: EntityEnderCrystal, entity: EntityLivingBase, calcBlastReduction: Boolean = true): Float { + return calcDamage(crystal.positionVector, entity, calcBlastReduction) + } + + @JvmStatic + fun calcDamage(blockPos: BlockPos, entity: EntityLivingBase, calcBlastReduction: Boolean = true): Float { + return calcDamage(Vec3d(blockPos).add(0.5, 1.0, 0.5), entity, calcBlastReduction) + } + + @JvmStatic + fun calcDamage(pos: Vec3d, entity: EntityLivingBase, calcBlastReduction: Boolean = true): Float { + if (entity is EntityPlayer && entity.isCreative) return 0.0f // Return 0 directly if entity is a player and in creative mode + var damage = calcRawDamage(pos, entity) + if (calcBlastReduction) damage = CombatUtils.calcDamage(entity, damage, getDamageSource(pos)) + if (entity is EntityPlayer) damage *= getDamageMultiplier() + return max(damage, 0f) + } + + @JvmStatic + private fun calcRawDamage(pos: Vec3d, entity: Entity): Float { + val distance = pos.distanceTo(entity.positionVector) + val v = (1.0 - (distance / 12.0)) * entity.world.getBlockDensity(pos, entity.boundingBox) + return ((v * v + v) / 2.0 * 84.0 + 1.0).toFloat() + } + + @JvmStatic + private fun getDamageSource(damagePos: Vec3d): DamageSource { + return DamageSource.causeExplosionDamage(Explosion(mc.world, mc.player, damagePos.x, damagePos.y, damagePos.z, 6F, false, true)) + } + + @JvmStatic + private fun getDamageMultiplier(): Float { + return mc.world.difficulty.id * 0.5f + } + /* End of damage calculation */ +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/util/combat/SurroundUtils.kt b/src/main/java/me/zeroeightsix/kami/util/combat/SurroundUtils.kt new file mode 100644 index 000000000..64bd169b7 --- /dev/null +++ b/src/main/java/me/zeroeightsix/kami/util/combat/SurroundUtils.kt @@ -0,0 +1,65 @@ +package me.zeroeightsix.kami.util.combat + +import me.zeroeightsix.kami.util.Wrapper +import net.minecraft.block.Block +import net.minecraft.entity.Entity +import net.minecraft.init.Blocks +import net.minecraft.util.math.BlockPos +import kotlin.math.floor + +/** + * @author Xiaro + * + * Created by Xiaro on 08/09/20 + */ +object SurroundUtils { + private val mc = Wrapper.minecraft + + @JvmStatic + val surroundOffset = arrayOf( + BlockPos(0, -1, 0), // down + BlockPos(0, 0, -1), // north + BlockPos(1, 0, 0), // east + BlockPos(0, 0, 1), // south + BlockPos(-1, 0, 0) // west + ) + + @JvmStatic + val surroundOffsetNoFloor = arrayOf( + BlockPos(0, 0, -1), // north + BlockPos(1, 0, 0), // east + BlockPos(0, 0, 1), // south + BlockPos(-1, 0, 0) // west + ) + + @JvmStatic + fun checkHole(entity: Entity): HoleType { + return checkHole(BlockPos(floor(entity.posX).toInt(), floor(entity.posY).toInt(), floor(entity.posZ).toInt())) + } + + @JvmStatic + fun checkHole(pos: BlockPos): HoleType { + // Must be a 1 * 3 * 1 empty space + if (!mc.world.isAirBlock(pos) || !mc.world.isAirBlock(pos.up()) || !mc.world.isAirBlock(pos.up().up())) return HoleType.NONE + + var type = HoleType.BEDROCK + for (offset in surroundOffset) { + val block = mc.world.getBlockState(pos.add(offset)).block + if (!checkBlock(block)) { + type = HoleType.NONE + break + } + if (block != Blocks.BEDROCK) type = HoleType.OBBY + } + return type + } + + @JvmStatic + fun checkBlock(block: Block): Boolean { + return block == Blocks.BEDROCK || block == Blocks.OBSIDIAN || block == Blocks.ENDER_CHEST || block == Blocks.ANVIL + } + + enum class HoleType { + NONE, OBBY, BEDROCK + } +} \ No newline at end of file diff --git a/src/main/java/me/zeroeightsix/kami/util/math/RotationUtils.kt b/src/main/java/me/zeroeightsix/kami/util/math/RotationUtils.kt index 8e50b281c..59c50d08f 100644 --- a/src/main/java/me/zeroeightsix/kami/util/math/RotationUtils.kt +++ b/src/main/java/me/zeroeightsix/kami/util/math/RotationUtils.kt @@ -2,11 +2,10 @@ package me.zeroeightsix.kami.util.math import me.zeroeightsix.kami.util.EntityUtils import me.zeroeightsix.kami.util.Wrapper -import me.zeroeightsix.kami.util.graphics.KamiTessellator import net.minecraft.entity.Entity +import net.minecraft.util.math.MathHelper import net.minecraft.util.math.Vec3d -import kotlin.math.atan2 -import kotlin.math.sqrt +import kotlin.math.* /** * Utils for calculating angles and rotations @@ -14,14 +13,50 @@ import kotlin.math.sqrt object RotationUtils { val mc = Wrapper.minecraft - fun faceEntity(entity: Entity) { - val rotation = getRotationToEntity(entity) + fun faceEntityClosest(entity: Entity, pTicks: Float = 1f) { + val rotation = getRotationToEntityClosest(entity, pTicks) mc.player.rotationYaw = rotation.x.toFloat() mc.player.rotationPitch = rotation.y.toFloat() } - fun getRotationToEntity(entity: Entity): Vec2d { - val posTo = EntityUtils.getInterpolatedPos(entity, KamiTessellator.pTicks()) + fun faceEntity(entity: Entity, pTicks: Float = 1f) { + val rotation = getRotationToEntity(entity, pTicks) + mc.player.rotationYaw = rotation.x.toFloat() + mc.player.rotationPitch = rotation.y.toFloat() + } + + fun getRelativeRotation(entity: Entity, pTicks: Float = 1f): Double { + return getRotationDiff(getRotationToEntity(entity, pTicks), getPlayerRotation()) + } + + fun getRelativeRotation(posTo: Vec3d, pTicks: Float = 1f): Double { + return getRotationDiff(getRotationTo(posTo, true, pTicks), getPlayerRotation()) + } + + fun getPlayerRotation(pTicks: Float = 1f): Vec2d { + val rotation = Vec2d(mc.player.rotationYaw.toDouble(), mc.player.rotationPitch.toDouble()) + val prevRotation = Vec2d(mc.player.rotationYaw.toDouble(), mc.player.rotationPitch.toDouble()) + return prevRotation.add(rotation.subtract(prevRotation).multiply(pTicks.toDouble())) + } + + fun getRotationDiff(r1: Vec2d, r2: Vec2d): Double { + val r1Radians = r1.toRadians() + val r2Radians = r2.toRadians() + return Math.toDegrees(acos(cos(r1Radians.y) * cos(r2Radians.y) * cos(r1Radians.x - r2Radians.x) + sin(r1Radians.y) * sin(r2Radians.y))) + } + + fun getRotationToEntityClosest(entity: Entity, pTicks: Float = 1f): Vec2d { + val box = entity.boundingBox + val eyePos = mc.player.getPositionEyes(1f) + val x = MathHelper.clamp(eyePos.x, box.minX + 0.1, box.maxX - 0.1) + val y = MathHelper.clamp(eyePos.y, box.minY + 0.1, box.maxY - 0.1) + val z = MathHelper.clamp(eyePos.z, box.minZ + 0.1, box.maxZ - 0.1) + val hitVec = Vec3d(x, y, z) + return getRotationTo(hitVec, true, pTicks) + } + + fun getRotationToEntity(entity: Entity, pTicks: Float = 1f): Vec2d { + val posTo = EntityUtils.getInterpolatedPos(entity, pTicks) return getRotationTo(posTo, true) } @@ -33,10 +68,10 @@ object RotationUtils { * @return [Pair] */ @JvmStatic - fun getRotationTo(posTo: Vec3d, eyeHeight: Boolean): Vec2d { + fun getRotationTo(posTo: Vec3d, eyeHeight: Boolean, pTicks: Float = 1f): Vec2d { val player = mc.player - val posFrom = if (eyeHeight) player.getPositionEyes(KamiTessellator.pTicks()) - else EntityUtils.getInterpolatedPos(player, KamiTessellator.pTicks()) + val posFrom = if (eyeHeight) player.getPositionEyes(pTicks) + else EntityUtils.getInterpolatedPos(player, pTicks) return getRotationTo(posFrom, posTo) } diff --git a/src/main/java/me/zeroeightsix/kami/util/math/Vec2d.kt b/src/main/java/me/zeroeightsix/kami/util/math/Vec2d.kt index 0326604d7..e5695b96b 100644 --- a/src/main/java/me/zeroeightsix/kami/util/math/Vec2d.kt +++ b/src/main/java/me/zeroeightsix/kami/util/math/Vec2d.kt @@ -10,6 +10,10 @@ class Vec2d(var x: Double = 0.0, var y: Double = 0.0) { constructor(vec2d: Vec2d) : this(vec2d.x, vec2d.y) + fun toRadians(): Vec2d { + return Vec2d(this.x / 180.0 * Math.PI, this.y / 180.0 * Math.PI) + } + fun length(): Double { return sqrt(lengthSquared()) } diff --git a/src/main/java/me/zeroeightsix/kami/util/math/Vec2f.kt b/src/main/java/me/zeroeightsix/kami/util/math/Vec2f.kt index 6abe1ac42..74aa6a0b8 100644 --- a/src/main/java/me/zeroeightsix/kami/util/math/Vec2f.kt +++ b/src/main/java/me/zeroeightsix/kami/util/math/Vec2f.kt @@ -16,6 +16,8 @@ class Vec2f(@JvmField var x: Float, @JvmField var y: Float) { */ constructor(entity: Entity) : this(entity.rotationYaw, entity.rotationPitch) + constructor(vec2d: Vec2d): this(vec2d.x.toFloat(), vec2d.y.toFloat()) + fun toRadians(): Vec2d { return Vec2d(this.x / 180.0 * Math.PI, this.y / 180.0 * Math.PI) }