Handle erroring during early mod construction phases, and actually report that into the error UI
by doing armslength exception handling and propagation. Signed-off-by: cpw <cpw+github@weeksfamily.ca>
This commit is contained in:
parent
160f3f88f9
commit
f78b943bdf
2 changed files with 45 additions and 8 deletions
|
@ -268,8 +268,10 @@ public class ModLoader
|
|||
final Map<String, IModInfo> modInfoMap = modFile.getModFileInfo().getMods().stream().collect(Collectors.toMap(IModInfo::getModId, Function.identity()));
|
||||
|
||||
LOGGER.debug(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader());
|
||||
final List<ModContainer> containers = modFile.getScanResult().getTargets().entrySet().stream().
|
||||
map(e -> buildModContainerFromTOML(modFile, modClassLoader, modInfoMap, e))
|
||||
final List<ModContainer> containers = modFile.getScanResult().getTargets()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(e -> buildModContainerFromTOML(modFile, modClassLoader, modInfoMap, e))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
if (containers.size() != modInfoMap.size()) {
|
||||
|
@ -279,7 +281,8 @@ public class ModLoader
|
|||
modInfoMap.size(), modInfoMap.values().stream().map(IModInfo::getModId).sorted().collect(Collectors.toList()));
|
||||
loadingExceptions.add(new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingclasses", null, modFile.getFilePath()));
|
||||
}
|
||||
return containers;
|
||||
// remove errored mod containers
|
||||
return containers.stream().filter(obj -> !(obj instanceof ErroredModContainer)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ModContainer buildModContainerFromTOML(final ModFile modFile, final TransformingClassLoader modClassLoader, final Map<String, IModInfo> modInfoMap, final Map.Entry<String, ? extends IModLanguageProvider.IModLanguageLoader> idToProviderEntry) {
|
||||
|
@ -291,9 +294,10 @@ public class ModLoader
|
|||
orElseThrow(()->new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingmetadata", null, modId));
|
||||
return languageLoader.loadMod(info, modClassLoader, modFile.getScanResult());
|
||||
} catch (ModLoadingException mle) {
|
||||
// exceptions are caught and added to the error list for later handling. Null is returned here.
|
||||
// exceptions are caught and added to the error list for later handling
|
||||
loadingExceptions.add(mle);
|
||||
return null;
|
||||
// return an errored container instance here, because we tried and failed building a container.
|
||||
return new ErroredModContainer(mle);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,4 +340,20 @@ public class ModLoader
|
|||
public static boolean isDataGenRunning () {
|
||||
return runningDataGen;
|
||||
}
|
||||
|
||||
static class ErroredModContainer extends ModContainer {
|
||||
public ErroredModContainer(final ModLoadingException mle) {
|
||||
super(mle.getModInfo());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(final Object mod) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getMod() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
|
||||
package net.minecraftforge.fml.javafmlmod;
|
||||
|
||||
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
|
||||
import net.minecraftforge.fml.ModLoadingException;
|
||||
import net.minecraftforge.fml.ModLoadingStage;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.forgespi.language.ILifecycleEvent;
|
||||
import net.minecraftforge.forgespi.language.IModLanguageProvider;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
|
@ -39,7 +43,6 @@ import static net.minecraftforge.fml.Logging.*;
|
|||
|
||||
public class FMLJavaModLanguageProvider implements IModLanguageProvider
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
private static class FMLModTarget implements IModLanguageProvider.IModLanguageLoader {
|
||||
|
@ -72,10 +75,24 @@ public class FMLJavaModLanguageProvider implements IModLanguageProvider
|
|||
final Constructor<?> constructor = fmlContainer.getConstructor(IModInfo.class, String.class, ClassLoader.class, ModFileScanData.class);
|
||||
return (T)constructor.newInstance(info, className, modClassLoader, modFileScanResults);
|
||||
}
|
||||
catch (NoSuchMethodException | ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e)
|
||||
// ALL exception handling has to be done through the classloader, because we're loaded in the wrong context, so any classes we just blind load will be in the wrong
|
||||
// class loading context. Funky but works.
|
||||
catch (InvocationTargetException e) {
|
||||
LOGGER.fatal(LOADING, "Failed to build mod", e);
|
||||
final Class<RuntimeException> mle = (Class<RuntimeException>)LamdbaExceptionUtils.uncheck(()->Class.forName("net.minecraftforge.fml.ModLoadingException", true, Thread.currentThread().getContextClassLoader()));
|
||||
if (mle.isInstance(e.getTargetException())) {
|
||||
throw mle.cast(e.getTargetException());
|
||||
} else {
|
||||
final Class<ModLoadingStage> mls = (Class<ModLoadingStage>) LamdbaExceptionUtils.uncheck(()->Class.forName("net.minecraftforge.fml.ModLoadingStage", true, Thread.currentThread().getContextClassLoader()));
|
||||
throw LamdbaExceptionUtils.uncheck(()->LamdbaExceptionUtils.uncheck(()->mle.getConstructor(IModInfo.class, mls, String.class, Throwable.class)).newInstance(info, Enum.valueOf(mls, "CONSTRUCT"), "fml.modloading.failedtoloadmodclass", e));
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException | ClassNotFoundException | InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
LOGGER.fatal(LOADING,"Unable to load FMLModContainer, wut?", e);
|
||||
throw new RuntimeException(e);
|
||||
final Class<RuntimeException> mle = (Class<RuntimeException>)LamdbaExceptionUtils.uncheck(()->Class.forName("net.minecraftforge.fml.ModLoadingException", true, Thread.currentThread().getContextClassLoader()));
|
||||
final Class<ModLoadingStage> mls = (Class<ModLoadingStage>) LamdbaExceptionUtils.uncheck(()->Class.forName("net.minecraftforge.fml.ModLoadingStage", true, Thread.currentThread().getContextClassLoader()));
|
||||
throw LamdbaExceptionUtils.uncheck(()->LamdbaExceptionUtils.uncheck(()->mle.getConstructor(IModInfo.class, mls, String.class, Throwable.class)).newInstance(info, Enum.valueOf(mls, "CONSTRUCT"), "fml.modloading.failedtoloadmodclass", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue