diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/loading_screen_freeze/GameDataMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/loading_screen_freeze/GameDataMixin.java new file mode 100644 index 00000000..b42ef336 --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/loading_screen_freeze/GameDataMixin.java @@ -0,0 +1,20 @@ +package org.embeddedt.modernfix.forge.mixin.bugfix.loading_screen_freeze; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.registries.GameData; +import org.embeddedt.modernfix.forge.util.AsyncLoadingScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(value = GameData.class, remap = false) +public class GameDataMixin { + @WrapOperation(method = "postRegisterEvents", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/ModLoader;postEventWrapContainerInModOrder(Lnet/minecraftforge/eventbus/api/Event;)V")) + private static void swapThreadAndPost(ModLoader loader, Event event, Operation operation) { + try(AsyncLoadingScreen ignored = new AsyncLoadingScreen()) { + operation.call(loader, event); + } + } +} diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/util/AsyncLoadingScreen.java b/forge/src/main/java/org/embeddedt/modernfix/forge/util/AsyncLoadingScreen.java new file mode 100644 index 00000000..bfa8f62d --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/util/AsyncLoadingScreen.java @@ -0,0 +1,53 @@ +package org.embeddedt.modernfix.forge.util; + +import net.minecraftforge.fml.loading.ImmediateWindowHandler; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.opengl.GL; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.LockSupport; + +public class AsyncLoadingScreen extends Thread implements AutoCloseable { + private final long theWindow; + private final AtomicBoolean keepRunning; + + private static int splashThreadNum = 1; + + public AsyncLoadingScreen() { + this.setName("ModernFix splash thread " + splashThreadNum++); + this.theWindow = GLFW.glfwGetCurrentContext(); + if(this.theWindow == 0) + throw new IllegalStateException("No context found but async loading screen was requested"); + this.keepRunning = new AtomicBoolean(true); + this.start(); + } + + @Override + public synchronized void start() { + GLFW.glfwMakeContextCurrent(0); + super.start(); + } + + @Override + public void run() { + GLFW.glfwMakeContextCurrent(theWindow); + GL.createCapabilities(); // seems to be needed, otherwise we get a "function not valid for context" error + while(keepRunning.get()) { + LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(50)); + ImmediateWindowHandler.renderTick(); + } + GLFW.glfwMakeContextCurrent(0); + } + + @Override + public void close() { + keepRunning.set(false); + try { + this.join(); + } catch(InterruptedException e) { + Thread.currentThread().interrupt(); + } + GLFW.glfwMakeContextCurrent(theWindow); + } +}