mirror of
https://github.com/PaperMC/Paper.git
synced 2025-08-04 22:22:18 -07:00
Add API for client-side signs (#11903)
This commit is contained in:
@@ -0,0 +1,94 @@
|
|||||||
|
package io.papermc.paper.event.packet;
|
||||||
|
|
||||||
|
import io.papermc.paper.math.BlockPosition;
|
||||||
|
import io.papermc.paper.math.Position;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.block.sign.Side;
|
||||||
|
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.Unmodifiable;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a client attempts to modify a sign, but the location at which the sign should be edited
|
||||||
|
* has not yet been checked for the existence of a real sign.
|
||||||
|
* <p>
|
||||||
|
* Cancelling this event will prevent further processing of the sign change, but needs further handling
|
||||||
|
* by the plugin as the client's local world might be in an inconsistent state.
|
||||||
|
*
|
||||||
|
* @see Player#openVirtualSign(Position, Side)
|
||||||
|
*/
|
||||||
|
@NullMarked
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
public class UncheckedSignChangeEvent extends PlayerEvent implements Cancellable {
|
||||||
|
|
||||||
|
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||||
|
private boolean cancel = false;
|
||||||
|
private final BlockPosition editedBlockPosition;
|
||||||
|
private final Side side;
|
||||||
|
private final List<Component> lines;
|
||||||
|
|
||||||
|
@ApiStatus.Internal
|
||||||
|
public UncheckedSignChangeEvent(
|
||||||
|
final Player editor,
|
||||||
|
final BlockPosition editedBlockPosition,
|
||||||
|
final Side side,
|
||||||
|
final List<Component> lines
|
||||||
|
) {
|
||||||
|
super(editor);
|
||||||
|
this.editedBlockPosition = editedBlockPosition;
|
||||||
|
this.side = side;
|
||||||
|
this.lines = lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the location at which a potential sign was edited.
|
||||||
|
*
|
||||||
|
* @return location where the change happened
|
||||||
|
*/
|
||||||
|
public BlockPosition getEditedBlockPosition() {
|
||||||
|
return editedBlockPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets which side of the sign was edited.
|
||||||
|
*
|
||||||
|
* @return {@link Side} that was edited
|
||||||
|
*/
|
||||||
|
public Side getSide() {
|
||||||
|
return side;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the lines that the player has entered.
|
||||||
|
*
|
||||||
|
* @return the lines
|
||||||
|
*/
|
||||||
|
public @Unmodifiable List<Component> lines() {
|
||||||
|
return Collections.unmodifiableList(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(final boolean cancel) {
|
||||||
|
this.cancel = cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return HANDLER_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return HANDLER_LIST;
|
||||||
|
}
|
||||||
|
}
|
@@ -12,6 +12,7 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import io.papermc.paper.entity.LookAnchor;
|
import io.papermc.paper.entity.LookAnchor;
|
||||||
import io.papermc.paper.entity.PlayerGiveResult;
|
import io.papermc.paper.entity.PlayerGiveResult;
|
||||||
|
import io.papermc.paper.math.Position;
|
||||||
import org.bukkit.BanEntry;
|
import org.bukkit.BanEntry;
|
||||||
import org.bukkit.DyeColor;
|
import org.bukkit.DyeColor;
|
||||||
import org.bukkit.Effect;
|
import org.bukkit.Effect;
|
||||||
@@ -52,7 +53,6 @@ import org.bukkit.plugin.Plugin;
|
|||||||
import org.bukkit.plugin.messaging.PluginMessageRecipient;
|
import org.bukkit.plugin.messaging.PluginMessageRecipient;
|
||||||
import org.bukkit.potion.PotionEffect;
|
import org.bukkit.potion.PotionEffect;
|
||||||
import org.bukkit.potion.PotionEffectType;
|
import org.bukkit.potion.PotionEffectType;
|
||||||
import org.bukkit.profile.PlayerProfile;
|
|
||||||
import org.bukkit.scoreboard.Scoreboard;
|
import org.bukkit.scoreboard.Scoreboard;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jspecify.annotations.NullMarked;
|
import org.jspecify.annotations.NullMarked;
|
||||||
@@ -3449,6 +3449,21 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
|
|||||||
*/
|
*/
|
||||||
public void openSign(Sign sign, Side side);
|
public void openSign(Sign sign, Side side);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a sign for editing by the player.
|
||||||
|
* <p>
|
||||||
|
* The sign must only be placed locally for the player, which can be done with {@link #sendBlockChange(Location, BlockData)} and {@link #sendBlockUpdate(Location, TileState)}.
|
||||||
|
* A side-effect of this is that normal events, like {@link org.bukkit.event.block.SignChangeEvent} will not be called (unless there is an actual sign in the world).
|
||||||
|
* Additionally, the client may enforce distance limits to the opened position.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param block The block where the client has a sign placed
|
||||||
|
* @param side The side to edit
|
||||||
|
* @see io.papermc.paper.event.packet.UncheckedSignChangeEvent
|
||||||
|
*/
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
void openVirtualSign(Position block, Side side);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the demo screen to the player, this screen is normally only seen in
|
* Shows the demo screen to the player, this screen is normally only seen in
|
||||||
* the demo version of the game.
|
* the demo version of the game.
|
||||||
|
@@ -2486,7 +2486,7 @@
|
|||||||
} else if (flag && flag2) {
|
} else if (flag && flag2) {
|
||||||
if (this.dropSpamThrottler.isUnderThreshold()) {
|
if (this.dropSpamThrottler.isUnderThreshold()) {
|
||||||
this.dropSpamThrottler.increment();
|
this.dropSpamThrottler.increment();
|
||||||
@@ -1895,11 +_,24 @@
|
@@ -1895,15 +_,38 @@
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleSignUpdate(ServerboundSignUpdatePacket packet) {
|
public void handleSignUpdate(ServerboundSignUpdatePacket packet) {
|
||||||
@@ -2512,6 +2512,20 @@
|
|||||||
this.player.resetLastActionTime();
|
this.player.resetLastActionTime();
|
||||||
ServerLevel serverLevel = this.player.serverLevel();
|
ServerLevel serverLevel = this.player.serverLevel();
|
||||||
BlockPos pos = packet.getPos();
|
BlockPos pos = packet.getPos();
|
||||||
|
if (serverLevel.hasChunkAt(pos)) {
|
||||||
|
+ // Paper start - Add API for client-side signs
|
||||||
|
+ if (!new io.papermc.paper.event.packet.UncheckedSignChangeEvent(
|
||||||
|
+ this.player.getBukkitEntity(),
|
||||||
|
+ io.papermc.paper.util.MCUtil.toPosition(pos),
|
||||||
|
+ packet.isFrontText() ? org.bukkit.block.sign.Side.FRONT : org.bukkit.block.sign.Side.BACK,
|
||||||
|
+ filteredText.stream().<net.kyori.adventure.text.Component>map(line -> net.kyori.adventure.text.Component.text(line.raw())).toList())
|
||||||
|
+ .callEvent()) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ // Paper end - Add API for client-side signs
|
||||||
|
if (!(serverLevel.getBlockEntity(pos) instanceof SignBlockEntity signBlockEntity)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
@@ -1915,14 +_,32 @@
|
@@ -1915,14 +_,32 @@
|
||||||
@Override
|
@Override
|
||||||
public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) {
|
public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) {
|
||||||
|
@@ -12,6 +12,8 @@ import io.papermc.paper.configuration.GlobalConfiguration;
|
|||||||
import io.papermc.paper.entity.LookAnchor;
|
import io.papermc.paper.entity.LookAnchor;
|
||||||
import io.papermc.paper.entity.PaperPlayerGiveResult;
|
import io.papermc.paper.entity.PaperPlayerGiveResult;
|
||||||
import io.papermc.paper.entity.PlayerGiveResult;
|
import io.papermc.paper.entity.PlayerGiveResult;
|
||||||
|
import io.papermc.paper.math.Position;
|
||||||
|
import io.papermc.paper.util.MCUtil;
|
||||||
import it.unimi.dsi.fastutil.shorts.ShortArraySet;
|
import it.unimi.dsi.fastutil.shorts.ShortArraySet;
|
||||||
import it.unimi.dsi.fastutil.shorts.ShortSet;
|
import it.unimi.dsi.fastutil.shorts.ShortSet;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -73,6 +75,7 @@ import net.minecraft.network.protocol.game.ClientboundHurtAnimationPacket;
|
|||||||
import net.minecraft.network.protocol.game.ClientboundLevelEventPacket;
|
import net.minecraft.network.protocol.game.ClientboundLevelEventPacket;
|
||||||
import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket;
|
import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket;
|
||||||
import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket;
|
import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket;
|
||||||
|
import net.minecraft.network.protocol.game.ClientboundOpenSignEditorPacket;
|
||||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
|
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
|
||||||
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
|
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
|
||||||
import net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket;
|
import net.minecraft.network.protocol.game.ClientboundRemoveMobEffectPacket;
|
||||||
@@ -3037,6 +3040,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|||||||
CraftSign.openSign(sign, this, side);
|
CraftSign.openSign(sign, this, side);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void openVirtualSign(Position block, Side side) {
|
||||||
|
if (this.getHandle().connection == null) return;
|
||||||
|
|
||||||
|
this.getHandle().connection.send(new ClientboundOpenSignEditorPacket(MCUtil.toBlockPos(block), side == Side.FRONT));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showDemoScreen() {
|
public void showDemoScreen() {
|
||||||
if (this.getHandle().connection == null) return;
|
if (this.getHandle().connection == null) return;
|
||||||
|
Reference in New Issue
Block a user