diff --git a/src/main/java/net/ccbluex/liquidbounce/features/command/commands/GiveCommand.kt b/src/main/java/net/ccbluex/liquidbounce/features/command/commands/GiveCommand.kt index 77a081ca6aa..500adc62181 100644 --- a/src/main/java/net/ccbluex/liquidbounce/features/command/commands/GiveCommand.kt +++ b/src/main/java/net/ccbluex/liquidbounce/features/command/commands/GiveCommand.kt @@ -32,23 +32,7 @@ class GiveCommand : Command("give", "item", "i", "get") { return } - var emptySlot = -1 - - for (i in 36..44) { - if (thePlayer.inventoryContainer.getSlot(i).stack == null) { - emptySlot = i - break - } - } - - if (emptySlot == -1) { - for (i in 9..44) { - if (thePlayer.inventoryContainer.getSlot(i).stack == null) { - emptySlot = i - break - } - } - } + val emptySlot = thePlayer.inventory.firstEmptyStack if (emptySlot != -1) { sendPacket(C10PacketCreativeInventoryAction(emptySlot, itemStack)) diff --git a/src/main/java/net/ccbluex/liquidbounce/features/module/Module.kt b/src/main/java/net/ccbluex/liquidbounce/features/module/Module.kt index fed03795188..f245bfd020d 100644 --- a/src/main/java/net/ccbluex/liquidbounce/features/module/Module.kt +++ b/src/main/java/net/ccbluex/liquidbounce/features/module/Module.kt @@ -156,7 +156,7 @@ open class Module @JvmOverloads constructor( TickedActions.schedule(id, instance, allowDuplicates, action) internal fun scheduleClick(slot: Int, button: Int, mode: Int, allowDuplicates: Boolean = false, windowId: Int = mc.thePlayer.openContainer.windowId, action: ((ItemStack?) -> Unit)? = null) = - TickedActions.schedule(slot, instance, allowDuplicates) { + schedule(slot, allowDuplicates) { val newStack = mc.playerController.windowClick(windowId, slot, button, mode, mc.thePlayer) action?.invoke(newStack) } @@ -170,9 +170,14 @@ open class Module @JvmOverloads constructor( internal fun scheduleAndSuspend(vararg actions: () -> Unit) = actions.forEach { this += it - waitUntil { isEmpty() } + waitUntil(::isEmpty) } + internal fun scheduleAndSuspend(id: Int = -1, allowDuplicates: Boolean = true, action: () -> Unit) { + schedule(id, allowDuplicates, action) + waitUntil(::isEmpty) + } + internal fun isScheduled(id: Int) = TickedActions.isScheduled(id, instance) // Checks if id click is scheduled: if (id in TickScheduler) diff --git a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineArmorer.kt b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineArmorer.kt index 6bb83fbfcde..ebc5f587ef0 100644 --- a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineArmorer.kt +++ b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineArmorer.kt @@ -19,7 +19,7 @@ import net.ccbluex.liquidbounce.utils.timing.TimeUtils.randomDelay import net.ccbluex.liquidbounce.value.BoolValue import net.ccbluex.liquidbounce.value.IntegerValue import net.minecraft.client.gui.inventory.GuiInventory -import net.minecraft.item.ItemArmor +import net.minecraft.entity.EntityLiving.getArmorPosition import net.minecraft.item.ItemStack import net.minecraft.network.play.client.C08PacketPlayerBlockPlacement import net.minecraft.network.play.client.C09PacketHeldItemChange @@ -59,7 +59,7 @@ object CoroutineArmorer: Module("CoroutineArmorer", ModuleCategory.BETA) { val onlyWhenNoScreen by BoolValue("OnlyWhenNoScreen", false) { hotbar } suspend fun equipFromHotbar() { - if (!shouldExecute(onlyHotbar = true)) + if (!shouldOperate(onlyHotbar = true)) return val thePlayer = mc.thePlayer ?: return @@ -67,7 +67,7 @@ object CoroutineArmorer: Module("CoroutineArmorer", ModuleCategory.BETA) { var hasClickedHotbar = false for (hotbarIndex in 0..8) { - if (!shouldExecute(onlyHotbar = true)) + if (!shouldOperate(onlyHotbar = true)) return // Don't right-click to equip items while inventory is open when value onlyWhenNoScreen is enabled @@ -76,17 +76,17 @@ object CoroutineArmorer: Module("CoroutineArmorer", ModuleCategory.BETA) { val stacks = thePlayer.openContainer.inventory - val bestArmorSet = getBestArmorSet(stacks) ?: return - val stack = stacks.getOrNull(hotbarIndex + 36) ?: continue + val bestArmorSet = getBestArmorSet(stacks) ?: return + if (stack !in bestArmorSet) continue - val equippedStack = stacks[(stack.item as ItemArmor).armorType + 5] + val armorPosition = getArmorPosition(stack) - 1 // If armor slot isn't occupied, right click to equip - if (equippedStack == null) { + if (thePlayer.getCurrentArmor(armorPosition) == null) { hasClickedHotbar = true val equippingAction = { @@ -96,12 +96,9 @@ object CoroutineArmorer: Module("CoroutineArmorer", ModuleCategory.BETA) { C08PacketPlayerBlockPlacement(stack) ) - // TODO: Still clicks repetitively, probably because openContainer gets updated after some ticks? // Instantly update inventory on client-side to prevent repetitive clicking because of ping - /* - thePlayer.inventory.armorInventory[abs((stack.item as ItemArmor).armorType - 3)] = stack + thePlayer.inventory.armorInventory[armorPosition] = stack thePlayer.inventory.mainInventory[hotbarIndex] = null - */ } if (delayedSlotSwitch) @@ -113,21 +110,24 @@ object CoroutineArmorer: Module("CoroutineArmorer", ModuleCategory.BETA) { } } - waitUntil { TickScheduler.isEmpty() } + // Not really needed to bypass + delay(randomDelay(minDelay, maxDelay).toLong()) + + waitUntil(TickScheduler::isEmpty) - // Sync selected slot + // Sync selected slot next tick if (hasClickedHotbar) TickScheduler += { serverSlot = thePlayer.inventory.currentItem } } suspend fun equipFromInventory() { - if (!shouldExecute()) + if (!shouldOperate()) return val thePlayer = mc.thePlayer ?: return for (armorType in 0..3) { - if (!shouldExecute()) + if (!shouldOperate()) return val stacks = thePlayer.openContainer.inventory @@ -183,7 +183,7 @@ object CoroutineArmorer: Module("CoroutineArmorer", ModuleCategory.BETA) { } // Wait till all scheduled clicks were sent - waitUntil { TickScheduler.isEmpty() } + waitUntil(TickScheduler::isEmpty) } fun equipFromHotbarInChest(hotbarIndex: Int?, stack: ItemStack) { @@ -197,11 +197,14 @@ object CoroutineArmorer: Module("CoroutineArmorer", ModuleCategory.BETA) { ) } - private suspend fun shouldExecute(onlyHotbar: Boolean = false): Boolean { + private suspend fun shouldOperate(onlyHotbar: Boolean = false): Boolean { while (true) { if (!state) return false + if (mc.playerController?.currentGameType?.isSurvivalOrAdventure != true) + return false + // It is impossible to equip armor when a container is open; only try to equip by right-clicking from hotbar (if onlyWhenNoScreen is disabled) if (mc.thePlayer?.openContainer?.windowId != 0 && (!onlyHotbar || onlyWhenNoScreen)) return false diff --git a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineCleaner.kt b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineCleaner.kt index a0569550b47..85a7e3a577e 100644 --- a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineCleaner.kt +++ b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineCleaner.kt @@ -81,14 +81,14 @@ object CoroutineCleaner: Module("CoroutineCleaner", ModuleCategory.BETA) { // Compact multiple small stacks into one to free up inventory space suspend fun compactStacks() { - if (!mergeStacks || !shouldExecute()) + if (!mergeStacks || !shouldOperate()) return val thePlayer = mc.thePlayer ?: return // Loop multiple times until no clicks were scheduled while (true) { - if (!shouldExecute()) return + if (!shouldOperate()) return val stacks = thePlayer.openContainer.inventory @@ -118,7 +118,7 @@ object CoroutineCleaner: Module("CoroutineCleaner", ModuleCategory.BETA) { var hasMerged = false for (index in indicesToDoubleClick) { - if (!shouldExecute()) return + if (!shouldOperate()) return if (index in TickScheduler) continue @@ -138,13 +138,13 @@ object CoroutineCleaner: Module("CoroutineCleaner", ModuleCategory.BETA) { // This part isn't fully instant because of the complex vanilla merging behaviour, stack size changes and so on // Waits a tick to see how the stacks got merged - waitUntil { TickScheduler.isEmpty() } + waitUntil(TickScheduler::isEmpty) } } // Sort hotbar (with useful items without even dropping bad items first) suspend fun sortHotbar() { - if (!sort || !shouldExecute()) return + if (!sort || !shouldOperate()) return val thePlayer = mc.thePlayer ?: return @@ -153,7 +153,7 @@ object CoroutineCleaner: Module("CoroutineCleaner", ModuleCategory.BETA) { val isRightType = SORTING_TARGETS[value.get()] ?: continue // Stop if player violates invopen or nomove checks - if (!shouldExecute()) return + if (!shouldOperate()) return val stacks = thePlayer.openContainer.inventory @@ -184,18 +184,18 @@ object CoroutineCleaner: Module("CoroutineCleaner", ModuleCategory.BETA) { } } - waitUntil { TickScheduler.isEmpty() } + waitUntil(TickScheduler::isEmpty) } // Drop bad items to free up inventory space suspend fun dropGarbage() { - if (!drop || !shouldExecute()) return + if (!drop || !shouldOperate()) return val thePlayer = mc.thePlayer ?: return for (index in thePlayer.openContainer.inventorySlots.indices.shuffled(randomSlot)) { // Stop if player violates invopen or nomove checks - if (!shouldExecute()) return + if (!shouldOperate()) return if (index in TickScheduler) continue @@ -211,14 +211,17 @@ object CoroutineCleaner: Module("CoroutineCleaner", ModuleCategory.BETA) { click(index, 1, 4) } - waitUntil { TickScheduler.isEmpty() } + waitUntil(TickScheduler::isEmpty) } - private suspend fun shouldExecute(): Boolean { + private suspend fun shouldOperate(): Boolean { while (true) { if (!state) return false + if (mc.playerController?.currentGameType?.isSurvivalOrAdventure != true) + return false + if (mc.thePlayer?.openContainer?.windowId != 0) return false diff --git a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineStealer.kt b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineStealer.kt index 978f28cbb47..c9d797dff51 100644 --- a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineStealer.kt +++ b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/beta/CoroutineStealer.kt @@ -14,7 +14,6 @@ import net.ccbluex.liquidbounce.features.module.Module import net.ccbluex.liquidbounce.features.module.ModuleCategory import net.ccbluex.liquidbounce.features.module.modules.beta.CoroutineCleaner.canBeSortedTo import net.ccbluex.liquidbounce.features.module.modules.beta.CoroutineCleaner.isStackUseful -import net.ccbluex.liquidbounce.features.module.modules.beta.CoroutineCleaner.toHotbarIndex import net.ccbluex.liquidbounce.utils.CoroutineUtils.waitUntil import net.ccbluex.liquidbounce.utils.extensions.component1 import net.ccbluex.liquidbounce.utils.extensions.component2 @@ -29,6 +28,7 @@ import net.ccbluex.liquidbounce.value.BoolValue import net.ccbluex.liquidbounce.value.IntegerValue import net.minecraft.client.gui.ScaledResolution import net.minecraft.client.gui.inventory.GuiChest +import net.minecraft.entity.EntityLiving.getArmorPosition import net.minecraft.init.Blocks import net.minecraft.init.Items import net.minecraft.item.ItemArmor @@ -79,11 +79,14 @@ object CoroutineStealer : Module("CoroutineStealer", ModuleCategory.BETA) { private var stacks = emptyList() - private suspend fun shouldExecute(): Boolean { + private suspend fun shouldOperate(): Boolean { while (true) { if (!state) return false + if (mc.playerController?.currentGameType?.isSurvivalOrAdventure != true) + return false + if (mc.currentScreen !is GuiChest) return false @@ -108,7 +111,7 @@ object CoroutineStealer : Module("CoroutineStealer", ModuleCategory.BETA) { val screen = mc.currentScreen ?: return - if (screen !is GuiChest || !shouldExecute()) + if (screen !is GuiChest || !shouldOperate()) return // Check if player isn't holding a compass and browsing navigation gui @@ -125,7 +128,7 @@ object CoroutineStealer : Module("CoroutineStealer", ModuleCategory.BETA) { // Go through the chest multiple times, till there are no useful items anymore while (true) { - if (!shouldExecute()) + if (!shouldOperate()) return val sortBlacklist = BooleanArray(9) @@ -176,7 +179,7 @@ object CoroutineStealer : Module("CoroutineStealer", ModuleCategory.BETA) { run scheduler@ { usefulItems.forEachIndexed { index, (slot, stack, sortableTo) -> - if (!shouldExecute()) { + if (!shouldOperate()) { TickScheduler += { serverSlot = thePlayer.inventory.currentItem } return } @@ -185,24 +188,24 @@ object CoroutineStealer : Module("CoroutineStealer", ModuleCategory.BETA) { // Check if the chest has any empty slot val hasChestEmptySlot = stacks.dropLast(36).any { it == null } - if (!hasChestEmptySlot) - return@scheduler - // If the item is supposed to be sorted, put the stack that occupies its slot into chest, else find first garbage item - var indexToMoveToChest = sortableTo?.plus(stacks.size - 9) + var garbageIndex = sortableTo?.plus(stacks.size - 9) - if (indexToMoveToChest == null) { + if (garbageIndex == null) { val garbageInventoryIndex = stacks.takeLast(36) .indexOfLast { CoroutineCleaner.state && !isStackUseful(it, stacks) } if (garbageInventoryIndex != -1) - indexToMoveToChest = stacks.size - 36 + garbageInventoryIndex + // Convert index in player's inventory to index of the whole open container + garbageIndex = stacks.size - 36 + garbageInventoryIndex } - indexToMoveToChest ?: return@scheduler + garbageIndex ?: return@scheduler // Shift + left-click bad item from inventory into chest to free up space - TickScheduler.scheduleClick(indexToMoveToChest, 0, 1) + if (hasChestEmptySlot) TickScheduler.scheduleClick(garbageIndex, 0, 1) + // Drop bad item from inventory when there is no space + else TickScheduler.scheduleClick(garbageIndex, 1, 4) delay(randomDelay(minDelay, maxDelay).toLong()) } @@ -210,6 +213,7 @@ object CoroutineStealer : Module("CoroutineStealer", ModuleCategory.BETA) { hasTaken = true // TODO: If armor can be equipped from hotbar, but all slots are occupied, sort it to slot with useless item or not sorted item and equip (if the item was useful or sorted, sort it back in the end) + // this is kinda finished ^ // TODO: might schedule clicks that exceed inventory space at low delays, it will notice that it doesn't have space in inventory next tick, when the scheduled click gets executed // If target is sortable to a hotbar slot, steal and sort it at the same time, else shift + left-click @@ -217,14 +221,20 @@ object CoroutineStealer : Module("CoroutineStealer", ModuleCategory.BETA) { progress = (index + 1) / usefulItems.size.toFloat() // Try to equip armor piece from hotbar 1 tick after stealing it - if (stack.item is ItemArmor) { + run equipArmor@ { + val item = stack.item + + if (item !is ItemArmor || thePlayer.inventory.armorInventory[getArmorPosition(stack) - 1] != null) + return@equipArmor + TickScheduler += { - val stacks = thePlayer.openContainer.inventory + val hotbarStacks = thePlayer.inventory.mainInventory.take(9) // Can't get index of stack instance, because it is different even from the one returned from windowClick() - stacks.indexOfLast { it?.getIsItemStackEqual(stack) ?: false }.toHotbarIndex(stacks.size)?.let { - CoroutineArmorer.equipFromHotbarInChest(it, stack) - } + val newIndex = hotbarStacks.indexOfFirst { it?.getIsItemStackEqual(stack) ?: false } + + if (newIndex != -1) + CoroutineArmorer.equipFromHotbarInChest(newIndex, stack) } } } @@ -243,17 +253,17 @@ object CoroutineStealer : Module("CoroutineStealer", ModuleCategory.BETA) { } // Wait till all scheduled clicks were sent - waitUntil { TickScheduler.isEmpty() } + waitUntil(TickScheduler::isEmpty) // Before closing the chest, check all items once more, whether server hadn't cancelled some of the actions. stacks = thePlayer.openContainer.inventory } // Wait before the chest gets closed (if it gets closed out of tick loop it could throw npe) - TickScheduler.scheduleAndSuspend({ + TickScheduler.scheduleAndSuspend { thePlayer.closeScreen() progress = null - }) + } } // Progress bar diff --git a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/combat/AutoPot.kt b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/combat/AutoPot.kt index fd3547c1923..2b0f6eea628 100644 --- a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/combat/AutoPot.kt +++ b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/combat/AutoPot.kt @@ -58,7 +58,7 @@ object AutoPot : Module("AutoPot", ModuleCategory.COMBAT) { // Hotbar Potion val potionInHotbar = findPotion(36, 45) - if (thePlayer.health <= health && potionInHotbar != -1) { + if (potionInHotbar != null && thePlayer.health <= health) { if (thePlayer.onGround) { when (mode.lowercase()) { "jump" -> thePlayer.jump() @@ -84,8 +84,8 @@ object AutoPot : Module("AutoPot", ModuleCategory.COMBAT) { } // Inventory Potion -> Hotbar Potion - val potionInInventory = findPotion(9, 36) - if (potionInInventory != -1 && InventoryUtils.hasSpaceInHotbar()) { + val potionInInventory = findPotion(9, 36) ?: return + if (InventoryUtils.hasSpaceInHotbar()) { if (openInventory && mc.currentScreen !is GuiInventory) return @@ -94,7 +94,7 @@ object AutoPot : Module("AutoPot", ModuleCategory.COMBAT) { mc.playerController.windowClick(0, potionInInventory, 0, 1, thePlayer) - if (simulateInventory) + if (simulateInventory && mc.currentScreen !is GuiInventory) serverOpenInventory = false msTimer.reset() @@ -119,7 +119,7 @@ object AutoPot : Module("AutoPot", ModuleCategory.COMBAT) { } } - private fun findPotion(startSlot: Int, endSlot: Int): Int { + private fun findPotion(startSlot: Int, endSlot: Int): Int? { val thePlayer = mc.thePlayer for (i in startSlot until endSlot) { @@ -140,7 +140,7 @@ object AutoPot : Module("AutoPot", ModuleCategory.COMBAT) { return i } - return -1 + return null } override val tag diff --git a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/combat/AutoSoup.kt b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/combat/AutoSoup.kt index fa88af37cc4..30136376cf8 100644 --- a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/combat/AutoSoup.kt +++ b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/combat/AutoSoup.kt @@ -102,7 +102,7 @@ object AutoSoup : Module("AutoSoup", ModuleCategory.COMBAT) { mc.playerController.windowClick(0, soupInInventory, 0, 1, thePlayer) - if (simulateInventory) + if (simulateInventory && mc.currentScreen !is GuiInventory) serverOpenInventory = false timer.reset() diff --git a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/player/InventoryCleaner.kt b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/player/InventoryCleaner.kt index a3f44781ab2..2ceef34fedf 100644 --- a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/player/InventoryCleaner.kt +++ b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/player/InventoryCleaner.kt @@ -276,7 +276,7 @@ object InventoryCleaner : Module("InventoryCleaner", ModuleCategory.PLAYER) { val item = stack.item if (item is ItemFood && item !is ItemAppleGold && type(index) != "Food") { - val replaceCurr = slotStack.isEmpty || slotStack?.item !is ItemFood + val replaceCurr = slotStack.isEmpty() || slotStack.item !is ItemFood return if (replaceCurr) index else null } @@ -290,7 +290,7 @@ object InventoryCleaner : Module("InventoryCleaner", ModuleCategory.PLAYER) { val item = stack.item if (item is ItemBlock && item.block !in InventoryUtils.BLOCK_BLACKLIST && type(index) != "Block") { - val replaceCurr = slotStack.isEmpty || slotStack?.item !is ItemBlock + val replaceCurr = slotStack.isEmpty() || slotStack.item !is ItemBlock return if (replaceCurr) index else null } @@ -305,7 +305,7 @@ object InventoryCleaner : Module("InventoryCleaner", ModuleCategory.PLAYER) { if (item is ItemBucket && item.isFull == Blocks.flowing_water && type(index) != "Water") { val replaceCurr = - slotStack.isEmpty || slotStack?.item !is ItemBucket || (slotStack.item as ItemBucket).isFull != Blocks.flowing_water + slotStack.isEmpty() || slotStack.item !is ItemBucket || (slotStack.item as ItemBucket).isFull != Blocks.flowing_water return if (replaceCurr) index else null } @@ -319,7 +319,7 @@ object InventoryCleaner : Module("InventoryCleaner", ModuleCategory.PLAYER) { val item = stack.item if (item is ItemAppleGold && type(index) != "Gapple") { - val replaceCurr = slotStack.isEmpty || slotStack?.item !is ItemAppleGold + val replaceCurr = slotStack.isEmpty() || slotStack.item !is ItemAppleGold return if (replaceCurr) index else null } @@ -333,7 +333,7 @@ object InventoryCleaner : Module("InventoryCleaner", ModuleCategory.PLAYER) { val item = stack.item if (item is ItemEnderPearl && type(index) != "Pearl") { - val replaceCurr = slotStack.isEmpty || slotStack?.item !is ItemEnderPearl + val replaceCurr = slotStack.isEmpty() || slotStack.item !is ItemEnderPearl return if (replaceCurr) index else null } @@ -354,7 +354,7 @@ object InventoryCleaner : Module("InventoryCleaner", ModuleCategory.PLAYER) { for (i in endInclusive downTo startInclusive) { val itemStack = mc.thePlayer.inventoryContainer.getSlot(i).stack ?: continue - if (itemStack.isEmpty) { + if (itemStack.isEmpty()) { continue } diff --git a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/world/ChestStealer.kt b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/world/ChestStealer.kt index 76cb7c2f085..68c15ea8e18 100644 --- a/src/main/java/net/ccbluex/liquidbounce/features/module/modules/world/ChestStealer.kt +++ b/src/main/java/net/ccbluex/liquidbounce/features/module/modules/world/ChestStealer.kt @@ -197,7 +197,7 @@ object ChestStealer : Module("ChestStealer", ModuleCategory.WORLD) { } private fun shouldTake(stack: ItemStack?, slot: Int): Boolean { - return stack != null && !stack.isEmpty && (!onlyItems || stack.item !is ItemBlock) + return !stack.isEmpty() && (!onlyItems || stack.item !is ItemBlock) && slot !in TickScheduler && (!InventoryCleaner.state || InventoryCleaner.isUseful(stack, -1)) } diff --git a/src/main/java/net/ccbluex/liquidbounce/utils/inventory/InventoryManager.kt b/src/main/java/net/ccbluex/liquidbounce/utils/inventory/InventoryManager.kt index 2449f97c9b5..2a2789a7aa4 100644 --- a/src/main/java/net/ccbluex/liquidbounce/utils/inventory/InventoryManager.kt +++ b/src/main/java/net/ccbluex/liquidbounce/utils/inventory/InventoryManager.kt @@ -90,7 +90,6 @@ object InventoryManager: MinecraftInstance() { // Try to search through inventory one more time, only close when no actions were scheduled in current iteration if (!hasScheduled) { - displayChatMessage("closing action was invoked $canCloseInventory") closingAction?.invoke() return } diff --git a/src/main/java/net/ccbluex/liquidbounce/utils/inventory/ItemUtils.kt b/src/main/java/net/ccbluex/liquidbounce/utils/inventory/ItemUtils.kt index 5637cf10e0e..9811d2b0f55 100644 --- a/src/main/java/net/ccbluex/liquidbounce/utils/inventory/ItemUtils.kt +++ b/src/main/java/net/ccbluex/liquidbounce/utils/inventory/ItemUtils.kt @@ -12,6 +12,8 @@ import net.minecraft.enchantment.Enchantment import net.minecraft.item.* import net.minecraft.nbt.JsonToNBT import net.minecraft.util.ResourceLocation +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract object ItemUtils : MinecraftInstance() { /** @@ -24,8 +26,8 @@ object ItemUtils : MinecraftInstance() { return try { val args = itemArguments.replace('&', 'ยง').split(" ") - val amount = args.getOrNull(1)?.toInt() ?: 1 - val meta = args.getOrNull(2)?.toInt() ?: 0 + val amount = args.getOrNull(1)?.toIntOrNull() ?: 1 + val meta = args.getOrNull(2)?.toIntOrNull() ?: 0 val resourceLocation = ResourceLocation(args[0]) val item = Item.itemRegistry.getObject(resourceLocation) ?: return null @@ -52,7 +54,7 @@ object ItemUtils : MinecraftInstance() { for (i in startInclusive..endInclusive) { val itemStack = mc.thePlayer.inventoryContainer.getSlot(i).stack ?: continue - if (itemStack.isEmpty) + if (itemStack.isEmpty()) continue if (itemDelay != null && !itemStack.hasItemAgePassed(itemDelay)) @@ -70,9 +72,8 @@ object ItemUtils : MinecraftInstance() { * Allows you to check if player is consuming item */ fun isConsumingItem(): Boolean { - if (!mc.thePlayer.isUsingItem) { + if (!mc.thePlayer.isUsingItem) return false - } val usingItem = mc.thePlayer.itemInUse.item return usingItem is ItemFood || usingItem is ItemBucketMilk || usingItem is ItemPotion @@ -88,6 +89,7 @@ object ItemUtils : MinecraftInstance() { val ItemStack.durability get() = maxDamage - itemDamage +// Calculates how much estimated durability does the item have thanks to its unbreaking level val ItemStack.totalDurability get() = durability * (getEnchantmentLevel(Enchantment.unbreaking) + 1) @@ -116,8 +118,15 @@ val ItemStack.enchantmentSum fun ItemStack.getEnchantmentLevel(enchantment: Enchantment) = enchantments.getOrDefault(enchantment, 0) -val ItemStack?.isEmpty - get() = this == null || item == null +// Makes Kotlin smart-cast the stack to not null ItemStack +@OptIn(ExperimentalContracts::class) +fun ItemStack?.isEmpty(): Boolean { + contract { + returns(false) implies (this@isEmpty != null) + } + + return this == null || item == null +} @Suppress("CAST_NEVER_SUCCEEDS") fun ItemStack?.hasItemAgePassed(delay: Int) = this == null @@ -127,4 +136,4 @@ val ItemStack.attackDamage get() = (attributeModifiers["generic.attackDamage"].firstOrNull()?.amount ?: 0.0) + 1.25 * getEnchantmentLevel(Enchantment.sharpness) -fun ItemStack.isSplashPotion() = item is ItemPotion && ItemPotion.isSplash(this.metadata) \ No newline at end of file +fun ItemStack.isSplashPotion() = item is ItemPotion && ItemPotion.isSplash(metadata) \ No newline at end of file