aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/server/0056-Add-exception-reporting-event.patch
blob: deb9b2f20b6bd63bc2d2ce993417c35bdf20eb06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
From 0000000000000000000000000000000000000000 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 0000000000000000000000000000000000000000..f699ce18ca044f813e194ef2786b7ea853ea86e7
--- /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;
+    }
+}
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index f9e9e00855627b78e8ff018bf6d52c9787fcffeb..fb8d50dc14e1d23001e184b425bc6ac2f8b0f37e 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -961,6 +961,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
                 return true;
             } catch (Exception exception) {
                 ChunkMap.LOGGER.error("Failed to save chunk {},{}", new Object[]{chunkcoordintpair.x, chunkcoordintpair.z, exception});
+                com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
                 return false;
             }
         }
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
index 7b84b20a4de0d6e95a1d47cb077abd0e00a2336c..b7b98832be6178a2bca534bf974519ede977b282 100644
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
@@ -1,5 +1,6 @@
 package net.minecraft.server.players;
 
+import com.destroystokyo.paper.exception.ServerInternalException;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.io.Files;
@@ -363,6 +364,7 @@ public class OldUsersConverter {
                             root = NbtIo.readCompressed(new java.io.FileInputStream(file5));
                         } catch (Exception exception) {
                             exception.printStackTrace();
+                            ServerInternalException.reportInternalException(exception); // Paper
                         }
 
                         if (root != null) {
@@ -376,6 +378,7 @@ public class OldUsersConverter {
                                 NbtIo.writeCompressed(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/world/entity/ai/village/VillageSiege.java b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
index 1a9dfd8411bb8affdb3ff4c003433ecab203b004..5e526d0feda11d6b73f71b965aa098e0a79457d1 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
@@ -118,6 +118,7 @@ public class VillageSiege implements CustomSpawner {
                 entityzombie.finalizeSpawn(world, world.getCurrentDifficultyAt(entityzombie.blockPosition()), MobSpawnType.EVENT, (SpawnGroupData) null, (CompoundTag) null);
             } catch (Exception exception) {
                 VillageSiege.LOGGER.warn("Failed to create zombie for village siege at {}", vec3d, exception);
+                com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
                 return;
             }
 
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 922b234865ff5d64049d634d0356f9a068bc8a8c..d923cc91a8f1e71831be8ded1b4818ac3b48fc34 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -1,5 +1,10 @@
 package net.minecraft.world.level;
 
+import co.aikar.timings.Timing;
+import co.aikar.timings.Timings;
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
+import com.destroystokyo.paper.exception.ServerInternalException;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.Lists;
 import com.mojang.serialization.Codec;
 import java.io.IOException;
@@ -738,6 +743,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
             // Paper start - Prevent tile entity and entity crashes
             final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
             MinecraftServer.LOGGER.error(msg, throwable);
+            getCraftServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable)));
             entity.discard();
             // Paper end
         }
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index 8d4efe65baf28760ee68cecd7ef7c8e65a2912ba..b8666d46e85bc7e9e3a05b4ebd65f59138ac55d1 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -289,6 +289,7 @@ public final class NaturalSpawner {
             }
         } catch (Exception exception) {
             NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
+            com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
             return null;
         }
     }
@@ -401,6 +402,7 @@ public final class NaturalSpawner {
                                     entity = biomesettingsmobs_c.type.create(world.getLevel());
                                 } catch (Exception exception) {
                                     NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
+                                    com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
                                     continue;
                                 }
 
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index ed6203119fe2e4ee47a2d51c84df5b7c236f32da..108c7ec010f826f9b9bb2db0987d2bcc18266482 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -1,6 +1,7 @@
 package net.minecraft.world.level.chunk;
 
 import com.google.common.collect.ImmutableList;
+import com.destroystokyo.paper.exception.ServerInternalException;
 import com.google.common.collect.Maps;
 import com.google.common.collect.UnmodifiableIterator;
 import com.mojang.logging.LogUtils;
@@ -544,10 +545,15 @@ public class LevelChunk extends ChunkAccess {
 
             // CraftBukkit start
         } else {
-            System.out.println("Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + "," + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
-                + " (" + this.getBlockState(blockposition) + ") where there was no entity tile!");
-            System.out.println("Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16));
-            new Exception().printStackTrace();
+            // Paper start
+            ServerInternalException e = new ServerInternalException(
+                "Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + ","
+                    + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
+                    + " (" + getBlockState(blockposition) + ") where there was no entity tile!\n" +
+                    "Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16));
+            e.printStackTrace();
+            ServerInternalException.reportInternalException(e);
+            // Paper end
             // CraftBukkit end
         }
     }
@@ -1027,6 +1033,7 @@ public class LevelChunk extends ChunkAccess {
                         // Paper start - Prevent tile entity and entity crashes
                         final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
                         net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
+                        net.minecraft.world.level.chunk.LevelChunk.this.level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new ServerInternalException(msg, throwable)));
                         LevelChunk.this.removeBlockEntity(this.getPos());
                         // Paper end
                         // Spigot start
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
index d51bafd2f5a763b8a49c835ab74a7cf60caa1ab6..fbf5f01a9a7968194fc85589ca7f9fa328da4881 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -274,6 +274,7 @@ public class RegionFile implements AutoCloseable {
                     return true;
                 }
             } catch (IOException ioexception) {
+                com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(ioexception); // Paper
                 return false;
             }
         }
@@ -355,6 +356,7 @@ public class RegionFile implements AutoCloseable {
             ((java.nio.Buffer) bytebuffer).position(5); // CraftBukkit - decompile error
             filechannel.write(bytebuffer);
         } catch (Throwable throwable) {
+            com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(throwable); // Paper
             if (filechannel != null) {
                 try {
                     filechannel.close();
diff --git a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
index 5272a718178b5a2cb1df263ce0c5500c92c9ebda..0465b397b628b11a6fc52e3375945c94d68cfdd5 100644
--- a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
+++ b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
@@ -120,6 +120,7 @@ public class DimensionDataStorage {
 
             pushbackInputStream.close();
         } catch (Throwable var15) {
+            com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(var15); // Paper
             try {
                 fileInputStream.close();
             } catch (Throwable var10) {
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
index 07c4d9cd5081378e1b903518f7174fca959cd9e3..dfc2789009fcaa08baa8054bdac915590b8701d6 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
@@ -17,6 +17,9 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
 import java.util.function.IntUnaryOperator;
 import java.util.logging.Level;
+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;
@@ -434,6 +437,8 @@ public class CraftScheduler implements BukkitScheduler {
                             msg,
                             throwable);
                     }
+                    org.bukkit.Bukkit.getServer().getPluginManager().callEvent(
+                        new ServerExceptionEvent(new ServerSchedulerException(msg, throwable, task)));
                     // Paper end
                 } finally {
                     this.currentTask = null;
@@ -441,7 +446,7 @@ public class CraftScheduler implements BukkitScheduler {
                 this.parsePending();
             } else {
                 this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass()));
-                this.executor.execute(task);
+                this.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)
             }