From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Thu, 15 Dec 2022 10:33:39 -0800 Subject: [PATCH] Improve PortalEvents diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 72072332578f6cffea79208442c12178bc68215e..1a7d2ade0e85dd5e6cd6c9202e3277cc2fa43d4a 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -1561,7 +1561,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player { Location enter = this.getBukkitEntity().getLocation(); PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(teleportTarget), teleportTarget.relatives()); - Location exit = (worldserver == null) ? null : CraftLocation.toBukkit(absolutePosition.position(), worldserver.getWorld(), absolutePosition.yRot(), absolutePosition.xRot()); + Location exit = /* (worldserver == null) ? null : // Paper - always non-null */CraftLocation.toBukkit(absolutePosition.position(), worldserver.getWorld(), absolutePosition.yRot(), absolutePosition.xRot()); PlayerTeleportEvent tpEvent = new PlayerTeleportEvent(this.getBukkitEntity(), enter, exit, teleportTarget.cause()); // Paper start - gateway-specific teleport event if (this.portalProcess != null && this.portalProcess.isSamePortal(((net.minecraft.world.level.block.EndGatewayBlock) net.minecraft.world.level.block.Blocks.END_GATEWAY)) && this.serverLevel().getBlockEntity(this.portalProcess.getEntryPosition()) instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity theEndGatewayBlockEntity) { diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index c34f98152866945f0c7b7cc45bbc9da6a3ac8f5c..960b3541140bfe36fda5cdb43e3408bbc9db5fde 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -3740,7 +3740,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); Location enter = bukkitEntity.getLocation(); - EntityPortalEvent event = new EntityPortalEvent(bukkitEntity, enter, exit, searchRadius, true, creationRadius); + // Paper start + final org.bukkit.PortalType portalType = switch (cause) { + case END_PORTAL -> org.bukkit.PortalType.ENDER; + case NETHER_PORTAL -> org.bukkit.PortalType.NETHER; + case END_GATEWAY -> org.bukkit.PortalType.END_GATEWAY; // not actually used yet + default -> org.bukkit.PortalType.CUSTOM; + }; + EntityPortalEvent event = new EntityPortalEvent(bukkitEntity, enter, exit, searchRadius, true, creationRadius, portalType); + // Paper end event.getEntity().getServer().getPluginManager().callEvent(event); if (event.isCancelled() || event.getTo() == null || event.getTo().getWorld() == null || !entity.isAlive()) { return null; diff --git a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java index bb4800c60ac05f2db8821737b2b884ea99b64799..a7a21f071161fb7e73a046717d2462f871ab653c 100644 --- a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java +++ b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java @@ -94,6 +94,10 @@ public class EndGatewayBlock extends BaseEntityBlock implements Portal { protected void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) { if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (entity.canUsePortal(false)) { + // Paper start - call EntityPortalEnterEvent + org.bukkit.event.entity.EntityPortalEnterEvent event = new org.bukkit.event.entity.EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.END_GATEWAY); // Paper - add portal type + if (!event.callEvent()) return; + // Paper end - call EntityPortalEnterEvent BlockEntity tileentity = world.getBlockEntity(pos); if (!world.isClientSide && tileentity instanceof TheEndGatewayBlockEntity) { diff --git a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java index 6ed6c2123ed4c54f191ed8cf6da72109fb95eb69..4aa14f975e1ceedf3d4a427e0daefb58b12fcafe 100644 --- a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java +++ b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java @@ -71,8 +71,9 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (entity.canUsePortal(false)) { // CraftBukkit start - Entity in portal - EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); + EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.ENDER); // Paper - add portal type world.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) return; // Paper - make cancellable // CraftBukkit end if (!world.isClientSide && world.dimension() == Level.END && entity instanceof ServerPlayer) { ServerPlayer entityplayer = (ServerPlayer) entity; @@ -95,7 +96,7 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { ServerLevel worldserver1 = world.getServer().getLevel(resourcekey); if (worldserver1 == null) { - return new TeleportTransition(PlayerTeleportEvent.TeleportCause.END_PORTAL); // CraftBukkit- always fire event in case plugins wish to change it + return null; // Paper - keep previous behavior of not firing PlayerTeleportEvent if the target world doesn't exist } else { boolean flag = resourcekey == Level.END; BlockPos blockposition1 = flag ? ServerLevel.END_SPAWN_POINT : worldserver1.getSharedSpawnPos(); diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java index fb361eac03c16ecee02219ff0524cce2292c7976..2b31bf586c1c0bd393d2aa8d0b6635dd9f22f21c 100644 --- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java +++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java @@ -118,8 +118,9 @@ public class NetherPortalBlock extends Block implements Portal { if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent if (entity.canUsePortal(false)) { // CraftBukkit start - Entity in portal - EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ())); + EntityPortalEnterEvent event = new EntityPortalEnterEvent(entity.getBukkitEntity(), new org.bukkit.Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()), org.bukkit.PortalType.NETHER); // Paper - add portal type world.getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) return; // Paper - make cancellable // CraftBukkit end entity.setAsInsidePortal(this, pos); } @@ -151,7 +152,7 @@ public class NetherPortalBlock extends Block implements Portal { // Paper end - Add EntityPortalReadyEvent if (worldserver1 == null) { - return new TeleportTransition(PlayerTeleportEvent.TeleportCause.NETHER_PORTAL); // always fire event in case plugins wish to change it + return null; // Paper - keep previous behavior of not firing PlayerTeleportEvent if the target world doesn't exist } else { boolean flag = worldserver1.getTypeKey() == LevelStem.NETHER; // CraftBukkit end diff --git a/src/main/java/net/minecraft/world/level/portal/DimensionTransition.java b/src/main/java/net/minecraft/world/level/portal/DimensionTransition.java new file mode 100644 index 0000000000000000000000000000000000000000..36c8735312c885eb153f4ffdf0f2a5495e9c9f65 --- /dev/null +++ b/src/main/java/net/minecraft/world/level/portal/DimensionTransition.java @@ -0,0 +1,75 @@ +package net.minecraft.world.level.portal; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.protocol.game.ClientboundLevelEventPacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; +// CraftBukkit start +import org.bukkit.event.player.PlayerTeleportEvent; + +public record DimensionTransition(ServerLevel newLevel, Vec3 pos, Vec3 speed, float yRot, float xRot, boolean missingRespawnBlock, DimensionTransition.PostDimensionTransition postDimensionTransition, PlayerTeleportEvent.TeleportCause cause) { + + public DimensionTransition(ServerLevel newLevel, Vec3 pos, Vec3 speed, float yRot, float xRot, boolean missingRespawnBlock, DimensionTransition.PostDimensionTransition postDimensionTransition) { + this(newLevel, pos, speed, yRot, xRot, missingRespawnBlock, postDimensionTransition, PlayerTeleportEvent.TeleportCause.UNKNOWN); + } + + // Paper - remove unused constructor (for safety) + // CraftBukkit end + + public static final DimensionTransition.PostDimensionTransition DO_NOTHING = (entity) -> { + }; + public static final DimensionTransition.PostDimensionTransition PLAY_PORTAL_SOUND = DimensionTransition::playPortalSound; + public static final DimensionTransition.PostDimensionTransition PLACE_PORTAL_TICKET = DimensionTransition::placePortalTicket; + + public DimensionTransition(ServerLevel world, Vec3 pos, Vec3 velocity, float yaw, float pitch, DimensionTransition.PostDimensionTransition postDimensionTransition) { + // CraftBukkit start + this(world, pos, velocity, yaw, pitch, postDimensionTransition, PlayerTeleportEvent.TeleportCause.UNKNOWN); + } + + public DimensionTransition(ServerLevel worldserver, Vec3 vec3d, Vec3 vec3d1, float f, float f1, DimensionTransition.PostDimensionTransition dimensiontransition_a, PlayerTeleportEvent.TeleportCause cause) { + this(worldserver, vec3d, vec3d1, f, f1, false, dimensiontransition_a, cause); + } + + public DimensionTransition(ServerLevel world, Entity entity, DimensionTransition.PostDimensionTransition postDimensionTransition) { + this(world, entity, postDimensionTransition, PlayerTeleportEvent.TeleportCause.UNKNOWN); + } + + public DimensionTransition(ServerLevel worldserver, Entity entity, DimensionTransition.PostDimensionTransition dimensiontransition_a, PlayerTeleportEvent.TeleportCause cause) { + this(worldserver, findAdjustedSharedSpawnPos(worldserver, entity), Vec3.ZERO, worldserver.getSharedSpawnAngle(), 0.0F, false, dimensiontransition_a, cause); // Paper - MC-200092 - fix spawn pos yaw being ignored + // CraftBukkit end + } + + private static void playPortalSound(Entity entity) { + if (entity instanceof ServerPlayer entityplayer) { + entityplayer.connection.send(new ClientboundLevelEventPacket(1032, BlockPos.ZERO, 0, false)); + } + + } + + private static void placePortalTicket(Entity entity) { + entity.placePortalTicket(BlockPos.containing(entity.position())); + } + + public static DimensionTransition missingRespawnBlock(ServerLevel world, Entity entity, DimensionTransition.PostDimensionTransition postDimensionTransition) { + return new DimensionTransition(world, findAdjustedSharedSpawnPos(world, entity), Vec3.ZERO, world.getSharedSpawnAngle(), 0.0F, true, postDimensionTransition); // Paper - MC-200092 - fix spawn pos yaw being ignored + } + + private static Vec3 findAdjustedSharedSpawnPos(ServerLevel world, Entity entity) { + return entity.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(); + } + + @FunctionalInterface + public interface PostDimensionTransition { + + void onTransition(Entity entity); + + default DimensionTransition.PostDimensionTransition then(DimensionTransition.PostDimensionTransition next) { + return (entity) -> { + this.onTransition(entity); + next.onTransition(entity); + }; + } + } +}