From 0000000000000000000000000000000000000000 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 diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index fa6783305aae385723d6bdb83166e147b8ebcfe9..27bcfe893db83bb369186ccf1d48f28e9d2cae82 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1570,6 +1570,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl } public void internalTeleport(double d0, double d1, double d2, float f, float f1, Set set) { // Paper + 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()); diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java index 8438ca0157d8a27f76858d8f5139a5f8a699a65c..bcb842a40ab97b4920e4e32cb3e6c8e1ff3081bd 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -1118,7 +1118,7 @@ public abstract class LivingEntity extends Entity implements Attackable { } 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/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java index bbbf6dd8e566ecdca8794e3b03765fe7e426a2bd..66ab901956ca394c251c420338643d39817a1b7e 100644 --- a/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java +++ b/src/main/java/net/minecraft/world/level/entity/PersistentEntitySectionManager.java @@ -77,6 +77,7 @@ public class PersistentEntitySectionManager implements A } 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; @@ -90,6 +91,7 @@ public class PersistentEntitySectionManager implements A } private boolean addEntity(T entity, boolean existing) { + org.spigotmc.AsyncCatcher.catchOp("Entity add"); // Paper // Paper start - chunk system hooks if (existing) { // I don't want to know why this is a generic type. @@ -145,19 +147,23 @@ public class PersistentEntitySectionManager implements A } 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); } @@ -169,6 +175,7 @@ public class PersistentEntitySectionManager implements A } public void updateChunkStatus(ChunkPos chunkPos, Visibility trackingStatus) { + org.spigotmc.AsyncCatcher.catchOp("Update chunk status"); // Paper long i = chunkPos.toLong(); if (trackingStatus == Visibility.HIDDEN) { @@ -213,6 +220,7 @@ public class PersistentEntitySectionManager implements A } 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) { @@ -257,6 +265,7 @@ public class PersistentEntitySectionManager implements A } 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); @@ -270,6 +279,7 @@ public class PersistentEntitySectionManager implements A } 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); }, true); // CraftBukkit - add boolean for event call @@ -294,6 +304,7 @@ public class PersistentEntitySectionManager implements A } private void processPendingLoads() { + org.spigotmc.AsyncCatcher.catchOp("Entity chunk process pending loads"); // Paper ChunkEntities chunkentities; // CraftBukkit - decompile error while ((chunkentities = (ChunkEntities) this.loadingInbox.poll()) != null) { @@ -310,6 +321,7 @@ public class PersistentEntitySectionManager implements A } public void tick() { + org.spigotmc.AsyncCatcher.catchOp("Entity manager tick"); // Paper this.processPendingLoads(); this.processUnloads(); } @@ -330,6 +342,7 @@ public class PersistentEntitySectionManager implements A } public void autoSave() { + 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; @@ -344,6 +357,7 @@ public class PersistentEntitySectionManager implements A } public void saveAll() { + org.spigotmc.AsyncCatcher.catchOp("Entity manager save"); // Paper LongSet longset = this.getAllChunksToSave(); while (!longset.isEmpty()) { @@ -451,6 +465,7 @@ public class PersistentEntitySectionManager implements A 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)) { @@ -505,6 +520,7 @@ public class PersistentEntitySectionManager implements A @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/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index d1b77ffe565a112556c7a04057c82b827e8ea7aa..989abde6b753a16b389c1145b3e6b337eb73c715 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -1803,6 +1803,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(); @@ -1814,6 +1815,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(); @@ -1846,6 +1848,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); @@ -1857,6 +1860,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(new ResourceLocation(sound))), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, seed); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java index 711f4ca8ee42a14e40af86d93a9685b4b9a2ba99..269664d3894835e5bafc39e65ee5245ae1d74d78 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -463,6 +463,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/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java index 05e94702e42b8f5c35d2a112c486d57948a3acba..d678ca116f9b81ab9d7d99a698e0ce066c132f34 100644 --- a/src/main/java/org/spigotmc/AsyncCatcher.java +++ b/src/main/java/org/spigotmc/AsyncCatcher.java @@ -11,6 +11,7 @@ public class AsyncCatcher { if ( !io.papermc.paper.util.TickThread.isTickThread() ) // Paper // Paper - rewrite chunk system { + MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable()); // Paper throw new IllegalStateException( "Asynchronous " + reason + "!" ); } }