From f86b4352282d753a4f6bde405f5a242ec5b0ec95 Mon Sep 17 00:00:00 2001 From: Warrior <50800980+Warriorrrr@users.noreply.github.com> Date: Sat, 26 Apr 2025 16:34:12 +0200 Subject: [PATCH] Add vault change state event (#12069) --- .../event/block/VaultChangeStateEvent.java | 79 +++++++++++++++++++ .../entity/vault/VaultBlockEntity.java.patch | 65 ++++++++++++++- .../block/data/CraftBlockData.java | 2 +- 3 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 paper-api/src/main/java/io/papermc/paper/event/block/VaultChangeStateEvent.java diff --git a/paper-api/src/main/java/io/papermc/paper/event/block/VaultChangeStateEvent.java b/paper-api/src/main/java/io/papermc/paper/event/block/VaultChangeStateEvent.java new file mode 100644 index 000000000..2fc049377 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/event/block/VaultChangeStateEvent.java @@ -0,0 +1,79 @@ +package io.papermc.paper.event.block; + +import com.google.common.base.Preconditions; +import org.bukkit.block.Block; +import org.bukkit.block.data.type.Vault; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.block.BlockEvent; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +/** + * Called when a vault block changes state. + */ +@NullMarked +public class VaultChangeStateEvent extends BlockEvent implements Cancellable { + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final @Nullable Player player; + private final Vault.State currentState; + private final Vault.State newState; + private boolean cancelled = false; + + @ApiStatus.Internal + public VaultChangeStateEvent(final Block vaultBlock, final @Nullable Player player, final Vault.State currentState, final Vault.State newState) { + super(vaultBlock); + this.player = player; + this.currentState = currentState; + this.newState = newState; + } + + /** + * Gets the player associated with this state change, if applicable. + * + * @return The associated player, or {@code null} if not known. + */ + public @Nullable Player getPlayer() { + return this.player; + } + + /** + * Gets the state the vault is currently in. + * + * @return The current vault state. + */ + public Vault.State getCurrentState() { + return currentState; + } + + /** + * Gets the state the vault is attempting to transition to. + * + * @return The new vault state. + */ + public Vault.State getNewState() { + return newState; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + @Override + public void setCancelled(final boolean cancel) { + this.cancelled = cancel; + } + + @Override + public HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java.patch index a84630639..024d2b4bd 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java.patch @@ -1,17 +1,52 @@ --- a/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java +++ b/net/minecraft/world/level/block/entity/vault/VaultBlockEntity.java -@@ -260,6 +_,11 @@ +@@ -260,7 +_,12 @@ if (!list.isEmpty()) { player.awardStat(Stats.ITEM_USED.get(stack.getItem())); stack.consume(config.keyItem().getCount(), player); +- unlock(level, state, pos, config, serverData, sharedData, list); + // CraftBukkit start + org.bukkit.event.block.BlockDispenseLootEvent vaultDispenseLootEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDispenseLootEvent(level, pos, player, list); + if (vaultDispenseLootEvent.isCancelled()) return; + list = vaultDispenseLootEvent.getDispensedLoot().stream().map(org.bukkit.craftbukkit.inventory.CraftItemStack::asNMSCopy).toList(); + // CraftBukkit end - unlock(level, state, pos, config, serverData, sharedData, list); ++ unlock(level, state, pos, config, serverData, sharedData, list, player); // Paper - Vault API serverData.addToRewardedPlayers(player); sharedData.updateConnectedPlayersWithinRange(level, pos, serverData, config, config.deactivationRange()); + } +@@ -269,8 +_,30 @@ + } + + static void setVaultState(ServerLevel level, BlockPos pos, BlockState oldState, BlockState newState, VaultConfig config, VaultSharedData sharedData) { +- VaultState vaultState = oldState.getValue(VaultBlock.STATE); +- VaultState vaultState1 = newState.getValue(VaultBlock.STATE); ++ // Paper start - Vault API ++ setVaultState(level, pos, oldState, newState, config,sharedData, null); ++ } ++ ++ static void setVaultState(ServerLevel level, BlockPos pos, BlockState oldState, BlockState newState, VaultConfig config, VaultSharedData sharedData, @Nullable Player associatedPlayer) { ++ VaultState vaultState = oldState.getValue(VaultBlock.STATE); final VaultState oldVaultState = vaultState; ++ VaultState vaultState1 = newState.getValue(VaultBlock.STATE); final VaultState newVaultState = vaultState1; ++ org.bukkit.entity.Player apiAssociatedPlayer = null; ++ if (associatedPlayer != null) { ++ apiAssociatedPlayer = (org.bukkit.entity.Player) associatedPlayer.getBukkitEntity(); ++ } else if (newVaultState == VaultState.ACTIVE) { ++ final Set connectedPlayers = sharedData.getConnectedPlayers(); ++ if (!connectedPlayers.isEmpty()) { // Used over sharedData#hasConnectedPlayers to ensure belows iterator#next is always okay. ++ apiAssociatedPlayer = level.getCraftServer().getPlayer(connectedPlayers.iterator().next()); ++ } ++ } ++ final io.papermc.paper.event.block.VaultChangeStateEvent event = new io.papermc.paper.event.block.VaultChangeStateEvent( ++ org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), ++ apiAssociatedPlayer, ++ org.bukkit.craftbukkit.block.data.CraftBlockData.toBukkit(oldVaultState, org.bukkit.block.data.type.Vault.State.class), ++ org.bukkit.craftbukkit.block.data.CraftBlockData.toBukkit(newVaultState, org.bukkit.block.data.type.Vault.State.class) ++ ); ++ if (!event.callEvent()) return; ++ // Paper end - Vault API + level.setBlock(pos, newState, 3); + vaultState.onTransition(level, pos, vaultState1, config, sharedData, newState.getValue(VaultBlock.OMINOUS)); + } @@ -282,6 +_,11 @@ ItemStack randomDisplayItemFromLootTable = getRandomDisplayItemFromLootTable( level, pos, config.overrideLootTableToDisplay().orElse(config.lootTable()) @@ -24,3 +59,29 @@ sharedData.setDisplayItem(randomDisplayItemFromLootTable); } } +@@ -304,10 +_,24 @@ + VaultSharedData sharedData, + List itemsToEject + ) { ++ // Paper start - Vault API ++ unlock(level, state, pos, config, serverData, sharedData, itemsToEject, null); ++ } ++ private static void unlock( ++ ServerLevel level, ++ BlockState state, ++ BlockPos pos, ++ VaultConfig config, ++ VaultServerData serverData, ++ VaultSharedData sharedData, ++ List itemsToEject, ++ final @Nullable Player associatedPlayer ++ ) { ++ // Paper end - Vault API + serverData.setItemsToEject(itemsToEject); + sharedData.setDisplayItem(serverData.getNextItemToEject()); + serverData.pauseStateUpdatingUntil(level.getGameTime() + 14L); +- setVaultState(level, pos, state, state.setValue(VaultBlock.STATE, VaultState.UNLOCKING), config, sharedData); ++ setVaultState(level, pos, state, state.setValue(VaultBlock.STATE, VaultState.UNLOCKING), config, sharedData, associatedPlayer); // Paper - Vault API + } + + private static List resolveItemsToEject(ServerLevel level, VaultConfig config, BlockPos pos, Player player, ItemStack key) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java index 328773b37..34a2e07da 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java @@ -165,7 +165,7 @@ public class CraftBlockData implements BlockData { * @throws IllegalStateException if the Enum could not be converted */ @SuppressWarnings("unchecked") - private static > B toBukkit(Enum nms, Class bukkit) { + public static > B toBukkit(Enum nms, Class bukkit) { if (nms instanceof Direction) { return (B) CraftBlock.notchToBlockFace((Direction) nms); }