100 lines
5.4 KiB
Diff
100 lines
5.4 KiB
Diff
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
|
From: Caleb Bassham <caleb.bassham@gmail.com>
|
||
|
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 <Spottedleaf@users.noreply.github.com>
|
||
|
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 <Spottedleaf@users.noreply.github.com>
|
||
|
|
||
|
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||
|
index 75419c866641ab654349cde6ca3fbdef701dd8d9..92139b271eb6c305787662ef8c7d221fb42296f7 100644
|
||
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||
|
@@ -1818,14 +1818,58 @@ public class ServerPlayer extends Player implements ContainerListener {
|
||
|
}
|
||
|
|
||
|
public void setCamera(Entity entity) {
|
||
|
+ // Paper start - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity Event and improve implementation
|
||
|
Entity entity1 = this.getCamera();
|
||
|
|
||
|
- this.camera = (Entity) (entity == null ? this : entity);
|
||
|
- if (entity1 != this.camera) {
|
||
|
- this.connection.send(new ClientboundSetCameraPacket(this.camera));
|
||
|
- this.connection.a(this.camera.getX(), this.camera.getY(), this.camera.getZ(), this.yRot, this.xRot, TeleportCause.SPECTATE); // CraftBukkit
|
||
|
+ if (entity == null) {
|
||
|
+ entity = this;
|
||
|
}
|
||
|
|
||
|
+ if (entity1 == entity) return; // new spec target is the current spec target
|
||
|
+
|
||
|
+ if (entity == 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(), entity.getBukkitEntity());
|
||
|
+
|
||
|
+ if (!playerStartSpectatingEntityEvent.callEvent()) {
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ // Validate
|
||
|
+ if (entity != this) {
|
||
|
+ if (entity.removed || entity.shouldBeRemoved || !entity.valid || entity.level == null) {
|
||
|
+ MinecraftServer.LOGGER.info("Blocking player " + this.toString() + " from spectating invalid entity " + entity.toString());
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ if (this.isImmobile()) {
|
||
|
+ // use debug: clients might maliciously spam this
|
||
|
+ MinecraftServer.LOGGER.debug("Blocking frozen player " + this.toString() + " from spectating entity " + entity.toString());
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ this.camera = entity; // only set after validating state
|
||
|
+
|
||
|
+ if (entity != this) {
|
||
|
+ // Make sure we're in the right place
|
||
|
+ this.ejectPassengers(); // teleport can fail if we have passengers...
|
||
|
+ this.getBukkitEntity().teleport(new Location(entity.getCommandSenderWorld().getWorld(), entity.getX(), entity.getY(), entity.getZ(), this.yRot, this.xRot), TeleportCause.SPECTATE); // Correctly handle cross-world entities from api calls by using CB teleport
|
||
|
+
|
||
|
+ // Make sure we're tracking the entity before sending
|
||
|
+ ChunkMap.TrackedEntity tracker = ((ServerLevel)entity.level).getChunkSource().chunkMap.entityMap.get(entity.getId());
|
||
|
+ if (tracker != null) { // dumb plugins...
|
||
|
+ tracker.updatePlayer(this);
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ this.connection.teleport(this.camera.getX(), this.camera.getY(), this.camera.getZ(), this.yRot, this.xRot, TeleportCause.SPECTATE); // CraftBukkit
|
||
|
+ }
|
||
|
+ this.connection.send(new ClientboundSetCameraPacket(entity));
|
||
|
+ // Paper end
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||
|
index 900c9b1106a153bc386f6c3d9c11226f8ac69f86..4fd8d775790c037e82f9b0d29ed0eccf03c2dc66 100644
|
||
|
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||
|
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||
|
@@ -1353,6 +1353,7 @@ public class ServerGamePacketListenerImpl implements ServerGamePacketListener {
|
||
|
}
|
||
|
|
||
|
// 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.<ClientboundPlayerPositionPacket.RelativeArgument>emptySet(), cause);
|
||
|
}
|