2022-07-22 21:36:43 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sun, 5 Sep 2021 12:15:59 -0400
Subject: [PATCH] More Teleport API
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
2024-10-31 17:25:52 +01:00
index bc8f9bd50de3894e6262e13ed55252c98f22ed8a..10f7e45f192ef50b9d9bf5fc83a8090efb2b1042 100644
2022-07-22 21:36:43 +02:00
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
2024-10-31 17:25:52 +01:00
@@ -1585,11 +1585,18 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
2024-06-15 18:28:18 +02:00
return true; // CraftBukkit - Return event status
2022-07-22 21:36:43 +02:00
}
- PlayerTeleportEvent event = new PlayerTeleportEvent(player, from.clone(), to.clone(), cause);
+ // Paper start - Teleport API
2024-10-31 17:25:52 +01:00
+ final Set<io.papermc.paper.entity.TeleportFlag.Relative> relativeFlags = java.util.EnumSet.noneOf(io.papermc.paper.entity.TeleportFlag.Relative.class);
+ for (final Relative relativeArgument : set) {
+ final io.papermc.paper.entity.TeleportFlag.Relative flag = org.bukkit.craftbukkit.entity.CraftPlayer.deltaRelativeToAPI(relativeArgument);
+ if (flag != null) relativeFlags.add(flag);
2022-07-22 21:36:43 +02:00
+ }
2023-03-15 00:10:18 +01:00
+ PlayerTeleportEvent event = new PlayerTeleportEvent(player, from.clone(), to.clone(), cause, java.util.Set.copyOf(relativeFlags));
2024-01-18 15:56:25 +01:00
+ // Paper end - Teleport API
2022-07-22 21:36:43 +02:00
this.cserver.getPluginManager().callEvent(event);
if (event.isCancelled() || !to.equals(event.getTo())) {
2024-08-17 21:39:11 +02:00
- set = Collections.emptySet(); // Can't relative teleport
+ // set = Collections.emptySet(); // Can't relative teleport // Paper - Teleport API; Now you can!
2022-07-22 21:36:43 +02:00
to = event.isCancelled() ? event.getFrom() : event.getTo();
2024-10-23 23:12:09 +02:00
positionmoverotation = new PositionMoveRotation(CraftLocation.toVec3D(to), Vec3.ZERO, to.getYaw(), to.getPitch());
}
2022-07-22 21:36:43 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
2024-11-09 21:17:42 +01:00
index 10fb64df10820974d11f142c102a11a5bd0f317c..8d2f6bb43fb69a4a1e2085960eb24f4397072499 100644
2022-07-22 21:36:43 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
2024-10-23 23:12:09 +02:00
@@ -222,15 +222,36 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
2022-07-22 21:36:43 +02:00
@Override
public boolean teleport(Location location, TeleportCause cause) {
+ // Paper start - Teleport passenger API
2023-03-04 23:07:23 +01:00
+ return teleport(location, cause, new io.papermc.paper.entity.TeleportFlag[0]);
2022-07-22 21:36:43 +02:00
+ }
+
+ @Override
2023-03-04 23:07:23 +01:00
+ public boolean teleport(Location location, TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) {
2022-07-22 21:36:43 +02:00
+ // Paper end
Preconditions.checkArgument(location != null, "location cannot be null");
location.checkFinite();
+ // Paper start - Teleport passenger API
2023-03-04 23:07:23 +01:00
+ Set<io.papermc.paper.entity.TeleportFlag> flagSet = Set.of(flags);
+ boolean dismount = !flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_VEHICLE);
+ boolean ignorePassengers = flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS);
2022-07-22 21:36:43 +02:00
+ // Don't allow teleporting between worlds while keeping passengers
2023-03-04 23:07:23 +01:00
+ if (flagSet.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS) && this.entity.isVehicle() && location.getWorld() != this.getWorld()) {
2022-07-22 21:36:43 +02:00
+ return false;
+ }
2023-03-23 22:57:03 +01:00
+
2022-07-22 21:36:43 +02:00
+ // Don't allow to teleport between worlds if remaining on vehicle
+ if (!dismount && this.entity.isPassenger() && location.getWorld() != this.getWorld()) {
+ return false;
+ }
+ // Paper end
2023-03-23 22:57:03 +01:00
- if (this.entity.isVehicle() || this.entity.isRemoved()) {
2022-07-22 21:36:43 +02:00
+ if ((!ignorePassengers && this.entity.isVehicle()) || this.entity.isRemoved()) { // Paper - Teleport passenger API
return false;
}
// If this entity is riding another entity, we must dismount before teleporting.
- this.entity.stopRiding();
+ if (dismount) this.entity.stopRiding(); // Paper - Teleport passenger API
// Let the server handle cross world teleports
if (location.getWorld() != null && !location.getWorld().equals(this.getWorld())) {
2024-11-09 21:17:42 +01:00
@@ -971,6 +992,39 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
2024-04-06 22:38:37 +02:00
return CraftEntity.perm;
}
+ // Paper start - more teleport API / async chunk API
+ @Override
+ public java.util.concurrent.CompletableFuture<Boolean> teleportAsync(final Location location, final TeleportCause cause, final io.papermc.paper.entity.TeleportFlag... teleportFlags) {
+ Preconditions.checkArgument(location != null, "location");
+ location.checkFinite();
+ Location locationClone = location.clone(); // clone so we don't need to worry about mutations after this call.
+
+ net.minecraft.server.level.ServerLevel world = ((CraftWorld)locationClone.getWorld()).getHandle();
+ java.util.concurrent.CompletableFuture<Boolean> ret = new java.util.concurrent.CompletableFuture<>();
+
+ world.loadChunksForMoveAsync(getHandle().getBoundingBoxAt(locationClone.getX(), locationClone.getY(), locationClone.getZ()),
2024-10-25 21:24:15 +02:00
+ this instanceof CraftPlayer ? ca.spottedleaf.concurrentutil.util.Priority.HIGHER : ca.spottedleaf.concurrentutil.util.Priority.NORMAL, (list) -> {
2024-04-06 22:38:37 +02:00
+ net.minecraft.server.level.ServerChunkCache chunkProviderServer = world.getChunkSource();
+ for (net.minecraft.world.level.chunk.ChunkAccess chunk : list) {
+ chunkProviderServer.addTicketAtLevel(net.minecraft.server.level.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId());
+ }
+ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> {
+ try {
+ ret.complete(CraftEntity.this.teleport(locationClone, cause, teleportFlags) ? Boolean.TRUE : Boolean.FALSE);
+ } catch (Throwable throwable) {
+ if (throwable instanceof ThreadDeath) {
+ throw (ThreadDeath)throwable;
+ }
+ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to teleport entity " + CraftEntity.this, throwable);
+ ret.completeExceptionally(throwable);
+ }
+ });
+ });
+
+ return ret;
+ }
+ // Paper end - more teleport API / async chunk API
+
// Spigot start
private final org.bukkit.entity.Entity.Spigot spigot = new org.bukkit.entity.Entity.Spigot()
{
2022-07-22 21:36:43 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
Rework async chunk api implementation
Firstly, the old methods all routed to the CompletableFuture method.
However, the CF method could not guarantee that if the caller
was off-main that the future would be "completed" on-main. Since
the callback methods used the CF one, this meant that the callback
methods did not guarantee that the callbacks were to be called on
the main thread.
Now, all methods route to getChunkAtAsync(x, z, gen, urgent, cb)
so that the methods with the callback are guaranteed to invoke
the callback on the main thread. The CF behavior remains unchanged;
it may still appear to complete on main if invoked off-main.
Secondly, remove the scheduleOnMain invocation in the async
chunk completion. This unnecessarily delays the callback
by 1 tick.
Thirdly, add getChunksAtAsync(minX, minZ, maxX, maxZ, ...) which
will load chunks within an area. This method is provided as a helper
as keeping all chunks loaded within an area can be complicated to
implement for plugins (due to the lacking ticket API), and is
already implemented internally anyways.
Fourthly, remove the ticket addition that occured with getChunkAt
and getChunkAtAsync. The ticket addition may delay the unloading
of the chunk unnecessarily. It also fixes a very rare timing bug
where the future/callback would be completed after the chunk
unloads.
2024-11-19 07:34:32 +01:00
index 728a65ad7a826596530b12594db15c93f1af68fb..87aa5f0d594ff697b87bc06019351d22b6c8c8e5 100644
2022-07-22 21:36:43 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
2024-11-09 21:17:42 +01:00
@@ -1291,13 +1291,94 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
2022-07-22 21:36:43 +02:00
@Override
public void setRotation(float yaw, float pitch) {
- throw new UnsupportedOperationException("Cannot set rotation of players. Consider teleporting instead.");
+ // Paper start - Teleport API
2024-10-28 17:14:00 +01:00
+ if (this.getHandle().connection == null) return;
+ this.getHandle().forceSetRotation(yaw, pitch);
+ // Paper end - Teleportation API
2022-07-22 21:36:43 +02:00
}
@Override
public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause) {
+ // Paper start - Teleport API
2023-03-04 23:07:23 +01:00
+ return this.teleport(location, cause, new io.papermc.paper.entity.TeleportFlag[0]);
2022-07-22 21:36:43 +02:00
+ }
+
+ @Override
+ public void lookAt(@NotNull org.bukkit.entity.Entity entity, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor, @NotNull io.papermc.paper.entity.LookAnchor entityAnchor) {
+ this.getHandle().lookAt(toNmsAnchor(playerAnchor), ((CraftEntity) entity).getHandle(), toNmsAnchor(entityAnchor));
+ }
+
+ @Override
+ public void lookAt(double x, double y, double z, @NotNull io.papermc.paper.entity.LookAnchor playerAnchor) {
2024-06-14 14:11:52 +02:00
+ this.getHandle().lookAt(toNmsAnchor(playerAnchor), new net.minecraft.world.phys.Vec3(x, y, z));
2022-07-22 21:36:43 +02:00
+ }
+
+ public static net.minecraft.commands.arguments.EntityAnchorArgument.Anchor toNmsAnchor(io.papermc.paper.entity.LookAnchor nmsAnchor) {
+ return switch (nmsAnchor) {
+ case EYES -> net.minecraft.commands.arguments.EntityAnchorArgument.Anchor.EYES;
+ case FEET -> net.minecraft.commands.arguments.EntityAnchorArgument.Anchor.FEET;
+ };
+ }
+
+ public static io.papermc.paper.entity.LookAnchor toApiAnchor(net.minecraft.commands.arguments.EntityAnchorArgument.Anchor playerAnchor) {
+ return switch (playerAnchor) {
+ case EYES -> io.papermc.paper.entity.LookAnchor.EYES;
+ case FEET -> io.papermc.paper.entity.LookAnchor.FEET;
+ };
+ }
+
2024-10-31 17:25:52 +01:00
+ public static net.minecraft.world.entity.Relative deltaRelativeToNMS(io.papermc.paper.entity.TeleportFlag.Relative apiFlag) {
2022-07-22 21:36:43 +02:00
+ return switch (apiFlag) {
2024-10-31 17:25:52 +01:00
+ case VELOCITY_X -> net.minecraft.world.entity.Relative.DELTA_X;
+ case VELOCITY_Y -> net.minecraft.world.entity.Relative.DELTA_Y;
+ case VELOCITY_Z -> net.minecraft.world.entity.Relative.DELTA_Z;
+ case VELOCITY_ROTATION -> net.minecraft.world.entity.Relative.ROTATE_DELTA;
2022-07-22 21:36:43 +02:00
+ };
+ }
+
2024-10-31 17:25:52 +01:00
+ public static @org.jetbrains.annotations.Nullable io.papermc.paper.entity.TeleportFlag.Relative deltaRelativeToAPI(net.minecraft.world.entity.Relative nmsFlag) {
2022-07-22 21:36:43 +02:00
+ return switch (nmsFlag) {
2024-10-31 17:25:52 +01:00
+ case DELTA_X -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_X;
+ case DELTA_Y -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_Y;
+ case DELTA_Z -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_Z;
+ case ROTATE_DELTA -> io.papermc.paper.entity.TeleportFlag.Relative.VELOCITY_ROTATION;
+ default -> null;
2022-07-22 21:36:43 +02:00
+ };
+ }
+
+ @Override
2023-03-04 23:07:23 +01:00
+ public boolean teleport(Location location, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) {
2024-01-02 20:42:26 +01:00
+ Set<io.papermc.paper.entity.TeleportFlag.Relative> relativeArguments;
+ Set<io.papermc.paper.entity.TeleportFlag> allFlags;
2023-03-04 23:07:23 +01:00
+ if (flags.length == 0) {
+ relativeArguments = Set.of();
+ allFlags = Set.of();
+ } else {
2024-01-02 20:42:26 +01:00
+ relativeArguments = java.util.EnumSet.noneOf(io.papermc.paper.entity.TeleportFlag.Relative.class);
2023-03-04 23:07:23 +01:00
+ allFlags = new HashSet<>();
+ for (io.papermc.paper.entity.TeleportFlag flag : flags) {
2024-01-02 20:42:26 +01:00
+ if (flag instanceof final io.papermc.paper.entity.TeleportFlag.Relative relativeTeleportFlag) {
+ relativeArguments.add(relativeTeleportFlag);
2023-03-04 23:07:23 +01:00
+ }
+ allFlags.add(flag);
+ }
2022-07-22 21:36:43 +02:00
+ }
2023-03-04 23:07:23 +01:00
+ boolean dismount = !allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_VEHICLE);
+ boolean ignorePassengers = allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_PASSENGERS);
2022-07-22 21:36:43 +02:00
+ // Paper end - Teleport API
Preconditions.checkArgument(location != null, "location");
Preconditions.checkArgument(location.getWorld() != null, "location.world");
+ // Paper start - Teleport passenger API
+ // Don't allow teleporting between worlds while keeping passengers
+ if (ignorePassengers && entity.isVehicle() && location.getWorld() != this.getWorld()) {
+ return false;
+ }
+
+ // Don't allow to teleport between worlds if remaining on vehicle
+ if (!dismount && entity.isPassenger() && location.getWorld() != this.getWorld()) {
+ return false;
+ }
+ // Paper end
location.checkFinite();
ServerPlayer entity = this.getHandle();
2024-11-09 21:17:42 +01:00
@@ -1310,7 +1391,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
Updated Upstream (Bukkit/CraftBukkit) (#10034)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing
Bukkit Changes:
f29cb801 Separate checkstyle-suppressions file is not required
86f99bbe SPIGOT-7540, PR-946: Add ServerTickManager API
d4119585 SPIGOT-6903, PR-945: Add BlockData#getMapColor
b7a2ed41 SPIGOT-7530, PR-947: Add Player#removeResourcePack
9dd56255 SPIGOT-7527, PR-944: Add WindCharge#explode()
994a6163 Attempt upgrade of resolver libraries
CraftBukkit Changes:
b3b43a6ad Add Checkstyle check for unused imports
13fb3358e SPIGOT-7544: Scoreboard#getEntries() doesn't get entries but class names
3dda99c06 SPIGOT-7540, PR-1312: Add ServerTickManager API
2ab4508c0 SPIGOT-6903, PR-1311: Add BlockData#getMapColor
1dbdbbed4 PR-1238: Remove unnecessary sign ticking
659728d2a MC-264285, SPIGOT-7439, PR-1237: Fix unbreakable flint and steel is completely consumed while igniting creeper
e37e29ce0 Increase outdated build delay
c00438b39 SPIGOT-7530, PR-1313: Add Player#removeResourcePack
492dd80ce SPIGOT-7527, PR-1310: Add WindCharge#explode()
e11fbb9d7 Upgrade MySQL driver
9f3a0bd2a Attempt upgrade of resolver libraries
60d16d7ca PR-1306: Centralize Bukkit and Minecraft entity conversion
Spigot Changes:
06d602e7 Rebuild patches
2023-12-17 03:09:28 +01:00
return false;
2022-07-22 21:36:43 +02:00
}
- if (entity.isVehicle()) {
+ if (entity.isVehicle() && !ignorePassengers) { // Paper - Teleport API
return false;
}
2024-11-09 21:17:42 +01:00
@@ -1319,7 +1400,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
2024-01-02 20:42:26 +01:00
// To = Players new Location if Teleport is Successful
Location to = location;
// Create & Call the Teleport Event.
- PlayerTeleportEvent event = new PlayerTeleportEvent(this, from, to, cause);
+ PlayerTeleportEvent event = new PlayerTeleportEvent(this, from, to, cause, Set.copyOf(relativeArguments)); // Paper - Teleport API
this.server.getPluginManager().callEvent(event);
// Return False to inform the Plugin that the Teleport was unsuccessful/cancelled.
2024-11-09 21:17:42 +01:00
@@ -1328,7 +1409,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
2022-07-22 21:36:43 +02:00
}
// If this player is riding another entity, we must dismount before teleporting.
- entity.stopRiding();
+ if (dismount) entity.stopRiding(); // Paper - Teleport API
// SPIGOT-5509: Wakeup, similar to riding
if (this.isSleeping()) {
2024-11-09 21:17:42 +01:00
@@ -1344,13 +1425,21 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
2023-03-04 23:07:23 +01:00
ServerLevel toWorld = ((CraftWorld) to.getWorld()).getHandle();
// Close any foreign inventory
- if (this.getHandle().containerMenu != this.getHandle().inventoryMenu) {
+ if (this.getHandle().containerMenu != this.getHandle().inventoryMenu && !allFlags.contains(io.papermc.paper.entity.TeleportFlag.EntityState.RETAIN_OPEN_INVENTORY)) { // Paper
2024-01-21 19:37:09 +01:00
this.getHandle().closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT); // Paper - Inventory close reason
2023-03-04 23:07:23 +01:00
}
2022-07-22 21:36:43 +02:00
// Check if the fromWorld and toWorld are the same.
if (fromWorld == toWorld) {
- entity.connection.teleport(to);
2024-01-02 20:42:26 +01:00
+ // Paper start - Teleport API
2024-10-25 12:30:19 +02:00
+ final Set<net.minecraft.world.entity.Relative> nms = java.util.EnumSet.noneOf(net.minecraft.world.entity.Relative.class);
2024-01-02 20:42:26 +01:00
+ for (final io.papermc.paper.entity.TeleportFlag.Relative bukkit : relativeArguments) {
2024-10-31 17:25:52 +01:00
+ nms.add(deltaRelativeToNMS(bukkit));
2024-01-02 20:42:26 +01:00
+ }
2024-10-25 18:08:28 +02:00
+ entity.connection.internalTeleport(new net.minecraft.world.entity.PositionMoveRotation(
+ io.papermc.paper.util.MCUtil.toVec3(to), net.minecraft.world.phys.Vec3.ZERO, to.getYaw(), to.getPitch()
+ ), nms);
2024-01-02 20:42:26 +01:00
+ // Paper end - Teleport API
2022-07-22 21:36:43 +02:00
} else {
2024-07-06 21:19:14 +02:00
entity.portalProcess = null; // SPIGOT-7785: there is no need to carry this over as it contains the old world/location and we might run into trouble if there is a portal in the same spot in both worlds
2023-04-10 10:03:36 +02:00
// The respawn reason should never be used if the passed location is non null.