diff --git a/Spigot-API-Patches/0312-Add-PlayerKickEvent-causes.patch b/Spigot-API-Patches/0312-Add-PlayerKickEvent-causes.patch new file mode 100644 index 000000000..b3cfb136d --- /dev/null +++ b/Spigot-API-Patches/0312-Add-PlayerKickEvent-causes.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 15 May 2021 20:30:34 -0700 +Subject: [PATCH] Add PlayerKickEvent causes + + +diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java +index 34b51466ffb281b05f531b3f7deda245ae7fd96a..a4b236d75e77176a163094edd31f81725bbf4eca 100644 +--- a/src/main/java/org/bukkit/entity/Player.java ++++ b/src/main/java/org/bukkit/entity/Player.java +@@ -237,6 +237,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM + * @param message kick message + */ + void kick(final @Nullable net.kyori.adventure.text.Component message); ++ ++ /** ++ * Kicks player with custom kick message and cause. ++ * ++ * @param message kick message ++ * @param cause kick cause ++ */ ++ void kick(final @Nullable Component message, @NotNull org.bukkit.event.player.PlayerKickEvent.Cause cause); + // Paper end + + /** +diff --git a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java +index 5c0efe74237dbe6803ce023fde99682ff70d1a92..02914c0743852e9e4fd2c085fd4b735e74d8875b 100644 +--- a/src/main/java/org/bukkit/event/player/PlayerKickEvent.java ++++ b/src/main/java/org/bukkit/event/player/PlayerKickEvent.java +@@ -12,6 +12,7 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + private net.kyori.adventure.text.Component leaveMessage; // Paper + private net.kyori.adventure.text.Component kickReason; // Paper ++ private final Cause cause; // Paper + private Boolean cancel; + + @Deprecated // Paper +@@ -19,14 +20,25 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { + super(playerKicked); + this.kickReason = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(kickReason); // Paper + this.leaveMessage = org.bukkit.Bukkit.getUnsafe().legacyComponentSerializer().deserialize(leaveMessage); // Paper ++ this.cause = Cause.UNKNOWN; // Paper + this.cancel = false; + } + // Paper start ++ @Deprecated + public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final net.kyori.adventure.text.Component kickReason, @NotNull final net.kyori.adventure.text.Component leaveMessage) { + super(playerKicked); + this.kickReason = kickReason; + this.leaveMessage = leaveMessage; + this.cancel = false; ++ this.cause = Cause.UNKNOWN; ++ } ++ ++ public PlayerKickEvent(@NotNull final Player playerKicked, @NotNull final net.kyori.adventure.text.Component kickReason, @NotNull final net.kyori.adventure.text.Component leaveMessage, @NotNull final Cause cause) { ++ super(playerKicked); ++ this.kickReason = kickReason; ++ this.leaveMessage = leaveMessage; ++ this.cancel = false; ++ this.cause = cause; + } + + /** +@@ -132,4 +144,63 @@ public class PlayerKickEvent extends PlayerEvent implements Cancellable { + public static HandlerList getHandlerList() { + return handlers; + } ++ // Paper start ++ /** ++ * Gets the cause of this kick ++ * ++ * @return ++ */ ++ @NotNull ++ public org.bukkit.event.player.PlayerKickEvent.Cause getCause() { ++ return cause; ++ } ++ ++ public enum Cause { ++ ++ PLUGIN, ++ ++ WHITELIST, ++ ++ BANNED, ++ ++ IP_BANNED, ++ ++ KICK_COMMAND, ++ ++ FLYING_PLAYER, ++ ++ FLYING_VEHICLE, ++ ++ TIMEOUT, ++ ++ IDLING, ++ ++ INVALID_VEHICLE_MOVEMENT, ++ ++ INVALID_PLAYER_MOVEMENT, ++ ++ INVALID_ENTITY_ATTACKED, ++ ++ INVALID_PAYLOAD, ++ ++ SPAM, ++ ++ ILLEGAL_ACTION, ++ ++ ILLEGAL_CHARACTERS, ++ ++ SELF_INTERACTION, ++ ++ DUPLICATE_LOGIN, ++ ++ /** ++ * Spigot's restart command ++ */ ++ RESTART_COMMAND, ++ /** ++ * Fallback cause ++ */ ++ UNKNOWN, ++ } ++ // Paper end + } diff --git a/Spigot-Server-Patches/0746-Add-PlayerKickEvent-causes.patch b/Spigot-Server-Patches/0746-Add-PlayerKickEvent-causes.patch new file mode 100644 index 000000000..f2b7136d9 --- /dev/null +++ b/Spigot-Server-Patches/0746-Add-PlayerKickEvent-causes.patch @@ -0,0 +1,393 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 15 May 2021 20:30:45 -0700 +Subject: [PATCH] Add PlayerKickEvent causes + + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 848219f43b2bcb2d79147107c68df52efd46d461..d88ba18014087a5f945c1ea616b83a7df133e25c 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -2043,7 +2043,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant 80) { + PlayerConnection.LOGGER.warn("{} was kicked for floating too long!", this.player.getDisplayName().getString()); +- this.disconnect(com.destroystokyo.paper.PaperConfig.flyingKickPlayerMessage); // Paper - use configurable kick message ++ this.disconnect(com.destroystokyo.paper.PaperConfig.flyingKickPlayerMessage, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_PLAYER); // Paper - use configurable kick message & kick event cause + return; + } + } else { +@@ -348,7 +348,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + if (this.D && this.player.getRootVehicle().getRidingPassenger() == this.player) { + if (++this.E > 80) { + PlayerConnection.LOGGER.warn("{} was kicked for floating a vehicle too long!", this.player.getDisplayName().getString()); +- this.disconnect(com.destroystokyo.paper.PaperConfig.flyingKickVehicleMessage); // Paper - use configurable kick message ++ this.disconnect(com.destroystokyo.paper.PaperConfig.flyingKickVehicleMessage, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_VEHICLE); // Paper - use configurable kick message & kick event cause + return; + } + } else { +@@ -370,7 +370,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + if (this.isPendingPing()) { + if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected + PlayerConnection.LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getName()); // more info +- this.disconnect(new ChatMessage("disconnect.timeout", new Object[0])); ++ this.disconnect(new ChatMessage("disconnect.timeout", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause + } + } else { + if (elapsedTime >= 15000L) { // 15 seconds +@@ -400,7 +400,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + + if (this.player.F() > 0L && this.minecraftServer.getIdleTimeout() > 0 && SystemUtils.getMonotonicMillis() - this.player.F() > (long) (this.minecraftServer.getIdleTimeout() * 1000 * 60)) { + this.player.resetIdleTimer(); // CraftBukkit - SPIGOT-854 +- this.disconnect(new ChatMessage("multiplayer.disconnect.idling")); ++ this.disconnect(new ChatMessage("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause + } + + } +@@ -425,14 +425,22 @@ public class PlayerConnection implements PacketListenerPlayIn { + + public void disconnect(String s) { + // Paper start +- this.disconnect(PaperAdventure.LEGACY_SECTION_UXRC.deserialize(s)); ++ this.disconnect(PaperAdventure.LEGACY_SECTION_UXRC.deserialize(s), org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); ++ } ++ ++ public void disconnect(String s, PlayerKickEvent.Cause cause) { ++ this.disconnect(PaperAdventure.LEGACY_SECTION_UXRC.deserialize(s), cause); + } + + public void disconnect(final IChatBaseComponent reason) { +- this.disconnect(PaperAdventure.asAdventure(reason)); ++ this.disconnect(PaperAdventure.asAdventure(reason), org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); ++ } ++ ++ public void disconnect(final IChatBaseComponent reason, PlayerKickEvent.Cause cause) { ++ this.disconnect(PaperAdventure.asAdventure(reason), cause); + } + +- public void disconnect(net.kyori.adventure.text.Component reason) { ++ public void disconnect(net.kyori.adventure.text.Component reason, org.bukkit.event.player.PlayerKickEvent.Cause cause) { + // Paper end + // CraftBukkit start - fire PlayerKickEvent + if (this.processedDisconnect) { +@@ -440,7 +448,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + } + net.kyori.adventure.text.Component leaveMessage = net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, this.player.getBukkitEntity().displayName()); // Paper - Adventure + +- PlayerKickEvent event = new PlayerKickEvent(this.server.getPlayer(this.player), reason, leaveMessage); // Paper - Adventure ++ PlayerKickEvent event = new PlayerKickEvent(this.server.getPlayer(this.player), reason, leaveMessage, cause); // Paper - Adventure & kick event reason + + if (this.server.getServer().isRunning()) { + this.server.getPluginManager().callEvent(event); +@@ -518,7 +526,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + public void a(PacketPlayInVehicleMove packetplayinvehiclemove) { + PlayerConnectionUtils.ensureMainThread(packetplayinvehiclemove, this, this.player.getWorldServer()); + if (b(packetplayinvehiclemove)) { +- this.disconnect(new ChatMessage("multiplayer.disconnect.invalid_vehicle_movement")); ++ this.disconnect(new ChatMessage("multiplayer.disconnect.invalid_vehicle_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_VEHICLE_MOVEMENT); // Paper - kick event cause + } else { + Entity entity = this.player.getRootVehicle(); + +@@ -752,13 +760,13 @@ public class PlayerConnection implements PacketListenerPlayIn { + // PlayerConnectionUtils.ensureMainThread(packetplayintabcomplete, this, this.player.getWorldServer()); // Paper - run this async + // CraftBukkit start + if (tabSpamLimiter.addAndGet(com.destroystokyo.paper.PaperConfig.tabSpamIncrement) > com.destroystokyo.paper.PaperConfig.tabSpamLimit && !this.minecraftServer.getPlayerList().isOp(this.player.getProfile())) { // Paper start - split and make configurable +- minecraftServer.scheduleOnMain(() -> this.disconnect(new ChatMessage("disconnect.spam", new Object[0]))); // Paper ++ minecraftServer.scheduleOnMain(() -> this.disconnect(new ChatMessage("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause + return; + } + // Paper start + String str = packetplayintabcomplete.c(); int index = -1; + if (str.length() > 64 && ((index = str.indexOf(' ')) == -1 || index >= 64)) { +- minecraftServer.scheduleOnMain(() -> this.disconnect(new ChatMessage("disconnect.spam", new Object[0]))); // Paper ++ minecraftServer.scheduleOnMain(() -> this.disconnect(new ChatMessage("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause + return; + } + // Paper end +@@ -906,7 +914,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + // Paper start - validate pick item position + if (!(packetplayinpickitem.b() >= 0 && packetplayinpickitem.b() < this.player.inventory.items.size())) { + PlayerConnection.LOGGER.warn("{} tried to set an invalid carried item", this.player.getDisplayName().getString()); +- this.disconnect("Invalid hotbar selection (Hacking?)"); ++ this.disconnect("Invalid hotbar selection (Hacking?)", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause + return; + } + this.player.inventory.c(packetplayinpickitem.b()); // Paper - Diff above if changed +@@ -1060,7 +1068,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + NBTTagList pageList = testStack.getTag().getList("pages", 8); + if (pageList.size() > 100) { + PlayerConnection.LOGGER.warn(this.player.getName() + " tried to send a book with too many pages"); +- minecraftServer.scheduleOnMain(() -> this.disconnect("Book too large!")); ++ minecraftServer.scheduleOnMain(() -> this.disconnect("Book too large!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION)); // Paper - kick event cause + return; + } + long byteTotal = 0; +@@ -1072,7 +1080,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + int byteLength = testString.getBytes(java.nio.charset.StandardCharsets.UTF_8).length; + if (byteLength > 256 * 4) { + PlayerConnection.LOGGER.warn(this.player.getName() + " tried to send a book with with a page too large!"); +- minecraftServer.scheduleOnMain(() -> this.disconnect("Book too large!")); ++ minecraftServer.scheduleOnMain(() -> this.disconnect("Book too large!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION)); // Paper - kick event cause + return; + } + byteTotal += byteLength; +@@ -1095,14 +1103,14 @@ public class PlayerConnection implements PacketListenerPlayIn { + + if (byteTotal > byteAllowed) { + PlayerConnection.LOGGER.warn(this.player.getName() + " tried to send too large of a book. Book Size: " + byteTotal + " - Allowed: "+ byteAllowed + " - Pages: " + pageList.size()); +- minecraftServer.scheduleOnMain(() -> this.disconnect("Book too large!")); ++ minecraftServer.scheduleOnMain(() -> this.disconnect("Book too large!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION)); // Paper - kick event cause + return; + } + } + // Paper end + // CraftBukkit start + if (this.lastBookTick + 20 > MinecraftServer.currentTick) { +- this.disconnect("Book edited too quickly!"); ++ this.disconnect("Book edited too quickly!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause + return; + } + this.lastBookTick = MinecraftServer.currentTick; +@@ -1214,7 +1222,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + public void a(PacketPlayInFlying packetplayinflying) { + PlayerConnectionUtils.ensureMainThread(packetplayinflying, this, this.player.getWorldServer()); + if (b(packetplayinflying)) { +- this.disconnect(new ChatMessage("multiplayer.disconnect.invalid_player_movement")); ++ this.disconnect(new ChatMessage("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause + } else { + WorldServer worldserver = this.player.getWorldServer(); + +@@ -1613,7 +1621,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + this.dropCount++; + if (this.dropCount >= 20) { + LOGGER.warn(this.player.getName() + " dropped their items too quickly!"); +- this.disconnect("You dropped your items too quickly (Hacking?)"); ++ this.disconnect("You dropped your items too quickly (Hacking?)", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause + return; + } + } +@@ -1926,7 +1934,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + this.player.resetIdleTimer(); + } else { + PlayerConnection.LOGGER.warn("{} tried to set an invalid carried item", this.player.getDisplayName().getString()); +- this.disconnect("Invalid hotbar selection (Hacking?)"); // CraftBukkit ++ this.disconnect("Invalid hotbar selection (Hacking?)", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // CraftBukkit // Paper - kick event cause + } + } + +@@ -1963,7 +1971,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + Waitable waitable = new Waitable() { + @Override + protected Object evaluate() { +- PlayerConnection.this.disconnect(new ChatMessage("multiplayer.disconnect.illegal_characters")); ++ PlayerConnection.this.disconnect(new ChatMessage("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - kick event cause + return null; + } + }; +@@ -1978,7 +1986,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + throw new RuntimeException(e); + } + } else { +- this.disconnect(new ChatMessage("multiplayer.disconnect.illegal_characters")); ++ this.disconnect(new ChatMessage("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - kick event cause + } + // CraftBukkit end + return; +@@ -2032,7 +2040,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + Waitable waitable = new Waitable() { + @Override + protected Object evaluate() { +- PlayerConnection.this.disconnect(new ChatMessage("disconnect.spam")); ++ PlayerConnection.this.disconnect(new ChatMessage("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause + return null; + } + }; +@@ -2047,7 +2055,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + throw new RuntimeException(e); + } + } else { +- this.disconnect(new ChatMessage("disconnect.spam")); ++ this.disconnect(new ChatMessage("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause + } + // CraftBukkit end + } +@@ -2320,7 +2328,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + // Spigot Start + if ( entity == player && !player.isSpectator() ) + { +- disconnect( "Cannot interact with self!" ); ++ disconnect( "Cannot interact with self!", org.bukkit.event.player.PlayerKickEvent.Cause.SELF_INTERACTION ); // Paper - kick event cause + return; + } + // Spigot End +@@ -2397,7 +2405,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + // CraftBukkit end + } else if (packetplayinuseentity.b() == PacketPlayInUseEntity.EnumEntityUseAction.ATTACK) { + if (entity instanceof EntityItem || entity instanceof EntityExperienceOrb || entity instanceof EntityArrow || (entity == this.player && !player.isSpectator())) { // CraftBukkit +- this.disconnect(new ChatMessage("multiplayer.disconnect.invalid_entity_attacked")); ++ this.disconnect(new ChatMessage("multiplayer.disconnect.invalid_entity_attacked"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_ENTITY_ATTACKED); // Paper - kick event cause + PlayerConnection.LOGGER.warn("Player {} tried to attack an invalid entity", this.player.getDisplayName().getString()); + return; + } +@@ -2802,7 +2810,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + // Paper start + if (!Bukkit.isPrimaryThread()) { + if (recipeSpamPackets.addAndGet(PaperConfig.autoRecipeIncrement) > PaperConfig.autoRecipeLimit) { +- minecraftServer.scheduleOnMain(() -> this.disconnect(new ChatMessage("disconnect.spam", new Object[0]))); // Paper ++ minecraftServer.scheduleOnMain(() -> this.disconnect(new ChatMessage("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause + return; + } + } +@@ -3001,7 +3009,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + } else if (!this.isExemptPlayer()) { + // Paper start - This needs to be handled on the main thread for plugins + minecraftServer.scheduleOnMain(() -> { +- this.disconnect(new ChatMessage("disconnect.timeout")); ++ this.disconnect(new ChatMessage("disconnect.timeout"), org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause + }); + // Paper end + } +@@ -3047,7 +3055,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + } + } catch (Exception ex) { + PlayerConnection.LOGGER.error("Couldn\'t register custom payload", ex); +- this.disconnect("Invalid payload REGISTER!"); ++ this.disconnect("Invalid payload REGISTER!", org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause + } + } else if (packetplayincustompayload.tag.equals(CUSTOM_UNREGISTER)) { + try { +@@ -3057,7 +3065,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + } + } catch (Exception ex) { + PlayerConnection.LOGGER.error("Couldn\'t unregister custom payload", ex); +- this.disconnect("Invalid payload UNREGISTER!"); ++ this.disconnect("Invalid payload UNREGISTER!", org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause + } + } else { + try { +@@ -3076,7 +3084,7 @@ public class PlayerConnection implements PacketListenerPlayIn { + server.getMessenger().dispatchIncomingMessage(player.getBukkitEntity(), packetplayincustompayload.tag.toString(), data); + } catch (Exception ex) { + PlayerConnection.LOGGER.error("Couldn\'t dispatch custom payload", ex); +- this.disconnect("Invalid custom payload!"); ++ this.disconnect("Invalid custom payload!", org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PAYLOAD); // Paper - kick event cause + } + } + +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index 2a76c3624c64e93509a96579f48c507e29901625..90776231b1faffb11e4394f555f336ca248e3004 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -720,7 +720,7 @@ public abstract class PlayerList { + while (iterator.hasNext()) { + entityplayer = (EntityPlayer) iterator.next(); + savePlayerFile(entityplayer); // CraftBukkit - Force the player's inventory to be saved +- entityplayer.playerConnection.disconnect(new ChatMessage("multiplayer.disconnect.duplicate_login", new Object[0])); ++ entityplayer.playerConnection.disconnect(new ChatMessage("multiplayer.disconnect.duplicate_login", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.DUPLICATE_LOGIN); // Paper - kick event cause + } + + // Instead of kicking then returning, we need to store the kick reason +@@ -1389,8 +1389,8 @@ public abstract class PlayerList { + public void shutdown(boolean isRestarting) { + // CraftBukkit start - disconnect safely + for (EntityPlayer player : this.players) { +- if (isRestarting) player.playerConnection.disconnect(org.spigotmc.SpigotConfig.restartMessage); else // Paper +- player.playerConnection.disconnect(this.server.server.shutdownMessage()); // CraftBukkit - add custom shutdown message // Paper - Adventure ++ if (isRestarting) player.playerConnection.disconnect(org.spigotmc.SpigotConfig.restartMessage, org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); else // Paper - kick event cause (cause is never used here) ++ player.playerConnection.disconnect(this.server.server.shutdownMessage(), org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); // CraftBukkit - add custom shutdown message // Paper - Adventure & KickEventCause (cause is never used here) + } + // CraftBukkit end + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 34395248e3daea47178cb40aad53680fbce73600..cfe6898dc373fe55a08acf5c90e200061aa7d0fc 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -499,16 +499,21 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + org.spigotmc.AsyncCatcher.catchOp("player kick"); // Spigot + if (getHandle().playerConnection == null) return; + +- getHandle().playerConnection.disconnect(message == null ? "" : message); ++ getHandle().playerConnection.disconnect(message == null ? "" : message, org.bukkit.event.player.PlayerKickEvent.Cause.PLUGIN); // Paper - kick event cause + } + + // Paper start + @Override + public void kick(final net.kyori.adventure.text.Component message) { ++ kick(message, org.bukkit.event.player.PlayerKickEvent.Cause.PLUGIN); ++ } ++ ++ @Override ++ public void kick(net.kyori.adventure.text.Component message, org.bukkit.event.player.PlayerKickEvent.Cause cause) { + org.spigotmc.AsyncCatcher.catchOp("player kick"); + final PlayerConnection connection = this.getHandle().playerConnection; + if (connection != null) { +- connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message); ++ connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message, cause); + } + } + // Paper end +diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java +index 6a408dc9286a60c3ca7830f88171919fb0fe6363..dc8da0448193a5fbf16cfe3b070923cfb8a23c6d 100644 +--- a/src/main/java/org/spigotmc/RestartCommand.java ++++ b/src/main/java/org/spigotmc/RestartCommand.java +@@ -74,7 +74,7 @@ public class RestartCommand extends Command + // Kick all players + for ( EntityPlayer p : com.google.common.collect.ImmutableList.copyOf( MinecraftServer.getServer().getPlayerList().players ) ) + { +- p.playerConnection.disconnect(SpigotConfig.restartMessage); ++ p.playerConnection.disconnect(SpigotConfig.restartMessage, org.bukkit.event.player.PlayerKickEvent.Cause.RESTART_COMMAND); // Paper - kick event reason (cause is never used)) + } + // Give the socket a chance to send the packets + try