From c593e8510ecb657479e9f36b60ef62f7a0a96bd5 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Wed, 25 Aug 2021 20:17:12 -0700 Subject: [PATCH] Improve and expand AsyncCatcher Log when the async catcher is tripped The chunk system can swallow the exception given it's all built with completablefuture, so ensure it is at least printed. Add/move several async catchers Async catch modifications to critical entity state These used to be here from Spigot, but were dropped with 1.17. Now in 1.17, this state is _even more_ critical than it was before, so these must exist to catch stupid plugins. Co-authored-by: Jake Potrebic --- .../ServerGamePacketListenerImpl.java.patch | 103 +++++++++-------- .../world/entity/LivingEntity.java.patch | 2 +- .../PersistentEntitySectionManager.java.patch | 107 ++++++++++++++++-- .../org/bukkit/craftbukkit/CraftWorld.java | 4 + .../craftbukkit/entity/CraftLivingEntity.java | 1 + .../main/java/org/spigotmc/AsyncCatcher.java | 1 + 6 files changed, 156 insertions(+), 62 deletions(-) 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 9d0d61a726..e569cfff87 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 @@ -881,7 +881,7 @@ return true; } else { -@@ -1147,23 +1604,90 @@ +@@ -1147,23 +1604,91 @@ } public void teleport(double x, double y, double z, float yaw, float pitch) { @@ -933,6 +933,7 @@ + } + + public void internalTeleport(PositionMoveRotation positionmoverotation, Set set) { ++ org.spigotmc.AsyncCatcher.catchOp("teleport"); // Paper + // Paper start - Prevent teleporting dead entities + if (player.isRemoved()) { + LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName()); @@ -975,7 +976,7 @@ if (this.player.hasClientLoaded()) { BlockPos blockposition = packet.getPos(); -@@ -1175,14 +1699,46 @@ +@@ -1175,14 +1700,46 @@ if (!this.player.isSpectator()) { ItemStack itemstack = this.player.getItemInHand(InteractionHand.OFF_HAND); @@ -1024,7 +1025,7 @@ this.player.drop(false); } -@@ -1199,6 +1755,12 @@ +@@ -1199,6 +1756,12 @@ case START_DESTROY_BLOCK: case ABORT_DESTROY_BLOCK: case STOP_DESTROY_BLOCK: @@ -1037,7 +1038,7 @@ this.player.gameMode.handleBlockBreakAction(blockposition, packetplayinblockdig_enumplayerdigtype, packet.getDirection(), this.player.level().getMaxY(), packet.getSequence()); this.player.connection.ackBlockChangesUpTo(packet.getSequence()); return; -@@ -1218,9 +1780,31 @@ +@@ -1218,9 +1781,31 @@ } } @@ -1069,7 +1070,7 @@ if (this.player.hasClientLoaded()) { this.player.connection.ackBlockChangesUpTo(packet.getSequence()); ServerLevel worldserver = this.player.serverLevel(); -@@ -1230,6 +1814,11 @@ +@@ -1230,6 +1815,11 @@ if (itemstack.isItemEnabled(worldserver.enabledFeatures())) { BlockHitResult movingobjectpositionblock = packet.getHitResult(); Vec3 vec3d = movingobjectpositionblock.getLocation(); @@ -1081,7 +1082,7 @@ BlockPos blockposition = movingobjectpositionblock.getBlockPos(); if (this.player.canInteractWithBlock(blockposition, 1.0D)) { -@@ -1243,7 +1832,8 @@ +@@ -1243,7 +1833,8 @@ int i = this.player.level().getMaxY(); if (blockposition.getY() <= i) { @@ -1091,7 +1092,7 @@ InteractionResult enuminteractionresult = this.player.gameMode.useItemOn(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock); if (enuminteractionresult.consumesAction()) { -@@ -1257,7 +1847,7 @@ +@@ -1257,7 +1848,7 @@ } else if (enuminteractionresult instanceof InteractionResult.Success) { InteractionResult.Success enuminteractionresult_d = (InteractionResult.Success) enuminteractionresult; @@ -1100,7 +1101,7 @@ this.player.swing(enumhand, true); } } -@@ -1281,6 +1871,8 @@ +@@ -1281,6 +1872,8 @@ @Override public void handleUseItem(ServerboundUseItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1109,12 +1110,10 @@ if (this.player.hasClientLoaded()) { this.ackBlockChangesUpTo(packet.getSequence()); ServerLevel worldserver = this.player.serverLevel(); -@@ -1294,8 +1886,49 @@ - - if (f1 != this.player.getXRot() || f != this.player.getYRot()) { +@@ -1296,6 +1889,47 @@ this.player.absRotateTo(f, f1); -+ } -+ + } + + // CraftBukkit start + // Raytrace to look for 'rogue armswings' + double d0 = this.player.getX(); @@ -1145,8 +1144,8 @@ + cancelled = event.useItemInHand() == Event.Result.DENY; + } + this.player.gameMode.firedInteract = false; - } - ++ } ++ + if (cancelled) { + this.player.getBukkitEntity().updateInventory(); // SPIGOT-2524 + return; @@ -1159,7 +1158,7 @@ InteractionResult enuminteractionresult = this.player.gameMode.useItem(this.player, worldserver, itemstack, enumhand); if (enuminteractionresult instanceof InteractionResult.Success) { -@@ -1321,7 +1954,7 @@ +@@ -1321,7 +1955,7 @@ Entity entity = packet.getEntity(worldserver); if (entity != null) { @@ -1168,7 +1167,7 @@ return; } } -@@ -1342,17 +1975,46 @@ +@@ -1342,17 +1976,46 @@ @Override public void onDisconnect(DisconnectionDetails info) { @@ -1219,7 +1218,7 @@ this.player.getTextFilter().leave(); } -@@ -1367,7 +2029,17 @@ +@@ -1367,7 +2030,17 @@ @Override public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1237,7 +1236,7 @@ if (this.player.getInventory().selected != packet.getSlot() && this.player.getUsedItemHand() == InteractionHand.MAIN_HAND) { this.player.stopUsingItem(); } -@@ -1376,11 +2048,18 @@ +@@ -1376,11 +2049,18 @@ this.player.resetLastActionTime(); } else { ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString()); @@ -1256,7 +1255,7 @@ Optional optional = this.unpackAndApplyLastSeen(packet.lastSeenMessages()); if (!optional.isEmpty()) { -@@ -1394,27 +2073,44 @@ +@@ -1394,27 +2074,44 @@ return; } @@ -1308,7 +1307,7 @@ ParseResults parseresults = this.parseCommand(command); if (this.server.enforceSecureProfile() && SignableCommand.hasSignableArguments(parseresults)) { -@@ -1431,19 +2127,37 @@ +@@ -1431,19 +2128,37 @@ if (!optional.isEmpty()) { this.tryHandleChat(packet.command(), () -> { @@ -1350,7 +1349,7 @@ } catch (SignedMessageChain.DecodeException signedmessagechain_a) { this.handleMessageDecodeFailure(signedmessagechain_a); return; -@@ -1451,10 +2165,10 @@ +@@ -1451,10 +2166,10 @@ CommandSigningContext.SignedArguments commandsigningcontext_a = new CommandSigningContext.SignedArguments(map); @@ -1363,7 +1362,7 @@ } private void handleMessageDecodeFailure(SignedMessageChain.DecodeException exception) { -@@ -1530,14 +2244,20 @@ +@@ -1530,14 +2245,20 @@ return com_mojang_brigadier_commanddispatcher.parse(command, this.player.createCommandSourceStack()); } @@ -1389,7 +1388,7 @@ } } -@@ -1549,7 +2269,7 @@ +@@ -1549,7 +2270,7 @@ if (optional.isEmpty()) { ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString()); @@ -1398,7 +1397,7 @@ } return optional; -@@ -1566,6 +2286,127 @@ +@@ -1566,6 +2287,127 @@ return false; } @@ -1526,7 +1525,7 @@ private PlayerChatMessage getSignedMessage(ServerboundChatPacket packet, LastSeenMessages lastSeenMessages) throws SignedMessageChain.DecodeException { SignedMessageBody signedmessagebody = new SignedMessageBody(packet.message(), packet.timeStamp(), packet.salt(), lastSeenMessages); -@@ -1573,15 +2414,44 @@ +@@ -1573,15 +2415,44 @@ } private void broadcastChatMessage(PlayerChatMessage message) { @@ -1577,7 +1576,7 @@ } -@@ -1592,7 +2462,7 @@ +@@ -1592,7 +2463,7 @@ synchronized (this.lastSeenMessages) { if (!this.lastSeenMessages.applyOffset(packet.offset())) { ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString()); @@ -1586,7 +1585,7 @@ } } -@@ -1601,7 +2471,40 @@ +@@ -1601,7 +2472,40 @@ @Override public void handleAnimate(ServerboundSwingPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1627,7 +1626,7 @@ this.player.swing(packet.getHand()); } -@@ -1609,6 +2512,29 @@ +@@ -1609,6 +2513,29 @@ public void handlePlayerCommand(ServerboundPlayerCommandPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); if (this.player.hasClientLoaded()) { @@ -1657,7 +1656,7 @@ this.player.resetLastActionTime(); Entity entity; PlayerRideableJumping ijumpable; -@@ -1616,6 +2542,11 @@ +@@ -1616,6 +2543,11 @@ switch (packet.getAction()) { case PRESS_SHIFT_KEY: this.player.setShiftKeyDown(true); @@ -1669,7 +1668,7 @@ break; case RELEASE_SHIFT_KEY: this.player.setShiftKeyDown(false); -@@ -1684,13 +2615,19 @@ +@@ -1684,13 +2616,19 @@ } if (i > 4096) { @@ -1690,7 +1689,7 @@ this.send(new ClientboundPlayerChatPacket(message.link().sender(), message.link().index(), message.signature(), message.signedBody().pack(this.messageSignatureCache), message.unsignedContent(), message.filterMask(), params)); this.addPendingMessage(message); } -@@ -1703,6 +2640,18 @@ +@@ -1703,6 +2641,18 @@ return this.connection.getRemoteAddress(); } @@ -1709,7 +1708,7 @@ public void switchToConfig() { this.waitingForSwitchToConfig = true; this.removePlayerFromWorld(); -@@ -1718,9 +2667,17 @@ +@@ -1718,9 +2668,17 @@ @Override public void handleInteract(ServerboundInteractPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1727,7 +1726,7 @@ this.player.resetLastActionTime(); this.player.setShiftKeyDown(packet.isUsingSecondaryAction()); -@@ -1733,20 +2690,58 @@ +@@ -1733,20 +2691,58 @@ if (this.player.canInteractWithEntity(axisalignedbb, 3.0D)) { packet.dispatch(new ServerboundInteractPacket.Handler() { @@ -1790,7 +1789,7 @@ } } -@@ -1755,19 +2750,20 @@ +@@ -1755,19 +2751,20 @@ @Override public void onInteraction(InteractionHand hand) { @@ -1814,7 +1813,7 @@ label23: { if (entity instanceof AbstractArrow) { -@@ -1785,17 +2781,41 @@ +@@ -1785,17 +2782,41 @@ } ServerGamePacketListenerImpl.this.player.attack(entity); @@ -1857,7 +1856,7 @@ } } -@@ -1809,7 +2829,7 @@ +@@ -1809,7 +2830,7 @@ case PERFORM_RESPAWN: if (this.player.wonGame) { this.player.wonGame = false; @@ -1866,7 +1865,7 @@ this.resetPosition(); CriteriaTriggers.CHANGED_DIMENSION.trigger(this.player, Level.END, Level.OVERWORLD); } else { -@@ -1817,11 +2837,11 @@ +@@ -1817,11 +2838,11 @@ return; } @@ -1881,7 +1880,7 @@ } } break; -@@ -1833,16 +2853,27 @@ +@@ -1833,16 +2854,27 @@ @Override public void handleContainerClose(ServerboundContainerClosePacket packet) { @@ -1911,7 +1910,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 +2886,284 @@ +@@ -1855,7 +2887,284 @@ boolean flag = packet.getStateId() != this.player.containerMenu.getStateId(); this.player.containerMenu.suppressRemoteUpdates(); @@ -2197,7 +2196,7 @@ ObjectIterator objectiterator = Int2ObjectMaps.fastIterable(packet.getChangedSlots()).iterator(); while (objectiterator.hasNext()) { -@@ -1879,6 +3187,14 @@ +@@ -1879,6 +3188,14 @@ @Override public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) { @@ -2212,7 +2211,7 @@ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); this.player.resetLastActionTime(); if (!this.player.isSpectator() && this.player.containerMenu.containerId == packet.containerId()) { -@@ -1900,9 +3216,43 @@ +@@ -1900,9 +3217,43 @@ ServerGamePacketListenerImpl.LOGGER.debug("Player {} tried to place impossible recipe {}", this.player, recipeholder.id().location()); return; } @@ -2257,7 +2256,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 +3267,7 @@ +@@ -1917,6 +3268,7 @@ @Override public void handleContainerButtonClick(ServerboundContainerButtonClickPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -2265,7 +2264,7 @@ this.player.resetLastActionTime(); if (this.player.containerMenu.containerId == packet.containerId() && !this.player.isSpectator()) { if (!this.player.containerMenu.stillValid(this.player)) { -@@ -1945,7 +3296,44 @@ +@@ -1945,7 +3297,44 @@ boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45; boolean flag2 = itemstack.isEmpty() || itemstack.getCount() <= itemstack.getMaxStackSize(); @@ -2310,7 +2309,7 @@ if (flag1 && flag2) { this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemstack); this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemstack); -@@ -1964,7 +3352,19 @@ +@@ -1964,7 +3353,19 @@ @Override public void handleSignUpdate(ServerboundSignUpdatePacket packet) { @@ -2331,7 +2330,7 @@ this.filterTextPacket(list).thenAcceptAsync((list1) -> { this.updateSignText(packet, list1); -@@ -1972,6 +3372,7 @@ +@@ -1972,6 +3373,7 @@ } private void updateSignText(ServerboundSignUpdatePacket packet, List signText) { @@ -2339,7 +2338,7 @@ this.player.resetLastActionTime(); ServerLevel worldserver = this.player.serverLevel(); BlockPos blockposition = packet.getPos(); -@@ -1993,15 +3394,33 @@ +@@ -1993,15 +3395,33 @@ @Override public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -2374,7 +2373,7 @@ if (this.player.isModelPartShown(PlayerModelPart.HAT) != flag) { this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_HAT, this.player)); } -@@ -2012,7 +3431,7 @@ +@@ -2012,7 +3432,7 @@ public void handleChangeDifficulty(ServerboundChangeDifficultyPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); if (this.player.hasPermissions(2) || this.isSingleplayerOwner()) { @@ -2383,7 +2382,7 @@ } } -@@ -2033,7 +3452,7 @@ +@@ -2033,7 +3453,7 @@ if (!Objects.equals(profilepublickey_a, profilepublickey_a1)) { if (profilepublickey_a != null && profilepublickey_a1.expiresAt().isBefore(profilepublickey_a.expiresAt())) { @@ -2392,7 +2391,7 @@ } else { try { SignatureValidator signaturevalidator = this.server.getProfileKeySignatureValidator(); -@@ -2046,7 +3465,7 @@ +@@ -2046,7 +3466,7 @@ this.resetPlayerChatState(remotechatsession_a.validate(this.player.getGameProfile(), signaturevalidator)); } catch (ProfilePublicKey.ValidationException profilepublickey_b) { ServerGamePacketListenerImpl.LOGGER.error("Failed to validate profile key: {}", profilepublickey_b.getMessage()); @@ -2401,7 +2400,7 @@ } } -@@ -2058,7 +3477,7 @@ +@@ -2058,7 +3478,7 @@ if (!this.waitingForSwitchToConfig) { throw new IllegalStateException("Client acknowledged config, but none was requested"); } else { @@ -2410,7 +2409,7 @@ } } -@@ -2083,8 +3502,10 @@ +@@ -2083,8 +3503,10 @@ }); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index 71db951715..d47e040538 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -398,7 +398,7 @@ + } + + public boolean addEffect(MobEffectInstance mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause) { -+ org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot ++ // org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot // Paper - move to API + if (this.isTickingEffects) { + this.effectsToProcess.add(new ProcessableEffect(mobeffect, cause)); + return true; diff --git a/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch b/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch index 3599ce9b84..68a70b169a 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/entity/PersistentEntitySectionManager.java.patch @@ -32,10 +32,19 @@ void removeSectionIfEmpty(long sectionPos, EntitySection section) { if (section.isEmpty()) { this.sectionStorage.remove(sectionPos); -@@ -76,6 +91,16 @@ +@@ -63,6 +78,7 @@ + } + + private boolean addEntityUuid(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity add by UUID"); // Paper + if (!this.knownUuids.add(entity.getUUID())) { + PersistentEntitySectionManager.LOGGER.warn("UUID of added entity already exists: {}", entity); + return false; +@@ -76,6 +92,17 @@ } private boolean addEntity(T entity, boolean existing) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper + // Paper start - chunk system hooks + // I don't want to know why this is a generic type. + Entity entityCasted = (Entity)entity; @@ -49,7 +58,47 @@ if (!this.addEntityUuid(entity)) { return false; } else { -@@ -196,27 +221,35 @@ +@@ -119,19 +146,23 @@ + } + + void startTicking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity start ticking"); // Paper + this.callbacks.onTickingStart(entity); + } + + void stopTicking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity stop ticking"); // Paper + this.callbacks.onTickingEnd(entity); + } + + void startTracking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity start tracking"); // Paper + this.visibleEntityStorage.add(entity); + this.callbacks.onTrackingStart(entity); + } + + void stopTracking(T entity) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity stop tracking"); // Paper + this.callbacks.onTrackingEnd(entity); + this.visibleEntityStorage.remove(entity); + } +@@ -143,6 +174,7 @@ + } + + public void updateChunkStatus(ChunkPos chunkPos, Visibility trackingStatus) { ++ org.spigotmc.AsyncCatcher.catchOp("Update chunk status"); // Paper + long i = chunkPos.toLong(); + + if (trackingStatus == Visibility.HIDDEN) { +@@ -187,6 +219,7 @@ + } + + public void ensureChunkQueuedForLoad(long chunkPos) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk save"); // Paper + PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(chunkPos); + + if (persistententitysectionmanager_b == PersistentEntitySectionManager.ChunkLoadStatus.FRESH) { +@@ -196,33 +229,42 @@ } private boolean storeChunkSections(long chunkPos, Consumer action) { @@ -91,8 +140,18 @@ return true; } } -@@ -238,7 +271,7 @@ + } + + private void requestChunkLoad(long chunkPos) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk load request"); // Paper + this.chunkLoadStatuses.put(chunkPos, PersistentEntitySectionManager.ChunkLoadStatus.PENDING); + ChunkPos chunkcoordintpair = new ChunkPos(chunkPos); + CompletableFuture completablefuture = this.permanentStorage.loadEntities(chunkcoordintpair); +@@ -236,9 +278,10 @@ + } + private boolean processChunkUnload(long chunkPos) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk unload process"); // Paper boolean flag = this.storeChunkSections(chunkPos, (entityaccess) -> { entityaccess.getPassengersAndSelf().forEach(this::unloadEntity); - }); @@ -100,7 +159,7 @@ if (!flag) { return false; -@@ -249,24 +282,28 @@ +@@ -249,29 +292,35 @@ } private void unloadEntity(EntityAccess entity) { @@ -118,6 +177,7 @@ private void processPendingLoads() { - ChunkEntities chunkentities; ++ org.spigotmc.AsyncCatcher.catchOp("Entity chunk process pending loads"); // Paper + ChunkEntities chunkentities; // CraftBukkit - decompile error while ((chunkentities = (ChunkEntities) this.loadingInbox.poll()) != null) { @@ -132,16 +192,29 @@ } } -@@ -292,7 +329,7 @@ + + public void tick() { ++ org.spigotmc.AsyncCatcher.catchOp("Entity manager tick"); // Paper + this.processPendingLoads(); + this.processUnloads(); + } +@@ -292,7 +341,8 @@ } public void autoSave() { - this.getAllChunksToSave().forEach((i) -> { ++ org.spigotmc.AsyncCatcher.catchOp("Entity manager autosave"); // Paper + this.getAllChunksToSave().forEach((java.util.function.LongConsumer) (i) -> { // CraftBukkit - decompile error boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN; if (flag) { -@@ -311,7 +348,7 @@ +@@ -306,12 +356,13 @@ + } + + public void saveAll() { ++ org.spigotmc.AsyncCatcher.catchOp("Entity manager save"); // Paper + LongSet longset = this.getAllChunksToSave(); + while (!longset.isEmpty()) { this.permanentStorage.flush(false); this.processPendingLoads(); @@ -150,7 +223,7 @@ boolean flag = this.chunkVisibility.get(i) == Visibility.HIDDEN; return flag ? this.processChunkUnload(i) : this.storeChunkSections(i, (entityaccess) -> { -@@ -323,7 +360,15 @@ +@@ -323,7 +374,15 @@ } public void close() throws IOException { @@ -167,7 +240,7 @@ this.permanentStorage.close(); } -@@ -350,7 +395,7 @@ +@@ -350,7 +409,7 @@ public void dumpSections(Writer writer) throws IOException { CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("y").addColumn("z").addColumn("visibility").addColumn("load_status").addColumn("entity_count").build(writer); @@ -176,7 +249,7 @@ PersistentEntitySectionManager.ChunkLoadStatus persistententitysectionmanager_b = (PersistentEntitySectionManager.ChunkLoadStatus) this.chunkLoadStatuses.get(i); this.sectionStorage.getExistingSectionPositionsInChunk(i).forEach((j) -> { -@@ -394,7 +439,7 @@ +@@ -394,7 +453,7 @@ private EntitySection currentSection; Callback(final EntityAccess entityaccess, final long i, final EntitySection entitysection) { @@ -185,3 +258,19 @@ this.currentSectionKey = i; this.currentSection = entitysection; } +@@ -405,6 +464,7 @@ + long i = SectionPos.asLong(blockposition); + + if (i != this.currentSectionKey) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity move"); // Paper + Visibility visibility = this.currentSection.getStatus(); + + if (!this.currentSection.remove(this.entity)) { +@@ -459,6 +519,7 @@ + + @Override + public void onRemove(Entity.RemovalReason reason) { ++ org.spigotmc.AsyncCatcher.catchOp("Entity remove"); // Paper + if (!this.currentSection.remove(this.entity)) { + PersistentEntitySectionManager.LOGGER.warn("Entity {} wasn't found in section {} (destroying due to {})", new Object[]{this.entity, SectionPos.of(this.currentSectionKey), reason}); + } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index d650822155..0ab6a9496e 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -1755,6 +1755,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void playSound(Location loc, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { + org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper if (loc == null || sound == null || category == null) return; double x = loc.getX(); @@ -1766,6 +1767,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void playSound(Location loc, String sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { + org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper if (loc == null || sound == null || category == null) return; double x = loc.getX(); @@ -1798,6 +1800,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void playSound(Entity entity, Sound sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { + org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(CraftSound.bukkitToMinecraftHolder(sound), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, seed); @@ -1818,6 +1821,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void playSound(Entity entity, String sound, org.bukkit.SoundCategory category, float volume, float pitch, long seed) { + org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(Holder.direct(SoundEvent.createVariableRangeEvent(ResourceLocation.parse(sound))), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, seed); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java index 5d6e4f2aec..10a95c1a40 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -534,6 +534,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { @Override public boolean addPotionEffect(PotionEffect effect, boolean force) { + org.spigotmc.AsyncCatcher.catchOp("effect add"); // Paper this.getHandle().addEffect(org.bukkit.craftbukkit.potion.CraftPotionUtil.fromBukkit(effect), EntityPotionEffectEvent.Cause.PLUGIN); // Paper - Don't ignore icon return true; } diff --git a/paper-server/src/main/java/org/spigotmc/AsyncCatcher.java b/paper-server/src/main/java/org/spigotmc/AsyncCatcher.java index bbf0d9d9c4..ef25987604 100644 --- a/paper-server/src/main/java/org/spigotmc/AsyncCatcher.java +++ b/paper-server/src/main/java/org/spigotmc/AsyncCatcher.java @@ -11,6 +11,7 @@ public class AsyncCatcher { if ( AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread ) { + MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable()); // Paper throw new IllegalStateException( "Asynchronous " + reason + "!" ); } }