From 8358b800e9d805870d41ef5e3d34050c7e2e43f7 Mon Sep 17 00:00:00 2001 From: KnightMiner Date: Wed, 30 Nov 2022 17:00:59 -0500 Subject: [PATCH] Fix some logical bugs related to the Grindstone Event (#9089) --- .../world/inventory/GrindstoneMenu.java.patch | 4 +- .../net/minecraftforge/common/ForgeHooks.java | 6 +- .../minecraftforge/event/GrindstoneEvent.java | 26 ++++-- .../debug/misc/GrindstoneEventTest.java | 86 +++++++++++++++++++ src/test/resources/META-INF/mods.toml | 2 + 5 files changed, 112 insertions(+), 12 deletions(-) create mode 100644 src/test/java/net/minecraftforge/debug/misc/GrindstoneEventTest.java diff --git a/patches/minecraft/net/minecraft/world/inventory/GrindstoneMenu.java.patch b/patches/minecraft/net/minecraft/world/inventory/GrindstoneMenu.java.patch index 8f31fefb4a..954836aefd 100644 --- a/patches/minecraft/net/minecraft/world/inventory/GrindstoneMenu.java.patch +++ b/patches/minecraft/net/minecraft/world/inventory/GrindstoneMenu.java.patch @@ -43,8 +43,8 @@ ItemStack itemstack1 = this.f_39560_.m_8020_(1); boolean flag = !itemstack.m_41619_() || !itemstack1.m_41619_(); boolean flag1 = !itemstack.m_41619_() && !itemstack1.m_41619_(); -+ this.xp = net.minecraftforge.common.ForgeHooks.onGrindstoneChange(itemstack, itemstack1, this.f_39559_, this.xp); -+ if (this.xp != Integer.MIN_VALUE) return; ++ this.xp = net.minecraftforge.common.ForgeHooks.onGrindstoneChange(itemstack, itemstack1, this.f_39559_, -1); ++ if (this.xp == Integer.MIN_VALUE) if (!flag) { this.f_39559_.m_6836_(0, ItemStack.f_41583_); } else { diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index ed57b0a316..c301c72a49 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -759,7 +759,11 @@ public class ForgeHooks public static int onGrindstoneChange(@NotNull ItemStack top, @NotNull ItemStack bottom, Container outputSlot, int xp) { GrindstoneEvent.OnplaceItem e = new GrindstoneEvent.OnplaceItem(top, bottom, xp); - if (MinecraftForge.EVENT_BUS.post(e)) return e.getXp(); + if (MinecraftForge.EVENT_BUS.post(e)) + { + outputSlot.setItem(0, ItemStack.EMPTY); + return -1; + } if (e.getOutput().isEmpty()) return Integer.MIN_VALUE; outputSlot.setItem(0, e.getOutput()); diff --git a/src/main/java/net/minecraftforge/event/GrindstoneEvent.java b/src/main/java/net/minecraftforge/event/GrindstoneEvent.java index c363ee3fda..734a5478e0 100644 --- a/src/main/java/net/minecraftforge/event/GrindstoneEvent.java +++ b/src/main/java/net/minecraftforge/event/GrindstoneEvent.java @@ -41,10 +41,7 @@ public abstract class GrindstoneEvent extends Event } /** - * This is the experience amount determined by the event, not the vanilla behavior.
- * If you are the first receiver of this event, it is guaranteed to be -1.
- * The value must be set to a positive value to override vanilla behavior.
- * if the value is equal to -1, the vanilla behavior for calculating experience will run.
+ * This is the experience amount determined by the event. It will be {@code -1} unless {@link #setXp(int)} is called.
* @return The experience amount given to the player.
*/ public int getXp() @@ -64,11 +61,22 @@ public abstract class GrindstoneEvent extends Event /** * This event is {@link Cancelable}
* {@link OnplaceItem} is fired when the inputs to a grindstone are changed.
- * It is called from {@link GrindstoneMenu#createResult()}.
- * If the event is canceled, vanilla behavior will not run, and the output will be set to {@link ItemStack#EMPTY}.
- * If the event is not canceled, but the output is not empty, it will set the output and not run vanilla behavior.
- * if the output is empty, and the event is not canceled, vanilla behavior will execute.
- * if the amount of experience is larger than or equal 0, the vanilla behavior for calculating experience will not run.
+ * + * The following rules apply: + * */ @Cancelable public static class OnplaceItem extends GrindstoneEvent diff --git a/src/test/java/net/minecraftforge/debug/misc/GrindstoneEventTest.java b/src/test/java/net/minecraftforge/debug/misc/GrindstoneEventTest.java new file mode 100644 index 0000000000..02b2d24bcb --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/misc/GrindstoneEventTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.debug.misc; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.GrindstoneEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.Bindings; +import net.minecraftforge.fml.common.Mod; + +@Mod("grindstone_event_test") +public class GrindstoneEventTest { + private static final boolean ENABLED = false; + public GrindstoneEventTest() { + if (ENABLED) { + MinecraftForge.EVENT_BUS.register(this); + } + } + + @SubscribeEvent + public void onGrindestonePlace(GrindstoneEvent.OnplaceItem event) + { + // all of these "recipes" are slot sensitive, the top and bottom must match exactly for the behavior to change + // switching the order will cause the "recipe" to fail + ItemStack topItem = event.getTopItem(); + ItemStack bottomItem = event.getBottomItem(); + // craft lapis + netherite to get diamond and 5 XP + // this "recipe" is handled in OnTakeItem so the inputs only shrink by 1 each time + if (topItem.is(Items.LAPIS_LAZULI) && bottomItem.is(Items.NETHERITE_INGOT)) + { + event.setOutput(new ItemStack(Items.DIAMOND, 1)); + event.setXp(5); + } + + // craft iron ore and flint to make raw iron ore, no XP is rewarded + // this "recipe" is *not* handled in OnTakeItem, so the inputs will always be set to empty regardless of stack size + if (topItem.is(Items.IRON_ORE) && bottomItem.is(Items.FLINT)) + { + event.setOutput(new ItemStack(Items.RAW_IRON, 3)); + event.setXp(0); + } + + // when placing an iron axe in the top slot, simply copy it to the output without change (do not remove enchants) + // still grant XP equivalent to all enchantments on the axe + if (topItem.is(Items.IRON_AXE) && bottomItem.is(Items.AIR)) + { + event.setOutput(topItem.copy()); + event.setXp(-1); + } + + // setting the output to empty will run default behavior, effectively ignoring all previous overrides to the event + // note this will ignore any XP value you set, effectively for this test mod this has no impact + if (topItem.is(Items.IRON_SHOVEL) && bottomItem.is(Items.AIR)) + { + event.setOutput(ItemStack.EMPTY); + } + + // canceling the event will prevent disenchanting an iron sword in the top slot + if (topItem.is(Items.IRON_SWORD) && bottomItem.is(Items.AIR)) + { + event.setCanceled(true); + } + } + + @SubscribeEvent + public void onGrindstoneTake(GrindstoneEvent.OnTakeItem event) + { + ItemStack topItem = event.getTopItem(); + ItemStack bottomItem = event.getBottomItem(); + // only shrink stacks by 1 for the lapis + netherite "recipe" + if (topItem.is(Items.LAPIS_LAZULI) && bottomItem.is(Items.NETHERITE_INGOT)) + { + ItemStack top = topItem.copy(); + ItemStack bottom = bottomItem.copy(); + bottom.shrink(1); + top.shrink(1); + event.setNewBottomItem(bottom); + event.setNewTopItem(top); + } + } +} \ No newline at end of file diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index a0fb47688f..5d5bfe507a 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -268,6 +268,8 @@ modId="custom_item_decorations_test" modId="item_stacked_on_other_test" [[mods]] modId="ambient_occlusion_elements_test" +[[mods]] +modId="grindstone_event_test" # ADD ABOVE THIS LINE