ModsMod/src/main/java/io/gitlab/jfronny/modsmod/FabricLoaderInterface.java

72 lines
3.1 KiB
Java

package io.gitlab.jfronny.modsmod;
import io.gitlab.jfronny.gson.reflect.TypeToken;
import io.gitlab.jfronny.modsmod.util.IteratorCallbackList;
import net.fabricmc.loader.impl.FabricLoaderImpl;
import net.fabricmc.loader.impl.ModContainerImpl;
import net.fabricmc.loader.impl.discovery.ModCandidate;
import net.fabricmc.loader.impl.metadata.LoaderModMetadata;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
public class FabricLoaderInterface {
private static final Method ADD_MOD_METHOD;
private static final Method CREATE_PLAIN_METHOD;
private static final Field MODS_FIELD;
static {
try {
ADD_MOD_METHOD = FabricLoaderImpl.class.getDeclaredMethod("addMod", ModCandidate.class);
ADD_MOD_METHOD.setAccessible(true);
MODS_FIELD = FabricLoaderImpl.class.getDeclaredField("mods");
MODS_FIELD.setAccessible(true);
CREATE_PLAIN_METHOD = ModCandidate.class.getDeclaredMethod("createPlain", new TypeToken<List<Path>>(){}.getRawType(), LoaderModMetadata.class, boolean.class, new TypeToken<Collection<ModCandidate>>(){}.getRawType());
CREATE_PLAIN_METHOD.setAccessible(true);
} catch (NoSuchMethodException | NoSuchFieldException e) {
MMSafeLog.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(FabricLoaderImpl fabricLoader) {
try {
MODS_FIELD.set(fabricLoader, new IteratorCallbackList<>((List<ModContainerImpl>) MODS_FIELD.get(fabricLoader), modContainers -> {
try {
MODS_FIELD.set(fabricLoader, modContainers);
} catch (IllegalAccessException e) {
MMSafeLog.error("Failed to reset mods field", e);
e.printStackTrace();
}
}, ModsMod::loadMods));
} catch (IllegalAccessException e) {
MMSafeLog.error("Failed to make mods list synchronized.", e);
throw new IllegalStateException(e);
}
}
public static void addMod(FabricLoaderImpl fabricLoader, ModCandidate modCandidate) {
try {
ADD_MOD_METHOD.invoke(fabricLoader, modCandidate);
} catch (IllegalAccessException | InvocationTargetException e) {
MMSafeLog.error("Failed to inject mod into fabric-loader.", e);
throw new IllegalStateException(e);
}
}
public static ModCandidate createPlain(Path path, LoaderModMetadata metadata, boolean requiresRemap, Collection<ModCandidate> nestedMods) {
try {
return (ModCandidate) CREATE_PLAIN_METHOD.invoke(null, List.of(path), metadata, requiresRemap, nestedMods);
} catch (IllegalAccessException | InvocationTargetException e) {
MMSafeLog.error("Failed to create plain mod container", e);
throw new IllegalStateException(e);
}
}
}