diff --git a/src/main/java/net/shadowfacts/autoswap/mixin/MixinServerPlayerInteractionManager.java b/src/main/java/net/shadowfacts/autoswap/mixin/MixinServerPlayerInteractionManager.java new file mode 100644 index 0000000..a82dc32 --- /dev/null +++ b/src/main/java/net/shadowfacts/autoswap/mixin/MixinServerPlayerInteractionManager.java @@ -0,0 +1,54 @@ +package net.shadowfacts.autoswap.mixin; + +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.network.ServerPlayerInteractionManager; +import net.minecraft.util.ActionResult; +import net.minecraft.util.math.BlockPos; +import net.shadowfacts.autoswap.AutoSwap; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * @author shadowfacts + */ +@Mixin(ServerPlayerInteractionManager.class) +public abstract class MixinServerPlayerInteractionManager { + + @Shadow + private ServerPlayerEntity player; + + private ItemStack heldStackAtBeginningOfBreak = ItemStack.EMPTY; + + @Inject(method = "tryBreakBlock", at = @At("HEAD")) + private void beginTryBreakBlock(BlockPos pos, CallbackInfoReturnable cb) { + PlayerInventory playerInv = player.inventory; + heldStackAtBeginningOfBreak = playerInv.getInvStack(playerInv.selectedSlot).copy(); + } + + @Inject(method = "tryBreakBlock", at = @At("RETURN")) + private void endTryBreakBlock(BlockPos pos, CallbackInfoReturnable cb) { + AutoSwap.INSTANCE.endBreakBlock(player.inventory, heldStackAtBeginningOfBreak); + heldStackAtBeginningOfBreak = ItemStack.EMPTY; + } + + @Redirect( + method = "interactBlock", + at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;useOnBlock(Lnet/minecraft/item/ItemUsageContext;)Lnet/minecraft/util/ActionResult;") + ) + private ActionResult useOnBlock(ItemStack self, ItemUsageContext context) { + ItemStack selfCopy = self.copy(); + ActionResult result = self.useOnBlock(context); + if (result == ActionResult.SUCCESS) { + AutoSwap.INSTANCE.onUseOnItem(player, player.inventory, selfCopy); + } + return result; + } + +} diff --git a/src/main/kotlin/net/shadowfacts/autoswap/AutoSwap.kt b/src/main/kotlin/net/shadowfacts/autoswap/AutoSwap.kt index 3b91ceb..3edd65b 100644 --- a/src/main/kotlin/net/shadowfacts/autoswap/AutoSwap.kt +++ b/src/main/kotlin/net/shadowfacts/autoswap/AutoSwap.kt @@ -1,7 +1,47 @@ package net.shadowfacts.autoswap +import net.fabricmc.api.ModInitializer +import net.minecraft.client.network.packet.EntityEquipmentUpdateS2CPacket +import net.minecraft.client.network.packet.ItemPickupAnimationS2CPacket +import net.minecraft.entity.EquipmentSlot +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.entity.player.PlayerInventory +import net.minecraft.item.ItemStack +import net.minecraft.server.network.ServerPlayerEntity +import net.minecraft.util.math.BlockPos + /** * @author shadowfacts */ -class AutoSwap { +object AutoSwap: ModInitializer { + + override fun onInitialize() { + } + + fun endBreakBlock(playerInv: PlayerInventory, heldStackAtBeginningOfBreak: ItemStack) { + val currentlySelected = playerInv.mainHandStack + if (currentlySelected.isEmpty && !heldStackAtBeginningOfBreak.isEmpty) { + val index = playerInv.main.indexOfFirst { + ItemStack.areItemsEqualIgnoreDamage(heldStackAtBeginningOfBreak, it) + } + if (index >= 0) { + playerInv.swapSlotWithHotbar(index) + } + } + } + + fun onUseOnItem(player: ServerPlayerEntity, playerInv: PlayerInventory, heldStackBeforeUse: ItemStack) { + val heldStack = playerInv.mainHandStack + if (!player.isCreative && heldStack.isEmpty) { + val index = playerInv.main.indexOfFirst { + ItemStack.areItemsEqualIgnoreDamage(heldStackBeforeUse, it) + } + if (index >= 0) { + playerInv.swapSlotWithHotbar(index) + val newStack = playerInv.mainHandStack + player.networkHandler.sendPacket(EntityEquipmentUpdateS2CPacket(player.entityId, EquipmentSlot.MAINHAND, newStack)) + } + } + } + } \ No newline at end of file diff --git a/src/main/resources/autoswap.mixins.json b/src/main/resources/autoswap.mixins.json new file mode 100644 index 0000000..5ff3a3e --- /dev/null +++ b/src/main/resources/autoswap.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "package": "net.shadowfacts.autoswap.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "MixinServerPlayerInteractionManager" + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 69830df..9b04715 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -24,7 +24,9 @@ } ] }, - "mixins": [], + "mixins": [ + "autoswap.mixins.json" + ], "depends": { "fabricloader": ">=0.4.0",