From 97ff8b2304836754dc4178e714f3484009a01288 Mon Sep 17 00:00:00 2001 From: md_5 Date: Tue, 25 Mar 2014 16:10:01 +1100 Subject: [PATCH] Async Operation Catching Catch and throw an exception when a potentially unsafe operation occurs on a thread other than the main server thread. diff --git a/src/main/java/net/minecraft/server/level/ChunkMapDistance.java b/src/main/java/net/minecraft/server/level/ChunkMapDistance.java index faff79f8f..2e44b6852 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMapDistance.java +++ b/src/main/java/net/minecraft/server/level/ChunkMapDistance.java @@ -102,6 +102,7 @@ public abstract class ChunkMapDistance { protected abstract PlayerChunk updateChunkScheduling(long i, int j, @Nullable PlayerChunk playerchunk, int k); public boolean runAllUpdates(PlayerChunkMap playerchunkmap) { + org.spigotmc.AsyncCatcher.catchOp("chunk updates"); // Spigot this.naturalSpawnChunkCounter.runAllUpdates(); this.tickingTicketsTracker.runAllUpdates(); this.playerTicketManager.runAllUpdates(); diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java index 4d8aa931f..5043631d1 100644 --- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java @@ -1249,6 +1249,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.b, Gener } protected void addEntity(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot if (!(entity instanceof EntityComplexPart)) { EntityTypes entitytypes = entity.getType(); int i = entitytypes.clientTrackingRange() * 16; @@ -1284,6 +1285,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.b, Gener } protected void removeEntity(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity untrack"); // Spigot if (entity instanceof EntityPlayer entityplayer) { this.updatePlayerStatus(entityplayer, false); ObjectIterator objectiterator = this.entityMap.values().iterator(); @@ -1503,6 +1505,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.b, Gener } public void removePlayer(EntityPlayer entityplayer) { + org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot if (this.seenBy.remove(entityplayer.connection)) { this.serverEntity.removePairing(entityplayer); } @@ -1510,6 +1513,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.b, Gener } public void updatePlayer(EntityPlayer entityplayer) { + org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot if (entityplayer != this.entity) { Vec3D vec3d = entityplayer.position().subtract(this.entity.position()); int i = PlayerChunkMap.this.getPlayerViewDistance(entityplayer); diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java index ba487c2ac..ad8a7fff1 100644 --- a/src/main/java/net/minecraft/server/level/WorldServer.java +++ b/src/main/java/net/minecraft/server/level/WorldServer.java @@ -1068,6 +1068,7 @@ public class WorldServer extends World implements ServerEntityGetter, GeneratorA // CraftBukkit start private boolean addEntity(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot if (entity.isRemoved()) { // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit return false; @@ -1936,6 +1937,7 @@ public class WorldServer extends World implements ServerEntityGetter, GeneratorA @Override public LevelEntityGetter getEntities() { + org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot return this.entityManager.getEntityGetter(); } @@ -2055,6 +2057,7 @@ public class WorldServer extends World implements ServerEntityGetter, GeneratorA } public void onTrackingStart(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot WorldServer.this.getChunkSource().addEntity(entity); if (entity instanceof EntityPlayer entityplayer) { WorldServer.this.players.add(entityplayer); @@ -2088,6 +2091,7 @@ public class WorldServer extends World implements ServerEntityGetter, GeneratorA } public void onTrackingEnd(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot WorldServer.this.getChunkSource().removeEntity(entity); if (entity instanceof EntityPlayer entityplayer) { WorldServer.this.players.remove(entityplayer); diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java index 510378852..86f232121 100644 --- a/src/main/java/net/minecraft/world/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java @@ -1129,6 +1129,7 @@ public abstract class EntityLiving extends Entity implements Attackable { } public boolean addEffect(MobEffect mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause) { + org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot if (isTickingEffects) { effectsToProcess.add(new ProcessableEffect(mobeffect, cause)); return true; diff --git a/src/main/java/net/minecraft/world/item/crafting/CraftingManager.java b/src/main/java/net/minecraft/world/item/crafting/CraftingManager.java index eaf464384..489aefe4a 100644 --- a/src/main/java/net/minecraft/world/item/crafting/CraftingManager.java +++ b/src/main/java/net/minecraft/world/item/crafting/CraftingManager.java @@ -118,6 +118,7 @@ public class CraftingManager extends ResourceDataAbstract implements // CraftBukkit start public void addRecipe(RecipeHolder irecipe) { + org.spigotmc.AsyncCatcher.catchOp("Recipe Add"); // Spigot this.recipes.addRecipe(irecipe); finalizeRecipeLoading(); } diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java index d60d8b93f..102121490 100644 --- a/src/main/java/net/minecraft/world/level/block/state/BlockBase.java +++ b/src/main/java/net/minecraft/world/level/block/state/BlockBase.java @@ -161,7 +161,9 @@ public abstract class BlockBase implements FeatureElement { protected void neighborChanged(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, @Nullable Orientation orientation, boolean flag) {} - protected void onPlace(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1, boolean flag) {} + protected void onPlace(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1, boolean flag) { + org.spigotmc.AsyncCatcher.catchOp("block onPlace"); // Spigot + } // CraftBukkit start protected void onPlace(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1, boolean flag, @Nullable ItemActionContext context) { @@ -170,6 +172,7 @@ public abstract class BlockBase implements FeatureElement { // CraftBukkit end protected void onRemove(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1, boolean flag) { + org.spigotmc.AsyncCatcher.catchOp("block remove"); // Spigot if (iblockdata.hasBlockEntity() && !iblockdata.is(iblockdata1.getBlock())) { world.removeBlockEntity(blockposition); } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 71cb0d98b..862f5d3ec 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -900,6 +900,7 @@ public final class CraftServer implements Server { public boolean dispatchCommand(CommandSender sender, String commandLine) { Preconditions.checkArgument(sender != null, "sender cannot be null"); Preconditions.checkArgument(commandLine != null, "commandLine cannot be null"); + org.spigotmc.AsyncCatcher.catchOp("command dispatch"); // Spigot if (commandMap.dispatch(sender, commandLine)) { return true; diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index b689d7d20..3aad490b1 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -288,6 +288,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean unloadChunkRequest(int x, int z) { + org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot if (isChunkLoaded(x, z)) { world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkCoordIntPair(x, z), 1, Unit.INSTANCE); } @@ -296,6 +297,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { } private boolean unloadChunk0(int x, int z, boolean save) { + org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot if (!isChunkLoaded(x, z)) { return true; } @@ -312,6 +314,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean regenerateChunk(int x, int z) { + org.spigotmc.AsyncCatcher.catchOp("chunk regenerate"); // Spigot throw new UnsupportedOperationException("Not supported in this Minecraft version! Unless you can fix it, this is not a bug :)"); /* if (!unloadChunk0(x, z, false)) { @@ -389,6 +392,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public boolean loadChunk(int x, int z, boolean generate) { + org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot IChunkAccess chunk = world.getChunkSource().getChunk(x, z, generate ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // If generate = false, but the chunk already exists, we will get this back. @@ -924,6 +928,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public Collection getNearbyEntities(BoundingBox boundingBox, Predicate filter) { + org.spigotmc.AsyncCatcher.catchOp("getNearbyEntities"); // Spigot Preconditions.checkArgument(boundingBox != null, "BoundingBox cannot be null"); AxisAlignedBB bb = new AxisAlignedBB(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ()); @@ -1078,6 +1083,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void save() { + org.spigotmc.AsyncCatcher.catchOp("world save"); // Spigot this.server.checkSaveState(); boolean oldSave = world.noSave; diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index ff47b09dc..f9aba6e6d 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -230,6 +230,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { @Override public List getNearbyEntities(double x, double y, double z) { Preconditions.checkState(!entity.generation, "Cannot get nearby entities during world generation"); + org.spigotmc.AsyncCatcher.catchOp("getNearbyEntities"); // Spigot List notchEntityList = entity.level().getEntities(entity, entity.getBoundingBox().inflate(x, y, z), Predicates.alwaysTrue()); List bukkitEntityList = new java.util.ArrayList(notchEntityList.size()); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index daf975fd0..7e49a4edf 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -496,6 +496,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void kickPlayer(String message) { + org.spigotmc.AsyncCatcher.catchOp("player kick"); // Spigot getHandle().transferCookieConnection.kickPlayer(CraftChatMessage.fromStringOrEmpty(message, true)); } diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java index 726887ece..ec5670e24 100644 --- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java +++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java @@ -41,6 +41,7 @@ public final class CraftScoreboardManager implements ScoreboardManager { @Override public CraftScoreboard getNewScoreboard() { + org.spigotmc.AsyncCatcher.catchOp("scoreboard creation"); // Spigot CraftScoreboard scoreboard = new CraftScoreboard(new ScoreboardServer(server)); scoreboards.add(scoreboard); return scoreboard; diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java index 2e057fd4c..ddef523ea 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java +++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java @@ -12,6 +12,7 @@ public class ServerShutdownThread extends Thread { @Override public void run() { try { + org.spigotmc.AsyncCatcher.enabled = false; // Spigot server.close(); } finally { try { diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java new file mode 100644 index 000000000..aeed76972 --- /dev/null +++ b/src/main/java/org/spigotmc/AsyncCatcher.java @@ -0,0 +1,17 @@ +package org.spigotmc; + +import net.minecraft.server.MinecraftServer; + +public class AsyncCatcher +{ + + public static boolean enabled = true; + + public static void catchOp(String reason) + { + if ( enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread ) + { + throw new IllegalStateException( "Asynchronous " + reason + "!" ); + } + } +} -- 2.48.1