mirror of
https://github.com/PaperMC/Paper.git
synced 2025-05-19 05:30:23 -07:00
The exit location passed to PlayerTeleportEvent/PlayerTeleportEndGatewayEvent in ServerPlayer#teleport(TeleportTransition) needs to be cloned, as it is later compared in case it was changed. Not cloning it results in the ability for plugins to mutate it but such changes will be ignored, as the instance of the Location being the same results in a successful equality check. It is not necessary to clone the location in other instantiations of the event (or subclasses) as those are not compared afterwards to change the outcome.
1548 lines
82 KiB
Diff
1548 lines
82 KiB
Diff
--- a/net/minecraft/server/level/ServerPlayer.java
|
|
+++ b/net/minecraft/server/level/ServerPlayer.java
|
|
@@ -235,7 +_,8 @@
|
|
private int levitationStartTime;
|
|
private boolean disconnected;
|
|
private int requestedViewDistance = 2;
|
|
- public String language = "en_us";
|
|
+ public String language = null; // Paper - default to null
|
|
+ public java.util.Locale adventure$locale = java.util.Locale.US; // Paper
|
|
@Nullable
|
|
private Vec3 startingToFallPosition;
|
|
@Nullable
|
|
@@ -281,6 +_,20 @@
|
|
}
|
|
}
|
|
|
|
+ // Paper start - Sync offhand slot in menus
|
|
+ @Override
|
|
+ public void sendOffHandSlotChange() {
|
|
+ ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(ServerPlayer.this.inventoryMenu.containerId, ServerPlayer.this.inventoryMenu.incrementStateId(), net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT, ServerPlayer.this.inventoryMenu.getSlot(net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT).getItem().copy()));
|
|
+ }
|
|
+ // Paper end - Sync offhand slot in menus
|
|
+
|
|
+ // Paper start - add flag to simplify remote matching logic
|
|
+ @Override
|
|
+ public ServerPlayer player() {
|
|
+ return ServerPlayer.this;
|
|
+ }
|
|
+ // Paper end - add flag to simplify remote matching logic
|
|
+
|
|
@Override
|
|
public void sendSlotChange(AbstractContainerMenu container, int slot, ItemStack itemStack) {
|
|
ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(container.containerId, container.incrementStateId(), slot, itemStack));
|
|
@@ -302,7 +_,7 @@
|
|
|
|
@Override
|
|
public RemoteSlot createSlot() {
|
|
- return new RemoteSlot.Synchronized(this.cache::getUnchecked);
|
|
+ return new RemoteSlot.Synchronized(this.cache::getUnchecked, ServerPlayer.this.getBukkitEntity().simplifyContainerDesyncCheck()); // Paper - add flag to simplify remote matching logic
|
|
}
|
|
};
|
|
private final ContainerListener containerListener = new ContainerListener() {
|
|
@@ -316,6 +_,32 @@
|
|
}
|
|
}
|
|
|
|
+ // Paper start - Add PlayerInventorySlotChangeEvent
|
|
+ @Override
|
|
+ public void slotChanged(AbstractContainerMenu containerToSend, int dataSlotIndex, ItemStack oldStack, ItemStack stack) {
|
|
+ // See slotChanged above
|
|
+ Slot slot = containerToSend.getSlot(dataSlotIndex);
|
|
+ if (!(slot instanceof ResultSlot)) {
|
|
+ if (slot.container == ServerPlayer.this.getInventory()) {
|
|
+ if (io.papermc.paper.event.player.PlayerInventorySlotChangeEvent.getHandlerList().getRegisteredListeners().length == 0) {
|
|
+ CriteriaTriggers.INVENTORY_CHANGED.trigger(ServerPlayer.this, ServerPlayer.this.getInventory(), stack);
|
|
+ return;
|
|
+ }
|
|
+ io.papermc.paper.event.player.PlayerInventorySlotChangeEvent event = new io.papermc.paper.event.player.PlayerInventorySlotChangeEvent(
|
|
+ ServerPlayer.this.getBukkitEntity(),
|
|
+ dataSlotIndex,
|
|
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(oldStack),
|
|
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(stack)
|
|
+ );
|
|
+ event.callEvent();
|
|
+ if (event.shouldTriggerAdvancements()) {
|
|
+ CriteriaTriggers.INVENTORY_CHANGED.trigger(ServerPlayer.this, ServerPlayer.this.getInventory(), stack);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // Paper end - Add PlayerInventorySlotChangeEvent
|
|
+
|
|
@Override
|
|
public void dataChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, int value) {
|
|
}
|
|
@@ -344,9 +_,43 @@
|
|
public void sendSystemMessage(Component component) {
|
|
ServerPlayer.this.sendSystemMessage(component);
|
|
}
|
|
+
|
|
+ // CraftBukkit start
|
|
+ @Override
|
|
+ public org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper) {
|
|
+ return ServerPlayer.this.getBukkitEntity();
|
|
+ }
|
|
+ // CraftBukkit end
|
|
};
|
|
private int containerCounter;
|
|
public boolean wonGame;
|
|
+ private int containerUpdateDelay; // Paper - Configurable container update tick rate
|
|
+ public long loginTime; // Paper - Replace OfflinePlayer#getLastPlayed
|
|
+ public int patrolSpawnDelay; // Paper - Pillager patrol spawn settings and per player options
|
|
+ // Paper start - cancellable death event
|
|
+ public boolean queueHealthUpdatePacket;
|
|
+ public @Nullable net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
|
|
+ // Paper end - cancellable death event
|
|
+ // CraftBukkit start
|
|
+ public org.bukkit.craftbukkit.entity.CraftPlayer.TransferCookieConnection transferCookieConnection;
|
|
+ public String displayName;
|
|
+ public net.kyori.adventure.text.Component adventure$displayName; // Paper
|
|
+ public @Nullable Component listName;
|
|
+ public int listOrder = 0;
|
|
+ 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 boolean supressTrackerForLogin = false; // Paper - Fire PlayerJoinEvent when Player is actually ready
|
|
+ // CraftBukkit end
|
|
+ public boolean isRealPlayer; // Paper
|
|
+ public @Nullable com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - PlayerNaturallySpawnCreaturesEvent
|
|
+ public @Nullable String clientBrandName = null; // Paper - Brand support
|
|
+ public @Nullable org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event
|
|
|
|
public ServerPlayer(MinecraftServer server, ServerLevel level, GameProfile gameProfile, ClientInformation clientInformation) {
|
|
super(level, level.getSharedSpawnPos(), level.getSharedSpawnAngle(), gameProfile);
|
|
@@ -356,16 +_,22 @@
|
|
this.server = server;
|
|
this.stats = server.getPlayerList().getPlayerStats(this);
|
|
this.advancements = server.getPlayerList().getPlayerAdvancements(this);
|
|
- this.snapTo(this.adjustSpawnLocation(level, level.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F);
|
|
- this.updateOptions(clientInformation);
|
|
+ // this.snapTo(this.adjustSpawnLocation(level, level.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); // Paper - Don't move existing players to world spawn
|
|
+ this.updateOptionsNoEvents(clientInformation); // Paper - don't call options events on login
|
|
this.object = null;
|
|
+
|
|
+ // CraftBukkit start
|
|
+ this.displayName = this.getScoreboardName();
|
|
+ this.adventure$displayName = net.kyori.adventure.text.Component.text(this.getScoreboardName()); // Paper
|
|
+ this.bukkitPickUpLoot = true;
|
|
+ this.maxHealthCache = this.getMaxHealth();
|
|
}
|
|
|
|
@Override
|
|
public BlockPos adjustSpawnLocation(ServerLevel level, BlockPos pos) {
|
|
AABB aabb = this.getDimensions(Pose.STANDING).makeBoundingBox(Vec3.ZERO);
|
|
BlockPos blockPos = pos;
|
|
- if (level.dimensionType().hasSkyLight() && level.getServer().getWorldData().getGameType() != GameType.ADVENTURE) {
|
|
+ if (level.dimensionType().hasSkyLight() && level.serverLevelData.getGameType() != GameType.ADVENTURE) { // CraftBukkit
|
|
int max = Math.max(0, this.server.getSpawnRadius(level));
|
|
int floor = Mth.floor(level.getWorldBorder().getDistanceToBorder(pos.getX(), pos.getZ()));
|
|
if (floor < max) {
|
|
@@ -436,6 +_,7 @@
|
|
this.enteredNetherPosition = compound.read("entered_nether_pos", Vec3.CODEC).orElse(null);
|
|
this.seenCredits = compound.getBooleanOr("seenCredits", false);
|
|
this.recipeBook.fromNbt(compound.getCompoundOrEmpty("recipeBook"), key -> this.server.getRecipeManager().byKey(key).isPresent());
|
|
+ this.getBukkitEntity().readExtraData(compound); // CraftBukkit
|
|
if (this.isSleeping()) {
|
|
this.stopSleeping();
|
|
}
|
|
@@ -459,12 +_,24 @@
|
|
compound.putBoolean("spawn_extra_particles_on_fall", this.spawnExtraParticlesOnFall);
|
|
compound.storeNullable("raid_omen_position", BlockPos.CODEC, this.raidOmenPosition);
|
|
this.saveEnderPearls(compound);
|
|
+ this.getBukkitEntity().setExtraData(compound); // CraftBukkit
|
|
}
|
|
|
|
private void saveParentVehicle(CompoundTag tag) {
|
|
Entity rootVehicle = this.getRootVehicle();
|
|
Entity vehicle = this.getVehicle();
|
|
- if (vehicle != null && rootVehicle != this && rootVehicle.hasExactlyOnePlayerPassenger()) {
|
|
+ // CraftBukkit start - handle non-persistent vehicles
|
|
+ boolean persistVehicle = true;
|
|
+ if (vehicle != null) {
|
|
+ for (Entity topVehicle = vehicle; topVehicle != null; topVehicle = topVehicle.getVehicle()) {
|
|
+ if (!topVehicle.persist) {
|
|
+ persistVehicle = false;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (persistVehicle && vehicle != null && rootVehicle != this && rootVehicle.hasExactlyOnePlayerPassenger() && !rootVehicle.isRemoved()) { // Paper - Ensure valid vehicle status
|
|
+ // CraftBukkit end
|
|
CompoundTag compoundTag = new CompoundTag();
|
|
CompoundTag compoundTag1 = new CompoundTag();
|
|
rootVehicle.save(compoundTag1);
|
|
@@ -479,7 +_,7 @@
|
|
if (!compound.isEmpty()) {
|
|
ServerLevel serverLevel = this.serverLevel();
|
|
Entity entity = EntityType.loadEntityRecursive(
|
|
- compound.get().getCompoundOrEmpty("Entity"), serverLevel, EntitySpawnReason.LOAD, entity2 -> !serverLevel.addWithUUID(entity2) ? null : entity2
|
|
+ compound.get().getCompoundOrEmpty("Entity"), serverLevel, EntitySpawnReason.LOAD, entity2 -> !serverLevel.addWithUUID(entity2, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT) ? null : entity2 // Paper - Entity#getEntitySpawnReason
|
|
);
|
|
if (entity != null) {
|
|
UUID uuid = compound.get().read("Attach", UUIDUtil.CODEC).orElse(null);
|
|
@@ -496,10 +_,10 @@
|
|
|
|
if (!this.isPassenger()) {
|
|
LOGGER.warn("Couldn't reattach entity to player");
|
|
- entity.discard();
|
|
+ entity.discard(null); // CraftBukkit - add Bukkit remove cause
|
|
|
|
for (Entity entity1x : entity.getIndirectPassengers()) {
|
|
- entity1x.discard();
|
|
+ entity1x.discard(null); // CraftBukkit - add Bukkit remove cause
|
|
}
|
|
}
|
|
}
|
|
@@ -511,6 +_,7 @@
|
|
ListTag listTag = new ListTag();
|
|
|
|
for (ThrownEnderpearl thrownEnderpearl : this.enderPearls) {
|
|
+ if (thrownEnderpearl.level().paperConfig().misc.legacyEnderPearlBehavior) continue; // Paper - Allow using old ender pearl behavior
|
|
if (thrownEnderpearl.isRemoved()) {
|
|
LOGGER.warn("Trying to save removed ender pearl, skipping");
|
|
} else {
|
|
@@ -546,6 +_,16 @@
|
|
}
|
|
}
|
|
|
|
+ // CraftBukkit start
|
|
+ public void spawnIn(final ServerLevel level) {
|
|
+ if (level == null) {
|
|
+ throw new IllegalArgumentException("level can't be null");
|
|
+ }
|
|
+ this.setLevel(level);
|
|
+ this.gameMode.setLevel(level);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+
|
|
public void setExperiencePoints(int experiencePoints) {
|
|
float f = this.getXpNeededForNextLevel();
|
|
float f1 = (f - 1.0F) / f;
|
|
@@ -603,6 +_,11 @@
|
|
|
|
@Override
|
|
public void tick() {
|
|
+ // CraftBukkit start
|
|
+ if (this.joining) {
|
|
+ this.joining = false;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
this.tickClientLoadTimeout();
|
|
this.gameMode.tick();
|
|
this.wardenSpawnTracker.tick();
|
|
@@ -610,9 +_,14 @@
|
|
this.invulnerableTime--;
|
|
}
|
|
|
|
- this.containerMenu.broadcastChanges();
|
|
- if (!this.containerMenu.stillValid(this)) {
|
|
- this.closeContainer();
|
|
+ // Paper start - Configurable container update tick rate
|
|
+ if (--this.containerUpdateDelay <= 0) {
|
|
+ this.containerMenu.broadcastChanges();
|
|
+ this.containerUpdateDelay = this.level().paperConfig().tickRates.containerUpdate;
|
|
+ }
|
|
+ // Paper end - Configurable container update tick rate
|
|
+ if (this.containerMenu != this.inventoryMenu && (this.isImmobile() || !this.containerMenu.stillValid(this))) { // Paper - Prevent opening inventories when frozen
|
|
+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper - Inventory close reason
|
|
this.containerMenu = this.inventoryMenu;
|
|
}
|
|
|
|
@@ -662,7 +_,7 @@
|
|
|
|
public void doTick() {
|
|
try {
|
|
- if (!this.isSpectator() || !this.touchingUnloadedChunk()) {
|
|
+ if (valid && !this.isSpectator() || !this.touchingUnloadedChunk()) { // Paper - don't tick dead players that are not in the world currently (pending respawn)
|
|
super.tick();
|
|
}
|
|
|
|
@@ -676,7 +_,7 @@
|
|
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()));
|
|
+ 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;
|
|
@@ -707,6 +_,12 @@
|
|
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));
|
|
@@ -720,6 +_,21 @@
|
|
if (this.tickCount % 20 == 0) {
|
|
CriteriaTriggers.LOCATION.trigger(this);
|
|
}
|
|
+
|
|
+ // 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) {
|
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLevelChangeEvent(this.getBukkitEntity(), this.oldLevel, this.experienceLevel);
|
|
+ this.oldLevel = this.experienceLevel;
|
|
+ }
|
|
+
|
|
+ if (this.getBukkitEntity().hasClientWorldBorder()) {
|
|
+ ((org.bukkit.craftbukkit.CraftWorldBorder) this.getBukkitEntity().getWorldBorder()).getHandle().tick();
|
|
+ }
|
|
+ // CraftBukkit end
|
|
} catch (Throwable var4) {
|
|
CrashReport crashReport = CrashReport.forThrowable(var4, "Ticking player");
|
|
CrashReportCategory crashReportCategory = crashReport.addCategory("Player being ticked");
|
|
@@ -744,7 +_,7 @@
|
|
if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.serverLevel().getGameRules().getBoolean(GameRules.RULE_NATURAL_REGENERATION)) {
|
|
if (this.tickCount % 20 == 0) {
|
|
if (this.getHealth() < this.getMaxHealth()) {
|
|
- this.heal(1.0F);
|
|
+ this.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit - added regain reason of "REGEN" for filtering purposes.
|
|
}
|
|
|
|
float saturationLevel = this.foodData.getSaturationLevel();
|
|
@@ -793,15 +_,84 @@
|
|
}
|
|
|
|
private void updateScoreForCriteria(ObjectiveCriteria criteria, int points) {
|
|
- this.getScoreboard().forAllObjectives(criteria, this, score -> score.set(points));
|
|
- }
|
|
+ this.level().getCraftServer().getScoreboardManager().forAllObjectives(criteria, this, score -> score.set(points)); // CraftBukkit - Use our scores instead
|
|
+ }
|
|
+
|
|
+ // Paper start - PlayerDeathEvent#getItemsToKeep
|
|
+ private static boolean shouldKeepDeathEventItem(
|
|
+ final org.bukkit.event.entity.PlayerDeathEvent event,
|
|
+ final ItemStack item
|
|
+ ) {
|
|
+ final List<org.bukkit.inventory.ItemStack> itemsToKeep = event.getItemsToKeep();
|
|
+ if (EnchantmentHelper.has(item, net.minecraft.world.item.enchantment.EnchantmentEffectComponents.PREVENT_EQUIPMENT_DROP) || itemsToKeep.isEmpty() || item.isEmpty()) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ final org.bukkit.inventory.ItemStack bukkitStack = item.getBukkitStack();
|
|
+ final java.util.Iterator<org.bukkit.inventory.ItemStack> iterator = itemsToKeep.iterator();
|
|
+ while (iterator.hasNext()) {
|
|
+ final org.bukkit.inventory.ItemStack itemStack = iterator.next();
|
|
+ if (bukkitStack.equals(itemStack)) {
|
|
+ iterator.remove();
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+ // Paper end - PlayerDeathEvent#getItemsToKeep
|
|
|
|
@Override
|
|
public void die(DamageSource cause) {
|
|
- this.gameEvent(GameEvent.ENTITY_DIE);
|
|
- boolean _boolean = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES);
|
|
- if (_boolean) {
|
|
- Component deathMessage = this.getCombatTracker().getDeathMessage();
|
|
+ // this.gameEvent(GameEvent.ENTITY_DIE); // Paper - move below event cancellation check
|
|
+ boolean _boolean = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES); final boolean showDeathMessage = _boolean; // Paper - OBFHELPER
|
|
+ // CraftBukkit start - fire PlayerDeathEvent
|
|
+ if (this.isRemoved()) {
|
|
+ return;
|
|
+ }
|
|
+ List<DefaultDrop> loot = new java.util.ArrayList<>(this.getInventory().getContainerSize()); // Paper - Restore vanilla drops behavior
|
|
+ boolean keepInventory = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || this.isSpectator();
|
|
+ if (!keepInventory) {
|
|
+ for (ItemStack item : this.getInventory().getContents()) {
|
|
+ if (!item.isEmpty() && !EnchantmentHelper.has(item, net.minecraft.world.item.enchantment.EnchantmentEffectComponents.PREVENT_EQUIPMENT_DROP)) {
|
|
+ loot.add(new DefaultDrop(item, stack -> this.drop(stack, true, false, false, null))); // Paper - Restore vanilla drops behavior; drop function taken from Inventory#dropAll (don't fire drop event)
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (this.shouldDropLoot() && this.serverLevel().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Paper - fix player loottables running when mob loot gamerule is false
|
|
+ // SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule)
|
|
+ this.dropFromLootTable(this.serverLevel(), cause, this.lastHurtByPlayerMemoryTime > 0);
|
|
+ // Paper - Restore vanilla drops behaviour; custom death loot is a noop on server player, remove.
|
|
+ loot.addAll(this.drops);
|
|
+ this.drops.clear(); // SPIGOT-5188: make sure to clear
|
|
+ } // Paper - fix player loottables running when mob loot gamerule is false
|
|
+
|
|
+ Component defaultMessage = this.getCombatTracker().getDeathMessage();
|
|
+
|
|
+ String deathmessage = defaultMessage.getString();
|
|
+ this.keepLevel = keepInventory; // SPIGOT-2222: pre-set keepLevel
|
|
+ org.bukkit.event.entity.PlayerDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerDeathEvent(this, cause, loot, io.papermc.paper.adventure.PaperAdventure.asAdventure(defaultMessage), keepInventory); // Paper - Adventure
|
|
+ // Paper start - cancellable death event
|
|
+ if (event.isCancelled()) {
|
|
+ // make compatible with plugins that might have already set the health in an event listener
|
|
+ if (this.getHealth() <= 0) {
|
|
+ this.setHealth((float) event.getReviveHealth());
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+ this.gameEvent(GameEvent.ENTITY_DIE); // moved from the top of this method
|
|
+ // Paper end
|
|
+
|
|
+ // SPIGOT-943 - only call if they have an inventory open
|
|
+ if (this.containerMenu != this.inventoryMenu) {
|
|
+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DEATH); // Paper - Inventory close reason
|
|
+ }
|
|
+
|
|
+ net.kyori.adventure.text.Component apiDeathMessage = event.deathMessage() != null ? event.deathMessage() : net.kyori.adventure.text.Component.empty(); // Paper - Adventure
|
|
+
|
|
+ if (apiDeathMessage != null && apiDeathMessage != net.kyori.adventure.text.Component.empty() && showDeathMessage) { // Paper - Adventure // TODO: allow plugins to override?
|
|
+ Component deathMessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(apiDeathMessage); // Paper - Adventure
|
|
+
|
|
this.connection
|
|
.send(
|
|
new ClientboundPlayerCombatKillPacket(this.getId(), deathMessage),
|
|
@@ -835,11 +_,35 @@
|
|
this.tellNeutralMobsThatIDied();
|
|
}
|
|
|
|
- if (!this.isSpectator()) {
|
|
- this.dropAllDeathLoot(this.serverLevel(), cause);
|
|
+ // SPIGOT-5478 must be called manually now
|
|
+ if (event.shouldDropExperience()) this.dropExperience(this.serverLevel(), cause.getEntity()); // Paper - tie to event
|
|
+ // we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory.
|
|
+ if (!event.getKeepInventory()) {
|
|
+ // Paper start - PlayerDeathEvent#getItemsToKeep
|
|
+ for (int i = 0; i < this.getInventory().getNonEquipmentItems().size(); i++) {
|
|
+ if (!shouldKeepDeathEventItem(event, this.getInventory().getNonEquipmentItems().get(i))) {
|
|
+ this.getInventory().getNonEquipmentItems().set(i, net.minecraft.world.item.ItemStack.EMPTY);
|
|
+ }
|
|
+ }
|
|
+ for (final EquipmentSlot value : EquipmentSlot.VALUES) {
|
|
+ if (this.getInventory().equipment.has(value) && !shouldKeepDeathEventItem(event, this.getInventory().equipment.get(value))) {
|
|
+ this.getInventory().equipment.set(value, net.minecraft.world.item.ItemStack.EMPTY);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // remainder of items left in toKeep - plugin added stuff on death that wasn't in the initial loot?
|
|
+ if (!event.getItemsToKeep().isEmpty()) {
|
|
+ for (org.bukkit.inventory.ItemStack itemStack : event.getItemsToKeep()) {
|
|
+ event.getEntity().getInventory().addItem(itemStack);
|
|
+ }
|
|
+ }
|
|
+ // Paper end - PlayerDeathEvent#getItemsToKeep
|
|
}
|
|
|
|
- this.getScoreboard().forAllObjectives(ObjectiveCriteria.DEATH_COUNT, this, ScoreAccess::increment);
|
|
+ this.setCamera(this); // Remove spectated target
|
|
+ // CraftBukkit end
|
|
+
|
|
+ this.level().getCraftServer().getScoreboardManager().forAllObjectives(ObjectiveCriteria.DEATH_COUNT, this, ScoreAccess::increment); // CraftBukkit - Get our scores instead
|
|
LivingEntity killCredit = this.getKillCredit();
|
|
if (killCredit != null) {
|
|
this.awardStat(Stats.ENTITY_KILLED_BY.get(killCredit.getType()));
|
|
@@ -872,10 +_,10 @@
|
|
public void awardKillScore(Entity entity, DamageSource damageSource) {
|
|
if (entity != this) {
|
|
super.awardKillScore(entity, damageSource);
|
|
- this.getScoreboard().forAllObjectives(ObjectiveCriteria.KILL_COUNT_ALL, this, ScoreAccess::increment);
|
|
+ this.level().getCraftServer().getScoreboardManager().forAllObjectives(ObjectiveCriteria.KILL_COUNT_ALL, this, ScoreAccess::increment); // CraftBukkit - Get our scores instead
|
|
if (entity instanceof Player) {
|
|
this.awardStat(Stats.PLAYER_KILLS);
|
|
- this.getScoreboard().forAllObjectives(ObjectiveCriteria.KILL_COUNT_PLAYERS, this, ScoreAccess::increment);
|
|
+ this.level().getCraftServer().getScoreboardManager().forAllObjectives(ObjectiveCriteria.KILL_COUNT_PLAYERS, this, ScoreAccess::increment); // CraftBukkit - Get our scores instead
|
|
} else {
|
|
this.awardStat(Stats.MOB_KILLS);
|
|
}
|
|
@@ -891,7 +_,7 @@
|
|
if (playersTeam != null) {
|
|
int id = playersTeam.getColor().getId();
|
|
if (id >= 0 && id < crtieria.length) {
|
|
- this.getScoreboard().forAllObjectives(crtieria[id], scoreHolder, ScoreAccess::increment);
|
|
+ this.level().getCraftServer().getScoreboardManager().forAllObjectives(crtieria[id], scoreHolder, ScoreAccess::increment); // CraftBukkit - Get our scores instead
|
|
}
|
|
}
|
|
}
|
|
@@ -902,9 +_,20 @@
|
|
return false;
|
|
} else {
|
|
Entity entity = damageSource.getEntity();
|
|
- return !(entity instanceof Player player && !this.canHarmPlayer(player))
|
|
+ if (!( // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false.
|
|
+ !(entity instanceof Player player && !this.canHarmPlayer(player))
|
|
&& !(entity instanceof AbstractArrow abstractArrow && abstractArrow.getOwner() instanceof Player player1 && !this.canHarmPlayer(player1))
|
|
- && super.hurtServer(level, damageSource, amount);
|
|
+ )) return false; // Paper - split the if statement. If below statement is false, hurtServer would not have been evaluated. Return false.
|
|
+ // Paper start - cancellable death events
|
|
+ this.queueHealthUpdatePacket = true;
|
|
+ boolean damaged = super.hurtServer(level, damageSource, amount);
|
|
+ this.queueHealthUpdatePacket = false;
|
|
+ if (this.queuedHealthUpdatePacket != null) {
|
|
+ this.connection.send(this.queuedHealthUpdatePacket);
|
|
+ this.queuedHealthUpdatePacket = null;
|
|
+ }
|
|
+ return damaged;
|
|
+ // Paper end - cancellable death events
|
|
}
|
|
}
|
|
|
|
@@ -914,23 +_,81 @@
|
|
}
|
|
|
|
private boolean isPvpAllowed() {
|
|
- return this.server.isPvpAllowed();
|
|
+ return this.level().pvpMode; // CraftBukkit - this.server.isPvpAllowed() -> this.world.pvpMode
|
|
}
|
|
|
|
- public TeleportTransition findRespawnPositionAndUseSpawnBlock(boolean useCharge, TeleportTransition.PostTeleportTransition postTeleportTransition) {
|
|
+ // CraftBukkit start
|
|
+ public @Nullable TeleportTransition findRespawnPositionAndUseSpawnBlock(boolean useCharge, TeleportTransition.PostTeleportTransition postTeleportTransition, @Nullable org.bukkit.event.player.PlayerRespawnEvent.RespawnReason respawnReason) {
|
|
+ TeleportTransition teleportTransition;
|
|
+ boolean isBedSpawn = false;
|
|
+ boolean isAnchorSpawn = false;
|
|
+ // CraftBukkit end
|
|
ServerPlayer.RespawnConfig respawnConfig = this.getRespawnConfig();
|
|
ServerLevel level = this.server.getLevel(ServerPlayer.RespawnConfig.getDimensionOrDefault(respawnConfig));
|
|
if (level != null && respawnConfig != null) {
|
|
Optional<ServerPlayer.RespawnPosAngle> optional = findRespawnAndUseSpawnBlock(level, respawnConfig, useCharge);
|
|
if (optional.isPresent()) {
|
|
ServerPlayer.RespawnPosAngle respawnPosAngle = optional.get();
|
|
- return new TeleportTransition(level, respawnPosAngle.position(), Vec3.ZERO, respawnPosAngle.yaw(), 0.0F, postTeleportTransition);
|
|
+ // CraftBukkit start
|
|
+ isBedSpawn = respawnPosAngle.isBedSpawn();
|
|
+ isAnchorSpawn = respawnPosAngle.isAnchorSpawn();
|
|
+ teleportTransition = new TeleportTransition(level, respawnPosAngle.position(), Vec3.ZERO, respawnPosAngle.yaw(), 0.0F, postTeleportTransition);
|
|
+ // CraftBukkit end
|
|
} else {
|
|
- return TeleportTransition.missingRespawnBlock(this.server.overworld(), this, postTeleportTransition);
|
|
+ teleportTransition = TeleportTransition.missingRespawnBlock(this.server.overworld(), this, postTeleportTransition); // CraftBukkit
|
|
}
|
|
} else {
|
|
- return new TeleportTransition(this.server.overworld(), this, postTeleportTransition);
|
|
- }
|
|
+ teleportTransition = new TeleportTransition(this.server.overworld(), this, postTeleportTransition); // CraftBukkit
|
|
+ }
|
|
+ // CraftBukkit start
|
|
+ if (respawnReason == null) {
|
|
+ return teleportTransition;
|
|
+ }
|
|
+
|
|
+ org.bukkit.entity.Player respawnPlayer = this.getBukkitEntity();
|
|
+ org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(
|
|
+ teleportTransition.position(),
|
|
+ teleportTransition.newLevel().getWorld(),
|
|
+ teleportTransition.yRot(),
|
|
+ teleportTransition.xRot()
|
|
+ );
|
|
+
|
|
+ // Paper start - respawn flags
|
|
+ com.google.common.collect.ImmutableSet.Builder<org.bukkit.event.player.PlayerRespawnEvent.RespawnFlag> builder = com.google.common.collect.ImmutableSet.builder();
|
|
+ if (respawnReason == org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.END_PORTAL) {
|
|
+ builder.add(org.bukkit.event.player.PlayerRespawnEvent.RespawnFlag.END_PORTAL);
|
|
+ }
|
|
+ org.bukkit.event.player.PlayerRespawnEvent respawnEvent = new org.bukkit.event.player.PlayerRespawnEvent(
|
|
+ respawnPlayer,
|
|
+ location,
|
|
+ isBedSpawn,
|
|
+ isAnchorSpawn,
|
|
+ respawnReason,
|
|
+ builder
|
|
+ );
|
|
+ // Paper end - respawn flags
|
|
+ this.level().getCraftServer().getPluginManager().callEvent(respawnEvent);
|
|
+ // Spigot start
|
|
+ if (this.connection.isDisconnected()) {
|
|
+ return null;
|
|
+ }
|
|
+ // Spigot end
|
|
+
|
|
+ location = respawnEvent.getRespawnLocation();
|
|
+
|
|
+ return new TeleportTransition(
|
|
+ ((org.bukkit.craftbukkit.CraftWorld) location.getWorld()).getHandle(),
|
|
+ org.bukkit.craftbukkit.util.CraftLocation.toVec3(location),
|
|
+ teleportTransition.deltaMovement(),
|
|
+ location.getYaw(),
|
|
+ location.getPitch(),
|
|
+ teleportTransition.missingRespawnBlock(),
|
|
+ teleportTransition.asPassenger(),
|
|
+ teleportTransition.relatives(),
|
|
+ teleportTransition.postTeleportTransition(),
|
|
+ teleportTransition.cause()
|
|
+ );
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
public static Optional<ServerPlayer.RespawnPosAngle> findRespawnAndUseSpawnBlock(
|
|
@@ -947,10 +_,10 @@
|
|
level.setBlock(blockPos, blockState.setValue(RespawnAnchorBlock.CHARGE, blockState.getValue(RespawnAnchorBlock.CHARGE) - 1), 3);
|
|
}
|
|
|
|
- return optional.map(pos -> ServerPlayer.RespawnPosAngle.of(pos, blockPos));
|
|
+ return optional.map(pos -> ServerPlayer.RespawnPosAngle.of(pos, blockPos, false, true)); // CraftBukkit
|
|
} else if (block instanceof BedBlock && BedBlock.canSetSpawn(level)) {
|
|
return BedBlock.findStandUpPosition(EntityType.PLAYER, level, blockPos, blockState.getValue(BedBlock.FACING), f)
|
|
- .map(pos -> ServerPlayer.RespawnPosAngle.of(pos, blockPos));
|
|
+ .map(pos -> ServerPlayer.RespawnPosAngle.of(pos, blockPos, true, false)); // CraftBukkit
|
|
} else if (!flag) {
|
|
return Optional.empty();
|
|
} else {
|
|
@@ -958,7 +_,7 @@
|
|
BlockState blockState1 = level.getBlockState(blockPos.above());
|
|
boolean isPossibleToRespawnInThis1 = blockState1.getBlock().isPossibleToRespawnInThis(blockState1);
|
|
return isPossibleToRespawnInThis && isPossibleToRespawnInThis1
|
|
- ? Optional.of(new ServerPlayer.RespawnPosAngle(new Vec3(blockPos.getX() + 0.5, blockPos.getY() + 0.1, blockPos.getZ() + 0.5), f))
|
|
+ ? Optional.of(new ServerPlayer.RespawnPosAngle(new Vec3(blockPos.getX() + 0.5, blockPos.getY() + 0.1, blockPos.getZ() + 0.5), f, false, false)) // CraftBukkit
|
|
: Optional.empty();
|
|
}
|
|
}
|
|
@@ -976,6 +_,7 @@
|
|
@Nullable
|
|
@Override
|
|
public ServerPlayer teleport(TeleportTransition teleportTransition) {
|
|
+ if (this.isSleeping()) return null; // CraftBukkit - SPIGOT-3154
|
|
if (this.isRemoved()) {
|
|
return null;
|
|
} else {
|
|
@@ -985,17 +_,52 @@
|
|
|
|
ServerLevel level = teleportTransition.newLevel();
|
|
ServerLevel serverLevel = this.serverLevel();
|
|
- ResourceKey<Level> resourceKey = serverLevel.dimension();
|
|
+ // CraftBukkit start
|
|
+ ResourceKey<net.minecraft.world.level.dimension.LevelStem> resourceKey = serverLevel.getTypeKey();
|
|
+
|
|
+ org.bukkit.Location enter = this.getBukkitEntity().getLocation();
|
|
+ PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(teleportTransition), teleportTransition.relatives());
|
|
+ org.bukkit.Location exit = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(absolutePosition.position(), level.getWorld(), absolutePosition.yRot(), absolutePosition.xRot());
|
|
+ org.bukkit.event.player.PlayerTeleportEvent tpEvent = new org.bukkit.event.player.PlayerTeleportEvent(this.getBukkitEntity(), enter, exit.clone(), teleportTransition.cause());
|
|
+ // Paper start - gateway-specific teleport event
|
|
+ if (this.portalProcess != null && this.portalProcess.isSamePortal(((net.minecraft.world.level.block.EndGatewayBlock) net.minecraft.world.level.block.Blocks.END_GATEWAY)) && this.serverLevel().getBlockEntity(this.portalProcess.getEntryPosition()) instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity theEndGatewayBlockEntity) {
|
|
+ tpEvent = new com.destroystokyo.paper.event.player.PlayerTeleportEndGatewayEvent(this.getBukkitEntity(), enter, exit.clone(), new org.bukkit.craftbukkit.block.CraftEndGateway(this.serverLevel().getWorld(), theEndGatewayBlockEntity));
|
|
+ }
|
|
+ // Paper end - gateway-specific teleport event
|
|
+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(tpEvent);
|
|
+ org.bukkit.Location newExit = tpEvent.getTo();
|
|
+ if (tpEvent.isCancelled() || newExit == null) {
|
|
+ return null;
|
|
+ }
|
|
+ if (!newExit.equals(exit)) {
|
|
+ level = ((org.bukkit.craftbukkit.CraftWorld) newExit.getWorld()).getHandle();
|
|
+ teleportTransition = new TeleportTransition(
|
|
+ level,
|
|
+ org.bukkit.craftbukkit.util.CraftLocation.toVec3(newExit),
|
|
+ Vec3.ZERO,
|
|
+ newExit.getYaw(),
|
|
+ newExit.getPitch(),
|
|
+ teleportTransition.missingRespawnBlock(),
|
|
+ teleportTransition.asPassenger(),
|
|
+ Set.of(),
|
|
+ teleportTransition.postTeleportTransition(),
|
|
+ teleportTransition.cause());
|
|
+ }
|
|
+ // CraftBukkit end
|
|
if (!teleportTransition.asPassenger()) {
|
|
this.removeVehicle();
|
|
}
|
|
|
|
- if (level.dimension() == resourceKey) {
|
|
- this.connection.teleport(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives());
|
|
+ // CraftBukkit start
|
|
+ if (level != null && level.dimension() == serverLevel.dimension()) {
|
|
+ this.connection.internalTeleport(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives());
|
|
+ // CraftBukkit end
|
|
this.connection.resetPosition();
|
|
teleportTransition.postTeleportTransition().onTransition(this);
|
|
return this;
|
|
} else {
|
|
+ // CraftBukkit start
|
|
+ /*
|
|
this.isChangingDimension = true;
|
|
LevelData levelData = level.getLevelData();
|
|
this.connection.send(new ClientboundRespawnPacket(this.createCommonSpawnInfo(level), (byte)3));
|
|
@@ -1004,16 +_,30 @@
|
|
playerList.sendPlayerPermissionLevel(this);
|
|
serverLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION);
|
|
this.unsetRemoved();
|
|
+ */
|
|
+ // CraftBukkit end
|
|
ProfilerFiller profilerFiller = Profiler.get();
|
|
profilerFiller.push("moving");
|
|
- if (resourceKey == Level.OVERWORLD && level.dimension() == Level.NETHER) {
|
|
+ if (level != null && resourceKey == net.minecraft.world.level.dimension.LevelStem.OVERWORLD && level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER) { // CraftBukkit - empty to fall through to null to event
|
|
this.enteredNetherPosition = this.position();
|
|
}
|
|
|
|
profilerFiller.pop();
|
|
profilerFiller.push("placing");
|
|
+ // CraftBukkit start
|
|
+ this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds
|
|
+ LevelData worlddata = level.getLevelData();
|
|
+
|
|
+ this.connection.send(new ClientboundRespawnPacket(this.createCommonSpawnInfo(level), (byte) 3));
|
|
+ this.connection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked()));
|
|
+ PlayerList playerList = this.server.getPlayerList();
|
|
+
|
|
+ playerList.sendPlayerPermissionLevel(this);
|
|
+ serverLevel.removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION);
|
|
+ this.unsetRemoved();
|
|
+ // CraftBukkit end
|
|
this.setServerLevel(level);
|
|
- this.connection.teleport(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives());
|
|
+ this.connection.internalTeleport(PositionMoveRotation.of(teleportTransition), teleportTransition.relatives()); // CraftBukkit - use internal teleport without event
|
|
this.connection.resetPosition();
|
|
level.addDuringTeleport(this);
|
|
profilerFiller.pop();
|
|
@@ -1027,10 +_,39 @@
|
|
this.lastSentExp = -1;
|
|
this.lastSentHealth = -1.0F;
|
|
this.lastSentFood = -1;
|
|
+
|
|
+
|
|
+ // CraftBukkit start
|
|
+ org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), serverLevel.getWorld());
|
|
+ this.level().getCraftServer().getPluginManager().callEvent(changeEvent);
|
|
+ // CraftBukkit end
|
|
+ // Paper start - Reset shield blocking on dimension change
|
|
+ if (this.isBlocking()) {
|
|
+ this.stopUsingItem();
|
|
+ }
|
|
+ // Paper end - Reset shield blocking on dimension change
|
|
return this;
|
|
}
|
|
}
|
|
}
|
|
+
|
|
+ // CraftBukkit start
|
|
+ @Override
|
|
+ public @Nullable org.bukkit.craftbukkit.event.CraftPortalEvent callPortalEvent(
|
|
+ Entity entity,
|
|
+ org.bukkit.Location exit,
|
|
+ org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause,
|
|
+ int searchRadius, int creationRadius
|
|
+ ) {
|
|
+ org.bukkit.Location enter = this.getBukkitEntity().getLocation();
|
|
+ org.bukkit.event.player.PlayerPortalEvent event = new org.bukkit.event.player.PlayerPortalEvent(this.getBukkitEntity(), enter, exit, cause, searchRadius, true, creationRadius);
|
|
+ event.callEvent();
|
|
+ if (event.isCancelled() || event.getTo() == null || event.getTo().getWorld() == null) {
|
|
+ return null;
|
|
+ }
|
|
+ return new org.bukkit.craftbukkit.event.CraftPortalEvent(event);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
|
|
@Override
|
|
public void forceSetRotation(float yRot, float xRot) {
|
|
@@ -1040,12 +_,26 @@
|
|
public void triggerDimensionChangeTriggers(ServerLevel level) {
|
|
ResourceKey<Level> resourceKey = level.dimension();
|
|
ResourceKey<Level> resourceKey1 = this.level().dimension();
|
|
- CriteriaTriggers.CHANGED_DIMENSION.trigger(this, resourceKey, resourceKey1);
|
|
- if (resourceKey == Level.NETHER && resourceKey1 == Level.OVERWORLD && this.enteredNetherPosition != null) {
|
|
+ // CraftBukkit start
|
|
+ ResourceKey<Level> maindimensionkey = org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(level);
|
|
+ ResourceKey<Level> maindimensionkey1 = org.bukkit.craftbukkit.util.CraftDimensionUtil.getMainDimensionKey(this.level());
|
|
+ // Paper start - Add option for strict advancement dimension checks
|
|
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.strictAdvancementDimensionCheck) {
|
|
+ maindimensionkey = resourceKey;
|
|
+ maindimensionkey1 = resourceKey1;
|
|
+ }
|
|
+ // Paper end - Add option for strict advancement dimension checks
|
|
+ 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;
|
|
}
|
|
}
|
|
@@ -1061,19 +_,18 @@
|
|
this.containerMenu.broadcastChanges();
|
|
}
|
|
|
|
- @Override
|
|
- public Either<Player.BedSleepingProblem, Unit> startSleepInBed(BlockPos at) {
|
|
- Direction direction = this.level().getBlockState(at).getValue(HorizontalDirectionalBlock.FACING);
|
|
+ // CraftBukkit start - moved bed result checks from below into separate method
|
|
+ private Either<Player.BedSleepingProblem, Unit> getBedResult(BlockPos at, Direction direction) {
|
|
if (this.isSleeping() || !this.isAlive()) {
|
|
return Either.left(Player.BedSleepingProblem.OTHER_PROBLEM);
|
|
- } else if (!this.level().dimensionType().natural()) {
|
|
+ } else if (!this.level().dimensionType().natural() && !this.level().dimensionType().bedWorks()) { // CraftBukkit - moved bed result checks from below into separate method
|
|
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(new ServerPlayer.RespawnConfig(this.level().dimension(), at, this.getYRot(), false), true);
|
|
+ this.setRespawnPosition(new ServerPlayer.RespawnConfig(this.level().dimension(), at, this.getYRot(), false), true, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.BED); // Paper - Add PlayerSetSpawnEvent
|
|
if (this.level().isBrightOutside()) {
|
|
return Either.left(Player.BedSleepingProblem.NOT_POSSIBLE_NOW);
|
|
} else {
|
|
@@ -1092,7 +_,34 @@
|
|
}
|
|
}
|
|
|
|
- Either<Player.BedSleepingProblem, Unit> either = super.startSleepInBed(at).ifRight(unit -> {
|
|
+ // CraftBukkit start
|
|
+ return Either.right(Unit.INSTANCE);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public Either<net.minecraft.world.entity.player.Player.BedSleepingProblem, Unit> startSleepInBed(BlockPos at, boolean force) {
|
|
+ Direction direction = this.level().getBlockState(at).getValue(HorizontalDirectionalBlock.FACING);
|
|
+ Either<net.minecraft.world.entity.player.Player.BedSleepingProblem, Unit> bedResult = this.getBedResult(at, direction);
|
|
+
|
|
+ if (bedResult.left().orElse(null) == net.minecraft.world.entity.player.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, at, bedResult);
|
|
+ if (bedResult.left().isPresent()) {
|
|
+ return bedResult;
|
|
+ }
|
|
+
|
|
+ {
|
|
+ {
|
|
+ Either<net.minecraft.world.entity.player.Player.BedSleepingProblem, Unit> either = super.startSleepInBed(at, force).ifRight(unit -> {
|
|
+ // CraftBukkit end
|
|
this.awardStat(Stats.SLEEP_IN_BED);
|
|
CriteriaTriggers.SLEPT_IN_BED.trigger(this);
|
|
});
|
|
@@ -1128,21 +_,29 @@
|
|
|
|
@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
|
|
+ org.bukkit.block.Block bed = org.bukkit.craftbukkit.block.CraftBlock.at(this.level(), this.getSleepingPos().orElse(this.blockPosition()));
|
|
+ org.bukkit.event.player.PlayerBedLeaveEvent event = new org.bukkit.event.player.PlayerBedLeaveEvent(this.getBukkitEntity(), bed, true);
|
|
+ if (!event.callEvent()) {
|
|
+ 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(), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.EXIT_BED); // CraftBukkit
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isInvulnerableTo(ServerLevel level, DamageSource damageSource) {
|
|
- return super.isInvulnerableTo(level, damageSource)
|
|
+ return (super.isInvulnerableTo(level, damageSource) // Paper - disable player cramming;
|
|
|| this.isChangingDimension() && !damageSource.is(DamageTypes.ENDER_PEARL)
|
|
- || !this.hasClientLoaded();
|
|
+ || !this.hasClientLoaded()) || (!this.level().paperConfig().collisions.allowPlayerCrammingDamage && damageSource.is(DamageTypes.CRAMMING)); // Paper - disable player cramming;
|
|
}
|
|
|
|
@Override
|
|
@@ -1185,8 +_,9 @@
|
|
this.connection.send(new ClientboundOpenSignEditorPacket(signEntity.getBlockPos(), isFrontText));
|
|
}
|
|
|
|
- public void nextContainerCounter() {
|
|
+ public int nextContainerCounter() { // CraftBukkit - void -> int
|
|
this.containerCounter = this.containerCounter % 100 + 1;
|
|
+ return this.containerCounter; // CraftBukkit
|
|
}
|
|
|
|
@Override
|
|
@@ -1194,12 +_,39 @@
|
|
if (menu == null) {
|
|
return OptionalInt.empty();
|
|
} else {
|
|
- if (this.containerMenu != this.inventoryMenu) {
|
|
+ if (false && this.containerMenu != this.inventoryMenu) { // CraftBukkit - SPIGOT-6552: Handle inventory closing in CraftEventFactory#callInventoryOpenEventWithTitle(...)
|
|
this.closeContainer();
|
|
}
|
|
|
|
this.nextContainerCounter();
|
|
AbstractContainerMenu abstractContainerMenu = menu.createMenu(this.containerCounter, this.getInventory(), this);
|
|
+ Component title = null; // Paper - Add titleOverride to InventoryOpenEvent
|
|
+ // CraftBukkit start - Inventory open hook
|
|
+ if (abstractContainerMenu != null) {
|
|
+ abstractContainerMenu.setTitle(menu.getDisplayName());
|
|
+
|
|
+ boolean cancelled = false;
|
|
+ // Paper start - Add titleOverride to InventoryOpenEvent
|
|
+ final com.mojang.datafixers.util.Pair<net.kyori.adventure.text.Component, AbstractContainerMenu> result = org.bukkit.craftbukkit.event.CraftEventFactory.callInventoryOpenEventWithTitle(this, abstractContainerMenu, cancelled);
|
|
+ abstractContainerMenu = result.getSecond();
|
|
+ title = io.papermc.paper.adventure.PaperAdventure.asVanilla(result.getFirst());
|
|
+ // Paper end - Add titleOverride to InventoryOpenEvent
|
|
+ if (abstractContainerMenu == null && !cancelled) { // Let pre-cancelled events fall through
|
|
+ // SPIGOT-5263 - close chest if cancelled
|
|
+ if (menu instanceof Container container) {
|
|
+ container.stopOpen(this);
|
|
+ } else if (menu instanceof net.minecraft.world.level.block.ChestBlock.DoubleInventory doubleInventory) {
|
|
+ // SPIGOT-5355 - double chests too :(
|
|
+ doubleInventory.container.stopOpen(this);
|
|
+ // Paper start - Fix InventoryOpenEvent cancellation
|
|
+ } else if (!this.enderChestInventory.isActiveChest(null)) {
|
|
+ this.enderChestInventory.stopOpen(this);
|
|
+ // Paper end - Fix InventoryOpenEvent cancellation
|
|
+ }
|
|
+ return OptionalInt.empty();
|
|
+ }
|
|
+ }
|
|
+ // CraftBukkit end
|
|
if (abstractContainerMenu == null) {
|
|
if (this.isSpectator()) {
|
|
this.displayClientMessage(Component.translatable("container.spectatorCantOpen").withStyle(ChatFormatting.RED), true);
|
|
@@ -1207,10 +_,14 @@
|
|
|
|
return OptionalInt.empty();
|
|
} else {
|
|
+ // CraftBukkit start
|
|
+ this.containerMenu = abstractContainerMenu; // Moved up
|
|
+ if (!this.isImmobile())
|
|
this.connection
|
|
- .send(new ClientboundOpenScreenPacket(abstractContainerMenu.containerId, abstractContainerMenu.getType(), menu.getDisplayName()));
|
|
+ .send(new net.minecraft.network.protocol.game.ClientboundOpenScreenPacket(abstractContainerMenu.containerId, abstractContainerMenu.getType(), java.util.Objects.requireNonNullElseGet(title, abstractContainerMenu::getTitle))); // Paper - Add titleOverride to InventoryOpenEven
|
|
+ // CraftBukkit end
|
|
this.initMenu(abstractContainerMenu);
|
|
- this.containerMenu = abstractContainerMenu;
|
|
+ // CraftBukkit - moved up
|
|
return OptionalInt.of(this.containerCounter);
|
|
}
|
|
}
|
|
@@ -1223,14 +_,25 @@
|
|
|
|
@Override
|
|
public void openHorseInventory(AbstractHorse horse, Container inventory) {
|
|
+ // CraftBukkit start - Inventory open hook
|
|
+ this.nextContainerCounter(); // Moved up from below
|
|
+ AbstractContainerMenu container = new HorseInventoryMenu(this.containerCounter, this.getInventory(), inventory, horse, horse.getInventoryColumns());
|
|
+ container.setTitle(horse.getDisplayName());
|
|
+ container = org.bukkit.craftbukkit.event.CraftEventFactory.callInventoryOpenEvent(this, container);
|
|
+
|
|
+ if (container == null) {
|
|
+ inventory.stopOpen(this);
|
|
+ return;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
if (this.containerMenu != this.inventoryMenu) {
|
|
- this.closeContainer();
|
|
+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.OPEN_NEW); // Paper - Inventory close reason
|
|
}
|
|
|
|
- this.nextContainerCounter();
|
|
+ // this.nextContainerCounter(); // CraftBukkit - moved up
|
|
int inventoryColumns = horse.getInventoryColumns();
|
|
this.connection.send(new ClientboundHorseScreenOpenPacket(this.containerCounter, inventoryColumns, horse.getId()));
|
|
- this.containerMenu = new HorseInventoryMenu(this.containerCounter, this.getInventory(), inventory, horse, inventoryColumns);
|
|
+ this.containerMenu = container; // CraftBukkit
|
|
this.initMenu(this.containerMenu);
|
|
}
|
|
|
|
@@ -1252,10 +_,30 @@
|
|
|
|
@Override
|
|
public void closeContainer() {
|
|
+ // Paper start - Inventory close reason
|
|
+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNKNOWN);
|
|
+ }
|
|
+ @Override
|
|
+ public void closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
|
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit
|
|
+ // Paper end - Inventory close reason
|
|
this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
|
|
this.doCloseContainer();
|
|
}
|
|
|
|
+ // Paper start - special close for unloaded inventory
|
|
+ @Override
|
|
+ public void closeUnloadedInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
|
|
+ // copied from above
|
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit
|
|
+ // Paper end
|
|
+ // copied from below
|
|
+ this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
|
|
+ this.containerMenu = this.inventoryMenu;
|
|
+ // do not run close logic
|
|
+ }
|
|
+ // Paper end - special close for unloaded inventory
|
|
+
|
|
@Override
|
|
public void doCloseContainer() {
|
|
this.containerMenu.removed(this);
|
|
@@ -1278,19 +_,19 @@
|
|
int rounded = Math.round((float)Math.sqrt(dx * dx + dy * dy + dz * dz) * 100.0F);
|
|
if (rounded > 0) {
|
|
this.awardStat(Stats.SWIM_ONE_CM, rounded);
|
|
- this.causeFoodExhaustion(0.01F * rounded * 0.01F);
|
|
+ this.causeFoodExhaustion(this.level().spigotConfig.swimMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.SWIM); // CraftBukkit - EntityExhaustionEvent // Spigot
|
|
}
|
|
} else if (this.isEyeInFluid(FluidTags.WATER)) {
|
|
int rounded = Math.round((float)Math.sqrt(dx * dx + dy * dy + dz * dz) * 100.0F);
|
|
if (rounded > 0) {
|
|
this.awardStat(Stats.WALK_UNDER_WATER_ONE_CM, rounded);
|
|
- this.causeFoodExhaustion(0.01F * rounded * 0.01F);
|
|
+ this.causeFoodExhaustion(this.level().spigotConfig.swimMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.WALK_UNDERWATER); // CraftBukkit - EntityExhaustionEvent // Spigot
|
|
}
|
|
} else if (this.isInWater()) {
|
|
int rounded = Math.round((float)Math.sqrt(dx * dx + dz * dz) * 100.0F);
|
|
if (rounded > 0) {
|
|
this.awardStat(Stats.WALK_ON_WATER_ONE_CM, rounded);
|
|
- this.causeFoodExhaustion(0.01F * rounded * 0.01F);
|
|
+ this.causeFoodExhaustion(this.level().spigotConfig.swimMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.WALK_ON_WATER); // CraftBukkit - EntityExhaustionEvent // Spigot
|
|
}
|
|
} else if (this.onClimbable()) {
|
|
if (dy > 0.0) {
|
|
@@ -1301,13 +_,13 @@
|
|
if (rounded > 0) {
|
|
if (this.isSprinting()) {
|
|
this.awardStat(Stats.SPRINT_ONE_CM, rounded);
|
|
- this.causeFoodExhaustion(0.1F * rounded * 0.01F);
|
|
+ this.causeFoodExhaustion(this.level().spigotConfig.sprintMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.SPRINT); // CraftBukkit - EntityExhaustionEvent // Spigot
|
|
} else if (this.isCrouching()) {
|
|
this.awardStat(Stats.CROUCH_ONE_CM, rounded);
|
|
- this.causeFoodExhaustion(0.0F * rounded * 0.01F);
|
|
+ this.causeFoodExhaustion(this.level().spigotConfig.otherMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.CROUCH); // CraftBukkit - EntityExhaustionEvent // Spigot
|
|
} else {
|
|
this.awardStat(Stats.WALK_ONE_CM, rounded);
|
|
- this.causeFoodExhaustion(0.0F * rounded * 0.01F);
|
|
+ this.causeFoodExhaustion(this.level().spigotConfig.otherMultiplier * (float) rounded * 0.01F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.WALK); // CraftBukkit - EntityExhaustionEvent // Spigot
|
|
}
|
|
}
|
|
} else if (this.isFallFlying()) {
|
|
@@ -1347,13 +_,13 @@
|
|
@Override
|
|
public void awardStat(Stat<?> stat, int amount) {
|
|
this.stats.increment(this, stat, amount);
|
|
- this.getScoreboard().forAllObjectives(stat, this, score -> score.add(amount));
|
|
+ this.level().getCraftServer().getScoreboardManager().forAllObjectives(stat, this, score -> score.add(amount)); // CraftBukkit - Get our scores instead
|
|
}
|
|
|
|
@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
|
|
@@ -1384,9 +_,9 @@
|
|
super.jumpFromGround();
|
|
this.awardStat(Stats.JUMP);
|
|
if (this.isSprinting()) {
|
|
- this.causeFoodExhaustion(0.2F);
|
|
+ this.causeFoodExhaustion(this.level().spigotConfig.jumpSprintExhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.JUMP_SPRINT); // CraftBukkit - EntityExhaustionEvent // Spigot - Change to use configurable value
|
|
} else {
|
|
- this.causeFoodExhaustion(0.05F);
|
|
+ this.causeFoodExhaustion(this.level().spigotConfig.jumpWalkExhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.JUMP); // CraftBukkit - EntityExhaustionEvent // Spigot - Change to use configurable value
|
|
}
|
|
}
|
|
|
|
@@ -1399,6 +_,13 @@
|
|
public void disconnect() {
|
|
this.disconnected = true;
|
|
this.ejectPassengers();
|
|
+
|
|
+ // Paper start - Workaround vehicle not tracking the passenger disconnection dismount
|
|
+ if (this.isPassenger() && this.getVehicle() instanceof ServerPlayer) {
|
|
+ this.stopRiding();
|
|
+ }
|
|
+ // Paper end - Workaround vehicle not tracking the passenger disconnection dismount
|
|
+
|
|
if (this.isSleeping()) {
|
|
this.stopSleepInBed(true, false);
|
|
}
|
|
@@ -1410,6 +_,7 @@
|
|
|
|
public void resetSentInfo() {
|
|
this.lastSentHealth = -1.0E8F;
|
|
+ this.lastSentExp = -1; // CraftBukkit - Added to reset
|
|
}
|
|
|
|
@Override
|
|
@@ -1444,12 +_,12 @@
|
|
this.onUpdateAbilities();
|
|
if (keepEverything) {
|
|
this.getAttributes().assignBaseValues(that.getAttributes());
|
|
- this.getAttributes().assignPermanentModifiers(that.getAttributes());
|
|
+ // this.getAttributes().assignPermanentModifiers(that.getAttributes()); // CraftBukkit
|
|
this.setHealth(that.getHealth());
|
|
this.foodData = that.foodData;
|
|
|
|
for (MobEffectInstance mobEffectInstance : that.getActiveEffects()) {
|
|
- this.addEffect(new MobEffectInstance(mobEffectInstance));
|
|
+ // this.addEffect(new MobEffectInstance(mobEffectInstance)); // CraftBukkit
|
|
}
|
|
|
|
this.getInventory().replaceWith(that.getInventory());
|
|
@@ -1460,7 +_,7 @@
|
|
this.portalProcess = that.portalProcess;
|
|
} else {
|
|
this.getAttributes().assignBaseValues(that.getAttributes());
|
|
- this.setHealth(this.getMaxHealth());
|
|
+ // this.setHealth(this.getMaxHealth()); // CraftBukkit
|
|
if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || that.isSpectator()) {
|
|
this.getInventory().replaceWith(that.getInventory());
|
|
this.experienceLevel = that.experienceLevel;
|
|
@@ -1476,7 +_,7 @@
|
|
this.lastSentExp = -1;
|
|
this.lastSentHealth = -1.0F;
|
|
this.lastSentFood = -1;
|
|
- this.recipeBook.copyOverData(that.recipeBook);
|
|
+ // this.recipeBook.copyOverData(that.recipeBook); // CraftBukkit
|
|
this.seenCredits = that.seenCredits;
|
|
this.enteredNetherPosition = that.enteredNetherPosition;
|
|
this.chunkTrackingView = that.chunkTrackingView;
|
|
@@ -1529,7 +_,7 @@
|
|
}
|
|
|
|
@Override
|
|
- public boolean teleportTo(ServerLevel level, double x, double y, double z, Set<Relative> relativeMovements, float yaw, float pitch, boolean setCamera) {
|
|
+ public boolean teleportTo(ServerLevel level, double x, double y, double z, Set<Relative> relativeMovements, float yaw, float pitch, boolean setCamera, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) { // CraftBukkit
|
|
if (this.isSleeping()) {
|
|
this.stopSleepInBed(true, true);
|
|
}
|
|
@@ -1538,7 +_,7 @@
|
|
this.setCamera(this);
|
|
}
|
|
|
|
- boolean flag = super.teleportTo(level, x, y, z, relativeMovements, yaw, pitch, setCamera);
|
|
+ boolean flag = super.teleportTo(level, x, y, z, relativeMovements, yaw, pitch, setCamera, cause); // CraftBukkit
|
|
if (flag) {
|
|
this.setYHeadRot(relativeMovements.contains(Relative.Y_ROT) ? this.getYHeadRot() + yaw : yaw);
|
|
}
|
|
@@ -1575,9 +_,17 @@
|
|
}
|
|
|
|
public boolean setGameMode(GameType gameMode) {
|
|
+ // Paper start - Expand PlayerGameModeChangeEvent
|
|
+ org.bukkit.event.player.PlayerGameModeChangeEvent event = this.setGameMode(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.UNKNOWN, null);
|
|
+ return event == null ? false : event.isCancelled();
|
|
+ }
|
|
+ @Nullable
|
|
+ public org.bukkit.event.player.PlayerGameModeChangeEvent setGameMode(GameType gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause cause, @Nullable net.kyori.adventure.text.Component message) {
|
|
boolean isSpectator = this.isSpectator();
|
|
- if (!this.gameMode.changeGameModeForPlayer(gameMode)) {
|
|
- return false;
|
|
+ org.bukkit.event.player.PlayerGameModeChangeEvent event = this.gameMode.changeGameModeForPlayer(gameMode, cause, message);
|
|
+ if (event == null || event.isCancelled()) {
|
|
+ return null;
|
|
+ // Paper end - Expand PlayerGameModeChangeEvent
|
|
} else {
|
|
this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, gameMode.getId()));
|
|
if (gameMode == GameType.SPECTATOR) {
|
|
@@ -1593,7 +_,7 @@
|
|
|
|
this.onUpdateAbilities();
|
|
this.updateEffectVisibility();
|
|
- return true;
|
|
+ return event; // Paper - Expand PlayerGameModeChangeEvent
|
|
}
|
|
}
|
|
|
|
@@ -1649,8 +_,13 @@
|
|
}
|
|
|
|
public void sendChatMessage(OutgoingChatMessage message, boolean filtered, ChatType.Bound boundType) {
|
|
+ // Paper start
|
|
+ this.sendChatMessage(message, filtered, boundType, null);
|
|
+ }
|
|
+ public void sendChatMessage(OutgoingChatMessage message, boolean filtered, ChatType.Bound boundType, @Nullable Component unsigned) {
|
|
+ // Paper end
|
|
if (this.acceptsChatMessages()) {
|
|
- message.sendToPlayer(this, filtered, boundType);
|
|
+ message.sendToPlayer(this, filtered, boundType, unsigned); // Paper
|
|
}
|
|
}
|
|
|
|
@@ -1661,7 +_,42 @@
|
|
}
|
|
|
|
public void updateOptions(ClientInformation clientInformation) {
|
|
+ // Paper start - settings event
|
|
+ new com.destroystokyo.paper.event.player.PlayerClientOptionsChangeEvent(this.getBukkitEntity(), Util.make(new java.util.IdentityHashMap<>(), map -> {
|
|
+ map.put(com.destroystokyo.paper.ClientOption.LOCALE, clientInformation.language());
|
|
+ map.put(com.destroystokyo.paper.ClientOption.VIEW_DISTANCE, clientInformation.viewDistance());
|
|
+ map.put(com.destroystokyo.paper.ClientOption.CHAT_VISIBILITY, com.destroystokyo.paper.ClientOption.ChatVisibility.valueOf(clientInformation.chatVisibility().name()));
|
|
+ map.put(com.destroystokyo.paper.ClientOption.CHAT_COLORS_ENABLED, clientInformation.chatColors());
|
|
+ map.put(com.destroystokyo.paper.ClientOption.SKIN_PARTS, new com.destroystokyo.paper.PaperSkinParts(clientInformation.modelCustomisation()));
|
|
+ map.put(com.destroystokyo.paper.ClientOption.MAIN_HAND, clientInformation.mainHand() == HumanoidArm.LEFT ? org.bukkit.inventory.MainHand.LEFT : org.bukkit.inventory.MainHand.RIGHT);
|
|
+ map.put(com.destroystokyo.paper.ClientOption.TEXT_FILTERING_ENABLED, clientInformation.textFilteringEnabled());
|
|
+ map.put(com.destroystokyo.paper.ClientOption.ALLOW_SERVER_LISTINGS, clientInformation.allowsListing());
|
|
+ map.put(com.destroystokyo.paper.ClientOption.PARTICLE_VISIBILITY, com.destroystokyo.paper.ClientOption.ParticleVisibility.valueOf(clientInformation.particleStatus().name()));
|
|
+ })).callEvent();
|
|
+ // Paper end - settings event
|
|
+ // CraftBukkit start
|
|
+ if (this.getMainArm() != clientInformation.mainHand()) {
|
|
+ org.bukkit.event.player.PlayerChangedMainHandEvent event = new org.bukkit.event.player.PlayerChangedMainHandEvent(
|
|
+ this.getBukkitEntity(),
|
|
+ clientInformation.mainHand() == HumanoidArm.LEFT ? org.bukkit.inventory.MainHand.LEFT : org.bukkit.inventory.MainHand.RIGHT
|
|
+ );
|
|
+ this.server.server.getPluginManager().callEvent(event);
|
|
+ }
|
|
+ if (this.language == null || !this.language.equals(clientInformation.language())) { // Paper
|
|
+ org.bukkit.event.player.PlayerLocaleChangeEvent event = new org.bukkit.event.player.PlayerLocaleChangeEvent(
|
|
+ this.getBukkitEntity(),
|
|
+ clientInformation.language()
|
|
+ );
|
|
+ this.server.server.getPluginManager().callEvent(event);
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+ // Paper start - don't call options events on login
|
|
+ this.updateOptionsNoEvents(clientInformation);
|
|
+ }
|
|
+ public void updateOptionsNoEvents(ClientInformation clientInformation) {
|
|
+ // Paper end
|
|
this.language = clientInformation.language();
|
|
+ this.adventure$locale = java.util.Objects.requireNonNullElse(net.kyori.adventure.translation.Translator.parseLocale(this.language), java.util.Locale.US); // Paper
|
|
this.requestedViewDistance = clientInformation.viewDistance();
|
|
this.chatVisibility = clientInformation.chatVisibility();
|
|
this.canChatColor = clientInformation.chatColors();
|
|
@@ -1747,8 +_,23 @@
|
|
Entity camera = this.getCamera();
|
|
this.camera = (Entity)(entityToSpectate == null ? this : entityToSpectate);
|
|
if (camera != this.camera) {
|
|
+ // Paper start - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity
|
|
+ if (this.camera == this) {
|
|
+ com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent playerStopSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStopSpectatingEntityEvent(this.getBukkitEntity(), camera.getBukkitEntity());
|
|
+ if (!playerStopSpectatingEntityEvent.callEvent()) {
|
|
+ this.camera = camera; // rollback camera entity again
|
|
+ return;
|
|
+ }
|
|
+ } else {
|
|
+ com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent playerStartSpectatingEntityEvent = new com.destroystokyo.paper.event.player.PlayerStartSpectatingEntityEvent(this.getBukkitEntity(), camera.getBukkitEntity(), entityToSpectate.getBukkitEntity());
|
|
+ if (!playerStartSpectatingEntityEvent.callEvent()) {
|
|
+ this.camera = camera; // rollback camera entity again
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ // Paper end - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity
|
|
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(), false);
|
|
+ this.teleportTo(serverLevel, this.camera.getX(), this.camera.getY(), this.camera.getZ(), Set.of(), this.getYRot(), this.getXRot(), false, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.SPECTATE); // CraftBukkit
|
|
}
|
|
|
|
if (entityToSpectate != null) {
|
|
@@ -1782,11 +_,11 @@
|
|
|
|
@Nullable
|
|
public Component getTabListDisplayName() {
|
|
- return null;
|
|
+ return this.listName; // CraftBukkit
|
|
}
|
|
|
|
public int getTabListOrder() {
|
|
- return 0;
|
|
+ return this.listOrder; // CraftBukkit
|
|
}
|
|
|
|
@Override
|
|
@@ -1817,11 +_,56 @@
|
|
}
|
|
|
|
public void setRespawnPosition(@Nullable ServerPlayer.RespawnConfig respawnConfig, boolean displayInChat) {
|
|
- if (displayInChat && respawnConfig != null && !respawnConfig.isSamePosition(this.respawnConfig)) {
|
|
- this.sendSystemMessage(SPAWN_SET_MESSAGE);
|
|
+ // Paper start - Add PlayerSetSpawnEvent
|
|
+ this.setRespawnPosition(respawnConfig, displayInChat, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.UNKNOWN);
|
|
+ }
|
|
+
|
|
+ public boolean setRespawnPosition(@Nullable ServerPlayer.RespawnConfig respawnConfig, boolean displayInChat, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause cause) {
|
|
+ org.bukkit.Location spawnLoc = null;
|
|
+ boolean actuallyDisplayInChat = false;
|
|
+ if (respawnConfig != null) {
|
|
+ actuallyDisplayInChat = displayInChat && !respawnConfig.isSamePosition(this.respawnConfig);
|
|
+ spawnLoc = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(respawnConfig.pos(), this.getServer().getLevel(respawnConfig.dimension()));
|
|
+ spawnLoc.setYaw(respawnConfig.angle());
|
|
+ }
|
|
+ org.bukkit.event.player.PlayerSpawnChangeEvent dumbEvent = new org.bukkit.event.player.PlayerSpawnChangeEvent(
|
|
+ this.getBukkitEntity(),
|
|
+ spawnLoc,
|
|
+ respawnConfig != null && respawnConfig.forced(),
|
|
+ cause == com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.PLAYER_RESPAWN
|
|
+ ? org.bukkit.event.player.PlayerSpawnChangeEvent.Cause.RESET
|
|
+ : org.bukkit.event.player.PlayerSpawnChangeEvent.Cause.valueOf(cause.name())
|
|
+ );
|
|
+ dumbEvent.callEvent();
|
|
+
|
|
+ com.destroystokyo.paper.event.player.PlayerSetSpawnEvent event = new com.destroystokyo.paper.event.player.PlayerSetSpawnEvent(
|
|
+ this.getBukkitEntity(),
|
|
+ cause,
|
|
+ dumbEvent.getNewSpawn(),
|
|
+ dumbEvent.isForced(),
|
|
+ actuallyDisplayInChat,
|
|
+ actuallyDisplayInChat ? io.papermc.paper.adventure.PaperAdventure.asAdventure(SPAWN_SET_MESSAGE) : null
|
|
+ );
|
|
+ event.setCancelled(dumbEvent.isCancelled());
|
|
+ if (!event.callEvent()) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (event.getLocation() != null) {
|
|
+ respawnConfig = new ServerPlayer.RespawnConfig(
|
|
+ ((org.bukkit.craftbukkit.CraftWorld) event.getLocation().getWorld()).getHandle().dimension(),
|
|
+ org.bukkit.craftbukkit.util.CraftLocation.toBlockPosition(event.getLocation()),
|
|
+ event.getLocation().getYaw(),
|
|
+ event.isForced()
|
|
+ );
|
|
+ if (event.willNotifyPlayer() && event.getNotification() != null) {
|
|
+ this.sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.getNotification()));
|
|
+ }
|
|
}
|
|
|
|
this.respawnConfig = respawnConfig;
|
|
+ return true;
|
|
+ // Paper end - Add PlayerSetSpawnEvent
|
|
}
|
|
|
|
public SectionPos getLastSectionPos() {
|
|
@@ -1851,16 +_,23 @@
|
|
}
|
|
|
|
@Override
|
|
- public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean traceItem) {
|
|
- ItemEntity itemEntity = super.drop(droppedItem, dropAround, traceItem);
|
|
+ public ItemEntity drop(ItemStack droppedItem, boolean dropAround, boolean traceItem, boolean callEvent, @Nullable java.util.function.Consumer<org.bukkit.entity.Item> entityOperation) { // Paper - Extend dropItem API
|
|
+ ItemEntity itemEntity = super.drop(droppedItem, dropAround, traceItem, callEvent, entityOperation); // Paper - Extend dropItem API
|
|
+ ItemStack itemStack = itemEntity != null ? itemEntity.getItem() : ItemStack.EMPTY; // Paper - move up
|
|
if (traceItem) {
|
|
- ItemStack itemStack = itemEntity != null ? itemEntity.getItem() : ItemStack.EMPTY;
|
|
if (!itemStack.isEmpty()) {
|
|
this.awardStat(Stats.ITEM_DROPPED.get(itemStack.getItem()), droppedItem.getCount());
|
|
this.awardStat(Stats.DROP);
|
|
}
|
|
}
|
|
-
|
|
+ // Paper start - remove player from map on drop
|
|
+ if (itemStack.is(net.minecraft.world.item.Items.FILLED_MAP)) {
|
|
+ final MapItemSavedData mapData = MapItem.getSavedData(itemStack, this.level());
|
|
+ if (mapData != null) {
|
|
+ mapData.tickCarriedBy(this, itemStack);
|
|
+ }
|
|
+ }
|
|
+ // Paper end - remove player from map on drop
|
|
return itemEntity;
|
|
}
|
|
|
|
@@ -1888,6 +_,16 @@
|
|
}
|
|
|
|
public void loadGameTypes(@Nullable CompoundTag tag) {
|
|
+ // Paper start - Expand PlayerGameModeChangeEvent
|
|
+ if (this.server.getForcedGameType() != null && this.server.getForcedGameType() != readPlayerMode(tag, "playerGameType")) {
|
|
+ if (new org.bukkit.event.player.PlayerGameModeChangeEvent(this.getBukkitEntity(), org.bukkit.GameMode.getByValue(this.server.getDefaultGameType().getId()), org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null).callEvent()) {
|
|
+ this.gameMode.setGameModeForPlayer(this.server.getForcedGameType(), GameType.DEFAULT_MODE);
|
|
+ } else {
|
|
+ this.gameMode.setGameModeForPlayer(readPlayerMode(tag,"playerGameType"), readPlayerMode(tag, "previousPlayerGameType"));
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+ // Paper end - Expand PlayerGameModeChangeEvent
|
|
this.gameMode
|
|
.setGameModeForPlayer(this.calculateGameModeForNewPlayer(readPlayerMode(tag, "playerGameType")), readPlayerMode(tag, "previousPlayerGameType"));
|
|
}
|
|
@@ -1989,8 +_,14 @@
|
|
|
|
@Override
|
|
public void removeVehicle() {
|
|
+ // Paper start - Force entity dismount during teleportation
|
|
+ this.removeVehicle(false);
|
|
+ }
|
|
+ @Override
|
|
+ public void removeVehicle(final boolean suppressCancellation) {
|
|
+ // Paper end - Force entity dismount during teleportation
|
|
Entity vehicle = this.getVehicle();
|
|
- super.removeVehicle();
|
|
+ super.removeVehicle(suppressCancellation); // Paper - Force entity dismount during teleportation
|
|
if (vehicle instanceof LivingEntity livingEntity) {
|
|
for (MobEffectInstance mobEffectInstance : livingEntity.getActiveEffects()) {
|
|
this.connection.send(new ClientboundRemoveMobEffectPacket(vehicle.getId(), mobEffectInstance.getEffect()));
|
|
@@ -2089,7 +_,7 @@
|
|
}
|
|
|
|
public static long placeEnderPearlTicket(ServerLevel level, ChunkPos pos) {
|
|
- level.getChunkSource().addTicketWithRadius(TicketType.ENDER_PEARL, pos, 2);
|
|
+ if (!level.paperConfig().misc.legacyEnderPearlBehavior) level.getChunkSource().addTicketWithRadius(TicketType.ENDER_PEARL, pos, 2); // Paper - Allow using old ender pearl behavior
|
|
return TicketType.ENDER_PEARL.timeout();
|
|
}
|
|
|
|
@@ -2113,9 +_,11 @@
|
|
}
|
|
}
|
|
|
|
- public record RespawnPosAngle(Vec3 position, float yaw) {
|
|
- public static ServerPlayer.RespawnPosAngle of(Vec3 position, BlockPos towardsPos) {
|
|
- return new ServerPlayer.RespawnPosAngle(position, calculateLookAtYaw(position, towardsPos));
|
|
+ // CraftBukkit start
|
|
+ public record RespawnPosAngle(Vec3 position, float yaw, boolean isBedSpawn, boolean isAnchorSpawn) {
|
|
+ public static ServerPlayer.RespawnPosAngle of(Vec3 position, BlockPos towardsPos, boolean isBedSpawn, boolean isAnchorSpawn) {
|
|
+ return new ServerPlayer.RespawnPosAngle(position, calculateLookAtYaw(position, towardsPos), isBedSpawn, isAnchorSpawn);
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
private static float calculateLookAtYaw(Vec3 position, BlockPos towardsPos) {
|
|
@@ -2123,4 +_,143 @@
|
|
return (float)Mth.wrapDegrees(Mth.atan2(vec3.z, vec3.x) * 180.0F / (float)Math.PI - 90.0);
|
|
}
|
|
}
|
|
+
|
|
+ // 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 @Nullable org.bukkit.WeatherType weatherType = null;
|
|
+
|
|
+ public void setPlayerWeather(org.bukkit.WeatherType type, boolean plugin) {
|
|
+ if (!plugin && this.weatherType != null) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (plugin) {
|
|
+ this.weatherType = type;
|
|
+ }
|
|
+
|
|
+ if (type == org.bukkit.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.weatherType == null) {
|
|
+ // Vanilla
|
|
+ if (oldRain != newRain) {
|
|
+ this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, newRain));
|
|
+ }
|
|
+ } else {
|
|
+ // Plugin
|
|
+ if (this.pluginRainPositionPrevious != this.pluginRainPosition) {
|
|
+ this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, this.pluginRainPosition));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (oldThunder != newThunder) {
|
|
+ if (this.weatherType == org.bukkit.WeatherType.DOWNFALL || this.weatherType == 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.weatherType == null) return;
|
|
+
|
|
+ this.pluginRainPositionPrevious = this.pluginRainPosition;
|
|
+ if (this.weatherType == org.bukkit.WeatherType.DOWNFALL) {
|
|
+ this.pluginRainPosition += 0.01F;
|
|
+ } else {
|
|
+ this.pluginRainPosition -= 0.01F;
|
|
+ }
|
|
+
|
|
+ this.pluginRainPosition = Mth.clamp(this.pluginRainPosition, 0.0F, 1.0F);
|
|
+ }
|
|
+
|
|
+ public void resetPlayerWeather() {
|
|
+ this.weatherType = null;
|
|
+ this.setPlayerWeather(this.level().getLevelData().isRaining() ? org.bukkit.WeatherType.DOWNFALL : org.bukkit.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.snapTo(x, y, z, yaw, pitch);
|
|
+ this.connection.resetPosition();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public boolean isImmobile() {
|
|
+ return super.isImmobile() || (this.connection != null && this.connection.isDisconnected()); // Paper - Fix duplication bugs
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public net.minecraft.world.scores.Scoreboard getScoreboard() {
|
|
+ return this.getBukkitEntity().getScoreboard().getHandle();
|
|
+ }
|
|
+
|
|
+ public void reset() {
|
|
+ float exp = 0;
|
|
+
|
|
+ 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.setAirSupply(this.getMaxAirSupply()); // Paper - Reset players airTicks on respawn
|
|
+ this.setRemainingFireTicks(0);
|
|
+ this.fallDistance = 0;
|
|
+ this.foodData = new net.minecraft.world.food.FoodData();
|
|
+ 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 net.minecraft.world.damagesource.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
|
|
+ this.skipDropExperience = false; // CraftBukkit - SPIGOT-7462: Reset experience drop skip, so that further deaths drop xp
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public org.bukkit.craftbukkit.entity.CraftPlayer getBukkitEntity() {
|
|
+ return (org.bukkit.craftbukkit.entity.CraftPlayer) super.getBukkitEntity();
|
|
+ }
|
|
+ // CraftBukkit end
|
|
}
|