From 1ac109c2d9deea71ac418f73a1b75f0a59d6495a Mon Sep 17 00:00:00 2001 From: YajatKaul <68262974+yajatkaul@users.noreply.github.com> Date: Sat, 8 Nov 2025 13:56:08 +0530 Subject: [PATCH 1/3] Added on itemPickup event --- .../lifecycle/v1/ServerEntityEvents.java | 18 +++++++++ .../event/lifecycle/ItemEntityMixin.java | 39 +++++++++++++++++++ .../fabric-lifecycle-events-v1.mixins.json | 1 + 3 files changed, 58 insertions(+) create mode 100644 fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java index dfc1cd7696..a1a59c0fcb 100644 --- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java +++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java @@ -18,7 +18,9 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.ItemEntity; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.server.world.ServerWorld; @@ -63,6 +65,17 @@ private ServerEntityEvents() { } }); + /** + * Called during {@link ItemEntity#tick()} if an entity tries to pick up any ItemEntity. + * + *

Picking up of an item is determined by {@link ItemEntity#onPlayerCollision(PlayerEntity)}. + */ + public static final Event ITEM_PICKUP = EventFactory.createArrayBacked(ServerEntityEvents.ItemPickup.class, callbacks -> (playerEntity, itemEntity, itemStack) -> { + for (ItemPickup callback : callbacks) { + callback.onPickup(playerEntity, itemEntity, itemStack); + } + }); + @FunctionalInterface public interface Load { void onLoad(Entity entity, ServerWorld world); @@ -77,4 +90,9 @@ public interface Unload { public interface EquipmentChange { void onChange(LivingEntity livingEntity, EquipmentSlot equipmentSlot, ItemStack previousStack, ItemStack currentStack); } + + @FunctionalInterface + public interface ItemPickup { + void onPickup(PlayerEntity playerEntity, ItemEntity itemEntity, ItemStack itemStack); + } } diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java new file mode 100644 index 0000000000..5086809876 --- /dev/null +++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.event.lifecycle; + +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 net.minecraft.entity.ItemEntity; +import net.minecraft.entity.player.PlayerEntity; + +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents; + +@Mixin(ItemEntity.class) +public class ItemEntityMixin { + @Inject(method = "onPlayerCollision", at = @At("HEAD")) + private void onPlayerPickup(PlayerEntity playerEntity, CallbackInfo ci) { + ItemEntity itemEntity = (ItemEntity) (Object) this; + + if (!itemEntity.getWorld().isClient && !itemEntity.cannotPickup()) { + ServerEntityEvents.ITEM_PICKUP.invoker().onPickup(playerEntity, itemEntity, itemEntity.getStack()); + } + } +} diff --git a/fabric-lifecycle-events-v1/src/main/resources/fabric-lifecycle-events-v1.mixins.json b/fabric-lifecycle-events-v1/src/main/resources/fabric-lifecycle-events-v1.mixins.json index 3beeeae11e..b1532d62f0 100644 --- a/fabric-lifecycle-events-v1/src/main/resources/fabric-lifecycle-events-v1.mixins.json +++ b/fabric-lifecycle-events-v1/src/main/resources/fabric-lifecycle-events-v1.mixins.json @@ -6,6 +6,7 @@ "ChunkGeneratingMixin", "ChunkHolderMixin", "DataPackContentsMixin", + "ItemEntityMixin", "LivingEntityMixin", "MinecraftServerMixin", "PlayerManagerMixin", From 782147e138c10169f585b0d630ee7ce08292a9f5 Mon Sep 17 00:00:00 2001 From: YajatKaul <68262974+yajatkaul@users.noreply.github.com> Date: Sat, 8 Nov 2025 17:07:18 +0530 Subject: [PATCH 2/3] Now item pickup is cancellable --- .../lifecycle/v1/ServerEntityEvents.java | 21 +++++++++++++------ .../event/lifecycle/ItemEntityMixin.java | 8 +++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java index a1a59c0fcb..7f3adb4415 100644 --- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java +++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java @@ -70,11 +70,20 @@ private ServerEntityEvents() { * *

Picking up of an item is determined by {@link ItemEntity#onPlayerCollision(PlayerEntity)}. */ - public static final Event ITEM_PICKUP = EventFactory.createArrayBacked(ServerEntityEvents.ItemPickup.class, callbacks -> (playerEntity, itemEntity, itemStack) -> { - for (ItemPickup callback : callbacks) { - callback.onPickup(playerEntity, itemEntity, itemStack); - } - }); + public static final Event ITEM_PICKUP = EventFactory.createArrayBacked( + ItemPickup.class, + (callbacks) -> (playerEntity, itemEntity, itemStack) -> { + for (ItemPickup callback : callbacks) { + boolean shouldContinue = callback.onPickup(playerEntity, itemEntity, itemStack); + + if (!shouldContinue) { + return false; + } + } + + return true; + } + ); @FunctionalInterface public interface Load { @@ -93,6 +102,6 @@ public interface EquipmentChange { @FunctionalInterface public interface ItemPickup { - void onPickup(PlayerEntity playerEntity, ItemEntity itemEntity, ItemStack itemStack); + boolean onPickup(PlayerEntity playerEntity, ItemEntity itemEntity, ItemStack itemStack); } } diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java index 5086809876..b1aebdef8c 100644 --- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java +++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java @@ -28,12 +28,16 @@ @Mixin(ItemEntity.class) public class ItemEntityMixin { - @Inject(method = "onPlayerCollision", at = @At("HEAD")) + @Inject(method = "onPlayerCollision", at = @At("HEAD"), cancellable = true) private void onPlayerPickup(PlayerEntity playerEntity, CallbackInfo ci) { ItemEntity itemEntity = (ItemEntity) (Object) this; if (!itemEntity.getWorld().isClient && !itemEntity.cannotPickup()) { - ServerEntityEvents.ITEM_PICKUP.invoker().onPickup(playerEntity, itemEntity, itemEntity.getStack()); + boolean allowPickup = ServerEntityEvents.ITEM_PICKUP.invoker().onPickup(playerEntity, itemEntity, itemEntity.getStack()); + + if (!allowPickup) { + ci.cancel(); + } } } } From 5b475b5f9ba2ecb9ba7a3c4c80105a1bc26a260c Mon Sep 17 00:00:00 2001 From: YajatKaul <68262974+yajatkaul@users.noreply.github.com> Date: Mon, 10 Nov 2025 10:52:21 +0530 Subject: [PATCH 3/3] Applying suggested changes --- .../api/event/lifecycle/v1/ServerEntityEvents.java | 4 +++- .../fabric/mixin/event/lifecycle/ItemEntityMixin.java | 11 ++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java index 7f3adb4415..503dd4cefc 100644 --- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java +++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/api/event/lifecycle/v1/ServerEntityEvents.java @@ -66,9 +66,11 @@ private ServerEntityEvents() { }); /** - * Called during {@link ItemEntity#tick()} if an entity tries to pick up any ItemEntity. + * Called during {@link ItemEntity#tick()} on the logical server if an entity tries to pick up any {@link ItemEntity}. * *

Picking up of an item is determined by {@link ItemEntity#onPlayerCollision(PlayerEntity)}. + * + *

Returning {@code false} prevents vanilla from handling the pick-up. */ public static final Event ITEM_PICKUP = EventFactory.createArrayBacked( ItemPickup.class, diff --git a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java index b1aebdef8c..c3cc3e5748 100644 --- a/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java +++ b/fabric-lifecycle-events-v1/src/main/java/net/fabricmc/fabric/mixin/event/lifecycle/ItemEntityMixin.java @@ -28,16 +28,13 @@ @Mixin(ItemEntity.class) public class ItemEntityMixin { - @Inject(method = "onPlayerCollision", at = @At("HEAD"), cancellable = true) + @Inject(method = "onPlayerCollision", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerInventory;insertStack(Lnet/minecraft/item/ItemStack;)Z"), cancellable = true) private void onPlayerPickup(PlayerEntity playerEntity, CallbackInfo ci) { ItemEntity itemEntity = (ItemEntity) (Object) this; + boolean allowPickup = ServerEntityEvents.ITEM_PICKUP.invoker().onPickup(playerEntity, itemEntity, itemEntity.getStack()); - if (!itemEntity.getWorld().isClient && !itemEntity.cannotPickup()) { - boolean allowPickup = ServerEntityEvents.ITEM_PICKUP.invoker().onPickup(playerEntity, itemEntity, itemEntity.getStack()); - - if (!allowPickup) { - ci.cancel(); - } + if (!allowPickup) { + ci.cancel(); } } }