package io.gitlab.jfronny.modsmod; import net.fabricmc.loader.FabricLoader; import net.fabricmc.loader.ModContainer; import net.fabricmc.loader.discovery.ModCandidate; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; public class FabricLoaderInterface { public static final Logger logger = LogManager.getLogger(ModsMod.MOD_ID); private static final Method addModMethod; private static final Field modsField; static { try { addModMethod = FabricLoader.class.getDeclaredMethod("addMod", ModCandidate.class); addModMethod.setAccessible(true); modsField = FabricLoader.class.getDeclaredField("mods"); modsField.setAccessible(true); } catch (NoSuchMethodException | NoSuchFieldException e) { logger.error("Failed to get reference to fabric-loader internals. The fabric-loader version may be incompatible with patchwork-runtime.", e); throw new IllegalStateException(e); } } public static void synchronize(FabricLoader fabricLoader) { try { modsField.set(fabricLoader, new IteratorCallbackList((List)modsField.get(fabricLoader), (s) -> { try { modsField.set(fabricLoader, s); } catch (IllegalAccessException e) { logger.error("Failed to reset mods field", e); e.printStackTrace(); } })); } catch (IllegalAccessException e) { logger.error("Failed to make mods list synchronized.", e); throw new IllegalStateException(e); } } public static void addMod(FabricLoader fabricLoader, ModCandidate modCandidate) { try { addModMethod.invoke(fabricLoader, modCandidate); } catch (IllegalAccessException | InvocationTargetException e) { logger.error("Failed to inject mod into fabric-loader.", e); throw new IllegalStateException(e); } } }