From 41b71c5e59d4539e4421ff3e43150bb7efde06c6 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 19 Jun 2023 21:49:45 -0400 Subject: [PATCH] Attempt fix for Engineer's Decor and related crashes --- .../modernfix/forge/config/ConfigFixer.java | 53 +++++++++++++++++++ .../modernfix/forge/init/ModernFixForge.java | 2 + 2 files changed, 55 insertions(+) create mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/config/ConfigFixer.java diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/config/ConfigFixer.java b/forge/src/main/java/org/embeddedt/modernfix/forge/config/ConfigFixer.java new file mode 100644 index 00000000..48150a34 --- /dev/null +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/config/ConfigFixer.java @@ -0,0 +1,53 @@ +package org.embeddedt.modernfix.forge.config; + +import net.minecraftforge.fml.ModContainer; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.config.ModConfig; +import org.embeddedt.modernfix.ModernFix; + +import java.util.Optional; +import java.util.function.Consumer; + +public class ConfigFixer { + /** + * To prevent mods from crashing if their ModConfigEvent is invoked by Night Config's watch thread and Forge + * at the same time, wrap their config handler so that it only executes the event in serial for that mod. + * + * Should have no noticeable performance impact as config handlers are virtually instant. + */ + public static void replaceConfigHandlers() { + ModList.get().forEachModContainer((id, container) -> { + try { + Optional> configOpt = ObfuscationReflectionHelper.getPrivateValue(ModContainer.class, container, "configHandler"); + if(configOpt.isPresent()) { + ObfuscationReflectionHelper.setPrivateValue(ModContainer.class, container, Optional.of(new LockingConfigHandler(id, configOpt.get())), "configHandler"); + } + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Error replacing config handler", e); + } + }); + } + + private static class LockingConfigHandler implements Consumer { + private final Consumer actualHandler; + private final String modId; + + LockingConfigHandler(String id, Consumer actualHandler) { + this.modId = id; + this.actualHandler = actualHandler; + } + + @Override + public void accept(ModConfig.ModConfigEvent modConfigEvent) { + synchronized (this) { + this.actualHandler.accept(modConfigEvent); + } + } + + @Override + public String toString() { + return "LockingConfigHandler{id=" + modId + "}"; + } + } +} diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java b/forge/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java index 570f5242..bb360b2c 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java @@ -25,6 +25,7 @@ import org.embeddedt.modernfix.forge.classloading.ClassLoadHack; import org.embeddedt.modernfix.forge.classloading.ModFileScanDataDeduplicator; import org.embeddedt.modernfix.forge.ModernFixConfig; import org.embeddedt.modernfix.entity.EntityDataIDSyncHandler; +import org.embeddedt.modernfix.forge.config.ConfigFixer; import org.embeddedt.modernfix.forge.packet.PacketHandler; import org.embeddedt.modernfix.forge.registry.ObjectHolderClearer; import org.embeddedt.modernfix.forge.util.KubeUtil; @@ -48,6 +49,7 @@ public class ModernFixForge { PacketHandler.register(); ModFileScanDataDeduplicator.deduplicate(); ClassLoadHack.loadModClasses(); + ConfigFixer.replaceConfigHandlers(); } @SubscribeEvent