Spigot had code that returned early in chunk add/remove methods. This was causing our code added to set current chunks and counts to be skipped over if the entity was default not persistent but made persistent. This was the source of many issues Fixes #1208
380 lines
19 KiB
Diff
380 lines
19 KiB
Diff
From 6ceadeb266a7fc9a4a41c7819ce49ec3e034b39c Mon Sep 17 00:00:00 2001
|
|
From: Joseph Hirschfeld <joe@ibj.io>
|
|
Date: Thu, 3 Mar 2016 03:15:41 -0600
|
|
Subject: [PATCH] Add exception reporting event
|
|
|
|
|
|
diff --git a/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
|
|
new file mode 100644
|
|
index 000000000..93397188b
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
|
|
@@ -0,0 +1,38 @@
|
|
+package com.destroystokyo.paper;
|
|
+
|
|
+import com.google.common.base.Preconditions;
|
|
+import org.bukkit.craftbukkit.scheduler.CraftTask;
|
|
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
|
|
+import com.destroystokyo.paper.exception.ServerSchedulerException;
|
|
+
|
|
+/**
|
|
+ * Reporting wrapper to catch exceptions not natively
|
|
+ */
|
|
+public class ServerSchedulerReportingWrapper implements Runnable {
|
|
+
|
|
+ private final CraftTask internalTask;
|
|
+
|
|
+ public ServerSchedulerReportingWrapper(CraftTask internalTask) {
|
|
+ this.internalTask = Preconditions.checkNotNull(internalTask, "internalTask");
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void run() {
|
|
+ try {
|
|
+ internalTask.run();
|
|
+ } catch (RuntimeException e) {
|
|
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
|
|
+ new ServerExceptionEvent(new ServerSchedulerException(e, internalTask))
|
|
+ );
|
|
+ throw e;
|
|
+ } catch (Throwable t) {
|
|
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
|
|
+ new ServerExceptionEvent(new ServerSchedulerException(t, internalTask))
|
|
+ ); //Do not rethrow, since it is not permitted with Runnable#run
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public CraftTask getInternalTask() {
|
|
+ return internalTask;
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
|
|
index 08d6ef09a..d5ef4ed0e 100644
|
|
--- a/src/main/java/net/minecraft/server/Chunk.java
|
|
+++ b/src/main/java/net/minecraft/server/Chunk.java
|
|
@@ -1,5 +1,6 @@
|
|
package net.minecraft.server;
|
|
|
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
|
import com.google.common.base.Predicate;
|
|
import com.google.common.collect.Maps;
|
|
import com.google.common.collect.Queues;
|
|
@@ -16,6 +17,7 @@ import org.apache.logging.log4j.Logger;
|
|
|
|
import com.google.common.collect.Lists; // CraftBukkit
|
|
import org.bukkit.Server; // CraftBukkit
|
|
+import org.bukkit.craftbukkit.util.CraftMagicNumbers; // Paper
|
|
|
|
public class Chunk {
|
|
|
|
@@ -791,10 +793,15 @@ public class Chunk {
|
|
this.tileEntities.remove(blockposition);
|
|
// Paper end
|
|
} else {
|
|
- System.out.println("Attempted to place a tile entity (" + tileentity + ") at " + tileentity.position.getX() + "," + tileentity.position.getY() + "," + tileentity.position.getZ()
|
|
- + " (" + org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(getBlockData(blockposition).getBlock()) + ") where there was no entity tile!");
|
|
- System.out.println("Chunk coordinates: " + (this.locX * 16) + "," + (this.locZ * 16));
|
|
- new Exception().printStackTrace();
|
|
+ // Paper start
|
|
+ ServerInternalException e = new ServerInternalException(
|
|
+ "Attempted to place a tile entity (" + tileentity + ") at " + tileentity.position.getX() + ","
|
|
+ + tileentity.position.getY() + "," + tileentity.position.getZ()
|
|
+ + " (" + CraftMagicNumbers.getMaterial(getBlockData(blockposition).getBlock()) + ") where there was no entity tile!\n" +
|
|
+ "Chunk coordinates: " + (this.locX * 16) + "," + (this.locZ * 16));
|
|
+ e.printStackTrace();
|
|
+ ServerInternalException.reportInternalException(e);
|
|
+ // Paper end
|
|
// CraftBukkit end
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
index 2b320cbd1..4e7e8e5fd 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
@@ -12,6 +12,7 @@ import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import javax.annotation.Nullable;
|
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
@@ -189,7 +190,11 @@ public class ChunkProviderServer implements IChunkProvider {
|
|
|
|
return chunk;
|
|
} catch (Exception exception) {
|
|
- ChunkProviderServer.a.error("Couldn\'t load chunk", exception);
|
|
+ // Paper start
|
|
+ String msg = "Couldn\'t load chunk";
|
|
+ ChunkProviderServer.a.error(msg, exception);
|
|
+ ServerInternalException.reportInternalException(exception);
|
|
+ // Paper end
|
|
return null;
|
|
}
|
|
}
|
|
@@ -198,7 +203,11 @@ public class ChunkProviderServer implements IChunkProvider {
|
|
try {
|
|
// this.chunkLoader.b(this.world, chunk); // Spigot
|
|
} catch (Exception exception) {
|
|
- ChunkProviderServer.a.error("Couldn\'t save entities", exception);
|
|
+ // Paper start
|
|
+ String msg = "Couldn\'t save entities";
|
|
+ ChunkProviderServer.a.error(msg, exception);
|
|
+ ServerInternalException.reportInternalException(exception);
|
|
+ // Paper end
|
|
}
|
|
|
|
}
|
|
@@ -208,9 +217,14 @@ public class ChunkProviderServer implements IChunkProvider {
|
|
chunk.setLastSaved(this.world.getTime());
|
|
this.chunkLoader.saveChunk(this.world, chunk, unloaded); // Spigot
|
|
} catch (IOException ioexception) {
|
|
- ChunkProviderServer.a.error("Couldn\'t save chunk", ioexception);
|
|
+ // Paper start
|
|
+ String msg = "Couldn\'t save chunk";
|
|
+ ChunkProviderServer.a.error(msg, ioexception);
|
|
+ ServerInternalException.reportInternalException(ioexception);
|
|
} catch (ExceptionWorldConflict exceptionworldconflict) {
|
|
- ChunkProviderServer.a.error("Couldn\'t save chunk; already in use by another instance of Minecraft?", exceptionworldconflict);
|
|
+ String msg = "Couldn\'t save chunk; already in use by another instance of Minecraft?";
|
|
+ ChunkProviderServer.a.error(msg, exceptionworldconflict);
|
|
+ ServerInternalException.reportInternalException(exceptionworldconflict);
|
|
}
|
|
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/NameReferencingFileConverter.java b/src/main/java/net/minecraft/server/NameReferencingFileConverter.java
|
|
index 83322b85b..b943a9b20 100644
|
|
--- a/src/main/java/net/minecraft/server/NameReferencingFileConverter.java
|
|
+++ b/src/main/java/net/minecraft/server/NameReferencingFileConverter.java
|
|
@@ -1,5 +1,7 @@
|
|
package net.minecraft.server;
|
|
|
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
|
+import com.google.common.base.Charsets;
|
|
import com.google.common.base.Predicate;
|
|
import com.google.common.collect.Iterators;
|
|
import com.google.common.collect.Lists;
|
|
@@ -361,6 +363,7 @@ public class NameReferencingFileConverter {
|
|
root = NBTCompressedStreamTools.a(new java.io.FileInputStream(file1));
|
|
} catch (Exception exception) {
|
|
exception.printStackTrace();
|
|
+ ServerInternalException.reportInternalException(exception); // Paper
|
|
}
|
|
|
|
if (root != null) {
|
|
@@ -374,6 +377,7 @@ public class NameReferencingFileConverter {
|
|
NBTCompressedStreamTools.a(root, new java.io.FileOutputStream(file2));
|
|
} catch (Exception exception) {
|
|
exception.printStackTrace();
|
|
+ ServerInternalException.reportInternalException(exception); // Paper
|
|
}
|
|
}
|
|
// CraftBukkit end
|
|
diff --git a/src/main/java/net/minecraft/server/PersistentCollection.java b/src/main/java/net/minecraft/server/PersistentCollection.java
|
|
index 936d6c640..50056f49a 100644
|
|
--- a/src/main/java/net/minecraft/server/PersistentCollection.java
|
|
+++ b/src/main/java/net/minecraft/server/PersistentCollection.java
|
|
@@ -1,5 +1,6 @@
|
|
package net.minecraft.server;
|
|
|
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Maps;
|
|
import java.io.DataInputStream;
|
|
@@ -53,6 +54,7 @@ public class PersistentCollection {
|
|
}
|
|
} catch (Exception exception1) {
|
|
exception1.printStackTrace();
|
|
+ ServerInternalException.reportInternalException(exception1); // Paper
|
|
}
|
|
}
|
|
|
|
@@ -102,6 +104,7 @@ public class PersistentCollection {
|
|
}
|
|
} catch (Exception exception) {
|
|
exception.printStackTrace();
|
|
+ ServerInternalException.reportInternalException(exception); // Paper
|
|
}
|
|
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
|
|
index 1ba26de5c..6a92b5af8 100644
|
|
--- a/src/main/java/net/minecraft/server/RegionFile.java
|
|
+++ b/src/main/java/net/minecraft/server/RegionFile.java
|
|
@@ -1,5 +1,6 @@
|
|
package net.minecraft.server;
|
|
|
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
|
import com.google.common.collect.Lists;
|
|
import java.io.BufferedInputStream;
|
|
import java.io.BufferedOutputStream;
|
|
@@ -82,6 +83,7 @@ public class RegionFile {
|
|
}
|
|
} catch (IOException ioexception) {
|
|
ioexception.printStackTrace();
|
|
+ ServerInternalException.reportInternalException(ioexception); // Paper
|
|
}
|
|
|
|
}
|
|
@@ -209,6 +211,7 @@ public class RegionFile {
|
|
this.b(i, j, (int) (MinecraftServer.aw() / 1000L));
|
|
} catch (IOException ioexception) {
|
|
ioexception.printStackTrace();
|
|
+ ServerInternalException.reportInternalException(ioexception); // Paper
|
|
}
|
|
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/RegionFileCache.java b/src/main/java/net/minecraft/server/RegionFileCache.java
|
|
index c15a0d1f8..5f9e9ddef 100644
|
|
--- a/src/main/java/net/minecraft/server/RegionFileCache.java
|
|
+++ b/src/main/java/net/minecraft/server/RegionFileCache.java
|
|
@@ -1,5 +1,6 @@
|
|
package net.minecraft.server;
|
|
|
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
|
import com.google.common.collect.Maps;
|
|
import java.io.DataInputStream;
|
|
import java.io.DataOutputStream;
|
|
@@ -68,6 +69,7 @@ public class RegionFileCache {
|
|
}
|
|
} catch (IOException ioexception) {
|
|
ioexception.printStackTrace();
|
|
+ ServerInternalException.reportInternalException(ioexception); // Paper
|
|
}
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java
|
|
index 1c7c187c7..68a045323 100644
|
|
--- a/src/main/java/net/minecraft/server/SpawnerCreature.java
|
|
+++ b/src/main/java/net/minecraft/server/SpawnerCreature.java
|
|
@@ -7,6 +7,7 @@ import java.util.Random;
|
|
import java.util.Set;
|
|
|
|
// CraftBukkit start
|
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
|
import org.bukkit.craftbukkit.util.LongHash;
|
|
import org.bukkit.craftbukkit.util.LongHashSet;
|
|
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
|
@@ -177,6 +178,7 @@ public final class SpawnerCreature {
|
|
entityinsentient = (EntityInsentient) biomebase_biomemeta.b.getConstructor(new Class[] { World.class}).newInstance(new Object[] { worldserver});
|
|
} catch (Exception exception) {
|
|
exception.printStackTrace();
|
|
+ ServerInternalException.reportInternalException(exception); // Paper
|
|
return j1;
|
|
}
|
|
|
|
@@ -288,6 +290,7 @@ public final class SpawnerCreature {
|
|
entityinsentient = (EntityInsentient) biomebase_biomemeta.b.getConstructor(new Class[] { World.class}).newInstance(new Object[] { world});
|
|
} catch (Exception exception) {
|
|
exception.printStackTrace();
|
|
+ ServerInternalException.reportInternalException(exception); // Paper
|
|
continue;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/VillageSiege.java b/src/main/java/net/minecraft/server/VillageSiege.java
|
|
index 9ff4f23ab..6fce3015f 100644
|
|
--- a/src/main/java/net/minecraft/server/VillageSiege.java
|
|
+++ b/src/main/java/net/minecraft/server/VillageSiege.java
|
|
@@ -1,5 +1,7 @@
|
|
package net.minecraft.server;
|
|
|
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
|
+
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import javax.annotation.Nullable;
|
|
@@ -136,6 +138,7 @@ public class VillageSiege {
|
|
entityzombie.prepare(this.a.D(new BlockPosition(entityzombie)), (GroupDataEntity) null);
|
|
} catch (Exception exception) {
|
|
exception.printStackTrace();
|
|
+ ServerInternalException.reportInternalException(exception); // Paper
|
|
return false;
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
|
|
index 89197281e..6be9c1815 100644
|
|
--- a/src/main/java/net/minecraft/server/World.java
|
|
+++ b/src/main/java/net/minecraft/server/World.java
|
|
@@ -1,5 +1,7 @@
|
|
package net.minecraft.server;
|
|
|
|
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
|
|
+import com.destroystokyo.paper.exception.ServerInternalException;
|
|
import com.google.common.base.Function;
|
|
import com.google.common.base.MoreObjects;
|
|
import com.google.common.base.Predicate;
|
|
@@ -1457,8 +1459,10 @@ public abstract class World implements IBlockAccess {
|
|
} catch (Throwable throwable1) {
|
|
entity.tickTimer.stopTiming();
|
|
// Paper start - Prevent tile entity and entity crashes
|
|
- System.err.println("Entity threw exception at " + entity.world.getWorld().getName() + ":" + entity.locX + "," + entity.locY + "," + entity.locZ);
|
|
+ String msg = "Entity threw exception at " + entity.world.getWorld().getName() + ":" + entity.locX + "," + entity.locY + "," + entity.locZ;
|
|
+ System.err.println(msg);
|
|
throwable1.printStackTrace();
|
|
+ getServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable1)));
|
|
entity.dead = true;
|
|
continue;
|
|
// Paper end
|
|
@@ -1523,8 +1527,10 @@ public abstract class World implements IBlockAccess {
|
|
this.methodProfiler.b();
|
|
} catch (Throwable throwable2) {
|
|
// Paper start - Prevent tile entity and entity crashes
|
|
- System.err.println("TileEntity threw exception at " + tileentity.world.getWorld().getName() + ":" + tileentity.position.getX() + "," + tileentity.position.getY() + "," + tileentity.position.getZ());
|
|
+ String msg = "TileEntity threw exception at " + tileentity.world.getWorld().getName() + ":" + tileentity.position.getX() + "," + tileentity.position.getY() + "," + tileentity.position.getZ();
|
|
+ System.err.println(msg);
|
|
throwable2.printStackTrace();
|
|
+ getServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable2)));
|
|
tilesThisCycle--;
|
|
this.tileEntityListTick.remove(tileTickPosition--);
|
|
continue;
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
|
index 93b9134d6..26753fac5 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
|
@@ -15,6 +15,9 @@ import java.util.concurrent.atomic.AtomicReference;
|
|
import java.util.logging.Level;
|
|
|
|
import co.aikar.timings.MinecraftTimings; // Paper
|
|
+import com.destroystokyo.paper.ServerSchedulerReportingWrapper;
|
|
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
|
|
+import com.destroystokyo.paper.exception.ServerSchedulerException;
|
|
import org.apache.commons.lang.Validate;
|
|
import org.bukkit.plugin.IllegalPluginAccessException;
|
|
import org.bukkit.plugin.Plugin;
|
|
@@ -360,20 +363,26 @@ public class CraftScheduler implements BukkitScheduler {
|
|
try {
|
|
task.run();
|
|
} catch (final Throwable throwable) {
|
|
+ // Paper start
|
|
+ String msg = String.format(
|
|
+ "Task #%s for %s generated an exception",
|
|
+ task.getTaskId(),
|
|
+ task.getOwner().getDescription().getFullName());
|
|
task.getOwner().getLogger().log(
|
|
Level.WARNING,
|
|
- String.format(
|
|
- "Task #%s for %s generated an exception",
|
|
- task.getTaskId(),
|
|
- task.getOwner().getDescription().getFullName()),
|
|
+ msg,
|
|
throwable);
|
|
+ task.getOwner().getServer().getPluginManager().callEvent(
|
|
+ new ServerExceptionEvent(new ServerSchedulerException(msg, throwable, task))
|
|
+ );
|
|
+ // Paper end
|
|
} finally {
|
|
currentTask = null;
|
|
}
|
|
parsePending();
|
|
} else {
|
|
debugTail = debugTail.setNext(new CraftAsyncDebugger(currentTick + RECENT_TICKS, task.getOwner(), task.getTaskClass()));
|
|
- executor.execute(task);
|
|
+ executor.execute(new ServerSchedulerReportingWrapper(task)); // Paper
|
|
// We don't need to parse pending
|
|
// (async tasks must live with race-conditions if they attempt to cancel between these few lines of code)
|
|
}
|
|
--
|
|
2.18.0
|
|
|