Engine-Room / Flywheel

A modern engine for modded Minecraft.
MIT License
205 stars 52 forks source link

[1.20.1] Issue when creating "fake" level off thread #227

Closed CreativeMD closed 5 months ago

CreativeMD commented 5 months ago

Describe the Bug

Hey there, I'm the author of LittleTiles. Problem is that I create a level for an animation preview off thread (to avoid a freeze). Unfortunately this causes a crash with flywheel needing an open gl context:

FATAL ERROR in native method: Thread[ForkJoinPool.commonPool-worker-38,5,main]: No context is current or a function that is not available in the current context was called. The JVM will abort execution.
--
873 | at org.lwjgl.opengl.GL15C.nglDeleteBuffers(org.lwjgl.opengl@3.3.1 7/Native Method)
874 | - parking to wait for  <0x0000000704d7ac40> (a java.util.concurrent.ForkJoinPool)
875 | at org.lwjgl.opengl.GL15C.glDeleteBuffers(org.lwjgl.opengl@3.3.1 7/GL15C.java:142)
876 | at org.lwjgl.opengl.GL15.glDeleteBuffers(org.lwjgl.opengl@3.3.1 7/GL15.java:160)
877 | at com.jozufozu.flywheel.backend.gl.buffer.GlBuffer.deleteInternal(flywheel@0.6.10-7/GlBuffer.java:102)
878 | at com.jozufozu.flywheel.backend.gl.GlObject.delete(flywheel@0.6.10-7/GlObject.java:38)
879 | at com.jozufozu.flywheel.backend.model.IndexedModel.delete(flywheel@0.6.10-7/IndexedModel.java:101)
880 | at com.jozufozu.flywheel.backend.model.ArrayModelRenderer.delete(flywheel@0.6.10-7/ArrayModelRenderer.java:52)
881 | at com.simibubi.create.content.contraptions.render.FlwContraption.invalidate(create@0.5.1.f/FlwContraption.java:125)
882 | at com.simibubi.create.content.contraptions.render.ContraptionRenderingWorld.delete(create@0.5.1.f/ContraptionRenderingWorld.java:104)
883 | at com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher$$Lambda$11267/0x000000080208ec88.accept(create@0.5.1.f/Unknown Source)
884 | at java.util.HashMap$Values.forEach(java.base@17.0.1/HashMap.java:1065)
885 | at com.jozufozu.flywheel.util.WorldAttached.empty(flywheel@0.6.10-7/WorldAttached.java:97)
886 | at com.simibubi.create.content.contraptions.render.ContraptionRenderDispatcher.reset(create@0.5.1.f/ContraptionRenderDispatcher.java:204)
887 | at com.simibubi.create.CreateClient.invalidateRenderers(create@0.5.1.f/CreateClient.java:95)
888 | at com.simibubi.create.foundation.events.ClientEvents.onLoadWorld(create@0.5.1.f/ClientEvents.java:190)
889 | at com.simibubi.create.foundation.events.__ClientEvents_onLoadWorld_Load.invoke(create@0.5.1.f/.dynamic)
890 | at net.minecraftforge.eventbus.ASMEventHandler.invoke(net.minecraftforge.eventbus/ASMEventHandler.java:73)
891 | at net.minecraftforge.eventbus.EventBus$$Lambda$4668/0x0000000801824628.invoke(net.minecraftforge.eventbus/Unknown Source)
892 | at net.minecraftforge.eventbus.EventBus.post(net.minecraftforge.eventbus/EventBus.java:315)
893 | at net.minecraftforge.eventbus.EventBus.post(net.minecraftforge.eventbus/EventBus.java:296)
894 | at net.minecraft.client.multiplayer.ClientLevel.<init>(minecraft@1.20.1/ClientLevel.java:182)
895 | at team.creative.littletiles.client.level.little.LittleClientLevel.<init>(littletiles@1.6.0-pre089/LittleClientLevel.java:69)
896 | at team.creative.littletiles.client.level.little.FakeClientLevel.<init>(littletiles@1.6.0-pre089/FakeClientLevel.java:41)

Not sure how to get around this issue. I would like to create this level off thread because it can take some time to set it up the animation, but I could also get around that (at least for the creation of the fake level). On the other hand I'm not sure why it requires the interaction with OpenGL in the first place. My guess it assumes it's a level like any other client level, which will cause issues even if it is executed on the main thread.

Let me know what you think.

Reproduction Steps

  1. Install CreativeCore, LittleTiles and Create
  2. Create a simple blueprint
  3. Open the blueprint (the issue can be seen in the logs)
  4. Save the blueprint (the game will crash due to the issue before)

Mod Version: 0.6.10-7

Jozufozu commented 5 months ago

Huh interesting issue. Seems that create's assumption that loading a new world should invalidate renderers isn't sound. Or at least create is being overzealous and invalidating resources for every world rather that just the one being loaded/unloaded.

This is a bug with create, though I'll leave this issue open for now.

Not sure what you could do for a workaround until create updates unfortunately. Perhaps a mixin into com.simibubi.create.foundation.events.ClientEvents.onLoadWorld?

Thanks for the report!

CreativeMD commented 5 months ago

Thanks for your quick and nice response. I reported the issue to Create, we shall see what they say. I could also execute this event on the main thread, which is not the best performance wise to at least a temporary fix. I will close this issue here, because as you pointed out it is an issue of create. Again thanks for your help!

Kneelawk commented 4 months ago

I've found that creating levels off thread just leads to issues. Minecraft levels synchronize to the thread they were created on, or at least they did in 1.16, and that breaks a lot of stuff if they're created off the main thread.