diff --git a/patches/minecraft/net/minecraft/commands/CommandSourceStack.java.patch b/patches/minecraft/net/minecraft/commands/CommandSourceStack.java.patch index c96aa628d3..72ff47b2de 100644 --- a/patches/minecraft/net/minecraft/commands/CommandSourceStack.java.patch +++ b/patches/minecraft/net/minecraft/commands/CommandSourceStack.java.patch @@ -8,4 +8,4 @@ +public class CommandSourceStack implements SharedSuggestionProvider, net.minecraftforge.common.extensions.IForgeCommandSourceStack { public static final SimpleCommandExceptionType f_81286_ = new SimpleCommandExceptionType(Component.m_237115_("permissions.requires.player")); public static final SimpleCommandExceptionType f_81287_ = new SimpleCommandExceptionType(Component.m_237115_("permissions.requires.entity")); - private final CommandSource f_81288_; + public final CommandSource f_81288_; diff --git a/patches/minecraft/net/minecraft/world/inventory/AbstractContainerMenu.java.patch b/patches/minecraft/net/minecraft/world/inventory/AbstractContainerMenu.java.patch index 83e37169a7..d19cd584c8 100644 --- a/patches/minecraft/net/minecraft/world/inventory/AbstractContainerMenu.java.patch +++ b/patches/minecraft/net/minecraft/world/inventory/AbstractContainerMenu.java.patch @@ -12,6 +12,14 @@ for(ContainerListener containerlistener : this.f_38848_) { containerlistener.m_7934_(this, p_150408_, itemstack1); } +@@ -400,6 +_,7 @@ + ItemStack itemstack11 = this.m_142621_(); + p_150434_.m_141945_(itemstack11, slot7.m_7993_(), clickaction); + if (!itemstack11.m_150926_(slot7, clickaction, p_150434_) && !itemstack10.m_150932_(itemstack11, slot7, clickaction, p_150434_, this.m_150446_())) { ++ if (!net.minecraftforge.common.ForgeHooks.onItemStackedOn(itemstack11, itemstack10, slot7, clickaction, p_150434_, m_150446_())) + if (itemstack10.m_41619_()) { + if (!itemstack11.m_41619_()) { + int l2 = clickaction == ClickAction.PRIMARY ? itemstack11.m_41613_() : 1; @@ -601,14 +_,15 @@ ItemStack itemstack = slot.m_7993_(); if (!itemstack.m_41619_() && ItemStack.m_150942_(p_38904_, itemstack)) { diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index 9c998ea1a5..ed57b0a316 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -60,7 +60,10 @@ import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.DefaultAttributes; import net.minecraft.world.entity.monster.EnderMan; +import net.minecraft.world.entity.SlotAccess; +import net.minecraft.world.inventory.ClickAction; import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.*; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.RecipeType; @@ -115,6 +118,7 @@ import net.minecraftforge.event.DifficultyChangeEvent; import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.event.GrindstoneEvent; import net.minecraftforge.event.ItemAttributeModifierEvent; +import net.minecraftforge.event.ItemStackedOnOtherEvent; import net.minecraftforge.event.ModMismatchEvent; import net.minecraftforge.event.ServerChatEvent; import net.minecraftforge.event.RegisterStructureConversionsEvent; @@ -266,6 +270,11 @@ public class ForgeHooks return false; } + public static boolean onItemStackedOn(ItemStack carriedItem, ItemStack stackedOnItem, Slot slot, ClickAction action, Player player, SlotAccess carriedSlotAccess) + { + return MinecraftForge.EVENT_BUS.post(new ItemStackedOnOtherEvent(carriedItem, stackedOnItem, slot, action, player, carriedSlotAccess)); + } + public static void onDifficultyChange(Difficulty difficulty, Difficulty oldDifficulty) { MinecraftForge.EVENT_BUS.post(new DifficultyChangeEvent(difficulty, oldDifficulty)); diff --git a/src/main/java/net/minecraftforge/event/ItemStackedOnOtherEvent.java b/src/main/java/net/minecraftforge/event/ItemStackedOnOtherEvent.java new file mode 100644 index 0000000000..dc82ca6d30 --- /dev/null +++ b/src/main/java/net/minecraftforge/event/ItemStackedOnOtherEvent.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.event; + +import net.minecraft.world.entity.SlotAccess; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ClickAction; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.LogicalSide; + +import org.jetbrains.annotations.ApiStatus; + +/** + * This event provides the functionality of the pair of functions used for the Bundle, in one event: + *
+ * This event is {@linkplain Cancelable cancellable}, and does not {@linkplain HasResult have a result}. + * If the event is cancelled, the container's logic halts, the carried item and the slot will not be swapped, and handling is assumed to have been done by the mod. + * This also means that the two vanilla checks described above will not be called. + */ +@Cancelable +public class ItemStackedOnOtherEvent extends Event +{ + private final ItemStack carriedItem; + private final ItemStack stackedOnItem; + private final Slot slot; + private final ClickAction action; + private final Player player; + private final SlotAccess carriedSlotAccess; + + @ApiStatus.Internal + public ItemStackedOnOtherEvent(ItemStack carriedItem, ItemStack stackedOnItem, Slot slot, ClickAction action, Player player, SlotAccess carriedSlotAccess) + { + this.carriedItem = carriedItem; + this.stackedOnItem = stackedOnItem; + this.slot = slot; + this.action = action; + this.player = player; + this.carriedSlotAccess = carriedSlotAccess; + } + + /** + * {@return the stack being carried by the mouse} This may be empty! + */ + public ItemStack getCarriedItem() + { + return carriedItem; + } + + /** + * {@return the stack currently in the slot being clicked on} This may be empty! + */ + public ItemStack getStackedOnItem() + { + return stackedOnItem; + } + + /** + * {@return the slot being clicked on} + */ + public Slot getSlot() + { + return slot; + } + + /** + * {@return the click action being used} By default {@linkplain ClickAction#PRIMARY} corresponds to left-click, and {@linkplain ClickAction#SECONDARY} is right-click. + */ + public ClickAction getClickAction() + { + return action; + } + + /** + * {@return the player doing the item swap attempt} + */ + public Player getPlayer() + { + return player; + } + + /** + * {@return a fake slot allowing the listener to see and change what item is being carried} + */ + public SlotAccess getCarriedSlotAccess() + { + return carriedSlotAccess; + } +} diff --git a/src/test/java/net/minecraftforge/debug/item/ItemStackedOnOtherTest.java b/src/test/java/net/minecraftforge/debug/item/ItemStackedOnOtherTest.java new file mode 100644 index 0000000000..dc2d88d736 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/item/ItemStackedOnOtherTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.debug.item; + +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ClickAction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.ItemStackedOnOtherEvent; +import net.minecraftforge.fml.common.Mod; + +@Mod(ItemStackedOnOtherTest.MODID) +public class ItemStackedOnOtherTest +{ + public static final String MODID = "item_stacked_on_other_test"; + + private static final boolean ENABLED = true; + + public ItemStackedOnOtherTest() + { + if (ENABLED) + { + MinecraftForge.EVENT_BUS.addListener(this::onStackedOn); + } + } + + /** + * When right clicking on a damageable item with a diamond sword + */ + private void onStackedOn(ItemStackedOnOtherEvent event) + { + Player player = event.getPlayer(); + if (!player.isCreative() && event.getClickAction() == ClickAction.SECONDARY) + { + ItemStack carried = event.getCarriedItem(); + ItemStack current = event.getStackedOnItem(); + if (carried.is(Items.DIAMOND_SWORD) && current.isDamageableItem()) + { + current.hurtAndBreak(1, player, p -> {}); + event.setCanceled(true); + } + } + } +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index 578d584685..56cbc5b701 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -263,6 +263,8 @@ modId="custom_color_resolver_test" [[mods]] modId="custom_item_decorations_test" [[mods]] +modId="item_stacked_on_other_test" +[[mods]] modId="ambient_occlusion_elements_test"