Skip to content

Commit

Permalink
Add PlayerEnchantItemEvent (#1363)
Browse files Browse the repository at this point in the history
This event is fired after a player enchants an item, allowing other mods to react to that action.
  • Loading branch information
Caltinor committed Aug 6, 2024
1 parent c556779 commit 74a0608
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,14 @@
- itemstack2 = itemstack.transmuteCopy(Items.ENCHANTED_BOOK);
- this.enchantSlots.setItem(0, itemstack2);
- }
-
- for (EnchantmentInstance enchantmentinstance : list) {
- itemstack2.enchant(enchantmentinstance.enchantment, enchantmentinstance.level);
- }
+ // Neo: Allow items to transform themselves when enchanted, instead of relying on hardcoded transformations for Items.BOOK
+ itemstack2 = itemstack.getItem().applyEnchantments(itemstack, list);
+ this.enchantSlots.setItem(0, itemstack2);
+ net.neoforged.neoforge.common.CommonHooks.onPlayerEnchantItem(p_39465_, itemstack2, list);

itemstack1.consume(i, p_39465_);
if (itemstack1.isEmpty()) {
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/net/neoforged/neoforge/common/CommonHooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
import net.minecraft.world.inventory.AnvilMenu;
import net.minecraft.world.inventory.ClickAction;
import net.minecraft.world.inventory.ContainerLevelAccess;
import net.minecraft.world.inventory.EnchantmentMenu;
import net.minecraft.world.inventory.RecipeBookType;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.AdventureModePredicate;
Expand All @@ -120,6 +121,7 @@
import net.minecraft.world.item.component.ItemAttributeModifiers;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.minecraft.world.item.enchantment.ItemEnchantments;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.GameType;
Expand Down Expand Up @@ -200,6 +202,7 @@
import net.neoforged.neoforge.event.entity.player.AnvilRepairEvent;
import net.neoforged.neoforge.event.entity.player.AttackEntityEvent;
import net.neoforged.neoforge.event.entity.player.CriticalHitEvent;
import net.neoforged.neoforge.event.entity.player.PlayerEnchantItemEvent;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
import net.neoforged.neoforge.event.level.BlockDropsEvent;
Expand Down Expand Up @@ -665,6 +668,18 @@ public static InteractionResult onPlaceItemIntoWorld(UseOnContext context) {
return ret;
}

/**
* Fires {@link PlayerEnchantItemEvent} in {@link EnchantmentMenu#clickMenuButton(Player, int)} after the enchants are
* applied to the item.
*
* @param player the player who clicked the menu button
* @param stack the item enchanted
* @param instances the specific enchantments that were applied to the item.
*/
public static void onPlayerEnchantItem(Player player, ItemStack stack, List<EnchantmentInstance> instances) {
NeoForge.EVENT_BUS.post(new PlayerEnchantItemEvent(player, stack, instances));
}

public static boolean onAnvilChange(AnvilMenu container, ItemStack left, ItemStack right, Container outputSlot, String name, long baseCost, Player player) {
AnvilUpdateEvent e = new AnvilUpdateEvent(left, right, name, baseCost, player);
if (NeoForge.EVENT_BUS.post(e).isCanceled())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.event.entity.player;

import java.util.List;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.neoforged.neoforge.common.extensions.IItemExtension;

/**
* This event fires when a player enchants an item, after {@link IItemExtension#applyEnchantments} has been called.
* <p>
* This event is only fired on the logical server.
*/
public class PlayerEnchantItemEvent extends PlayerEvent {
private final ItemStack enchantedItem;
private final List<EnchantmentInstance> enchantments;

public PlayerEnchantItemEvent(Player player, ItemStack enchantedItem, List<EnchantmentInstance> enchantments) {
super(player);
this.enchantedItem = enchantedItem;
this.enchantments = enchantments;
}

/**
* @return the {@link ItemStack} after it was enchanted
*/
public ItemStack getEnchantedItem() {
return enchantedItem;
}

/**
* @return the list of {@link EnchantmentInstance}s that were applied to the item for this event firing
*/
public List<EnchantmentInstance> getEnchantments() {
return enchantments;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package net.neoforged.neoforge.debug.enchantment;

import java.util.Objects;
import net.minecraft.core.BlockPos;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.Registries;
import net.minecraft.gametest.framework.GameTest;
Expand All @@ -14,7 +16,10 @@
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.item.enchantment.ItemEnchantments;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.EnchantingTableBlockEntity;
import net.neoforged.neoforge.event.enchanting.GetEnchantmentLevelEvent;
import net.neoforged.neoforge.event.entity.player.PlayerEnchantItemEvent;
import net.neoforged.testframework.DynamicTest;
import net.neoforged.testframework.annotation.ForEachTest;
import net.neoforged.testframework.annotation.TestHolder;
Expand All @@ -23,7 +28,7 @@

@ForEachTest(groups = EnchantmentLevelTests.GROUP)
public class EnchantmentLevelTests {
public static final String GROUP = "enchantment.level";
public static final String GROUP = "enchantment";

@GameTest
@EmptyTemplate
Expand Down Expand Up @@ -65,4 +70,35 @@ static void getEnchLevelEvent(final DynamicTest test, final RegistrationHelper r
helper.succeed();
});
}

@GameTest
@EmptyTemplate
@TestHolder(description = "Tests if the PlayerEnchantedItemEvent fired.")
static void playerEnchantItemTest(final DynamicTest test, final RegistrationHelper reg) {
test.eventListeners().forge().addListener((PlayerEnchantItemEvent event) -> {
event.getEnchantedItem().setDamageValue(1); //change a value we can reference in our test sequence
});
final BlockPos pos = new BlockPos(1, 2, 1);
test.onGameTest(helper -> helper.startSequence(helper::makeMockPlayer)
//ensure the player has enough experience to perform an enchantment
.thenExecute(player -> player.experienceLevel = 30)
//place a table into the world to hold our container
.thenExecute(player -> helper.setBlock(pos, Blocks.ENCHANTING_TABLE))
//open the menu container on the player
.thenExecute(player -> player.containerMenu = Objects.requireNonNull(Objects.requireNonNull(
Objects.requireNonNull(helper.getBlockEntity(pos, EnchantingTableBlockEntity.class)).getBlockState()
.getMenuProvider(player.level(), helper.absolutePos(pos)))
.createMenu(1, player.getInventory(), player)))
//simulate putting an iron sword in the first slot
.thenExecute(player -> player.containerMenu.setItem(0, player.containerMenu.getStateId(), new ItemStack(Items.IRON_SWORD)))
//simulate putting the lapis into the second slot
.thenExecute(player -> player.containerMenu.setItem(1, player.containerMenu.getStateId(), new ItemStack(Items.LAPIS_LAZULI)))
//ensure the lapis count is enough to pay for any enchanting costs
.thenExecute(player -> player.containerMenu.getSlot(1).getItem().setCount(64))
//simulate clicking the button on the screen.
.thenExecute(player -> player.containerMenu.clickMenuButton(player, 1))
//verify the event listener has set the damage value of our item to one
.thenWaitUntil(player -> helper.assertTrue(player.containerMenu.getSlot(0).getItem().getDamageValue() == 1, "Enchanted item damage not set by the event"))
.thenSucceed());
}
}

0 comments on commit 74a0608

Please sign in to comment.