Add PlayerLiddedOpenEvent

This commit is contained in:
Isaac - The456 2024-12-25 01:19:30 +00:00
parent 0450bda4fe
commit abf6eca3dc
No known key found for this signature in database
GPG key ID: 57A848D2F87C14EF
4 changed files with 139 additions and 6 deletions

View file

@ -0,0 +1,89 @@
package io.papermc.paper.event.player;
import io.papermc.paper.block.LidMode;
import io.papermc.paper.block.LidState;
import io.papermc.paper.block.Lidded;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.player.PlayerEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.NullMarked;
/**
* Called when a player opens a {@link Lidded} block.
*
* <p>
* This is called every time a player opens a {@link Lidded} block
* regardless of if the lid is already open (e.g. multiple players).
* <p>
* Cancelling this event prevents the player from being considered in other {@link Lidded} methods:
* they will not contribute to the {@link Lidded#getTrueLidState()} and {@link Lidded#getEffectiveLidState()}.
* <p>
* This event is called twice for double chests, once for each half.
*/
@NullMarked
public class PlayerLiddedOpenEvent extends PlayerEvent implements Cancellable {
private static final HandlerList HANDLER_LIST = new HandlerList();
private final Lidded blockState;
private final Block block;
private boolean cancelled;
@ApiStatus.Internal
public PlayerLiddedOpenEvent(final @NotNull Player who, final @NotNull Lidded blockState, final @NotNull Block block) {
super(who);
this.cancelled = false;
this.blockState = blockState;
this.block = block;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(final boolean cancel) {
this.cancelled = cancel;
}
/**
* Gets the {@link Lidded} block involved in this event.
* @return the lidded block
*/
@NotNull
public Lidded getLidded() {
return blockState;
}
/**
* Gets the block involved in this event.
* @return the block
*/
@NotNull
public Block getBlock() {
return block;
}
/**
* Gets if the block would appear to open, if this event is not cancelled.
* return if the block would appear to open
*/
public boolean isOpening() {
return blockState.getLidMode() == LidMode.DEFAULT && blockState.getTrueLidState() == LidState.CLOSED;
}
@Override
@NotNull
public HandlerList getHandlers() {
return HANDLER_LIST;
}
public static @NotNull HandlerList getHandlerList() {
return HANDLER_LIST;
}
}

View file

@ -8,7 +8,7 @@
protected abstract void onOpen(Level level, BlockPos pos, BlockState state);
@@ -20,10 +_,94 @@
@@ -20,10 +_,109 @@
protected abstract void openerCountChanged(Level level, BlockPos pos, BlockState state, int count, int openCount);
@ -33,13 +33,17 @@
- public void incrementOpeners(Player player, Level level, BlockPos pos, BlockState state) {
+ // Paper start - add Improved Lidded API
+ private io.papermc.paper.block.LidMode apiLidMode = io.papermc.paper.block.LidMode.DEFAULT;
+ private final java.util.Set<Player> cancelledPlayers = new java.util.HashSet<>(); // Paper - store players whose opening was cancelled by PlayerLiddedOpenEvent
+
+ public void startForceLiddedLidOpen(Level level, BlockPos pos, BlockState state) {
+ incrementOpeners(null, level, pos, state);
+ }
+
+ public void stopForceLiddedLidOpen(Level level, BlockPos pos, BlockState state) {
+ decrementOpeners(null, level, pos, state);
+ apiLidMode = io.papermc.paper.block.LidMode.DEFAULT;
+ }
+
+ public void startForceLiddedLidClose(Level level, BlockPos pos, BlockState state) {
+ if (this.getTrueLidState() == io.papermc.paper.block.LidState.OPEN) {
+ this.onClose(level, pos, state);
@ -47,6 +51,7 @@
+ }
+ this.openerCountChanged(level, pos, state, this.openCount, 0);
+ }
+
+ public void stopForceLiddedLidClose(Level level, BlockPos pos, BlockState state) {
+ if (this.getTrueLidState() == io.papermc.paper.block.LidState.OPEN) {
+ this.onOpen(level, pos, state);
@ -56,12 +61,15 @@
+ this.openerCountChanged(level, pos, state, 0, this.openCount);
+ apiLidMode = io.papermc.paper.block.LidMode.DEFAULT;
+ }
+
+ public io.papermc.paper.block.LidMode getLidMode() {
+ return apiLidMode;
+ }
+
+ public void setLidMode(final io.papermc.paper.block.LidMode targetLidMode) {
+ apiLidMode = targetLidMode;
+ }
+
+ public io.papermc.paper.block.LidState getEffectiveLidState() {
+ return switch (apiLidMode) {
+ case OPEN_UNTIL_VIEWED, FORCED_OPEN -> io.papermc.paper.block.LidState.OPEN;
@ -69,6 +77,7 @@
+ default -> getTrueLidState();
+ };
+ }
+
+ public io.papermc.paper.block.LidState getTrueLidState() {
+ boolean virtualViewerPresent = (apiLidMode == io.papermc.paper.block.LidMode.FORCED_OPEN || apiLidMode == io.papermc.paper.block.LidMode.OPEN_UNTIL_VIEWED);
+ int trueOpenCount = this.openCount - (virtualViewerPresent ? 1 : 0);
@ -80,6 +89,12 @@
+ // Paper end - add Improved Lidded API
+
+ public void incrementOpeners(@javax.annotation.Nullable Player player, Level level, BlockPos pos, BlockState state) { // Paper - make player nullable for New Lidded API
+ // Paper start - Call PlayerLiddedOpenEvent
+ if (player != null && !org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLiddedOpenEvent(player, level, pos)) {
+ cancelledPlayers.add(player);
+ return;
+ }
+ // Paper end - Call PlayerLiddedOpenEvent
+ // Paper start - add Improved Lidded API
+ if (this.openCount == 0 && apiLidMode == io.papermc.paper.block.LidMode.CLOSED_UNTIL_NOT_VIEWED) {
+ apiLidMode = io.papermc.paper.block.LidMode.DEFAULT;
@ -104,7 +119,7 @@
if (i == 0) {
this.onOpen(level, pos, state);
level.gameEvent(player, GameEvent.CONTAINER_OPEN, pos);
@@ -31,11 +_,43 @@
@@ -31,11 +_,44 @@
}
this.openerCountChanged(level, pos, state, i, this.openCount);
@ -122,6 +137,7 @@
- public void decrementOpeners(Player player, Level level, BlockPos pos, BlockState state) {
+ public void decrementOpeners(@javax.annotation.Nullable Player player, Level level, BlockPos pos, BlockState state) { // Paper - make player nullable for New Lidded API
+ if (player != null && cancelledPlayers.remove(player)) return; // Paper - do not decrement if player's opening was cancelled by PlayerLiddedOpenEvent
+ int oldPower = Math.max(0, Math.min(15, this.openCount)); // CraftBukkit - Get power before new viewer is added
+ if (this.openCount == 0) return; // Paper - Prevent ContainerOpenersCounter openCount from going negative
int i = this.openCount--;
@ -149,7 +165,17 @@
if (this.openCount == 0) {
this.onClose(level, pos, state);
level.gameEvent(player, GameEvent.CONTAINER_CLOSE, pos);
@@ -59,8 +_,14 @@
@@ -53,14 +_,24 @@
public void recheckOpeners(Level level, BlockPos pos, BlockState state) {
List<Player> playersWithContainerOpen = this.getPlayersWithContainerOpen(level, pos);
+ // Paper start - maintain cancelledPlayers, list of players with the chest open, but without the lid.
+ cancelledPlayers.removeIf(java.util.function.Predicate.not(playersWithContainerOpen::contains));
+ playersWithContainerOpen.removeIf(cancelledPlayers::contains);
+ // Paper end - maintain cancelledPlayers, list of players with the chest open, but without the lid.
this.maxInteractionRange = 0.0;
for (Player player : playersWithContainerOpen) {
this.maxInteractionRange = Math.max(player.blockInteractionRange(), this.maxInteractionRange);
}

View file

@ -46,12 +46,13 @@
this.openCount = type;
if (type == 0) {
this.animationStatus = ShulkerBoxBlockEntity.AnimationStatus.CLOSING;
@@ -159,6 +_,71 @@
@@ -159,6 +_,72 @@
level.updateNeighborsAt(pos, state.getBlock());
}
+ // Paper start - add Improved Lidded API
+ private io.papermc.paper.block.LidMode apiLidMode = io.papermc.paper.block.LidMode.DEFAULT;
+ private final java.util.Set<Player> cancelledPlayers = new java.util.HashSet<>(); // Paper - store players whose opening was cancelled by PlayerLiddedOpenEvent
+
+ public void startForceLiddedLidOpen() {
+ this.openCount++;
@ -118,10 +119,16 @@
@Override
public void startOpen(Player player) {
if (!this.remove && !player.isSpectator()) {
@@ -166,13 +_,36 @@
@@ -166,20 +_,63 @@
this.openCount = 0;
}
+ // Paper start - Call PlayerLiddedOpenEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLiddedOpenEvent(player, this.level, this.worldPosition)) {
+ cancelledPlayers.add(player);
+ return;
+ }
+ // Paper end - Call PlayerLiddedOpenEvent
+ // Paper start - add Improved Lidded API
+ if (this.openCount == 0) {
+ if (apiLidMode == io.papermc.paper.block.LidMode.CLOSED_UNTIL_NOT_VIEWED) {
@ -155,9 +162,10 @@
}
}
@@ -180,6 +_,19 @@
@Override
public void stopOpen(Player player) {
if (!this.remove && !player.isSpectator()) {
+ if (cancelledPlayers.remove(player)) return; // Paper - do not decrement if player's opening was cancelled by PlayerLiddedOpenEvent
this.openCount--;
+
+ // Paper start - add Improved Lidded API

View file

@ -2271,4 +2271,14 @@ public class CraftEventFactory {
return event;
}
// Paper end - add EntityFertilizeEggEvent
public static boolean callPlayerLiddedOpenEvent(net.minecraft.world.entity.player.Player who, final Level world, final BlockPos pos) {
Player player = (Player) who.getBukkitEntity();
Block block = CraftBlock.at(world, pos);
io.papermc.paper.block.PaperLidded blockState = (io.papermc.paper.block.PaperLidded) CraftBlockStates.getBlockState(block);
io.papermc.paper.event.player.PlayerLiddedOpenEvent event = new io.papermc.paper.event.player.PlayerLiddedOpenEvent(player, blockState, block);
return event.callEvent();
}
}