WearBlackAllDay / DimensionalThreading

An attempt to optimize the fabric server, by assigning each dimension their own thread.
MIT License
256 stars 22 forks source link

Crash: Exception Ticking World #63

Open TheAyes opened 2 years ago

TheAyes commented 2 years ago

I'm using a local fabric server for developing datapacks. My character has been in the nether and the crash occurred a few ticks after me joining it.

[19:30:04] [Netty Server IO #1/INFO]: Priority overwritten for player CrystalMemories. Normal: GRAVE / Robbing: INVENTORY
[19:30:12] [Server thread/ERROR]: Encountered an unexpected exception
net.minecraft.class_148: Exception ticking world
    at wearblackallday.dimthread.util.CrashInfo.crash(CrashInfo.java:12) ~[DimThread-1.2.6.jar:?]
    at net.minecraft.server.MinecraftServer.handler$znj000$tickWorlds(MinecraftServer.java:4336) ~[server-intermediary.jar:?]
    at net.minecraft.server.MinecraftServer.method_3813(MinecraftServer.java:896) ~[server-intermediary.jar:?]
    at net.minecraft.class_3176.method_3813(class_3176.java:322) ~[server-intermediary.jar:?]
    at net.minecraft.server.MinecraftServer.method_3748(MinecraftServer.java:851) ~[server-intermediary.jar:?]
    at net.minecraft.server.MinecraftServer.method_29741(MinecraftServer.java:697) ~[server-intermediary.jar:?]
    at net.minecraft.server.MinecraftServer.method_29739(MinecraftServer.java:273) ~[server-intermediary.jar:?]
    at java.lang.Thread.run(Thread.java:833) [?:?]
Caused by: java.lang.ClassCastException: class net.minecraft.class_2821 cannot be cast to class net.minecraft.class_2818 (net.minecraft.class_2821 and net.minecraft.class_2818 are in unnamed module of loader net.fabricmc.loader.impl.launch.knot.KnotClassLoader @91161c7)
    at net.minecraft.class_1937.method_8497(class_1937.java:4598) ~[server-intermediary.jar:?]
    at net.minecraft.class_1937.method_8320(class_1937.java:5090) ~[server-intermediary.jar:?]
    at net.minecraft.class_1937.method_8492(class_1937.java:353) ~[server-intermediary.jar:?]
    at net.minecraft.class_1937.method_8452(class_1937.java:321) ~[server-intermediary.jar:?]
    at net.minecraft.class_3218.method_8408(class_3218.java:1377) ~[server-intermediary.jar:?]
    at net.minecraft.class_1937.method_30092(class_1937.java:235) ~[server-intermediary.jar:?]
    at net.minecraft.class_1937.method_8652(class_1937.java:196) ~[server-intermediary.jar:?]
    at net.minecraft.class_3609.method_15745(class_3609.java:262) ~[server-intermediary.jar:?]
    at net.minecraft.class_3616.method_15745(class_3616.java:194) ~[server-intermediary.jar:?]
    at net.minecraft.class_3609.method_15725(class_3609.java:135) ~[server-intermediary.jar:?]
    at net.minecraft.class_3609.method_15778(class_3609.java:463) ~[server-intermediary.jar:?]
    at net.minecraft.class_3610.method_15770(class_3610.java:79) ~[server-intermediary.jar:?]
    at net.minecraft.class_3218.method_14171(class_3218.java:684) ~[server-intermediary.jar:?]
    at net.minecraft.class_6757.method_39390(class_6757.java:215) ~[server-intermediary.jar:?]
    at net.minecraft.class_6757.method_39377(class_6757.java:98) ~[server-intermediary.jar:?]
    at net.minecraft.class_3218.method_18765(class_3218.java:303) ~[server-intermediary.jar:?]
    at net.minecraft.server.MinecraftServer.md5f51a4$lambda$tickWorlds$0$2(MinecraftServer.java:4326) ~[server-intermediary.jar:?]
    at wearblackallday.dimthread.DimThread.swapThreadsAndRun(DimThread.java:34) ~[DimThread-1.2.6.jar:?]
    at net.minecraft.server.MinecraftServer.md5f51a4$lambda$tickWorlds$1$1(MinecraftServer.java:4324) ~[server-intermediary.jar:?]
    at wearblackallday.util.ThreadPool.lambda$execute$1(ThreadPool.java:49) ~[com_github_wearblackallday_javau-bd58640372-66147bdb5f3fcaf7.jar:?]
    at wearblackallday.util.ThreadPool.lambda$execute$0(ThreadPool.java:43) ~[com_github_wearblackallday_javau-bd58640372-66147bdb5f3fcaf7.jar:?]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?]
    ... 1 more
[19:30:12] [Server thread/ERROR]: This crash report has been saved to: C:\Users\Ayes\Desktop\InfiniaServerControl\DevServer\.\crash-reports\crash-2022-05-26_19.30.12-server.txt
yikerman commented 2 years ago

Seems like a duplicate of #42.

skerit commented 2 years ago

That's strange, I got the same class net.minecraft.class_2821 cannot be cast to class net.minecraft.class_2818 error, which means it's trying to cast ReadOnlyChunk to WorldChunk.

