diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/MineRotationMode.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/MineRotationMode.kt index f99e83058ec..a72281fc2b3 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/MineRotationMode.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/MineRotationMode.kt @@ -114,8 +114,11 @@ enum class FailProcedure { mode.activeChoice.onCannotLookAtTarget(mineTarget) // if required, we already switch - switch(switchMode.activeChoice.getSlot(mineTarget.blockState), mineTarget) - interaction.syncSelectedSlot() + val switchMode = switchMode.activeChoice + switch(switchMode.getSlot(mineTarget.blockState), mineTarget) + if (switchMode.getSwitchingMethod().shouldSync) { + interaction.syncSelectedSlot() + } } return true diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/ModulePacketMine.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/ModulePacketMine.kt index eb522faacc8..a8fb406e8fc 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/ModulePacketMine.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/ModulePacketMine.kt @@ -24,10 +24,13 @@ import net.ccbluex.liquidbounce.event.handler import net.ccbluex.liquidbounce.event.tickHandler import net.ccbluex.liquidbounce.features.module.Category import net.ccbluex.liquidbounce.features.module.ClientModule -import net.ccbluex.liquidbounce.features.module.modules.world.ModuleAutoTool import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.mode.CivMineMode import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.mode.ImmediateMineMode import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.mode.NormalMineMode +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.tool.AlwaysToolMode +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.tool.NeverToolMode +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.tool.OnStopToolMode +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.tool.PostStartToolMode import net.ccbluex.liquidbounce.render.engine.Color4b import net.ccbluex.liquidbounce.utils.aiming.Rotation import net.ccbluex.liquidbounce.utils.aiming.RotationManager @@ -37,7 +40,6 @@ import net.ccbluex.liquidbounce.utils.block.SwingMode import net.ccbluex.liquidbounce.utils.block.getState import net.ccbluex.liquidbounce.utils.block.outlineBox import net.ccbluex.liquidbounce.utils.client.Chronometer -import net.ccbluex.liquidbounce.utils.client.SilentHotbar import net.ccbluex.liquidbounce.utils.kotlin.Priority import net.ccbluex.liquidbounce.utils.render.placement.PlacementRenderer import net.minecraft.block.BlockState @@ -225,15 +227,19 @@ object ModulePacketMine : ClientModule("PacketMine", Category.WORLD) { return } - val slot = switchMode.activeChoice.getSlot(mineTarget.blockState) + val switchMode = switchMode.activeChoice + val slot = switchMode.getSlot(mineTarget.blockState) if (!mineTarget.started) { startBreaking(slot, mineTarget) } else if (mode.activeChoice.shouldUpdate(mineTarget, slot)) { updateBreakingProgress(mineTarget, slot) if (mineTarget.progress >= breakDamage && !mineTarget.finished) { mode.activeChoice.finish(mineTarget) + switchMode.getSwitchingMethod().switchBack() } } + + switchMode.getSwitchingMethod().reset() } private fun startBreaking(slot: IntObjectImmutablePair?, mineTarget: MineTarget) { @@ -247,14 +253,17 @@ object ModulePacketMine : ClientModule("PacketMine", Category.WORLD) { } private fun updateBreakingProgress(mineTarget: MineTarget, slot: IntObjectImmutablePair?) { - mineTarget.progress += switchMode.activeChoice.getBlockBreakingDelta( + val switchMode = switchMode.activeChoice + mineTarget.progress += switchMode.getBlockBreakingDelta( mineTarget.targetPos, mineTarget.blockState, slot?.second() ) switch(slot, mineTarget) - interaction.syncSelectedSlot() + if (switchMode.getSwitchingMethod().shouldSync) { + interaction.syncSelectedSlot() + } val f = if (breakDamage > 0f) { val breakDamageD = breakDamage.toDouble() @@ -282,11 +291,9 @@ object ModulePacketMine : ClientModule("PacketMine", Category.WORLD) { return } - val shouldSwitch = switchMode.activeChoice.shouldSwitch(mineTarget) - if (shouldSwitch && ModuleAutoTool.running) { - ModuleAutoTool.switchToBreakBlock(mineTarget.targetPos) - } else if (shouldSwitch) { - SilentHotbar.selectSlotSilently(this, slot.firstInt(), 1) + val switchMode = switchMode.activeChoice + if (switchMode.shouldSwitch(mineTarget)) { + switchMode.getSwitchingMethod().switch(slot, mineTarget) } } diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/AlwaysToolMode.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/AlwaysToolMode.kt new file mode 100644 index 00000000000..1b675dc869d --- /dev/null +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/AlwaysToolMode.kt @@ -0,0 +1,68 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2025 CCBlueX + * + * LiquidBounce is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiquidBounce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LiquidBounce. If not, see . + */ +package net.ccbluex.liquidbounce.features.module.modules.world.packetmine.tool + +import net.ccbluex.liquidbounce.event.events.PacketEvent +import net.ccbluex.liquidbounce.event.events.SelectHotbarSlotSilentlyEvent +import net.ccbluex.liquidbounce.event.handler +import net.ccbluex.liquidbounce.features.module.modules.world.ModuleAutoTool +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.MineTarget +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.ModulePacketMine +import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket +import net.minecraft.network.packet.s2c.play.UpdateSelectedSlotS2CPacket + +object AlwaysToolMode : MineToolMode("Always", syncOnStart = true) { + + private val abortOnSwitch by boolean("AbortOnSwitch", true) + private val cancelAutomaticSwitching by boolean("CancelAutomaticSwitching", true) + + @Suppress("unused") + private val packetHandler = handler { event -> + mc.execute { + val target = ModulePacketMine._target ?: return@execute + if (!abortOnSwitch || !target.started) { + return@execute + } + + val packet = event.packet + val serverInitiatedSwitch = packet is UpdateSelectedSlotS2CPacket && + packet.slot == getSlot(target.blockState)?.firstInt() + val clientInitiatedSwitch = packet is UpdateSelectedSlotC2SPacket && + packet.selectedSlot == getSlot(target.blockState)?.firstInt() + if (serverInitiatedSwitch || clientInitiatedSwitch) { + ModulePacketMine._resetTarget() + } + } + } + + @Suppress("unused") + private val silentSwitchHandler = handler { event -> + val target = ModulePacketMine._target ?: return@handler + + val requester = event.requester + val fromPacketMine = requester == ModulePacketMine + val fromAutoTool = requester == ModuleAutoTool && event.slot == getSlot(target.blockState)?.firstInt() + if (cancelAutomaticSwitching && target.started && !fromPacketMine && !fromAutoTool) { + event.cancelEvent() + } + } + + override fun shouldSwitch(mineTarget: MineTarget) = true + +} diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/MineToolMode.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/MineToolMode.kt similarity index 66% rename from src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/MineToolMode.kt rename to src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/MineToolMode.kt index 702665f82b8..069842bcdb8 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/MineToolMode.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/MineToolMode.kt @@ -16,16 +16,15 @@ * You should have received a copy of the GNU General Public License * along with LiquidBounce. If not, see . */ -package net.ccbluex.liquidbounce.features.module.modules.world.packetmine +package net.ccbluex.liquidbounce.features.module.modules.world.packetmine.tool import it.unimi.dsi.fastutil.ints.IntObjectImmutablePair import net.ccbluex.liquidbounce.config.types.Choice import net.ccbluex.liquidbounce.config.types.ChoiceConfigurable -import net.ccbluex.liquidbounce.event.events.PacketEvent -import net.ccbluex.liquidbounce.event.events.SelectHotbarSlotSilentlyEvent -import net.ccbluex.liquidbounce.event.handler import net.ccbluex.liquidbounce.features.module.MinecraftShortcuts import net.ccbluex.liquidbounce.features.module.modules.world.ModuleAutoTool +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.MineTarget +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.ModulePacketMine import net.ccbluex.liquidbounce.utils.client.player import net.ccbluex.liquidbounce.utils.client.world import net.ccbluex.liquidbounce.utils.item.getEnchantment @@ -36,69 +35,9 @@ import net.minecraft.entity.attribute.EntityAttributes import net.minecraft.entity.effect.StatusEffectUtil import net.minecraft.entity.effect.StatusEffects import net.minecraft.item.ItemStack -import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket -import net.minecraft.network.packet.s2c.play.UpdateSelectedSlotS2CPacket import net.minecraft.registry.tag.FluidTags import net.minecraft.util.math.BlockPos -object AlwaysToolMode : MineToolMode("Always", syncOnStart = true) { - - private val abortOnSwitch by boolean("AbortOnSwitch", true) - private val cancelAutomaticSwitching by boolean("CancelAutomaticSwitching", true) - - @Suppress("unused") - private val packetHandler = handler { event -> - mc.execute { - val target = ModulePacketMine._target ?: return@execute - if (!abortOnSwitch || !target.started) { - return@execute - } - - val packet = event.packet - val serverInitiatedSwitch = packet is UpdateSelectedSlotS2CPacket && - packet.slot == getSlot(target.blockState)?.firstInt() - val clientInitiatedSwitch = packet is UpdateSelectedSlotC2SPacket && - packet.selectedSlot == getSlot(target.blockState)?.firstInt() - if (serverInitiatedSwitch || clientInitiatedSwitch) { - ModulePacketMine._resetTarget() - } - } - } - - @Suppress("unused") - private val silentSwitchHandler = handler { event -> - val target = ModulePacketMine._target ?: return@handler - - val requester = event.requester - val fromPacketMine = requester == ModulePacketMine - val fromAutoTool = requester == ModuleAutoTool && event.slot == getSlot(target.blockState)?.firstInt() - if (cancelAutomaticSwitching && target.started && !fromPacketMine && !fromAutoTool) { - event.cancelEvent() - } - } - - override fun shouldSwitch(mineTarget: MineTarget) = true - -} - -object PostStartToolMode : MineToolMode("PostStart") { - - override fun shouldSwitch(mineTarget: MineTarget) = true - -} - -object OnStopToolMode : MineToolMode("OnStop") { - - override fun shouldSwitch(mineTarget: MineTarget) = mineTarget.progress >= ModulePacketMine.breakDamage - -} - -object NeverToolMode : MineToolMode("Never", switchesNever = true) { - - override fun shouldSwitch(mineTarget: MineTarget) = false - -} - /** * Determines when to switch to a tool and calculates the breaking process delta. */ @@ -111,6 +50,8 @@ abstract class MineToolMode( abstract fun shouldSwitch(mineTarget: MineTarget): Boolean + open fun getSwitchingMethod() = SwitchMethod.NORMAL + fun getBlockBreakingDelta(pos: BlockPos, state: BlockState, itemStack: ItemStack?): Float { if (switchesNever || itemStack == null) { return state.calcBlockBreakingDelta(player, world, pos) diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/NeverToolMode.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/NeverToolMode.kt new file mode 100644 index 00000000000..a5c7cf559ae --- /dev/null +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/NeverToolMode.kt @@ -0,0 +1,27 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2025 CCBlueX + * + * LiquidBounce is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiquidBounce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LiquidBounce. If not, see . + */ +package net.ccbluex.liquidbounce.features.module.modules.world.packetmine.tool + +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.MineTarget + +object NeverToolMode : MineToolMode("Never", switchesNever = true) { + + override fun shouldSwitch(mineTarget: MineTarget) = false + +} diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/OnStopToolMode.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/OnStopToolMode.kt new file mode 100644 index 00000000000..9da1cb297e0 --- /dev/null +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/OnStopToolMode.kt @@ -0,0 +1,32 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2025 CCBlueX + * + * LiquidBounce is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiquidBounce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LiquidBounce. If not, see . + */ +package net.ccbluex.liquidbounce.features.module.modules.world.packetmine.tool + +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.MineTarget +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.ModulePacketMine + +object OnStopToolMode : MineToolMode("OnStop") { + + private val switchMethod by enumChoice("SwitchMethod", SwitchMethod.NORMAL) + + override fun shouldSwitch(mineTarget: MineTarget) = mineTarget.progress >= ModulePacketMine.breakDamage + + override fun getSwitchingMethod() = switchMethod + +} diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/PostStartToolMode.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/PostStartToolMode.kt new file mode 100644 index 00000000000..b7406da6e70 --- /dev/null +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/PostStartToolMode.kt @@ -0,0 +1,27 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2025 CCBlueX + * + * LiquidBounce is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiquidBounce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LiquidBounce. If not, see . + */ +package net.ccbluex.liquidbounce.features.module.modules.world.packetmine.tool + +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.MineTarget + +object PostStartToolMode : MineToolMode("PostStart") { + + override fun shouldSwitch(mineTarget: MineTarget) = true + +} diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/SwitchMethod.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/SwitchMethod.kt new file mode 100644 index 00000000000..2e6c8506b46 --- /dev/null +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/world/packetmine/tool/SwitchMethod.kt @@ -0,0 +1,132 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2025 CCBlueX + * + * LiquidBounce is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiquidBounce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LiquidBounce. If not, see . + */ +package net.ccbluex.liquidbounce.features.module.modules.world.packetmine.tool + +import it.unimi.dsi.fastutil.ints.IntObjectImmutablePair +import net.ccbluex.liquidbounce.config.types.NamedChoice +import net.ccbluex.liquidbounce.features.module.MinecraftShortcuts +import net.ccbluex.liquidbounce.features.module.modules.world.ModuleAutoTool +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.MineTarget +import net.ccbluex.liquidbounce.features.module.modules.world.packetmine.ModulePacketMine +import net.ccbluex.liquidbounce.utils.client.* +import net.ccbluex.liquidbounce.utils.inventory.ClickInventoryAction +import net.ccbluex.liquidbounce.utils.inventory.Slots +import net.ccbluex.liquidbounce.utils.network.PickFromInventoryPacket +import net.ccbluex.liquidbounce.utils.network.sendPacket +import net.minecraft.item.ItemStack + +enum class SwitchMethod(override val choiceName: String, val shouldSync: Boolean) : NamedChoice, MinecraftShortcuts { + + NORMAL("Normal", true) { + + override fun switch(slot: IntObjectImmutablePair, mineTarget: MineTarget) { + if (ModuleAutoTool.running) { + ModuleAutoTool.switchToBreakBlock(mineTarget.targetPos) + return + } + + SilentHotbar.selectSlotSilently(ModulePacketMine, slot.firstInt(), 1) + } + + override fun switchBack() { + // nothing, handled by SilentHotbar + } + + }, + + @Suppress("unused") + SWAP("Swap", false) { + + override fun switch(slot: IntObjectImmutablePair, mineTarget: MineTarget) { + val selectedSlot = SilentHotbar.serversideSlot + val desiredSlot = slot.firstInt() + if (selectedSlot == desiredSlot) { + return + } + + + exchanged = desiredSlot + ClickInventoryAction.performSwap( + from = Slots.Hotbar.slots[desiredSlot], + to = Slots.Hotbar.slots[selectedSlot] + ).performAction() + } + + override fun switchBack() { + val desiredSlot = exchanged ?: return + val selectedSlot = SilentHotbar.serversideSlot + exchanged = null + ClickInventoryAction.performSwap( + from = Slots.Hotbar.slots[desiredSlot], + to = Slots.Hotbar.slots[selectedSlot] + ).performAction() + } + + }, + + /** + * Only works before 1.21.3. + */ + @Suppress("unused") + PICK("Pick", false) { + + override fun switch(slot: IntObjectImmutablePair, mineTarget: MineTarget) { + if (!usesViaFabricPlus) { + chat(warning(ModulePacketMine.message("noVfp"))) + ModulePacketMine.disable() + return + } + + exchanged = slot.firstInt() + network.sendPacket( + PickFromInventoryPacket(slot.firstInt() - 1), + onFailure = { + chat( + markAsError( + "Failed to pick an item from your inventory using ViaFabricPlus, report to developers!" + ) + ) + exchanged = null + } + ) + } + + override fun switchBack() { + if (!usesViaFabricPlus) { + return + } + + // TODO make it not mess up the hotbar + exchanged?.let { network.sendPacket(PickFromInventoryPacket(it)) } + exchanged = null + } + + }; + + var exchanged: Int? = null + + abstract fun switch(slot: IntObjectImmutablePair, mineTarget: MineTarget) + + abstract fun switchBack() + + fun reset() { + exchanged = null + } + +} diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/inventory/InventoryUtils.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/inventory/InventoryUtils.kt index 9939121f550..6a9aed4da88 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/utils/inventory/InventoryUtils.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/inventory/InventoryUtils.kt @@ -18,16 +18,10 @@ * * */ - @file:Suppress("TooManyFunctions") package net.ccbluex.liquidbounce.utils.inventory -import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1 -import com.viaversion.viaversion.api.Via -import com.viaversion.viaversion.api.protocol.packet.PacketWrapper -import com.viaversion.viaversion.api.type.Types -import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3 import net.ccbluex.liquidbounce.config.types.Configurable import net.ccbluex.liquidbounce.features.module.modules.player.invcleaner.* import net.ccbluex.liquidbounce.features.module.modules.world.scaffold.ModuleScaffold @@ -35,7 +29,8 @@ import net.ccbluex.liquidbounce.utils.aiming.RotationManager import net.ccbluex.liquidbounce.utils.client.* import net.ccbluex.liquidbounce.utils.input.shouldSwingHand import net.ccbluex.liquidbounce.utils.item.isNothing -import net.fabricmc.loader.api.FabricLoader +import net.ccbluex.liquidbounce.utils.network.OpenInventorySilentlyPacket +import net.ccbluex.liquidbounce.utils.network.sendPacket import net.minecraft.block.Blocks import net.minecraft.client.gui.screen.ingame.GenericContainerScreen import net.minecraft.component.type.DyedColorComponent @@ -80,12 +75,15 @@ class PlayerInventoryConstraints : InventoryConstraints() { * When this option is not enabled, the inventory will be opened silently * depending on the Minecraft version chosen using ViaFabricPlus. * - * If the protocol contains [Protocol1_12To1_11_1] and the client status packet is supported, + * If the protocol contains [com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1] + * and the client status packet is supported, * the inventory will be opened silently using [openInventorySilently]. * Otherwise, the inventory will not have any open tracking and * the server will only know when clicking in the inventory. * - * Closing will still be required to be done for any version. Sad. :( + * Closing will still be required to be done for any version. + * Sad. + * :( */ private val requiresOpenInventory by boolean("RequiresInventoryOpen", false) @@ -113,36 +111,16 @@ fun findNonEmptySlotsInInventory(): List { /** * Sends an open inventory packet with the help of ViaFabricPlus. This is only for older versions. */ - -// https://github.com/ViaVersion/ViaFabricPlus/blob/ecd5d188187f2ebaaad8ded0ffe53538911f7898/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/MixinMinecraftClient.java#L124-L130 fun openInventorySilently() { - if (InventoryManager.isInventoryOpenServerSide) { + if (InventoryManager.isInventoryOpenServerSide || !usesViaFabricPlus) { return } - runCatching { - val isViaFabricPlusLoaded = FabricLoader.getInstance().isModLoaded("viafabricplus") - - if (!isViaFabricPlusLoaded) { - return - } - - val viaConnection = Via.getManager().connectionManager.connections.firstOrNull() ?: return - - if (viaConnection.protocolInfo.pipeline.contains(Protocol1_12To1_11_1::class.java)) { - val clientStatus = PacketWrapper.create(ServerboundPackets1_9_3.CLIENT_COMMAND, viaConnection) - clientStatus.write(Types.VAR_INT, 2) // Open Inventory Achievement - - runCatching { - clientStatus.scheduleSendToServer(Protocol1_12To1_11_1::class.java) - }.onSuccess { - InventoryManager.isInventoryOpenServerSide = true - }.onFailure { - chat("§cFailed to open inventory using ViaFabricPlus, report to developers!") - it.printStackTrace() - } - } - } + network.sendPacket( + OpenInventorySilentlyPacket(), + onSuccess = { InventoryManager.isInventoryOpenServerSide = true }, + onFailure = { chat(markAsError("Failed to open inventory using ViaFabricPlus, report to developers!")) } + ) } fun closeInventorySilently() { diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/network/LegacyPacket.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/network/LegacyPacket.kt new file mode 100644 index 00000000000..6bcb8a9f875 --- /dev/null +++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/network/LegacyPacket.kt @@ -0,0 +1,91 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2025 CCBlueX + * + * LiquidBounce is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiquidBounce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LiquidBounce. If not, see . + */ +package net.ccbluex.liquidbounce.utils.network + +import com.viaversion.viaversion.api.Via +import com.viaversion.viaversion.api.protocol.Protocol +import com.viaversion.viaversion.api.protocol.packet.PacketType +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper +import net.fabricmc.loader.api.FabricLoader +import net.minecraft.client.network.ClientCommonNetworkHandler + +/** + * A packet that is directly sent to the server over ViaVersion. + * + * This class can be implemented and sent over [sendPacket] to imitated behavior from older minecraft versions. + */ +interface LegacyPacket { + + /** + * Should provide the class of the protocol from the version where the packet got removed to the version where it + * was still present. + */ + val protocol: Class> + + /** + * The type of the packet. + */ + val packetType: PacketType + + /** + * Writes the actual information to the [packetWrapper]. + */ + fun write(packetWrapper: PacketWrapper) + +} + +// TODO integrate into the packet logger +/** + * Sends the [packet]. + * + * Make sure to check if ViaFabricPlus is loaded before using this or constructing the packet. + * + * Keep in mind, the packet won't be caught by the packet event. + * + * @param onSuccess Gets executed when sending succeeds. + * @param onFailure Gets executed when sending fails. + */ +inline fun ClientCommonNetworkHandler.sendPacket( + packet: LegacyPacket, + onSuccess: () -> Unit = {}, + onFailure: () -> Unit = {} +) { + runCatching { + val isViaFabricPlusLoaded = FabricLoader.getInstance().isModLoaded("viafabricplus") + if (!isViaFabricPlusLoaded) { + return + } + + val viaConnection = Via.getManager().connectionManager.connections.firstOrNull() ?: return + + if (viaConnection.protocolInfo.pipeline.contains(packet.protocol)) { + val clientStatus = PacketWrapper.create(packet.packetType, viaConnection) + packet.write(clientStatus) + + runCatching { + clientStatus.scheduleSendToServer(packet.protocol) + }.onSuccess { + onSuccess() + }.onFailure { + onFailure() + it.printStackTrace() + } + } + } +} diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/network/OpenInventorySilentlyPacket.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/network/OpenInventorySilentlyPacket.kt new file mode 100644 index 00000000000..469e29c346c --- /dev/null +++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/network/OpenInventorySilentlyPacket.kt @@ -0,0 +1,37 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2025 CCBlueX + * + * LiquidBounce is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiquidBounce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LiquidBounce. If not, see . + */ +package net.ccbluex.liquidbounce.utils.network + +import com.viaversion.viabackwards.protocol.v1_12to1_11_1.Protocol1_12To1_11_1 +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper +import com.viaversion.viaversion.api.type.Types +import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3 + +// https://github.com/ViaVersion/ViaFabricPlus/blob/ecd5d188187f2ebaaad8ded0ffe53538911f7898/src/main/java/de/florianmichael/viafabricplus/injection/mixin/fixes/minecraft/MixinMinecraftClient.java#L124-L130 +class OpenInventorySilentlyPacket : LegacyPacket { + + override val protocol = Protocol1_12To1_11_1::class.java + + override val packetType = ServerboundPackets1_9_3.CLIENT_COMMAND + + override fun write(packetWrapper: PacketWrapper) { + packetWrapper.write(Types.VAR_INT, 2) // Open Inventory Achievement + } + +} diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/utils/network/PickFromInventoryPacket.kt b/src/main/kotlin/net/ccbluex/liquidbounce/utils/network/PickFromInventoryPacket.kt new file mode 100644 index 00000000000..f5a2f5de6ef --- /dev/null +++ b/src/main/kotlin/net/ccbluex/liquidbounce/utils/network/PickFromInventoryPacket.kt @@ -0,0 +1,36 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2025 CCBlueX + * + * LiquidBounce is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LiquidBounce is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LiquidBounce. If not, see . + */ +package net.ccbluex.liquidbounce.utils.network + +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper +import com.viaversion.viaversion.api.type.Types +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.Protocol1_21_2To1_21_4 +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPackets1_21_2 + +class PickFromInventoryPacket(val slot: Int): LegacyPacket { + + override val protocol = Protocol1_21_2To1_21_4::class.java + + override val packetType = ServerboundPackets1_21_2.PICK_ITEM + + override fun write(packetWrapper: PacketWrapper) { + packetWrapper.write(Types.VAR_INT, slot) + } + +} diff --git a/src/main/resources/resources/liquidbounce/lang/en_us.json b/src/main/resources/resources/liquidbounce/lang/en_us.json index 1ce8a0ec327..23be7edea35 100644 --- a/src/main/resources/resources/liquidbounce/lang/en_us.json +++ b/src/main/resources/resources/liquidbounce/lang/en_us.json @@ -630,6 +630,7 @@ "liquidbounce.module.blockIn.messages.filled": "Filled!", "liquidbounce.module.blockIn.messages.positionChanged": "Your position has changed!", "liquidbounce.module.packetMine.description": "Allows you to mine blocks by clicking them once.", + "liquidbounce.module.packetMine.messages.noVfp": "Either choose another switch method or install via fabric plus!", "liquidbounce.module.fastExp.description": "Automatically repairs your armor.", "liquidbounce.module.bookBot.description": "Automatically writes in books.", "liquidbounce.module.itemChams.description": "Applies visual effects to your held items.",