Skip to content

Commit 09bc7f6

Browse files
committed
Add PlayerClickSlotEvent & PlayerDropItemEvent
1 parent d5b3406 commit 09bc7f6

File tree

5 files changed

+380
-6
lines changed

5 files changed

+380
-6
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2023-2025 Fox2Code
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package com.fox2code.foxloader.event.inventory;
25+
26+
import com.fox2code.foxevents.Event;
27+
import com.fox2code.foxloader.event.player.PlayerEvent;
28+
import net.minecraft.common.block.container.Container;
29+
import net.minecraft.common.block.container.Slot;
30+
import net.minecraft.common.entity.player.EntityPlayer;
31+
import net.minecraft.common.item.ItemStack;
32+
import org.jetbrains.annotations.NotNull;
33+
import org.jetbrains.annotations.Nullable;
34+
35+
public final class PlayerClickSlotEvent extends PlayerEvent implements Event.Cancellable {
36+
private final Container container;
37+
private final int slotId, mouseButton, transferType;
38+
private final Slot slot;
39+
40+
public PlayerClickSlotEvent(@NotNull Container container, int slotId, int mouseButton,
41+
int transferType, @NotNull EntityPlayer entityPlayer) {
42+
super(entityPlayer);
43+
this.container = container;
44+
this.slotId = slotId;
45+
this.mouseButton = mouseButton;
46+
this.transferType = transferType;
47+
this.slot = slotId == -999 ? null : container.getSlot(slotId);
48+
}
49+
50+
public @NotNull Container getContainer() {
51+
return this.container;
52+
}
53+
54+
public int getSlotId() {
55+
return this.slotId;
56+
}
57+
58+
public int getMouseButton() {
59+
return this.mouseButton;
60+
}
61+
62+
public int getTransferType() {
63+
return this.transferType;
64+
}
65+
66+
public @Nullable Slot getSlot() {
67+
return this.slot;
68+
}
69+
70+
public @Nullable ItemStack getSlotItem() {
71+
return this.slotId != -999 ? (this.slot != null ? this.slot.getStack() : null) :
72+
this.getEntityPlayer().getPlayerDataInventory().getCursorStack();
73+
}
74+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2023-2025 Fox2Code
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package com.fox2code.foxloader.event.inventory;
25+
26+
import com.fox2code.foxevents.Event;
27+
import com.fox2code.foxloader.event.player.PlayerEvent;
28+
import net.minecraft.common.entity.player.EntityPlayer;
29+
import net.minecraft.common.item.ItemStack;
30+
import org.jetbrains.annotations.NotNull;
31+
32+
import java.util.Objects;
33+
34+
public final class PlayerDropItemEvent extends PlayerEvent implements Event.Cancellable {
35+
private final ItemStack itemToDrop;
36+
private final int slotId, maxAmountToDrop;
37+
private final boolean creative;
38+
39+
public PlayerDropItemEvent(@NotNull EntityPlayer entityPlayer, @NotNull ItemStack itemToDrop,
40+
int slotId, int maxAmountToDrop, boolean creative) {
41+
super(entityPlayer);
42+
this.itemToDrop = Objects.requireNonNull(itemToDrop);
43+
this.slotId = slotId;
44+
this.maxAmountToDrop = maxAmountToDrop;
45+
this.creative = creative;
46+
}
47+
48+
public @NotNull ItemStack getItemToDrop() {
49+
return this.itemToDrop;
50+
}
51+
52+
public int getAmountToDrop() {
53+
return Math.min(this.maxAmountToDrop, this.itemToDrop.stackSize);
54+
}
55+
56+
public int getMaxAmountToDrop() {
57+
return this.maxAmountToDrop;
58+
}
59+
60+
public int getSlotId() {
61+
return this.slotId;
62+
}
63+
64+
public boolean isCreative() {
65+
return this.creative;
66+
}
67+
}

loader/src/main/java/com/fox2code/foxloader/internal/InternalInteractionHooks.java

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,17 @@
2525

2626
import com.fox2code.foxevents.EventHolder;
2727
import com.fox2code.foxloader.event.interaction.*;
28+
import com.fox2code.foxloader.event.inventory.PlayerClickSlotEvent;
29+
import com.fox2code.foxloader.event.inventory.PlayerDropItemEvent;
30+
import net.minecraft.common.block.container.Container;
31+
import net.minecraft.common.block.container.Slot;
2832
import net.minecraft.common.entity.Entity;
2933
import net.minecraft.common.entity.player.EntityPlayer;
3034
import net.minecraft.common.item.ItemStack;
35+
import net.minecraft.common.networking.Packet103SetSlot;
3136
import net.minecraft.common.util.math.Vec3D;
3237
import net.minecraft.common.world.World;
38+
import net.minecraft.server.entity.player.EntityPlayerMP;
3339

3440
/**
3541
* Internal hook for player network event and interactions.
@@ -51,6 +57,10 @@ public final class InternalInteractionHooks {
5157
EventHolder.getHolderFromEvent(PlayerUseItemOnEntityEvent.class);
5258
private static final EventHolder<PlayerAttackEntityEvent> PLAYER_ATTACK_ENTITY_EVENT =
5359
EventHolder.getHolderFromEvent(PlayerAttackEntityEvent.class);
60+
private static final EventHolder<PlayerClickSlotEvent> PLAYER_CLICK_SLOT_EVENT =
61+
EventHolder.getHolderFromEvent(PlayerClickSlotEvent.class);
62+
private static final EventHolder<PlayerDropItemEvent> PLAYER_DROP_ITEM_EVENT =
63+
EventHolder.getHolderFromEvent(PlayerDropItemEvent.class);
5464

5565
public static boolean sendPlayerStartBreakBlockEvent(
5666
EntityPlayer entityPlayer, int x, int y, int z, int facing) {
@@ -111,4 +121,91 @@ public static boolean sendPlayerAttackEntityEvent(EntityPlayer player, Entity ta
111121
PLAYER_ATTACK_ENTITY_EVENT.callEvent(playerAttackEntityEvent);
112122
return playerAttackEntityEvent.isCancelled();
113123
}
124+
125+
public static boolean onHandleClickSlot(Container container, int slotId, int mouseButton,
126+
int transferType, EntityPlayer player) {
127+
if (!PLAYER_CLICK_SLOT_EVENT.isEmpty()) {
128+
PlayerClickSlotEvent playerClickSlotEvent = new PlayerClickSlotEvent(
129+
container, slotId, mouseButton, transferType, player);
130+
PLAYER_CLICK_SLOT_EVENT.callEvent(playerClickSlotEvent);
131+
if (playerClickSlotEvent.isCancelled()) {
132+
return true;
133+
}
134+
}
135+
// Handle dropping manually there.
136+
if (PLAYER_DROP_ITEM_EVENT.isEmpty()) {
137+
return false;
138+
}
139+
if ((transferType == 0 || transferType == 1) && (mouseButton == 0 || mouseButton == 1) &&
140+
slotId == -999 && player.inventory.getCursorStack() != null) {
141+
return mouseButton == 0 ? onDropCursorItemStack(player) : onDropCursorItem(player);
142+
}
143+
Slot slot;
144+
ItemStack slotStack;
145+
if (transferType == 3 && (mouseButton == 0 || mouseButton == 1) && slotId >= 0 &&
146+
slotId < container.slots.size() && (slot = container.getSlot(slotId)) != null &&
147+
(slotStack = slot.getStack()) != null) {
148+
PlayerDropItemEvent playerDropItemEvent = new PlayerDropItemEvent(
149+
player, slotStack, slotId, mouseButton == 0 ? 64 : 1, false);
150+
PLAYER_DROP_ITEM_EVENT.callEvent(playerDropItemEvent);
151+
updateSlotItemIfCancelled(playerDropItemEvent);
152+
return playerDropItemEvent.isCancelled();
153+
}
154+
return false;
155+
}
156+
157+
public static boolean onDropCurrentItem(EntityPlayer player) {
158+
if (PLAYER_DROP_ITEM_EVENT.isEmpty()) return false;
159+
PlayerDropItemEvent playerDropItemEvent = new PlayerDropItemEvent(
160+
player, player.inventory.getCurrentItem(), player.inventory.currentItem, 1, false);
161+
PLAYER_DROP_ITEM_EVENT.callEvent(playerDropItemEvent);
162+
updateSlotItemIfCancelled(playerDropItemEvent);
163+
return playerDropItemEvent.isCancelled();
164+
}
165+
166+
public static boolean onDropCurrentItemStack(EntityPlayer player) {
167+
if (PLAYER_DROP_ITEM_EVENT.isEmpty()) return false;
168+
PlayerDropItemEvent playerDropItemEvent = new PlayerDropItemEvent(
169+
player, player.inventory.getCurrentItem(), player.inventory.currentItem, 64, false);
170+
PLAYER_DROP_ITEM_EVENT.callEvent(playerDropItemEvent);
171+
updateSlotItemIfCancelled(playerDropItemEvent);
172+
return playerDropItemEvent.isCancelled();
173+
}
174+
175+
public static boolean onDropCursorItem(EntityPlayer player) {
176+
if (PLAYER_DROP_ITEM_EVENT.isEmpty()) return false;
177+
PlayerDropItemEvent playerDropItemEvent = new PlayerDropItemEvent(
178+
player, player.inventory.getCursorStack(), -999, 1, false);
179+
PLAYER_DROP_ITEM_EVENT.callEvent(playerDropItemEvent);
180+
updateSlotItemIfCancelled(playerDropItemEvent);
181+
return playerDropItemEvent.isCancelled();
182+
}
183+
184+
public static boolean onDropCursorItemStack(EntityPlayer player) {
185+
if (PLAYER_DROP_ITEM_EVENT.isEmpty()) return false;
186+
PlayerDropItemEvent playerDropItemEvent = new PlayerDropItemEvent(
187+
player, player.inventory.getCursorStack(), -999, 64, false);
188+
PLAYER_DROP_ITEM_EVENT.callEvent(playerDropItemEvent);
189+
updateSlotItemIfCancelled(playerDropItemEvent);
190+
return playerDropItemEvent.isCancelled();
191+
}
192+
193+
public static boolean onDropCreativeItemStack(EntityPlayer player, ItemStack itemStack) {
194+
if (PLAYER_DROP_ITEM_EVENT.isEmpty()) return false;
195+
PlayerDropItemEvent playerDropItemEvent = new PlayerDropItemEvent(
196+
player, itemStack, -999, 64, true);
197+
PLAYER_DROP_ITEM_EVENT.callEvent(playerDropItemEvent);
198+
return playerDropItemEvent.isCancelled();
199+
}
200+
201+
private static void updateSlotItemIfCancelled(PlayerDropItemEvent playerDropItemEvent) {
202+
int slotId = playerDropItemEvent.getSlotId();
203+
EntityPlayer entityPlayer = playerDropItemEvent.getEntityPlayer();
204+
if (playerDropItemEvent.isCancelled() && entityPlayer instanceof EntityPlayerMP) {
205+
((EntityPlayerMP) entityPlayer).playerNetServerHandler.sendPacket(slotId == -999 ?
206+
new Packet103SetSlot(-1, -1, entityPlayer.inventory.getCursorStack()) :
207+
new Packet103SetSlot(((EntityPlayerMP) entityPlayer).currentWindowId,
208+
slotId, playerDropItemEvent.getItemToDrop()));
209+
}
210+
}
114211
}

loader/src/main/java/com/fox2code/foxloader/loader/ModLoader.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.fox2code.foxloader.energy.FoxPowerUtils;
3131
import com.fox2code.foxloader.event.FoxLoaderEvents;
3232
import com.fox2code.foxloader.event.client.GuiScreenInitEvent;
33+
import com.fox2code.foxloader.event.inventory.PlayerDropItemEvent;
3334
import com.fox2code.foxloader.event.lifecycle.LifecycleStartEvent;
3435
import com.fox2code.foxloader.internal.InternalTranslateHooks;
3536
import com.fox2code.foxloader.launcher.FoxLauncher;
@@ -201,6 +202,15 @@ public void onLifecycle(LifecycleStartEvent lifecycleStartEvent) {
201202
FoxPowerUtils.updateMaxSinkPriorityValue();
202203
}
203204

205+
@EventHandler
206+
public void onItemDrop(PlayerDropItemEvent dropItemEvent) {
207+
this.getLogger().info(dropItemEvent.getItemToDrop().getItemName() +
208+
" -> " + dropItemEvent.getMaxAmountToDrop());
209+
if (!dropItemEvent.getEntityPlayer().worldObj.isRemote) {
210+
dropItemEvent.setCancelled(true);
211+
}
212+
}
213+
204214
public static boolean areAllModsLoaded() {
205215
return areAllModsLoaded;
206216
}

0 commit comments

Comments
 (0)