diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/feature/registry_event_progress/GameDataMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/feature/registry_event_progress/GameDataMixin.java new file mode 100644 index 00000000..4b0b568e --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/feature/registry_event_progress/GameDataMixin.java @@ -0,0 +1,52 @@ +package org.embeddedt.modernfix.forge.mixin.feature.registry_event_progress; + +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.StartupMessageManager; +import net.minecraftforge.fml.event.IModBusEvent; +import net.minecraftforge.registries.GameData; +import net.minecraftforge.registries.RegisterEvent; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.forge.util.AsyncLoadingScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = GameData.class, remap = false) +@ClientOnlyMixin +public class GameDataMixin { + + private static AsyncLoadingScreen mfix$asyncScreen; + + @Inject(method = "postRegisterEvents", at = @At(value = "INVOKE", target = "Ljava/util/Set;iterator()Ljava/util/Iterator;", ordinal = 0)) + private static void createAsyncScreen(CallbackInfo ci) { + mfix$asyncScreen = new AsyncLoadingScreen(); + } + + @Inject(method = "postRegisterEvents", at = @At(value = "INVOKE", target = "Ljava/lang/RuntimeException;getSuppressed()[Ljava/lang/Throwable;", ordinal = 0)) + private static void closeAsyncScreen(CallbackInfo ci) { + mfix$asyncScreen.close(); + mfix$asyncScreen = null; + } + + @Redirect(method = "postRegisterEvents", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/ModLoader;postEventWrapContainerInModOrder(Lnet/minecraftforge/eventbus/api/Event;)V")) + private static void swapThreadAndPost(ModLoader loader, T event) { + RegisterEvent registryEvent = (RegisterEvent)event; + var pb = StartupMessageManager.addProgressBar(registryEvent.getRegistryKey().location().toString(), ModList.get().size()); + try { + loader.postEventWithWrapInModOrder(event, (mc, e) -> { + ModLoadingContext.get().setActiveContainer(mc); + pb.label(pb.name() + " - " + mc.getModInfo().getDisplayName()); + pb.increment(); + }, (mc, e) -> { + ModLoadingContext.get().setActiveContainer(null); + }); + } finally { + pb.complete(); + } + } +} 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..3cb765b8 --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/util/AsyncLoadingScreen.java @@ -0,0 +1,58 @@ +package org.embeddedt.modernfix.forge.util; + +import net.minecraftforge.fml.loading.ImmediateWindowHandler; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.opengl.GL; +import org.lwjgl.opengl.GLCapabilities; + +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; + + private static GLCapabilities caps; + + public AsyncLoadingScreen() { + this.setName("ModernFix splash thread " + splashThreadNum++); + this.theWindow = GLFW.glfwGetCurrentContext(); + if(caps == null) + caps = GL.createCapabilities(); + 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.setCapabilities(caps); + 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); + } +}