--- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -4,10 +4,14 @@ import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Either; import com.mojang.logging.LogUtils; +import com.mojang.serialization.DataResult; import com.mojang.serialization.Dynamic; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.Collection; +import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.OptionalInt; import java.util.Set; @@ -35,9 +39,9 @@ import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.HoverEvent; +import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.OutgoingChatMessage; import net.minecraft.network.chat.RemoteChatSession; -import net.minecraft.network.chat.Style; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientboundAnimatePacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; @@ -91,8 +95,8 @@ import net.minecraft.util.RandomSource; import net.minecraft.util.Unit; import net.minecraft.world.Container; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.MenuProvider; +import net.minecraft.world.EnumHand; +import net.minecraft.world.ITileInventory; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffects; @@ -115,6 +119,7 @@ import net.minecraft.world.entity.projectile.AbstractArrow; import net.minecraft.world.entity.vehicle.AbstractMinecart; import net.minecraft.world.entity.vehicle.Boat; +import net.minecraft.world.food.FoodData; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.ContainerListener; import net.minecraft.world.inventory.ContainerSynchronizer; @@ -128,6 +133,7 @@ import net.minecraft.world.item.ServerItemCooldowns; import net.minecraft.world.item.WrittenBookItem; import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.GameRules; @@ -135,26 +141,53 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.ChestBlock; import net.minecraft.world.level.block.HorizontalDirectionalBlock; import net.minecraft.world.level.block.NetherPortalBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.CommandBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.portal.PortalInfo; -import net.minecraft.world.level.storage.LevelData; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.ScoreAccess; import net.minecraft.world.scores.ScoreHolder; +import org.slf4j.Logger; +import net.minecraft.world.damagesource.CombatTracker; +import net.minecraft.world.scores.Scoreboard; import net.minecraft.world.scores.Team; import net.minecraft.world.scores.criteria.ObjectiveCriteria; -import org.slf4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.WeatherType; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.CraftWorldBorder; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.craftbukkit.event.CraftPortalEvent; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftDimensionUtil; +import org.bukkit.craftbukkit.util.CraftLocation; +import org.bukkit.event.entity.EntityExhaustionEvent; +import org.bukkit.event.player.PlayerBedLeaveEvent; +import org.bukkit.event.player.PlayerChangedMainHandEvent; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerLocaleChangeEvent; +import org.bukkit.event.player.PlayerPortalEvent; +import org.bukkit.event.player.PlayerSpawnChangeEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.event.player.PlayerToggleSneakEvent; +import org.bukkit.inventory.MainHand; +// CraftBukkit end public class ServerPlayer extends Player { + private static final Logger LOGGER = LogUtils.getLogger(); private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32; private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10; @@ -173,31 +206,31 @@ private float lastSentHealth = -1.0E8F; private int lastSentFood = -99999999; private boolean lastFoodSaturationZero = true; - private int lastSentExp = -99999999; - private int spawnInvulnerableTime = 60; - private ChatVisiblity chatVisibility = ChatVisiblity.FULL; - private boolean canChatColor = true; - private long lastActionTime = Util.getMillis(); + public int lastSentExp = -99999999; + public int spawnInvulnerableTime = 60; + private ChatVisiblity chatVisibility; + private boolean canChatColor; + private long lastActionTime; @Nullable private Entity camera; - private boolean isChangingDimension; + public boolean isChangingDimension; private boolean seenCredits; - private final ServerRecipeBook recipeBook = new ServerRecipeBook(); + private final ServerRecipeBook recipeBook; @Nullable private Vec3 levitationStartPos; private int levitationStartTime; private boolean disconnected; - private int requestedViewDistance = 2; - private String language = "en_us"; + private int requestedViewDistance; + public String language = "en_us"; // CraftBukkit - default @Nullable private Vec3 startingToFallPosition; @Nullable private Vec3 enteredNetherPosition; @Nullable private Vec3 enteredLavaOnVehiclePosition; - private SectionPos lastSectionPos = SectionPos.of(0, 0, 0); - private ChunkTrackingView chunkTrackingView = ChunkTrackingView.EMPTY; - private ResourceKey respawnDimension = Level.OVERWORLD; + private SectionPos lastSectionPos; + private ChunkTrackingView chunkTrackingView; + private ResourceKey respawnDimension; @Nullable private BlockPos respawnPosition; private boolean respawnForced; @@ -205,109 +238,182 @@ private final TextFilter textFilter; private boolean textFilteringEnabled; private boolean allowsListing; - private WardenSpawnTracker wardenSpawnTracker = new WardenSpawnTracker(0, 0, 0); - private final ContainerSynchronizer containerSynchronizer = new ContainerSynchronizer() { - @Override - public void sendInitialData(AbstractContainerMenu container, NonNullList items, ItemStack carriedItem, int[] initialData) { - ServerPlayer.this.connection - .send(new ClientboundContainerSetContentPacket(container.containerId, container.incrementStateId(), items, carriedItem)); + private WardenSpawnTracker wardenSpawnTracker; + private final ContainerSynchronizer containerSynchronizer; + private final ContainerListener containerListener; + @Nullable + private RemoteChatSession chatSession; + private int containerCounter; + public boolean wonGame; - for (int i = 0; i < initialData.length; i++) { - this.broadcastDataValue(container, i, initialData[i]); + // CraftBukkit start + public String displayName; + public Component listName; + public org.bukkit.Location compassTarget; + public int newExp = 0; + public int newLevel = 0; + public int newTotalExp = 0; + public boolean keepLevel = false; + public double maxHealthCache; + public boolean joining = true; + public boolean sentListPacket = false; + public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent + // CraftBukkit end + + public ServerPlayer(MinecraftServer minecraftserver, ServerLevel worldserver, GameProfile gameprofile, ClientInformation clientinformation) { + super(worldserver, worldserver.getSharedSpawnPos(), worldserver.getSharedSpawnAngle(), gameprofile); + this.chatVisibility = ChatVisiblity.FULL; + this.canChatColor = true; + this.lastActionTime = Util.getMillis(); + this.recipeBook = new ServerRecipeBook(); + this.requestedViewDistance = 2; + this.language = "en_us"; + this.lastSectionPos = SectionPos.of(0, 0, 0); + this.chunkTrackingView = ChunkTrackingView.EMPTY; + this.respawnDimension = Level.OVERWORLD; + this.wardenSpawnTracker = new WardenSpawnTracker(0, 0, 0); + this.containerSynchronizer = new ContainerSynchronizer() { + @Override + public void sendInitialData(AbstractContainerMenu container, NonNullList items, ItemStack carriedItem, int[] initialData) { + ServerPlayer.this.connection.send(new ClientboundContainerSetContentPacket(container.containerId, container.incrementStateId(), items, carriedItem)); + + for (int i = 0; i < initialData.length; ++i) { + this.broadcastDataValue(container, i, initialData[i]); + } + } - } - @Override - public void sendSlotChange(AbstractContainerMenu container, int slot, ItemStack itemStack) { - ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(container.containerId, container.incrementStateId(), slot, itemStack)); - } + @Override + public void sendSlotChange(AbstractContainerMenu container, int slot, ItemStack itemStack) { + ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(container.containerId, container.incrementStateId(), slot, itemStack)); + } - @Override - public void sendCarriedChange(AbstractContainerMenu containerMenu, ItemStack stack) { - ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(-1, containerMenu.incrementStateId(), -1, stack)); - } + @Override + public void sendCarriedChange(AbstractContainerMenu containerMenu, ItemStack stack) { + ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(-1, containerMenu.incrementStateId(), -1, stack)); + } - @Override - public void sendDataChange(AbstractContainerMenu container, int id, int value) { - this.broadcastDataValue(container, id, value); - } + @Override + public void sendDataChange(AbstractContainerMenu container, int id, int value) { + this.broadcastDataValue(container, id, value); + } - private void broadcastDataValue(AbstractContainerMenu container, int id, int value) { - ServerPlayer.this.connection.send(new ClientboundContainerSetDataPacket(container.containerId, id, value)); - } - }; - private final ContainerListener containerListener = new ContainerListener() { - @Override - public void slotChanged(AbstractContainerMenu containerToSend, int dataSlotIndex, ItemStack stack) { - Slot slot = containerToSend.getSlot(dataSlotIndex); - if (!(slot instanceof ResultSlot)) { - if (slot.container == ServerPlayer.this.getInventory()) { - CriteriaTriggers.INVENTORY_CHANGED.trigger(ServerPlayer.this, ServerPlayer.this.getInventory(), stack); + private void broadcastDataValue(AbstractContainerMenu container, int id, int value) { + ServerPlayer.this.connection.send(new ClientboundContainerSetDataPacket(container.containerId, id, value)); + } + }; + this.containerListener = new ContainerListener() { + @Override + public void slotChanged(AbstractContainerMenu containerToSend, int dataSlotIndex, ItemStack stack) { + Slot slot = containerToSend.getSlot(dataSlotIndex); + + if (!(slot instanceof ResultSlot)) { + if (slot.container == ServerPlayer.this.getInventory()) { + CriteriaTriggers.INVENTORY_CHANGED.trigger(ServerPlayer.this, ServerPlayer.this.getInventory(), stack); + } + } } - } - @Override - public void dataChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, int value) { + @Override + public void dataChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, int value) {} + }; + this.textFilter = minecraftserver.createTextFilterForPlayer(this); + this.gameMode = minecraftserver.createGameModeForPlayer(this); + this.server = minecraftserver; + this.stats = minecraftserver.getPlayerList().getPlayerStats(this); + this.advancements = minecraftserver.getPlayerList().getPlayerAdvancements(this); + this.setMaxUpStep(1.0F); + this.fudgeSpawnLocation(worldserver); + this.updateOptions(clientinformation); + + // CraftBukkit start + this.displayName = this.getScoreboardName(); + this.bukkitPickUpLoot = true; + this.maxHealthCache = this.getMaxHealth(); + } + + // Yes, this doesn't match Vanilla, but it's the best we can do for now. + // If this is an issue, PRs are welcome + public final BlockPos getSpawnPoint(ServerLevel worldserver) { + BlockPos blockposition = worldserver.getSharedSpawnPos(); + + if (worldserver.dimensionType().hasSkyLight() && worldserver.serverLevelData.getGameType() != GameType.ADVENTURE) { + int i = Math.max(0, this.server.getSpawnRadius(worldserver)); + int j = Mth.floor(worldserver.getWorldBorder().getDistanceToBorder((double) blockposition.getX(), (double) blockposition.getZ())); + + if (j < i) { + i = j; + } + + if (j <= 1) { + i = 1; + } + + long k = (long) (i * 2 + 1); + long l = k * k; + int i1 = l > 2147483647L ? Integer.MAX_VALUE : (int) l; + int j1 = this.getCoprime(i1); + int k1 = RandomSource.create().nextInt(i1); + + for (int l1 = 0; l1 < i1; ++l1) { + int i2 = (k1 + j1 * l1) % i1; + int j2 = i2 % (i * 2 + 1); + int k2 = i2 / (i * 2 + 1); + BlockPos blockposition1 = PlayerRespawnLogic.getOverworldRespawnPos(worldserver, blockposition.getX() + j2 - i, blockposition.getZ() + k2 - i); + + if (blockposition1 != null) { + return blockposition1; + } + } } - }; - @Nullable - private RemoteChatSession chatSession; - private int containerCounter; - public boolean wonGame; - public ServerPlayer(MinecraftServer minecraftServer, ServerLevel level, GameProfile gameProfile, ClientInformation clientInformation) { - super(level, level.getSharedSpawnPos(), level.getSharedSpawnAngle(), gameProfile); - this.textFilter = minecraftServer.createTextFilterForPlayer(this); - this.gameMode = minecraftServer.createGameModeForPlayer(this); - this.server = minecraftServer; - this.stats = minecraftServer.getPlayerList().getPlayerStats(this); - this.advancements = minecraftServer.getPlayerList().getPlayerAdvancements(this); - this.setMaxUpStep(1.0F); - this.fudgeSpawnLocation(level); - this.updateOptions(clientInformation); + return blockposition; } + // CraftBukkit end private void fudgeSpawnLocation(ServerLevel level) { - BlockPos sharedSpawnPos = level.getSharedSpawnPos(); - if (level.dimensionType().hasSkyLight() && level.getServer().getWorldData().getGameType() != GameType.ADVENTURE) { - int max = Math.max(0, this.server.getSpawnRadius(level)); - int floor = Mth.floor(level.getWorldBorder().getDistanceToBorder((double)sharedSpawnPos.getX(), (double)sharedSpawnPos.getZ())); - if (floor < max) { - max = floor; + BlockPos blockposition = level.getSharedSpawnPos(); + + if (level.dimensionType().hasSkyLight() && level.serverLevelData.getGameType() != GameType.ADVENTURE) { // CraftBukkit + int i = Math.max(0, this.server.getSpawnRadius(level)); + int j = Mth.floor(level.getWorldBorder().getDistanceToBorder((double) blockposition.getX(), (double) blockposition.getZ())); + + if (j < i) { + i = j; } - if (floor <= 1) { - max = 1; + if (j <= 1) { + i = 1; } - long l = (long)(max * 2 + 1); - long l1 = l * l; - int i = l1 > 2147483647L ? Integer.MAX_VALUE : (int)l1; - int coprime = this.getCoprime(i); - int randomInt = RandomSource.create().nextInt(i); + long k = (long) (i * 2 + 1); + long l = k * k; + int i1 = l > 2147483647L ? Integer.MAX_VALUE : (int) l; + int j1 = this.getCoprime(i1); + int k1 = RandomSource.create().nextInt(i1); - for (int i1 = 0; i1 < i; i1++) { - int i2 = (randomInt + coprime * i1) % i; - int i3 = i2 % (max * 2 + 1); - int i4 = i2 / (max * 2 + 1); - BlockPos overworldRespawnPos = PlayerRespawnLogic.getOverworldRespawnPos( - level, sharedSpawnPos.getX() + i3 - max, sharedSpawnPos.getZ() + i4 - max - ); - if (overworldRespawnPos != null) { - this.moveTo(overworldRespawnPos, 0.0F, 0.0F); - if (level.noCollision(this)) { + for (int l1 = 0; l1 < i1; ++l1) { + int i2 = (k1 + j1 * l1) % i1; + int j2 = i2 % (i * 2 + 1); + int k2 = i2 / (i * 2 + 1); + BlockPos blockposition1 = PlayerRespawnLogic.getOverworldRespawnPos(level, blockposition.getX() + j2 - i, blockposition.getZ() + k2 - i); + + if (blockposition1 != null) { + this.moveTo(blockposition1, 0.0F, 0.0F); + if (level.noCollision((Entity) this)) { break; } } } } else { - this.moveTo(sharedSpawnPos, 0.0F, 0.0F); + this.moveTo(blockposition, 0.0F, 0.0F); - while (!level.noCollision(this) && this.getY() < (double)(level.getMaxBuildHeight() - 1)) { - this.setPos(this.getX(), this.getY() + 1.0, this.getZ()); + while (!level.noCollision((Entity) this) && this.getY() < (double) (level.getMaxBuildHeight() - 1)) { + this.setPos(this.getX(), this.getY() + 1.0D, this.getZ()); } } + } private int getCoprime(int spawnArea) { @@ -318,67 +424,101 @@ public void readAdditionalSaveData(CompoundTag compound) { super.readAdditionalSaveData(compound); if (compound.contains("warden_spawn_tracker", 10)) { - WardenSpawnTracker.CODEC - .parse(new Dynamic<>(NbtOps.INSTANCE, compound.get("warden_spawn_tracker"))) - .resultOrPartial(LOGGER::error) - .ifPresent(wardenSpawnTracker -> this.wardenSpawnTracker = wardenSpawnTracker); + DataResult dataresult = WardenSpawnTracker.CODEC.parse(new Dynamic(NbtOps.INSTANCE, compound.get("warden_spawn_tracker"))); // CraftBukkit - decompile error + Logger logger = ServerPlayer.LOGGER; + + Objects.requireNonNull(logger); + dataresult.resultOrPartial(logger::error).ifPresent((wardenspawntracker) -> { + this.wardenSpawnTracker = wardenspawntracker; + }); } if (compound.contains("enteredNetherPosition", 10)) { - CompoundTag compound1 = compound.getCompound("enteredNetherPosition"); - this.enteredNetherPosition = new Vec3(compound1.getDouble("x"), compound1.getDouble("y"), compound1.getDouble("z")); + CompoundTag nbttagcompound1 = compound.getCompound("enteredNetherPosition"); + + this.enteredNetherPosition = new Vec3(nbttagcompound1.getDouble("x"), nbttagcompound1.getDouble("y"), nbttagcompound1.getDouble("z")); } this.seenCredits = compound.getBoolean("seenCredits"); if (compound.contains("recipeBook", 10)) { this.recipeBook.fromNbt(compound.getCompound("recipeBook"), this.server.getRecipeManager()); } + this.getBukkitEntity().readExtraData(compound); // CraftBukkit if (this.isSleeping()) { this.stopSleeping(); } + // CraftBukkit start + String spawnWorld = compound.getString("SpawnWorld"); + CraftWorld oldWorld = (CraftWorld) Bukkit.getWorld(spawnWorld); + if (oldWorld != null) { + this.respawnDimension = oldWorld.getHandle().dimension(); + } + // CraftBukkit end + if (compound.contains("SpawnX", 99) && compound.contains("SpawnY", 99) && compound.contains("SpawnZ", 99)) { this.respawnPosition = new BlockPos(compound.getInt("SpawnX"), compound.getInt("SpawnY"), compound.getInt("SpawnZ")); this.respawnForced = compound.getBoolean("SpawnForced"); this.respawnAngle = compound.getFloat("SpawnAngle"); if (compound.contains("SpawnDimension")) { - this.respawnDimension = Level.RESOURCE_KEY_CODEC - .parse(NbtOps.INSTANCE, compound.get("SpawnDimension")) - .resultOrPartial(LOGGER::error) - .orElse(Level.OVERWORLD); + DataResult> dataresult1 = Level.RESOURCE_KEY_CODEC.parse(NbtOps.INSTANCE, compound.get("SpawnDimension")); // CraftBukkit - decompile error + Logger logger1 = ServerPlayer.LOGGER; + + Objects.requireNonNull(logger1); + this.respawnDimension = (ResourceKey) dataresult1.resultOrPartial(logger1::error).orElse(Level.OVERWORLD); } } + } @Override public void addAdditionalSaveData(CompoundTag compound) { super.addAdditionalSaveData(compound); - WardenSpawnTracker.CODEC - .encodeStart(NbtOps.INSTANCE, this.wardenSpawnTracker) - .resultOrPartial(LOGGER::error) - .ifPresent(tag -> compound.put("warden_spawn_tracker", tag)); + DataResult dataresult = WardenSpawnTracker.CODEC.encodeStart(NbtOps.INSTANCE, this.wardenSpawnTracker); // CraftBukkit - decompile error + Logger logger = ServerPlayer.LOGGER; + + Objects.requireNonNull(logger); + dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> { + compound.put("warden_spawn_tracker", nbtbase); + }); this.storeGameTypes(compound); compound.putBoolean("seenCredits", this.seenCredits); if (this.enteredNetherPosition != null) { - CompoundTag compoundTag = new CompoundTag(); - compoundTag.putDouble("x", this.enteredNetherPosition.x); - compoundTag.putDouble("y", this.enteredNetherPosition.y); - compoundTag.putDouble("z", this.enteredNetherPosition.z); - compound.put("enteredNetherPosition", compoundTag); + CompoundTag nbttagcompound1 = new CompoundTag(); + + nbttagcompound1.putDouble("x", this.enteredNetherPosition.x); + nbttagcompound1.putDouble("y", this.enteredNetherPosition.y); + nbttagcompound1.putDouble("z", this.enteredNetherPosition.z); + compound.put("enteredNetherPosition", nbttagcompound1); } - Entity rootVehicle = this.getRootVehicle(); - Entity vehicle = this.getVehicle(); - if (vehicle != null && rootVehicle != this && rootVehicle.hasExactlyOnePlayerPassenger()) { - CompoundTag compoundTag1 = new CompoundTag(); - CompoundTag compoundTag2 = new CompoundTag(); - rootVehicle.save(compoundTag2); - compoundTag1.putUUID("Attach", vehicle.getUUID()); - compoundTag1.put("Entity", compoundTag2); - compound.put("RootVehicle", compoundTag1); + Entity entity = this.getRootVehicle(); + Entity entity1 = this.getVehicle(); + + // CraftBukkit start - handle non-persistent vehicles + boolean persistVehicle = true; + if (entity1 != null) { + Entity vehicle; + for (vehicle = entity1; vehicle != null; vehicle = vehicle.getVehicle()) { + if (!vehicle.persist) { + persistVehicle = false; + break; + } + } } + if (persistVehicle && entity1 != null && entity != this && entity.hasExactlyOnePlayerPassenger()) { + // CraftBukkit end + CompoundTag nbttagcompound2 = new CompoundTag(); + CompoundTag nbttagcompound3 = new CompoundTag(); + + entity.save(nbttagcompound3); + nbttagcompound2.putUUID("Attach", entity1.getUUID()); + nbttagcompound2.put("Entity", nbttagcompound3); + compound.put("RootVehicle", nbttagcompound2); + } + compound.put("recipeBook", this.recipeBook.toNbt()); compound.putString("Dimension", this.level().dimension().location().toString()); if (this.respawnPosition != null) { @@ -387,17 +527,45 @@ compound.putInt("SpawnZ", this.respawnPosition.getZ()); compound.putBoolean("SpawnForced", this.respawnForced); compound.putFloat("SpawnAngle", this.respawnAngle); - ResourceLocation.CODEC - .encodeStart(NbtOps.INSTANCE, this.respawnDimension.location()) - .resultOrPartial(LOGGER::error) - .ifPresent(tag -> compound.put("SpawnDimension", tag)); + dataresult = ResourceLocation.CODEC.encodeStart(NbtOps.INSTANCE, this.respawnDimension.location()); + logger = ServerPlayer.LOGGER; + Objects.requireNonNull(logger); + dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> { + compound.put("SpawnDimension", nbtbase); + }); } + this.getBukkitEntity().setExtraData(compound); // CraftBukkit + } + // CraftBukkit start - World fallback code, either respawn location or global spawn + public void spawnIn(Level world) { + this.setLevel(world); + if (world == null) { + this.unsetRemoved(); + Vec3 position = null; + if (this.respawnDimension != null) { + world = this.server.getLevel(this.respawnDimension); + if (world != null && this.getRespawnPosition() != null) { + position = Player.findRespawnPositionAndUseSpawnBlock((ServerLevel) world, this.getRespawnPosition(), this.getRespawnAngle(), false, false).orElse(null); + } + } + if (world == null || position == null) { + world = ((CraftWorld) Bukkit.getServer().getWorlds().get(0)).getHandle(); + position = Vec3.atCenterOf(world.getSharedSpawnPos()); + } + this.setLevel(world); + this.setPos(position); + } + this.gameMode.setLevel((ServerLevel) world); + } + // CraftBukkit end + public void setExperiencePoints(int experiencePoints) { - float f = (float)this.getXpNeededForNextLevel(); + float f = (float) this.getXpNeededForNextLevel(); float f1 = (f - 1.0F) / f; - this.experienceProgress = Mth.clamp((float)experiencePoints / f, 0.0F, f1); + + this.experienceProgress = Mth.clamp((float) experiencePoints / f, 0.0F, f1); this.lastSentExp = -1; } @@ -418,7 +586,7 @@ this.lastSentExp = -1; } - private void initMenu(AbstractContainerMenu menu) { + public void initMenu(AbstractContainerMenu menu) { menu.addSlotListener(this.containerListener); menu.setSynchronizer(this.containerSynchronizer); } @@ -440,7 +608,7 @@ } @Override - protected void onInsideBlock(BlockState state) { + protected void onInsideBlock(IBlockData state) { CriteriaTriggers.ENTER_BLOCK.trigger(this, state); } @@ -451,11 +619,16 @@ @Override public void tick() { + // CraftBukkit start + if (this.joining) { + this.joining = false; + } + // CraftBukkit end this.gameMode.tick(); this.wardenSpawnTracker.tick(); - this.spawnInvulnerableTime--; + --this.spawnInvulnerableTime; if (this.invulnerableTime > 0) { - this.invulnerableTime--; + --this.invulnerableTime; } this.containerMenu.broadcastChanges(); @@ -464,10 +637,11 @@ this.containerMenu = this.inventoryMenu; } - Entity camera = this.getCamera(); - if (camera != this) { - if (camera.isAlive()) { - this.absMoveTo(camera.getX(), camera.getY(), camera.getZ(), camera.getYRot(), camera.getXRot()); + Entity entity = this.getCamera(); + + if (entity != this) { + if (entity.isAlive()) { + this.absMoveTo(entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot()); this.serverLevel().getChunkSource().move(this); if (this.wantsToStopRiding()) { this.setCamera(this); @@ -493,20 +667,20 @@ super.tick(); } - for (int i = 0; i < this.getInventory().getContainerSize(); i++) { - ItemStack item = this.getInventory().getItem(i); - if (item.getItem().isComplex()) { - Packet updatePacket = ((ComplexItem)item.getItem()).getUpdatePacket(item, this.level(), this); - if (updatePacket != null) { - this.connection.send(updatePacket); + for (int i = 0; i < this.getInventory().getContainerSize(); ++i) { + ItemStack itemstack = this.getInventory().getItem(i); + + if (itemstack.getItem().isComplex()) { + Packet packet = ((ComplexItem) itemstack.getItem()).getUpdatePacket(itemstack, this.level(), this); + + if (packet != null) { + this.connection.send(packet); } } } - if (this.getHealth() != this.lastSentHealth - || this.lastSentFood != this.foodData.getFoodLevel() - || this.foodData.getSaturationLevel() == 0.0F != this.lastFoodSaturationZero) { - this.connection.send(new ClientboundSetHealthPacket(this.getHealth(), this.foodData.getFoodLevel(), this.foodData.getSaturationLevel())); + if (this.getHealth() != this.lastSentHealth || this.lastSentFood != this.foodData.getFoodLevel() || this.foodData.getSaturationLevel() == 0.0F != this.lastFoodSaturationZero) { + this.connection.send(new ClientboundSetHealthPacket(this.getBukkitEntity().getScaledHealth(), this.foodData.getFoodLevel(), this.foodData.getSaturationLevel())); // CraftBukkit this.lastSentHealth = this.getHealth(); this.lastSentFood = this.foodData.getFoodLevel(); this.lastFoodSaturationZero = this.foodData.getSaturationLevel() == 0.0F; @@ -519,27 +693,33 @@ if (this.foodData.getFoodLevel() != this.lastRecordedFoodLevel) { this.lastRecordedFoodLevel = this.foodData.getFoodLevel(); - this.updateScoreForCriteria(ObjectiveCriteria.FOOD, Mth.ceil((float)this.lastRecordedFoodLevel)); + this.updateScoreForCriteria(ObjectiveCriteria.FOOD, Mth.ceil((float) this.lastRecordedFoodLevel)); } if (this.getAirSupply() != this.lastRecordedAirLevel) { this.lastRecordedAirLevel = this.getAirSupply(); - this.updateScoreForCriteria(ObjectiveCriteria.AIR, Mth.ceil((float)this.lastRecordedAirLevel)); + this.updateScoreForCriteria(ObjectiveCriteria.AIR, Mth.ceil((float) this.lastRecordedAirLevel)); } if (this.getArmorValue() != this.lastRecordedArmor) { this.lastRecordedArmor = this.getArmorValue(); - this.updateScoreForCriteria(ObjectiveCriteria.ARMOR, Mth.ceil((float)this.lastRecordedArmor)); + this.updateScoreForCriteria(ObjectiveCriteria.ARMOR, Mth.ceil((float) this.lastRecordedArmor)); } if (this.totalExperience != this.lastRecordedExperience) { this.lastRecordedExperience = this.totalExperience; - this.updateScoreForCriteria(ObjectiveCriteria.EXPERIENCE, Mth.ceil((float)this.lastRecordedExperience)); + this.updateScoreForCriteria(ObjectiveCriteria.EXPERIENCE, Mth.ceil((float) this.lastRecordedExperience)); } + // CraftBukkit start - Force max health updates + if (this.maxHealthCache != this.getMaxHealth()) { + this.getBukkitEntity().updateScaledHealth(); + } + // CraftBukkit end + if (this.experienceLevel != this.lastRecordedLevel) { this.lastRecordedLevel = this.experienceLevel; - this.updateScoreForCriteria(ObjectiveCriteria.LEVEL, Mth.ceil((float)this.lastRecordedLevel)); + this.updateScoreForCriteria(ObjectiveCriteria.LEVEL, Mth.ceil((float) this.lastRecordedLevel)); } if (this.totalExperience != this.lastSentExp) { @@ -550,11 +730,27 @@ if (this.tickCount % 20 == 0) { CriteriaTriggers.LOCATION.trigger(this); } - } catch (Throwable var4) { - CrashReport crashReport = CrashReport.forThrowable(var4, "Ticking player"); - CrashReportCategory crashReportCategory = crashReport.addCategory("Player being ticked"); - this.fillCrashReportCategory(crashReportCategory); - throw new ReportedException(crashReport); + + // CraftBukkit start - initialize oldLevel, fire PlayerLevelChangeEvent, and tick client-sided world border + if (this.oldLevel == -1) { + this.oldLevel = this.experienceLevel; + } + + if (this.oldLevel != this.experienceLevel) { + CraftEventFactory.callPlayerLevelChangeEvent(this.getBukkitEntity(), this.oldLevel, this.experienceLevel); + this.oldLevel = this.experienceLevel; + } + + if (this.getBukkitEntity().hasClientWorldBorder()) { + ((CraftWorldBorder) this.getBukkitEntity().getWorldBorder()).getHandle().tick(); + } + // CraftBukkit end + } catch (Throwable throwable) { + CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking player"); + CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Player being ticked"); + + this.fillCrashReportCategory(crashreportsystemdetails); + throw new ReportedException(crashreport); } } @@ -572,6 +768,7 @@ if (this.fallDistance > 0.0F && this.startingToFallPosition == null) { this.startingToFallPosition = this.position(); } + } public void trackEnteredOrExitedLavaOnVehicle() { @@ -586,42 +783,83 @@ if (this.enteredLavaOnVehiclePosition != null && (this.getVehicle() == null || !this.getVehicle().isInLava())) { this.enteredLavaOnVehiclePosition = null; } + } private void updateScoreForCriteria(ObjectiveCriteria criteria, int points) { - this.getScoreboard().forAllObjectives(criteria, this, scoreAccess -> scoreAccess.set(points)); + // CraftBukkit - Use our scores instead + this.level().getCraftServer().getScoreboardManager().forAllObjectives(criteria, this, (scoreaccess) -> { + scoreaccess.set(points); + }); } @Override public void die(DamageSource cause) { this.gameEvent(GameEvent.ENTITY_DIE); - boolean _boolean = this.level().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES); - if (_boolean) { - Component deathMessage = this.getCombatTracker().getDeathMessage(); - this.connection - .send( - new ClientboundPlayerCombatKillPacket(this.getId(), deathMessage), - PacketSendListener.exceptionallySend( - () -> { - int i = 256; - String string = deathMessage.getString(256); - Component component = Component.translatable( - "death.attack.message_too_long", Component.literal(string).withStyle(ChatFormatting.YELLOW) - ); - Component component1 = Component.translatable("death.attack.even_more_magic", this.getDisplayName()) - .withStyle(style -> style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, component))); - return new ClientboundPlayerCombatKillPacket(this.getId(), component1); - } - ) - ); - Team team = this.getTeam(); - if (team == null || team.getDeathMessageVisibility() == Team.Visibility.ALWAYS) { - this.server.getPlayerList().broadcastSystemMessage(deathMessage, false); - } else if (team.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OTHER_TEAMS) { - this.server.getPlayerList().broadcastSystemToTeam(this, deathMessage); - } else if (team.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OWN_TEAM) { - this.server.getPlayerList().broadcastSystemToAllExceptTeam(this, deathMessage); + boolean flag = this.level().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES); + // CraftBukkit start - fire PlayerDeathEvent + if (this.isRemoved()) { + return; + } + java.util.List loot = new java.util.ArrayList(this.getInventory().getContainerSize()); + boolean keepInventory = this.level().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || this.isSpectator(); + + if (!keepInventory) { + for (ItemStack item : this.getInventory().getContents()) { + if (!item.isEmpty() && !EnchantmentHelper.hasVanishingCurse(item)) { + loot.add(CraftItemStack.asCraftMirror(item)); + } } + } + // SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule) + this.dropFromLootTable(cause, this.lastHurtByPlayerTime > 0); + for (org.bukkit.inventory.ItemStack item : this.drops) { + loot.add(item); + } + this.drops.clear(); // SPIGOT-5188: make sure to clear + + Component defaultMessage = this.getCombatTracker().getDeathMessage(); + + String deathmessage = defaultMessage.getString(); + keepLevel = keepInventory; // SPIGOT-2222: pre-set keepLevel + org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, loot, deathmessage, keepInventory); + + // SPIGOT-943 - only call if they have an inventory open + if (this.containerMenu != this.inventoryMenu) { + this.closeContainer(); + } + + String deathMessage = event.getDeathMessage(); + + if (deathMessage != null && deathMessage.length() > 0 && flag) { // TODO: allow plugins to override? + Component ichatbasecomponent; + if (deathMessage.equals(deathmessage)) { + ichatbasecomponent = this.getCombatTracker().getDeathMessage(); + } else { + ichatbasecomponent = org.bukkit.craftbukkit.util.CraftChatMessage.fromStringOrNull(deathMessage); + } + + this.connection.send(new ClientboundPlayerCombatKillPacket(this.getId(), ichatbasecomponent), PacketSendListener.exceptionallySend(() -> { + boolean flag1 = true; + String s = ichatbasecomponent.getString(256); + MutableComponent ichatmutablecomponent = Component.translatable("death.attack.message_too_long", Component.literal(s).withStyle(ChatFormatting.YELLOW)); + MutableComponent ichatmutablecomponent1 = Component.translatable("death.attack.even_more_magic", this.getDisplayName()).withStyle((chatmodifier) -> { + return chatmodifier.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, ichatmutablecomponent)); + }); + + return new ClientboundPlayerCombatKillPacket(this.getId(), ichatmutablecomponent1); + })); + PlayerTeam scoreboardteam = this.getTeam(); + + if (scoreboardteam != null && scoreboardteam.getDeathMessageVisibility() != Team.Visibility.ALWAYS) { + if (scoreboardteam.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OTHER_TEAMS) { + this.server.getPlayerList().broadcastSystemToTeam(this, ichatbasecomponent); + } else if (scoreboardteam.getDeathMessageVisibility() == Team.Visibility.HIDE_FOR_OWN_TEAM) { + this.server.getPlayerList().broadcastSystemToAllExceptTeam(this, ichatbasecomponent); + } + } else { + this.server.getPlayerList().broadcastSystemMessage(ichatbasecomponent, false); + } } else { this.connection.send(new ClientboundPlayerCombatKillPacket(this.getId(), CommonComponents.EMPTY)); } @@ -630,20 +868,27 @@ if (this.level().getGameRules().getBoolean(GameRules.RULE_FORGIVE_DEAD_PLAYERS)) { this.tellNeutralMobsThatIDied(); } - - if (!this.isSpectator()) { - this.dropAllDeathLoot(cause); + // SPIGOT-5478 must be called manually now + this.dropExperience(); + // we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory. + if (!event.getKeepInventory()) { + this.getInventory().clearContent(); } - this.getScoreboard().forAllObjectives(ObjectiveCriteria.DEATH_COUNT, this, ScoreAccess::increment); - LivingEntity killCredit = this.getKillCredit(); - if (killCredit != null) { - this.awardStat(Stats.ENTITY_KILLED_BY.get(killCredit.getType())); - killCredit.awardKillScore(this, this.deathScore, cause); - this.createWitherRose(killCredit); + this.setCamera(this); // Remove spectated target + // CraftBukkit end + + // CraftBukkit - Get our scores instead + this.level().getCraftServer().getScoreboardManager().forAllObjectives(ObjectiveCriteria.DEATH_COUNT, this, ScoreAccess::increment); + LivingEntity entityliving = this.getKillCredit(); + + if (entityliving != null) { + this.awardStat(Stats.ENTITY_KILLED_BY.get(entityliving.getType())); + entityliving.awardKillScore(this, this.deathScore, cause); + this.createWitherRose(entityliving); } - this.level().broadcastEntityEvent(this, (byte)3); + this.level().broadcastEntityEvent(this, (byte) 3); this.awardStat(Stats.DEATHS); this.resetStat(Stats.CUSTOM.get(Stats.TIME_SINCE_DEATH)); this.resetStat(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)); @@ -655,12 +900,13 @@ } private void tellNeutralMobsThatIDied() { - AABB aABB = new AABB(this.blockPosition()).inflate(32.0, 10.0, 32.0); - this.level() - .getEntitiesOfClass(Mob.class, aABB, EntitySelector.NO_SPECTATORS) - .stream() - .filter(mob -> mob instanceof NeutralMob) - .forEach(mob -> ((NeutralMob)mob).playerDied(this)); + AABB axisalignedbb = (new AABB(this.blockPosition())).inflate(32.0D, 10.0D, 32.0D); + + this.level().getEntitiesOfClass(Mob.class, axisalignedbb, EntitySelector.NO_SPECTATORS).stream().filter((entityinsentient) -> { + return entityinsentient instanceof NeutralMob; + }).forEach((entityinsentient) -> { + ((NeutralMob) entityinsentient).playerDied(this); + }); } @Override @@ -668,10 +914,12 @@ if (killed != this) { super.awardKillScore(killed, scoreValue, damageSource); this.increaseScore(scoreValue); - this.getScoreboard().forAllObjectives(ObjectiveCriteria.KILL_COUNT_ALL, this, ScoreAccess::increment); + // CraftBukkit - Get our scores instead + this.level().getCraftServer().getScoreboardManager().forAllObjectives(ObjectiveCriteria.KILL_COUNT_ALL, this, ScoreAccess::increment); if (killed instanceof Player) { this.awardStat(Stats.PLAYER_KILLS); - this.getScoreboard().forAllObjectives(ObjectiveCriteria.KILL_COUNT_PLAYERS, this, ScoreAccess::increment); + // CraftBukkit - Get our scores instead + this.level().getCraftServer().getScoreboardManager().forAllObjectives(ObjectiveCriteria.KILL_COUNT_PLAYERS, this, ScoreAccess::increment); } else { this.awardStat(Stats.MOB_KILLS); } @@ -682,14 +930,18 @@ } } - private void handleTeamKill(ScoreHolder scoreHolder, ScoreHolder scoreHolder1, ObjectiveCriteria[] objectiveCriterias) { - PlayerTeam playersTeam = this.getScoreboard().getPlayersTeam(scoreHolder1.getScoreboardName()); - if (playersTeam != null) { - int id = playersTeam.getColor().getId(); - if (id >= 0 && id < objectiveCriterias.length) { - this.getScoreboard().forAllObjectives(objectiveCriterias[id], scoreHolder, ScoreAccess::increment); + private void handleTeamKill(ScoreHolder scoreholder, ScoreHolder scoreholder1, ObjectiveCriteria[] aiscoreboardcriteria) { + PlayerTeam scoreboardteam = this.getScoreboard().getPlayersTeam(scoreholder1.getScoreboardName()); + + if (scoreboardteam != null) { + int i = scoreboardteam.getColor().getId(); + + if (i >= 0 && i < aiscoreboardcriteria.length) { + // CraftBukkit - Get our scores instead + this.level().getCraftServer().getScoreboardManager().forAllObjectives(aiscoreboardcriteria[i], scoreholder, ScoreAccess::increment); } } + } @Override @@ -698,16 +950,31 @@ return false; } else { boolean flag = this.server.isDedicatedServer() && this.isPvpAllowed() && source.is(DamageTypeTags.IS_FALL); + if (!flag && this.spawnInvulnerableTime > 0 && !source.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) { return false; } else { Entity entity = source.getEntity(); - if (entity instanceof Player player && !this.canHarmPlayer(player)) { - return false; + + if (entity instanceof Player) { + Player entityhuman = (Player) entity; + + if (!this.canHarmPlayer(entityhuman)) { + return false; + } } - if (entity instanceof AbstractArrow abstractArrow && abstractArrow.getOwner() instanceof Player player1 && !this.canHarmPlayer(player1)) { - return false; + if (entity instanceof AbstractArrow) { + AbstractArrow entityarrow = (AbstractArrow) entity; + Entity entity1 = entityarrow.getOwner(); + + if (entity1 instanceof Player) { + Player entityhuman1 = (Player) entity1; + + if (!this.canHarmPlayer(entityhuman1)) { + return false; + } + } } return super.hurt(source, amount); @@ -717,32 +984,46 @@ @Override public boolean canHarmPlayer(Player other) { - return this.isPvpAllowed() && super.canHarmPlayer(other); + return !this.isPvpAllowed() ? false : super.canHarmPlayer(other); } private boolean isPvpAllowed() { - return this.server.isPvpAllowed(); + // CraftBukkit - this.server.isPvpAllowed() -> this.world.pvpMode + return this.level().pvpMode; } @Nullable @Override protected PortalInfo findDimensionEntryPoint(ServerLevel destination) { - PortalInfo portalInfo = super.findDimensionEntryPoint(destination); - if (portalInfo != null && this.level().dimension() == Level.OVERWORLD && destination.dimension() == Level.END) { - Vec3 vec3 = portalInfo.pos.add(0.0, -1.0, 0.0); - return new PortalInfo(vec3, Vec3.ZERO, 90.0F, 0.0F); + PortalInfo shapedetectorshape = super.findDimensionEntryPoint(destination); + destination = (shapedetectorshape == null) ? destination : shapedetectorshape.world; // CraftBukkit + + if (shapedetectorshape != null && this.level().getTypeKey() == LevelStem.OVERWORLD && destination != null && destination.getTypeKey() == LevelStem.END) { // CraftBukkit + Vec3 vec3d = shapedetectorshape.pos.add(0.0D, -1.0D, 0.0D); + + return new PortalInfo(vec3d, Vec3.ZERO, 90.0F, 0.0F, destination, shapedetectorshape.portalEventInfo); // CraftBukkit } else { - return portalInfo; + return shapedetectorshape; } } @Nullable @Override public Entity changeDimension(ServerLevel server) { - this.isChangingDimension = true; - ServerLevel serverLevel = this.serverLevel(); - ResourceKey resourceKey = serverLevel.dimension(); - if (resourceKey == Level.END && server.dimension() == Level.OVERWORLD) { + // CraftBukkit start + return changeDimension(server, TeleportCause.UNKNOWN); + } + + @Nullable + public Entity changeDimension(ServerLevel worldserver, PlayerTeleportEvent.TeleportCause cause) { + // CraftBukkit end + if (this.isSleeping()) return this; // CraftBukkit - SPIGOT-3154 + // this.isChangingDimension = true; // CraftBukkit - Moved down and into PlayerList#changeDimension + ServerLevel worldserver1 = this.serverLevel(); + ResourceKey resourcekey = worldserver1.getTypeKey(); // CraftBukkit + + if (resourcekey == LevelStem.END && worldserver != null && worldserver.getTypeKey() == LevelStem.OVERWORLD) { // CraftBukkit + this.isChangingDimension = true; // CraftBukkit - Moved down from above this.unRide(); this.serverLevel().removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); if (!this.wonGame) { @@ -753,93 +1034,172 @@ return this; } else { - LevelData levelData = server.getLevelData(); - this.connection.send(new ClientboundRespawnPacket(this.createCommonSpawnInfo(server), (byte)3)); - this.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); - PlayerList playerList = this.server.getPlayerList(); - playerList.sendPlayerPermissionLevel(this); - serverLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); + // CraftBukkit start + /* + WorldData worlddata = worldserver.getLevelData(); + + this.connection.send(new PacketPlayOutRespawn(this.createCommonSpawnInfo(worldserver), (byte) 3)); + this.connection.send(new PacketPlayOutServerDifficulty(worlddata.getDifficulty(), worlddata.isDifficultyLocked())); + PlayerList playerlist = this.server.getPlayerList(); + + playerlist.sendPlayerPermissionLevel(this); + worldserver1.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); this.unsetRemoved(); - PortalInfo portalInfo = this.findDimensionEntryPoint(server); - if (portalInfo != null) { - serverLevel.getProfiler().push("moving"); - if (resourceKey == Level.OVERWORLD && server.dimension() == Level.NETHER) { + */ + // CraftBukkit end + PortalInfo shapedetectorshape = this.findDimensionEntryPoint(worldserver); + + if (shapedetectorshape != null) { + worldserver1.getProfiler().push("moving"); + worldserver = shapedetectorshape.world; // CraftBukkit + if (worldserver == null) { } else // CraftBukkit - empty to fall through to null to event + if (resourcekey == LevelStem.OVERWORLD && worldserver.getTypeKey() == LevelStem.NETHER) { // CraftBukkit this.enteredNetherPosition = this.position(); - } else if (server.dimension() == Level.END) { - this.createEndPlatform(server, BlockPos.containing(portalInfo.pos)); + } else if (worldserver.getTypeKey() == LevelStem.END && shapedetectorshape.portalEventInfo != null && shapedetectorshape.portalEventInfo.getCanCreatePortal()) { // CraftBukkit + this.createEndPlatform(worldserver, BlockPos.containing(shapedetectorshape.pos)); } + // CraftBukkit start + } else { + return null; + } + Location enter = this.getBukkitEntity().getLocation(); + Location exit = (worldserver == null) ? null : CraftLocation.toBukkit(shapedetectorshape.pos, worldserver.getWorld(), shapedetectorshape.yRot, shapedetectorshape.xRot); + PlayerTeleportEvent tpEvent = new PlayerTeleportEvent(this.getBukkitEntity(), enter, exit, cause); + Bukkit.getServer().getPluginManager().callEvent(tpEvent); + if (tpEvent.isCancelled() || tpEvent.getTo() == null) { + return null; + } + exit = tpEvent.getTo(); + worldserver = ((CraftWorld) exit.getWorld()).getHandle(); + // CraftBukkit end - serverLevel.getProfiler().pop(); - serverLevel.getProfiler().push("placing"); - this.setServerLevel(server); - this.connection.teleport(portalInfo.pos.x, portalInfo.pos.y, portalInfo.pos.z, portalInfo.yRot, portalInfo.xRot); + worldserver1.getProfiler().pop(); + worldserver1.getProfiler().push("placing"); + if (true) { // CraftBukkit + this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds + + this.connection.send(new ClientboundRespawnPacket(this.createCommonSpawnInfo(worldserver), (byte) 3)); + this.connection.send(new ClientboundChangeDifficultyPacket(this.level().getDifficulty(), this.level().getLevelData().isDifficultyLocked())); + PlayerList playerlist = this.server.getPlayerList(); + + playerlist.sendPlayerPermissionLevel(this); + worldserver1.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); + this.unsetRemoved(); + + // CraftBukkit end + this.setServerLevel(worldserver); + this.connection.teleport(exit); // CraftBukkit - use internal teleport without event this.connection.resetPosition(); - server.addDuringPortalTeleport(this); - serverLevel.getProfiler().pop(); - this.triggerDimensionChangeTriggers(serverLevel); + worldserver.addDuringPortalTeleport(this); + worldserver1.getProfiler().pop(); + this.triggerDimensionChangeTriggers(worldserver1); this.connection.send(new ClientboundPlayerAbilitiesPacket(this.getAbilities())); - playerList.sendLevelInfo(this, server); - playerList.sendAllPlayerInfo(this); + playerlist.sendLevelInfo(this, worldserver); + playerlist.sendAllPlayerInfo(this); + Iterator iterator = this.getActiveEffects().iterator(); - for (MobEffectInstance mobEffectInstance : this.getActiveEffects()) { - this.connection.send(new ClientboundUpdateMobEffectPacket(this.getId(), mobEffectInstance)); + while (iterator.hasNext()) { + MobEffectInstance mobeffect = (MobEffectInstance) iterator.next(); + + this.connection.send(new ClientboundUpdateMobEffectPacket(this.getId(), mobeffect)); } this.connection.send(new ClientboundLevelEventPacket(1032, BlockPos.ZERO, 0, false)); this.lastSentExp = -1; this.lastSentHealth = -1.0F; this.lastSentFood = -1; + + // CraftBukkit start + PlayerChangedWorldEvent changeEvent = new PlayerChangedWorldEvent(this.getBukkitEntity(), worldserver1.getWorld()); + this.level().getCraftServer().getPluginManager().callEvent(changeEvent); + // CraftBukkit end } return this; } } + // CraftBukkit start + @Override + protected CraftPortalEvent callPortalEvent(Entity entity, ServerLevel exitWorldServer, Vec3 exitPosition, TeleportCause cause, int searchRadius, int creationRadius) { + Location enter = this.getBukkitEntity().getLocation(); + Location exit = CraftLocation.toBukkit(exitPosition, exitWorldServer.getWorld(), getYRot(), getXRot()); + PlayerPortalEvent event = new PlayerPortalEvent(this.getBukkitEntity(), enter, exit, cause, searchRadius, true, creationRadius); + Bukkit.getServer().getPluginManager().callEvent(event); + if (event.isCancelled() || event.getTo() == null || event.getTo().getWorld() == null) { + return null; + } + return new CraftPortalEvent(event); + } + // CraftBukkit end + private void createEndPlatform(ServerLevel level, BlockPos pos) { - BlockPos.MutableBlockPos mutableBlockPos = pos.mutable(); + BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable(); + org.bukkit.craftbukkit.util.BlockStateListPopulator blockList = new org.bukkit.craftbukkit.util.BlockStateListPopulator(level); // CraftBukkit - for (int i = -2; i <= 2; i++) { - for (int i1 = -2; i1 <= 2; i1++) { - for (int i2 = -1; i2 < 3; i2++) { - BlockState blockState = i2 == -1 ? Blocks.OBSIDIAN.defaultBlockState() : Blocks.AIR.defaultBlockState(); - level.setBlockAndUpdate(mutableBlockPos.set(pos).move(i1, i2, i), blockState); + for (int i = -2; i <= 2; ++i) { + for (int j = -2; j <= 2; ++j) { + for (int k = -1; k < 3; ++k) { + IBlockData iblockdata = k == -1 ? Blocks.OBSIDIAN.defaultBlockState() : Blocks.AIR.defaultBlockState(); + + blockList.setBlock(blockposition_mutableblockposition.set(pos).move(j, k, i), iblockdata, 3); // CraftBukkit } } } + // CraftBukkit start - call portal event + org.bukkit.event.world.PortalCreateEvent portalEvent = new org.bukkit.event.world.PortalCreateEvent((List) (List) blockList.getList(), level.getWorld(), this.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.END_PLATFORM); + level.getCraftServer().getPluginManager().callEvent(portalEvent); + if (!portalEvent.isCancelled()) { + blockList.updateList(); + } + // CraftBukkit end + } @Override - protected Optional getExitPortal(ServerLevel destination, BlockPos findFrom, boolean isToNether, WorldBorder worldBorder) { - Optional optional = super.getExitPortal(destination, findFrom, isToNether, worldBorder); - if (optional.isPresent()) { + protected Optional getExitPortal(ServerLevel worldserver, BlockPos blockposition, boolean flag, WorldBorder worldborder, int searchRadius, boolean canCreatePortal, int createRadius) { // CraftBukkit + Optional optional = super.getExitPortal(worldserver, blockposition, flag, worldborder, searchRadius, canCreatePortal, createRadius); // CraftBukkit + + if (optional.isPresent() || !canCreatePortal) { // CraftBukkit return optional; } else { - Direction.Axis axis = this.level().getBlockState(this.portalEntrancePos).getOptionalValue(NetherPortalBlock.AXIS).orElse(Direction.Axis.X); - Optional optional1 = destination.getPortalForcer().createPortal(findFrom, axis); + Direction.Axis enumdirection_enumaxis = (Direction.Axis) this.level().getBlockState(this.portalEntrancePos).getOptionalValue(NetherPortalBlock.AXIS).orElse(Direction.Axis.X); + Optional optional1 = worldserver.getPortalForcer().createPortal(blockposition, enumdirection_enumaxis, this, createRadius); // CraftBukkit + if (optional1.isEmpty()) { - LOGGER.error("Unable to create a portal, likely target out of worldborder"); + // EntityPlayer.LOGGER.error("Unable to create a portal, likely target out of worldborder"); // CraftBukkit } return optional1; } } - private void triggerDimensionChangeTriggers(ServerLevel level) { - ResourceKey resourceKey = level.dimension(); - ResourceKey resourceKey1 = this.level().dimension(); - CriteriaTriggers.CHANGED_DIMENSION.trigger(this, resourceKey, resourceKey1); - if (resourceKey == Level.NETHER && resourceKey1 == Level.OVERWORLD && this.enteredNetherPosition != null) { + public void triggerDimensionChangeTriggers(ServerLevel level) { + ResourceKey resourcekey = level.dimension(); + ResourceKey resourcekey1 = this.level().dimension(); + // CraftBukkit start + ResourceKey maindimensionkey = CraftDimensionUtil.getMainDimensionKey(level); + ResourceKey maindimensionkey1 = CraftDimensionUtil.getMainDimensionKey(this.level()); + + CriteriaTriggers.CHANGED_DIMENSION.trigger(this, maindimensionkey, maindimensionkey1); + if (maindimensionkey != resourcekey || maindimensionkey1 != resourcekey1) { + CriteriaTriggers.CHANGED_DIMENSION.trigger(this, resourcekey, resourcekey1); + } + + if (maindimensionkey == Level.NETHER && maindimensionkey1 == Level.OVERWORLD && this.enteredNetherPosition != null) { + // CraftBukkit end CriteriaTriggers.NETHER_TRAVEL.trigger(this, this.enteredNetherPosition); } - if (resourceKey1 != Level.NETHER) { + if (maindimensionkey1 != Level.NETHER) { // CraftBukkit this.enteredNetherPosition = null; } + } @Override public boolean broadcastToPlayer(ServerPlayer player) { - return player.isSpectator() ? this.getCamera() == this : !this.isSpectator() && super.broadcastToPlayer(player); + return player.isSpectator() ? this.getCamera() == this : (this.isSpectator() ? false : super.broadcastToPlayer(player)); } @Override @@ -848,49 +1208,77 @@ this.containerMenu.broadcastChanges(); } - @Override - public Either startSleepInBed(BlockPos at) { - Direction direction = this.level().getBlockState(at).getValue(HorizontalDirectionalBlock.FACING); - if (this.isSleeping() || !this.isAlive()) { - return Either.left(Player.BedSleepingProblem.OTHER_PROBLEM); - } else if (!this.level().dimensionType().natural()) { - return Either.left(Player.BedSleepingProblem.NOT_POSSIBLE_HERE); - } else if (!this.bedInRange(at, direction)) { - return Either.left(Player.BedSleepingProblem.TOO_FAR_AWAY); - } else if (this.bedBlocked(at, direction)) { - return Either.left(Player.BedSleepingProblem.OBSTRUCTED); - } else { - this.setRespawnPosition(this.level().dimension(), at, this.getYRot(), false, true); - if (this.level().isDay()) { - return Either.left(Player.BedSleepingProblem.NOT_POSSIBLE_NOW); + // CraftBukkit start - moved bed result checks from below into separate method + private Either getBedResult(BlockPos blockposition, Direction enumdirection) { + if (!this.isSleeping() && this.isAlive()) { + if (!this.level().dimensionType().natural() || !this.level().dimensionType().bedWorks()) { + return Either.left(Player.BedSleepingProblem.NOT_POSSIBLE_HERE); + } else if (!this.bedInRange(blockposition, enumdirection)) { + return Either.left(Player.BedSleepingProblem.TOO_FAR_AWAY); + } else if (this.bedBlocked(blockposition, enumdirection)) { + return Either.left(Player.BedSleepingProblem.OBSTRUCTED); } else { - if (!this.isCreative()) { - double d = 8.0; - double d1 = 5.0; - Vec3 vec3 = Vec3.atBottomCenterOf(at); - List entitiesOfClass = this.level() - .getEntitiesOfClass( - Monster.class, - new AABB(vec3.x() - 8.0, vec3.y() - 5.0, vec3.z() - 8.0, vec3.x() + 8.0, vec3.y() + 5.0, vec3.z() + 8.0), - monster -> monster.isPreventingPlayerRest(this) - ); - if (!entitiesOfClass.isEmpty()) { - return Either.left(Player.BedSleepingProblem.NOT_SAFE); + this.setRespawnPosition(this.level().dimension(), blockposition, this.getYRot(), false, true, PlayerSpawnChangeEvent.Cause.BED); // CraftBukkit + if (this.level().isDay()) { + return Either.left(Player.BedSleepingProblem.NOT_POSSIBLE_NOW); + } else { + if (!this.isCreative()) { + double d0 = 8.0D; + double d1 = 5.0D; + Vec3 vec3d = Vec3.atBottomCenterOf(blockposition); + List list = this.level().getEntitiesOfClass(Monster.class, new AABB(vec3d.x() - 8.0D, vec3d.y() - 5.0D, vec3d.z() - 8.0D, vec3d.x() + 8.0D, vec3d.y() + 5.0D, vec3d.z() + 8.0D), (entitymonster) -> { + return entitymonster.isPreventingPlayerRest(this); + }); + + if (!list.isEmpty()) { + return Either.left(Player.BedSleepingProblem.NOT_SAFE); + } } - } - Either either = super.startSleepInBed(at).ifRight(unit -> { - this.awardStat(Stats.SLEEP_IN_BED); - CriteriaTriggers.SLEPT_IN_BED.trigger(this); - }); - if (!this.serverLevel().canSleepThroughNights()) { - this.displayClientMessage(Component.translatable("sleep.not_possible"), true); + return Either.right(Unit.INSTANCE); } + } + } else { + return Either.left(Player.BedSleepingProblem.OTHER_PROBLEM); + } + } - ((ServerLevel)this.level()).updateSleepingPlayerList(); - return either; + @Override + public Either startSleepInBed(BlockPos blockposition, boolean force) { + Direction enumdirection = (Direction) this.level().getBlockState(blockposition).getValue(HorizontalDirectionalBlock.FACING); + Either bedResult = this.getBedResult(blockposition, enumdirection); + + if (bedResult.left().orElse(null) == Player.BedSleepingProblem.OTHER_PROBLEM) { + return bedResult; // return immediately if the result is not bypassable by plugins + } + + if (force) { + bedResult = Either.right(Unit.INSTANCE); + } + + bedResult = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBedEnterEvent(this, blockposition, bedResult); + if (bedResult.left().isPresent()) { + return bedResult; + } + + { + { + { + Either either = super.startSleepInBed(blockposition, force).ifRight((unit) -> { + this.awardStat(Stats.SLEEP_IN_BED); + CriteriaTriggers.SLEPT_IN_BED.trigger(this); + }); + + if (!this.serverLevel().canSleepThroughNights()) { + this.displayClientMessage(Component.translatable("sleep.not_possible"), true); + } + + ((ServerLevel) this.level()).updateSleepingPlayerList(); + return either; + } } } + // CraftBukkit end } @Override @@ -904,31 +1292,52 @@ } private boolean isReachableBedBlock(BlockPos pos) { - Vec3 vec3 = Vec3.atBottomCenterOf(pos); - return Math.abs(this.getX() - vec3.x()) <= 3.0 && Math.abs(this.getY() - vec3.y()) <= 2.0 && Math.abs(this.getZ() - vec3.z()) <= 3.0; + Vec3 vec3d = Vec3.atBottomCenterOf(pos); + + return Math.abs(this.getX() - vec3d.x()) <= 3.0D && Math.abs(this.getY() - vec3d.y()) <= 2.0D && Math.abs(this.getZ() - vec3d.z()) <= 3.0D; } private boolean bedBlocked(BlockPos pos, Direction direction) { - BlockPos blockPos = pos.above(); - return !this.freeAt(blockPos) || !this.freeAt(blockPos.relative(direction.getOpposite())); + BlockPos blockposition1 = pos.above(); + + return !this.freeAt(blockposition1) || !this.freeAt(blockposition1.relative(direction.getOpposite())); } @Override public void stopSleepInBed(boolean wakeImmediately, boolean updateLevelForSleepingPlayers) { + if (!this.isSleeping()) return; // CraftBukkit - Can't leave bed if not in one! + // CraftBukkit start - fire PlayerBedLeaveEvent + CraftPlayer player = this.getBukkitEntity(); + BlockPos bedPosition = this.getSleepingPos().orElse(null); + + org.bukkit.block.Block bed; + if (bedPosition != null) { + bed = this.level().getWorld().getBlockAt(bedPosition.getX(), bedPosition.getY(), bedPosition.getZ()); + } else { + bed = this.level().getWorld().getBlockAt(player.getLocation()); + } + + PlayerBedLeaveEvent event = new PlayerBedLeaveEvent(player, bed, true); + this.level().getCraftServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + // CraftBukkit end if (this.isSleeping()) { this.serverLevel().getChunkSource().broadcastAndSend(this, new ClientboundAnimatePacket(this, 2)); } super.stopSleepInBed(wakeImmediately, updateLevelForSleepingPlayers); if (this.connection != null) { - this.connection.teleport(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); + this.connection.teleport(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot(), TeleportCause.EXIT_BED); // CraftBukkit } + } @Override - public void dismountTo(double x, double y, double z) { + public void dismountTo(double x, double d1, double y) { this.removeVehicle(); - this.setPos(x, y, z); + this.setPos(x, d1, y); } @Override @@ -937,21 +1346,22 @@ } @Override - protected void checkFallDamage(double y, boolean onGround, BlockState state, BlockPos pos) { - } + protected void checkFallDamage(double y, boolean flag, IBlockData onGround, BlockPos state) {} @Override protected void onChangedBlock(BlockPos pos) { if (!this.isSpectator()) { super.onChangedBlock(pos); } + } - public void doCheckFallDamage(double movementX, double movementY, double movementZ, boolean onGround) { + public void doCheckFallDamage(double movementX, double d1, double movementY, boolean flag) { if (!this.touchingUnloadedChunk()) { - this.checkSupportingBlock(onGround, new Vec3(movementX, movementY, movementZ)); - BlockPos onPosLegacy = this.getOnPosLegacy(); - super.checkFallDamage(movementY, onGround, this.level().getBlockState(onPosLegacy), onPosLegacy); + this.checkSupportingBlock(flag, new Vec3(movementX, d1, movementY)); + BlockPos blockposition = this.getOnPosLegacy(); + + super.checkFallDamage(d1, flag, this.level().getBlockState(blockposition), blockposition); } } @@ -960,6 +1370,7 @@ if (this.level().tickRateManager().runsNormally()) { super.pushEntities(); } + } @Override @@ -968,32 +1379,57 @@ this.connection.send(new ClientboundOpenSignEditorPacket(signEntity.getBlockPos(), isFrontText)); } - private void nextContainerCounter() { + public int nextContainerCounter() { // CraftBukkit - void -> int this.containerCounter = this.containerCounter % 100 + 1; + return containerCounter; // CraftBukkit } @Override - public OptionalInt openMenu(@Nullable MenuProvider menu) { + public OptionalInt openMenu(@Nullable ITileInventory menu) { if (menu == null) { return OptionalInt.empty(); } else { + // CraftBukkit start - SPIGOT-6552: Handle inventory closing in CraftEventFactory#callInventoryOpenEvent(...) + /* if (this.containerMenu != this.inventoryMenu) { this.closeContainer(); } + */ + // CraftBukkit end this.nextContainerCounter(); - AbstractContainerMenu abstractContainerMenu = menu.createMenu(this.containerCounter, this.getInventory(), this); - if (abstractContainerMenu == null) { + AbstractContainerMenu container = menu.createMenu(this.containerCounter, this.getInventory(), this); + + // CraftBukkit start - Inventory open hook + if (container != null) { + container.setTitle(menu.getDisplayName()); + + boolean cancelled = false; + container = CraftEventFactory.callInventoryOpenEvent(this, container, cancelled); + if (container == null && !cancelled) { // Let pre-cancelled events fall through + // SPIGOT-5263 - close chest if cancelled + if (menu instanceof Container) { + ((Container) menu).stopOpen(this); + } else if (menu instanceof ChestBlock.DoubleInventory) { + // SPIGOT-5355 - double chests too :( + ((ChestBlock.DoubleInventory) menu).inventorylargechest.stopOpen(this); + } + return OptionalInt.empty(); + } + } + // CraftBukkit end + if (container == null) { if (this.isSpectator()) { this.displayClientMessage(Component.translatable("container.spectatorCantOpen").withStyle(ChatFormatting.RED), true); } return OptionalInt.empty(); } else { - this.connection - .send(new ClientboundOpenScreenPacket(abstractContainerMenu.containerId, abstractContainerMenu.getType(), menu.getDisplayName())); - this.initMenu(abstractContainerMenu); - this.containerMenu = abstractContainerMenu; + // CraftBukkit start + this.containerMenu = container; + this.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), container.getTitle())); + // CraftBukkit end + this.initMenu(container); return OptionalInt.of(this.containerCounter); } } @@ -1006,18 +1442,29 @@ @Override public void openHorseInventory(AbstractHorse horse, Container inventory) { + // CraftBukkit start - Inventory open hook + this.nextContainerCounter(); + AbstractContainerMenu container = new HorseInventoryMenu(this.containerCounter, this.getInventory(), inventory, horse); + container.setTitle(horse.getDisplayName()); + container = CraftEventFactory.callInventoryOpenEvent(this, container); + + if (container == null) { + inventory.stopOpen(this); + return; + } + // CraftBukkit end if (this.containerMenu != this.inventoryMenu) { this.closeContainer(); } - this.nextContainerCounter(); + // this.nextContainerCounter(); // CraftBukkit - moved up this.connection.send(new ClientboundHorseScreenOpenPacket(this.containerCounter, inventory.getContainerSize(), horse.getId())); - this.containerMenu = new HorseInventoryMenu(this.containerCounter, this.getInventory(), inventory, horse); + this.containerMenu = container; // CraftBukkit this.initMenu(this.containerMenu); } @Override - public void openItemGui(ItemStack stack, InteractionHand hand) { + public void openItemGui(ItemStack stack, EnumHand hand) { if (stack.is(Items.WRITTEN_BOOK)) { if (WrittenBookItem.resolveBookComponents(stack, this.createCommandSourceStack(), this)) { this.containerMenu.broadcastChanges(); @@ -1025,6 +1472,7 @@ this.connection.send(new ClientboundOpenBookPacket(hand)); } + } @Override @@ -1034,6 +1482,7 @@ @Override public void closeContainer() { + CraftEventFactory.handleInventoryCloseEvent(this); // CraftBukkit this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId)); this.doCloseContainer(); } @@ -1056,110 +1505,130 @@ } this.jumping = jumping; + // CraftBukkit start + if (sneaking != this.isShiftKeyDown()) { + PlayerToggleSneakEvent event = new PlayerToggleSneakEvent(this.getBukkitEntity(), sneaking); + this.server.server.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return; + } + } + // CraftBukkit end this.setShiftKeyDown(sneaking); } + } @Override public void travel(Vec3 travelVector) { - double x = this.getX(); - double y = this.getY(); - double z = this.getZ(); + double d0 = this.getX(); + double d1 = this.getY(); + double d2 = this.getZ(); + super.travel(travelVector); - this.checkMovementStatistics(this.getX() - x, this.getY() - y, this.getZ() - z); + this.checkMovementStatistics(this.getX() - d0, this.getY() - d1, this.getZ() - d2); } @Override public void rideTick() { - double x = this.getX(); - double y = this.getY(); - double z = this.getZ(); + double d0 = this.getX(); + double d1 = this.getY(); + double d2 = this.getZ(); + super.rideTick(); - this.checkRidingStatistics(this.getX() - x, this.getY() - y, this.getZ() - z); + this.checkRidingStatistics(this.getX() - d0, this.getY() - d1, this.getZ() - d2); } - public void checkMovementStatistics(double d, double d1, double d2) { - if (!this.isPassenger() && !didNotMove(d, d1, d2)) { + public void checkMovementStatistics(double d0, double d1, double d2) { + if (!this.isPassenger() && !didNotMove(d0, d1, d2)) { + int i; + if (this.isSwimming()) { - int rounded = Math.round((float)Math.sqrt(d * d + d1 * d1 + d2 * d2) * 100.0F); - if (rounded > 0) { - this.awardStat(Stats.SWIM_ONE_CM, rounded); - this.causeFoodExhaustion(0.01F * (float)rounded * 0.01F); + i = Math.round((float) Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2) * 100.0F); + if (i > 0) { + this.awardStat(Stats.SWIM_ONE_CM, i); + this.causeFoodExhaustion(0.01F * (float) i * 0.01F, EntityExhaustionEvent.ExhaustionReason.SWIM); // CraftBukkit - EntityExhaustionEvent } } else if (this.isEyeInFluid(FluidTags.WATER)) { - int rounded = Math.round((float)Math.sqrt(d * d + d1 * d1 + d2 * d2) * 100.0F); - if (rounded > 0) { - this.awardStat(Stats.WALK_UNDER_WATER_ONE_CM, rounded); - this.causeFoodExhaustion(0.01F * (float)rounded * 0.01F); + i = Math.round((float) Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2) * 100.0F); + if (i > 0) { + this.awardStat(Stats.WALK_UNDER_WATER_ONE_CM, i); + this.causeFoodExhaustion(0.01F * (float) i * 0.01F, EntityExhaustionEvent.ExhaustionReason.WALK_UNDERWATER); // CraftBukkit - EntityExhaustionEvent } } else if (this.isInWater()) { - int rounded = Math.round((float)Math.sqrt(d * d + d2 * d2) * 100.0F); - if (rounded > 0) { - this.awardStat(Stats.WALK_ON_WATER_ONE_CM, rounded); - this.causeFoodExhaustion(0.01F * (float)rounded * 0.01F); + i = Math.round((float) Math.sqrt(d0 * d0 + d2 * d2) * 100.0F); + if (i > 0) { + this.awardStat(Stats.WALK_ON_WATER_ONE_CM, i); + this.causeFoodExhaustion(0.01F * (float) i * 0.01F, EntityExhaustionEvent.ExhaustionReason.WALK_ON_WATER); // CraftBukkit - EntityExhaustionEvent } } else if (this.onClimbable()) { - if (d1 > 0.0) { - this.awardStat(Stats.CLIMB_ONE_CM, (int)Math.round(d1 * 100.0)); + if (d1 > 0.0D) { + this.awardStat(Stats.CLIMB_ONE_CM, (int) Math.round(d1 * 100.0D)); } } else if (this.onGround()) { - int rounded = Math.round((float)Math.sqrt(d * d + d2 * d2) * 100.0F); - if (rounded > 0) { + i = Math.round((float) Math.sqrt(d0 * d0 + d2 * d2) * 100.0F); + if (i > 0) { if (this.isSprinting()) { - this.awardStat(Stats.SPRINT_ONE_CM, rounded); - this.causeFoodExhaustion(0.1F * (float)rounded * 0.01F); + this.awardStat(Stats.SPRINT_ONE_CM, i); + this.causeFoodExhaustion(0.1F * (float) i * 0.01F, EntityExhaustionEvent.ExhaustionReason.SPRINT); // CraftBukkit - EntityExhaustionEvent } else if (this.isCrouching()) { - this.awardStat(Stats.CROUCH_ONE_CM, rounded); - this.causeFoodExhaustion(0.0F * (float)rounded * 0.01F); + this.awardStat(Stats.CROUCH_ONE_CM, i); + this.causeFoodExhaustion(0.0F * (float) i * 0.01F, EntityExhaustionEvent.ExhaustionReason.CROUCH); // CraftBukkit - EntityExhaustionEvent } else { - this.awardStat(Stats.WALK_ONE_CM, rounded); - this.causeFoodExhaustion(0.0F * (float)rounded * 0.01F); + this.awardStat(Stats.WALK_ONE_CM, i); + this.causeFoodExhaustion(0.0F * (float) i * 0.01F, EntityExhaustionEvent.ExhaustionReason.WALK); // CraftBukkit - EntityExhaustionEvent } } } else if (this.isFallFlying()) { - int rounded = Math.round((float)Math.sqrt(d * d + d1 * d1 + d2 * d2) * 100.0F); - this.awardStat(Stats.AVIATE_ONE_CM, rounded); + i = Math.round((float) Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2) * 100.0F); + this.awardStat(Stats.AVIATE_ONE_CM, i); } else { - int rounded = Math.round((float)Math.sqrt(d * d + d2 * d2) * 100.0F); - if (rounded > 25) { - this.awardStat(Stats.FLY_ONE_CM, rounded); + i = Math.round((float) Math.sqrt(d0 * d0 + d2 * d2) * 100.0F); + if (i > 25) { + this.awardStat(Stats.FLY_ONE_CM, i); } } + } } - private void checkRidingStatistics(double d, double d1, double d2) { - if (this.isPassenger() && !didNotMove(d, d1, d2)) { - int rounded = Math.round((float)Math.sqrt(d * d + d1 * d1 + d2 * d2) * 100.0F); - Entity vehicle = this.getVehicle(); - if (vehicle instanceof AbstractMinecart) { - this.awardStat(Stats.MINECART_ONE_CM, rounded); - } else if (vehicle instanceof Boat) { - this.awardStat(Stats.BOAT_ONE_CM, rounded); - } else if (vehicle instanceof Pig) { - this.awardStat(Stats.PIG_ONE_CM, rounded); - } else if (vehicle instanceof AbstractHorse) { - this.awardStat(Stats.HORSE_ONE_CM, rounded); - } else if (vehicle instanceof Strider) { - this.awardStat(Stats.STRIDER_ONE_CM, rounded); + private void checkRidingStatistics(double d0, double d1, double d2) { + if (this.isPassenger() && !didNotMove(d0, d1, d2)) { + int i = Math.round((float) Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2) * 100.0F); + Entity entity = this.getVehicle(); + + if (entity instanceof AbstractMinecart) { + this.awardStat(Stats.MINECART_ONE_CM, i); + } else if (entity instanceof Boat) { + this.awardStat(Stats.BOAT_ONE_CM, i); + } else if (entity instanceof Pig) { + this.awardStat(Stats.PIG_ONE_CM, i); + } else if (entity instanceof AbstractHorse) { + this.awardStat(Stats.HORSE_ONE_CM, i); + } else if (entity instanceof Strider) { + this.awardStat(Stats.STRIDER_ONE_CM, i); } + } } - private static boolean didNotMove(double d, double d1, double d2) { - return d == 0.0 && d1 == 0.0 && d2 == 0.0; + private static boolean didNotMove(double d0, double d1, double d2) { + return d0 == 0.0D && d1 == 0.0D && d2 == 0.0D; } @Override public void awardStat(Stat stat, int amount) { this.stats.increment(this, stat, amount); - this.getScoreboard().forAllObjectives(stat, this, scoreAccess -> scoreAccess.add(amount)); + this.level().getCraftServer().getScoreboardManager().forAllObjectives(stat, this, (scoreaccess) -> { + scoreaccess.add(amount); + }); } @Override public void resetStat(Stat stat) { this.stats.setValue(this, stat, 0); - this.getScoreboard().forAllObjectives(stat, this, ScoreAccess::reset); + this.level().getCraftServer().getScoreboardManager().forAllObjectives(stat, this, ScoreAccess::reset); // CraftBukkit - Get our scores instead } @Override @@ -1168,15 +1637,16 @@ } @Override - public void triggerRecipeCrafted(RecipeHolder recipeHolder, List list) { - CriteriaTriggers.RECIPE_CRAFTED.trigger(this, recipeHolder.id(), list); + public void triggerRecipeCrafted(RecipeHolder recipeholder, List list) { + CriteriaTriggers.RECIPE_CRAFTED.trigger(this, recipeholder.id(), list); } @Override public void awardRecipesByKey(List list) { - List> list1 = list.stream() - .flatMap(resourceLocation -> this.server.getRecipeManager().byKey(resourceLocation).stream()) - .collect(Collectors.toList()); + List> list1 = (List) list.stream().flatMap((minecraftkey) -> { + return this.server.getRecipeManager().byKey(minecraftkey).stream(); + }).collect(Collectors.toList()); + this.awardRecipes(list1); } @@ -1197,6 +1667,7 @@ if (this.isSleeping()) { this.stopSleepInBed(true, false); } + } public boolean hasDisconnected() { @@ -1205,6 +1676,7 @@ public void resetSentInfo() { this.lastSentHealth = -1.0E8F; + this.lastSentExp = -1; // CraftBukkit - Added to reset } @Override @@ -1215,9 +1687,10 @@ @Override protected void completeUsingItem() { if (!this.useItem.isEmpty() && this.isUsingItem()) { - this.connection.send(new ClientboundEntityEventPacket(this, (byte)9)); + this.connection.send(new ClientboundEntityEventPacket(this, (byte) 9)); super.completeUsingItem(); } + } @Override @@ -1227,8 +1700,9 @@ } public void lookAt(EntityAnchorArgument.Anchor fromAnchor, Entity entity, EntityAnchorArgument.Anchor toAnchor) { - Vec3 vec3 = toAnchor.apply(entity); - super.lookAt(fromAnchor, vec3); + Vec3 vec3d = toAnchor.apply(entity); + + super.lookAt(fromAnchor, vec3d); this.connection.send(new ClientboundPlayerLookAtPacket(fromAnchor, entity, toAnchor)); } @@ -1256,11 +1730,11 @@ this.enchantmentSeed = that.enchantmentSeed; this.enderChestInventory = that.enderChestInventory; - this.getEntityData().set(DATA_PLAYER_MODE_CUSTOMISATION, that.getEntityData().get(DATA_PLAYER_MODE_CUSTOMISATION)); + this.getEntityData().set(ServerPlayer.DATA_PLAYER_MODE_CUSTOMISATION, (Byte) that.getEntityData().get(ServerPlayer.DATA_PLAYER_MODE_CUSTOMISATION)); this.lastSentExp = -1; this.lastSentHealth = -1.0F; this.lastSentFood = -1; - this.recipeBook.copyOverData(that.recipeBook); + // this.recipeBook.copyOverData(entityplayer.recipeBook); // CraftBukkit this.seenCredits = that.seenCredits; this.enteredNetherPosition = that.enteredNetherPosition; this.chunkTrackingView = that.chunkTrackingView; @@ -1296,41 +1770,48 @@ this.levitationStartPos = null; } - CriteriaTriggers.EFFECTS_CHANGED.trigger(this, null); + CriteriaTriggers.EFFECTS_CHANGED.trigger(this, (Entity) null); } @Override - public void teleportTo(double x, double y, double z) { - this.connection.teleport(x, y, z, this.getYRot(), this.getXRot(), RelativeMovement.ROTATION); + public void teleportTo(double x, double d1, double y) { + this.connection.teleport(x, d1, y, this.getYRot(), this.getXRot(), RelativeMovement.ROTATION); } @Override - public void teleportRelative(double dx, double dy, double dz) { - this.connection.teleport(this.getX() + dx, this.getY() + dy, this.getZ() + dz, this.getYRot(), this.getXRot(), RelativeMovement.ALL); + public void teleportRelative(double dx, double d1, double dy) { + this.connection.teleport(this.getX() + dx, this.getY() + d1, this.getZ() + dy, this.getYRot(), this.getXRot(), RelativeMovement.ALL); } @Override - public boolean teleportTo(ServerLevel level, double x, double y, double z, Set relativeMovements, float yRot, float xRot) { - ChunkPos chunkPos = new ChunkPos(BlockPos.containing(x, y, z)); - level.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, chunkPos, 1, this.getId()); + public boolean teleportTo(ServerLevel level, double x, double d1, double y, Set set, float z, float f1) { + // CraftBukkit start + return teleportTo(level, x, d1, y, set, z, f1, TeleportCause.UNKNOWN); + } + + public boolean teleportTo(ServerLevel worldserver, double d0, double d1, double d2, Set set, float f, float f1, TeleportCause cause) { + // CraftBukkit end + ChunkPos chunkcoordintpair = new ChunkPos(BlockPos.containing(d0, d1, d2)); + + worldserver.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, chunkcoordintpair, 1, this.getId()); this.stopRiding(); if (this.isSleeping()) { this.stopSleepInBed(true, true); } - if (level == this.level()) { - this.connection.teleport(x, y, z, yRot, xRot, relativeMovements); + if (worldserver == this.level()) { + this.connection.teleport(d0, d1, d2, f, f1, set, cause); // CraftBukkit } else { - this.teleportTo(level, x, y, z, yRot, xRot); + this.teleportTo(worldserver, d0, d1, d2, f, f1, cause); // CraftBukkit } - this.setYHeadRot(yRot); + this.setYHeadRot(f); return true; } @Override - public void moveTo(double x, double y, double z) { - super.moveTo(x, y, z); + public void moveTo(double x, double d1, double y) { + super.moveTo(x, d1, y); this.connection.resetPosition(); } @@ -1353,14 +1834,14 @@ } public ServerLevel serverLevel() { - return (ServerLevel)this.level(); + return (ServerLevel) this.level(); } public boolean setGameMode(GameType gameMode) { if (!this.gameMode.changeGameModeForPlayer(gameMode)) { return false; } else { - this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, (float)gameMode.getId())); + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, (float) gameMode.getId())); if (gameMode == GameType.SPECTATOR) { this.removeEntitiesOnShoulder(); this.stopRiding(); @@ -1391,24 +1872,17 @@ public void sendSystemMessage(Component component, boolean bypassHiddenChat) { if (this.acceptsSystemMessages(bypassHiddenChat)) { - this.connection - .send( - new ClientboundSystemChatPacket(component, bypassHiddenChat), - PacketSendListener.exceptionallySend( - () -> { - if (this.acceptsSystemMessages(false)) { - int i = 256; - String string = component.getString(256); - Component component1 = Component.literal(string).withStyle(ChatFormatting.YELLOW); - return new ClientboundSystemChatPacket( - Component.translatable("multiplayer.message_not_delivered", component1).withStyle(ChatFormatting.RED), false - ); - } else { - return null; - } - } - ) - ); + this.connection.send(new ClientboundSystemChatPacket(component, bypassHiddenChat), PacketSendListener.exceptionallySend(() -> { + if (this.acceptsSystemMessages(false)) { + boolean flag1 = true; + String s = component.getString(256); + MutableComponent ichatmutablecomponent = Component.literal(s).withStyle(ChatFormatting.YELLOW); + + return new ClientboundSystemChatPacket(Component.translatable("multiplayer.message_not_delivered", ichatmutablecomponent).withStyle(ChatFormatting.RED), false); + } else { + return null; + } + })); } } @@ -1416,31 +1890,47 @@ if (this.acceptsChatMessages()) { message.sendToPlayer(this, filtered, boundType); } + } public String getIpAddress() { - return this.connection.getRemoteAddress() instanceof InetSocketAddress inetSocketAddress - ? InetAddresses.toAddrString(inetSocketAddress.getAddress()) - : ""; + SocketAddress socketaddress = this.connection.getRemoteAddress(); + + if (socketaddress instanceof InetSocketAddress) { + InetSocketAddress inetsocketaddress = (InetSocketAddress) socketaddress; + + return InetAddresses.toAddrString(inetsocketaddress.getAddress()); + } else { + return ""; + } } - public void updateOptions(ClientInformation clientInformation) { - this.language = clientInformation.language(); - this.requestedViewDistance = clientInformation.viewDistance(); - this.chatVisibility = clientInformation.chatVisibility(); - this.canChatColor = clientInformation.chatColors(); - this.textFilteringEnabled = clientInformation.textFilteringEnabled(); - this.allowsListing = clientInformation.allowsListing(); - this.getEntityData().set(DATA_PLAYER_MODE_CUSTOMISATION, (byte)clientInformation.modelCustomisation()); - this.getEntityData().set(DATA_PLAYER_MAIN_HAND, (byte)clientInformation.mainHand().getId()); + public void updateOptions(ClientInformation clientinformation) { + // CraftBukkit start + if (getMainArm() != clientinformation.mainHand()) { + PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT); + this.server.server.getPluginManager().callEvent(event); + } + if (!this.language.equals(clientinformation.language())) { + PlayerLocaleChangeEvent event = new PlayerLocaleChangeEvent(getBukkitEntity(), clientinformation.language()); + this.server.server.getPluginManager().callEvent(event); + } + // CraftBukkit end + this.language = clientinformation.language(); + this.requestedViewDistance = clientinformation.viewDistance(); + this.chatVisibility = clientinformation.chatVisibility(); + this.canChatColor = clientinformation.chatColors(); + this.textFilteringEnabled = clientinformation.textFilteringEnabled(); + this.allowsListing = clientinformation.allowsListing(); + this.getEntityData().set(ServerPlayer.DATA_PLAYER_MODE_CUSTOMISATION, (byte) clientinformation.modelCustomisation()); + this.getEntityData().set(ServerPlayer.DATA_PLAYER_MAIN_HAND, (byte) clientinformation.mainHand().getId()); } public ClientInformation clientInformation() { - int i = this.getEntityData().get(DATA_PLAYER_MODE_CUSTOMISATION); - HumanoidArm humanoidArm = HumanoidArm.BY_ID.apply(this.getEntityData().get(DATA_PLAYER_MAIN_HAND)); - return new ClientInformation( - this.language, this.requestedViewDistance, this.chatVisibility, this.canChatColor, i, humanoidArm, this.textFilteringEnabled, this.allowsListing - ); + byte b0 = (Byte) this.getEntityData().get(ServerPlayer.DATA_PLAYER_MODE_CUSTOMISATION); + HumanoidArm enummainhand = (HumanoidArm) HumanoidArm.BY_ID.apply((Byte) this.getEntityData().get(ServerPlayer.DATA_PLAYER_MAIN_HAND)); + + return new ClientInformation(this.language, this.requestedViewDistance, this.chatVisibility, this.canChatColor, b0, enummainhand, this.textFilteringEnabled, this.allowsListing); } public boolean canChatInColor() { @@ -1452,7 +1942,7 @@ } private boolean acceptsSystemMessages(boolean bypassHiddenChat) { - return this.chatVisibility != ChatVisiblity.HIDDEN || bypassHiddenChat; + return this.chatVisibility == ChatVisiblity.HIDDEN ? bypassHiddenChat : true; } private boolean acceptsChatMessages() { @@ -1464,12 +1954,7 @@ } public void sendServerStatus(ServerStatus serverStatus) { - this.connection - .send( - new ClientboundServerDataPacket( - serverStatus.description(), serverStatus.favicon().map(ServerStatus.Favicon::iconBytes), serverStatus.enforcesSecureChat() - ) - ); + this.connection.send(new ClientboundServerDataPacket(serverStatus.description(), serverStatus.favicon().map(ServerStatus.a::iconBytes), serverStatus.enforcesSecureChat())); } @Override @@ -1497,18 +1982,24 @@ } else { super.updateInvisibilityStatus(); } + } public Entity getCamera() { - return (Entity)(this.camera == null ? this : this.camera); + return (Entity) (this.camera == null ? this : this.camera); } public void setCamera(@Nullable Entity entityToSpectate) { - Entity camera = this.getCamera(); - this.camera = (Entity)(entityToSpectate == null ? this : entityToSpectate); - if (camera != this.camera) { - if (this.camera.level() instanceof ServerLevel serverLevel) { - this.teleportTo(serverLevel, this.camera.getX(), this.camera.getY(), this.camera.getZ(), Set.of(), this.getYRot(), this.getXRot()); + Entity entity1 = this.getCamera(); + + this.camera = (Entity) (entityToSpectate == null ? this : entityToSpectate); + if (entity1 != this.camera) { + Level world = this.camera.level(); + + if (world instanceof ServerLevel) { + ServerLevel worldserver = (ServerLevel) world; + + this.teleportTo(worldserver, this.camera.getX(), this.camera.getY(), this.camera.getZ(), Set.of(), this.getYRot(), this.getXRot(), TeleportCause.SPECTATE); // CraftBukkit } if (entityToSpectate != null) { @@ -1518,6 +2009,7 @@ this.connection.send(new ClientboundSetCameraPacket(this.camera)); this.connection.resetPosition(); } + } @Override @@ -1525,6 +2017,7 @@ if (!this.isChangingDimension) { super.processPortalCooldown(); } + } @Override @@ -1534,6 +2027,7 @@ } else { super.attack(targetEntity); } + } public long getLastActionTime() { @@ -1542,11 +2036,11 @@ @Nullable public Component getTabListDisplayName() { - return null; + return listName; // CraftBukkit } @Override - public void swing(InteractionHand hand) { + public void swing(EnumHand hand) { super.swing(hand); this.resetAttackStrengthTicker(); } @@ -1563,27 +2057,39 @@ return this.advancements; } - public void teleportTo(ServerLevel newLevel, double x, double y, double z, float yaw, float pitch) { + // CraftBukkit start + public void teleportTo(ServerLevel newLevel, double x, double d1, double y, float f, float z) { + this.teleportTo(newLevel, x, d1, y, f, z, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN); + } + + public void teleportTo(ServerLevel worldserver, double d0, double d1, double d2, float f, float f1, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { + // CraftBukkit end this.setCamera(this); this.stopRiding(); - if (newLevel == this.level()) { - this.connection.teleport(x, y, z, yaw, pitch); + /* CraftBukkit start - replace with bukkit handling for multi-world + if (worldserver == this.level()) { + this.connection.teleport(d0, d1, d2, f, f1); } else { - ServerLevel serverLevel = this.serverLevel(); - LevelData levelData = newLevel.getLevelData(); - this.connection.send(new ClientboundRespawnPacket(this.createCommonSpawnInfo(newLevel), (byte)3)); - this.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked())); + WorldServer worldserver1 = this.serverLevel(); + WorldData worlddata = worldserver.getLevelData(); + + this.connection.send(new PacketPlayOutRespawn(this.createCommonSpawnInfo(worldserver), (byte) 3)); + this.connection.send(new PacketPlayOutServerDifficulty(worlddata.getDifficulty(), worlddata.isDifficultyLocked())); this.server.getPlayerList().sendPlayerPermissionLevel(this); - serverLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); + worldserver1.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION); this.unsetRemoved(); - this.moveTo(x, y, z, yaw, pitch); - this.setServerLevel(newLevel); - newLevel.addDuringCommandTeleport(this); - this.triggerDimensionChangeTriggers(serverLevel); - this.connection.teleport(x, y, z, yaw, pitch); - this.server.getPlayerList().sendLevelInfo(this, newLevel); + this.moveTo(d0, d1, d2, f, f1); + this.setServerLevel(worldserver); + worldserver.addDuringCommandTeleport(this); + this.triggerDimensionChangeTriggers(worldserver1); + this.connection.teleport(d0, d1, d2, f, f1); + this.server.getPlayerList().sendLevelInfo(this, worldserver); this.server.getPlayerList().sendAllPlayerInfo(this); } + */ + this.getBukkitEntity().teleport(new Location(worldserver.getWorld(), d0, d1, d2, f, f1), cause); + // CraftBukkit end + } @Nullable @@ -1604,22 +2110,50 @@ } public void setRespawnPosition(ResourceKey dimension, @Nullable BlockPos position, float angle, boolean forced, boolean sendMessage) { - if (position != null) { - boolean flag = position.equals(this.respawnPosition) && dimension.equals(this.respawnDimension); - if (sendMessage && !flag) { + // CraftBukkit start + this.setRespawnPosition(dimension, position, angle, forced, sendMessage, PlayerSpawnChangeEvent.Cause.UNKNOWN); + } + + public void setRespawnPosition(ResourceKey resourcekey, @Nullable BlockPos blockposition, float f, boolean flag, boolean flag1, PlayerSpawnChangeEvent.Cause cause) { + ServerLevel newWorld = this.server.getLevel(resourcekey); + Location newSpawn = (blockposition != null) ? CraftLocation.toBukkit(blockposition, newWorld.getWorld(), f, 0) : null; + + PlayerSpawnChangeEvent event = new PlayerSpawnChangeEvent(this.getBukkitEntity(), newSpawn, flag, cause); + Bukkit.getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return; + } + newSpawn = event.getNewSpawn(); + flag = event.isForced(); + + if (newSpawn != null) { + resourcekey = ((CraftWorld) newSpawn.getWorld()).getHandle().dimension(); + blockposition = BlockPos.containing(newSpawn.getX(), newSpawn.getY(), newSpawn.getZ()); + f = newSpawn.getYaw(); + } else { + resourcekey = Level.OVERWORLD; + blockposition = null; + f = 0.0F; + } + // CraftBukkit end + if (blockposition != null) { + boolean flag2 = blockposition.equals(this.respawnPosition) && resourcekey.equals(this.respawnDimension); + + if (flag1 && !flag2) { this.sendSystemMessage(Component.translatable("block.minecraft.set_spawn")); } - this.respawnPosition = position; - this.respawnDimension = dimension; - this.respawnAngle = angle; - this.respawnForced = forced; + this.respawnPosition = blockposition; + this.respawnDimension = resourcekey; + this.respawnAngle = f; + this.respawnForced = flag; } else { this.respawnPosition = null; this.respawnDimension = Level.OVERWORLD; this.respawnAngle = 0.0F; this.respawnForced = false; } + } public SectionPos getLastSectionPos() { @@ -1634,37 +2168,34 @@ return this.chunkTrackingView; } - public void setChunkTrackingView(ChunkTrackingView chunkTrackingView) { - this.chunkTrackingView = chunkTrackingView; + public void setChunkTrackingView(ChunkTrackingView chunktrackingview) { + this.chunkTrackingView = chunktrackingview; } @Override public void playNotifySound(SoundEvent sound, SoundSource source, float volume, float pitch) { - this.connection - .send( - new ClientboundSoundPacket( - BuiltInRegistries.SOUND_EVENT.wrapAsHolder(sound), source, this.getX(), this.getY(), this.getZ(), volume, pitch, this.random.nextLong() - ) - ); + this.connection.send(new ClientboundSoundPacket(BuiltInRegistries.SOUND_EVENT.wrapAsHolder(sound), source, this.getX(), this.getY(), this.getZ(), volume, pitch, this.random.nextLong())); } @Override public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean traceItem) { - ItemEntity itemEntity = super.drop(droppedItem, dropAround, traceItem); - if (itemEntity == null) { + ItemEntity entityitem = super.drop(droppedItem, dropAround, traceItem); + + if (entityitem == null) { return null; } else { - this.level().addFreshEntity(itemEntity); - ItemStack item = itemEntity.getItem(); + this.level().addFreshEntity(entityitem); + ItemStack itemstack1 = entityitem.getItem(); + if (traceItem) { - if (!item.isEmpty()) { - this.awardStat(Stats.ITEM_DROPPED.get(item.getItem()), droppedItem.getCount()); + if (!itemstack1.isEmpty()) { + this.awardStat(Stats.ITEM_DROPPED.get(itemstack1.getItem()), droppedItem.getCount()); } this.awardStat(Stats.DROP); } - return itemEntity; + return entityitem; } } @@ -1683,25 +2214,23 @@ } private GameType calculateGameModeForNewPlayer(@Nullable GameType gameType) { - GameType forcedGameType = this.server.getForcedGameType(); - if (forcedGameType != null) { - return forcedGameType; - } else { - return gameType != null ? gameType : this.server.getDefaultGameType(); - } + GameType enumgamemode1 = this.server.getForcedGameType(); + + return enumgamemode1 != null ? enumgamemode1 : (gameType != null ? gameType : this.server.getDefaultGameType()); } public void loadGameTypes(@Nullable CompoundTag tag) { - this.gameMode - .setGameModeForPlayer(this.calculateGameModeForNewPlayer(readPlayerMode(tag, "playerGameType")), readPlayerMode(tag, "previousPlayerGameType")); + this.gameMode.setGameModeForPlayer(this.calculateGameModeForNewPlayer(readPlayerMode(tag, "playerGameType")), readPlayerMode(tag, "previousPlayerGameType")); } private void storeGameTypes(CompoundTag tag) { tag.putInt("playerGameType", this.gameMode.getGameModeForPlayer().getId()); - GameType previousGameModeForPlayer = this.gameMode.getPreviousGameModeForPlayer(); - if (previousGameModeForPlayer != null) { - tag.putInt("previousPlayerGameType", previousGameModeForPlayer.getId()); + GameType enumgamemode = this.gameMode.getPreviousGameModeForPlayer(); + + if (enumgamemode != null) { + tag.putInt("previousPlayerGameType", enumgamemode.getId()); } + } @Override @@ -1710,7 +2239,7 @@ } public boolean shouldFilterMessageTo(ServerPlayer player) { - return player != this && (this.textFilteringEnabled || player.textFilteringEnabled); + return player == this ? false : this.textFilteringEnabled || player.textFilteringEnabled; } @Override @@ -1725,10 +2254,13 @@ } public boolean drop(boolean dropStack) { - Inventory inventory = this.getInventory(); - ItemStack itemStack = inventory.removeFromSelected(dropStack); - this.containerMenu.findSlot(inventory, inventory.selected).ifPresent(i -> this.containerMenu.setRemoteSlot(i, inventory.getSelected())); - return this.drop(itemStack, false, true) != null; + Inventory playerinventory = this.getInventory(); + ItemStack itemstack = playerinventory.removeFromSelected(dropStack); + + this.containerMenu.findSlot(playerinventory, playerinventory.selected).ifPresent((i) -> { + this.containerMenu.setRemoteSlot(i, playerinventory.getSelected()); + }); + return this.drop(itemstack, false, true) != null; } public boolean allowsListing() { @@ -1743,10 +2275,12 @@ @Override public void onItemPickup(ItemEntity itemEntity) { super.onItemPickup(itemEntity); - Entity owner = itemEntity.getOwner(); - if (owner != null) { - CriteriaTriggers.THROWN_ITEM_PICKED_UP_BY_PLAYER.trigger(this, itemEntity.getItem(), owner); + Entity entity = itemEntity.getOwner(); + + if (entity != null) { + CriteriaTriggers.THROWN_ITEM_PICKED_UP_BY_PLAYER.trigger(this, itemEntity.getItem(), entity); } + } public void setChatSession(RemoteChatSession chatSession) { @@ -1759,8 +2293,8 @@ } @Override - public void indicateDamage(double xDistance, double zDistance) { - this.hurtDir = (float)(Mth.atan2(zDistance, xDistance) * 180.0F / (float)Math.PI - (double)this.getYRot()); + public void indicateDamage(double xDistance, double d1) { + this.hurtDir = (float) (Mth.atan2(d1, xDistance) * 57.2957763671875D - (double) this.getYRot()); this.connection.send(new ClientboundHurtAnimationPacket(this)); } @@ -1771,9 +2305,14 @@ } else { vehicle.positionRider(this); this.connection.teleport(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); - if (vehicle instanceof LivingEntity livingEntity) { - for (MobEffectInstance mobEffectInstance : livingEntity.getActiveEffects()) { - this.connection.send(new ClientboundUpdateMobEffectPacket(vehicle.getId(), mobEffectInstance)); + if (vehicle instanceof LivingEntity) { + LivingEntity entityliving = (LivingEntity) vehicle; + Iterator iterator = entityliving.getActiveEffects().iterator(); + + while (iterator.hasNext()) { + MobEffectInstance mobeffect = (MobEffectInstance) iterator.next(); + + this.connection.send(new ClientboundUpdateMobEffectPacket(vehicle.getId(), mobeffect)); } } @@ -1783,26 +2322,165 @@ @Override public void stopRiding() { - Entity vehicle = this.getVehicle(); + Entity entity = this.getVehicle(); + super.stopRiding(); - if (vehicle instanceof LivingEntity livingEntity) { - for (MobEffectInstance mobEffectInstance : livingEntity.getActiveEffects()) { - this.connection.send(new ClientboundRemoveMobEffectPacket(vehicle.getId(), mobEffectInstance.getEffect())); + if (entity instanceof LivingEntity) { + LivingEntity entityliving = (LivingEntity) entity; + Iterator iterator = entityliving.getActiveEffects().iterator(); + + while (iterator.hasNext()) { + MobEffectInstance mobeffect = (MobEffectInstance) iterator.next(); + + this.connection.send(new ClientboundRemoveMobEffectPacket(entity.getId(), mobeffect.getEffect())); } } + } - public CommonPlayerSpawnInfo createCommonSpawnInfo(ServerLevel serverLevel) { - return new CommonPlayerSpawnInfo( - serverLevel.dimensionTypeId(), - serverLevel.dimension(), - BiomeManager.obfuscateSeed(serverLevel.getSeed()), - this.gameMode.getGameModeForPlayer(), - this.gameMode.getPreviousGameModeForPlayer(), - serverLevel.isDebug(), - serverLevel.isFlat(), - this.getLastDeathLocation(), - this.getPortalCooldown() - ); + public CommonPlayerSpawnInfo createCommonSpawnInfo(ServerLevel worldserver) { + return new CommonPlayerSpawnInfo(worldserver.dimensionTypeId(), worldserver.dimension(), BiomeManager.obfuscateSeed(worldserver.getSeed()), this.gameMode.getGameModeForPlayer(), this.gameMode.getPreviousGameModeForPlayer(), worldserver.isDebug(), worldserver.isFlat(), this.getLastDeathLocation(), this.getPortalCooldown()); } + + // CraftBukkit start - Add per-player time and weather. + public long timeOffset = 0; + public boolean relativeTime = true; + + public long getPlayerTime() { + if (this.relativeTime) { + // Adds timeOffset to the current server time. + return this.level().getDayTime() + this.timeOffset; + } else { + // Adds timeOffset to the beginning of this day. + return this.level().getDayTime() - (this.level().getDayTime() % 24000) + this.timeOffset; + } + } + + public WeatherType weather = null; + + public WeatherType getPlayerWeather() { + return this.weather; + } + + public void setPlayerWeather(WeatherType type, boolean plugin) { + if (!plugin && this.weather != null) { + return; + } + + if (plugin) { + this.weather = type; + } + + if (type == WeatherType.DOWNFALL) { + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.STOP_RAINING, 0)); + } else { + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.START_RAINING, 0)); + } + } + + private float pluginRainPosition; + private float pluginRainPositionPrevious; + + public void updateWeather(float oldRain, float newRain, float oldThunder, float newThunder) { + if (this.weather == null) { + // Vanilla + if (oldRain != newRain) { + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, newRain)); + } + } else { + // Plugin + if (pluginRainPositionPrevious != pluginRainPosition) { + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, pluginRainPosition)); + } + } + + if (oldThunder != newThunder) { + if (weather == WeatherType.DOWNFALL || weather == null) { + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, newThunder)); + } else { + this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, 0)); + } + } + } + + public void tickWeather() { + if (this.weather == null) return; + + pluginRainPositionPrevious = pluginRainPosition; + if (weather == WeatherType.DOWNFALL) { + pluginRainPosition += 0.01; + } else { + pluginRainPosition -= 0.01; + } + + pluginRainPosition = Mth.clamp(pluginRainPosition, 0.0F, 1.0F); + } + + public void resetPlayerWeather() { + this.weather = null; + this.setPlayerWeather(this.level().getLevelData().isRaining() ? WeatherType.DOWNFALL : WeatherType.CLEAR, false); + } + + @Override + public String toString() { + return super.toString() + "(" + this.getScoreboardName() + " at " + this.getX() + "," + this.getY() + "," + this.getZ() + ")"; + } + + // SPIGOT-1903, MC-98153 + public void forceSetPositionRotation(double x, double y, double z, float yaw, float pitch) { + this.moveTo(x, y, z, yaw, pitch); + this.connection.resetPosition(); + } + + @Override + public boolean isImmobile() { + return super.isImmobile() || !getBukkitEntity().isOnline(); + } + + @Override + public Scoreboard getScoreboard() { + return getBukkitEntity().getScoreboard().getHandle(); + } + + public void reset() { + float exp = 0; + boolean keepInventory = this.level().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY); + + if (this.keepLevel) { // CraftBukkit - SPIGOT-6687: Only use keepLevel (was pre-set with RULE_KEEPINVENTORY value in PlayerDeathEvent) + exp = this.experienceProgress; + this.newTotalExp = this.totalExperience; + this.newLevel = this.experienceLevel; + } + + this.setHealth(this.getMaxHealth()); + this.stopUsingItem(); // CraftBukkit - SPIGOT-6682: Clear active item on reset + this.setRemainingFireTicks(0); + this.fallDistance = 0; + this.foodData = new FoodData(this); + this.experienceLevel = this.newLevel; + this.totalExperience = this.newTotalExp; + this.experienceProgress = 0; + this.deathTime = 0; + this.setArrowCount(0, true); // CraftBukkit - ArrowBodyCountChangeEvent + this.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.DEATH); + this.effectsDirty = true; + this.containerMenu = this.inventoryMenu; + this.lastHurtByPlayer = null; + this.lastHurtByMob = null; + this.combatTracker = new CombatTracker(this); + this.lastSentExp = -1; + if (this.keepLevel) { // CraftBukkit - SPIGOT-6687: Only use keepLevel (was pre-set with RULE_KEEPINVENTORY value in PlayerDeathEvent) + this.experienceProgress = exp; + } else { + this.giveExperiencePoints(this.newExp); + } + this.keepLevel = false; + this.setDeltaMovement(0, 0, 0); // CraftBukkit - SPIGOT-6948: Reset velocity on death + } + + @Override + public CraftPlayer getBukkitEntity() { + return (CraftPlayer) super.getBukkitEntity(); + } + // CraftBukkit end }