From b75d996dd25ba80654e06dbe0cd7b3024163d01e Mon Sep 17 00:00:00 2001 From: hammy275 Date: Thu, 10 Oct 2024 12:18:45 -0400 Subject: [PATCH] Improved Item Exchanging and Refactoring in that Area (#346) --- .../api/server/ItemSwapAmount.java | 2 +- .../api_impl/ImmersiveLogicHelpersImpl.java | 31 +------ .../immersive/handler/AnvilHandler.java | 2 +- .../immersive/handler/BeaconHandler.java | 3 +- .../handler/BrewingStandHandler.java | 5 +- .../immersive/handler/CraftingHandler.java | 4 +- .../immersive/handler/ETableHandler.java | 3 +- .../immersive/handler/FurnaceHandler.java | 4 +- .../handler/SmithingTableHandler.java | 8 +- .../handler/TCCraftingStationHandler.java | 4 +- .../storage/dual/impl/ItemStorage.java | 92 +++++++++---------- .../api_impl/ConstantItemSwapAmount.java | 17 ++++ .../immersivemc/server/swap/Swap.java | 84 ++++++++++++----- 13 files changed, 136 insertions(+), 123 deletions(-) create mode 100644 common/src/main/java/com/hammy275/immersivemc/server/api_impl/ConstantItemSwapAmount.java diff --git a/common/src/main/java/com/hammy275/immersivemc/api/server/ItemSwapAmount.java b/common/src/main/java/com/hammy275/immersivemc/api/server/ItemSwapAmount.java index f4259f82e..d9b58d161 100644 --- a/common/src/main/java/com/hammy275/immersivemc/api/server/ItemSwapAmount.java +++ b/common/src/main/java/com/hammy275/immersivemc/api/server/ItemSwapAmount.java @@ -7,7 +7,7 @@ public interface ItemSwapAmount { /** * Get the number of items to swap based on the input item stack size. - * @param stackSize The size of the item stack being swapped. + * @param stackSize The size of the item stack being swapped from the player. * @return The amount of the stack to ideally swap. */ public int getNumItemsToSwap(int stackSize); diff --git a/common/src/main/java/com/hammy275/immersivemc/common/api_impl/ImmersiveLogicHelpersImpl.java b/common/src/main/java/com/hammy275/immersivemc/common/api_impl/ImmersiveLogicHelpersImpl.java index 94000e533..4c936e3aa 100644 --- a/common/src/main/java/com/hammy275/immersivemc/common/api_impl/ImmersiveLogicHelpersImpl.java +++ b/common/src/main/java/com/hammy275/immersivemc/common/api_impl/ImmersiveLogicHelpersImpl.java @@ -3,8 +3,7 @@ import com.hammy275.immersivemc.api.common.ImmersiveLogicHelpers; import com.hammy275.immersivemc.api.server.ItemSwapAmount; import com.hammy275.immersivemc.api.server.SwapResult; -import com.hammy275.immersivemc.common.util.Util; -import com.hammy275.immersivemc.server.api_impl.SwapResultImpl; +import com.hammy275.immersivemc.server.swap.Swap; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.entity.player.Player; @@ -30,32 +29,6 @@ public Direction getHorizontalBlockForward(Player player, BlockPos blockPos) { @Override public SwapResult swapItems(ItemStack stackFromPlayer, ItemStack stackInImmersive, ItemSwapAmount swapAmount) { - int toPlace = swapAmount.getNumItemsToSwap(stackFromPlayer.getCount()); - - // Swap toPlace from stackFromPlayer to otherIn - ItemStack toHand; - ItemStack toOther; - ItemStack leftovers; - if (Util.stacksEqualBesidesCount(stackFromPlayer, stackInImmersive) && !stackFromPlayer.isEmpty() && !stackInImmersive.isEmpty()) { - ItemStack stackFromPlayerCountAdjusted = stackFromPlayer.copy(); - stackFromPlayerCountAdjusted.setCount(toPlace); - Util.ItemStackMergeResult mergeResult = Util.mergeStacks(stackInImmersive.copy(), stackFromPlayerCountAdjusted, false); - toOther = mergeResult.mergedInto; - // Take our original hand, shrink by all of the amount to be moved, then grow by the amount - // that didn't get moved - toHand = stackFromPlayer.copy(); - toHand.shrink(toPlace); - toHand.grow(mergeResult.mergedFrom.getCount()); - leftovers = ItemStack.EMPTY; - } else if (stackFromPlayer.isEmpty()) { // We grab the items from the immersive into our hand - return new SwapResultImpl(stackInImmersive.copy(), ItemStack.EMPTY, ItemStack.EMPTY); - } else { // We're placing into a slot of air OR the other slot contains something that isn't what we have - toOther = stackFromPlayer.copy(); - toOther.setCount(toPlace); - toHand = stackFromPlayer.copy(); - toHand.shrink(toPlace); - leftovers = stackInImmersive.copy(); - } - return new SwapResultImpl(toHand, toOther, leftovers); + return Swap.swapItems(stackFromPlayer, stackInImmersive, swapAmount, null, null); } } diff --git a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/AnvilHandler.java b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/AnvilHandler.java index 16188fb46..6b3724339 100644 --- a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/AnvilHandler.java +++ b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/AnvilHandler.java @@ -35,7 +35,7 @@ public AnvilStorage getEmptyNetworkStorage() { public void swap(int slot, InteractionHand hand, BlockPos pos, ServerPlayer player, ItemSwapAmount amount) { AnvilStorage storage = (AnvilStorage) WorldStoragesImpl.getOrCreateS(pos, player.getLevel()); if (slot != 2) { - storage.placeItem(player, hand, amount.getNumItemsToSwap(player.getItemInHand(hand).getCount()), slot); + storage.placeItem(player, hand, slot, amount); storage.setItem(2, ItemStack.EMPTY); storage.xpLevels = 0; if (!storage.getItem(0).isEmpty() && !storage.getItem(1).isEmpty()) { diff --git a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/BeaconHandler.java b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/BeaconHandler.java index 129f801c4..1e644383b 100644 --- a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/BeaconHandler.java +++ b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/BeaconHandler.java @@ -6,6 +6,7 @@ import com.hammy275.immersivemc.common.immersive.storage.dual.impl.BeaconStorage; import com.hammy275.immersivemc.common.util.Util; import com.hammy275.immersivemc.api.server.WorldStorage; +import com.hammy275.immersivemc.server.api_impl.ConstantItemSwapAmount; import com.hammy275.immersivemc.server.storage.world.WorldStoragesImpl; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; @@ -37,7 +38,7 @@ public void swap(int slot, InteractionHand hand, BlockPos pos, ServerPlayer play Util.placeLeftovers(player, beaconItem); beaconStorage.setItem(0, ItemStack.EMPTY); } - beaconStorage.placeItem(player, hand, 1, 0); + beaconStorage.placeItem(player, hand, 0, new ConstantItemSwapAmount(1)); beaconStorage.setDirty(player.getLevel()); } diff --git a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/BrewingStandHandler.java b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/BrewingStandHandler.java index 2050e1e50..ac80ee00a 100644 --- a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/BrewingStandHandler.java +++ b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/BrewingStandHandler.java @@ -6,8 +6,6 @@ import com.hammy275.immersivemc.api.server.SwapResult; import com.hammy275.immersivemc.common.config.ActiveConfig; import com.hammy275.immersivemc.common.immersive.storage.network.impl.ListOfItemsStorage; -import com.hammy275.immersivemc.common.util.Util; -import com.hammy275.immersivemc.server.swap.Swap; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; @@ -43,9 +41,8 @@ public void swap(int slot, InteractionHand hand, BlockPos pos, ServerPlayer play } else { // Ingredient and Fuel if (!stand.canPlaceItem(slot, playerItem) && playerItem != ItemStack.EMPTY) return; SwapResult result = ImmersiveLogicHelpers.instance().swapItems(playerItem, standItem, amount); - Swap.givePlayerItemSwap(result.playerHandStack(), playerItem, player, hand); + result.giveToPlayer(player, hand); stand.setItem(slot, result.immersiveStack()); - Util.placeLeftovers(player, result.leftoverStack()); } stand.setChanged(); } diff --git a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/CraftingHandler.java b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/CraftingHandler.java index a26dcc624..5d78579c0 100644 --- a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/CraftingHandler.java +++ b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/CraftingHandler.java @@ -32,9 +32,7 @@ public CraftingTableStorage getEmptyNetworkStorage() { public void swap(int slot, InteractionHand hand, BlockPos pos, ServerPlayer player, ItemSwapAmount amount) { CraftingTableStorage storage = (CraftingTableStorage) WorldStoragesImpl.getOrCreateS(pos, player.getLevel()); if (slot < 9) { - storage.placeItem(player, hand, - amount.getNumItemsToSwap(player.getItemInHand(hand).getCount()), - slot); + storage.placeItem(player, hand, slot, amount); storage.setItem(9, Swap.getRecipeOutput(player, storage.getItemsRaw())); } else { Swap.handleDoCraft(player, storage.getItemsRaw(), pos); diff --git a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/ETableHandler.java b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/ETableHandler.java index 0bab7f496..e2c129bde 100644 --- a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/ETableHandler.java +++ b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/ETableHandler.java @@ -7,6 +7,7 @@ import com.hammy275.immersivemc.common.immersive.storage.network.impl.ETableStorage; import com.hammy275.immersivemc.common.vr.VRRumble; import com.hammy275.immersivemc.api.server.WorldStorage; +import com.hammy275.immersivemc.server.api_impl.ConstantItemSwapAmount; import com.hammy275.immersivemc.server.storage.world.WorldStoragesImpl; import com.hammy275.immersivemc.server.storage.world.impl.ETableWorldStorage; import com.hammy275.immersivemc.server.swap.Swap; @@ -61,7 +62,7 @@ public void swap(int slot, InteractionHand hand, BlockPos pos, ServerPlayer play if (slot == 0) { ItemStack toEnchant = player.getItemInHand(hand); if (!toEnchant.isEmpty() && !toEnchant.isEnchantable()) return; - enchStorage.placeItem(player, hand, 1, slot); + enchStorage.placeItem(player, hand, slot, new ConstantItemSwapAmount(1)); } else if (player.getItemInHand(hand).isEmpty()) { boolean res = Swap.doEnchanting(slot, pos, player, hand); if (res) { diff --git a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/FurnaceHandler.java b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/FurnaceHandler.java index 88183d8cf..287d9fe73 100644 --- a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/FurnaceHandler.java +++ b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/FurnaceHandler.java @@ -7,7 +7,6 @@ import com.hammy275.immersivemc.common.config.ActiveConfig; import com.hammy275.immersivemc.common.immersive.storage.network.impl.ListOfItemsStorage; import com.hammy275.immersivemc.common.util.Util; -import com.hammy275.immersivemc.server.swap.Swap; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; @@ -39,9 +38,8 @@ public void swap(int slot, InteractionHand hand, BlockPos pos, ServerPlayer play if (slot != 2) { if (slot != 1 || furnace.canPlaceItem(1, playerItem) || playerItem.isEmpty()) { SwapResult result = ImmersiveLogicHelpers.instance().swapItems(playerItem, furnaceItem, amount); - Swap.givePlayerItemSwap(result.playerHandStack(), playerItem, player, hand); + result.giveToPlayer(player, hand); furnace.setItem(slot, result.immersiveStack()); - Util.placeLeftovers(player, result.leftoverStack()); } } else { boolean itemTaken = false; diff --git a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/SmithingTableHandler.java b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/SmithingTableHandler.java index 6cf308c51..3cedb90d8 100644 --- a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/SmithingTableHandler.java +++ b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/SmithingTableHandler.java @@ -33,10 +33,10 @@ public SmithingTableStorage getEmptyNetworkStorage() { @Override public void swap(int slot, InteractionHand hand, BlockPos pos, ServerPlayer player, ItemSwapAmount amount) { SmithingTableStorage storage = (SmithingTableStorage) WorldStoragesImpl.getOrCreateS(pos, player.getLevel()); - if (slot != 2) { - storage.placeItem(player, hand, amount.getNumItemsToSwap(player.getItemInHand(hand).getCount()), slot); - storage.setItem(2, ItemStack.EMPTY); - if (!storage.getItem(0).isEmpty() && !storage.getItem(1).isEmpty()) { + if (slot != 3) { + storage.placeItem(player, hand, slot, amount); + storage.setItem(3, ItemStack.EMPTY); + if (!storage.getItem(0).isEmpty() && !storage.getItem(1).isEmpty() && !storage.getItem(2).isEmpty()) { ItemStack output = Swap.getSmithingTableOutput(storage.getItem(0), storage.getItem(1), player); storage.setItem(2, output); diff --git a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/TCCraftingStationHandler.java b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/TCCraftingStationHandler.java index de491b092..2199e7ace 100644 --- a/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/TCCraftingStationHandler.java +++ b/common/src/main/java/com/hammy275/immersivemc/common/immersive/handler/TCCraftingStationHandler.java @@ -7,7 +7,6 @@ import com.hammy275.immersivemc.common.compat.TinkersConstruct; import com.hammy275.immersivemc.common.config.ActiveConfig; import com.hammy275.immersivemc.common.immersive.storage.network.impl.ListOfItemsStorage; -import com.hammy275.immersivemc.common.util.Util; import com.hammy275.immersivemc.server.swap.Swap; import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; @@ -55,9 +54,8 @@ public void swap(int slot, InteractionHand hand, BlockPos pos, ServerPlayer play // Just place the item in. Recipe result is calculated in makeInventoryContents() to show the client // and at actual crafting time (else block below). SwapResult result = ImmersiveLogicHelpers.instance().swapItems(playerItem, craftingItem, amount); - Swap.givePlayerItemSwap(result.playerHandStack(), playerItem, player, hand); + result.giveToPlayer(player, hand); table.setItem(slot, result.immersiveStack()); - Util.placeLeftovers(player, result.leftoverStack()); } else { // Get the items into an array, do the craft, then put the items back. ItemStack[] items = new ItemStack[10]; diff --git a/common/src/main/java/com/hammy275/immersivemc/common/immersive/storage/dual/impl/ItemStorage.java b/common/src/main/java/com/hammy275/immersivemc/common/immersive/storage/dual/impl/ItemStorage.java index 8f21a4342..e06258ccf 100644 --- a/common/src/main/java/com/hammy275/immersivemc/common/immersive/storage/dual/impl/ItemStorage.java +++ b/common/src/main/java/com/hammy275/immersivemc/common/immersive/storage/dual/impl/ItemStorage.java @@ -1,20 +1,28 @@ package com.hammy275.immersivemc.common.immersive.storage.dual.impl; -import com.hammy275.immersivemc.common.config.ActiveConfig; import com.hammy275.immersivemc.api.common.immersive.NetworkStorage; -import com.hammy275.immersivemc.common.util.Util; +import com.hammy275.immersivemc.api.server.ItemSwapAmount; +import com.hammy275.immersivemc.api.server.SwapResult; import com.hammy275.immersivemc.api.server.WorldStorage; -import com.hammy275.immersivemc.server.ServerSubscriber; +import com.hammy275.immersivemc.common.config.ActiveConfig; +import com.hammy275.immersivemc.common.util.Util; import com.hammy275.immersivemc.server.ServerUtil; import com.hammy275.immersivemc.server.storage.world.WorldStoragesImpl; +import com.hammy275.immersivemc.server.swap.Swap; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import java.util.*; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.Stack; +import java.util.UUID; /** * Functions both as WorldStorage for saving server side and as a NetworkStorage for sending items @@ -105,56 +113,40 @@ public void shrinkCountsOnly(int slot, int amount) { * @param player Player to get items from * @param hand Hand to get item from * @param slot Slot to merge into + * @param amount Amount of items to swap * */ - public void placeItem(Player player, InteractionHand hand, int amountToPlace, int slot) { + public void placeItem(Player player, InteractionHand hand, int slot, ItemSwapAmount amount) { + ItemStack playerStack = player.getItemInHand(hand); + ItemStack otherStack = this.getItem(slot); + SwapResult result = Swap.swapItems(playerStack, otherStack, amount, + incrementAmount -> incrementCountForPlayer(player, incrementAmount, slot), + ignored -> this.itemCounts[slot].clear()); + result.giveToPlayer(player, hand); + this.items[slot] = result.immersiveStack(); // Set without clearing item counts, since those are updated above + if (player instanceof ServerPlayer sp) { + setDirty(sp.getLevel()); + } + } + + /** + * Increments the return item count for the provided player. + * @param player Player to increment for. + * @param amount Amount to increment. + * @param slot Slot to increment in. + */ + public void incrementCountForPlayer(Player player, int amount, int slot) { boolean shouldReturnItems = ActiveConfig.getConfigForPlayer(player).returnItemsWhenLeavingImmersives; - ItemStack toHand; - ItemStack toImmersive; - ItemStack leftovers; - ItemStack handStack = player.getItemInHand(hand); - ItemStack immersiveStack = this.items[slot]; - if (Util.stacksEqualBesidesCount(handStack, this.items[slot]) && !handStack.isEmpty()) { - ItemStack handStackToPlace = handStack.copy(); - handStackToPlace.setCount(amountToPlace); - int oldImmersiveCount = immersiveStack.getCount(); - Util.ItemStackMergeResult mergeResult = Util.mergeStacks(immersiveStack, handStackToPlace, false); - toImmersive = immersiveStack; - toHand = handStack.copy(); - toHand.shrink(amountToPlace); - // Add anything that wasn't transferred due to stack size back - toHand.grow(mergeResult.mergedFrom.getCount()); - leftovers = ItemStack.EMPTY; - // Always place only in last slot. If Player A places, then Player B, then A places again, order is - // A-B-A, rather than all of A then B. - PlayerItemCounts last = this.itemCounts[slot].get(this.itemCounts[slot].size() - 1); - int itemsMoved = immersiveStack.getCount() - oldImmersiveCount; - if (shouldReturnItems && last.uuid.isPresent() && last.uuid.get().equals(player.getUUID())) { - last.count += itemsMoved; - } else if (shouldReturnItems) { - this.itemCounts[slot].add(new PlayerItemCounts(Optional.of(player.getUUID()), itemsMoved)); - } else if (last.uuid.isEmpty()) { - last.count += itemsMoved; - } else { - this.itemCounts[slot].add(new PlayerItemCounts(Optional.empty(), itemsMoved)); - } - } else if (handStack.isEmpty()) { - toHand = immersiveStack; - toImmersive = ItemStack.EMPTY; - leftovers = ItemStack.EMPTY; - this.itemCounts[slot].clear(); - } else { // Slots contain different item types and hand isn't air (place new stack in and old items go somewhere) - toHand = handStack.copy(); - toHand.shrink(amountToPlace); - toImmersive = handStack.copy(); - toImmersive.setCount(amountToPlace); - leftovers = immersiveStack.copy(); - this.itemCounts[slot].add( - new PlayerItemCounts(Optional.ofNullable(shouldReturnItems ? player.getUUID() : null), amountToPlace)); + ItemStorage.PlayerItemCounts last = this.itemCounts[slot].isEmpty() ? null : this.itemCounts[slot].get(this.itemCounts[slot].size() - 1); + if (last != null && shouldReturnItems && last.uuid.isPresent() && last.uuid.get().equals(player.getUUID())) { + last.count += amount; + } else if (shouldReturnItems) { + this.itemCounts[slot].add(new ItemStorage.PlayerItemCounts(Optional.of(player.getUUID()), amount)); + } else if (last != null && last.uuid.isEmpty()) { + last.count += amount; + } else { + this.itemCounts[slot].add(new ItemStorage.PlayerItemCounts(Optional.empty(), amount)); } - this.items[slot] = toImmersive; - player.setItemInHand(hand, toHand); - Util.placeLeftovers(player, leftovers); } public ItemStack getItem(int slot) { diff --git a/common/src/main/java/com/hammy275/immersivemc/server/api_impl/ConstantItemSwapAmount.java b/common/src/main/java/com/hammy275/immersivemc/server/api_impl/ConstantItemSwapAmount.java new file mode 100644 index 000000000..41804ced1 --- /dev/null +++ b/common/src/main/java/com/hammy275/immersivemc/server/api_impl/ConstantItemSwapAmount.java @@ -0,0 +1,17 @@ +package com.hammy275.immersivemc.server.api_impl; + +import com.hammy275.immersivemc.api.server.ItemSwapAmount; + +public class ConstantItemSwapAmount implements ItemSwapAmount { + + private final int amountToSwap; + + public ConstantItemSwapAmount(int amountToSwap) { + this.amountToSwap = amountToSwap; + } + + @Override + public int getNumItemsToSwap(int stackSize) { + return amountToSwap; + } +} diff --git a/common/src/main/java/com/hammy275/immersivemc/server/swap/Swap.java b/common/src/main/java/com/hammy275/immersivemc/server/swap/Swap.java index 81496b9d9..f5a6131a8 100644 --- a/common/src/main/java/com/hammy275/immersivemc/server/swap/Swap.java +++ b/common/src/main/java/com/hammy275/immersivemc/server/swap/Swap.java @@ -6,10 +6,12 @@ import com.hammy275.immersivemc.common.compat.Lootr; import com.hammy275.immersivemc.common.config.PlacementMode; import com.hammy275.immersivemc.common.immersive.storage.dual.impl.AnvilStorage; +import com.hammy275.immersivemc.common.immersive.storage.dual.impl.ItemStorage; import com.hammy275.immersivemc.common.immersive.storage.dual.impl.SmithingTableStorage; import com.hammy275.immersivemc.common.util.NullContainer; import com.hammy275.immersivemc.common.util.Util; import com.hammy275.immersivemc.mixin.AnvilMenuMixin; +import com.hammy275.immersivemc.server.api_impl.SwapResultImpl; import com.hammy275.immersivemc.server.storage.world.ImmersiveMCPlayerStorages; import com.hammy275.immersivemc.server.storage.world.WorldStoragesImpl; import com.hammy275.immersivemc.server.storage.world.impl.ETableWorldStorage; @@ -29,13 +31,71 @@ import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.block.entity.ChestBlockEntity; import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Optional; import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Consumer; public class Swap { + /** + * Swap items. This is the logic for + * {@link ImmersiveLogicHelpers#swapItems(ItemStack, ItemStack, ItemSwapAmount)}, + * but also has callbacks for incrementing or clearing the item counts for the purposes of {@link ItemStorage}. See + * the above-mentioned method for details of this method. + * @param itemCountIncrementer Callback to run when the amount of items in this Immersive is increased + * @param itemCountClearer Callback to run when the amount of items in this Immersive is decreased + */ + public static SwapResult swapItems(ItemStack handStack, ItemStack immersiveStack, ItemSwapAmount swapAmount, + @Nullable Consumer itemCountIncrementer, @Nullable Consumer itemCountClearer) { + ItemStack toHand; + ItemStack toImmersive; + ItemStack leftovers; + int amountToPlace = swapAmount.getNumItemsToSwap(handStack.getCount()); + boolean handAndImmersiveStackMatch = Util.stacksEqualBesidesCount(handStack, immersiveStack); + boolean immersiveStackAtMax = immersiveStack.getCount() == immersiveStack.getMaxStackSize(); + // Both stacks are the same item and the immersive stack can hold some more items + if (handAndImmersiveStackMatch && !handStack.isEmpty() && !immersiveStackAtMax) { + ItemStack handStackToPlace = handStack.copy(); + handStackToPlace.setCount(amountToPlace); + int oldImmersiveCount = immersiveStack.getCount(); + Util.ItemStackMergeResult mergeResult = Util.mergeStacks(immersiveStack, handStackToPlace, false); + toImmersive = immersiveStack; + toHand = handStack.copy(); + toHand.shrink(amountToPlace); + // Add anything that wasn't transferred due to stack size back + toHand.grow(mergeResult.mergedFrom.getCount()); + leftovers = ItemStack.EMPTY; + // Always place only in last slot. If Player A places, then Player B, then A places again, order is + // A-B-A, rather than all of A then B. + int itemsMoved = immersiveStack.getCount() - oldImmersiveCount; + if (itemCountIncrementer != null) { + itemCountIncrementer.accept(itemsMoved); + } + } else if (handStack.isEmpty() || (immersiveStackAtMax && handAndImmersiveStackMatch)) { // Taking item from Immersive + // Prioritize leftovers over toHand, since we likely don't care about the items anymore, and we don't + // want to fill the hotbar with item grabs + toHand = handStack.isEmpty() ? ItemStack.EMPTY : immersiveStack.copy(); + toImmersive = ItemStack.EMPTY; + leftovers = handStack.isEmpty() ? immersiveStack.copy() : handStack.copy(); + if (itemCountClearer != null) { + itemCountClearer.accept(null); + } + } else { // Slots contain different item types and hand isn't air (place new stack in and old items go somewhere) + toHand = handStack.copy(); + toHand.shrink(amountToPlace); + toImmersive = handStack.copy(); + toImmersive.setCount(amountToPlace); + leftovers = immersiveStack.copy(); + if (itemCountIncrementer != null) { + itemCountIncrementer.accept(amountToPlace); + } + } + return new SwapResultImpl(toHand, toImmersive, leftovers); + } + public static boolean doEnchanting(int slot, BlockPos pos, ServerPlayer player, InteractionHand hand) { // NOTE: slot is 1-3, depending on which enchantment the player is going for. if (!player.getItemInHand(hand).isEmpty()) return false; @@ -87,8 +147,7 @@ public static void handleBackpackCraftingSwap(int slot, InteractionHand hand, Li ItemStack tableItem = itemArray[slot]; SwapResult result = ImmersiveLogicHelpers.instance().swapItems(playerItem, tableItem, amount); itemArray[slot] = result.immersiveStack(); - givePlayerItemSwap(result.playerHandStack(), playerItem, player, hand); - Util.placeLeftovers(player, result.leftoverStack()); + result.giveToPlayer(player, hand); itemArray[4] = getRecipeOutput(player, itemArray); } else { handleDoCraft(player, itemArray, null); @@ -300,25 +359,4 @@ public static int getPlaceAmount(int handInSize, PlacementMode mode) { throw new IllegalArgumentException("Unhandled placement mode " + mode); } } - - public static void givePlayerItemSwap(ItemStack toPlayer, ItemStack fromPlayer, Player player, InteractionHand hand) { - if (fromPlayer.isEmpty() && toPlayer.getMaxStackSize() > 1) { - Util.addStackToInventory(player, toPlayer); - } else { - player.setItemInHand(hand, toPlayer); - } - } - - - public static class SwapResultOld { - public final ItemStack toHand; - public final ItemStack toOther; - public final ItemStack leftovers; - public SwapResultOld(ItemStack toHand, ItemStack toOther, ItemStack leftovers) { - this.toHand = toHand; - this.toOther = toOther; - this.leftovers = leftovers; - } - } - }