diff --git a/lophine-server/minecraft-patches/features/0010-Better-ShulkerBox.patch b/lophine-server/minecraft-patches/features/0010-Better-ShulkerBox.patch new file mode 100644 index 0000000..9c648b7 --- /dev/null +++ b/lophine-server/minecraft-patches/features/0010-Better-ShulkerBox.patch @@ -0,0 +1,174 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Helvetica Volubi +Date: Sat, 14 Jun 2025 05:32:51 +0800 +Subject: [PATCH] Better ShulkerBox + +You can open shulker box with shift & right click + +diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java +index 1764875b9024569671bf2be537afb8b492f79102..0ae350d7e4b63abad1666c84df6925c71b73a013 100644 +--- a/net/minecraft/server/level/ServerPlayer.java ++++ b/net/minecraft/server/level/ServerPlayer.java +@@ -2351,6 +2351,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + this.containerMenu.removed(this); + this.inventoryMenu.transferState(this.containerMenu); + this.containerMenu = this.inventoryMenu; ++ this.shulkerOpen = false; + } + + @Override +diff --git a/net/minecraft/world/entity/player/Inventory.java b/net/minecraft/world/entity/player/Inventory.java +index 9fbd605df26d388c01d2ed9ca6a6138651e7f9a7..e8141cb25d6b9a433890e2cded188c2eb5bcf755 100644 +--- a/net/minecraft/world/entity/player/Inventory.java ++++ b/net/minecraft/world/entity/player/Inventory.java +@@ -470,6 +470,16 @@ public class Inventory implements Container, Nameable { + if (equipmentSlot != null) { + this.equipment.set(equipmentSlot, stack); + } ++ ++ // Lophine start - better shulker box ++ if (me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.betterShulker && !this.player.pendingClosingShulker) { ++ boolean isMainHand = index == selected; ++ boolean isOffHand = index == 40; ++ if (isMainHand || isOffHand) { ++ me.earthme.lophine.utils.ShulkerBoxesUtil.inventoryCallBack(isMainHand, this.player); ++ } ++ } ++ // Lophine end - better shulker box + } + + public ListTag save(ListTag listTag) { +diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java +index 27e335e01d8f09f05a4fea5f15407dbe3a4555cb..fbb9fee8223cc27125e4c0c94a7eb8acab5e9a13 100644 +--- a/net/minecraft/world/entity/player/Player.java ++++ b/net/minecraft/world/entity/player/Player.java +@@ -211,6 +211,11 @@ public abstract class Player extends LivingEntity { + public boolean affectsSpawning = true; // Paper - Affects Spawning API + public net.kyori.adventure.util.TriState flyingFallDamage = net.kyori.adventure.util.TriState.NOT_SET; // Paper - flying fall damage + public int enderChestSlotCount = -1; // Purpur - Barrels and enderchests 6 rows ++ // Lophine start - better shulker box ++ public net.minecraft.world.InteractionHand shulkerHand; ++ public boolean pendingClosingShulker = false; ++ public boolean shulkerOpen = false; ++ // Lophine end - better shulker box + + // CraftBukkit start + public boolean fauxSleeping; +@@ -595,11 +600,13 @@ public abstract class Player extends LivingEntity { + // Paper start - special close for unloaded inventory + public void closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { + this.containerMenu = this.inventoryMenu; ++ this.shulkerOpen = false; + } + // Paper end - special close for unloaded inventory + + public void closeContainer() { + this.containerMenu = this.inventoryMenu; ++ this.shulkerOpen = false; + } + + protected void doCloseContainer() { +diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java +index 6c5a01b065c7daa37219a8ab2a471d93e882e756..7b49b35e7a0b9872daceb620cf83b06ae61c3df9 100644 +--- a/net/minecraft/world/inventory/AbstractContainerMenu.java ++++ b/net/minecraft/world/inventory/AbstractContainerMenu.java +@@ -697,7 +697,7 @@ public abstract class AbstractContainerMenu { + } + } + +- private static void dropOrPlaceInInventory(Player player, ItemStack stack) { ++ public static void dropOrPlaceInInventory(Player player, ItemStack stack) { // Lophine - better shulker box + boolean flag = !player.isAlive(); //player.isRemoved() && player.getRemovalReason() != Entity.RemovalReason.CHANGED_DIMENSION; // Luminol - Fix uncorrected death check of folia + boolean flag1 = player instanceof ServerPlayer serverPlayer && serverPlayer.hasDisconnected(); + if (flag || flag1) { +diff --git a/net/minecraft/world/inventory/ShulkerBoxMenu.java b/net/minecraft/world/inventory/ShulkerBoxMenu.java +index 903025c659e6a9423224fe65973696405c69ec6a..545fc46416932db922dc1476b983ac8b9b9f3c7b 100644 +--- a/net/minecraft/world/inventory/ShulkerBoxMenu.java ++++ b/net/minecraft/world/inventory/ShulkerBoxMenu.java +@@ -53,7 +53,7 @@ public class ShulkerBoxMenu extends AbstractContainerMenu { + + @Override + public boolean stillValid(Player player) { +- if (!this.checkReachable) return true; // CraftBukkit ++ if (!this.checkReachable || player.shulkerOpen) return true; // CraftBukkit // Lophine - better shulker box + return this.container.stillValid(player); + } + +diff --git a/net/minecraft/world/item/Item.java b/net/minecraft/world/item/Item.java +index c52fb17d1e496a91223b7387cacb128c1865caee..86d43c4e81dfe9775400e09ae706d4e9cc640bd8 100644 +--- a/net/minecraft/world/item/Item.java ++++ b/net/minecraft/world/item/Item.java +@@ -187,6 +187,13 @@ public class Item implements FeatureElement, ItemLike { + player.startUsingItem(hand); + return InteractionResult.CONSUME; + } else { ++ // Lophine start - better shulker box ++ if (me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.betterShulker ++ && player.isShiftKeyDown() ++ && me.earthme.lophine.utils.ShulkerBoxesUtil.checkIfCanOpen(itemInHand)) { ++ me.earthme.lophine.utils.ShulkerBoxesUtil.openShulkerBox(player, itemInHand, hand); ++ } ++ // Lophine end - better shulker box + return InteractionResult.PASS; + } + } +diff --git a/net/minecraft/world/item/component/ItemContainerContents.java b/net/minecraft/world/item/component/ItemContainerContents.java +index ecf794f94177fc7b6df483516d920719fbc6fa43..4fda59a4c17009a0009f3d3c13258f4ffcb300c3 100644 +--- a/net/minecraft/world/item/component/ItemContainerContents.java ++++ b/net/minecraft/world/item/component/ItemContainerContents.java +@@ -33,7 +33,7 @@ public final class ItemContainerContents implements TooltipProvider { + public final NonNullList items; + private final int hashCode; + +- private ItemContainerContents(NonNullList items) { ++ public ItemContainerContents(NonNullList items) { // Lophine - better shulker box + if (items.size() > 256) { + throw new IllegalArgumentException("Got " + items.size() + " items, but maximum is 256"); + } else { +diff --git a/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java b/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java +index 87ebdb6deb66662a38b3eec0dae27eaf859ecabb..e22114dbfbfd1619260a45929397c11c9356b8a0 100644 +--- a/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java +@@ -46,6 +46,11 @@ public class ShulkerBoxBlockEntity extends RandomizableContainerBlockEntity impl + private ShulkerBoxBlockEntity.AnimationStatus animationStatus = ShulkerBoxBlockEntity.AnimationStatus.CLOSED; + private float progress; + private float progressOld; ++ // Lophine start - better shulker box ++ public boolean haveRealBlock = true; ++ public Player createPlayer; ++ public ItemStack item; ++ // Lophine end - better shulker box + @Nullable + private final DyeColor color; + +@@ -236,6 +241,15 @@ public class ShulkerBoxBlockEntity extends RandomizableContainerBlockEntity impl + return Component.translatable("container.shulkerBox"); + } + ++ // Lophine start - better shulker box ++ public void setItem(int index, ItemStack stack) { ++ super.setItem(index, stack); ++ if (!createPlayer.pendingClosingShulker && !haveRealBlock && me.earthme.lophine.config.modules.misc.ContainerExpansionConfig.betterShulker) { ++ me.earthme.lophine.utils.ShulkerBoxesUtil.shulkerBoxEntityCallBack(this); ++ } ++ } ++ // Lophine end - better shulker box ++ + @Override + protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.loadAdditional(tag, registries); +@@ -258,12 +272,12 @@ public class ShulkerBoxBlockEntity extends RandomizableContainerBlockEntity impl + } + + @Override +- protected NonNullList getItems() { ++ public NonNullList getItems() { // Lophine - better shulker box + return this.itemStacks; + } + + @Override +- protected void setItems(NonNullList items) { ++ public void setItems(NonNullList items) { // Lophine - better shulker box + this.itemStacks = items; + } + diff --git a/lophine-server/minecraft-patches/features/0010-Old-nether-portal-collision.patch b/lophine-server/minecraft-patches/features/0012-Old-nether-portal-collision.patch similarity index 100% rename from lophine-server/minecraft-patches/features/0010-Old-nether-portal-collision.patch rename to lophine-server/minecraft-patches/features/0012-Old-nether-portal-collision.patch diff --git a/lophine-server/minecraft-patches/features/0012-Old-zombie-reinforcement.patch b/lophine-server/minecraft-patches/features/0013-Old-zombie-reinforcement.patch similarity index 100% rename from lophine-server/minecraft-patches/features/0012-Old-zombie-reinforcement.patch rename to lophine-server/minecraft-patches/features/0013-Old-zombie-reinforcement.patch diff --git a/lophine-server/minecraft-patches/features/0013-I18n-support.patch b/lophine-server/minecraft-patches/features/0014-I18n-support.patch similarity index 50% rename from lophine-server/minecraft-patches/features/0013-I18n-support.patch rename to lophine-server/minecraft-patches/features/0014-I18n-support.patch index 2d298da..f2bd3ca 100644 --- a/lophine-server/minecraft-patches/features/0013-I18n-support.patch +++ b/lophine-server/minecraft-patches/features/0014-I18n-support.patch @@ -4,28 +4,6 @@ Date: Thu, 12 Jun 2025 04:44:24 +0800 Subject: [PATCH] I18n support -diff --git a/net/minecraft/locale/Language.java b/net/minecraft/locale/Language.java -index 7b9e2a1a208b46a69c16e6afd8b502259893574f..e2a42996bb01c99fc71a5994e8eeb66ce836af34 100644 ---- a/net/minecraft/locale/Language.java -+++ b/net/minecraft/locale/Language.java -@@ -31,7 +31,7 @@ public abstract class Language { - public static final String DEFAULT = "en_us"; - private static volatile Language instance = loadDefault(); - -- private static Language loadDefault() { -+ public static Language loadDefault() { // Lophine - I18n support - DeprecatedTranslationsInfo deprecatedTranslationsInfo = DeprecatedTranslationsInfo.loadFromDefaultResource(); - Map map = new HashMap<>(); - BiConsumer biConsumer = map::put; -@@ -65,7 +65,7 @@ public abstract class Language { - }; - } - -- private static void parseTranslations(BiConsumer output, String languagePath) { -+ public static void parseTranslations(BiConsumer output, String languagePath) { // Lophine - I18n support - try (InputStream resourceAsStream = Language.class.getResourceAsStream(languagePath)) { - loadFromJson(resourceAsStream, output); - } catch (JsonParseException | IOException var7) { diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java index ba0cdba050cd3bf9231e15dd9543d34f37d9dae5..ce7d70afa524e5b8ea6f9de75d34c8f1eaa6ad72 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java diff --git a/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/misc/ContainerExpansionConfig.java.patch b/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/misc/ContainerExpansionConfig.java.patch index 8eff83a..fa9f531 100644 --- a/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/misc/ContainerExpansionConfig.java.patch +++ b/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/misc/ContainerExpansionConfig.java.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/src/main/java/me/earthme/lophine/config/modules/misc/ContainerExpansionConfig.java -@@ -1,0 +_,32 @@ +@@ -1,0 +_,37 @@ +package me.earthme.lophine.config.modules.misc; + +import me.earthme.luminol.config.EnumConfigCategory; @@ -23,6 +23,11 @@ + range: 1~64""") + public static int shulkerCount = 1; + ++ @ConfigInfo(baseName = "better_shulker_box", comments = ++ """ ++ Enable sneak + use to open shulker box.""") ++ public static boolean betterShulker = false; ++ + @Override + public EnumConfigCategory getCategory() { + return EnumConfigCategory.MISC; diff --git a/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/optimizations/LanguageConfig.java.patch b/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/optimizations/LanguageConfig.java.patch index 87dc8b2..b2604f9 100644 --- a/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/optimizations/LanguageConfig.java.patch +++ b/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/optimizations/LanguageConfig.java.patch @@ -7,8 +7,8 @@ +import me.earthme.luminol.config.IConfigModule; +import me.earthme.luminol.config.flags.ConfigInfo; + -+public class LanguageConfig implements IConfigModule { -+ @ConfigInfo(baseName = "lang" ,comments = """ ++public class LanguageConfig implements IConfigModule { ++ @ConfigInfo(baseName = "lang", comments = """ + Please use the key from https://minecraft.wiki/w/Language + Sample of format: en_us zh_cn zh_hk zh_tw""") + public static String lang = "en_us"; diff --git a/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/removed/RemovedConfig.java.patch b/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/removed/RemovedConfig.java.patch index fd25d0d..1c156ac 100644 --- a/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/removed/RemovedConfig.java.patch +++ b/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/config/modules/removed/RemovedConfig.java.patch @@ -1,12 +1,11 @@ --- /dev/null +++ b/src/main/java/me/earthme/lophine/config/modules/removed/RemovedConfig.java -@@ -1,0 +_,25 @@ +@@ -1,0 +_,24 @@ +package me.earthme.lophine.config.modules.removed; + +import me.earthme.luminol.config.EnumConfigCategory; +import me.earthme.luminol.config.IConfigModule; +import me.earthme.luminol.config.flags.ConfigInfo; -+import me.earthme.luminol.config.flags.DoNotLoad; +import me.earthme.luminol.config.flags.TransformedConfig; + +public class RemovedConfig implements IConfigModule { diff --git a/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/utils/LocalLangUtil.java.patch b/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/utils/LocalLangUtil.java.patch index e4d836c..c596994 100644 --- a/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/utils/LocalLangUtil.java.patch +++ b/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/utils/LocalLangUtil.java.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/src/main/java/me/earthme/lophine/utils/LocalLangUtil.java -@@ -1,0 +_,267 @@ +@@ -1,0 +_,264 @@ +package me.earthme.lophine.utils; + +import com.google.gson.JsonElement; @@ -23,7 +23,10 @@ +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; -+import java.util.*; ++import java.util.HashMap; ++import java.util.Map; ++import java.util.Objects; ++import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; +import java.util.logging.Logger; @@ -33,6 +36,8 @@ + final static String VERSION = "1.21.5"; + final static String basePath = "cache/lophine/" + VERSION + "/"; + static String lang = me.earthme.lophine.config.modules.optimizations.LanguageConfig.lang; ++ static String versionManifestUrl = "https://launchermeta.mojang.com/mc/game/version_manifest.json"; ++ static String resourceUrlHeader = "https://resources.download.minecraft.net/"; + + public static void init() { + init(true); @@ -100,8 +105,7 @@ + } + + private static void downloadLang(String hash) { -+ String url = "https://resources.download.minecraft.net/" -+ + hash.substring(0, 2) + "/" + hash; ++ String url = resourceUrlHeader + hash.substring(0, 2) + "/" + hash; + + for (int i = 0; i < 3; i++) { + try { @@ -114,7 +118,6 @@ + } + + private static JsonObject download() { -+ String versionManifestUrl = "https://launchermeta.mojang.com/mc/game/version_manifest.json"; + String targetVersionUrl = null; + + // Phase 1: Fetch version manifest @@ -178,7 +181,6 @@ + try { + if (Files.exists(cachePath)) { + Files.walk(cachePath) -+ .sorted(Comparator.reverseOrder()) + .forEach(path -> { + try { + Files.deleteIfExists(path); @@ -207,11 +209,7 @@ + } catch (Exception e) { + logger.warning("Failed to load language file for " + lang + "\n" + e); + logger.info("Load default en_us instead of local lang " + lang); -+ if (init) { -+ throw e; -+ } else { -+ Language.inject(Language.loadDefault()); -+ } ++ if (init) throw e; + } + } + @@ -219,7 +217,6 @@ + DeprecatedTranslationsInfo deprecatedTranslationsInfo = DeprecatedTranslationsInfo.loadFromDefaultResource(); + Map map = new HashMap<>(); + BiConsumer biConsumer = map::put; -+ Language.parseTranslations(biConsumer, "/assets/minecraft/lang/en_us.json"); + parseTranslations(biConsumer, lang); + deprecatedTranslationsInfo.applyToMap(map); + final Map map1 = Map.copyOf(map); diff --git a/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/utils/ShulkerBoxesUtil.java.patch b/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/utils/ShulkerBoxesUtil.java.patch index 4c71d17..2c97e01 100644 --- a/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/utils/ShulkerBoxesUtil.java.patch +++ b/lophine-server/paper-patches/files/src/main/java/me/earthme/lophine/utils/ShulkerBoxesUtil.java.patch @@ -1,29 +1,41 @@ --- /dev/null +++ b/src/main/java/me/earthme/lophine/utils/ShulkerBoxesUtil.java -@@ -1,0 +_,76 @@ +@@ -1,0 +_,153 @@ +package me.earthme.lophine.utils; + +import me.earthme.lophine.config.modules.misc.ContainerExpansionConfig; ++import net.minecraft.core.NonNullList; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.CompoundTag; ++import net.minecraft.server.level.ServerPlayer; ++import net.minecraft.stats.Stats; ++import net.minecraft.world.InteractionHand; ++import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ItemContainerContents; +import net.minecraft.world.level.block.ShulkerBoxBlock; ++import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; +import org.jetbrains.annotations.NotNull; + ++import java.util.Objects; +import java.util.Optional; + ++import static net.minecraft.world.inventory.AbstractContainerMenu.dropOrPlaceInInventory; ++ +public class ShulkerBoxesUtil { -+ // Lophine - Stackable ShulkerBoxes ++ // Stackable ShulkerBoxes part + public static boolean shouldCheck() { + return ContainerExpansionConfig.shulkerCount > 1 && ContainerExpansionConfig.shulkerCount <= 64; + } + + public static boolean checkShulkerBox(ItemStack itemStack) { -+ return shouldCheck() && itemStack.getItem() instanceof BlockItem b -+ && b.getBlock() instanceof ShulkerBoxBlock; ++ return shouldCheck() && checkIsShulkerBox(itemStack); ++ } ++ ++ public static boolean checkIsShulkerBox(ItemStack itemStack) { ++ return itemStack.getItem() instanceof BlockItem b && b.getBlock() instanceof ShulkerBoxBlock; + } + + public static int getItemMaxCount(ItemStack itemStack) { @@ -76,4 +88,69 @@ + } + return itemStack; + } ++ ++ // Better ShulkerBox part ++ public static boolean checkIfCanOpen(ItemStack itemStack) { ++ return checkIsShulkerBox(itemStack) && itemStack.getCount() == 1; ++ } ++ ++ public static void openShulkerBox(Player player, ItemStack itemInHand, InteractionHand hand) { ++ ShulkerBoxBlockEntity shulkerBoxEntity = new ShulkerBoxBlockEntity( ++ player.blockPosition(), ++ ((BlockItem) itemInHand.getItem()).getBlock().defaultBlockState() ++ ); ++ ItemContainerContents container = itemInHand.getOrDefault( ++ DataComponents.CONTAINER, ++ ItemContainerContents.EMPTY ++ ); ++ ++ NonNullList items = NonNullList.withSize(27, ItemStack.EMPTY); ++ for (int i = 0; i < container.items.size(); i++) { ++ items.set(i, container.items.get(i)); ++ } ++ ++ shulkerBoxEntity.setItems(items); ++ ++ shulkerBoxEntity.setLevel(player.level()); ++ shulkerBoxEntity.haveRealBlock = false; ++ shulkerBoxEntity.createPlayer = player; ++ player.shulkerHand = hand; ++ player.shulkerOpen = true; ++ ++ if (player.openMenu(shulkerBoxEntity).isPresent()) { ++ player.awardStat(Stats.OPEN_SHULKER_BOX); ++ } ++ } ++ ++ public static void shulkerBoxEntityCallBack(ShulkerBoxBlockEntity shulkerBoxEntity) { ++ Player player = shulkerBoxEntity.createPlayer; ++ if (player.shulkerOpen) { ++ InteractionHand hand = player.shulkerHand; ++ ItemStack currentItem = player.getItemInHand(hand); ++ ++ currentItem.set(DataComponents.CONTAINER, ItemContainerContents.fromItems(shulkerBoxEntity.getItems())); ++ ++ player.setItemInHand(hand, currentItem); ++ } ++ } ++ ++ public static void inventoryCallBack(boolean isMainHand, Player player) { ++ if (player.shulkerOpen) { ++ if (isMainHand == Objects.equals(player.shulkerHand, InteractionHand.MAIN_HAND)) { ++ player.pendingClosingShulker = true; ++ closeScreen(player); ++ player.pendingClosingShulker = false; ++ } ++ } ++ } ++ ++ public static void closeScreen(Player player) { ++ if (player instanceof ServerPlayer) { ++ ItemStack stack = player.containerMenu.getCarried(); ++ if (!stack.isEmpty()) { ++ dropOrPlaceInInventory(player, stack); ++ } ++ } ++ player.closeContainer(); ++ } +}