I don't have any datapacks though, though I do seem to have an extra mixin in my crash report ~which I can't find~ (net.minecraft.class_3218.redirect$bke000$redirectBlockStateTick(class_3218.java:9231))

I believe this extra redirectBlockStateTick comes from Lithium, but not sure if that's actually the cause or just a coincidence.

skerit commented 2 years ago

Been looking into this casting to WorldChunk thing a bit more: in my cast I believe it has to do with using ServerWorld#setChunkForced, though I guess other seemingly OK ways can cause the error too.

So World#getChunk(int i, int j) always returns a WorldChunk. To do this, it just calls this.getChunk(i, j, ChunkStatus.FULL) (which returns a Chunk) and then just blindly downcasts it to WorldChunk. Sometimes it doesn't return a WorldChunk but a ReadOnlyChunk, and that's the error that's crashing the server.

Following this trail, World#getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) calls this.getChunkManager().getChunk(chunkX, chunkZ, leastStatus, create), which takes us to the ServerChunkManager#getChunk method.

In there it does a thread check: if (Thread.currentThread() != this.serverThread), and I guess this will be false a lot when using DimensionalThreading.

Though the only thing it then does is to force getting the chunk on the main thread and blocking until it has done so, so still not 100% sure what's actually causing the wrong chunk type being returned.

CaveNightingale commented 2 years ago

That's strange, I got the same class net.minecraft.class_2821 cannot be cast to class net.minecraft.class_2818 error, which means it's trying to cast ReadOnlyChunk to WorldChunk.

I don't have any datapacks though, though I do seem to have an extra mixin in my crash report ~which I can't find~ (net.minecraft.class_3218.redirect$bke000$redirectBlockStateTick(class_3218.java:9231))

I believe this extra redirectBlockStateTick comes from Lithium, but not sure if that's actually the cause or just a coincidence.

I got the similar java.lang.ClassCastException: class net.minecraft.class_2821 cannot be cast to class net.minecraft.class_2818 (net.minecraft.class_2821 and net.minecraft.class_2818 are in unnamed module of loader net.fabricmc.loader.impl.launch.knot.KnotClassLoader @4520ebad), but I don't have a redirectBlockStateTick in my stacktrace. My stacktrace is below.

java.lang.ClassCastException: class net.minecraft.class_2821 cannot be cast to class net.minecraft.class_2818 (net.minecraft.class_2821 and net.minecraft.class_2818 are in unnamed module of loader net.fabricmc.loader.impl.launch.knot.KnotClassLoader @4520ebad)
    at net.minecraft.class_1937.method_8497(class_1937.java:181)
    at net.minecraft.class_1937.method_8500(class_1937.java:176)
    at net.minecraft.class_1937.method_8316(class_1937.java:407)
    at net.minecraft.class_1948.method_8660(class_1948.java:449)
    at net.minecraft.class_1948.method_24934(class_1948.java:338)
    at net.minecraft.class_1948.method_24930(class_1948.java:274)
    at net.minecraft.class_1948.method_8663(class_1948.java:211)
    at net.minecraft.class_1948.redirect$zgd000$spawnMultipleTimes(class_1948.java:1832)
    at net.minecraft.class_1948.method_27821(class_1948.java:199)
    at net.minecraft.class_3215.method_14161(class_3215.java:375)
    at net.minecraft.class_3215.method_12127(class_3215.java:322)
    at net.minecraft.class_3218.method_18765(class_3218.java:311)
    at net.minecraft.server.MinecraftServer.md4efe61$lambda$tickWorlds$0$5(MinecraftServer.java:7826)
    at wearblackallday.dimthread.DimThread.swapThreadsAndRun(DimThread.java:34)
    at net.minecraft.server.MinecraftServer.md4efe61$lambda$tickWorlds$1$4(MinecraftServer.java:7824)
    at wearblackallday.util.ThreadPool.lambda$execute$1(ThreadPool.java:49)
    at wearblackallday.util.ThreadPool.lambda$execute$0(ThreadPool.java:43)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:833)

So I believe redirectBlockStateTick here is just a coincidence.

CaveNightingale commented 2 years ago

Been looking into this casting to WorldChunk thing a bit more: in my cast I believe it has to do with using ServerWorld#setChunkForced, though I guess other seemingly OK ways can cause the error too.

So World#getChunk(int i, int j) always returns a WorldChunk. To do this, it just calls this.getChunk(i, j, ChunkStatus.FULL) (which returns a Chunk) and then just blindly downcasts it to WorldChunk. Sometimes it doesn't return a WorldChunk but a ReadOnlyChunk, and that's the error that's crashing the server.

Following this trail, World#getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) calls this.getChunkManager().getChunk(chunkX, chunkZ, leastStatus, create), which takes us to the ServerChunkManager#getChunk method.

In there it does a thread check: if (Thread.currentThread() != this.serverThread), and I guess this will be false a lot when using DimensionalThreading.

Though the only thing it then does is to force getting the chunk on the main thread and blocking until it has done so, so still not 100% sure what's actually causing the wrong chunk type being returned.

I think this make no sense, because DimThread has ServerChunkManagerMixin which redirected the thread::currentThread() as well as made the serverThread mutable.