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()));
|
final Map<String, IModInfo> modInfoMap = modFile.getModFileInfo().getMods().stream().collect(Collectors.toMap(IModInfo::getModId, Function.identity()));
|
||||||
|
|
||||||
LOGGER.debug(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader());
|
LOGGER.debug(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader());
|
||||||
final List<ModContainer> containers = modFile.getScanResult().getTargets().entrySet().stream().
|
final List<ModContainer> containers = modFile.getScanResult().getTargets()
|
||||||
map(e -> buildModContainerFromTOML(modFile, modClassLoader, modInfoMap, e))
|
.entrySet()
|
||||||
|
.stream()
|
||||||
|
.map(e -> buildModContainerFromTOML(modFile, modClassLoader, modInfoMap, e))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
if (containers.size() != modInfoMap.size()) {
|
if (containers.size() != modInfoMap.size()) {
|
||||||
|
@ -279,7 +281,8 @@ public class ModLoader
|
||||||
modInfoMap.size(), modInfoMap.values().stream().map(IModInfo::getModId).sorted().collect(Collectors.toList()));
|
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()));
|
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) {
|
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));
|
orElseThrow(()->new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingmetadata", null, modId));
|
||||||
return languageLoader.loadMod(info, modClassLoader, modFile.getScanResult());
|
return languageLoader.loadMod(info, modClassLoader, modFile.getScanResult());
|
||||||
} catch (ModLoadingException mle) {
|
} 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);
|
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 () {
|
public static boolean isDataGenRunning () {
|
||||||
return runningDataGen;
|
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;
|
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.ILifecycleEvent;
|
||||||
import net.minecraftforge.forgespi.language.IModLanguageProvider;
|
import net.minecraftforge.forgespi.language.IModLanguageProvider;
|
||||||
import net.minecraftforge.forgespi.language.IModInfo;
|
import net.minecraftforge.forgespi.language.IModInfo;
|
||||||
|
@ -39,7 +43,6 @@ import static net.minecraftforge.fml.Logging.*;
|
||||||
|
|
||||||
public class FMLJavaModLanguageProvider implements IModLanguageProvider
|
public class FMLJavaModLanguageProvider implements IModLanguageProvider
|
||||||
{
|
{
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger();
|
private static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
|
||||||
private static class FMLModTarget implements IModLanguageProvider.IModLanguageLoader {
|
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);
|
final Constructor<?> constructor = fmlContainer.getConstructor(IModInfo.class, String.class, ClassLoader.class, ModFileScanData.class);
|
||||||
return (T)constructor.newInstance(info, className, modClassLoader, modFileScanResults);
|
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);
|
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