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-api/src/main/java/org/bukkit/Server.java b/paper-api/src/main/java/org/bukkit/Server.java index 7dbfff8e0..5f649c86c 100644 --- a/paper-api/src/main/java/org/bukkit/Server.java +++ b/paper-api/src/main/java/org/bukkit/Server.java @@ -830,9 +830,8 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi * @param id the id of the map to get * @return a map view if it exists, or null otherwise */ - // @Deprecated(since = "1.6.2") // Paper - Not a magic value @Nullable - public MapView getMap(int id); + MapView getMap(int id); /** * Create a new map with an automatically assigned ID. diff --git a/paper-api/src/main/java/org/bukkit/entity/FishHook.java b/paper-api/src/main/java/org/bukkit/entity/FishHook.java index 470443e3e..1839195eb 100644 --- a/paper-api/src/main/java/org/bukkit/entity/FishHook.java +++ b/paper-api/src/main/java/org/bukkit/entity/FishHook.java @@ -1,5 +1,6 @@ package org.bukkit.entity; +import org.bukkit.inventory.EquipmentSlot; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -323,7 +324,6 @@ public interface FishHook extends Projectile { BOBBING; } - // Paper start - More FishHook API /** * Get the number of ticks the hook needs to wait for a fish to bite. * @@ -367,5 +367,18 @@ public interface FishHook extends Projectile { * enchantment. */ void resetFishingState(); - // Paper end + + /** + * Retrieve this fishhook back to the casting player. + *

