diff --git a/gradle.properties b/gradle.properties index dfee058..e6ca9f5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ loader_version=0.14.17 # Mod Properties mod_version = 0.1.0 -maven_group = today.theladpack +maven_group = io.github.twokilohertz archives_base_name = HotbarReplace # Dependencies diff --git a/src/main/java/io/github/twokilohertz/HotbarReplace.java b/src/main/java/io/github/twokilohertz/HotbarReplace.java new file mode 100644 index 0000000..b599d92 --- /dev/null +++ b/src/main/java/io/github/twokilohertz/HotbarReplace.java @@ -0,0 +1,67 @@ +package io.github.twokilohertz; + +import net.fabricmc.api.ModInitializer; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.slot.SlotActionType; +import org.lwjgl.glfw.GLFW; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class HotbarReplace implements ModInitializer { + public static final Logger LOGGER = LoggerFactory.getLogger("hotbarreplace"); + private static final MinecraftClient client = MinecraftClient.getInstance(); + private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + + @Override + public void onInitialize() { + LOGGER.info("HotbarReplace initialised"); + } + + public static void tryReplaceSlot(ItemPlacementContext context, Item item) { + // Return immediately if player is a spectator + PlayerEntity player = context.getPlayer(); + if (player.isSpectator()) return; + + // Creative inventories don't run out of anyway + if (player.getAbilities().creativeMode) return; + + // Get reference to player's current inventory + PlayerInventory inventory = player.getInventory(); + if (inventory == null) return; + + // Return if the inventory is empty + if (inventory.isEmpty()) return; + + // Attempt to find a stack of matching items + for (int i = 0; i < inventory.main.size(); i++) { + if (i == inventory.selectedSlot) continue; + + ItemStack stack = inventory.main.get(i); + + if (stack.isOf(item)) { + // Simulate moving the stack from one slot to another + if (client != null) { + client.interactionManager.clickSlot(player.currentScreenHandler.syncId, i, GLFW.GLFW_MOUSE_BUTTON_1, SlotActionType.PICKUP, player); + + // Wait 50 seconds (on another thread) before attempting to move the new stack + // The magic number 36 is the offset to get the hotbar slotId + scheduler.schedule(() -> { + client.interactionManager.clickSlot(player.currentScreenHandler.syncId, inventory.selectedSlot + 36, GLFW.GLFW_MOUSE_BUTTON_1, SlotActionType.PICKUP, player); + }, 50, TimeUnit.MILLISECONDS); + } + + return; + } + } + } +} diff --git a/src/main/java/io/github/twokilohertz/mixin/BlockItemMixin.java b/src/main/java/io/github/twokilohertz/mixin/BlockItemMixin.java new file mode 100644 index 0000000..90642c2 --- /dev/null +++ b/src/main/java/io/github/twokilohertz/mixin/BlockItemMixin.java @@ -0,0 +1,32 @@ +package io.github.twokilohertz.mixin; + +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.util.ActionResult; +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.CallbackInfoReturnable; +import io.github.twokilohertz.HotbarReplace; + +@Mixin(BlockItem.class) +public class BlockItemMixin { + private Item lastPlacedItem; + + @Inject(at = @At("HEAD"), method = "Lnet/minecraft/item/BlockItem;place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;") + private void BlockItem_place_head(ItemPlacementContext context, CallbackInfoReturnable info) { + lastPlacedItem = context.getStack().getItem(); + } + @Inject(at = @At("TAIL"), method = "Lnet/minecraft/item/BlockItem;place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;") + private void mixin_BlockItem_place_tail(ItemPlacementContext context, CallbackInfoReturnable info) { + // Early return if the block place action would fail + if (info.getReturnValue() != ActionResult.SUCCESS) return; + + // Check if the stack is not empty, return if so + if (context.getStack().getCount() != 0) return; + + // Try to replace the hotbar slot + HotbarReplace.tryReplaceSlot(context, lastPlacedItem); + } +} diff --git a/src/main/java/today/theladpack/hotbarreplace/HotbarReplace.java b/src/main/java/today/theladpack/hotbarreplace/HotbarReplace.java deleted file mode 100644 index 18bc3a8..0000000 --- a/src/main/java/today/theladpack/hotbarreplace/HotbarReplace.java +++ /dev/null @@ -1,21 +0,0 @@ -package today.theladpack.hotbarreplace; - -import net.fabricmc.api.ModInitializer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class HotbarReplace implements ModInitializer { - // This logger is used to write text to the console and the log file. - // It is considered best practice to use your mod id as the logger's name. - // That way, it's clear which mod wrote info, warnings, and errors. - public static final Logger LOGGER = LoggerFactory.getLogger("hotbarreplace"); - - @Override - public void onInitialize() { - // This code runs as soon as Minecraft is in a mod-load-ready state. - // However, some things (like resources) may still be uninitialized. - // Proceed with mild caution. - - LOGGER.info("Hello from the main class"); - } -} diff --git a/src/main/java/today/theladpack/hotbarreplace/mixin/HotbarReplaceMixin.java b/src/main/java/today/theladpack/hotbarreplace/mixin/HotbarReplaceMixin.java deleted file mode 100644 index 4f8a2bc..0000000 --- a/src/main/java/today/theladpack/hotbarreplace/mixin/HotbarReplaceMixin.java +++ /dev/null @@ -1,16 +0,0 @@ -package today.theladpack.hotbarreplace.mixin; - -import net.minecraft.client.gui.screen.TitleScreen; -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 today.theladpack.hotbarreplace.HotbarReplace; - -@Mixin(TitleScreen.class) -public class HotbarReplaceMixin { - @Inject(at = @At("HEAD"), method = "init()V") - private void init(CallbackInfo info) { - HotbarReplace.LOGGER.info("Hello from the HotbarReplace mixin"); - } -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index d8df644..d531ce5 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -9,8 +9,8 @@ "Adam Macdonald" ], "contact": { - "homepage": "https://theladpack.today/", - "sources": "https://theladpack.today/" + "homepage": "https://twokilohertz.github.io/", + "sources": "https://twokilohertz.github.io/" }, "license": "GPLv3", @@ -19,7 +19,7 @@ "environment": "*", "entrypoints": { "main": [ - "today.theladpack.hotbarreplace.HotbarReplace" + "io.github.twokilohertz.HotbarReplace" ] }, "mixins": [ diff --git a/src/main/resources/hotbarreplace.mixins.json b/src/main/resources/hotbarreplace.mixins.json index 0933d78..2955140 100644 --- a/src/main/resources/hotbarreplace.mixins.json +++ b/src/main/resources/hotbarreplace.mixins.json @@ -1,12 +1,12 @@ { "required": true, "minVersion": "0.8", - "package": "today.theladpack.hotbarreplace.mixin", + "package": "io.github.twokilohertz.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ ], "client": [ - "HotbarReplaceMixin" + "BlockItemMixin" ], "injectors": { "defaultRequire": 1