package net.minecraft.server; import java.util.Iterator; import java.util.List; import java.util.Random; import javax.annotation.Nullable; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; // CraftBukkit start import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.event.player.PlayerTeleportEvent; // CraftBukkit end public class TileEntityEndGateway extends TileEntityEnderPortal implements ITickable { private static final Logger a = LogManager.getLogger(); private long f; private int g; public BlockPosition exitPortal; public boolean exactTeleport; public TileEntityEndGateway() {} public NBTTagCompound save(NBTTagCompound nbttagcompound) { super.save(nbttagcompound); nbttagcompound.setLong("Age", this.f); if (this.exitPortal != null) { nbttagcompound.set("ExitPortal", GameProfileSerializer.a(this.exitPortal)); } if (this.exactTeleport) { nbttagcompound.setBoolean("ExactTeleport", this.exactTeleport); } return nbttagcompound; } public void a(NBTTagCompound nbttagcompound) { super.a(nbttagcompound); this.f = nbttagcompound.getLong("Age"); if (nbttagcompound.hasKeyOfType("ExitPortal", 10)) { this.exitPortal = GameProfileSerializer.c(nbttagcompound.getCompound("ExitPortal")); } this.exactTeleport = nbttagcompound.getBoolean("ExactTeleport"); } public void F_() { boolean flag = this.a(); boolean flag1 = this.e(); ++this.f; if (flag1) { --this.g; } else if (!this.world.isClientSide) { List list = this.world.a(Entity.class, new AxisAlignedBB(this.getPosition())); if (!list.isEmpty()) { this.a((Entity) list.get(0)); } if (this.f % 2400L == 0L) { this.f(); } } if (flag != this.a() || flag1 != this.e()) { this.update(); } } public boolean a() { return this.f < 200L; } public boolean e() { return this.g > 0; } @Nullable public PacketPlayOutTileEntityData getUpdatePacket() { return new PacketPlayOutTileEntityData(this.position, 8, this.d()); } public NBTTagCompound d() { return this.save(new NBTTagCompound()); } public void f() { if (!this.world.isClientSide) { this.g = 40; this.world.playBlockAction(this.getPosition(), this.getBlock(), 1, 0); this.update(); } } public boolean c(int i, int j) { if (i == 1) { this.g = 40; return true; } else { return super.c(i, j); } } public void a(Entity entity) { if (!this.world.isClientSide && !this.e()) { this.g = 100; if (this.exitPortal == null && this.world.worldProvider instanceof WorldProviderTheEnd) { this.j(); } if (this.exitPortal != null) { BlockPosition blockposition = this.exactTeleport ? this.exitPortal : this.i(); // CraftBukkit start - Fire PlayerTeleportEvent if (entity instanceof EntityPlayer) { org.bukkit.craftbukkit.entity.CraftPlayer player = (CraftPlayer) entity.getBukkitEntity(); org.bukkit.Location location = new Location(world.getWorld(), (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D); location.setPitch(player.getLocation().getPitch()); location.setYaw(player.getLocation().getYaw()); PlayerTeleportEvent teleEvent = new com.destroystokyo.paper.event.player.PlayerTeleportEndGatewayEvent(player, player.getLocation(), location, new org.bukkit.craftbukkit.block.CraftEndGateway(MCUtil.toLocation(world, this.getPosition()).getBlock())); // Paper Bukkit.getPluginManager().callEvent(teleEvent); if (teleEvent.isCancelled()) { return; } ((EntityPlayer) entity).playerConnection.teleport(teleEvent.getTo()); this.i(); return; } // CraftBukkit end entity.enderTeleportTo((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D); } this.f(); } } private BlockPosition i() { BlockPosition blockposition = a(this.world, this.exitPortal, 5, false); TileEntityEndGateway.a.debug("Best exit position for portal at {} is {}", new Object[] { this.exitPortal, blockposition}); return blockposition.up(); } private void j() { Vec3D vec3d = (new Vec3D((double) this.getPosition().getX(), 0.0D, (double) this.getPosition().getZ())).a(); Vec3D vec3d1 = vec3d.a(1024.0D); int i; for (i = 16; a(this.world, vec3d1).g() > 0 && i-- > 0; vec3d1 = vec3d1.e(vec3d.a(-16.0D))) { TileEntityEndGateway.a.debug("Skipping backwards past nonempty chunk at {}", new Object[] { vec3d1}); } for (i = 16; a(this.world, vec3d1).g() == 0 && i-- > 0; vec3d1 = vec3d1.e(vec3d.a(16.0D))) { TileEntityEndGateway.a.debug("Skipping forward past empty chunk at {}", new Object[] { vec3d1}); } TileEntityEndGateway.a.debug("Found chunk at {}", new Object[] { vec3d1}); Chunk chunk = a(this.world, vec3d1); this.exitPortal = a(chunk); if (this.exitPortal == null) { this.exitPortal = new BlockPosition(vec3d1.x + 0.5D, 75.0D, vec3d1.z + 0.5D); TileEntityEndGateway.a.debug("Failed to find suitable block, settling on {}", new Object[] { this.exitPortal}); (new WorldGenEndIsland()).generate(this.world, new Random(this.exitPortal.asLong()), this.exitPortal); } else { TileEntityEndGateway.a.debug("Found block at {}", new Object[] { this.exitPortal}); } this.exitPortal = a(this.world, this.exitPortal, 16, true); TileEntityEndGateway.a.debug("Creating portal at {}", new Object[] { this.exitPortal}); this.exitPortal = this.exitPortal.up(10); this.c(this.exitPortal); this.update(); } private static BlockPosition a(World world, BlockPosition blockposition, int i, boolean flag) { BlockPosition blockposition1 = null; for (int j = -i; j <= i; ++j) { for (int k = -i; k <= i; ++k) { if (j != 0 || k != 0 || flag) { for (int l = 255; l > (blockposition1 == null ? 0 : blockposition1.getY()); --l) { BlockPosition blockposition2 = new BlockPosition(blockposition.getX() + j, l, blockposition.getZ() + k); IBlockData iblockdata = world.getType(blockposition2); if (iblockdata.l() && (flag || iblockdata.getBlock() != Blocks.BEDROCK)) { blockposition1 = blockposition2; break; } } } } } return blockposition1 == null ? blockposition : blockposition1; } private static Chunk a(World world, Vec3D vec3d) { return world.getChunkAt(MathHelper.floor(vec3d.x / 16.0D), MathHelper.floor(vec3d.z / 16.0D)); } @Nullable private static BlockPosition a(Chunk chunk) { BlockPosition blockposition = new BlockPosition(chunk.locX * 16, 30, chunk.locZ * 16); int i = chunk.g() + 16 - 1; BlockPosition blockposition1 = new BlockPosition(chunk.locX * 16 + 16 - 1, i, chunk.locZ * 16 + 16 - 1); BlockPosition blockposition2 = null; double d0 = 0.0D; Iterator iterator = BlockPosition.a(blockposition, blockposition1).iterator(); while (iterator.hasNext()) { BlockPosition blockposition3 = (BlockPosition) iterator.next(); IBlockData iblockdata = chunk.getBlockData(blockposition3); if (iblockdata.getBlock() == Blocks.END_STONE && !chunk.getBlockData(blockposition3.up(1)).l() && !chunk.getBlockData(blockposition3.up(2)).l()) { double d1 = blockposition3.g(0.0D, 0.0D, 0.0D); if (blockposition2 == null || d1 < d0) { blockposition2 = blockposition3; d0 = d1; } } } return blockposition2; } private void c(BlockPosition blockposition) { (new WorldGenEndGateway()).generate(this.world, new Random(), blockposition); TileEntity tileentity = this.world.getTileEntity(blockposition); if (tileentity instanceof TileEntityEndGateway) { TileEntityEndGateway tileentityendgateway = (TileEntityEndGateway) tileentity; tileentityendgateway.exitPortal = new BlockPosition(this.getPosition()); tileentityendgateway.update(); } else { TileEntityEndGateway.a.warn("Couldn\'t save exit portal at {}", new Object[] { blockposition}); } } public void b(BlockPosition blockposition) { this.exactTeleport = true; this.exitPortal = blockposition; } }