From e0fae5ef02dc02f0f096da1046f9f64aaf001a6c Mon Sep 17 00:00:00 2001 From: Bjarne Koll <git@lynxplay.dev> Date: Fri, 13 Dec 2024 19:02:07 +0100 Subject: [PATCH] Part of block entities --- .../block/entity/BarrelBlockEntity.java.patch | 29 +- .../BaseContainerBlockEntity.java.patch | 28 +- .../block/entity/BellBlockEntity.java.patch | 45 ++- .../block/entity/ChestBlockEntity.java.patch | 39 +++ .../ChiseledBookShelfBlockEntity.java.patch | 49 +-- .../entity/CommandBlockEntity.java.patch | 25 ++ .../block/entity/HopperBlockEntity.java.patch | 303 ++++++++++++++++ .../SculkCatalystBlockEntity.java.patch | 21 ++ .../TheEndGatewayBlockEntity.java.patch | 11 + .../block/entity/ChestBlockEntity.java.patch | 51 --- .../entity/CommandBlockEntity.java.patch | 26 -- .../block/entity/HopperBlockEntity.java.patch | 322 ------------------ .../SculkCatalystBlockEntity.java.patch | 29 -- .../TheEndGatewayBlockEntity.java.patch | 19 -- 14 files changed, 461 insertions(+), 536 deletions(-) rename paper-server/patches/{unapplied => sources}/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch (52%) rename paper-server/patches/{unapplied => sources}/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java.patch (75%) rename paper-server/patches/{unapplied => sources}/net/minecraft/world/level/block/entity/BellBlockEntity.java.patch (50%) create mode 100644 paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch rename paper-server/patches/{unapplied => sources}/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java.patch (55%) create mode 100644 paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch similarity index 52% rename from paper-server/patches/unapplied/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch rename to paper-server/patches/sources/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch index bc89832782..11854ff324 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BarrelBlockEntity.java.patch @@ -1,45 +1,36 @@ --- a/net/minecraft/world/level/block/entity/BarrelBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -@@ -20,9 +20,49 @@ - import net.minecraft.world.level.Level; - import net.minecraft.world.level.block.BarrelBlock; +@@ -21,6 +_,40 @@ import net.minecraft.world.level.block.state.BlockState; -+// CraftBukkit start -+import java.util.ArrayList; -+import java.util.List; -+import org.bukkit.craftbukkit.entity.CraftHumanEntity; -+import org.bukkit.entity.HumanEntity; -+// CraftBukkit end public class BarrelBlockEntity extends RandomizableContainerBlockEntity { - + // CraftBukkit start - add fields and methods -+ public List<HumanEntity> transaction = new ArrayList<>(); ++ public java.util.List<org.bukkit.entity.HumanEntity> transaction = new java.util.ArrayList<>(); + private int maxStack = MAX_STACK; + + @Override -+ public List<ItemStack> getContents() { ++ public java.util.List<ItemStack> getContents() { + return this.items; + } + + @Override -+ public void onOpen(CraftHumanEntity who) { ++ public void onOpen(org.bukkit.craftbukkit.entity.CraftHumanEntity who) { + this.transaction.add(who); + } + + @Override -+ public void onClose(CraftHumanEntity who) { ++ public void onClose(org.bukkit.craftbukkit.entity.CraftHumanEntity who) { + this.transaction.remove(who); + } + + @Override -+ public List<HumanEntity> getViewers() { ++ public java.util.List<org.bukkit.entity.HumanEntity> getViewers() { + return this.transaction; + } + + @Override + public int getMaxStackSize() { -+ return this.maxStack; ++ return this.maxStack; + } + + @Override @@ -47,6 +38,6 @@ + this.maxStack = i; + } + // CraftBukkit end - private NonNullList<ItemStack> items; - public final ContainerOpenersCounter openersCounter; - + private NonNullList<ItemStack> items = NonNullList.withSize(27, ItemStack.EMPTY); + private final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() { + @Override diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java.patch similarity index 75% rename from paper-server/patches/unapplied/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java.patch rename to paper-server/patches/sources/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java.patch index 07ed6af225..09da60cff3 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java.patch @@ -1,28 +1,28 @@ --- a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java -@@ -73,17 +73,44 @@ +@@ -68,17 +_,44 @@ protected abstract Component getDefaultName(); public boolean canOpen(Player player) { -- return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName()); -+ return BaseContainerBlockEntity.canUnlock(player, this.lockKey, this.getDisplayName(), this); // Paper - Add BlockLockCheckEvent +- return canUnlock(player, this.lockKey, this.getDisplayName()); ++ return canUnlock(player, this.lockKey, this.getDisplayName(), this); // Paper - Add BlockLockCheckEvent } + @Deprecated @io.papermc.paper.annotation.DoNotUse // Paper - Add BlockLockCheckEvent - public static boolean canUnlock(Player player, LockCode lock, Component containerName) { + public static boolean canUnlock(Player player, LockCode code, Component displayName) { + // Paper start - Add BlockLockCheckEvent -+ return canUnlock(player, lock, containerName, null); ++ return canUnlock(player, code, displayName, null); + } -+ public static boolean canUnlock(Player player, LockCode lock, Component containerName, @Nullable BlockEntity blockEntity) { ++ public static boolean canUnlock(Player player, LockCode code, Component displayName, @Nullable BlockEntity blockEntity) { + if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer && blockEntity != null && blockEntity.getLevel() != null && blockEntity.getLevel().getBlockEntity(blockEntity.getBlockPos()) == blockEntity) { + final org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(blockEntity.getLevel(), blockEntity.getBlockPos()); -+ net.kyori.adventure.text.Component lockedMessage = net.kyori.adventure.text.Component.translatable("container.isLocked", io.papermc.paper.adventure.PaperAdventure.asAdventure(containerName)); ++ net.kyori.adventure.text.Component lockedMessage = net.kyori.adventure.text.Component.translatable("container.isLocked", io.papermc.paper.adventure.PaperAdventure.asAdventure(displayName)); + net.kyori.adventure.sound.Sound lockedSound = net.kyori.adventure.sound.Sound.sound(org.bukkit.Sound.BLOCK_CHEST_LOCKED, net.kyori.adventure.sound.Sound.Source.BLOCK, 1.0F, 1.0F); + final io.papermc.paper.event.block.BlockLockCheckEvent event = new io.papermc.paper.event.block.BlockLockCheckEvent(block, serverPlayer.getBukkitEntity(), lockedMessage, lockedSound); + event.callEvent(); + if (event.getResult() == org.bukkit.event.Event.Result.ALLOW) { + return true; -+ } else if (event.getResult() == org.bukkit.event.Event.Result.DENY || (!player.isSpectator() && !lock.unlocksWith(event.isUsingCustomKeyItemStack() ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getKeyItem()) : player.getMainHandItem()))) { ++ } else if (event.getResult() == org.bukkit.event.Event.Result.DENY || (!player.isSpectator() && !code.unlocksWith(event.isUsingCustomKeyItemStack() ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getKeyItem()) : player.getMainHandItem()))) { + if (event.getLockedMessage() != null) { + event.getPlayer().sendActionBar(event.getLockedMessage()); + } @@ -35,9 +35,9 @@ + } + } else { // logic below is replaced by logic above + // Paper end - Add BlockLockCheckEvent - if (!player.isSpectator() && !lock.unlocksWith(player.getMainHandItem())) { -- player.displayClientMessage(Component.translatable("container.isLocked", containerName), true); -+ player.displayClientMessage(Component.translatable("container.isLocked", containerName), true); // Paper - diff on change + if (!player.isSpectator() && !code.unlocksWith(player.getMainHandItem())) { +- player.displayClientMessage(Component.translatable("container.isLocked", displayName), true); ++ player.displayClientMessage(Component.translatable("container.isLocked", displayName), true); // Paper - diff on change player.playNotifySound(SoundEvents.CHEST_LOCKED, SoundSource.BLOCKS, 1.0F, 1.0F); return false; } else { @@ -47,9 +47,9 @@ } protected abstract NonNullList<ItemStack> getItems(); -@@ -178,4 +205,12 @@ - nbt.remove("lock"); - nbt.remove("Items"); +@@ -166,4 +_,12 @@ + tag.remove("lock"); + tag.remove("Items"); } + + // CraftBukkit start diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/BellBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BellBlockEntity.java.patch similarity index 50% rename from paper-server/patches/unapplied/net/minecraft/world/level/block/entity/BellBlockEntity.java.patch rename to paper-server/patches/sources/net/minecraft/world/level/block/entity/BellBlockEntity.java.patch index c8f5ced60a..1cc3771a2f 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/BellBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/BellBlockEntity.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/block/entity/BellBlockEntity.java +++ b/net/minecraft/world/level/block/entity/BellBlockEntity.java -@@ -63,6 +63,11 @@ +@@ -60,6 +_,11 @@ if (blockEntity.ticks >= 50) { blockEntity.shaking = false; @@ -12,53 +12,48 @@ blockEntity.ticks = 0; } -@@ -76,6 +81,7 @@ - ++blockEntity.resonationTicks; +@@ -73,6 +_,7 @@ + blockEntity.resonationTicks++; } else { - bellEffect.run(world, pos, blockEntity.nearbyEntities); + resonationEndAction.run(level, pos, blockEntity.nearbyEntities); + blockEntity.nearbyEntities.clear(); // Paper - Fix bell block entity memory leak blockEntity.resonating = false; } } -@@ -120,11 +126,12 @@ - LivingEntity entityliving = (LivingEntity) iterator.next(); - - if (entityliving.isAlive() && !entityliving.isRemoved() && blockposition.closerToCenterThan(entityliving.position(), 32.0D)) { -- entityliving.getBrain().setMemory(MemoryModuleType.HEARD_BELL_TIME, (Object) this.level.getGameTime()); -+ entityliving.getBrain().setMemory(MemoryModuleType.HEARD_BELL_TIME, this.level.getGameTime()); // CraftBukkit - decompile error +@@ -113,6 +_,8 @@ } } } - ++ + this.nearbyEntities.removeIf(e -> !e.isAlive()); // Paper - Fix bell block entity memory leak } - private static boolean areRaidersNearby(BlockPos pos, List<LivingEntity> hearingEntities) { -@@ -144,9 +151,13 @@ + private static boolean areRaidersNearby(BlockPos pos, List<LivingEntity> raiders) { +@@ -129,7 +_,10 @@ } - private static void makeRaidersGlow(Level world, BlockPos pos, List<LivingEntity> hearingEntities) { -+ List<org.bukkit.entity.LivingEntity> entities = // CraftBukkit - hearingEntities.stream().filter((entityliving) -> { - return BellBlockEntity.isRaiderWithinRange(pos, entityliving); -- }).forEach(BellBlockEntity::glow); -+ }).map((entity) -> (org.bukkit.entity.LivingEntity) entity.getBukkitEntity()).collect(java.util.stream.Collectors.toCollection(java.util.ArrayList::new)); // CraftBukkit -+ -+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBellResonateEvent(world, pos, entities).forEach(entity -> glow(entity, pos)); // Paper - Add BellRevealRaiderEvent -+ // CraftBukkit end + private static void makeRaidersGlow(Level level, BlockPos pos, List<LivingEntity> raiders) { +- raiders.stream().filter(raider -> isRaiderWithinRange(pos, raider)).forEach(BellBlockEntity::glow); ++ // Paper start - call bell resonate event and bell reveal raider event ++ final List<org.bukkit.entity.LivingEntity> inRangeRaiders = raiders.stream().filter(raider -> isRaiderWithinRange(pos, raider)).map(e -> e.getBukkitEntity()).toList(); ++ org.bukkit.craftbukkit.event.CraftEventFactory.handleBellResonateEvent(level, pos, inRangeRaiders).forEach(e -> glow(e, pos)); ++ // Paper end - call bell resonate event and bell reveal raider event } - private static void showBellParticles(Level world, BlockPos pos, List<LivingEntity> hearingEntities) { -@@ -178,6 +189,13 @@ + private static void showBellParticles(Level level, BlockPos pos, List<LivingEntity> raiders) { +@@ -159,7 +_,16 @@ + return raider.isAlive() && !raider.isRemoved() && pos.closerToCenterThan(raider.position(), 48.0) && raider.getType().is(EntityTypeTags.RAIDERS); } ++ @io.papermc.paper.annotation.DoNotUse // Paper - Add BellRevealRaiderEvent private static void glow(LivingEntity entity) { + // Paper start - Add BellRevealRaiderEvent + glow(entity, null); + } + + private static void glow(LivingEntity entity, @javax.annotation.Nullable BlockPos pos) { -+ if (pos != null && !new io.papermc.paper.event.block.BellRevealRaiderEvent(org.bukkit.craftbukkit.block.CraftBlock.at(entity.level(), pos), (org.bukkit.entity.Raider) entity.getBukkitEntity()).callEvent()) return; ++ if (pos != null && !new io.papermc.paper.event.block.BellRevealRaiderEvent(org.bukkit.craftbukkit.block.CraftBlock.at(entity.level(), pos), (org.bukkit.entity.Raider) entity.getBukkitEntity()).callEvent()) ++ return; + // Paper end - Add BellRevealRaiderEvent entity.addEffect(new MobEffectInstance(MobEffects.GLOWING, 60)); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch new file mode 100644 index 0000000000..d3845d7cfa --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch @@ -0,0 +1,39 @@ +--- a/net/minecraft/world/level/block/entity/ChestBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/ChestBlockEntity.java +@@ -56,6 +_,36 @@ + }; + private final ChestLidController chestLidController = new ChestLidController(); + ++ // CraftBukkit start - add fields and methods ++ public java.util.List<org.bukkit.entity.HumanEntity> transaction = new java.util.ArrayList<>(); ++ private int maxStack = MAX_STACK; ++ ++ public java.util.List<net.minecraft.world.item.ItemStack> getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(org.bukkit.craftbukkit.entity.CraftHumanEntity who) { ++ this.transaction.add(who); ++ } ++ ++ public void onClose(org.bukkit.craftbukkit.entity.CraftHumanEntity who) { ++ this.transaction.remove(who); ++ } ++ ++ public java.util.List<org.bukkit.entity.HumanEntity> getViewers() { ++ return this.transaction; ++ } ++ ++ @Override ++ public int getMaxStackSize() { ++ return this.maxStack; ++ } ++ ++ public void setMaxStackSize(int size) { ++ this.maxStack = size; ++ } ++ // CraftBukkit end ++ + protected ChestBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState blockState) { + super(type, pos, blockState); + } diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java.patch similarity index 55% rename from paper-server/patches/unapplied/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java.patch rename to paper-server/patches/sources/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java.patch index af35923253..bb3e767def 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java.patch @@ -1,43 +1,30 @@ --- a/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java +++ b/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java -@@ -23,13 +23,55 @@ - import net.minecraft.world.level.gameevent.GameEvent; - import org.slf4j.Logger; +@@ -27,6 +_,42 @@ + private final NonNullList<ItemStack> items = NonNullList.withSize(6, ItemStack.EMPTY); + private int lastInteractedSlot = -1; -+// CraftBukkit start -+import java.util.List; -+import org.bukkit.Location; -+import org.bukkit.craftbukkit.entity.CraftHumanEntity; -+import org.bukkit.entity.HumanEntity; -+// CraftBukkit end -+ - public class ChiseledBookShelfBlockEntity extends BlockEntity implements Container { - - public static final int MAX_BOOKS_IN_STORAGE = 6; - private static final Logger LOGGER = LogUtils.getLogger(); - private final NonNullList<ItemStack> items; - public int lastInteractedSlot; + // CraftBukkit start - add fields and methods -+ public List<HumanEntity> transaction = new java.util.ArrayList<>(); ++ public java.util.List<org.bukkit.entity.HumanEntity> transaction = new java.util.ArrayList<>(); + private int maxStack = 1; - ++ + @Override -+ public List<ItemStack> getContents() { ++ public java.util.List<net.minecraft.world.item.ItemStack> getContents() { + return this.items; + } + + @Override -+ public void onOpen(CraftHumanEntity who) { ++ public void onOpen(org.bukkit.craftbukkit.entity.CraftHumanEntity who) { + this.transaction.add(who); + } + + @Override -+ public void onClose(CraftHumanEntity who) { ++ public void onClose(org.bukkit.craftbukkit.entity.CraftHumanEntity who) { + this.transaction.remove(who); + } + + @Override -+ public List<HumanEntity> getViewers() { ++ public List<org.bukkit.entity.HumanEntity> getViewers() { + return this.transaction; + } + @@ -47,25 +34,25 @@ + } + + @Override -+ public Location getLocation() { ++ public org.bukkit.Location getLocation() { + if (this.level == null) return null; -+ return new org.bukkit.Location(this.level.getWorld(), this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ()); ++ return io.papermc.paper.util.MCUtil.toLocation(this.level, this.worldPosition); + } + // CraftBukkit end + public ChiseledBookShelfBlockEntity(BlockPos pos, BlockState state) { super(BlockEntityType.CHISELED_BOOKSHELF, pos, state); - this.items = NonNullList.withSize(6, ItemStack.EMPTY); -@@ -100,7 +142,7 @@ - + } +@@ -93,7 +_,7 @@ + ItemStack itemStack = Objects.requireNonNullElse(this.items.get(slot), ItemStack.EMPTY); this.items.set(slot, ItemStack.EMPTY); - if (!itemstack.isEmpty()) { + if (!itemStack.isEmpty()) { - this.updateState(slot); + if (this.level != null) this.updateState(slot); // CraftBukkit - SPIGOT-7381: check for null world } - return itemstack; -@@ -115,7 +157,7 @@ + return itemStack; +@@ -108,7 +_,7 @@ public void setItem(int slot, ItemStack stack) { if (stack.is(ItemTags.BOOKSHELF_BOOKS)) { this.items.set(slot, stack); @@ -74,7 +61,7 @@ } else if (stack.isEmpty()) { this.removeItem(slot, 1); } -@@ -131,7 +173,7 @@ +@@ -124,7 +_,7 @@ @Override public int getMaxStackSize() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch new file mode 100644 index 0000000000..dca791d38d --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch @@ -0,0 +1,25 @@ +--- a/net/minecraft/world/level/block/entity/CommandBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/CommandBlockEntity.java +@@ -21,6 +_,13 @@ + private boolean auto; + private boolean conditionMet; + private final BaseCommandBlock commandBlock = new BaseCommandBlock() { ++ // CraftBukkit start ++ @Override ++ public org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper) { ++ return new org.bukkit.craftbukkit.command.CraftBlockCommandSender(wrapper, CommandBlockEntity.this); ++ } ++ // CraftBukkit end ++ + @Override + public void setCommand(String command) { + super.setCommand(command); +@@ -51,7 +_,7 @@ + Vec3.atCenterOf(CommandBlockEntity.this.worldPosition), + new Vec2(0.0F, direction.toYRot()), + this.getLevel(), +- 2, ++ this.getLevel().paperConfig().commandBlocks.permissionsLevel, // Paper - configurable command block perm level + this.getName().getString(), + this.getName(), + this.getLevel().getServer(), diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch new file mode 100644 index 0000000000..9f296844d6 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch @@ -0,0 +1,303 @@ +--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java +@@ -37,6 +_,37 @@ + private long tickedGameTime; + private Direction facing; + ++ // CraftBukkit start - add fields and methods ++ public List<org.bukkit.entity.HumanEntity> transaction = new java.util.ArrayList<>(); ++ private int maxStack = MAX_STACK; ++ ++ public List<ItemStack> getContents() { ++ return this.items; ++ } ++ ++ public void onOpen(org.bukkit.craftbukkit.entity.CraftHumanEntity who) { ++ this.transaction.add(who); ++ } ++ ++ public void onClose(org.bukkit.craftbukkit.entity.CraftHumanEntity who) { ++ this.transaction.remove(who); ++ } ++ ++ public List<org.bukkit.entity.HumanEntity> getViewers() { ++ return this.transaction; ++ } ++ ++ @Override ++ public int getMaxStackSize() { ++ return this.maxStack; ++ } ++ ++ public void setMaxStackSize(int size) { ++ this.maxStack = size; ++ } ++ // CraftBukkit end ++ ++ + public HopperBlockEntity(BlockPos pos, BlockState blockState) { + super(BlockEntityType.HOPPER, pos, blockState); + this.facing = blockState.getValue(HopperBlock.FACING); +@@ -97,7 +_,14 @@ + blockEntity.tickedGameTime = level.getGameTime(); + if (!blockEntity.isOnCooldown()) { + blockEntity.setCooldown(0); +- tryMoveItems(level, pos, state, blockEntity, () -> suckInItems(level, blockEntity)); ++ // Spigot start ++ boolean result = tryMoveItems(level, pos, state, blockEntity, () -> { ++ return suckInItems(level, blockEntity); ++ }); ++ if (!result && blockEntity.level.spigotConfig.hopperCheck > 1) { ++ blockEntity.setCooldown(blockEntity.level.spigotConfig.hopperCheck); ++ } ++ // Spigot end + } + } + +@@ -116,7 +_,7 @@ + } + + if (flag) { +- blockEntity.setCooldown(8); ++ blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot + setChanged(level, pos, state); + return true; + } +@@ -149,14 +_,47 @@ + ItemStack item = blockEntity.getItem(i); + if (!item.isEmpty()) { + int count = item.getCount(); +- ItemStack itemStack = addItem(blockEntity, attachedContainer, blockEntity.removeItem(i, 1), opposite); ++ // CraftBukkit start - Call event when pushing items into other inventories ++ ItemStack original = item.copy(); ++ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror( ++ blockEntity.removeItem(i, level.spigotConfig.hopperAmount) ++ ); // Spigot ++ ++ org.bukkit.inventory.Inventory destinationInventory; ++ // Have to special case large chests as they work oddly ++ if (attachedContainer instanceof final CompoundContainer compoundContainer) { ++ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer); ++ } else if (attachedContainer.getOwner() != null) { ++ destinationInventory = attachedContainer.getOwner().getInventory(); ++ } else { ++ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(attachedContainer); ++ } ++ ++ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent( ++ blockEntity.getOwner().getInventory(), ++ oitemstack, ++ destinationInventory, ++ true ++ ); ++ if (!event.callEvent()) { ++ blockEntity.setItem(i, original); ++ blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot ++ return false; ++ } ++ int origCount = event.getItem().getAmount(); // Spigot ++ ItemStack itemStack = HopperBlockEntity.addItem(blockEntity, attachedContainer, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), opposite); ++ // CraftBukkit end ++ + if (itemStack.isEmpty()) { + attachedContainer.setChanged(); + return true; + } + + item.setCount(count); +- if (count == 1) { ++ // Spigot start ++ item.shrink(origCount - itemStack.getCount()); ++ if (count <= level.spigotConfig.hopperAmount) { ++ // Spigot end + blockEntity.setItem(i, item); + } + } +@@ -219,7 +_,7 @@ + Direction direction = Direction.DOWN; + + for (int i : getSlots(sourceContainer, direction)) { +- if (tryTakeInItemFromSlot(hopper, sourceContainer, i, direction)) { ++ if (tryTakeInItemFromSlot(hopper, sourceContainer, i, direction, level)) { // Spigot + return true; + } + } +@@ -239,18 +_,54 @@ + } + } + +- private static boolean tryTakeInItemFromSlot(Hopper hopper, Container container, int slot, Direction direction) { ++ private static boolean tryTakeInItemFromSlot(Hopper hopper, Container container, int slot, Direction direction, Level level) { // Spigot + ItemStack item = container.getItem(slot); + if (!item.isEmpty() && canTakeItemFromContainer(hopper, container, item, slot, direction)) { + int count = item.getCount(); +- ItemStack itemStack = addItem(container, hopper, container.removeItem(slot, 1), null); ++ // CraftBukkit start - Call event on collection of items from inventories into the hopper ++ ItemStack original = item.copy(); ++ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror( ++ container.removeItem(slot, level.spigotConfig.hopperAmount) // Spigot ++ ); ++ ++ org.bukkit.inventory.Inventory sourceInventory; ++ // Have to special case large chests as they work oddly ++ if (container instanceof final CompoundContainer compoundContainer) { ++ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer); ++ } else if (container.getOwner() != null) { ++ sourceInventory = container.getOwner().getInventory(); ++ } else { ++ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container); ++ } ++ ++ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent( ++ sourceInventory, ++ oitemstack, ++ hopper.getOwner().getInventory(), ++ false ++ ); ++ ++ if (!event.callEvent()) { ++ container.setItem(slot, original); ++ ++ if (hopper instanceof final HopperBlockEntity hopperBlockEntity) { ++ hopperBlockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot ++ } ++ ++ return false; ++ } ++ int origCount = event.getItem().getAmount(); // Spigot ++ ItemStack itemStack = HopperBlockEntity.addItem(container, hopper, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), null); ++ // CraftBukkit end ++ + if (itemStack.isEmpty()) { + container.setChanged(); + return true; + } + + item.setCount(count); +- if (count == 1) { ++ item.shrink(origCount - itemStack.getCount()); ++ if (count <= level.spigotConfig.hopperAmount) { + container.setItem(slot, item); + } + } +@@ -260,12 +_,21 @@ + + public static boolean addItem(Container container, ItemEntity item) { + boolean flag = false; ++ // CraftBukkit start ++ org.bukkit.event.inventory.InventoryPickupItemEvent event = new org.bukkit.event.inventory.InventoryPickupItemEvent( ++ container.getOwner().getInventory(), (org.bukkit.entity.Item) item.getBukkitEntity() ++ ); ++ item.level().getCraftServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return false; ++ } ++ // CraftBukkit end + ItemStack itemStack = item.getItem().copy(); + ItemStack itemStack1 = addItem(null, container, itemStack, null); + if (itemStack1.isEmpty()) { + flag = true; + item.setItem(ItemStack.EMPTY); +- item.discard(); ++ item.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause + } else { + item.setItem(itemStack1); + } +@@ -307,11 +_,18 @@ + boolean flag = false; + boolean isEmpty = destination.isEmpty(); + if (item.isEmpty()) { ++ // Spigot start - SPIGOT-6693, InventorySubcontainer#setItem ++ ItemStack leftover = ItemStack.EMPTY; // Paper - Make hoppers respect inventory max stack size ++ if (!stack.isEmpty() && stack.getCount() > destination.getMaxStackSize()) { ++ leftover = stack; // Paper - Make hoppers respect inventory max stack size ++ stack = stack.split(destination.getMaxStackSize()); ++ } ++ // Spigot end + destination.setItem(slot, stack); +- stack = ItemStack.EMPTY; ++ stack = leftover; // Paper - Make hoppers respect inventory max stack size + flag = true; + } else if (canMergeItems(item, stack)) { +- int i = stack.getMaxStackSize() - item.getCount(); ++ int i = Math.min(stack.getMaxStackSize(), destination.getMaxStackSize()) - item.getCount(); // Paper - Make hoppers respect inventory max stack size + int min = Math.min(stack.getCount(), i); + stack.shrink(min); + item.grow(min); +@@ -325,7 +_,7 @@ + min = 1; + } + +- hopperBlockEntity.setCooldown(8 - min); ++ hopperBlockEntity.setCooldown(hopperBlockEntity.level.spigotConfig.hopperTransfer - min); // Spigot + } + + destination.setChanged(); +@@ -335,14 +_,57 @@ + return stack; + } + ++ // CraftBukkit start ++ @Nullable ++ private static Container runHopperInventorySearchEvent( ++ Container container, ++ org.bukkit.craftbukkit.block.CraftBlock hopper, ++ org.bukkit.craftbukkit.block.CraftBlock searchLocation, ++ org.bukkit.event.inventory.HopperInventorySearchEvent.ContainerType containerType ++ ) { ++ org.bukkit.event.inventory.HopperInventorySearchEvent event = new org.bukkit.event.inventory.HopperInventorySearchEvent( ++ (container != null) ? new org.bukkit.craftbukkit.inventory.CraftInventory(container) : null, ++ containerType, ++ hopper, ++ searchLocation ++ ); ++ event.callEvent(); ++ return (event.getInventory() != null) ? ((org.bukkit.craftbukkit.inventory.CraftInventory) event.getInventory()).getInventory() : null; ++ } ++ // CraftBukkit end ++ + @Nullable + private static Container getAttachedContainer(Level level, BlockPos pos, HopperBlockEntity blockEntity) { +- return getContainerAt(level, pos.relative(blockEntity.facing)); ++ // CraftBukkit start ++ BlockPos searchPosition = pos.relative(blockEntity.facing); ++ Container inventory = getContainerAt(level, searchPosition); ++ ++ org.bukkit.craftbukkit.block.CraftBlock hopper = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); ++ org.bukkit.craftbukkit.block.CraftBlock searchBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, searchPosition); ++ return HopperBlockEntity.runHopperInventorySearchEvent( ++ inventory, ++ hopper, ++ searchBlock, ++ org.bukkit.event.inventory.HopperInventorySearchEvent.ContainerType.DESTINATION ++ ); ++ // CraftBukkit end + } + + @Nullable + private static Container getSourceContainer(Level level, Hopper hopper, BlockPos pos, BlockState state) { +- return getContainerAt(level, pos, state, hopper.getLevelX(), hopper.getLevelY() + 1.0, hopper.getLevelZ()); ++ // CraftBukkit start ++ final Container inventory = HopperBlockEntity.getContainerAt(level, pos, state, hopper.getLevelX(), hopper.getLevelY() + 1.0D, hopper.getLevelZ()); ++ ++ final BlockPos blockPosition = BlockPos.containing(hopper.getLevelX(), hopper.getLevelY(), hopper.getLevelZ()); ++ org.bukkit.craftbukkit.block.CraftBlock hopperBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPosition); ++ org.bukkit.craftbukkit.block.CraftBlock containerBlock = org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPosition.above()); ++ return HopperBlockEntity.runHopperInventorySearchEvent( ++ inventory, ++ hopperBlock, ++ containerBlock, ++ org.bukkit.event.inventory.HopperInventorySearchEvent.ContainerType.SOURCE ++ ); ++ // CraftBukkit end + } + + public static List<ItemEntity> getItemsAtAndAbove(Level level, Hopper hopper) { +@@ -367,6 +_,7 @@ + + @Nullable + private static Container getBlockContainer(Level level, BlockPos pos, BlockState state) { ++ if (!level.spigotConfig.hopperCanLoadChunks && !level.hasChunkAt(pos)) return null; // Spigot + Block block = state.getBlock(); + if (block instanceof WorldlyContainerHolder) { + return ((WorldlyContainerHolder)block).getContainer(state, level, pos); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch new file mode 100644 index 0000000000..657dcc0967 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java +@@ -34,8 +_,18 @@ + this.catalystListener = new SculkCatalystBlockEntity.CatalystListener(blockState, new BlockPositionSource(pos)); + } + ++ // Paper start - Fix NPE in SculkBloomEvent world access ++ @Override ++ public void setLevel(Level level) { ++ super.setLevel(level); ++ this.catalystListener.sculkSpreader.level = level; ++ } ++ // Paper end - Fix NPE in SculkBloomEvent world access ++ + public static void serverTick(Level level, BlockPos pos, BlockState state, SculkCatalystBlockEntity sculkCatalyst) { ++ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = sculkCatalyst.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. + sculkCatalyst.catalystListener.getSculkSpreader().updateCursors(level, pos, level.getRandom(), true); ++ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = null; // CraftBukkit + } + + @Override diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch new file mode 100644 index 0000000000..09f5bd3726 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java +@@ -131,7 +_,7 @@ + + @Nullable + public Vec3 getPortalPosition(ServerLevel level, BlockPos pos) { +- if (this.exitPortal == null && level.dimension() == Level.END) { ++ if (this.exitPortal == null && level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.END) { // CraftBukkit - work in alternate worlds + BlockPos blockPos = findOrCreateValidTeleportPos(level, pos); + blockPos = blockPos.above(10); + LOGGER.debug("Creating portal at {}", blockPos); diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch b/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch deleted file mode 100644 index 537f1913b2..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch +++ /dev/null @@ -1,51 +0,0 @@ ---- a/net/minecraft/world/level/block/entity/ChestBlockEntity.java -+++ b/net/minecraft/world/level/block/entity/ChestBlockEntity.java -@@ -23,6 +23,11 @@ - import net.minecraft.world.level.block.ChestBlock; - import net.minecraft.world.level.block.state.BlockState; - import net.minecraft.world.level.block.state.properties.ChestType; -+// CraftBukkit start -+import java.util.List; -+import org.bukkit.craftbukkit.entity.CraftHumanEntity; -+import org.bukkit.entity.HumanEntity; -+// CraftBukkit end - - public class ChestBlockEntity extends RandomizableContainerBlockEntity implements LidBlockEntity { - -@@ -31,6 +36,36 @@ - public final ContainerOpenersCounter openersCounter; - private final ChestLidController chestLidController; - -+ // CraftBukkit start - add fields and methods -+ public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>(); -+ private int maxStack = MAX_STACK; -+ -+ public List<ItemStack> getContents() { -+ return this.items; -+ } -+ -+ public void onOpen(CraftHumanEntity who) { -+ this.transaction.add(who); -+ } -+ -+ public void onClose(CraftHumanEntity who) { -+ this.transaction.remove(who); -+ } -+ -+ public List<HumanEntity> getViewers() { -+ return this.transaction; -+ } -+ -+ @Override -+ public int getMaxStackSize() { -+ return this.maxStack; -+ } -+ -+ public void setMaxStackSize(int size) { -+ this.maxStack = size; -+ } -+ // CraftBukkit end -+ - protected ChestBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) { - super(type, pos, state); - this.items = NonNullList.withSize(27, ItemStack.EMPTY); diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch b/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch deleted file mode 100644 index 49a6bff68c..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/CommandBlockEntity.java.patch +++ /dev/null @@ -1,26 +0,0 @@ ---- a/net/minecraft/world/level/block/entity/CommandBlockEntity.java -+++ b/net/minecraft/world/level/block/entity/CommandBlockEntity.java -@@ -24,7 +24,14 @@ - private boolean auto; - private boolean conditionMet; - private final BaseCommandBlock commandBlock = new BaseCommandBlock() { -+ // CraftBukkit start - @Override -+ public org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper) { -+ return new org.bukkit.craftbukkit.command.CraftBlockCommandSender(wrapper, CommandBlockEntity.this); -+ } -+ // CraftBukkit end -+ -+ @Override - public void setCommand(String command) { - super.setCommand(command); - CommandBlockEntity.this.setChanged(); -@@ -51,7 +58,7 @@ - public CommandSourceStack createCommandSourceStack() { - Direction enumdirection = (Direction) CommandBlockEntity.this.getBlockState().getValue(CommandBlock.FACING); - -- return new CommandSourceStack(this, Vec3.atCenterOf(CommandBlockEntity.this.worldPosition), new Vec2(0.0F, enumdirection.toYRot()), this.getLevel(), 2, this.getName().getString(), this.getName(), this.getLevel().getServer(), (Entity) null); -+ return new CommandSourceStack(this, Vec3.atCenterOf(CommandBlockEntity.this.worldPosition), new Vec2(0.0F, enumdirection.toYRot()), this.getLevel(), this.getLevel().paperConfig().commandBlocks.permissionsLevel, this.getName().getString(), this.getName(), this.getLevel().getServer(), (Entity) null); // Paper - configurable command block perm level - } - - @Override diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch b/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch deleted file mode 100644 index 58e1ea39e6..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/HopperBlockEntity.java.patch +++ /dev/null @@ -1,322 +0,0 @@ ---- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java -+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java -@@ -11,6 +11,7 @@ - import net.minecraft.nbt.CompoundTag; - import net.minecraft.network.chat.Component; - import net.minecraft.tags.BlockTags; -+import net.minecraft.world.CompoundContainer; - import net.minecraft.world.Container; - import net.minecraft.world.ContainerHelper; - import net.minecraft.world.WorldlyContainer; -@@ -18,7 +19,6 @@ - import net.minecraft.world.entity.Entity; - import net.minecraft.world.entity.EntitySelector; - import net.minecraft.world.entity.item.ItemEntity; --import net.minecraft.world.entity.player.Inventory; - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.inventory.AbstractContainerMenu; - import net.minecraft.world.inventory.HopperMenu; -@@ -29,6 +29,18 @@ - import net.minecraft.world.level.block.HopperBlock; - import net.minecraft.world.level.block.state.BlockState; - import net.minecraft.world.phys.AABB; -+import org.bukkit.Bukkit; -+import org.bukkit.craftbukkit.block.CraftBlock; -+import org.bukkit.craftbukkit.entity.CraftHumanEntity; -+import org.bukkit.craftbukkit.inventory.CraftInventory; -+import org.bukkit.craftbukkit.inventory.CraftItemStack; -+import org.bukkit.entity.HumanEntity; -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.inventory.HopperInventorySearchEvent; -+import org.bukkit.event.inventory.InventoryMoveItemEvent; -+import org.bukkit.event.inventory.InventoryPickupItemEvent; -+import org.bukkit.inventory.Inventory; -+// CraftBukkit end - - public class HopperBlockEntity extends RandomizableContainerBlockEntity implements Hopper { - -@@ -40,6 +52,36 @@ - private long tickedGameTime; - private Direction facing; - -+ // CraftBukkit start - add fields and methods -+ public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>(); -+ private int maxStack = MAX_STACK; -+ -+ public List<ItemStack> getContents() { -+ return this.items; -+ } -+ -+ public void onOpen(CraftHumanEntity who) { -+ this.transaction.add(who); -+ } -+ -+ public void onClose(CraftHumanEntity who) { -+ this.transaction.remove(who); -+ } -+ -+ public List<HumanEntity> getViewers() { -+ return this.transaction; -+ } -+ -+ @Override -+ public int getMaxStackSize() { -+ return this.maxStack; -+ } -+ -+ public void setMaxStackSize(int size) { -+ this.maxStack = size; -+ } -+ // CraftBukkit end -+ - public HopperBlockEntity(BlockPos pos, BlockState state) { - super(BlockEntityType.HOPPER, pos, state); - this.items = NonNullList.withSize(5, ItemStack.EMPTY); -@@ -102,9 +144,14 @@ - blockEntity.tickedGameTime = world.getGameTime(); - if (!blockEntity.isOnCooldown()) { - blockEntity.setCooldown(0); -- HopperBlockEntity.tryMoveItems(world, pos, state, blockEntity, () -> { -+ // Spigot start -+ boolean result = HopperBlockEntity.tryMoveItems(world, pos, state, blockEntity, () -> { - return HopperBlockEntity.suckInItems(world, blockEntity); - }); -+ if (!result && blockEntity.level.spigotConfig.hopperCheck > 1) { -+ blockEntity.setCooldown(blockEntity.level.spigotConfig.hopperCheck); -+ } -+ // Spigot end - } - - } -@@ -125,7 +172,7 @@ - } - - if (flag) { -- blockEntity.setCooldown(8); -+ blockEntity.setCooldown(world.spigotConfig.hopperTransfer); // Spigot - setChanged(world, pos, state); - return true; - } -@@ -167,15 +214,41 @@ - - if (!itemstack.isEmpty()) { - int j = itemstack.getCount(); -- ItemStack itemstack1 = HopperBlockEntity.addItem(blockEntity, iinventory, blockEntity.removeItem(i, 1), enumdirection); -+ // CraftBukkit start - Call event when pushing items into other inventories -+ ItemStack original = itemstack.copy(); -+ CraftItemStack oitemstack = CraftItemStack.asCraftMirror(blockEntity.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot - -+ Inventory destinationInventory; -+ // Have to special case large chests as they work oddly -+ if (iinventory instanceof CompoundContainer) { -+ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory); -+ } else if (iinventory.getOwner() != null) { -+ destinationInventory = iinventory.getOwner().getInventory(); -+ } else { -+ destinationInventory = new CraftInventory(iinventory); -+ } -+ -+ InventoryMoveItemEvent event = new InventoryMoveItemEvent(blockEntity.getOwner().getInventory(), oitemstack, destinationInventory, true); -+ world.getCraftServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) { -+ blockEntity.setItem(i, original); -+ blockEntity.setCooldown(world.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot -+ return false; -+ } -+ int origCount = event.getItem().getAmount(); // Spigot -+ ItemStack itemstack1 = HopperBlockEntity.addItem(blockEntity, iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection); -+ // CraftBukkit end -+ - if (itemstack1.isEmpty()) { - iinventory.setChanged(); - return true; - } - - itemstack.setCount(j); -- if (j == 1) { -+ // Spigot start -+ itemstack.shrink(origCount - itemstack1.getCount()); -+ if (j <= world.spigotConfig.hopperAmount) { -+ // Spigot end - blockEntity.setItem(i, itemstack); - } - } -@@ -249,7 +322,7 @@ - for (int j = 0; j < i; ++j) { - int k = aint[j]; - -- if (HopperBlockEntity.tryTakeInItemFromSlot(hopper, iinventory, k, enumdirection)) { -+ if (HopperBlockEntity.tryTakeInItemFromSlot(hopper, iinventory, k, enumdirection, world)) { // Spigot - return true; - } - } -@@ -274,21 +347,52 @@ - } - } - -- private static boolean tryTakeInItemFromSlot(Hopper hopper, Container inventory, int slot, Direction side) { -- ItemStack itemstack = inventory.getItem(slot); -+ private static boolean tryTakeInItemFromSlot(Hopper ihopper, Container iinventory, int i, Direction enumdirection, Level world) { // Spigot -+ ItemStack itemstack = iinventory.getItem(i); - -- if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(hopper, inventory, itemstack, slot, side)) { -+ if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) { - int j = itemstack.getCount(); -- ItemStack itemstack1 = HopperBlockEntity.addItem(inventory, hopper, inventory.removeItem(slot, 1), (Direction) null); -+ // CraftBukkit start - Call event on collection of items from inventories into the hopper -+ ItemStack original = itemstack.copy(); -+ CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot - -+ Inventory sourceInventory; -+ // Have to special case large chests as they work oddly -+ if (iinventory instanceof CompoundContainer) { -+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory); -+ } else if (iinventory.getOwner() != null) { -+ sourceInventory = iinventory.getOwner().getInventory(); -+ } else { -+ sourceInventory = new CraftInventory(iinventory); -+ } -+ -+ InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack, ihopper.getOwner().getInventory(), false); -+ -+ Bukkit.getServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) { -+ iinventory.setItem(i, original); -+ -+ if (ihopper instanceof HopperBlockEntity) { -+ ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot -+ } -+ -+ return false; -+ } -+ int origCount = event.getItem().getAmount(); // Spigot -+ ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null); -+ // CraftBukkit end -+ - if (itemstack1.isEmpty()) { -- inventory.setChanged(); -+ iinventory.setChanged(); - return true; - } - - itemstack.setCount(j); -- if (j == 1) { -- inventory.setItem(slot, itemstack); -+ // Spigot start -+ itemstack.shrink(origCount - itemstack1.getCount()); -+ if (j <= world.spigotConfig.hopperAmount) { -+ // Spigot end -+ iinventory.setItem(i, itemstack); - } - } - -@@ -297,13 +401,20 @@ - - public static boolean addItem(Container inventory, ItemEntity itemEntity) { - boolean flag = false; -+ // CraftBukkit start -+ InventoryPickupItemEvent event = new InventoryPickupItemEvent(inventory.getOwner().getInventory(), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); -+ itemEntity.level().getCraftServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) { -+ return false; -+ } -+ // CraftBukkit end - ItemStack itemstack = itemEntity.getItem().copy(); - ItemStack itemstack1 = HopperBlockEntity.addItem((Container) null, inventory, itemstack, (Direction) null); - - if (itemstack1.isEmpty()) { - flag = true; - itemEntity.setItem(ItemStack.EMPTY); -- itemEntity.discard(); -+ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause - } else { - itemEntity.setItem(itemstack1); - } -@@ -383,11 +494,18 @@ - boolean flag1 = to.isEmpty(); - - if (itemstack1.isEmpty()) { -+ // Spigot start - SPIGOT-6693, InventorySubcontainer#setItem -+ ItemStack leftover = ItemStack.EMPTY; // Paper - Make hoppers respect inventory max stack size -+ if (!stack.isEmpty() && stack.getCount() > to.getMaxStackSize()) { -+ leftover = stack; // Paper - Make hoppers respect inventory max stack size -+ stack = stack.split(to.getMaxStackSize()); -+ } -+ // Spigot end - to.setItem(slot, stack); -- stack = ItemStack.EMPTY; -+ stack = leftover; // Paper - Make hoppers respect inventory max stack size - flag = true; - } else if (HopperBlockEntity.canMergeItems(itemstack1, stack)) { -- int j = stack.getMaxStackSize() - itemstack1.getCount(); -+ int j = Math.min(stack.getMaxStackSize(), to.getMaxStackSize()) - itemstack1.getCount(); // Paper - Make hoppers respect inventory max stack size - int k = Math.min(stack.getCount(), j); - - stack.shrink(k); -@@ -410,7 +528,7 @@ - } - } - -- tileentityhopper.setCooldown(8 - b0); -+ tileentityhopper.setCooldown(tileentityhopper.level.spigotConfig.hopperTransfer - b0); // Spigot - } - } - -@@ -421,14 +539,38 @@ - return stack; - } - -+ // CraftBukkit start - @Nullable -+ private static Container runHopperInventorySearchEvent(Container inventory, CraftBlock hopper, CraftBlock searchLocation, HopperInventorySearchEvent.ContainerType containerType) { -+ HopperInventorySearchEvent event = new HopperInventorySearchEvent((inventory != null) ? new CraftInventory(inventory) : null, containerType, hopper, searchLocation); -+ Bukkit.getServer().getPluginManager().callEvent(event); -+ CraftInventory craftInventory = (CraftInventory) event.getInventory(); -+ return (craftInventory != null) ? craftInventory.getInventory() : null; -+ } -+ // CraftBukkit end -+ -+ @Nullable - private static Container getAttachedContainer(Level world, BlockPos pos, HopperBlockEntity blockEntity) { -- return HopperBlockEntity.getContainerAt(world, pos.relative(blockEntity.facing)); -+ // CraftBukkit start -+ BlockPos searchPosition = pos.relative(blockEntity.facing); -+ Container inventory = HopperBlockEntity.getContainerAt(world, searchPosition); -+ -+ CraftBlock hopper = CraftBlock.at(world, pos); -+ CraftBlock searchBlock = CraftBlock.at(world, searchPosition); -+ return HopperBlockEntity.runHopperInventorySearchEvent(inventory, hopper, searchBlock, HopperInventorySearchEvent.ContainerType.DESTINATION); -+ // CraftBukkit end - } - - @Nullable - private static Container getSourceContainer(Level world, Hopper hopper, BlockPos pos, BlockState state) { -- return HopperBlockEntity.getContainerAt(world, pos, state, hopper.getLevelX(), hopper.getLevelY() + 1.0D, hopper.getLevelZ()); -+ // CraftBukkit start -+ Container inventory = HopperBlockEntity.getContainerAt(world, pos, state, hopper.getLevelX(), hopper.getLevelY() + 1.0D, hopper.getLevelZ()); -+ -+ BlockPos blockPosition = BlockPos.containing(hopper.getLevelX(), hopper.getLevelY(), hopper.getLevelZ()); -+ CraftBlock hopper1 = CraftBlock.at(world, blockPosition); -+ CraftBlock container = CraftBlock.at(world, blockPosition.above()); -+ return HopperBlockEntity.runHopperInventorySearchEvent(inventory, hopper1, container, HopperInventorySearchEvent.ContainerType.SOURCE); -+ // CraftBukkit end - } - - public static List<ItemEntity> getItemsAtAndAbove(Level world, Hopper hopper) { -@@ -455,6 +597,7 @@ - - @Nullable - private static Container getBlockContainer(Level world, BlockPos pos, BlockState state) { -+ if ( !world.spigotConfig.hopperCanLoadChunks && !world.hasChunkAt( pos ) ) return null; // Spigot - Block block = state.getBlock(); - - if (block instanceof WorldlyContainerHolder) { -@@ -543,7 +686,7 @@ - } - - @Override -- protected AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) { -+ protected AbstractContainerMenu createMenu(int syncId, net.minecraft.world.entity.player.Inventory playerInventory) { - return new HopperMenu(syncId, playerInventory, this); - } - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch b/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch deleted file mode 100644 index 49d4011082..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -+++ b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -@@ -37,8 +37,18 @@ - this.catalystListener = new SculkCatalystBlockEntity.CatalystListener(state, new BlockPositionSource(pos)); - } - -+ // Paper start - Fix NPE in SculkBloomEvent world access -+ @Override -+ public void setLevel(Level level) { -+ super.setLevel(level); -+ this.catalystListener.sculkSpreader.level = level; -+ } -+ // Paper end - Fix NPE in SculkBloomEvent world access -+ - public static void serverTick(Level world, BlockPos pos, BlockState state, SculkCatalystBlockEntity blockEntity) { -+ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = blockEntity.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. - blockEntity.catalystListener.getSculkSpreader().updateCursors(world, pos, world.getRandom(), true); -+ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = null; // CraftBukkit - } - - @Override -@@ -69,6 +79,7 @@ - this.blockState = state; - this.positionSource = positionSource; - this.sculkSpreader = SculkSpreader.createLevelSpreader(); -+ // this.sculkSpreader.level = this.level; // CraftBukkit // Paper - Fix NPE in SculkBloomEvent world access - } - - @Override diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch b/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch deleted file mode 100644 index b5587ac5d9..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java.patch +++ /dev/null @@ -1,19 +0,0 @@ ---- a/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java -+++ b/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java -@@ -21,6 +21,7 @@ - import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.state.BlockState; - import net.minecraft.world.level.chunk.LevelChunk; -+import net.minecraft.world.level.dimension.LevelStem; - import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; - import net.minecraft.world.level.levelgen.feature.Feature; - import net.minecraft.world.level.levelgen.feature.configurations.EndGatewayConfiguration; -@@ -143,7 +144,7 @@ - public Vec3 getPortalPosition(ServerLevel world, BlockPos pos) { - BlockPos blockposition1; - -- if (this.exitPortal == null && world.dimension() == Level.END) { -+ if (this.exitPortal == null && world.getTypeKey() == LevelStem.END) { // CraftBukkit - work in alternate worlds - blockposition1 = TheEndGatewayBlockEntity.findOrCreateValidTeleportPos(world, pos); - blockposition1 = blockposition1.above(10); - TheEndGatewayBlockEntity.LOGGER.debug("Creating portal at {}", blockposition1);