From 900e4ab83ad9d8d92d2f750225adb01b7ff7b9f5 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Tue, 21 Oct 2025 19:21:21 +0200 Subject: [PATCH 1/6] Add easy trash prototype --- .../mixin/render/ScreenHandlerMixin.java | 12 ++++ .../lambda/module/modules/player/EasyTrash.kt | 70 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt diff --git a/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java b/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java index 23c243a6f..d402a4c0a 100644 --- a/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java +++ b/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java @@ -19,8 +19,13 @@ import com.lambda.event.EventFlow; import com.lambda.event.events.InventoryEvent; +import com.lambda.module.modules.player.EasyTrash; +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.SlotActionType; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -34,4 +39,11 @@ public class ScreenHandlerMixin { private void onUpdateSlotStacksHead(int revision, List stacks, ItemStack cursorStack, CallbackInfo ci) { EventFlow.post(new InventoryEvent.FullUpdate(revision, stacks, cursorStack)); } + + @WrapMethod(method = "internalOnSlotClick(IILnet/minecraft/screen/slot/SlotActionType;Lnet/minecraft/entity/player/PlayerEntity;)V") + private void onInternalOnSlotClick(int slotIndex, int button, SlotActionType actionType, PlayerEntity player, Operation original) { + if (EasyTrash.onClick((ScreenHandler) (Object) this, slotIndex, button, actionType, player)) { + original.call(slotIndex, button, actionType, player); + } + } } diff --git a/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt new file mode 100644 index 000000000..a6840efa6 --- /dev/null +++ b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2025 Lambda + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +package com.lambda.module.modules.player + +import com.lambda.module.Module +import com.lambda.module.tag.ModuleTag +import com.lambda.threading.runSafe +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.item.Items +import net.minecraft.screen.GenericContainerScreenHandler +import net.minecraft.screen.ScreenHandler +import net.minecraft.screen.slot.Slot +import net.minecraft.screen.slot.SlotActionType + +object EasyTrash : Module( + "EasyTrash", + "Automatically trashes unwanted items", + ModuleTag.PLAYER +) { + + private val trashNetherrack by setting("Trash Netherrack", true) + + /** + * Called when a slot is clicked in a screen handler. + * Returns false if the click was handled and should be cancelled. + */ + @JvmStatic + fun onClick(screenHandler: ScreenHandler, slotIndex: Int, button: Int, actionType: SlotActionType, player: PlayerEntity): Boolean = + runSafe { + if (!isEnabled) return true + if (actionType != SlotActionType.QUICK_MOVE || button != 0) return true + + if (!trashNetherrack) return true + if (screenHandler is GenericContainerScreenHandler) { + val slot = screenHandler.getSlot(slotIndex) + val rows = screenHandler.rows + + if (slotIndex >= rows * 9) return true // Not in the container + + val inventorySlots = screenHandler.slots.subList(rows * 9, screenHandler.slots.size) + val freeInventorySlot = inventorySlots.any { !it.hasStack() } + if (freeInventorySlot) return true + + val netherrackSlot: Slot? = inventorySlots.firstOrNull { it.stack.item == Items.NETHERRACK } + if (netherrackSlot == null) return true + + mc.interactionManager?.clickSlot(screenHandler.syncId, slot.id, 0, SlotActionType.PICKUP, player) + mc.interactionManager?.clickSlot(screenHandler.syncId, netherrackSlot.id, 0, SlotActionType.PICKUP, player) + mc.interactionManager?.clickSlot(screenHandler.syncId, ScreenHandler.EMPTY_SPACE_SLOT_INDEX, 0, SlotActionType.PICKUP, player) + + return false + } + return true + } ?: true +} \ No newline at end of file From 5dec1d4bfc82ec795dae5a17c43ec1d8361c337f Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Mon, 26 Jan 2026 22:15:40 +0100 Subject: [PATCH 2/6] Improved EasyTrash --- .../java/com/lambda/mixin/render/HandledScreenMixin.java | 6 ++++++ .../java/com/lambda/mixin/render/ScreenHandlerMixin.java | 7 ------- .../kotlin/com/lambda/module/modules/player/EasyTrash.kt | 5 +++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java b/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java index 3c66e9c53..111cca4e0 100644 --- a/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java +++ b/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java @@ -17,6 +17,7 @@ package com.lambda.mixin.render; +import com.lambda.module.modules.player.EasyTrash; import com.lambda.module.modules.render.ContainerPreview; import net.minecraft.client.gui.Click; import net.minecraft.client.gui.screen.ingame.HandledScreen; @@ -34,6 +35,11 @@ private void onMouseClicked(Click click, boolean doubled, CallbackInfoReturnable cir.setReturnValue(true); } } + if (EasyTrash.INSTANCE.isEnabled()) { + if (!EasyTrash.onClick(slotId, button, actionType)) { + ci.cancel(); + } + } } @Inject(method = "mouseReleased", at = @At("HEAD"), cancellable = true) diff --git a/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java b/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java index d402a4c0a..18baf4df1 100644 --- a/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java +++ b/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java @@ -39,11 +39,4 @@ public class ScreenHandlerMixin { private void onUpdateSlotStacksHead(int revision, List stacks, ItemStack cursorStack, CallbackInfo ci) { EventFlow.post(new InventoryEvent.FullUpdate(revision, stacks, cursorStack)); } - - @WrapMethod(method = "internalOnSlotClick(IILnet/minecraft/screen/slot/SlotActionType;Lnet/minecraft/entity/player/PlayerEntity;)V") - private void onInternalOnSlotClick(int slotIndex, int button, SlotActionType actionType, PlayerEntity player, Operation original) { - if (EasyTrash.onClick((ScreenHandler) (Object) this, slotIndex, button, actionType, player)) { - original.call(slotIndex, button, actionType, player); - } - } } diff --git a/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt index a6840efa6..80edc9f59 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt @@ -37,13 +37,14 @@ object EasyTrash : Module( /** * Called when a slot is clicked in a screen handler. - * Returns false if the click was handled and should be cancelled. + * Returns false if the click was handled and should be canceled. */ @JvmStatic - fun onClick(screenHandler: ScreenHandler, slotIndex: Int, button: Int, actionType: SlotActionType, player: PlayerEntity): Boolean = + fun onClick(slotIndex: Int, button: Int, actionType: SlotActionType): Boolean = runSafe { if (!isEnabled) return true if (actionType != SlotActionType.QUICK_MOVE || button != 0) return true + var screenHandler = player.currentScreenHandler if (!trashNetherrack) return true if (screenHandler is GenericContainerScreenHandler) { From c128fd118076c6b0ede9d835ac7df58454f543a5 Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Tue, 27 Jan 2026 00:25:31 +0100 Subject: [PATCH 3/6] Improved EasyTrash --- .../mixin/render/HandledScreenMixin.java | 14 ++- .../lambda/module/modules/player/EasyTrash.kt | 88 +++++++++++++++---- 2 files changed, 79 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java b/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java index 111cca4e0..5bca28ffe 100644 --- a/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java +++ b/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java @@ -21,9 +21,12 @@ import com.lambda.module.modules.render.ContainerPreview; import net.minecraft.client.gui.Click; import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.screen.slot.Slot; +import net.minecraft.screen.slot.SlotActionType; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(HandledScreen.class) @@ -35,10 +38,13 @@ private void onMouseClicked(Click click, boolean doubled, CallbackInfoReturnable cir.setReturnValue(true); } } - if (EasyTrash.INSTANCE.isEnabled()) { - if (!EasyTrash.onClick(slotId, button, actionType)) { - ci.cancel(); - } + } + + @Inject(method = "onMouseClick(Lnet/minecraft/screen/slot/Slot;IILnet/minecraft/screen/slot/SlotActionType;)V", at = @At(value = "HEAD"), cancellable = true) + private void onMouseClickSlotPre(Slot slot, int slotId, int button, SlotActionType actionType, CallbackInfo ci) { + if (slot == null) return; + if (EasyTrash.INSTANCE.isEnabled() && EasyTrash.onClick(slot.id, button, actionType)) { + ci.cancel(); } } diff --git a/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt index 80edc9f59..d139f62c5 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt @@ -17,55 +17,105 @@ package com.lambda.module.modules.player +import com.lambda.context.SafeContext +import com.lambda.event.events.TickEvent +import com.lambda.event.listener.SafeListener.Companion.listen +import com.lambda.interaction.managers.inventory.InventoryRequest.Companion.inventoryRequest +import com.lambda.interaction.material.StackSelection +import com.lambda.interaction.material.container.containers.InventoryContainer import com.lambda.module.Module import com.lambda.module.tag.ModuleTag import com.lambda.threading.runSafe -import net.minecraft.entity.player.PlayerEntity +import com.lambda.util.Timer +import net.minecraft.entity.EntityType +import net.minecraft.entity.ItemEntity +import net.minecraft.item.Item import net.minecraft.item.Items +import net.minecraft.registry.Registries.ITEM import net.minecraft.screen.GenericContainerScreenHandler import net.minecraft.screen.ScreenHandler -import net.minecraft.screen.slot.Slot import net.minecraft.screen.slot.SlotActionType +import kotlin.time.Duration.Companion.milliseconds object EasyTrash : Module( "EasyTrash", "Automatically trashes unwanted items", ModuleTag.PLAYER ) { + private val itemsCanTrash by setting("Items Can Trash", setOf(Items.NETHERRACK, Items.COBBLESTONE), ITEM.toSet()) - private val trashNetherrack by setting("Trash Netherrack", true) + private val dropToPickup by setting("Drop To Pickup", true) + private val itemsToPickup by setting("Items To Pickup", setOf(), ITEM.toSet()) + + private val timer = Timer() + + init { + listen { + if (!timer.timePassed(200.milliseconds)) { + return@listen + } + checkShouldTrashSomething() + } + } + + fun SafeContext.checkShouldTrashSomething() { + if (player.health > 0.0f && !player.isSpectator && dropToPickup && !player.isCreative) { + val box = if (player.vehicle != null && !player.vehicle!!.isRemoved) { + player.boundingBox.union(player.vehicle!!.boundingBox).expand(1.0, 0.0, 1.0) + } else { + player.boundingBox.expand(1.0, 0.5, 1.0) + } + val items = world.getEntitiesByType(EntityType.ITEM, box) { entity -> itemsToPickup.contains(entity.stack.item) && entity.isOnGround }.map { i -> i.stack.item } + if (items.isNotEmpty() && InventoryContainer.spaceAvailable(StackSelection.selectStack { isOneOfItems(items) }) == 0) { + if (trashSomething()) timer.reset() + } + } + } + + fun SafeContext.trashSomething(): Boolean { + StackSelection.selectStack { + isOneOfItems(itemsCanTrash) + }.filterSlots(InventoryContainer.slots).firstOrNull()?.let { + inventoryRequest { + throwStack(it.id) + }.submit(true) + return true + } + return false + } /** * Called when a slot is clicked in a screen handler. - * Returns false if the click was handled and should be canceled. + * Returns true if the click was handled */ @JvmStatic fun onClick(slotIndex: Int, button: Int, actionType: SlotActionType): Boolean = runSafe { - if (!isEnabled) return true - if (actionType != SlotActionType.QUICK_MOVE || button != 0) return true + if (!isEnabled) return false + if (actionType != SlotActionType.QUICK_MOVE || button != 0) return false var screenHandler = player.currentScreenHandler - if (!trashNetherrack) return true if (screenHandler is GenericContainerScreenHandler) { val slot = screenHandler.getSlot(slotIndex) val rows = screenHandler.rows - if (slotIndex >= rows * 9) return true // Not in the container + if (slotIndex >= rows * 9) return false // Not in the container val inventorySlots = screenHandler.slots.subList(rows * 9, screenHandler.slots.size) val freeInventorySlot = inventorySlots.any { !it.hasStack() } - if (freeInventorySlot) return true - - val netherrackSlot: Slot? = inventorySlots.firstOrNull { it.stack.item == Items.NETHERRACK } - if (netherrackSlot == null) return true + if (freeInventorySlot) return false - mc.interactionManager?.clickSlot(screenHandler.syncId, slot.id, 0, SlotActionType.PICKUP, player) - mc.interactionManager?.clickSlot(screenHandler.syncId, netherrackSlot.id, 0, SlotActionType.PICKUP, player) - mc.interactionManager?.clickSlot(screenHandler.syncId, ScreenHandler.EMPTY_SPACE_SLOT_INDEX, 0, SlotActionType.PICKUP, player) - - return false + StackSelection.selectStack { + isOneOfItems(itemsCanTrash) + }.filterSlots(InventoryContainer.slots).firstOrNull()?.let { trashSlot -> + inventoryRequest { + pickup(slot.id, 0) + pickup(trashSlot.id, 0) + pickup(ScreenHandler.EMPTY_SPACE_SLOT_INDEX, 0) + }.submit(true) + return true + } } - return true - } ?: true + return false + } ?: false } \ No newline at end of file From 2bc9bb8ec20e720279ade3d80062ca193334518c Mon Sep 17 00:00:00 2001 From: Ic3Tank <61137113+IceTank@users.noreply.github.com> Date: Tue, 27 Jan 2026 00:27:55 +0100 Subject: [PATCH 4/6] Lint --- .../java/com/lambda/mixin/render/ScreenHandlerMixin.java | 5 ----- .../kotlin/com/lambda/module/modules/player/EasyTrash.kt | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java b/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java index 18baf4df1..23c243a6f 100644 --- a/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java +++ b/src/main/java/com/lambda/mixin/render/ScreenHandlerMixin.java @@ -19,13 +19,8 @@ import com.lambda.event.EventFlow; import com.lambda.event.events.InventoryEvent; -import com.lambda.module.modules.player.EasyTrash; -import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.screen.ScreenHandler; -import net.minecraft.screen.slot.SlotActionType; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; diff --git a/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt index d139f62c5..76314081f 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt @@ -93,7 +93,7 @@ object EasyTrash : Module( runSafe { if (!isEnabled) return false if (actionType != SlotActionType.QUICK_MOVE || button != 0) return false - var screenHandler = player.currentScreenHandler + val screenHandler = player.currentScreenHandler if (screenHandler is GenericContainerScreenHandler) { val slot = screenHandler.getSlot(slotIndex) From 70c9add50b9106d8626b18daf23f06e36147f401 Mon Sep 17 00:00:00 2001 From: IceTank <61137113+IceTank@users.noreply.github.com> Date: Tue, 27 Jan 2026 03:19:08 +0100 Subject: [PATCH 5/6] Add InventoryEvent$SlotAction$Click Event Use @WrapMethod in mixin Other nits --- .../mixin/render/HandledScreenMixin.java | 25 ++++-- .../com/lambda/event/events/InventoryEvent.kt | 29 +++++++ .../lambda/module/modules/player/EasyTrash.kt | 80 +++++++++---------- 3 files changed, 86 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java b/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java index 5bca28ffe..27ae4c0a9 100644 --- a/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java +++ b/src/main/java/com/lambda/mixin/render/HandledScreenMixin.java @@ -17,20 +17,29 @@ package com.lambda.mixin.render; -import com.lambda.module.modules.player.EasyTrash; +import com.lambda.event.EventFlow; +import com.lambda.event.events.InventoryEvent; import com.lambda.module.modules.render.ContainerPreview; +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import net.minecraft.client.gui.Click; import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.screen.ScreenHandler; import net.minecraft.screen.slot.Slot; import net.minecraft.screen.slot.SlotActionType; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(HandledScreen.class) -public class HandledScreenMixin { +public class HandledScreenMixin { + @Final + @Shadow + protected T handler; + @Inject(method = "mouseClicked", at = @At("HEAD"), cancellable = true) private void onMouseClicked(Click click, boolean doubled, CallbackInfoReturnable cir) { if (ContainerPreview.INSTANCE.isEnabled() && ContainerPreview.isLocked()) { @@ -40,11 +49,11 @@ private void onMouseClicked(Click click, boolean doubled, CallbackInfoReturnable } } - @Inject(method = "onMouseClick(Lnet/minecraft/screen/slot/Slot;IILnet/minecraft/screen/slot/SlotActionType;)V", at = @At(value = "HEAD"), cancellable = true) - private void onMouseClickSlotPre(Slot slot, int slotId, int button, SlotActionType actionType, CallbackInfo ci) { - if (slot == null) return; - if (EasyTrash.INSTANCE.isEnabled() && EasyTrash.onClick(slot.id, button, actionType)) { - ci.cancel(); + @WrapMethod(method = "onMouseClick(Lnet/minecraft/screen/slot/Slot;IILnet/minecraft/screen/slot/SlotActionType;)V") + private void onMouseClickSlotPre(Slot slot, int slotId, int button, SlotActionType actionType, Operation original) { + if (!EventFlow.post(new InventoryEvent.SlotAction.Click(handler, slot, slotId, button, actionType)).isCanceled()) { + int slotIdFinal = slot == null ? slotId : slot.id; + original.call(slot, slotIdFinal, button, actionType); } } diff --git a/src/main/kotlin/com/lambda/event/events/InventoryEvent.kt b/src/main/kotlin/com/lambda/event/events/InventoryEvent.kt index 10d1e53b6..0d4419602 100644 --- a/src/main/kotlin/com/lambda/event/events/InventoryEvent.kt +++ b/src/main/kotlin/com/lambda/event/events/InventoryEvent.kt @@ -22,6 +22,8 @@ import com.lambda.event.callback.Cancellable import com.lambda.event.callback.ICancellable import net.minecraft.item.ItemStack import net.minecraft.screen.ScreenHandler +import net.minecraft.screen.slot.Slot +import net.minecraft.screen.slot.SlotActionType /** * Represents various events related to inventory interactions, updates, and state changes. @@ -82,6 +84,33 @@ sealed class InventoryEvent { val stack: ItemStack, ) : Event + /** + * Represents an action performed on an inventory slot, such as clicking or interacting with it. + */ + abstract class SlotAction : Event, ICancellable { + /** + * Represents a click action performed on an inventory slot. + * + * This event provides detailed information about the click action, including the screen handler, + * the slot involved, the button used, and the type of action performed. + * + * This event is [Cancellable], allowing handlers to prevent the default click behavior if necessary. + * + * @property screenHandler The screen handler managing the inventory interaction. + * @property slot The slot that was clicked, or null if no slot was involved. + * @property slotId The ID of the slot that was clicked. + * @property button The mouse button used for the click action. + * @property actionType The type of action performed on the slot. + */ + data class Click( + val screenHandler: ScreenHandler, + val slot: Slot?, + val slotId: Int, + val button: Int, + val actionType: SlotActionType, + ) : ICancellable by Cancellable() + } + abstract class HotbarSlot : Event { /** * Represents an event triggered when the client attempts to send slot update to the server. diff --git a/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt index 76314081f..c10bac895 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt @@ -18,6 +18,7 @@ package com.lambda.module.modules.player import com.lambda.context.SafeContext +import com.lambda.event.events.InventoryEvent import com.lambda.event.events.TickEvent import com.lambda.event.listener.SafeListener.Companion.listen import com.lambda.interaction.managers.inventory.InventoryRequest.Companion.inventoryRequest @@ -25,7 +26,6 @@ import com.lambda.interaction.material.StackSelection import com.lambda.interaction.material.container.containers.InventoryContainer import com.lambda.module.Module import com.lambda.module.tag.ModuleTag -import com.lambda.threading.runSafe import com.lambda.util.Timer import net.minecraft.entity.EntityType import net.minecraft.entity.ItemEntity @@ -56,17 +56,52 @@ object EasyTrash : Module( } checkShouldTrashSomething() } + + listen { event -> + if (event.actionType != SlotActionType.QUICK_MOVE || event.button != 0) { + return@listen + } + + if (event.screenHandler is GenericContainerScreenHandler) { + val sh = event.screenHandler + val rows = sh.rows + + if (event.slotId >= rows * 9) { + // Clicked in inventory, not in container + return@listen + } + + if (sh.slots.subList(rows * 9, sh.slots.size).any { !it.hasStack() }) { + // There is empty space in the inventory, no need to trash + return@listen + } + + StackSelection.selectStack { + isOneOfItems(itemsCanTrash) + }.filterSlots(InventoryContainer.slots).firstOrNull()?.let { trashSlot -> + inventoryRequest { + pickup(event.slotId, 0) + pickup(trashSlot.id, 0) + pickup(ScreenHandler.EMPTY_SPACE_SLOT_INDEX, 0) + }.submit(true) + event.cancel() + } + } + } } fun SafeContext.checkShouldTrashSomething() { if (player.health > 0.0f && !player.isSpectator && dropToPickup && !player.isCreative) { - val box = if (player.vehicle != null && !player.vehicle!!.isRemoved) { - player.boundingBox.union(player.vehicle!!.boundingBox).expand(1.0, 0.0, 1.0) + val vehicle = player.vehicle + val box = if (vehicle != null && !vehicle.isRemoved) { + player.boundingBox.union(vehicle.boundingBox).expand(1.0, 0.0, 1.0) } else { player.boundingBox.expand(1.0, 0.5, 1.0) } - val items = world.getEntitiesByType(EntityType.ITEM, box) { entity -> itemsToPickup.contains(entity.stack.item) && entity.isOnGround }.map { i -> i.stack.item } - if (items.isNotEmpty() && InventoryContainer.spaceAvailable(StackSelection.selectStack { isOneOfItems(items) }) == 0) { + val items = world.getEntitiesByType(EntityType.ITEM, box) { + entity -> itemsToPickup.contains(entity.stack.item) && entity.isOnGround + }.map { i -> i.stack.item } + if (items.isNotEmpty() && InventoryContainer.spaceAvailable(StackSelection.selectStack { isOneOfItems(items) }) <= 0) { if (trashSomething()) timer.reset() } } @@ -83,39 +118,4 @@ object EasyTrash : Module( } return false } - - /** - * Called when a slot is clicked in a screen handler. - * Returns true if the click was handled - */ - @JvmStatic - fun onClick(slotIndex: Int, button: Int, actionType: SlotActionType): Boolean = - runSafe { - if (!isEnabled) return false - if (actionType != SlotActionType.QUICK_MOVE || button != 0) return false - val screenHandler = player.currentScreenHandler - - if (screenHandler is GenericContainerScreenHandler) { - val slot = screenHandler.getSlot(slotIndex) - val rows = screenHandler.rows - - if (slotIndex >= rows * 9) return false // Not in the container - - val inventorySlots = screenHandler.slots.subList(rows * 9, screenHandler.slots.size) - val freeInventorySlot = inventorySlots.any { !it.hasStack() } - if (freeInventorySlot) return false - - StackSelection.selectStack { - isOneOfItems(itemsCanTrash) - }.filterSlots(InventoryContainer.slots).firstOrNull()?.let { trashSlot -> - inventoryRequest { - pickup(slot.id, 0) - pickup(trashSlot.id, 0) - pickup(ScreenHandler.EMPTY_SPACE_SLOT_INDEX, 0) - }.submit(true) - return true - } - } - return false - } ?: false } \ No newline at end of file From 9c6358ecae011558286fe4e63a12b9a0867490ed Mon Sep 17 00:00:00 2001 From: IceTank <61137113+IceTank@users.noreply.github.com> Date: Tue, 27 Jan 2026 03:24:10 +0100 Subject: [PATCH 6/6] Add named module initialization parameters --- .../kotlin/com/lambda/module/modules/player/EasyTrash.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt index c10bac895..2645bb5af 100644 --- a/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt +++ b/src/main/kotlin/com/lambda/module/modules/player/EasyTrash.kt @@ -38,9 +38,9 @@ import net.minecraft.screen.slot.SlotActionType import kotlin.time.Duration.Companion.milliseconds object EasyTrash : Module( - "EasyTrash", - "Automatically trashes unwanted items", - ModuleTag.PLAYER + name = "EasyTrash", + description = "Automatically trashes unwanted items", + tag = ModuleTag.PLAYER ) { private val itemsCanTrash by setting("Items Can Trash", setOf(Items.NETHERRACK, Items.COBBLESTONE), ITEM.toSet())