Skip to content
This repository has been archived by the owner on Apr 22, 2021. It is now read-only.

Commit

Permalink
impr: Add "Disable on Complete" and "Take Off" option for Automend (#…
Browse files Browse the repository at this point in the history
…2088)

Co-authored-by: lv <[email protected]>
  • Loading branch information
Toshimichi0915 and 5HT2 authored Mar 18, 2021
1 parent 7a7076b commit 2bec86e
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,29 @@ internal object AutoArmor : Module(
description = "Automatically equips armour",
modulePriority = 500
) {

private val delay = setting("Delay", 5, 1..10, 1)

private val timer = TickTimer(TimeUnit.TICKS)
private var lastTask = TaskState(true)

var isPaused = false

init {
onToggle {
isPaused = false
}

safeListener<TickEvent.ClientTickEvent> {
if (isPaused) return@safeListener
if (!timer.tick(delay.value.toLong()) || !lastTask.done) return@safeListener

if (!player.inventory.itemStack.isEmpty) {
if (mc.currentScreen is GuiContainer) timer.reset(150L) // Wait for 3 extra ticks if player is moving item
else removeHoldingItem()
return@safeListener
}

// store slots and values of best armor pieces, initialize with currently equipped armor
// Pair<Slot, Value>
val bestArmors = Array(4) { -1 to getArmorValue(player.inventory.armorInventory[it]) }
Expand All @@ -46,10 +55,14 @@ internal object AutoArmor : Module(
if (item !is ItemArmor) continue

val armorType = item.armorType.index
if (armorType == 2 && player.inventory.armorInventory[2].item == Items.ELYTRA) continue // Skip if item is chestplate and we have elytra equipped

// Skip if item is chestplate and we have elytra equipped
if (armorType == 2 && player.inventory.armorInventory[2].item == Items.ELYTRA) continue
val armorValue = getArmorValue(itemStack)

if (armorValue > bestArmors[armorType].second) bestArmors[armorType] = slot to armorValue
if (armorValue > bestArmors[armorType].second) {
bestArmors[armorType] = slot to armorValue
}
}

// equip better armor
Expand All @@ -67,6 +80,7 @@ internal object AutoArmor : Module(
for (i in 0 until itemStack.enchantmentTagList.tagCount()) {
val id = itemStack.enchantmentTagList.getCompoundTagAt(i).getShort("id").toInt()
val level = itemStack.enchantmentTagList.getCompoundTagAt(i).getShort("lvl").toInt()

if (id != 0) continue
return 1f + 0.04f * level
}
Expand All @@ -87,6 +101,7 @@ internal object AutoArmor : Module(
PlayerInventoryManager.ClickInfo(0, pair.first, type = ClickType.PICKUP) // Put the old one into the empty slot
)
}

break // Don't move more than one at once
}
}
Expand Down
123 changes: 92 additions & 31 deletions src/main/kotlin/org/kamiblue/client/module/modules/combat/AutoMend.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import net.minecraft.enchantment.EnchantmentHelper
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.init.Enchantments
import net.minecraft.init.Items
import net.minecraft.inventory.ClickType
import net.minecraft.util.EnumHand
import net.minecraft.util.math.RayTraceResult
import net.minecraftforge.fml.common.gameevent.TickEvent
Expand All @@ -17,9 +18,9 @@ import org.kamiblue.client.module.Module
import org.kamiblue.client.util.EntityUtils.isFakeOrSelf
import org.kamiblue.client.util.TickTimer
import org.kamiblue.client.util.TimeUnit
import org.kamiblue.client.util.items.clickSlot
import org.kamiblue.client.util.items.swapToSlot
import org.kamiblue.client.util.math.Vec2f
import org.kamiblue.client.util.text.MessageSendHelper
import org.kamiblue.client.util.threads.runSafe
import org.kamiblue.client.util.threads.safeListener
import org.kamiblue.commons.utils.MathUtils.reverseNumber
Expand All @@ -30,10 +31,14 @@ internal object AutoMend : Module(
category = Category.COMBAT,
description = "Automatically mends armour"
) {

private val autoThrow by setting("Auto Throw", true)
private val throwDelay = setting("Throw Delay", 2, 0..5, 1, description = "Number of ticks between throws to allow absorption")
private val autoSwitch by setting("Auto Switch", true)
private val autoDisable by setting("Auto Disable", false, { autoSwitch })
private val autoDisableExp by setting("Auto Disable", false, { autoSwitch }, description = "Disable when you run out of XP bottles")
private val autoDisableComplete by setting("Disable on Complete", false)
private val takeOff by setting("Take Off", true)
private val pauseAutoArmor = setting("Pause AutoArmor", true, { takeOff })
private val cancelNearby by setting("Cancel Nearby", NearbyMode.OFF, description = "Don't mend when an enemy is nearby")
private val pauseNearbyRadius by setting("Nearby Radius", 8, 1..8, 1, { cancelNearby != NearbyMode.OFF })
private val threshold by setting("Repair At", 75, 1..100, 1, description = "Percentage to start repairing any armor piece")
Expand Down Expand Up @@ -62,6 +67,16 @@ internal object AutoMend : Module(

onDisable {
switchback()
if (AutoArmor.isPaused && pauseAutoArmor.value) {
AutoArmor.isPaused = false
}
}

// TODO: Add proper module pausing system
pauseAutoArmor.listeners.add {
if (!pauseAutoArmor.value) {
AutoArmor.isPaused = false
}
}

listener<GuiEvent.Displayed> {
Expand All @@ -73,47 +88,89 @@ internal object AutoMend : Module(
}

safeListener<TickEvent.ClientTickEvent> {
if (isGuiOpened && !gui) return@safeListener
var isMending = false

if (!isGuiOpened || gui) {
if (cancelNearby != NearbyMode.OFF && isNearbyPlayer()) {
if (cancelNearby == NearbyMode.DISABLE) {
disable()
} else {
if (!paused)
switchback()
paused = true
}

return@safeListener
}

if (cancelNearby != NearbyMode.OFF && isNearbyPlayer()) {
if (cancelNearby == NearbyMode.DISABLE) {
paused = false

// don't call twice in same tick so store in a var
val shouldMend = shouldMend(0) || shouldMend(1) || shouldMend(2) || shouldMend(3)
if (!shouldMend && autoDisableComplete) {
disable()
} else {
if (!paused)
switchback()
paused = true
}
return@safeListener
}
paused = false

if ((autoSwitch || autoThrow) // avoid checking if no actions are going to be done
&& hasBlockUnder()
&& (shouldMend(0) || shouldMend(1) || shouldMend(2) || shouldMend(3))) {
if (autoSwitch && player.heldItemMainhand.item !== Items.EXPERIENCE_BOTTLE) {
val xpSlot = findXpPots()
if ((autoSwitch || autoThrow) // avoid checking if no actions are going to be done
&& hasBlockUnder() && shouldMend) {
if (autoSwitch && player.heldItemMainhand.item !== Items.EXPERIENCE_BOTTLE) {
val xpSlot = findXpPots()

if (xpSlot == -1) {
if (autoDisableExp) {
disable()
}

if (xpSlot == -1) {
if (autoDisable) {
MessageSendHelper.sendWarningMessage("$chatName No XP in hotbar, disabling")
disable()
return@safeListener
}
return@safeListener

player.inventory.currentItem = xpSlot
}
player.inventory.currentItem = xpSlot
}
if (autoThrow && player.heldItemMainhand.item === Items.EXPERIENCE_BOTTLE) {
sendPlayerPacket {
rotate(Vec2f(player.rotationYaw, 90.0f))

if (autoThrow && player.heldItemMainhand.item === Items.EXPERIENCE_BOTTLE) {
sendPlayerPacket {
rotate(Vec2f(player.rotationYaw, 90.0f))
}

isMending = true

if (validServerSideRotation() && throwDelayTimer.tick(throwDelay.value.toLong())) {
playerController.processRightClick(player, world, EnumHand.MAIN_HAND)
}
}
if (validServerSideRotation() && throwDelayTimer.tick(throwDelay.value.toLong())) {
playerController.processRightClick(player, world, EnumHand.MAIN_HAND)
}
}

if (pauseAutoArmor.value) {
AutoArmor.isPaused = isMending

if (takeOff && isMending) {
var minSlot = 9

for (i in 0..3) {
if (shouldMend(i) || !hasMending(i)) continue
val emptySlot = findEmptySlot(minSlot)
minSlot = emptySlot + 1

if (emptySlot == -1) break
clickSlot(player.inventoryContainer.windowId, 8 - i, 0, ClickType.PICKUP)
clickSlot(player.inventoryContainer.windowId, emptySlot, 0, ClickType.PICKUP)
}
}
}
}
}

private fun SafeClientEvent.findEmptySlot(min: Int): Int {
for (i in min..36) {
if (player.inventory.getStackInSlot(i).isEmpty) {
return i
}
}

return -1
}

private fun SafeClientEvent.findXpPots(): Int {
var slot = -1
for (i in 0..8) {
Expand All @@ -125,10 +182,14 @@ internal object AutoMend : Module(
return slot
}

private fun SafeClientEvent.hasMending(slot: Int): Boolean {
val stack = player.inventory.armorInventory[slot]
return EnchantmentHelper.getEnchantmentLevel(Enchantments.MENDING, stack) > 0
}

private fun SafeClientEvent.shouldMend(i: Int): Boolean { // (100 * damage / max damage) >= (100 - 70)
val stack = player.inventory.armorInventory[i]
val hasMending = EnchantmentHelper.getEnchantmentLevel(Enchantments.MENDING, stack) > 0
return hasMending && stack.isItemDamaged && 100 * stack.itemDamage / stack.maxDamage > reverseNumber(threshold, 1, 100)
return hasMending(i) && stack.isItemDamaged && 100 * stack.itemDamage / stack.maxDamage > reverseNumber(threshold, 1, 100)
}

private fun switchback() {
Expand Down

0 comments on commit 2bec86e

Please sign in to comment.