diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/concurrency/ReloadableResourceManagerMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/concurrency/ReloadableResourceManagerMixin.java new file mode 100644 index 00000000..e056c64f --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/concurrency/ReloadableResourceManagerMixin.java @@ -0,0 +1,49 @@ +package org.embeddedt.modernfix.common.mixin.bugfix.concurrency; + +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import net.minecraft.client.Minecraft; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.resources.PreparableReloadListener; +import net.minecraft.server.packs.resources.ReloadableResourceManager; +import net.minecraftforge.fml.ModContainer; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.ModLoadingStage; +import net.minecraftforge.registries.ForgeRegistries; +import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.forge.init.ModernFixForge; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(ReloadableResourceManager.class) +@ClientOnlyMixin +public abstract class ReloadableResourceManagerMixin { + @Shadow + @Final + private PackType type; + + @Shadow + public abstract void registerReloadListener(PreparableReloadListener listener); + + /** + * @author embeddedt + * @reason complain loudly when reload listeners are being registered too late in a way that would cause + * concurrency issues, and prevent them from crashing the game + */ + @WrapMethod(method = "registerReloadListener") + private void checkCallingThread(PreparableReloadListener listener, Operation original) { + if (ModernFixForge.registryEventsFired && this.type == PackType.CLIENT_RESOURCES + && (Object)this == Minecraft.getInstance().getResourceManager() + && !Minecraft.getInstance().isSameThread()) { + ModernFix.LOGGER.error("A mod is calling registerReloadListener at the wrong time. This will cause random concurrency crashes when ModernFix is not installed. Please report this to them. If you are a modder, refer to https://github.com/embeddedt/ModernFix/wiki/registerReloadListener-called-on-wrong-thread for more information.", new Exception("registerReloadListener called on wrong thread")); + // Defer the call onto the main client thread. There is a decent chance the mod's listener will be + // ignored in this case, but it is more predictable than allowing them to randomly crash the game. + Minecraft.getInstance().tell(() -> this.registerReloadListener(listener)); + return; + } + + original.call(listener); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/core/GameDataMixin.java b/src/main/java/org/embeddedt/modernfix/common/mixin/core/GameDataMixin.java new file mode 100644 index 00000000..3756e72b --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/core/GameDataMixin.java @@ -0,0 +1,16 @@ +package org.embeddedt.modernfix.common.mixin.core; + +import net.minecraftforge.registries.GameData; +import org.embeddedt.modernfix.forge.init.ModernFixForge; +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.callback.CallbackInfo; + +@Mixin(value = GameData.class, remap = false) +public class GameDataMixin { + @Inject(method = "postRegisterEvents", at = @At("RETURN")) + private static void markPosted(CallbackInfo ci) { + ModernFixForge.registryEventsFired = true; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java b/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java index dd2cd228..a95cbdd2 100644 --- a/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java +++ b/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java @@ -38,6 +38,7 @@ import java.util.List; public class ModernFixForge { private static ModernFix commonMod; public static boolean launchDone = false; + public static boolean registryEventsFired = false; public ModernFixForge() { commonMod = new ModernFix();