From 3430a002d12b6bb7e5325215d347052910a42fc3 Mon Sep 17 00:00:00 2001 From: Aikar Date: Tue, 3 Jul 2018 21:56:23 -0400 Subject: [PATCH] InventoryCloseEvent Reason API Allows you to determine why an inventory was closed, enabling plugin developers to "confirm" things based on if it was player triggered close or not. --- .../server/level/ServerLevel.java.patch | 4 +- .../server/level/ServerPlayer.java.patch | 90 +++++++++++-------- .../ServerGamePacketListenerImpl.java.patch | 74 ++++++++------- .../server/players/PlayerList.java.patch | 2 +- .../world/entity/player/Player.java.patch | 84 ++++++++++------- .../craftbukkit/entity/CraftHumanEntity.java | 10 ++- .../craftbukkit/entity/CraftPlayer.java | 2 +- .../craftbukkit/event/CraftEventFactory.java | 14 ++- 8 files changed, 168 insertions(+), 112 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch index 6027f94fe9..5259fe2a14 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerLevel.java.patch @@ -617,7 +617,7 @@ + for (net.minecraft.world.level.block.entity.BlockEntity tileentity : chunk.getBlockEntities().values()) { + if (tileentity instanceof net.minecraft.world.Container) { + for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((net.minecraft.world.Container) tileentity).getViewers())) { -+ h.closeInventory(); ++ h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - Inventory close reason + } + } + } @@ -976,7 +976,7 @@ + // Spigot Start + if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message + for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((org.bukkit.inventory.InventoryHolder) entity.getBukkitEntity()).getInventory().getViewers())) { -+ h.closeInventory(); ++ h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper - Inventory close reason + } + } + // Spigot End diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch index 3a01e38e99..6091983499 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -175,8 +175,8 @@ + this.adventure$displayName = net.kyori.adventure.text.Component.text(this.getScoreboardName()); // Paper + this.bukkitPickUpLoot = true; + this.maxHealthCache = this.getMaxHealth(); -+ } -+ + } + + // Use method to resend items in hands in case of client desync, because the item use got cancelled. + // For example, when cancelling the leash event + public void resendItemInHands() { @@ -222,9 +222,9 @@ + } + + return blockposition; - } ++ } + // CraftBukkit end - ++ @Override public BlockPos adjustSpawnLocation(ServerLevel world, BlockPos basePos) { AABB axisalignedbb = this.getDimensions(Pose.STANDING).makeBoundingBox(Vec3.ZERO); @@ -418,7 +418,7 @@ this.tickClientLoadTimeout(); this.gameMode.tick(); this.wardenSpawnTracker.tick(); -@@ -751,7 +924,11 @@ +@@ -751,9 +924,13 @@ --this.invulnerableTime; } @@ -429,8 +429,11 @@ + } + // Paper end - Configurable container update tick rate if (!this.containerMenu.stillValid(this)) { - this.closeContainer(); +- this.closeContainer(); ++ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper - Inventory close reason this.containerMenu = this.inventoryMenu; + } + @@ -820,7 +997,7 @@ } @@ -528,11 +531,11 @@ + + // SPIGOT-943 - only call if they have an inventory open + if (this.containerMenu != this.inventoryMenu) { -+ this.closeContainer(); ++ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DEATH); // Paper - Inventory close reason + } - -+ net.kyori.adventure.text.Component deathMessage = event.deathMessage() != null ? event.deathMessage() : net.kyori.adventure.text.Component.empty(); // Paper - Adventure + ++ net.kyori.adventure.text.Component deathMessage = event.deathMessage() != null ? event.deathMessage() : net.kyori.adventure.text.Component.empty(); // Paper - Adventure + + if (deathMessage != null && deathMessage != net.kyori.adventure.text.Component.empty() && flag) { // Paper - Adventure // TODO: allow plugins to override? + Component ichatbasecomponent = PaperAdventure.asVanilla(deathMessage); // Paper - Adventure + @@ -799,7 +802,7 @@ this.connection.resetPosition(); worldserver.addDuringTeleport(this); gameprofilerfiller.pop(); -@@ -1215,10 +1525,28 @@ +@@ -1215,12 +1525,30 @@ this.lastSentExp = -1; this.lastSentHealth = -1.0F; this.lastSentFood = -1; @@ -810,24 +813,26 @@ + // CraftBukkit end return this; } -+ } -+ } -+ + } + } + + // CraftBukkit start -+ @Override + @Override + public CraftPortalEvent callPortalEvent(Entity entity, Location exit, TeleportCause cause, int searchRadius, int creationRadius) { + Location enter = this.getBukkitEntity().getLocation(); + 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 - - @Override ++ ++ @Override public void forceSetRotation(float yaw, float pitch) { + this.connection.send(new ClientboundPlayerRotationPacket(yaw, pitch)); + } @@ -1228,13 +1556,21 @@ public void triggerDimensionChangeTriggers(ServerLevel origin) { ResourceKey resourcekey = origin.dimension(); @@ -1053,7 +1058,8 @@ + } + // CraftBukkit end if (this.containerMenu != this.inventoryMenu) { - this.closeContainer(); +- this.closeContainer(); ++ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.OPEN_NEW); // Paper - Inventory close reason } - this.nextContainerCounter(); @@ -1066,15 +1072,21 @@ this.initMenu(this.containerMenu); } -@@ -1456,6 +1872,7 @@ +@@ -1456,6 +1872,13 @@ @Override public void closeContainer() { -+ CraftEventFactory.handleInventoryCloseEvent(this); // CraftBukkit ++ // 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) { ++ CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit ++ // Paper end - Inventory close reason this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId)); this.doCloseContainer(); } -@@ -1485,19 +1902,19 @@ +@@ -1485,19 +1908,19 @@ i = Math.round((float) Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) * 100.0F); if (i > 0) { this.awardStat(Stats.SWIM_ONE_CM, i); @@ -1097,7 +1109,7 @@ } } else if (this.onClimbable()) { if (deltaY > 0.0D) { -@@ -1508,13 +1925,13 @@ +@@ -1508,13 +1931,13 @@ if (i > 0) { if (this.isSprinting()) { this.awardStat(Stats.SPRINT_ONE_CM, i); @@ -1114,7 +1126,7 @@ } } } else if (this.isFallFlying()) { -@@ -1557,7 +1974,7 @@ +@@ -1557,7 +1980,7 @@ @Override public void awardStat(Stat stat, int amount) { this.stats.increment(this, stat, amount); @@ -1123,7 +1135,7 @@ scoreaccess.add(amount); }); } -@@ -1565,7 +1982,7 @@ +@@ -1565,7 +1988,7 @@ @Override public void resetStat(Stat stat) { this.stats.setValue(this, stat, 0); @@ -1132,7 +1144,7 @@ } @Override -@@ -1597,9 +2014,9 @@ +@@ -1597,9 +2020,9 @@ super.jumpFromGround(); this.awardStat(Stats.JUMP); if (this.isSprinting()) { @@ -1144,7 +1156,7 @@ } } -@@ -1625,6 +2042,7 @@ +@@ -1625,6 +2048,7 @@ public void resetSentInfo() { this.lastSentHealth = -1.0E8F; @@ -1152,7 +1164,7 @@ } @Override -@@ -1661,7 +2079,7 @@ +@@ -1661,7 +2085,7 @@ this.onUpdateAbilities(); if (alive) { this.getAttributes().assignBaseValues(oldPlayer.getAttributes()); @@ -1161,7 +1173,7 @@ this.setHealth(oldPlayer.getHealth()); this.foodData = oldPlayer.foodData; Iterator iterator = oldPlayer.getActiveEffects().iterator(); -@@ -1669,7 +2087,7 @@ +@@ -1669,7 +2093,7 @@ while (iterator.hasNext()) { MobEffectInstance mobeffect = (MobEffectInstance) iterator.next(); @@ -1170,7 +1182,7 @@ } this.getInventory().replaceWith(oldPlayer.getInventory()); -@@ -1680,7 +2098,7 @@ +@@ -1680,7 +2104,7 @@ this.portalProcess = oldPlayer.portalProcess; } else { this.getAttributes().assignBaseValues(oldPlayer.getAttributes()); @@ -1179,7 +1191,7 @@ if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || oldPlayer.isSpectator()) { this.getInventory().replaceWith(oldPlayer.getInventory()); this.experienceLevel = oldPlayer.experienceLevel; -@@ -1696,7 +2114,7 @@ +@@ -1696,7 +2120,7 @@ this.lastSentExp = -1; this.lastSentHealth = -1.0F; this.lastSentFood = -1; @@ -1188,7 +1200,7 @@ this.seenCredits = oldPlayer.seenCredits; this.enteredNetherPosition = oldPlayer.enteredNetherPosition; this.chunkTrackingView = oldPlayer.chunkTrackingView; -@@ -1752,19 +2170,19 @@ +@@ -1752,19 +2176,19 @@ } @Override @@ -1212,7 +1224,7 @@ } return flag1; -@@ -1861,8 +2279,13 @@ +@@ -1861,8 +2285,13 @@ } public void sendChatMessage(OutgoingChatMessage message, boolean filterMaskEnabled, ChatType.Bound params) { @@ -1227,7 +1239,7 @@ } } -@@ -1878,7 +2301,18 @@ +@@ -1878,7 +2307,18 @@ } public void updateOptions(ClientInformation clientOptions) { @@ -1246,7 +1258,7 @@ this.requestedViewDistance = clientOptions.viewDistance(); this.chatVisibility = clientOptions.chatVisibility(); this.canChatColor = clientOptions.chatColors(); -@@ -1962,7 +2396,7 @@ +@@ -1962,7 +2402,7 @@ if (world instanceof ServerLevel) { ServerLevel worldserver = (ServerLevel) world; @@ -1255,7 +1267,7 @@ } if (entity != null) { -@@ -1999,11 +2433,11 @@ +@@ -1999,11 +2439,11 @@ @Nullable public Component getTabListDisplayName() { @@ -1269,7 +1281,7 @@ } @Override -@@ -2046,17 +2480,43 @@ +@@ -2046,17 +2486,43 @@ } public void setRespawnPosition(ResourceKey dimension, @Nullable BlockPos pos, float angle, boolean forced, boolean sendMessage) { @@ -1320,7 +1332,7 @@ } else { this.respawnPosition = null; this.respawnDimension = Level.OVERWORLD; -@@ -2088,18 +2548,44 @@ +@@ -2088,18 +2554,44 @@ } @Override @@ -1369,7 +1381,7 @@ } this.awardStat(Stats.DROP); -@@ -2375,16 +2861,160 @@ +@@ -2375,16 +2867,160 @@ return TicketType.ENDER_PEARL.timeout(); } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index 92c53790ec..e440c00996 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -129,14 +129,14 @@ this.chunkSender = new PlayerChunkSender(connection.isMemoryConnection()); this.player = player; player.connection = this; -@@ -256,8 +320,24 @@ +@@ -256,9 +320,25 @@ Objects.requireNonNull(server); this.signedMessageDecoder = SignedMessageChain.Decoder.unsigned(uuid, server::enforceSecureProfile); - this.chatMessageChain = new FutureChain(server); + this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat } -+ + + // CraftBukkit start - add fields and methods + private int lastTick = MinecraftServer.currentTick; + private int allowedPlayerTicks = 1; @@ -152,9 +152,10 @@ + private float lastYaw = Float.MAX_VALUE; + private boolean justTeleported = false; + // CraftBukkit end - ++ @Override public void tick() { + if (this.ackBlockChangesUpTo > -1) { @@ -277,7 +357,7 @@ if (this.clientIsFloating && !this.player.isSleeping() && !this.player.isPassenger() && !this.player.isDeadOrDying()) { if (++this.aboveGroundTickCount > this.getMaximumFlyingTicks(this.player)) { @@ -243,7 +244,7 @@ ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", new Object[]{entity.getName().getString(), this.player.getName().getString(), d6, d7, d8}); this.send(ClientboundMoveVehiclePacket.fromEntity(entity)); return; -@@ -449,20 +569,73 @@ +@@ -449,19 +569,72 @@ d10 = d6 * d6 + d7 * d7 + d8 * d8; boolean flag2 = false; @@ -262,8 +263,8 @@ + this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit this.send(ClientboundMoveVehiclePacket.fromEntity(entity)); return; - } - ++ } ++ + // CraftBukkit start - fire PlayerMoveEvent + Player player = this.getCraftPlayer(); + if (!this.hasMoved) { @@ -312,12 +313,11 @@ + this.justTeleported = false; + return; + } -+ } + } + // CraftBukkit end -+ + this.player.serverLevel().getChunkSource().move(this.player); entity.recordMovementThroughBlocks(new Vec3(d0, d1, d2), entity.position()); - Vec3 vec3d = new Vec3(entity.getX() - d0, entity.getY() - d1, entity.getZ() - d2); @@ -499,6 +672,7 @@ this.lastGoodZ = this.awaitingPositionFromClient.z; this.player.hasChangedDimension(); @@ -800,10 +800,12 @@ this.player.drop(false); } -@@ -1218,9 +1669,31 @@ - } - } +@@ -1216,11 +1667,33 @@ + return (item instanceof BlockItem || item instanceof BucketItem) && !player.getCooldowns().isOnCooldown(stack); + } ++ } ++ + // Spigot start - limit place/interactions + private int limitedPackets; + private long lastLimitedPacket = -1; @@ -821,9 +823,9 @@ + } + + return true; -+ } + } + // Spigot end -+ + @Override public void handleUseItemOn(ServerboundUseItemOnPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1111,12 +1113,10 @@ } } -@@ -1564,8 +2155,129 @@ - } - +@@ -1566,6 +2157,127 @@ return false; -+ } -+ + } + + // CraftBukkit start - add method + public void chat(String s, PlayerChatMessage original, boolean async) { + if (s.isEmpty() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { @@ -1209,8 +1209,8 @@ + this.server.console.sendMessage(s); + } + } - } - ++ } ++ + private void handleCommand(String s) { + org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + s); // Paper - Add async catcher + if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot @@ -1426,7 +1426,7 @@ + ItemStack itemInHand = ServerGamePacketListenerImpl.this.player.getItemInHand(enumhand); + boolean triggerLeashUpdate = itemInHand != null && itemInHand.getItem() == Items.LEAD && entity instanceof Mob; + Item origItem = ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null ? null : ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem(); - ++ + ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event); + + // Entity in bucket - SPIGOT-4048 and SPIGOT-6859a @@ -1449,7 +1449,7 @@ + ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); + } + } -+ + + if (event.isCancelled()) { + return; + } @@ -1559,13 +1559,19 @@ } } break; -@@ -1834,15 +2713,21 @@ +@@ -1833,16 +2712,27 @@ + @Override public void handleContainerClose(ServerboundContainerClosePacket packet) { ++ // Paper start - Inventory close reason ++ this.handleContainerClose(packet, org.bukkit.event.inventory.InventoryCloseEvent.Reason.PLAYER); ++ } ++ public void handleContainerClose(ServerboundContainerClosePacket packet, org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { ++ // Paper end - Inventory close reason PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + + if (this.player.isImmobile()) return; // CraftBukkit -+ CraftEventFactory.handleInventoryCloseEvent(this.player); // CraftBukkit ++ CraftEventFactory.handleInventoryCloseEvent(this.player, reason); // CraftBukkit // Paper + this.player.doCloseContainer(); } @@ -1583,7 +1589,7 @@ this.player.containerMenu.sendAllDataToRemote(); } else if (!this.player.containerMenu.stillValid(this.player)) { ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu); -@@ -1855,7 +2740,284 @@ +@@ -1855,7 +2745,284 @@ boolean flag = packet.getStateId() != this.player.containerMenu.getStateId(); this.player.containerMenu.suppressRemoteUpdates(); @@ -1869,7 +1875,7 @@ ObjectIterator objectiterator = Int2ObjectMaps.fastIterable(packet.getChangedSlots()).iterator(); while (objectiterator.hasNext()) { -@@ -1901,8 +3063,22 @@ +@@ -1901,8 +3068,22 @@ return; } @@ -1893,7 +1899,7 @@ if (containerrecipebook_a == RecipeBookMenu.PostPlaceAction.PLACE_GHOST_RECIPE) { this.player.connection.send(new ClientboundPlaceGhostRecipePacket(this.player.containerMenu.containerId, craftingmanager_d.display().display())); } -@@ -1917,6 +3093,7 @@ +@@ -1917,6 +3098,7 @@ @Override public void handleContainerButtonClick(ServerboundContainerButtonClickPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1901,7 +1907,7 @@ this.player.resetLastActionTime(); if (this.player.containerMenu.containerId == packet.containerId() && !this.player.isSpectator()) { if (!this.player.containerMenu.stillValid(this.player)) { -@@ -1945,7 +3122,44 @@ +@@ -1945,7 +3127,44 @@ boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45; boolean flag2 = itemstack.isEmpty() || itemstack.getCount() <= itemstack.getMaxStackSize(); @@ -1946,7 +1952,7 @@ if (flag1 && flag2) { this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemstack); this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemstack); -@@ -1972,6 +3186,7 @@ +@@ -1972,6 +3191,7 @@ } private void updateSignText(ServerboundSignUpdatePacket packet, List signText) { @@ -1954,7 +1960,7 @@ this.player.resetLastActionTime(); ServerLevel worldserver = this.player.serverLevel(); BlockPos blockposition = packet.getPos(); -@@ -1993,7 +3208,17 @@ +@@ -1993,7 +3213,17 @@ @Override public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1973,7 +1979,7 @@ } @Override -@@ -2002,6 +3227,7 @@ +@@ -2002,6 +3232,7 @@ boolean flag = this.player.isModelPartShown(PlayerModelPart.HAT); this.player.updateOptions(packet.information()); @@ -1981,7 +1987,7 @@ if (this.player.isModelPartShown(PlayerModelPart.HAT) != flag) { this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_HAT, this.player)); } -@@ -2058,7 +3284,7 @@ +@@ -2058,7 +3289,7 @@ if (!this.waitingForSwitchToConfig) { throw new IllegalStateException("Client acknowledged config, but none was requested"); } else { @@ -1990,7 +1996,7 @@ } } -@@ -2083,8 +3309,10 @@ +@@ -2083,8 +3314,10 @@ }); } diff --git a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch index d8e7dcb5ce..be24f93934 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch @@ -341,7 +341,7 @@ + // CraftBukkit start - Quitting must be before we do final save of data, in case plugins need to modify it + // See SPIGOT-5799, SPIGOT-6145 + if (entityplayer.containerMenu != entityplayer.inventoryMenu) { -+ entityplayer.closeContainer(); ++ entityplayer.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT); // Paper - Inventory close reason + } + + PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName()))); // Paper - Adventure diff --git a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch index e53cacfe11..d81764f1bc 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/player/Player.java.patch @@ -35,12 +35,12 @@ public final InventoryMenu inventoryMenu; public AbstractContainerMenu containerMenu; protected FoodData foodData = new FoodData(); -@@ -188,7 +198,18 @@ +@@ -188,6 +198,17 @@ public Entity currentExplosionCause; private boolean ignoreFallDamageFromCurrentImpulse; private int currentImpulseContextResetGraceTime; + public boolean affectsSpawning = true; // Paper - Affects Spawning API - ++ + // CraftBukkit start + public boolean fauxSleeping; + public int oldLevel = -1; @@ -50,10 +50,18 @@ + return (CraftHumanEntity) super.getBukkitEntity(); + } + // CraftBukkit end -+ + public Player(Level world, BlockPos pos, float yaw, GameProfile gameProfile) { super(EntityType.PLAYER, world); - this.lastItemInMainHand = ItemStack.EMPTY; +@@ -261,7 +282,7 @@ + this.updateIsUnderwater(); + super.tick(); + if (!this.level().isClientSide && this.containerMenu != null && !this.containerMenu.stillValid(this)) { +- this.closeContainer(); ++ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper - Inventory close reason + this.containerMenu = this.inventoryMenu; + } + @@ -353,7 +374,7 @@ } @@ -63,7 +71,22 @@ } private boolean isEquipped(Item item) { -@@ -523,8 +544,14 @@ +@@ -511,7 +532,14 @@ + super.handleEntityEvent(status); + } + ++ } ++ ++ // Paper start - Inventory close reason; unused code, but to keep signatures aligned ++ public void closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { ++ closeContainer(); ++ this.containerMenu = this.inventoryMenu; + } ++ // Paper end - Inventory close reason + + public void closeContainer() { + this.containerMenu = this.inventoryMenu; +@@ -523,8 +551,14 @@ public void rideTick() { if (!this.level().isClientSide && this.wantsToStopRiding() && this.isPassenger()) { this.stopRiding(); @@ -80,7 +103,7 @@ super.rideTick(); this.oBob = this.bob; this.bob = 0.0F; -@@ -593,6 +620,7 @@ +@@ -593,6 +627,7 @@ this.playShoulderEntityAmbientSound(this.getShoulderEntityLeft()); this.playShoulderEntityAmbientSound(this.getShoulderEntityRight()); if (!this.level().isClientSide && (this.fallDistance > 0.5F || this.isInWater()) || this.abilities.flying || this.isSleeping() || this.isInPowderSnow) { @@ -88,7 +111,7 @@ this.removeEntitiesOnShoulder(); } -@@ -719,7 +747,14 @@ +@@ -719,7 +754,14 @@ @Nullable public ItemEntity drop(ItemStack stack, boolean throwRandomly, boolean retainOwnership) { @@ -104,7 +127,7 @@ this.swing(InteractionHand.MAIN_HAND); } -@@ -809,7 +844,7 @@ +@@ -809,7 +851,7 @@ } if (nbt.contains("LastDeathLocation", 10)) { @@ -113,7 +136,7 @@ Logger logger = Player.LOGGER; Objects.requireNonNull(logger); -@@ -817,7 +852,7 @@ +@@ -817,7 +859,7 @@ } if (nbt.contains("current_explosion_impact_pos", 9)) { @@ -122,7 +145,7 @@ Logger logger1 = Player.LOGGER; Objects.requireNonNull(logger1); -@@ -854,7 +889,7 @@ +@@ -854,7 +896,7 @@ } this.getLastDeathLocation().flatMap((globalpos) -> { @@ -131,7 +154,7 @@ Logger logger = Player.LOGGER; Objects.requireNonNull(logger); -@@ -886,10 +921,10 @@ +@@ -886,10 +928,10 @@ if (this.isDeadOrDying()) { return false; } else { @@ -144,7 +167,7 @@ } if (world.getDifficulty() == Difficulty.EASY) { -@@ -901,7 +936,13 @@ +@@ -901,7 +943,13 @@ } } @@ -159,7 +182,7 @@ } } } -@@ -923,10 +964,29 @@ +@@ -923,10 +971,29 @@ } public boolean canHarmPlayer(Player player) { @@ -192,7 +215,7 @@ } @Override -@@ -966,32 +1026,38 @@ +@@ -966,32 +1033,38 @@ } } @@ -245,7 +268,7 @@ } public boolean isTextFilteringEnabled() { -@@ -1144,10 +1210,15 @@ +@@ -1144,10 +1217,15 @@ f *= 0.2F + f2 * f2 * 0.8F; f1 *= f2; @@ -262,7 +285,7 @@ if (iprojectile.deflect(ProjectileDeflection.AIM_DEFLECT, this, this, true)) { this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource()); return; -@@ -1159,7 +1230,7 @@ +@@ -1159,7 +1237,7 @@ boolean flag1; if (this.isSprinting() && flag) { @@ -271,7 +294,7 @@ flag1 = true; } else { flag1 = false; -@@ -1168,6 +1239,7 @@ +@@ -1168,6 +1246,7 @@ f += itemstack.getItem().getAttackDamageBonus(target, f, damagesource); boolean flag2 = flag && this.fallDistance > 0.0F && !this.onGround() && !this.onClimbable() && !this.isInWater() && !this.hasEffect(MobEffects.BLINDNESS) && !this.isPassenger() && target instanceof LivingEntity && !this.isSprinting(); @@ -279,7 +302,7 @@ if (flag2) { f *= 1.5F; } -@@ -1202,13 +1274,17 @@ +@@ -1202,13 +1281,17 @@ if (target instanceof LivingEntity) { LivingEntity entityliving1 = (LivingEntity) target; @@ -299,7 +322,7 @@ } LivingEntity entityliving2; -@@ -1223,8 +1299,13 @@ +@@ -1223,8 +1306,13 @@ if (entityliving2 != this && entityliving2 != target && !this.isAlliedTo((Entity) entityliving2) && (!(entityliving2 instanceof ArmorStand) || !((ArmorStand) entityliving2).isMarker()) && this.distanceToSqr((Entity) entityliving2) < 9.0D) { float f7 = this.getEnchantedDamage(entityliving2, f6, damagesource) * f2; @@ -315,7 +338,7 @@ Level world = this.level(); if (world instanceof ServerLevel) { -@@ -1235,26 +1316,43 @@ +@@ -1235,26 +1323,43 @@ } } @@ -363,7 +386,7 @@ } } -@@ -1308,9 +1406,14 @@ +@@ -1308,9 +1413,14 @@ } } @@ -380,7 +403,7 @@ } } -@@ -1351,7 +1454,14 @@ +@@ -1351,7 +1461,14 @@ @Override public void remove(Entity.RemovalReason reason) { @@ -396,7 +419,7 @@ this.inventoryMenu.removed(this); if (this.containerMenu != null && this.hasContainerOpen()) { this.doCloseContainer(); -@@ -1391,7 +1501,13 @@ +@@ -1391,7 +1508,13 @@ } public Either startSleepInBed(BlockPos pos) { @@ -411,7 +434,7 @@ this.sleepCounter = 0; return Either.right(Unit.INSTANCE); } -@@ -1545,12 +1661,24 @@ +@@ -1545,12 +1668,24 @@ } public void startFallFlying() { @@ -437,18 +460,17 @@ } @Override -@@ -1663,12 +1791,31 @@ - +@@ -1664,11 +1799,30 @@ public int getXpNeededForNextLevel() { return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2); -+ } + } + // Paper start - send while respecting visibility + private static void sendSoundEffect(Player fromEntity, double x, double y, double z, SoundEvent soundEffect, SoundSource soundCategory, float volume, float pitch) { + fromEntity.level().playSound(fromEntity, x, y, z, soundEffect, soundCategory, volume, pitch); // This will not send the effect to the entity itself + if (fromEntity instanceof ServerPlayer serverPlayer) { + serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundSoundPacket(net.minecraft.core.registries.BuiltInRegistries.SOUND_EVENT.wrapAsHolder(soundEffect), soundCategory, x, y, z, volume, pitch, fromEntity.random.nextLong())); + } - } ++ } + // Paper end - send while respecting visibility + // CraftBukkit start @@ -470,7 +492,7 @@ } } -@@ -1748,13 +1895,20 @@ +@@ -1748,13 +1902,20 @@ @Override public void setItemSlot(EquipmentSlot slot, ItemStack stack) { @@ -498,7 +520,7 @@ } } -@@ -1798,26 +1952,55 @@ +@@ -1798,26 +1959,55 @@ public void removeEntitiesOnShoulder() { if (this.timeEntitySatOnShoulder + 20L < this.level().getGameTime()) { @@ -561,7 +583,7 @@ } @Override -@@ -2003,20 +2186,31 @@ +@@ -2003,20 +2193,31 @@ @Override public ImmutableList getDismountPoses() { return ImmutableList.of(Pose.STANDING, Pose.CROUCHING, Pose.SWIMMING); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java index 6d4e0a90c7..5ff159be1a 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java @@ -387,7 +387,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { if (((ServerPlayer) this.getHandle()).connection == null) return; if (this.getHandle().containerMenu != this.getHandle().inventoryMenu) { // fire INVENTORY_CLOSE if one already open - ((ServerPlayer) this.getHandle()).connection.handleContainerClose(new ServerboundContainerClosePacket(this.getHandle().containerMenu.containerId)); + ((ServerPlayer) this.getHandle()).connection.handleContainerClose(new ServerboundContainerClosePacket(this.getHandle().containerMenu.containerId), org.bukkit.event.inventory.InventoryCloseEvent.Reason.OPEN_NEW); // Paper - Inventory close reason } ServerPlayer player = (ServerPlayer) this.getHandle(); AbstractContainerMenu container; @@ -457,8 +457,14 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { @Override public void closeInventory() { - this.getHandle().closeContainer(); + // Paper start - Inventory close reason + this.getHandle().closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.PLUGIN); } + @Override + public void closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { + getHandle().closeContainer(reason); + } + // Paper end - Inventory close reason @Override public boolean isBlocking() { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 6538a3ee38..c76f5d21d6 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1278,7 +1278,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { // Close any foreign inventory if (this.getHandle().containerMenu != this.getHandle().inventoryMenu) { - this.getHandle().closeContainer(); + this.getHandle().closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT); // Paper - Inventory close reason } // Check if the fromWorld and toWorld are the same. diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 60a16ac62a..41c6a72603 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -1281,7 +1281,7 @@ public class CraftEventFactory { public static AbstractContainerMenu callInventoryOpenEvent(ServerPlayer player, AbstractContainerMenu container, boolean cancelled) { if (player.containerMenu != player.inventoryMenu) { // fire INVENTORY_CLOSE if one already open - player.connection.handleContainerClose(new ServerboundContainerClosePacket(player.containerMenu.containerId)); + player.connection.handleContainerClose(new ServerboundContainerClosePacket(player.containerMenu.containerId), InventoryCloseEvent.Reason.OPEN_NEW); // Paper - Inventory close reason } CraftServer server = player.level().getCraftServer(); @@ -1477,8 +1477,18 @@ public class CraftEventFactory { return event; } + // Paper start + /** + * Incase plugins hooked into this or Spigot adds a new inventory close event. Prefer to pass a reason + * @param human + */ + @Deprecated public static void handleInventoryCloseEvent(net.minecraft.world.entity.player.Player human) { - InventoryCloseEvent event = new InventoryCloseEvent(human.containerMenu.getBukkitView()); + handleInventoryCloseEvent(human, org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNKNOWN); + } + public static void handleInventoryCloseEvent(net.minecraft.world.entity.player.Player human, org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) { + // Paper end + InventoryCloseEvent event = new InventoryCloseEvent(human.containerMenu.getBukkitView(), reason); // Paper human.level().getCraftServer().getPluginManager().callEvent(event); human.containerMenu.transferTo(human.inventoryMenu, human.getBukkitEntity()); }