+ * This method will trigger and respect API events, which may be subject to cancellation. + * Plugins listening to {@link org.bukkit.event.player.PlayerFishEvent} might for example cancel this action. + * + * @param slot Slot holding the fishing rod (must be HAND/OFF_HAND) + * @return The amount of damage which would be applied to the itemstack + * @throws IllegalStateException if the fish hook does not have a player casting it. + * @throws IllegalStateException if the player casting it is not holding a + * {@link org.bukkit.inventory.ItemType#FISHING_ROD} in the specified equipment slot. + */ + int retrieve(@NotNull EquipmentSlot slot); } diff --git a/paper-api/src/main/java/org/bukkit/entity/Player.java b/paper-api/src/main/java/org/bukkit/entity/Player.java index 7b9324d12..9ccb7e901 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Player.java +++ b/paper-api/src/main/java/org/bukkit/entity/Player.java @@ -2109,6 +2109,8 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM * * @param other The other {@link Player} to list. * @return True if the {@code other} player was not listed. + * @throws IllegalStateException if this player can't see the other player + * @see #canSee(Player) */ boolean listPlayer(Player other); // Paper end diff --git a/paper-api/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java b/paper-api/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java index 7ef5fbd88..8730daf02 100644 --- a/paper-api/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java +++ b/paper-api/src/main/java/org/bukkit/event/inventory/InventoryClickEvent.java @@ -203,10 +203,10 @@ public class InventoryClickEvent extends InventoryInteractEvent { /** * If the ClickType is NUMBER_KEY, this method will return the index of - * the pressed key (0-8). + * the pressed key (0-8) and -1 if player swapped with off-hand (or the action is not NUMBER_KEY). * - * @return the number on the key minus 1 (range 0-8); or -1 if not - * a NUMBER_KEY action + * @return the number on the key minus 1 (range 0-8); + * or -1 if ClickType is NUMBER_KEY and player did an off-hand swap. Is also -1 if ClickType is not NUMBER_KEY */ public int getHotbarButton() { return this.hotbarKey; diff --git a/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch b/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch index 10729a44c..0a8480644 100644 --- a/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch +++ b/paper-server/patches/features/0015-Moonrise-optimisation-patches.patch @@ -28202,10 +28202,10 @@ index b30f56fbc1fd17259a1d05dc9155fffcab292ca1..11fed81a4696ba18440e755c3b8a5ca3 this.generatingStep = generatingStep; this.cache = cache; diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index 73717609fccd9af12e2cc39824106f49426b581c..72524ff3399a4477dfa3db2f4e79bb14f6519a8b 100644 +index 5ec9e3b37e575e9805bf9f0ce5cae5c1284461d8..78201407a37eced73998b97d5d5c412eaba69af1 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -1321,7 +1321,7 @@ public abstract class PlayerList { +@@ -1320,7 +1320,7 @@ public abstract class PlayerList { public void setViewDistance(int viewDistance) { this.viewDistance = viewDistance; @@ -28214,7 +28214,7 @@ index 73717609fccd9af12e2cc39824106f49426b581c..72524ff3399a4477dfa3db2f4e79bb14 for (ServerLevel serverLevel : this.server.getAllLevels()) { if (serverLevel != null) { -@@ -1332,7 +1332,7 @@ public abstract class PlayerList { +@@ -1331,7 +1331,7 @@ public abstract class PlayerList { public void setSimulationDistance(int simulationDistance) { this.simulationDistance = simulationDistance; diff --git a/paper-server/patches/features/0023-Incremental-chunk-and-player-saving.patch b/paper-server/patches/features/0023-Incremental-chunk-and-player-saving.patch index 4cdfa5a7a..ba97d07c8 100644 --- a/paper-server/patches/features/0023-Incremental-chunk-and-player-saving.patch +++ b/paper-server/patches/features/0023-Incremental-chunk-and-player-saving.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Incremental chunk and player saving diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 00f7f4356d6bffdd31f58b9d798c755edd9cd3ff..ea85cac4a41075efe8525c40755e7ebac6ca9dea 100644 +index 094ef7f54ad71795a2d8c2a8d03a32bef6ff2164..79bc1b7d9f640d2322814177eb3e921da8671e87 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -952,7 +952,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { ++ server.executeBlocking(() -> { // Paper - Broadcast chat session update sync + this.player.setChatSession(chatSession); this.server .getPlayerList() .broadcastAll( - new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT), List.of(this.player)) + new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT), List.of(this.player)), this.player // Paper - Use single player info update packet on join ); ++ }); } ); -@@ -2013,11 +_,13 @@ + } @Override public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { diff --git a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch index 114e7eac7..04c85d3a4 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch @@ -756,7 +756,7 @@ return serverPlayer; } -@@ -488,24 +_,60 @@ +@@ -488,24 +_,59 @@ } public void sendActiveEffects(LivingEntity entity, ServerGamePacketListenerImpl connection) { @@ -800,12 +800,11 @@ + // CraftBukkit start - add a world/entity limited version + public void broadcastAll(Packet packet, net.minecraft.world.entity.player.Player entityhuman) { -+ for (int i = 0; i < this.players.size(); ++i) { -+ ServerPlayer entityplayer = this.players.get(i); ++ for (ServerPlayer entityplayer : this.players) { // Paper - replace for i with for each for thread safety + if (entityhuman != null && !entityplayer.getBukkitEntity().canSee(entityhuman.getBukkitEntity())) { + continue; + } -+ ((ServerPlayer) this.players.get(i)).connection.send(packet); ++ ((ServerPlayer) entityplayer).connection.send(packet); // Paper - replace for i with for each for thread safety + } + } + diff --git a/paper-server/patches/sources/net/minecraft/world/InteractionResult.java.patch b/paper-server/patches/sources/net/minecraft/world/InteractionResult.java.patch new file mode 100644 index 000000000..5471cd718 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/InteractionResult.java.patch @@ -0,0 +1,40 @@ +--- a/net/minecraft/world/InteractionResult.java ++++ b/net/minecraft/world/InteractionResult.java +@@ -30,18 +_,34 @@ + public record Pass() implements InteractionResult { + } + +- public record Success(InteractionResult.SwingSource swingSource, InteractionResult.ItemContext itemContext) implements InteractionResult { ++ // Paper start - track more context in interaction result ++ public record PaperSuccessContext(net.minecraft.core.@org.jspecify.annotations.Nullable BlockPos placedBlockPosition) { ++ static PaperSuccessContext DEFAULT = new PaperSuccessContext(null); ++ ++ public PaperSuccessContext placedBlockAt(final net.minecraft.core.BlockPos blockPos) { ++ return new PaperSuccessContext(blockPos); ++ } ++ } ++ public record Success(InteractionResult.SwingSource swingSource, InteractionResult.ItemContext itemContext, PaperSuccessContext paperSuccessContext) implements InteractionResult { ++ public InteractionResult.Success configurePaper(final java.util.function.UnaryOperator edit) { ++ return new InteractionResult.Success(this.swingSource, this.itemContext, edit.apply(this.paperSuccessContext)); ++ } ++ ++ public Success(final net.minecraft.world.InteractionResult.SwingSource swingSource, final net.minecraft.world.InteractionResult.ItemContext itemContext) { ++ this(swingSource, itemContext, PaperSuccessContext.DEFAULT); ++ } ++ // Paper end - track more context in interaction result + @Override + public boolean consumesAction() { + return true; + } + + public InteractionResult.Success heldItemTransformedTo(ItemStack stack) { +- return new InteractionResult.Success(this.swingSource, new InteractionResult.ItemContext(true, stack)); ++ return new InteractionResult.Success(this.swingSource, new InteractionResult.ItemContext(true, stack), this.paperSuccessContext); // Paper - track more context in interaction result + } + + public InteractionResult.Success withoutItem() { +- return new InteractionResult.Success(this.swingSource, InteractionResult.ItemContext.NONE); ++ return new InteractionResult.Success(this.swingSource, InteractionResult.ItemContext.NONE, this.paperSuccessContext); // Paper - track more context in interaction result + } + + public boolean wasItemInteraction() { diff --git a/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch b/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch index bbcf05ba0..a529dd9ad 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/BlockItem.java.patch @@ -56,6 +56,15 @@ level.playSound( player, clickedPos, +@@ -88,7 +_,7 @@ + ); + level.gameEvent(GameEvent.BLOCK_PLACE, clickedPos, GameEvent.Context.of(player, blockState)); + itemInHand.consume(1, player); +- return InteractionResult.SUCCESS; ++ return InteractionResult.SUCCESS.configurePaper(e -> e.placedBlockAt(clickedPos.immutable())); // Paper - track placed block position from block item + } + } + } @@ -137,8 +_,19 @@ protected boolean canPlace(BlockPlaceContext context, BlockState state) { diff --git a/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch index 6d3893213..443385a23 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch @@ -23,7 +23,7 @@ } } }; -@@ -373,10 +_,167 @@ +@@ -373,10 +_,166 @@ return InteractionResult.PASS; } else { Item item = this.getItem(); @@ -175,10 +175,9 @@ + } + + // SPIGOT-1288 - play sound stripped from BlockItem -+ if (this.item instanceof BlockItem) { ++ if (this.item instanceof BlockItem && success.paperSuccessContext().placedBlockPosition() != null) { + // Paper start - Fix spigot sound playing for BlockItem ItemStacks -+ BlockPos pos = new net.minecraft.world.item.context.BlockPlaceContext(context).getClickedPos(); -+ net.minecraft.world.level.block.state.BlockState state = serverLevel.getBlockState(pos); ++ net.minecraft.world.level.block.state.BlockState state = serverLevel.getBlockState(success.paperSuccessContext().placedBlockPosition()); + net.minecraft.world.level.block.SoundType soundType = state.getSoundType(); + // Paper end - Fix spigot sound playing for BlockItem ItemStacks + serverLevel.playSound(player, clickedPos, soundType.getPlaceSound(), net.minecraft.sounds.SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); 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/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 5fb7b3a76..6ce00157d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -40,6 +40,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; import javax.imageio.ImageIO; +import net.minecraft.Optionull; import net.minecraft.advancements.AdvancementHolder; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; @@ -1943,12 +1944,13 @@ public final class CraftServer implements Server { } @Override - @Deprecated public CraftMapView getMap(int id) { - MapItemSavedData mapData = this.console.getLevel(net.minecraft.world.level.Level.OVERWORLD).getMapData(new MapId(id)); - if (mapData == null) { - return null; - } + final net.minecraft.world.level.Level overworld = this.console.overworld(); + if (overworld == null) return null; + + final MapItemSavedData mapData = overworld.getMapData(new MapId(id)); + if (mapData == null) return null; + return mapData.mapView; } @@ -2261,7 +2263,11 @@ public final class CraftServer implements Server { @Override public GameMode getDefaultGameMode() { - return GameMode.getByValue(this.console.getLevel(net.minecraft.world.level.Level.OVERWORLD).serverLevelData.getGameType().getId()); + return GameMode.getByValue(Optionull.mapOrDefault( + this.console.getLevel(net.minecraft.world.level.Level.OVERWORLD), + l -> l.serverLevelData.getGameType(), + this.console.getProperties().gamemode + ).getId()); } @Override 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); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java index 94f07ebc2..5f7225f18 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java @@ -2,10 +2,16 @@ package org.bukkit.craftbukkit.entity; import com.google.common.base.Preconditions; import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.FishingHook; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import org.bukkit.craftbukkit.CraftEquipmentSlot; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.entity.Entity; import org.bukkit.entity.FishHook; +import org.bukkit.inventory.EquipmentSlot; public class CraftFishHook extends CraftProjectile implements FishHook { private double biteChance = -1; @@ -233,4 +239,18 @@ public class CraftFishHook extends CraftProjectile implements FishHook { hook.resetTimeUntilLured(); hook.timeUntilHooked = 0; // Reset time until hooked, will be repopulated once lured time is ticked down. } + + @Override + public int retrieve(EquipmentSlot slot) { + Preconditions.checkArgument(slot == EquipmentSlot.HAND || slot == EquipmentSlot.OFF_HAND, "Equipment slot must be HAND or OFF_HAND"); + final FishingHook fishingHook = getHandle(); + final Player playerOwner = fishingHook.getPlayerOwner(); + Preconditions.checkState(playerOwner != null, "Player owner cannot be null"); + + final InteractionHand hand = CraftEquipmentSlot.getHand(slot); + final ItemStack itemInHand = playerOwner.getItemInHand(hand); + Preconditions.checkState(itemInHand.is(Items.FISHING_ROD), "Item in slot is not a FISHING_ROD"); + + return fishingHook.retrieve(itemInHand, hand); + } } diff --git a/paper-server/src/main/resources/configurations/help.yml b/paper-server/src/main/resources/configurations/help.yml index 2cd6b353e..2a41f56a8 100644 --- a/paper-server/src/main/resources/configurations/help.yml +++ b/paper-server/src/main/resources/configurations/help.yml @@ -57,6 +57,7 @@ # If you need help with the configuration or have any questions related to Paper, # join us in our Discord or check the docs page. # +# File Reference: https://docs.papermc.io/paper/reference/bukkit-help-configuration/ # Docs: https://docs.papermc.io/ # Discord: https://discord.gg/papermc # Website: https://papermc.io/