From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sat, 15 May 2021 10:04:43 -0700
Subject: [PATCH] additions to PlayerGameModeChangeEvent


diff --git a/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java b/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java
index c0098a8f8a9fa2671ff66cbcf50ac74b057d1446..ebbd6f2b0e7236b33d136ab2218c8eca4c5df03e 100644
--- a/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java
+++ b/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java
@@ -43,7 +43,13 @@ public class DefaultGameModeCommands {
                 ServerPlayer entityplayer = (ServerPlayer) iterator.next();
 
                 if (entityplayer.gameMode.getGameModeForPlayer() != defaultGameMode) {
-                    entityplayer.setGameMode(defaultGameMode);
+                    // Paper start - handle event cancelling the change
+                    org.bukkit.event.player.PlayerGameModeChangeEvent event = entityplayer.setGamemode(defaultGameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, net.kyori.adventure.text.Component.text("Failed to set the gamemode of '" + entityplayer.getScoreboardName() + "'", net.kyori.adventure.text.format.NamedTextColor.RED));
+                    if (event != null && event.isCancelled()) {
+                        source.sendSuccess(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), false);
+                        continue;
+                    }
+                    // Paper end
                     ++i;
                 }
             }
diff --git a/src/main/java/net/minecraft/server/commands/GameModeCommand.java b/src/main/java/net/minecraft/server/commands/GameModeCommand.java
index 3e999090fb3b03b996a9790c53e5b4618c8891f7..3b17c81167f8e011e7f9c09bf42eb632f5a3c2f2 100644
--- a/src/main/java/net/minecraft/server/commands/GameModeCommand.java
+++ b/src/main/java/net/minecraft/server/commands/GameModeCommand.java
@@ -62,13 +62,13 @@ public class GameModeCommand {
             ServerPlayer entityplayer = (ServerPlayer) iterator.next();
 
             if (entityplayer.gameMode.getGameModeForPlayer() != gameMode) {
-                entityplayer.setGameMode(gameMode);
-                // CraftBukkit start - handle event cancelling the change
-                if (entityplayer.gameMode.getGameModeForPlayer() != gameMode) {
-                    context.getSource().sendFailure(new net.minecraft.network.chat.TextComponent("Failed to set the gamemode of '" + entityplayer.getScoreboardName() + "'"));
+                // Paper start - handle event cancelling the change
+                org.bukkit.event.player.PlayerGameModeChangeEvent event = entityplayer.setGamemode(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.COMMAND, net.kyori.adventure.text.Component.text("Failed to set the gamemode of '" + entityplayer.getScoreboardName() + "'", net.kyori.adventure.text.format.NamedTextColor.RED));
+                if (event != null && event.isCancelled()) {
+                    context.getSource().sendSuccess(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), false);
                     continue;
                 }
-                // CraftBukkit end
+                // Paper end
                 logGamemodeChange((CommandSourceStack) context.getSource(), entityplayer, gameMode);
                 ++i;
             }
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 5d710a1f4e0c61d4be6efe8cebd9b80789868338..779b926921fd435620cbbc69ed6f9931a422b652 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -393,7 +393,16 @@ public class ServerPlayer extends Player implements ContainerListener {
         if (this.getY() > 300) this.setPosRaw(getX(), 257, getZ()); // Paper - bring down to a saner Y level if out of world
         if (tag.contains("playerGameType", 99)) {
             if (this.getServer().getForceGameType()) {
+                // Paper start - call PlayerGameModeChangeEvent on join for players that do not have the correct gamemode
+                if (this.getServer().getDefaultGameType() != GameType.byId(tag.getInt("playerGameType"))) {
+                    if (new org.bukkit.event.player.PlayerGameModeChangeEvent(this.getBukkitEntity(), GameMode.getByValue(this.getServer().getDefaultGameType().getId()), org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null).callEvent()) {
                 this.gameMode.setGameModeForPlayer(this.getServer().getDefaultGameType(), GameType.NOT_SET);
+                    } else {
+                        this.gameMode.setGameModeForPlayer(GameType.byId(tag.getInt("playerGameType")), tag.contains("previousPlayerGameType", 3) ? GameType.byId(tag.getInt("previousPlayerGameType")) : GameType.NOT_SET); // copied from below; if cancelled, set gamemode normally
+                    }
+                } else {
+                    this.gameMode.setGameModeForPlayer(GameType.byId(tag.getInt("playerGameType")), tag.contains("previousPlayerGameType", 3) ? GameType.byId(tag.getInt("previousPlayerGameType")) : GameType.NOT_SET); // copied from below; if no change needed, set gamemode normally
+                } // Paper end
             } else {
                 this.gameMode.setGameModeForPlayer(GameType.byId(tag.getInt("playerGameType")), tag.contains("previousPlayerGameType", 3) ? GameType.byId(tag.getInt("previousPlayerGameType")) : GameType.NOT_SET);
             }
@@ -1789,21 +1798,27 @@ public class ServerPlayer extends Player implements ContainerListener {
 
     @Override
     public void setGameMode(GameType gameMode) {
+        // Paper start - Add cause and nullable message to event
+        setGamemode(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.UNKNOWN, null);
+    }
+
+    public PlayerGameModeChangeEvent setGamemode(GameType enumgamemode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause cause, net.kyori.adventure.text.Component message) {
+        // Paper end
         // CraftBukkit start
-        if (gameMode == this.gameMode.getGameModeForPlayer()) {
-            return;
+        if (enumgamemode == this.gameMode.getGameModeForPlayer()) {
+            return null; // Paper
         }
 
-        PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(getBukkitEntity(), GameMode.getByValue(gameMode.getId()));
+        PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(getBukkitEntity(), GameMode.getByValue(enumgamemode.getId()), cause, message); // Paper
         level.getCraftServer().getPluginManager().callEvent(event);
         if (event.isCancelled()) {
-            return;
+            return event; // Paper
         }
         // CraftBukkit end
 
-        this.gameMode.setGameModeForPlayer(gameMode);
-        this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, (float) gameMode.getId()));
-        if (gameMode == GameType.SPECTATOR) {
+        this.gameMode.setGameModeForPlayer(enumgamemode);
+        this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, (float) enumgamemode.getId()));
+        if (enumgamemode == GameType.SPECTATOR) {
             this.removeEntitiesOnShoulder();
             this.stopRiding();
         } else {
@@ -1812,6 +1827,7 @@ public class ServerPlayer extends Player implements ContainerListener {
 
         this.onUpdateAbilities();
         this.updateEffectVisibility();
+        return event; // Paper
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index a0e69cac7699ddc318057c8016e329850d3baa26..c454908f23a436f66f8e64fc346186f113b6eefb 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2449,7 +2449,7 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
 
                     this.player = this.server.getPlayerList().respawn(this.player, false);
                     if (this.server.isHardcore()) {
-                        this.player.setGameMode(GameType.SPECTATOR);
+                        this.player.setGamemode(GameType.SPECTATOR, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.HARDCORE_DEATH, null); // Paper
                         ((GameRules.BooleanValue) this.player.getLevel().getGameRules().getRule(GameRules.RULE_SPECTATORSGENERATECHUNKS)).set(false, this.server);
                     }
                 }
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index ec8c7499662c0a810f1337ebc0fa24d2f3ca79e7..3dbe94d9b9647f5cc1e27335b36042e50c652cea 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1189,7 +1189,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
             throw new IllegalArgumentException("Mode cannot be null");
         }
 
-        getHandle().setGameMode(GameType.byId(mode.getValue()));
+        getHandle().setGamemode(GameType.byId(mode.getValue()), org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.PLUGIN, null); // Paper
     }
 
     @Override