From 3264dc795351494b35c413c83b0e84db763d7232 Mon Sep 17 00:00:00 2001 From: Traister101 <66151907+Traister101@users.noreply.github.com> Date: Fri, 11 Oct 2024 18:35:08 -0700 Subject: [PATCH] Lets hope I tested this thoroughly enough this time (#4) * Revert "Fix major dupe bug caused by trying to be polite and setting the `ItemEntitys` `ItemStack` instead of messing with it's size in place" This reverts commit 6c74927ce7824d0ac8064129f43e4d8e90dba6b2. * Actually fix the dupe bug * 1.1.1 --- CHANGELOG.md | 8 +- .../sns/util/handlers/PickupHandler.java | 173 ++++++++---------- 2 files changed, 73 insertions(+), 108 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e5e592..d7c8436 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,3 @@ ### Bug fixes -- Fix duplication bug when picking up items which entirely refill all partial slots with at least one left over - -### Changes - -- Added new tag 'allowed_in_ore_sack' for items which can go into ore sacks (wow crazy) -- Not ugly Icon courtesy of Aleki -- Start of patchouli entires \ No newline at end of file +- Fix new duplication bug caused by poorly fixing the previous. First reported by: Sigmenzzz \ No newline at end of file diff --git a/src/main/java/mod/traister101/sns/util/handlers/PickupHandler.java b/src/main/java/mod/traister101/sns/util/handlers/PickupHandler.java index 5a08422..94c96b2 100644 --- a/src/main/java/mod/traister101/sns/util/handlers/PickupHandler.java +++ b/src/main/java/mod/traister101/sns/util/handlers/PickupHandler.java @@ -1,18 +1,16 @@ package mod.traister101.sns.util.handlers; -import mod.traister101.sns.common.items.ContainerItem; import mod.traister101.sns.config.SNSConfig; import mod.traister101.sns.util.ContainerType; import net.dries007.tfc.common.blocks.GroundcoverBlock; import net.dries007.tfc.common.blocks.rock.LooseRockBlock; import net.dries007.tfc.common.blocks.wood.FallenLeavesBlock; import top.theillusivec4.curios.api.CuriosApi; -import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; import net.minecraft.core.BlockPos; -import net.minecraft.network.protocol.game.ClientboundTakeItemEntityPacket; -import net.minecraft.server.level.*; +import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.*; +import net.minecraft.stats.Stats; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.*; @@ -25,10 +23,10 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities; import net.minecraftforge.event.entity.player.EntityItemPickupEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock; +import net.minecraftforge.eventbus.api.Event.Result; import net.minecraftforge.fml.ModList; import net.minecraftforge.items.*; - -import java.util.Optional; +import net.minecraftforge.items.wrapper.PlayerMainInvWrapper; public final class PickupHandler { @@ -40,22 +38,30 @@ public static void onPickupItem(final EntityItemPickupEvent event) { final Player player = event.getEntity(); final ItemEntity itemEntity = event.getItem(); - final ItemStack itemResult; - final int pickupCount; - { - final ItemStack stack = itemEntity.getItem(); - final int startCount = stack.getCount(); - itemResult = pickupItemStack(player, stack); - pickupCount = startCount - itemResult.getCount(); - if (itemResult.isEmpty()) event.setCanceled(true); - } + + final ItemStack entityStack = itemEntity.getItem(); + final int startCount = entityStack.getCount(); + final ItemStack itemResult = pickupItemStack(player, entityStack); + final int pickupCount = startCount - itemResult.getCount(); // Picked up more than 0 if (0 < pickupCount) { player.containerMenu.broadcastChanges(); - final var packet = new ClientboundTakeItemEntityPacket(itemEntity.getId(), player.getId(), pickupCount); - ((ServerPlayer) player).connection.send(packet); + player.take(itemEntity, pickupCount); + + // Update the item entity + if (itemResult.isEmpty()) { + itemEntity.discard(); + } else { + itemEntity.setItem(itemResult); + } + + player.awardStat(Stats.ITEM_PICKED_UP.get(entityStack.getItem()), pickupCount); + player.onItemPickup(itemEntity); } + + event.setCanceled(itemResult.isEmpty()); + event.setResult(Result.ALLOW); } /** @@ -108,99 +114,74 @@ public static void onBlockActivated(final RightClickBlock event) { } /** - * Tries to first fill any valid stacks in the player inventory then tries to fill any {@link ContainerItem}s. If both fail to consume the entire - * stack - * the remainer is returned + * Our item pickup handling * * @param player Player to handle * @param itemPickup The item being picked up * - * @return Empty {@link ItemStack} or the remainer. + * @return The remainer */ private static ItemStack pickupItemStack(final Player player, final ItemStack itemPickup) { ItemStack remainder = itemPickup; - final Inventory playerInventory = player.getInventory(); - if (topOffPlayerInventory(playerInventory, remainder)) return ItemStack.EMPTY; - - if (ModList.get().isLoaded(CuriosApi.MODID)) { - final Optional optionalCuriosItemHandler = CuriosApi.getCuriosInventory(player).resolve(); - - if (optionalCuriosItemHandler.isPresent()) { - final ICuriosItemHandler curiosItemHandler = optionalCuriosItemHandler.get(); - final IItemHandlerModifiable equippedCurios = curiosItemHandler.getEquippedCurios(); - - for (int slotIndex = 0; slotIndex < equippedCurios.getSlots(); slotIndex++) { - final ItemStack itemContainer = equippedCurios.getStackInSlot(slotIndex); - - if (!ContainerType.canDoItemPickup(itemContainer)) continue; + final Inventory inventory = player.getInventory(); + remainder = topOffPlayerInventory(inventory, remainder); - final Optional containerInv = itemContainer.getCapability(ForgeCapabilities.ITEM_HANDLER) - .resolve() - .filter(h -> isValidForContainer(h, itemPickup)); + if (remainder.isEmpty()) return ItemStack.EMPTY; - if (containerInv.isEmpty()) continue; - - remainder = insertStack(itemPickup, containerInv.get()); - - if (remainder.isEmpty()) continue; - if (SNSConfig.SERVER.doVoiding.get() && !ContainerType.canDoItemVoiding(itemContainer)) continue; + if (ModList.get().isLoaded(CuriosApi.MODID)) { + final var maybeCuriosItemHandler = CuriosApi.getCuriosInventory(player).resolve(); - if (!voidedItem(remainder, containerInv.get())) continue; + if (maybeCuriosItemHandler.isPresent()) { + final var curiosItemHandler = maybeCuriosItemHandler.get(); + final var equippedCurios = curiosItemHandler.getEquippedCurios(); - return ItemStack.EMPTY; - } + remainder = insertItemPickup(equippedCurios, remainder, equippedCurios.getSlots()); + if (remainder.isEmpty()) return ItemStack.EMPTY; } } - for (int slotIndex = 0; slotIndex < playerInventory.getContainerSize(); slotIndex++) { - final ItemStack itemContainer = playerInventory.getItem(slotIndex); - - if (!ContainerType.canDoItemPickup(itemContainer)) continue; - - final Optional containerInv = itemContainer.getCapability(ForgeCapabilities.ITEM_HANDLER) - .resolve() - .filter(h -> isValidForContainer(h, itemPickup)); - - if (containerInv.isEmpty()) continue; - - remainder = insertStack(itemPickup, containerInv.get()); - - if (remainder.isEmpty()) continue; - if (SNSConfig.SERVER.doVoiding.get() && !ContainerType.canDoItemVoiding(itemContainer)) continue; - - if (!voidedItem(remainder, containerInv.get())) continue; + remainder = insertItemPickup(new PlayerMainInvWrapper(inventory), remainder, Inventory.INVENTORY_SIZE); - return ItemStack.EMPTY; - } return remainder; } /** - * Tries to fill the provided handler until it runs out of capacity or the fillStack runs out. + * Inserts the picked up item into the provided {@link IItemHandler} * - * @param fillStack The stack to put into the {@link IItemHandler}. May be mutated + * @param itemHandler The {@link IItemHandler} to insert into + * @param itemPickup The {@link ItemStack} to pickup + * @param slotCount The slot count * - * @return The remaining items that didn't fit + * @return The remaining items */ - private static ItemStack insertStack(final ItemStack fillStack, final IItemHandler itemHandler) { - ItemStack pickupResult = fillStack; - for (int slotIndex = 0; slotIndex < itemHandler.getSlots(); slotIndex++) { - if (itemHandler.getStackInSlot(slotIndex).getCount() >= itemHandler.getSlotLimit(slotIndex)) continue; + private static ItemStack insertItemPickup(final IItemHandler itemHandler, final ItemStack itemPickup, final int slotCount) { + ItemStack remainder = itemPickup; + for (int slotIndex = 0; slotIndex < slotCount; slotIndex++) { + final ItemStack itemContainer = itemHandler.getStackInSlot(slotIndex); - pickupResult = itemHandler.insertItem(slotIndex, fillStack, false); + if (!ContainerType.canDoItemPickup(itemContainer)) continue; + + final var maybeContainerInv = itemContainer.getCapability(ForgeCapabilities.ITEM_HANDLER).resolve(); + + if (maybeContainerInv.isEmpty()) continue; + + remainder = ItemHandlerHelper.insertItem(maybeContainerInv.get(), remainder, false); + + if (remainder.isEmpty()) return ItemStack.EMPTY; + if (SNSConfig.SERVER.doVoiding.get() && !ContainerType.canDoItemVoiding(itemContainer)) continue; - if (pickupResult.isEmpty()) return ItemStack.EMPTY; + if (!voidedItem(remainder, maybeContainerInv.get())) return ItemStack.EMPTY; - fillStack.shrink(fillStack.getCount() - pickupResult.getCount()); + return ItemStack.EMPTY; } - return pickupResult; + return remainder; } /** - * @param itemStack The Item Stack to try and void. Will be modified if successful + * @param itemStack The Item Stack to try and void * - * @return If the item was voided. + * @return If the item was voided */ @SuppressWarnings("BooleanMethodIsAlwaysInverted") private static boolean voidedItem(final ItemStack itemStack, final IItemHandler itemHandler) { @@ -208,33 +189,24 @@ private static boolean voidedItem(final ItemStack itemStack, final IItemHandler for (int slotIndex = 0; slotIndex < itemHandler.getSlots(); slotIndex++) { final ItemStack slotStack = itemHandler.getStackInSlot(slotIndex); if (!ItemStack.isSameItem(slotStack, itemStack)) continue; - - itemStack.setCount(0); return true; } return false; } - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - private static boolean isValidForContainer(final IItemHandler containerInv, final ItemStack itemPickup) { - for (int slotIndex = 0; slotIndex < containerInv.getSlots(); slotIndex++) { - if (containerInv.isItemValid(slotIndex, itemPickup)) return true; - } - return false; - } - /** * Tops off the player inventory consuming the itemstack until all stacks in the inventory are filled * - * @param inventoryPlayer Player inventory we should top up - * @param itemStack The itemstack we consume to fill the inventory + * @param inventoryPlayer Player inventory handler + * @param insertStack The {@link ItemStack} we insert into the inventory * * @return If the item stack was fully consumed */ - private static boolean topOffPlayerInventory(final Inventory inventoryPlayer, final ItemStack itemStack) { + private static ItemStack topOffPlayerInventory(final Inventory inventoryPlayer, final ItemStack insertStack) { + ItemStack remainder = insertStack; // Add to player inventory first, if there is an incomplete stack in there. - for (int i = 0; i < inventoryPlayer.getContainerSize(); i++) { - final ItemStack inventoryStack = inventoryPlayer.getItem(i); + for (int slotIndex = 0; slotIndex < inventoryPlayer.getContainerSize(); slotIndex++) { + final ItemStack inventoryStack = inventoryPlayer.getItem(slotIndex); // We only add to existing stacks. if (inventoryStack.isEmpty()) continue; @@ -243,22 +215,21 @@ private static boolean topOffPlayerInventory(final Inventory inventoryPlayer, fi if (inventoryStack.getCount() >= inventoryStack.getMaxStackSize()) continue; // Can merge stacks - if (ItemStack.isSameItemSameTags(inventoryStack, itemStack)) { + if (ItemStack.isSameItemSameTags(inventoryStack, remainder)) { final int remainingSpace = inventoryStack.getMaxStackSize() - inventoryStack.getCount(); - if (remainingSpace >= itemStack.getCount()) { + if (remainingSpace >= remainder.getCount()) { // Enough space to add all - inventoryStack.grow(itemStack.getCount()); - itemStack.setCount(0); - return true; + inventoryStack.grow(remainder.getCount()); + return ItemStack.EMPTY; } else { // Only part can be added inventoryStack.setCount(inventoryStack.getMaxStackSize()); - itemStack.shrink(remainingSpace); + remainder = ItemHandlerHelper.copyStackWithSize(remainder, remainder.getCount() - remainingSpace); } } } - return false; + return remainder; } /**