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/CommandGamemode.java b/src/main/java/net/minecraft/server/commands/CommandGamemode.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/commands/CommandGamemode.java
+++ b/src/main/java/net/minecraft/server/commands/CommandGamemode.java
@@ -0,0 +0,0 @@ public class CommandGamemode {
             EntityPlayer entityplayer = (EntityPlayer) iterator.next();
 
             if (entityplayer.playerInteractManager.getGameMode() != enumgamemode) {
-                entityplayer.a(enumgamemode);
-                // CraftBukkit start - handle event cancelling the change
-                if (entityplayer.playerInteractManager.getGameMode() != enumgamemode) {
-                    commandcontext.getSource().sendFailureMessage(new net.minecraft.network.chat.ChatComponentText("Failed to set the gamemode of '" + entityplayer.getName() + "'"));
+                // Paper start - handle event cancelling the change
+                org.bukkit.event.player.PlayerGameModeChangeEvent event = entityplayer.setGamemode(enumgamemode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.COMMAND, net.kyori.adventure.text.Component.text("Failed to set the gamemode of '" + entityplayer.getName() + "'", net.kyori.adventure.text.format.NamedTextColor.RED));
+                if (event != null && event.isCancelled()) {
+                    commandcontext.getSource().sendMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), false);
                     continue;
                 }
-                // CraftBukkit end
+                // Paper end
                 a((CommandListenerWrapper) commandcontext.getSource(), entityplayer, enumgamemode);
                 ++i;
             }
diff --git a/src/main/java/net/minecraft/server/commands/CommandGamemodeDefault.java b/src/main/java/net/minecraft/server/commands/CommandGamemodeDefault.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/commands/CommandGamemodeDefault.java
+++ b/src/main/java/net/minecraft/server/commands/CommandGamemodeDefault.java
@@ -0,0 +0,0 @@ public class CommandGamemodeDefault {
                 EntityPlayer entityplayer = (EntityPlayer) iterator.next();
 
                 if (entityplayer.playerInteractManager.getGameMode() != enumgamemode) {
-                    entityplayer.a(enumgamemode);
+                    // Paper start - handle event cancelling the change
+                    org.bukkit.event.player.PlayerGameModeChangeEvent event = entityplayer.setGamemode(enumgamemode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, net.kyori.adventure.text.Component.text("Failed to set the gamemode of '" + entityplayer.getName() + "'", net.kyori.adventure.text.format.NamedTextColor.RED));
+                    if (event != null && event.isCancelled()) {
+                        commandlistenerwrapper.sendMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), false);
+                        continue;
+                    }
+                    // Paper end
                     ++i;
                 }
             }
diff --git a/src/main/java/net/minecraft/server/level/EntityPlayer.java b/src/main/java/net/minecraft/server/level/EntityPlayer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/level/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/level/EntityPlayer.java
@@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
         if (this.locY() > 300) this.setPositionRaw(locX(), 257, locZ()); // Paper - bring down to a saner Y level if out of world
         if (nbttagcompound.hasKeyOfType("playerGameType", 99)) {
             if (this.getMinecraftServer().getForceGamemode()) {
+                // Paper start - call PlayerGameModeChangeEvent on join for players that do not have the correct gamemode
+                if (this.getMinecraftServer().getGamemode() != EnumGamemode.getById(nbttagcompound.getInt("playerGameType"))) {
+                    if (new org.bukkit.event.player.PlayerGameModeChangeEvent(this.getBukkitEntity(), GameMode.getByValue(this.getMinecraftServer().getGamemode().getId()), org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null).callEvent()) {
                 this.playerInteractManager.a(this.getMinecraftServer().getGamemode(), EnumGamemode.NOT_SET);
+                    } else {
+                        this.playerInteractManager.a(EnumGamemode.getById(nbttagcompound.getInt("playerGameType")), nbttagcompound.hasKeyOfType("previousPlayerGameType", 3) ? EnumGamemode.getById(nbttagcompound.getInt("previousPlayerGameType")) : EnumGamemode.NOT_SET); // copied from below; if cancelled, set gamemode normally
+                    }
+                } else {
+                    this.playerInteractManager.a(EnumGamemode.getById(nbttagcompound.getInt("playerGameType")), nbttagcompound.hasKeyOfType("previousPlayerGameType", 3) ? EnumGamemode.getById(nbttagcompound.getInt("previousPlayerGameType")) : EnumGamemode.NOT_SET); // copied from below; if no change needed, set gamemode normally
+                } // Paper end
             } else {
                 this.playerInteractManager.a(EnumGamemode.getById(nbttagcompound.getInt("playerGameType")), nbttagcompound.hasKeyOfType("previousPlayerGameType", 3) ? EnumGamemode.getById(nbttagcompound.getInt("previousPlayerGameType")) : EnumGamemode.NOT_SET);
             }
@@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
 
     @Override
     public void a(EnumGamemode enumgamemode) {
+        // Paper start - Add cause and nullable message to event
+        setGamemode(enumgamemode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.UNKNOWN, null);
+    }
+
+    public PlayerGameModeChangeEvent setGamemode(EnumGamemode enumgamemode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause cause, net.kyori.adventure.text.Component message) {
+        // Paper end
         // CraftBukkit start
         if (enumgamemode == this.playerInteractManager.getGameMode()) {
-            return;
+            return null; // Paper
         }
 
-        PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(getBukkitEntity(), GameMode.getByValue(enumgamemode.getId()));
+        PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(getBukkitEntity(), GameMode.getByValue(enumgamemode.getId()), cause, message); // Paper
         world.getServer().getPluginManager().callEvent(event);
         if (event.isCancelled()) {
-            return;
+            return event; // Paper
         }
         // CraftBukkit end
 
@@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
 
         this.updateAbilities();
         this.dU();
+        return event; // Paper
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/server/network/PlayerConnection.java b/src/main/java/net/minecraft/server/network/PlayerConnection.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/server/network/PlayerConnection.java
+++ b/src/main/java/net/minecraft/server/network/PlayerConnection.java
@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn {
 
                     this.player = this.minecraftServer.getPlayerList().moveToWorld(this.player, false);
                     if (this.minecraftServer.isHardcore()) {
-                        this.player.a(EnumGamemode.SPECTATOR);
+                        this.player.setGamemode(EnumGamemode.SPECTATOR, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.HARDCORE_DEATH, null); // Paper
                         ((GameRules.GameRuleBoolean) this.player.getWorldServer().getGameRules().get(GameRules.SPECTATORS_GENERATE_CHUNKS)).a(false, this.minecraftServer);
                     }
                 }
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 {
             throw new IllegalArgumentException("Mode cannot be null");
         }
 
-        getHandle().a(EnumGamemode.getById(mode.getValue()));
+        getHandle().setGamemode(EnumGamemode.getById(mode.getValue()), org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.PLUGIN, null); // Paper
     }
 
     @Override