88 lines
4.3 KiB
Diff
88 lines
4.3 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 56b1c585d1c330bf9b904ebf8ef0b8be47102aa3..e4f991578d4ee581e65f2edb7d32640ff36a01bd 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
@@ -1875,14 +1875,58 @@ public class ServerPlayer extends Player {
|
|
}
|
|
|
|
public void setCamera(@Nullable 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.teleport(this.camera.getX(), this.camera.getY(), this.camera.getZ(), this.getYRot(), this.getXRot(), 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.isRemoved() || !entity.valid || entity.level == null) {
|
|
+ MinecraftServer.LOGGER.info("Blocking player " + this + " from spectating invalid entity " + entity);
|
|
+ return;
|
|
+ }
|
|
+ if (this.isImmobile()) {
|
|
+ // use debug: clients might maliciously spam this
|
|
+ MinecraftServer.LOGGER.debug("Blocking frozen player " + this + " from spectating entity " + entity);
|
|
+ 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.getYRot(), this.getXRot()), 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.getYRot(), this.getXRot(), TeleportCause.SPECTATE); // CraftBukkit
|
|
+ }
|
|
+ this.connection.send(new ClientboundSetCameraPacket(entity));
|
|
+ // Paper end
|
|
}
|
|
|
|
@Override
|