535 lines
		
	
	
	
		
			38 KiB
			
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			535 lines
		
	
	
	
		
			38 KiB
			
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 | 
						|
From: Jake Potrebic <jake.m.potrebic@gmail.com>
 | 
						|
Date: Sat, 15 May 2021 20:30:45 -0700
 | 
						|
Subject: [PATCH] Add PlayerKickEvent causes
 | 
						|
 | 
						|
 | 
						|
diff --git a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/net/minecraft/network/chat/SignedMessageChain.java
 | 
						|
+++ b/src/main/java/net/minecraft/network/chat/SignedMessageChain.java
 | 
						|
@@ -0,0 +0,0 @@ public class SignedMessageChain {
 | 
						|
             } else {
 | 
						|
                 PlayerChatMessage playerChatMessage = new PlayerChatMessage(signedMessageLink, signature, body, (Component)null, FilterMask.PASS_THROUGH);
 | 
						|
                 if (!playerChatMessage.verify(signatureValidator)) {
 | 
						|
-                    throw new SignedMessageChain.DecodeException(Component.translatable("multiplayer.disconnect.unsigned_chat"), true);
 | 
						|
+                    throw new SignedMessageChain.DecodeException(Component.translatable("multiplayer.disconnect.unsigned_chat"), true, org.bukkit.event.player.PlayerKickEvent.Cause.UNSIGNED_CHAT); // Paper - kick event causes
 | 
						|
                 } else {
 | 
						|
                     if (playerChatMessage.hasExpiredServer(Instant.now())) {
 | 
						|
                         LOGGER.warn("Received expired chat: '{}'. Is the client/server system time unsynchronized?", (Object)body.content());
 | 
						|
@@ -0,0 +0,0 @@ public class SignedMessageChain {
 | 
						|
 
 | 
						|
     public static class DecodeException extends ThrowingComponent {
 | 
						|
         private final boolean shouldDisconnect;
 | 
						|
+        public final org.bukkit.event.player.PlayerKickEvent.Cause kickCause; // Paper
 | 
						|
 
 | 
						|
         public DecodeException(Component message, boolean shouldDisconnect) {
 | 
						|
+            // Paper start
 | 
						|
+            this(message, shouldDisconnect, org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN);
 | 
						|
+        }
 | 
						|
+        public DecodeException(Component message, boolean shouldDisconnect, org.bukkit.event.player.PlayerKickEvent.Cause kickCause) {
 | 
						|
+            // Paper end
 | 
						|
             super(message);
 | 
						|
             this.shouldDisconnect = shouldDisconnect;
 | 
						|
+            this.kickCause = kickCause; // Paper
 | 
						|
         }
 | 
						|
 
 | 
						|
         public boolean shouldDisconnect() {
 | 
						|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
 | 
						|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
 | 
						|
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
 | 
						|
                 ServerPlayer entityplayer = (ServerPlayer) iterator.next();
 | 
						|
 
 | 
						|
                 if (!whitelist.isWhiteListed(entityplayer.getGameProfile()) && !this.getPlayerList().isOp(entityplayer.getGameProfile())) { // Paper - Fix kicking ops when whitelist is reloaded (MC-171420)
 | 
						|
-                    entityplayer.connection.disconnect(org.spigotmc.SpigotConfig.whitelistMessage); // Paper - use configurable message
 | 
						|
+                    entityplayer.connection.disconnect(org.spigotmc.SpigotConfig.whitelistMessage, org.bukkit.event.player.PlayerKickEvent.Cause.WHITELIST); // Paper - use configurable message
 | 
						|
                 }
 | 
						|
             }
 | 
						|
 
 | 
						|
diff --git a/src/main/java/net/minecraft/server/commands/BanIpCommands.java b/src/main/java/net/minecraft/server/commands/BanIpCommands.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/net/minecraft/server/commands/BanIpCommands.java
 | 
						|
+++ b/src/main/java/net/minecraft/server/commands/BanIpCommands.java
 | 
						|
@@ -0,0 +0,0 @@ public class BanIpCommands {
 | 
						|
             }
 | 
						|
 
 | 
						|
             for(ServerPlayer serverPlayer : list) {
 | 
						|
-                serverPlayer.connection.disconnect(Component.translatable("multiplayer.disconnect.ip_banned"));
 | 
						|
+                serverPlayer.connection.disconnect(Component.translatable("multiplayer.disconnect.ip_banned"), org.bukkit.event.player.PlayerKickEvent.Cause.IP_BANNED); // Paper - kick event cause
 | 
						|
             }
 | 
						|
 
 | 
						|
             return list.size();
 | 
						|
diff --git a/src/main/java/net/minecraft/server/commands/BanPlayerCommands.java b/src/main/java/net/minecraft/server/commands/BanPlayerCommands.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/net/minecraft/server/commands/BanPlayerCommands.java
 | 
						|
+++ b/src/main/java/net/minecraft/server/commands/BanPlayerCommands.java
 | 
						|
@@ -0,0 +0,0 @@ public class BanPlayerCommands {
 | 
						|
                 source.sendSuccess(Component.translatable("commands.ban.success", ComponentUtils.getDisplayName(gameProfile), userBanListEntry.getReason()), true);
 | 
						|
                 ServerPlayer serverPlayer = source.getServer().getPlayerList().getPlayer(gameProfile.getId());
 | 
						|
                 if (serverPlayer != null) {
 | 
						|
-                    serverPlayer.connection.disconnect(Component.translatable("multiplayer.disconnect.banned"));
 | 
						|
+                    serverPlayer.connection.disconnect(Component.translatable("multiplayer.disconnect.banned"), org.bukkit.event.player.PlayerKickEvent.Cause.BANNED); // Paper - kick event cause
 | 
						|
                 }
 | 
						|
             }
 | 
						|
         }
 | 
						|
diff --git a/src/main/java/net/minecraft/server/commands/KickCommand.java b/src/main/java/net/minecraft/server/commands/KickCommand.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/net/minecraft/server/commands/KickCommand.java
 | 
						|
+++ b/src/main/java/net/minecraft/server/commands/KickCommand.java
 | 
						|
@@ -0,0 +0,0 @@ public class KickCommand {
 | 
						|
 
 | 
						|
     private static int kickPlayers(CommandSourceStack source, Collection<ServerPlayer> targets, Component reason) {
 | 
						|
         for(ServerPlayer serverPlayer : targets) {
 | 
						|
-            serverPlayer.connection.disconnect(reason);
 | 
						|
+            serverPlayer.connection.disconnect(reason, org.bukkit.event.player.PlayerKickEvent.Cause.KICK_COMMAND); // Paper - kick event cause
 | 
						|
             source.sendSuccess(Component.translatable("commands.kick.success", serverPlayer.getDisplayName(), reason), true);
 | 
						|
         }
 | 
						|
 
 | 
						|
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
 | 
						|
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         if (this.clientIsFloating && !this.player.isSleeping() && !this.player.isPassenger()) {
 | 
						|
             if (++this.aboveGroundTickCount > 80) {
 | 
						|
                 ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating too long!", this.player.getName().getString());
 | 
						|
-                this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingPlayer); // Paper - use configurable kick message
 | 
						|
+                this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingPlayer, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_PLAYER); // Paper - use configurable kick message & kick event cause
 | 
						|
                 return;
 | 
						|
             }
 | 
						|
         } else {
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
             if (this.clientVehicleIsFloating && this.player.getRootVehicle().getControllingPassenger() == this.player) {
 | 
						|
                 if (++this.aboveGroundVehicleTickCount > 80) {
 | 
						|
                     ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked for floating a vehicle too long!", this.player.getName().getString());
 | 
						|
-                    this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingVehicle); // Paper - use configurable kick message
 | 
						|
+                    this.disconnect(io.papermc.paper.configuration.GlobalConfiguration.get().messages.kick.flyingVehicle, org.bukkit.event.player.PlayerKickEvent.Cause.FLYING_VEHICLE); // Paper - use configurable kick message & kick event cause
 | 
						|
                     return;
 | 
						|
                 }
 | 
						|
             } else {
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         if (this.keepAlivePending) {
 | 
						|
             if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected
 | 
						|
                 ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getScoreboardName()); // more info
 | 
						|
-                this.disconnect(Component.translatable("disconnect.timeout", new Object[0]));
 | 
						|
+                this.disconnect(Component.translatable("disconnect.timeout", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause
 | 
						|
             }
 | 
						|
         } else {
 | 
						|
             if (elapsedTime >= 15000L) { // 15 seconds
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
 
 | 
						|
         if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) (this.server.getPlayerIdleTimeout() * 1000 * 60)) {
 | 
						|
             this.player.resetLastActionTime(); // CraftBukkit - SPIGOT-854
 | 
						|
-            this.disconnect(Component.translatable("multiplayer.disconnect.idling"));
 | 
						|
+            this.disconnect(Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause
 | 
						|
         }
 | 
						|
 
 | 
						|
     }
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         return this.server.isSingleplayerOwner(this.player.getGameProfile());
 | 
						|
     }
 | 
						|
 
 | 
						|
+    @io.papermc.paper.annotation.DoNotUse // Paper
 | 
						|
     public void disconnect(String s) {
 | 
						|
         // Paper start
 | 
						|
-        this.disconnect(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(s));
 | 
						|
+        this.disconnect(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(s), org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN);
 | 
						|
     }
 | 
						|
 
 | 
						|
+    public void disconnect(String s, PlayerKickEvent.Cause cause) {
 | 
						|
+        this.disconnect(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(s), cause);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    @io.papermc.paper.annotation.DoNotUse // Paper
 | 
						|
     public void disconnect(final Component reason) {
 | 
						|
-        this.disconnect(PaperAdventure.asAdventure(reason));
 | 
						|
+        this.disconnect(PaperAdventure.asAdventure(reason), org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN);
 | 
						|
+    }
 | 
						|
+
 | 
						|
+    public void disconnect(final Component 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) {
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
             Waitable waitable = new Waitable() {
 | 
						|
                 @Override
 | 
						|
                 protected Object evaluate() {
 | 
						|
-                    ServerGamePacketListenerImpl.this.disconnect(reason); // Paper - adventure
 | 
						|
+                    ServerGamePacketListenerImpl.this.disconnect(reason, cause); // Paper - adventure, kick event cause
 | 
						|
                     return null;
 | 
						|
                 }
 | 
						|
             };
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
 
 | 
						|
         net.kyori.adventure.text.Component leaveMessage = net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? this.player.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(this.player.getScoreboardName())); // Paper - Adventure
 | 
						|
 
 | 
						|
-        PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), reason, leaveMessage); // Paper - Adventure
 | 
						|
+        PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), reason, leaveMessage, cause); // Paper - Adventure & kick event reason
 | 
						|
 
 | 
						|
         if (this.cserver.getServer().isRunning()) {
 | 
						|
             this.cserver.getPluginManager().callEvent(event);
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
     public void handleMoveVehicle(ServerboundMoveVehiclePacket packet) {
 | 
						|
         PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
 | 
						|
         if (ServerGamePacketListenerImpl.containsInvalidValues(packet.getX(), packet.getY(), packet.getZ(), packet.getYRot(), packet.getXRot())) {
 | 
						|
-            this.disconnect(Component.translatable("multiplayer.disconnect.invalid_vehicle_movement"));
 | 
						|
+            this.disconnect(Component.translatable("multiplayer.disconnect.invalid_vehicle_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_VEHICLE_MOVEMENT); // Paper - kick event cause
 | 
						|
         } else {
 | 
						|
             Entity entity = this.player.getRootVehicle();
 | 
						|
 
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
 | 
						|
         if (packet.getId() == this.awaitingTeleport) {
 | 
						|
             if (this.awaitingPositionFromClient == null) {
 | 
						|
-                this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"));
 | 
						|
+                this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause
 | 
						|
                 return;
 | 
						|
             }
 | 
						|
 
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         // PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel()); // Paper - run this async
 | 
						|
         // CraftBukkit start
 | 
						|
         if (this.chatSpamTickCount.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamLimit && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { // Paper start - split and make configurable
 | 
						|
-            server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper
 | 
						|
+            server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause
 | 
						|
             return;
 | 
						|
         }
 | 
						|
         // Paper start
 | 
						|
         String str = packet.getCommand(); int index = -1;
 | 
						|
         if (str.length() > 64 && ((index = str.indexOf(' ')) == -1 || index >= 64)) {
 | 
						|
-            server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper
 | 
						|
+            server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause
 | 
						|
             return;
 | 
						|
         }
 | 
						|
         // Paper end
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         // Paper start - validate pick item position
 | 
						|
         if (!(packet.getSlot() >= 0 && packet.getSlot() < this.player.getInventory().items.size())) {
 | 
						|
             ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().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.getInventory().pickSlot(packet.getSlot()); // Paper - Diff above if changed
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
                 int byteLength = testString.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;
 | 
						|
                 if (byteLength > 256 * 4) {
 | 
						|
                     ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " tried to send a book with with a page too large!");
 | 
						|
-                    server.scheduleOnMain(() -> this.disconnect("Book too large!"));
 | 
						|
+                    server.scheduleOnMain(() -> this.disconnect("Book too large!", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION)); // Paper - kick event cause
 | 
						|
                     return;
 | 
						|
                 }
 | 
						|
                 byteTotal += byteLength;
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
 
 | 
						|
             if (byteTotal > byteAllowed) {
 | 
						|
                 ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " tried to send too large of a book. Book Size: " + byteTotal + " - Allowed:  "+ byteAllowed + " - Pages: " + pageList.size());
 | 
						|
-                server.scheduleOnMain(() -> this.disconnect("Book too large!"));
 | 
						|
+                server.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;
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
     public void handleMovePlayer(ServerboundMovePlayerPacket packet) {
 | 
						|
         PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
 | 
						|
         if (ServerGamePacketListenerImpl.containsInvalidValues(packet.getX(0.0D), packet.getY(0.0D), packet.getZ(0.0D), packet.getYRot(0.0F), packet.getXRot(0.0F))) {
 | 
						|
-            this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"));
 | 
						|
+            this.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_movement"), org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PLAYER_MOVEMENT); // Paper - kick event cause
 | 
						|
         } else {
 | 
						|
             ServerLevel worldserver = this.player.getLevel();
 | 
						|
 
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
                         this.dropCount++;
 | 
						|
                         if (this.dropCount >= 20) {
 | 
						|
                             ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " 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;
 | 
						|
                         }
 | 
						|
                     }
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
 | 
						|
         if (packet.getAction() == ServerboundResourcePackPacket.Action.DECLINED && this.server.isResourcePackRequired()) {
 | 
						|
             ServerGamePacketListenerImpl.LOGGER.info("Disconnecting {} due to resource pack rejection", this.player.getName());
 | 
						|
-            this.disconnect(Component.translatable("multiplayer.requiredTexturePrompt.disconnect"));
 | 
						|
+            this.disconnect(Component.translatable("multiplayer.requiredTexturePrompt.disconnect"), org.bukkit.event.player.PlayerKickEvent.Cause.RESOURCE_PACK_REJECTION); // Paper - add cause
 | 
						|
         }
 | 
						|
         // Paper start
 | 
						|
         PlayerResourcePackStatusEvent.Status packStatus = PlayerResourcePackStatusEvent.Status.values()[packet.action.ordinal()];
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
             this.player.resetLastActionTime();
 | 
						|
         } else {
 | 
						|
             ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().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
 | 
						|
         }
 | 
						|
     }
 | 
						|
 
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         }
 | 
						|
         // CraftBukkit end
 | 
						|
         if (ServerGamePacketListenerImpl.isChatMessageIllegal(packet.message())) {
 | 
						|
-            this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"));
 | 
						|
+            this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - add cause
 | 
						|
         } else {
 | 
						|
             Optional<LastSeenMessages> optional = this.tryHandleChat(packet.message(), packet.timeStamp(), packet.lastSeenMessages());
 | 
						|
 
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
     @Override
 | 
						|
     public void handleChatCommand(ServerboundChatCommandPacket packet) {
 | 
						|
         if (ServerGamePacketListenerImpl.isChatMessageIllegal(packet.command())) {
 | 
						|
-            this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"));
 | 
						|
+            this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper
 | 
						|
         } else {
 | 
						|
             Optional<LastSeenMessages> optional = this.tryHandleChat(packet.command(), packet.timeStamp(), packet.lastSeenMessages());
 | 
						|
 
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
 
 | 
						|
     private void handleMessageDecodeFailure(SignedMessageChain.DecodeException exception) {
 | 
						|
         if (exception.shouldDisconnect()) {
 | 
						|
-            this.disconnect(exception.getComponent());
 | 
						|
+            this.disconnect(exception.getComponent(), exception.kickCause); // Paper - kick event causes
 | 
						|
         } else {
 | 
						|
             this.player.sendSystemMessage(exception.getComponent().copy().withStyle(ChatFormatting.RED));
 | 
						|
         }
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
     private Optional<LastSeenMessages> tryHandleChat(String message, Instant timestamp, LastSeenMessages.Update acknowledgment) {
 | 
						|
         if (!this.updateChatOrder(timestamp)) {
 | 
						|
             ServerGamePacketListenerImpl.LOGGER.warn("{} sent out-of-order chat: '{}'", this.player.getName().getString(), message);
 | 
						|
-            this.disconnect(Component.translatable("multiplayer.disconnect.out_of_order_chat"));
 | 
						|
+            this.disconnect(Component.translatable("multiplayer.disconnect.out_of_order_chat"), org.bukkit.event.player.PlayerKickEvent.Cause.OUT_OF_ORDER_CHAT); // Paper - kick event ca
 | 
						|
             return Optional.empty();
 | 
						|
         } else if (this.player.isRemoved() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { // CraftBukkit - dead men tell no tales
 | 
						|
             this.send(new ClientboundSystemChatPacket(Component.translatable("chat.disabled.options").withStyle(ChatFormatting.RED), false));
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
 
 | 
						|
             if (optional.isEmpty()) {
 | 
						|
                 ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString());
 | 
						|
-                this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED);
 | 
						|
+                this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes
 | 
						|
             }
 | 
						|
 
 | 
						|
             return optional;
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         // this.chatSpamTickCount += 20;
 | 
						|
         if (this.chatSpamTickCount.addAndGet(20) > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) {
 | 
						|
             // CraftBukkit end
 | 
						|
-            this.disconnect(Component.translatable("disconnect.spam"));
 | 
						|
+            this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause
 | 
						|
         }
 | 
						|
 
 | 
						|
     }
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         synchronized (this.lastSeenMessages) {
 | 
						|
             if (!this.lastSeenMessages.applyOffset(packet.offset())) {
 | 
						|
                 ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString());
 | 
						|
-                this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED);
 | 
						|
+                this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes
 | 
						|
             }
 | 
						|
 
 | 
						|
         }
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
             }
 | 
						|
 
 | 
						|
             if (i > 4096) {
 | 
						|
-                this.disconnect(Component.translatable("multiplayer.disconnect.too_many_pending_chats"));
 | 
						|
+                this.disconnect(Component.translatable("multiplayer.disconnect.too_many_pending_chats"), org.bukkit.event.player.PlayerKickEvent.Cause.TOO_MANY_PENDING_CHATS); // Paper - kick event cause
 | 
						|
             }
 | 
						|
 
 | 
						|
         }
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         // Spigot Start
 | 
						|
         if ( entity == this.player && !this.player.isSpectator() )
 | 
						|
         {
 | 
						|
-            this.disconnect( "Cannot interact with self!" );
 | 
						|
+            this.disconnect( "Cannot interact with self!", org.bukkit.event.player.PlayerKickEvent.Cause.SELF_INTERACTION ); // Paper - add cause
 | 
						|
             return;
 | 
						|
         }
 | 
						|
         // Spigot End
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
                                 // CraftBukkit end
 | 
						|
                             }
 | 
						|
                         } else {
 | 
						|
-                            ServerGamePacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.invalid_entity_attacked"));
 | 
						|
+                            ServerGamePacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.invalid_entity_attacked"),  org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_ENTITY_ATTACKED); // Paper - add cause
 | 
						|
                             ServerGamePacketListenerImpl.LOGGER.warn("Player {} tried to attack an invalid entity", ServerGamePacketListenerImpl.this.player.getName().getString());
 | 
						|
                         }
 | 
						|
                     }
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         // Paper start
 | 
						|
         if (!org.bukkit.Bukkit.isPrimaryThread()) {
 | 
						|
             if (recipeSpamPackets.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit) {
 | 
						|
-                server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", new Object[0]))); // Paper
 | 
						|
+                server.scheduleOnMain(() -> this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause
 | 
						|
                 return;
 | 
						|
             }
 | 
						|
         }
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
         } else if (!this.isSingleplayerOwner()) {
 | 
						|
             // Paper start - This needs to be handled on the main thread for plugins
 | 
						|
             server.submit(() -> {
 | 
						|
-            this.disconnect(Component.translatable("disconnect.timeout"));
 | 
						|
+            this.disconnect(Component.translatable("disconnect.timeout"), org.bukkit.event.player.PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause
 | 
						|
             });
 | 
						|
             // Paper end
 | 
						|
         }
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
                 }
 | 
						|
             } catch (Exception ex) {
 | 
						|
                 ServerGamePacketListenerImpl.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 (packet.identifier.equals(CUSTOM_UNREGISTER)) {
 | 
						|
             try {
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
                 }
 | 
						|
             } catch (Exception ex) {
 | 
						|
                 ServerGamePacketListenerImpl.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 {
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
                 this.cserver.getMessenger().dispatchIncomingMessage(this.player.getBukkitEntity(), packet.identifier.toString(), data);
 | 
						|
             } catch (Exception ex) {
 | 
						|
                 ServerGamePacketListenerImpl.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
 | 
						|
             }
 | 
						|
         }
 | 
						|
 
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
 
 | 
						|
         if (!Objects.equals(profilepublickey_a, profilepublickey_a1)) {
 | 
						|
             if (profilepublickey_a != null && profilepublickey_a1.expiresAt().isBefore(profilepublickey_a.expiresAt())) {
 | 
						|
-                this.disconnect(ProfilePublicKey.EXPIRED_PROFILE_PUBLIC_KEY);
 | 
						|
+                this.disconnect(ProfilePublicKey.EXPIRED_PROFILE_PUBLIC_KEY, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes
 | 
						|
             } else {
 | 
						|
                 try {
 | 
						|
                     SignatureValidator signaturevalidator = this.server.getServiceSignatureValidator();
 | 
						|
@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
 | 
						|
                     this.resetPlayerChatState(remotechatsession_a.validate(this.player.getGameProfile(), signaturevalidator, Duration.ZERO));
 | 
						|
                 } catch (ProfilePublicKey.ValidationException profilepublickey_b) {
 | 
						|
                     ServerGamePacketListenerImpl.LOGGER.error("Failed to validate profile key: {}", profilepublickey_b.getMessage());
 | 
						|
-                    this.disconnect(profilepublickey_b.getComponent());
 | 
						|
+                    this.disconnect(profilepublickey_b.getComponent(), profilepublickey_b.kickCause); // Paper - kick event causes
 | 
						|
                 }
 | 
						|
 
 | 
						|
             }
 | 
						|
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
 | 
						|
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
 | 
						|
@@ -0,0 +0,0 @@ public abstract class PlayerList {
 | 
						|
         while (iterator.hasNext()) {
 | 
						|
             entityplayer = (ServerPlayer) iterator.next();
 | 
						|
             this.save(entityplayer); // CraftBukkit - Force the player's inventory to be saved
 | 
						|
-            entityplayer.connection.disconnect(Component.translatable("multiplayer.disconnect.duplicate_login"));
 | 
						|
+            entityplayer.connection.disconnect(Component.translatable("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
 | 
						|
@@ -0,0 +0,0 @@ public abstract class PlayerList {
 | 
						|
         // Paper end
 | 
						|
         // CraftBukkit start - disconnect safely
 | 
						|
         for (ServerPlayer player : this.players) {
 | 
						|
-            if (isRestarting) player.connection.disconnect(org.spigotmc.SpigotConfig.restartMessage); else // Paper
 | 
						|
-            player.connection.disconnect(this.server.server.shutdownMessage()); // CraftBukkit - add custom shutdown message // Paper - Adventure
 | 
						|
+            if (isRestarting) player.connection.disconnect(org.spigotmc.SpigotConfig.restartMessage, org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); else // Paper - kick event cause (cause is never used here)
 | 
						|
+            player.connection.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/net/minecraft/world/entity/player/ProfilePublicKey.java b/src/main/java/net/minecraft/world/entity/player/ProfilePublicKey.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/net/minecraft/world/entity/player/ProfilePublicKey.java
 | 
						|
+++ b/src/main/java/net/minecraft/world/entity/player/ProfilePublicKey.java
 | 
						|
@@ -0,0 +0,0 @@ public record ProfilePublicKey(ProfilePublicKey.Data data) {
 | 
						|
 
 | 
						|
     public static ProfilePublicKey createValidated(SignatureValidator servicesSignatureVerifier, UUID playerUuid, ProfilePublicKey.Data publicKeyData, Duration gracePeriod) throws ProfilePublicKey.ValidationException {
 | 
						|
         if (publicKeyData.hasExpired(gracePeriod)) {
 | 
						|
-            throw new ProfilePublicKey.ValidationException(EXPIRED_PROFILE_PUBLIC_KEY);
 | 
						|
+            throw new ProfilePublicKey.ValidationException(EXPIRED_PROFILE_PUBLIC_KEY, org.bukkit.event.player.PlayerKickEvent.Cause.EXPIRED_PROFILE_PUBLIC_KEY); // Paper - kick event causes
 | 
						|
         } else if (!publicKeyData.validateSignature(servicesSignatureVerifier, playerUuid)) {
 | 
						|
-            throw new ProfilePublicKey.ValidationException(INVALID_SIGNATURE);
 | 
						|
+            throw new ProfilePublicKey.ValidationException(INVALID_SIGNATURE, org.bukkit.event.player.PlayerKickEvent.Cause.INVALID_PUBLIC_KEY_SIGNATURE); // Paper - kick event causes
 | 
						|
         } else {
 | 
						|
             return new ProfilePublicKey(publicKeyData);
 | 
						|
         }
 | 
						|
@@ -0,0 +0,0 @@ public record ProfilePublicKey(ProfilePublicKey.Data data) {
 | 
						|
     }
 | 
						|
 
 | 
						|
     public static class ValidationException extends ThrowingComponent {
 | 
						|
+        public final org.bukkit.event.player.PlayerKickEvent.Cause kickCause; // Paper
 | 
						|
+        @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper
 | 
						|
         public ValidationException(Component messageText) {
 | 
						|
+            // Paper start
 | 
						|
+            this(messageText, org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN);
 | 
						|
+        }
 | 
						|
+        public ValidationException(Component messageText, org.bukkit.event.player.PlayerKickEvent.Cause kickCause) {
 | 
						|
+            // Paper end
 | 
						|
             super(messageText);
 | 
						|
+            this.kickCause = kickCause; // Paper
 | 
						|
         }
 | 
						|
     }
 | 
						|
 }
 | 
						|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
 | 
						|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
 | 
						|
@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
 | 
						|
         org.spigotmc.AsyncCatcher.catchOp("player kick"); // Spigot
 | 
						|
         if (this.getHandle().connection == null) return;
 | 
						|
 
 | 
						|
-        this.getHandle().connection.disconnect(message == null ? "" : message);
 | 
						|
+        this.getHandle().connection.disconnect(message == null ? "" : message, org.bukkit.event.player.PlayerKickEvent.Cause.PLUGIN); // Paper - kick event cause
 | 
						|
     }
 | 
						|
 
 | 
						|
     // Paper start
 | 
						|
@@ -0,0 +0,0 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
 | 
						|
 
 | 
						|
     @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 ServerGamePacketListenerImpl connection = this.getHandle().connection;
 | 
						|
         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);
 | 
						|
         }
 | 
						|
     }
 | 
						|
 
 | 
						|
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
 | 
						|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
 | 
						|
--- a/src/main/java/org/spigotmc/RestartCommand.java
 | 
						|
+++ b/src/main/java/org/spigotmc/RestartCommand.java
 | 
						|
@@ -0,0 +0,0 @@ public class RestartCommand extends Command
 | 
						|
             // Kick all players
 | 
						|
             for ( ServerPlayer p : com.google.common.collect.ImmutableList.copyOf( MinecraftServer.getServer().getPlayerList().players ) )
 | 
						|
             {
 | 
						|
-                p.connection.disconnect(SpigotConfig.restartMessage);
 | 
						|
+                p.connection.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
 |