From cd2960b8aa55432c6ceb1dbc60aac219fe8872d1 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/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java index dbdd18b96..6fd7cc2e8 100644 --- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java @@ -1058,6 +1058,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { } protected void addEntity(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot if (!(entity instanceof EntityComplexPart)) { EntityTypes entitytypes = entity.getEntityType(); int i = entitytypes.getChunkRange() * 16; @@ -1090,6 +1091,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { } protected void removeEntity(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity untrack"); // Spigot if (entity instanceof EntityPlayer) { EntityPlayer entityplayer = (EntityPlayer) entity; @@ -1279,6 +1281,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { } public void clear(EntityPlayer entityplayer) { + org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot if (this.trackedPlayers.remove(entityplayer)) { this.trackerEntry.a(entityplayer); } @@ -1286,6 +1289,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { } public void updatePlayer(EntityPlayer entityplayer) { + org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot if (entityplayer != this.tracker) { Vec3D vec3d = entityplayer.getPositionVector().d(this.tracker.getPositionVector()); // MC-155077, SPIGOT-5113 int i = Math.min(this.b(), (PlayerChunkMap.this.viewDistance - 1) * 16); diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java index f876beded..2f4bdc944 100644 --- a/src/main/java/net/minecraft/server/level/WorldServer.java +++ b/src/main/java/net/minecraft/server/level/WorldServer.java @@ -998,6 +998,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { // CraftBukkit start private boolean addEntity0(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot if (entity.dead) { // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getName(entity.getEntityType())); // CraftBukkit return false; @@ -1105,6 +1106,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { } public void unregisterEntity(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot if (entity instanceof EntityEnderDragon) { EntityComplexPart[] aentitycomplexpart = ((EntityEnderDragon) entity).eJ(); int i = aentitycomplexpart.length; @@ -1139,6 +1141,7 @@ public class WorldServer extends World implements GeneratorAccessSeed { } private void registerEntity(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot if (this.tickingEntities) { this.entitiesToAdd.add(entity); } else { diff --git a/src/main/java/net/minecraft/world/entity/EntityLiving.java b/src/main/java/net/minecraft/world/entity/EntityLiving.java index d58dac5b5..5d97c425e 100644 --- a/src/main/java/net/minecraft/world/entity/EntityLiving.java +++ b/src/main/java/net/minecraft/world/entity/EntityLiving.java @@ -982,6 +982,7 @@ public abstract class EntityLiving extends Entity { } public boolean addEffect(MobEffect mobeffect, 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 9676cb331..54a636a3d 100644 --- a/src/main/java/net/minecraft/world/item/crafting/CraftingManager.java +++ b/src/main/java/net/minecraft/world/item/crafting/CraftingManager.java @@ -82,6 +82,7 @@ public class CraftingManager extends ResourceDataJson { // CraftBukkit start public void addRecipe(IRecipe irecipe) { + org.spigotmc.AsyncCatcher.catchOp("Recipe Add"); // Spigot Object2ObjectLinkedOpenHashMap> map = this.recipes.get(irecipe.g()); // CraftBukkit if (map.containsKey(irecipe.getKey())) { 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 b7130360c..ef652d8f3 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 @@ -121,10 +121,13 @@ public abstract class BlockBase { } @Deprecated - public void onPlace(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1, boolean flag) {} + public void onPlace(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1, boolean flag) { + org.spigotmc.AsyncCatcher.catchOp("block onPlace"); // Spigot + } @Deprecated public void remove(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1, boolean flag) { + org.spigotmc.AsyncCatcher.catchOp("block remove"); // Spigot if (this.isTileEntity() && !iblockdata.a(iblockdata1.getBlock())) { world.removeTileEntity(blockposition); } diff --git a/src/main/java/net/minecraft/world/level/chunk/Chunk.java b/src/main/java/net/minecraft/world/level/chunk/Chunk.java index e5cdce069..de2521e11 100644 --- a/src/main/java/net/minecraft/world/level/chunk/Chunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/Chunk.java @@ -367,6 +367,7 @@ public class Chunk implements IChunkAccess { @Override public void a(Entity entity) { + org.spigotmc.AsyncCatcher.catchOp("Chunk add entity"); // Spigot this.q = true; int i = MathHelper.floor(entity.locX() / 16.0D); int j = MathHelper.floor(entity.locZ() / 16.0D); @@ -403,6 +404,7 @@ public class Chunk implements IChunkAccess { } public void a(Entity entity, int i) { + org.spigotmc.AsyncCatcher.catchOp("Chunk remove entity"); // Spigot if (i < 0) { i = 0; } @@ -591,6 +593,7 @@ public class Chunk implements IChunkAccess { } public void a(@Nullable Entity entity, AxisAlignedBB axisalignedbb, List list, @Nullable Predicate predicate) { + org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot int i = MathHelper.floor((axisalignedbb.minY - 2.0D) / 16.0D); int j = MathHelper.floor((axisalignedbb.maxY + 2.0D) / 16.0D); @@ -629,6 +632,7 @@ public class Chunk implements IChunkAccess { } public void a(@Nullable EntityTypes entitytypes, AxisAlignedBB axisalignedbb, List list, Predicate predicate) { + org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot int i = MathHelper.floor((axisalignedbb.minY - 2.0D) / 16.0D); int j = MathHelper.floor((axisalignedbb.maxY + 2.0D) / 16.0D); @@ -650,6 +654,7 @@ public class Chunk implements IChunkAccess { } public void a(Class oclass, AxisAlignedBB axisalignedbb, List list, @Nullable Predicate predicate) { + org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot int i = MathHelper.floor((axisalignedbb.minY - 2.0D) / 16.0D); int j = MathHelper.floor((axisalignedbb.maxY + 2.0D) / 16.0D); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 343e8fea9..c334e1471 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -737,6 +737,7 @@ public final class CraftServer implements Server { public boolean dispatchCommand(CommandSender sender, String commandLine) { Validate.notNull(sender, "Sender cannot be null"); Validate.notNull(commandLine, "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 478e44f05..5fe2d321d 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -389,6 +389,7 @@ public class CraftWorld implements World { @Override public boolean unloadChunkRequest(int x, int z) { + org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot if (isChunkLoaded(x, z)) { world.getChunkProvider().removeTicket(TicketType.PLUGIN, new ChunkCoordIntPair(x, z), 1, Unit.INSTANCE); } @@ -397,6 +398,7 @@ public class CraftWorld implements World { } private boolean unloadChunk0(int x, int z, boolean save) { + org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot if (!isChunkLoaded(x, z)) { return true; } @@ -411,6 +413,7 @@ public class CraftWorld 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)) { @@ -462,6 +465,7 @@ public class CraftWorld implements World { @Override public boolean loadChunk(int x, int z, boolean generate) { + org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot IChunkAccess chunk = world.getChunkProvider().getChunkAt(x, z, generate ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // If generate = false, but the chunk already exists, we will get this back. @@ -1100,6 +1104,7 @@ public class CraftWorld implements World { @Override public Collection getNearbyEntities(BoundingBox boundingBox, Predicate filter) { + org.spigotmc.AsyncCatcher.catchOp("getNearbyEntities"); // Spigot Validate.notNull(boundingBox, "Bounding box is null!"); AxisAlignedBB bb = new AxisAlignedBB(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ()); @@ -1254,6 +1259,7 @@ public class CraftWorld implements World { @Override public void save() { + org.spigotmc.AsyncCatcher.catchOp("world save"); // Spigot this.server.checkSaveState(); boolean oldSave = world.savingDisabled; diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index 74016c957..9ab492c95 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -512,6 +512,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { @Override public List getNearbyEntities(double x, double y, double z) { + org.spigotmc.AsyncCatcher.catchOp("getNearbyEntities"); // Spigot List notchEntityList = entity.world.getEntities(entity, entity.getBoundingBox().grow(x, y, z), null); 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 d4a992f33..a4546a0c3 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -327,6 +327,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void kickPlayer(String message) { + org.spigotmc.AsyncCatcher.catchOp("player kick"); // Spigot if (getHandle().playerConnection == null) return; getHandle().playerConnection.disconnect(message == null ? "" : message); diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScoreboardManager.java index efcd5aa02..73663bcea 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.25.1