diff --git a/Spigot-Server-Patches/Call-player-spectator-target-events-and-improve-impl.patch b/Spigot-Server-Patches/Call-player-spectator-target-events-and-improve-impl.patch new file mode 100644 index 0000000000..6bb2fe43d0 --- /dev/null +++ b/Spigot-Server-Patches/Call-player-spectator-target-events-and-improve-impl.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Caleb Bassham +Date: Fri, 28 Sep 2018 02:32:19 -0500 +Subject: [PATCH] Call player spectator target events and improve + implementation + +Use a proper teleport for teleporting to entities in different +worlds. + +Implementation improvements authored by Spottedleaf +Validate that the target entity is valid and deny spectate +requests from frozen players. + +Also, make sure the entity is spawned to the client before +sending the camera packet. If the entity isn't spawned clientside +when it receives the camera packet, then the client will not +spectate the target entity. + +Co-authored-by: Spottedleaf + +diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/EntityPlayer.java ++++ b/src/main/java/net/minecraft/server/EntityPlayer.java +@@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting { + return (Entity) (this.spectatedEntity == null ? this : this.spectatedEntity); + } + +- public void setSpectatorTarget(Entity entity) { ++ public void setSpectatorTarget(Entity newSpectatorTarget) { ++ // Paper start - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity Event and improve implementation + Entity entity1 = this.getSpecatorTarget(); + +- this.spectatedEntity = (Entity) (entity == null ? this : entity); +- if (entity1 != this.spectatedEntity) { +- this.playerConnection.sendPacket(new PacketPlayOutCamera(this.spectatedEntity)); +- this.playerConnection.a(this.spectatedEntity.locX(), this.spectatedEntity.locY(), this.spectatedEntity.locZ(), this.yaw, this.pitch, TeleportCause.SPECTATE); // CraftBukkit ++ if (newSpectatorTarget == null) { ++ newSpectatorTarget = this; + } + ++ if (entity1 == newSpectatorTarget) return; // new spec target is the current spec target ++ ++ if (newSpectatorTarget == this) { ++ com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent playerStopSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent(this.getBukkitEntity(), entity1.getBukkitEntity()); ++ ++ if (!playerStopSpectatingEntityEvent.callEvent()) { ++ return; ++ } ++ } else { ++ com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent playerStartSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent(this.getBukkitEntity(), entity1.getBukkitEntity(), newSpectatorTarget.getBukkitEntity()); ++ ++ if (!playerStartSpectatingEntityEvent.callEvent()) { ++ return; ++ } ++ } ++ // Validate ++ if (newSpectatorTarget != this) { ++ if (newSpectatorTarget.dead || newSpectatorTarget.shouldBeRemoved || !newSpectatorTarget.valid || newSpectatorTarget.world == null) { ++ MinecraftServer.LOGGER.info("Blocking player " + this.toString() + " from spectating invalid entity " + newSpectatorTarget.toString()); ++ return; ++ } ++ if (this.isFrozen()) { ++ // use debug: clients might maliciously spam this ++ MinecraftServer.LOGGER.debug("Blocking frozen player " + this.toString() + " from spectating entity " + newSpectatorTarget.toString()); ++ return; ++ } ++ } ++ ++ this.spectatedEntity = newSpectatorTarget; // only set after validating state ++ ++ if (newSpectatorTarget != this) { ++ // Make sure we're in the right place ++ this.ejectPassengers(); // teleport can fail if we have passengers... ++ this.getBukkitEntity().teleport(new Location(newSpectatorTarget.getWorld().getWorld(), newSpectatorTarget.locX(), newSpectatorTarget.locY(), newSpectatorTarget.locZ(), this.yaw, this.pitch), TeleportCause.SPECTATE); // Correctly handle cross-world entities from api calls by using CB teleport ++ ++ // Make sure we're tracking the entity before sending ++ PlayerChunkMap.EntityTracker tracker = ((WorldServer)newSpectatorTarget.world).getChunkProvider().playerChunkMap.trackedEntities.get(newSpectatorTarget.getId()); ++ if (tracker != null) { // dumb plugins... ++ tracker.updatePlayer(this); ++ } ++ } else { ++ this.playerConnection.teleport(this.spectatedEntity.locX(), this.spectatedEntity.locY(), this.spectatedEntity.locZ(), this.yaw, this.pitch, TeleportCause.SPECTATE); // CraftBukkit ++ } ++ this.playerConnection.sendPacket(new PacketPlayOutCamera(newSpectatorTarget)); ++ // Paper end + } + + @Override +diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/PlayerConnection.java ++++ b/src/main/java/net/minecraft/server/PlayerConnection.java +@@ -0,0 +0,0 @@ public class PlayerConnection implements PacketListenerPlayIn { + } + + // CraftBukkit start - Delegate to teleport(Location) ++ public final void teleport(double d0, double d1, double d2, float f, float f1, PlayerTeleportEvent.TeleportCause cause) { this.a(d0, d1, d2, f, f1, cause); } // Paper - OBFHELPER + public void a(double d0, double d1, double d2, float f, float f1, PlayerTeleportEvent.TeleportCause cause) { + this.a(d0, d1, d2, f, f1, Collections.emptySet(), cause); + } diff --git a/Spigot-Server-Patches/Call-player-spectator-target-events.patch b/Spigot-Server-Patches/Call-player-spectator-target-events.patch deleted file mode 100644 index 6d3b557c61..0000000000 --- a/Spigot-Server-Patches/Call-player-spectator-target-events.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Caleb Bassham -Date: Fri, 28 Sep 2018 02:32:19 -0500 -Subject: [PATCH] Call player spectator target events - - -diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/EntityPlayer.java -+++ b/src/main/java/net/minecraft/server/EntityPlayer.java -@@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting { - private EnumChatVisibility ch; - private boolean ci = true; - private long cj = SystemUtils.getMonotonicMillis(); -- private Entity spectatedEntity; -+ private Entity spectatedEntity; private void setSpectatorTargetField(Entity e) { this.spectatedEntity = e; } // Paper - OBFHELPER - public boolean worldChangeInvuln; - private boolean cm; private void setHasSeenCredits(boolean has) { this.cm = has; } // Paper - OBFHELPER - private final RecipeBookServer recipeBook; -@@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting { - return (Entity) (this.spectatedEntity == null ? this : this.spectatedEntity); - } - -- public void setSpectatorTarget(Entity entity) { -+ public void setSpectatorTarget(Entity newSpectatorTarget) { -+ // Paper start - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity Event - Entity entity1 = this.getSpecatorTarget(); - -- this.spectatedEntity = (Entity) (entity == null ? this : entity); -- if (entity1 != this.spectatedEntity) { -- this.playerConnection.sendPacket(new PacketPlayOutCamera(this.spectatedEntity)); -- this.playerConnection.a(this.spectatedEntity.locX(), this.spectatedEntity.locY(), this.spectatedEntity.locZ(), this.yaw, this.pitch, TeleportCause.SPECTATE); // CraftBukkit -+ if (newSpectatorTarget == null) { -+ newSpectatorTarget = this; - } - -+ if (entity1 == newSpectatorTarget) return; // new spec target is the current spec target -+ -+ if (newSpectatorTarget == this) { -+ com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent playerStopSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent(this.getBukkitEntity(), entity1.getBukkitEntity()); -+ -+ if (!playerStopSpectatingEntityEvent.callEvent()) { -+ return; -+ } -+ } else { -+ com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent playerStartSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent(this.getBukkitEntity(), entity1.getBukkitEntity(), newSpectatorTarget.getBukkitEntity()); -+ -+ if (!playerStartSpectatingEntityEvent.callEvent()) { -+ return; -+ } -+ } -+ -+ setSpectatorTargetField(newSpectatorTarget); -+ -+ this.playerConnection.sendPacket(new PacketPlayOutCamera(newSpectatorTarget)); -+ this.playerConnection.a(this.spectatedEntity.locX(), this.spectatedEntity.locY(), this.spectatedEntity.locZ(), this.yaw, this.pitch, TeleportCause.SPECTATE); // CraftBukkit -+ // Paper end - } - - @Override -@@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting { - if (this.portalCooldown > 0 && !this.worldChangeInvuln) { - --this.portalCooldown; - } -- - } - - @Override diff --git a/Spigot-Server-Patches/Implement-Player-Client-Options-API.patch b/Spigot-Server-Patches/Implement-Player-Client-Options-API.patch index 3b1c632645..c2a4a04419 100644 --- a/Spigot-Server-Patches/Implement-Player-Client-Options-API.patch +++ b/Spigot-Server-Patches/Implement-Player-Client-Options-API.patch @@ -116,7 +116,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - private boolean ci = true; + private boolean ci = true; public boolean hasChatColorsEnabled() { return this.ci; } // Paper - OBFHELPER private long cj = SystemUtils.getMonotonicMillis(); - private Entity spectatedEntity; private void setSpectatorTargetField(Entity e) { this.spectatedEntity = e; } // Paper - OBFHELPER + private Entity spectatedEntity; public boolean worldChangeInvuln; @@ -0,0 +0,0 @@ public class EntityPlayer extends EntityHuman implements ICrafting { }