Skip to content

Commit

Permalink
Merge branch 'main' into StartupConfigs
Browse files Browse the repository at this point in the history
  • Loading branch information
TelepathicGrunt authored Jun 2, 2024
2 parents 3e27125 + 69b5811 commit fb13c55
Show file tree
Hide file tree
Showing 28 changed files with 751 additions and 201 deletions.
2 changes: 1 addition & 1 deletion loader/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies {
api "net.neoforged:JarJarSelector:${jarjar_version}"
api "net.neoforged:JarJarMetadata:${jarjar_version}"
api("net.neoforged:bus:${eventbus_version}")
implementation("net.neoforged:JarJarFileSystems:$jarjar_version")

implementation("net.sf.jopt-simple:jopt-simple:${jopt_simple_version}")
implementation("cpw.mods:securejarhandler:${securejarhandler_version}")
Expand All @@ -44,7 +45,6 @@ dependencies {
testCompileOnly("org.jetbrains:annotations:${jetbrains_annotations_version}")
testRuntimeOnly("cpw.mods:bootstraplauncher:${bootstraplauncher_version}")
testRuntimeOnly("org.apache.logging.log4j:log4j-core:$log4j_version")
testRuntimeOnly("net.neoforged:JarJarFileSystems:$jarjar_version")
testImplementation("org.junit.jupiter:junit-jupiter-api:$jupiter_version")
testImplementation("org.junit.jupiter:junit-jupiter-params:$jupiter_version")
testImplementation("org.mockito:mockito-junit-jupiter:$mockito_version")
Expand Down
9 changes: 8 additions & 1 deletion loader/src/main/java/net/neoforged/fml/ModLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.VisibleForTesting;

/**
* Contains the logic to load mods, i.e. turn the {@link LoadingModList} into the {@link ModList},
Expand Down Expand Up @@ -91,7 +92,6 @@ private static String computeModLauncherServiceList() {
*/
public static void gatherAndInitializeMods(final Executor syncExecutor, final Executor parallelExecutor, final Runnable periodicTask) {
var loadingModList = FMLLoader.getLoadingModList();
loadingIssues.clear();
loadingIssues.addAll(loadingModList.getModLoadingIssues());

ForgeFeature.registerFeature("javaVersion", ForgeFeature.VersionFeatureTest.forVersionString(IModInfo.DependencySide.BOTH, System.getProperty("java.version")));
Expand Down Expand Up @@ -410,6 +410,13 @@ public static List<ModLoadingIssue> getLoadingIssues() {
return List.copyOf(loadingIssues);
}

@VisibleForTesting
@ApiStatus.Internal
public static void clearLoadingIssues() {
LOGGER.info("Clearing {} loading issues", loadingIssues.size());
loadingIssues.clear();
}

@ApiStatus.Internal
public static void addLoadingIssue(ModLoadingIssue issue) {
loadingIssues.add(issue);
Expand Down
35 changes: 32 additions & 3 deletions loader/src/main/java/net/neoforged/fml/ModLoadingException.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
package net.neoforged.fml;

import java.util.List;
import java.util.stream.Collectors;
import net.neoforged.fml.i18n.FMLTranslations;

public class ModLoadingException extends RuntimeException {
private final List<ModLoadingIssue> issues;
Expand All @@ -25,7 +25,36 @@ public List<ModLoadingIssue> getIssues() {

@Override
public String getMessage() {
return "Loading errors encountered: " + this.issues.stream().map(ModLoadingIssue::translationKey)
.collect(Collectors.joining(",\n\t", "[\n\t", "\n]"));
var result = new StringBuilder();
var errors = this.issues.stream().filter(i -> i.severity() == ModLoadingIssue.Severity.ERROR).toList();
if (!errors.isEmpty()) {
result.append("Loading errors encountered:\n");
for (var error : errors) {
appendIssue(error, result);
}
}
var warnings = this.issues.stream().filter(i -> i.severity() == ModLoadingIssue.Severity.WARNING).toList();
if (!warnings.isEmpty()) {
result.append("Loading warnings encountered:\n");
for (var warning : warnings) {
appendIssue(warning, result);
}
}
return result.toString();
}

private void appendIssue(ModLoadingIssue issue, StringBuilder result) {
String translation;
try {
translation = FMLTranslations.stripControlCodes(FMLTranslations.translateIssueEnglish(issue));
} catch (Exception e) {
// Fall back to *something* readable in case the translation fails
translation = issue.toString();
}

// Poor mans indentation
translation = translation.replace("\n", "\n\t ");

result.append("\t- ").append(translation).append("\n");
}
}
22 changes: 17 additions & 5 deletions loader/src/main/java/net/neoforged/fml/i18n/FMLTranslations.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,26 @@ public static String parseFormat(String format, final Object... args) {
return extendedMessageFormat.format(args);
}

public static String translateIssueEnglish(ModLoadingIssue issue) {
var args = getTranslationArgs(issue);
return parseEnglishMessage(issue.translationKey(), args);
}

public static String translateIssue(ModLoadingIssue issue) {
var args = getTranslationArgs(issue);
return parseMessage(issue.translationKey(), args);
}

private static Object[] getTranslationArgs(ModLoadingIssue issue) {
var args = new ArrayList<>(3 + issue.translationArgs().size());

var modInfo = issue.affectedMod();
if (modInfo == null && issue.affectedModFile() != null) {
if (!issue.affectedModFile().getModInfos().isEmpty()) {
modInfo = issue.affectedModFile().getModInfos().getFirst();
var file = issue.affectedModFile();
while (modInfo == null && file != null) {
if (!file.getModInfos().isEmpty()) {
modInfo = file.getModInfos().getFirst();
}
file = file.getDiscoveryAttributes().parent();
}
args.add(modInfo);
args.add(null); // Previously mod-loading phase
Expand All @@ -144,13 +156,13 @@ public static String translateIssue(ModLoadingIssue issue) {

args.replaceAll(FMLTranslations::formatArg);

return parseMessage(issue.translationKey(), args.toArray(Object[]::new));
return args.toArray(Object[]::new);
}

private static Object formatArg(Object arg) {
if (arg instanceof Path path) {
var gameDir = FMLLoader.getGamePath();
if (path.startsWith(gameDir)) {
if (gameDir != null && path.startsWith(gameDir)) {
return gameDir.relativize(path).toString();
} else {
return path.toString();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.fml.loading;

import cpw.mods.modlauncher.api.ITransformer;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.util.List;
import net.neoforged.coremod.CoreModScriptingEngine;
import net.neoforged.coremod.ICoreModScriptSource;
import net.neoforged.fml.loading.moddiscovery.CoreModFile;
import net.neoforged.fml.loading.moddiscovery.ModFileInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Uses the coremod scripting engine from https://github.com/neoforged/CoreMods
* to load JS-based coremods. Avoids loading any of the classes unless a mod
* contains a JS-based coremod.
*/
class CoreModScriptLoader {
private static final Logger LOGGER = LoggerFactory.getLogger(CoreModScriptLoader.class);

private CoreModScriptLoader() {}

/**
* Enumerate script-based coremods.
*/
public static List<ITransformer<?>> loadCoreModScripts(List<ModFileInfo> modFileInfos) {
CoreModScriptingEngine engine;
try {
engine = new CoreModScriptingEngine();
} catch (NoClassDefFoundError e) {
// Fail for all mods that require a coremod scripting engine to be present
throw new IllegalStateException("Could not find the coremod script-engine, but the following mods require it: " + modFileInfos, e);
}

LOGGER.debug(LogMarkers.CORE, "Loading coremod scripts");
for (var modFile : modFileInfos) {
for (var coreMod : modFile.getFile().getCoreMods()) {
engine.loadCoreMod(new ScriptSourceAdapter(coreMod));
}
}

return engine.initializeCoreMods();
}

private record ScriptSourceAdapter(CoreModFile coreMod) implements ICoreModScriptSource {
@Override
public Reader readCoreMod() throws IOException {
return Files.newBufferedReader(coreMod.path());
}

@Override
public String getDebugSource() {
return coreMod.path().toString();
}

@Override
public Reader getAdditionalFile(final String fileName) throws IOException {
return Files.newBufferedReader(coreMod.file().findResource(fileName));
}

@Override
public String getOwnerId() {
return this.coreMod.file().getModInfos().getFirst().getModId();
}

@Override
public String toString() {
return "{Name: " + coreMod.name() + ", Owner: " + getOwnerId() + " @ " + getDebugSource() + "}";
}
}
}
9 changes: 0 additions & 9 deletions loader/src/main/java/net/neoforged/fml/loading/FMLLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import net.neoforged.accesstransformer.api.AccessTransformerEngine;
import net.neoforged.accesstransformer.ml.AccessTransformerService;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.coremod.CoreModScriptingEngine;
import net.neoforged.fml.common.asm.RuntimeDistCleaner;
import net.neoforged.fml.loading.mixin.DeferredMixinConfigRegistration;
import net.neoforged.fml.loading.moddiscovery.ModDiscoverer;
Expand All @@ -38,7 +37,6 @@
public class FMLLoader {
private static final Logger LOGGER = LogUtils.getLogger();
private static AccessTransformerEngine accessTransformer;
private static CoreModScriptingEngine coreModEngine;
private static LanguageProviderLoader languageProviderLoader;
private static Dist dist;
private static LoadingModList loadingModList;
Expand Down Expand Up @@ -90,9 +88,6 @@ static void onInitialLoad(IEnvironment environment) throws IncompatibleEnvironme
});
LOGGER.debug(LogMarkers.CORE, "Found Runtime Dist Cleaner");

coreModEngine = new CoreModScriptingEngine();
LOGGER.debug(LogMarkers.CORE, "FML found CoreMods version : {}", coreModEngine.getClass().getPackage().getImplementationVersion());

try {
Class.forName("com.electronwill.nightconfig.core.Config", false, environment.getClass().getClassLoader());
Class.forName("com.electronwill.nightconfig.toml.TomlFormat", false, environment.getClass().getClassLoader());
Expand Down Expand Up @@ -147,10 +142,6 @@ public static List<ITransformationService.Resource> completeScan(ILaunchContext
return List.of(modValidator.getModResources());
}

static CoreModScriptingEngine getCoreModEngine() {
return coreModEngine;
}

public static LanguageProviderLoader getLanguageLoadingProvider() {
return languageProviderLoader;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
package net.neoforged.fml.loading;

import static net.neoforged.fml.loading.LogMarkers.CORE;
import static net.neoforged.fml.loading.LogMarkers.LOADING;

import com.mojang.logging.LogUtils;
import cpw.mods.modlauncher.api.IEnvironment;
import cpw.mods.modlauncher.api.IModuleLayerManager;
import cpw.mods.modlauncher.api.ITransformationService;
import cpw.mods.modlauncher.api.ITransformer;
import cpw.mods.modlauncher.api.IncompatibleEnvironmentException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
Expand All @@ -21,8 +23,13 @@
import java.util.function.Supplier;
import joptsimple.ArgumentAcceptingOptionSpec;
import joptsimple.OptionSpecBuilder;
import net.neoforged.fml.ModLoader;
import net.neoforged.fml.ModLoadingIssue;
import net.neoforged.fml.util.ServiceLoaderUtil;
import net.neoforged.neoforgespi.Environment;
import net.neoforged.neoforgespi.ILaunchContext;
import net.neoforged.neoforgespi.coremod.ICoreMod;
import org.jetbrains.annotations.VisibleForTesting;
import org.slf4j.Logger;

public class FMLServiceProvider implements ITransformationService {
Expand All @@ -40,7 +47,8 @@ public class FMLServiceProvider implements ITransformationService {
private List<String> mavenRootsArgumentList;
private List<String> mixinConfigsArgumentList;
private VersionInfo versionInfo;
private ILaunchContext launchContext;
@VisibleForTesting
ILaunchContext launchContext;

public FMLServiceProvider() {
final String markerselection = System.getProperty("forge.logging.markers", "");
Expand Down Expand Up @@ -115,7 +123,50 @@ public void argumentValues(OptionResult option) {

@Override
public List<? extends ITransformer<?>> transformers() {
LOGGER.debug(CORE, "Loading coremod transformers");
return FMLLoader.getCoreModEngine().initializeCoreMods();
LOGGER.debug(LOADING, "Loading coremod transformers");

var result = new ArrayList<>(loadCoreModScripts());

// Find all Java core mods
for (var coreMod : ServiceLoaderUtil.loadServices(launchContext, ICoreMod.class)) {
// Try to identify the mod-file this is from
var sourceFile = ServiceLoaderUtil.identifySourcePath(launchContext, coreMod);

try {
for (var transformer : coreMod.getTransformers()) {
LOGGER.debug(CORE, "Adding {} transformer from core-mod {} in {}", transformer.targets(), coreMod, sourceFile);
result.add(transformer);
}
} catch (Exception e) {
// Throwing here would cause the game to immediately crash without a proper error screen,
// since this method is called by ModLauncher directly.
ModLoader.addLoadingIssue(
ModLoadingIssue.error("fml.modloading.coremod_error", coreMod.getClass().getName(), sourceFile).withCause(e));
}
}

return result;
}

private List<ITransformer<?>> loadCoreModScripts() {
var filesWithCoreModScripts = LoadingModList.get().getModFiles()
.stream()
.filter(mf -> !mf.getFile().getCoreMods().isEmpty())
.toList();

if (filesWithCoreModScripts.isEmpty()) {
// Don't even bother starting the scripting engine if no mod contains scripting core mods
LOGGER.debug(LogMarkers.CORE, "Not loading coremod script-engine since no mod requested it");
return List.of();
}

LOGGER.info(LogMarkers.CORE, "Loading coremod script-engine for {}", filesWithCoreModScripts);
try {
return CoreModScriptLoader.loadCoreModScripts(filesWithCoreModScripts);
} catch (NoClassDefFoundError e) {
var message = "Could not find the coremod script-engine, but the following mods require it: " + filesWithCoreModScripts;
ImmediateWindowHandler.crash(message);
throw new IllegalStateException(message, e);
}
}
}
Loading

0 comments on commit fb13c55

Please sign in to comment.