diff --git a/src/main/java/com/lambda/mixin/player/MixinPlayerControllerMP.java b/src/main/java/com/lambda/mixin/player/MixinPlayerControllerMP.java index c0e173f53..14a2b112f 100644 --- a/src/main/java/com/lambda/mixin/player/MixinPlayerControllerMP.java +++ b/src/main/java/com/lambda/mixin/player/MixinPlayerControllerMP.java @@ -2,12 +2,15 @@ import com.lambda.client.event.LambdaEventBus; import com.lambda.client.event.events.PlayerAttackEvent; +import com.lambda.client.module.modules.player.NoGhostItems; import com.lambda.client.module.modules.player.TpsSync; import com.lambda.client.util.TpsCalculator; import net.minecraft.block.state.IBlockState; import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.ClickType; +import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; @@ -15,6 +18,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(PlayerControllerMP.class) public class MixinPlayerControllerMP { @@ -33,4 +37,12 @@ public void attackEntity(EntityPlayer playerIn, Entity targetEntity, CallbackInf ci.cancel(); } } + + @Inject(method = "windowClick", at = @At("HEAD"), cancellable = true) + public void onWindowClick(int windowId, int slotId, int mouseButton, ClickType type, EntityPlayer player, CallbackInfoReturnable cir) { + if (NoGhostItems.INSTANCE.isEnabled()) { + NoGhostItems.INSTANCE.handleWindowClick(windowId, slotId, mouseButton, type, player); + cir.cancel(); + } + } } diff --git a/src/main/kotlin/com/lambda/client/module/modules/player/NoGhostItems.kt b/src/main/kotlin/com/lambda/client/module/modules/player/NoGhostItems.kt new file mode 100644 index 000000000..b7b373a50 --- /dev/null +++ b/src/main/kotlin/com/lambda/client/module/modules/player/NoGhostItems.kt @@ -0,0 +1,54 @@ +package com.lambda.client.module.modules.player + +import com.lambda.client.event.events.PacketEvent +import com.lambda.client.event.listener.listener +import com.lambda.client.module.Category +import com.lambda.client.module.Module +import com.lambda.client.util.threads.runSafe +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.inventory.ClickType +import net.minecraft.item.ItemStack +import net.minecraft.network.play.client.CPacketClickWindow +import net.minecraft.network.play.server.SPacketConfirmTransaction + +object NoGhostItems : Module( + name = "NoGhostItems", + description = "Syncs inventory transactions for strict environments", + category = Category.PLAYER +) { + private val timeout by setting("Timeout in ticks", 5, 1..50, 1) + + private var pendingTransaction: InventoryTransaction? = null + private var lastPending = System.currentTimeMillis() + + init { + listener { event -> + if (event.packet is SPacketConfirmTransaction) { + pendingTransaction?.let { + it.player.openContainer.slotClick(it.slotId, it.mouseButton, it.type, it.player) + pendingTransaction = null + } + } + } + } + + fun handleWindowClick(windowId: Int, slotId: Int, mouseButton: Int, type: ClickType, player: EntityPlayer) { + val transaction = InventoryTransaction(windowId, slotId, mouseButton, type, player) + + if (pendingTransaction == null || System.currentTimeMillis() - lastPending > timeout * 50L) { + val transactionID = transaction.player.openContainer.getNextTransactionID(transaction.player.inventory) + pendingTransaction = transaction + lastPending = System.currentTimeMillis() + + runSafe { + connection.sendPacket(CPacketClickWindow(transaction.windowId, transaction.slotId, transaction.mouseButton, transaction.type, ItemStack.EMPTY, transactionID)) + } + } + } + + data class InventoryTransaction(val windowId: Int, val slotId: Int, val mouseButton: Int, val type: ClickType, val player: EntityPlayer) { + override fun toString(): String { + return "windowId: $windowId slotId: $slotId mouseButton: $mouseButton type: ${type.name} player: ${player.name}" + } + } +} \ No newline at end of file