From 32dc3f0a94b2b40cf61cad307d2a397d3dbc5127 Mon Sep 17 00:00:00 2001 From: Matyrobbrt Date: Sat, 13 Jan 2024 17:38:41 +0200 Subject: [PATCH 1/2] Remove hard casts to `ModFile` and co --- .../main/java/net/neoforged/fml/ModList.java | 11 +-- .../java/net/neoforged/fml/ModLoader.java | 12 +-- .../net/neoforged/fml/loading/FMLLoader.java | 3 +- .../fml/loading/LanguageLoadingProvider.java | 3 +- .../neoforged/fml/loading/LoadingModList.java | 45 ++++----- .../net/neoforged/fml/loading/ModSorter.java | 23 ++--- .../fml/loading/UniqueModListBuilder.java | 36 ++++---- .../moddiscovery/BackgroundScanHandler.java | 18 ++-- .../loading/moddiscovery/ModDiscoverer.java | 11 +-- .../fml/loading/moddiscovery/ModFile.java | 92 +++++++++++-------- .../loading/moddiscovery/ModFileParser.java | 7 +- .../loading/moddiscovery/ModValidator.java | 54 +++++++---- spi/build.gradle | 3 +- .../neoforgespi/locating/IModFile.java | 44 +++++++-- .../locating/IModFileController.java | 39 ++++++++ 15 files changed, 249 insertions(+), 152 deletions(-) create mode 100644 spi/src/main/java/net/neoforged/neoforgespi/locating/IModFileController.java diff --git a/core/src/main/java/net/neoforged/fml/ModList.java b/core/src/main/java/net/neoforged/fml/ModList.java index e2d416fc5..ee95209fb 100644 --- a/core/src/main/java/net/neoforged/fml/ModList.java +++ b/core/src/main/java/net/neoforged/fml/ModList.java @@ -51,21 +51,20 @@ public class ModList private static ModList INSTANCE; private final List modFiles; private final List sortedList; - private final Map fileById; + private final Map fileById; private List mods; private Map indexedMods; private List modFileScanData; private List sortedContainers; - private ModList(final List modFiles, final List sortedList) + private ModList(final List modFiles, final List sortedList) { - this.modFiles = modFiles.stream().map(ModFile::getModFileInfo).map(ModFileInfo.class::cast).collect(Collectors.toList()); + this.modFiles = modFiles.stream().map(IModFile::getModFileInfo).toList(); this.sortedList = sortedList.stream(). map(ModInfo.class::cast). collect(Collectors.toList()); this.fileById = this.modFiles.stream().map(IModFileInfo::getMods).flatMap(Collection::stream). - map(ModInfo.class::cast). - collect(Collectors.toMap(ModInfo::getModId, ModInfo::getOwningFile)); + collect(Collectors.toMap(IModInfo::getModId, IModInfo::getOwningFile)); CrashReportCallables.registerCrashCallable("Mod List", this::crashReport); } @@ -85,7 +84,7 @@ private String crashReport() { return "\n"+applyForEachModFile(this::fileToLine).collect(Collectors.joining("\n\t\t", "\t\t", "")); } - public static ModList of(List modFiles, List sortedList) + public static ModList of(List modFiles, List sortedList) { INSTANCE = new ModList(modFiles, sortedList); return INSTANCE; diff --git a/core/src/main/java/net/neoforged/fml/ModLoader.java b/core/src/main/java/net/neoforged/fml/ModLoader.java index 176280e07..362f21626 100644 --- a/core/src/main/java/net/neoforged/fml/ModLoader.java +++ b/core/src/main/java/net/neoforged/fml/ModLoader.java @@ -19,6 +19,7 @@ import net.neoforged.fml.loading.moddiscovery.ModInfo; import net.neoforged.fml.loading.progress.ProgressMeter; import net.neoforged.fml.loading.progress.StartupNotificationManager; +import net.neoforged.neoforgespi.language.IModFileInfo; import net.neoforged.neoforgespi.language.IModInfo; import net.neoforged.neoforgespi.language.IModLanguageProvider; import net.neoforged.neoforgespi.locating.ForgeFeature; @@ -105,11 +106,6 @@ private ModLoader() .flatMap(ModLoadingWarning::fromEarlyException) .forEach(this.loadingWarnings::add); - FMLLoader.getLoadingModList().getModFiles().stream() - .filter(ModFileInfo::missingLicense) - .filter(modFileInfo -> modFileInfo.getMods().stream().noneMatch(thisModInfo -> this.loadingExceptions.stream().map(ModLoadingException::getModInfo).anyMatch(otherInfo -> otherInfo == thisModInfo))) //Ignore files where any other mod already encountered an error - .map(modFileInfo -> new ModLoadingException(null, ModLoadingStage.VALIDATE, "fml.modloading.missinglicense", null, modFileInfo.getFile())) - .forEach(this.loadingExceptions::add); this.stateManager = new ModStateManager(); CrashReportCallables.registerCrashCallable("ModLauncher", FMLLoader::getLauncherInfo); CrashReportCallables.registerCrashCallable("ModLauncher launch target", FMLLoader::launcherHandlerName); @@ -147,7 +143,7 @@ public void gatherAndInitializeMods(final ModWorkManager.DrivenExecutor syncExec ForgeFeature.registerFeature("openGLVersion", ForgeFeature.VersionFeatureTest.forVersionString(IModInfo.DependencySide.CLIENT, ImmediateWindowHandler.getGLVersion())); loadingStateValid = true; FMLLoader.backgroundScanHandler.waitForScanToComplete(periodicTask); - final ModList modList = ModList.of(loadingModList.getModFiles().stream().map(ModFileInfo::getFile).toList(), + final ModList modList = ModList.of(loadingModList.getModFiles().stream().map(IModFileInfo::getFile).toList(), loadingModList.getMods()); if (!this.loadingExceptions.isEmpty()) { LOGGER.fatal(CORE, "Error during pre-loading phase", loadingExceptions.get(0)); @@ -157,7 +153,7 @@ public void gatherAndInitializeMods(final ModWorkManager.DrivenExecutor syncExec throw new LoadingFailedException(loadingExceptions); } List failedBounds = loadingModList.getMods().stream() - .map(ModInfo::getForgeFeatures) + .map(IModInfo::getForgeFeatures) .flatMap(Collection::stream) .filter(bound -> !ForgeFeature.testFeature(FMLEnvironment.dist, bound)) .toList(); @@ -173,7 +169,7 @@ public void gatherAndInitializeMods(final ModWorkManager.DrivenExecutor syncExec } final List modContainers = loadingModList.getModFiles().stream() - .map(ModFileInfo::getFile) + .map(IModFileInfo::getFile) .map(this::buildMods) .mapMulti(Iterable::forEach) .toList(); diff --git a/loader/src/main/java/net/neoforged/fml/loading/FMLLoader.java b/loader/src/main/java/net/neoforged/fml/loading/FMLLoader.java index a1efb7d2e..ad73bf7ce 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/FMLLoader.java +++ b/loader/src/main/java/net/neoforged/fml/loading/FMLLoader.java @@ -21,6 +21,7 @@ import net.neoforged.fml.loading.targets.CommonLaunchHandler; import net.neoforged.neoforgespi.Environment; import net.neoforged.neoforgespi.coremod.ICoreModProvider; +import net.neoforged.neoforgespi.locating.IModFile; import org.slf4j.Logger; import java.io.IOException; @@ -186,7 +187,7 @@ public static CommonLaunchHandler getLaunchHandler() { return commonLaunchHandler; } - public static void addAccessTransformer(Path atPath, ModFile modName) + public static void addAccessTransformer(Path atPath, IModFile modName) { LOGGER.debug(LogMarkers.SCAN, "Adding Access Transformer in {}", modName.getFilePath()); try { diff --git a/loader/src/main/java/net/neoforged/fml/loading/LanguageLoadingProvider.java b/loader/src/main/java/net/neoforged/fml/loading/LanguageLoadingProvider.java index ecdbba405..7dd4b2202 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/LanguageLoadingProvider.java +++ b/loader/src/main/java/net/neoforged/fml/loading/LanguageLoadingProvider.java @@ -12,6 +12,7 @@ import net.neoforged.neoforgespi.language.IModLanguageProvider; import net.neoforged.fml.loading.moddiscovery.ExplodedDirectoryLocator; import net.neoforged.fml.loading.moddiscovery.ModFile; +import net.neoforged.neoforgespi.locating.IModFile; import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.artifact.versioning.VersionRange; @@ -129,7 +130,7 @@ Stream getLibraries() { return languagePaths.stream(); } - public IModLanguageProvider findLanguage(ModFile mf, String modLoader, VersionRange modLoaderVersion) { + public IModLanguageProvider findLanguage(IModFile mf, String modLoader, VersionRange modLoaderVersion) { final String languageFileName = mf.getProvider() instanceof ExplodedDirectoryLocator ? "in-development" : mf.getFileName(); final ModLanguageWrapper mlw = languageProviderMap.get(modLoader); if (mlw == null) { diff --git a/loader/src/main/java/net/neoforged/fml/loading/LoadingModList.java b/loader/src/main/java/net/neoforged/fml/loading/LoadingModList.java index b790639c5..5bb654da3 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/LoadingModList.java +++ b/loader/src/main/java/net/neoforged/fml/loading/LoadingModList.java @@ -11,6 +11,8 @@ import net.neoforged.fml.loading.moddiscovery.ModFile; import net.neoforged.fml.loading.moddiscovery.ModFileInfo; import net.neoforged.fml.loading.moddiscovery.ModInfo; +import net.neoforged.neoforgespi.language.IModFileInfo; +import net.neoforged.neoforgespi.language.IModInfo; import net.neoforged.neoforgespi.locating.IModFile; import java.net.URL; @@ -32,32 +34,31 @@ public class LoadingModList { private static LoadingModList INSTANCE; - private final List modFiles; - private final List sortedList; - private final Map fileById; + private final List modFiles; + private final List sortedList; + private final Map fileById; private final List preLoadErrors; private final List preLoadWarnings; private List brokenFiles; - private LoadingModList(final List modFiles, final List sortedList) + private LoadingModList(final List modFiles, final List sortedList) { this.modFiles = modFiles.stream() - .map(ModFile::getModFileInfo) + .map(IModFile::getModFileInfo) .map(ModFileInfo.class::cast) .collect(Collectors.toList()); this.sortedList = sortedList.stream() .map(ModInfo.class::cast) .collect(Collectors.toList()); - this.fileById = this.modFiles.stream() - .map(ModFileInfo::getMods) + this.fileById = modFiles.stream() + .map(IModFile::getModInfos) .flatMap(Collection::stream) - .map(ModInfo.class::cast) - .collect(Collectors.toMap(ModInfo::getModId, ModInfo::getOwningFile)); + .collect(Collectors.toMap(IModInfo::getModId, IModInfo::getOwningFile)); this.preLoadErrors = new ArrayList<>(); this.preLoadWarnings = new ArrayList<>(); } - public static LoadingModList of(List modFiles, List sortedList, final EarlyLoadingException earlyLoadingException) + public static LoadingModList of(List modFiles, List sortedList, final EarlyLoadingException earlyLoadingException) { INSTANCE = new LoadingModList(modFiles, sortedList); if (earlyLoadingException != null) @@ -73,16 +74,16 @@ public static LoadingModList get() { public void addCoreMods() { modFiles.stream() - .map(ModFileInfo::getFile) - .map(ModFile::getCoreMods) + .map(IModFileInfo::getFile) + .map(IModFile::getCoreMods) .flatMap(List::stream) .forEach(FMLLoader.getCoreModProvider()::addCoreMod); } public void addMixinConfigs() { modFiles.stream() - .map(ModFileInfo::getFile) - .map(ModFile::getMixinConfigs) + .map(IModFileInfo::getFile) + .map(IModFile::getMixinConfigs) .flatMap(List::stream) .forEach(DeferredMixinConfigRegistration::addMixinConfig); } @@ -90,7 +91,7 @@ public void addMixinConfigs() { public void addAccessTransformers() { modFiles.stream() - .map(ModFileInfo::getFile) + .map(IModFileInfo::getFile) .forEach(mod -> mod.getAccessTransformers().forEach(path -> FMLLoader.addAccessTransformer(path, mod))); } @@ -98,18 +99,18 @@ public void addForScanning(BackgroundScanHandler backgroundScanHandler) { backgroundScanHandler.setLoadingModList(this); modFiles.stream() - .map(ModFileInfo::getFile) + .map(IModFileInfo::getFile) .forEach(backgroundScanHandler::submitForScanning); } - public List getModFiles() + public List getModFiles() { return modFiles; } public Path findResource(final String className) { - for (ModFileInfo mf : modFiles) { + for (var mf : modFiles) { final Path resource = mf.getFile().findResource(className); if (Files.exists(resource)) return resource; } @@ -125,7 +126,7 @@ public Enumeration findAllURLsForResource(final String resName) { resourceName = resName; } return new Enumeration() { - private final Iterator modFileIterator = modFiles.iterator(); + private final Iterator modFileIterator = modFiles.iterator(); private URL next; @Override public boolean hasMoreElements() { @@ -147,7 +148,7 @@ public URL nextElement() { private URL findNextURL() { while (modFileIterator.hasNext()) { - final ModFileInfo next = modFileIterator.next(); + final var next = modFileIterator.next(); final Path resource = next.getFile().findResource(resourceName); if (Files.exists(resource)) { return LamdbaExceptionUtils.uncheck(()->new URL("modjar://" + next.getMods().get(0).getModId() + "/" + resourceName)); @@ -158,12 +159,12 @@ private URL findNextURL() { }; } - public ModFileInfo getModFileById(String modid) + public IModFileInfo getModFileById(String modid) { return this.fileById.get(modid); } - public List getMods() + public List getMods() { return this.sortedList; } diff --git a/loader/src/main/java/net/neoforged/fml/loading/ModSorter.java b/loader/src/main/java/net/neoforged/fml/loading/ModSorter.java index 2c789b58d..22bdbe55e 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/ModSorter.java +++ b/loader/src/main/java/net/neoforged/fml/loading/ModSorter.java @@ -16,6 +16,7 @@ import net.neoforged.fml.loading.moddiscovery.ModInfo; import net.neoforged.fml.loading.toposort.CyclePresentException; import net.neoforged.fml.loading.toposort.TopologicalSort; +import net.neoforged.neoforgespi.locating.IModFile; import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.slf4j.Logger; @@ -33,17 +34,17 @@ public class ModSorter { private static final Logger LOGGER = LogUtils.getLogger(); private final UniqueModListBuilder uniqueModListBuilder; - private List modFiles; - private List sortedList; + private List modFiles; + private List sortedList; private Map modIdNameLookup; - private List systemMods; + private List systemMods; - private ModSorter(final List modFiles) + private ModSorter(final List modFiles) { this.uniqueModListBuilder = new UniqueModListBuilder(modFiles); } - public static LoadingModList sort(List mods, final List errors) + public static LoadingModList sort(List mods, final List errors) { final ModSorter ms = new ModSorter(mods); try { @@ -90,13 +91,13 @@ private void sort() final MutableGraph graph = GraphBuilder.directed().build(); AtomicInteger counter = new AtomicInteger(); Map infos = modFiles.stream() - .map(ModFile::getModFileInfo) + .map(IModFile::getModFileInfo) .filter(ModFileInfo.class::isInstance) .map(ModFileInfo.class::cast) .collect(toMap(Function.identity(), e -> counter.incrementAndGet())); infos.keySet().forEach(graph::addNode); modFiles.stream() - .map(ModFile::getModInfos) + .map(IModFile::getModInfos) .mapMulti(Iterable::forEach) .map(IModInfo::getDependencies) .mapMulti(Iterable::forEach) @@ -163,7 +164,7 @@ private void buildUniqueList() )); } - private void detectSystemMods(final Map> modFilesByFirstId) + private void detectSystemMods(final Map> modFilesByFirstId) { // Capture system mods (ex. MC, Forge) here, so we can keep them for later final Set systemMods = new HashSet<>(); @@ -172,7 +173,7 @@ private void detectSystemMods(final Map> modFilesByFirstId // Find mod file from MinecraftLocator to define the system mods modFiles.stream() .filter(modFile -> modFile.getProvider().getClass() == MinecraftLocator.class) - .map(ModFile::getSecureJar) + .map(IModFile::getSecureJar) .map(SecureJar::moduleDataProvider) .map(SecureJar.ModuleDataProvider::getManifest) .map(Manifest::getMainAttributes) @@ -228,12 +229,12 @@ public List buildErrorMessages() { private DependencyResolutionResult verifyDependencyVersions() { final var modVersions = modFiles.stream() - .map(ModFile::getModInfos) + .map(IModFile::getModInfos) .mapMulti(Iterable::forEach) .collect(toMap(IModInfo::getModId, IModInfo::getVersion)); final var modVersionDependencies = modFiles.stream() - .map(ModFile::getModInfos) + .map(IModFile::getModInfos) .mapMulti(Iterable::forEach) .collect(groupingBy(Function.identity(), flatMapping(e -> e.getDependencies().stream(), toList()))); diff --git a/loader/src/main/java/net/neoforged/fml/loading/UniqueModListBuilder.java b/loader/src/main/java/net/neoforged/fml/loading/UniqueModListBuilder.java index 816e28db8..56c77862f 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/UniqueModListBuilder.java +++ b/loader/src/main/java/net/neoforged/fml/loading/UniqueModListBuilder.java @@ -8,7 +8,9 @@ import com.mojang.logging.LogUtils; import net.neoforged.fml.loading.moddiscovery.ModFile; import net.neoforged.neoforgespi.language.IModInfo; +import net.neoforged.neoforgespi.locating.IModFile; import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.slf4j.Logger; import java.util.ArrayList; @@ -16,7 +18,9 @@ import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Function; +import java.util.jar.Attributes; import java.util.stream.Collectors; import static java.util.stream.Collectors.groupingBy; @@ -27,21 +31,21 @@ public class UniqueModListBuilder { private final static Logger LOGGER = LogUtils.getLogger(); - private final List modFiles; + private final List modFiles; - public UniqueModListBuilder(final List modFiles) {this.modFiles = modFiles;} + public UniqueModListBuilder(final List modFiles) {this.modFiles = modFiles;} public UniqueModListData buildUniqueList() { - List uniqueModList; - List uniqueLibListWithVersion; + List uniqueModList; + List uniqueLibListWithVersion; // Collect mod files by module name. This will be used for deduping purposes - final Map> modFilesByFirstId = modFiles.stream() + final Map> modFilesByFirstId = modFiles.stream() .filter(mf -> mf.getModFileInfo() != null) .collect(groupingBy(UniqueModListBuilder::getModId)); - final Map> libFilesWithVersionByModuleName = modFiles.stream() + final Map> libFilesWithVersionByModuleName = modFiles.stream() .filter(mf -> mf.getModFileInfo() == null) .collect(groupingBy(UniqueModListBuilder::getModId)); @@ -58,12 +62,12 @@ public UniqueModListData buildUniqueList() // Transform to the full mod id list final Map> modIds = uniqueModList.stream() .filter(mf -> mf.getModFileInfo() != null) //Filter out non-mod files, we don't care about those for now..... - .map(ModFile::getModInfos) + .map(IModFile::getModInfos) .flatMap(Collection::stream) .collect(groupingBy(IModInfo::getModId)); // Transform to the full lib id list - final Map> versionedLibIds = uniqueLibListWithVersion.stream() + final Map> versionedLibIds = uniqueLibListWithVersion.stream() .map(UniqueModListBuilder::getModId) .collect(Collectors.toMap( Function.identity(), @@ -104,18 +108,18 @@ public UniqueModListData buildUniqueList() } // Collect unique mod files by module name. This will be used for deduping purposes - final Map> uniqueModFilesByFirstId = uniqueModList.stream() + final Map> uniqueModFilesByFirstId = uniqueModList.stream() .collect(groupingBy(UniqueModListBuilder::getModId)); - final List loadedList = new ArrayList<>(); + final List loadedList = new ArrayList<>(); loadedList.addAll(uniqueModList); loadedList.addAll(uniqueLibListWithVersion); return new UniqueModListData(loadedList, uniqueModFilesByFirstId); } - private ModFile selectNewestModInfo(Map.Entry> fullList) { - List modInfoList = fullList.getValue(); + private IModFile selectNewestModInfo(Map.Entry> fullList) { + List modInfoList = fullList.getValue(); if (modInfoList.size() > 1) { LOGGER.debug("Found {} mods for first modid {}, selecting most recent based on version data", modInfoList.size(), fullList.getKey()); modInfoList.sort(Comparator.comparing(this::getVersion).reversed()); @@ -124,16 +128,16 @@ private ModFile selectNewestModInfo(Map.Entry> fullList) { return modInfoList.get(0); } - private ArtifactVersion getVersion(final ModFile mf) + private ArtifactVersion getVersion(final IModFile mf) { if (mf.getModFileInfo() == null || mf.getModInfos() == null || mf.getModInfos().isEmpty()) { - return mf.getJarVersion(); + return mf.getVersion(); } return mf.getModInfos().get(0).getVersion(); } - private static String getModId(ModFile modFile) { + private static String getModId(IModFile modFile) { if (modFile.getModFileInfo() == null || modFile.getModFileInfo().getMods().isEmpty()) { return modFile.getSecureJar().name(); } @@ -141,6 +145,6 @@ private static String getModId(ModFile modFile) { return modFile.getModFileInfo().moduleName(); } - public record UniqueModListData(List modFiles, Map> modFilesByFirstId) {} + public record UniqueModListData(List modFiles, Map> modFilesByFirstId) {} } diff --git a/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/BackgroundScanHandler.java b/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/BackgroundScanHandler.java index a527c85b0..78016ddd8 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/BackgroundScanHandler.java +++ b/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/BackgroundScanHandler.java @@ -10,7 +10,7 @@ import net.neoforged.fml.loading.ImmediateWindowHandler; import net.neoforged.fml.loading.LoadingModList; import net.neoforged.fml.loading.LogMarkers; -import net.neoforged.neoforgespi.language.ModFileScanData; +import net.neoforged.neoforgespi.locating.IModFile; import org.slf4j.Logger; import java.time.Duration; @@ -33,9 +33,9 @@ private enum ScanStatus { private static final Logger LOGGER = LogUtils.getLogger(); private final ExecutorService modContentScanner; - private final List pendingFiles; - private final List scannedFiles; - private final List allFiles; + private final List pendingFiles; + private final List scannedFiles; + private final List allFiles; private ScanStatus status; private LoadingModList loadingModList; @@ -56,7 +56,7 @@ public BackgroundScanHandler() { status = ScanStatus.NOT_STARTED; } - public void submitForScanning(final ModFile file) { + public void submitForScanning(final IModFile file) { if (modContentScanner.isShutdown()) { status = ScanStatus.ERRORED; throw new IllegalStateException("Scanner has shutdown"); @@ -65,13 +65,11 @@ public void submitForScanning(final ModFile file) { ImmediateWindowHandler.updateProgress("Scanning mod candidates"); allFiles.add(file); pendingFiles.add(file); - final CompletableFuture future = CompletableFuture.supplyAsync(file::compileContent, modContentScanner) - .whenComplete(file::setScanResult) - .whenComplete((r,t)-> this.addCompletedFile(file,r,t)); - file.setFutureScanResult(future); + file.getController().submitForScanning(modContentScanner) + .whenComplete((r, t)-> this.addCompletedFile(file, t)); } - private synchronized void addCompletedFile(final ModFile file, final ModFileScanData modFileScanData, final Throwable throwable) { + private synchronized void addCompletedFile(final IModFile file, final Throwable throwable) { if (throwable != null) { status = ScanStatus.ERRORED; LOGGER.error(LogMarkers.SCAN,"An error occurred scanning file {}", file, throwable); diff --git a/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModDiscoverer.java b/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModDiscoverer.java index 38ab45dec..b526f9000 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModDiscoverer.java +++ b/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModDiscoverer.java @@ -63,7 +63,7 @@ public ModDiscoverer(Map arguments) { public ModValidator discoverMods() { LOGGER.debug(LogMarkers.SCAN,"Scanning for mods and other resources to load. We know {} ways to find mods", modLocatorList.size()); - List loadedFiles = new ArrayList<>(); + List loadedFiles = new ArrayList<>(); List discoveryErrorData = new ArrayList<>(); boolean successfullyLoadedMods = true; List brokenFiles = new ArrayList<>(); @@ -100,7 +100,7 @@ public ModValidator discoverMods() { } //First processing run of the mod list. Any duplicates will cause resolution failure and dependency loading will be skipped. - Map> modFilesMap = Maps.newHashMap(); + Map> modFilesMap = Maps.newHashMap(); try { final UniqueModListBuilder modsUniqueListBuilder = new UniqueModListBuilder(loadedFiles); final UniqueModListBuilder.UniqueModListData uniqueModsData = modsUniqueListBuilder.buildUniqueList(); @@ -164,12 +164,11 @@ public ModValidator discoverMods() { return validator; } - private void handleLocatedFiles(final List loadedFiles, final List locatedFiles) + private void handleLocatedFiles(final List loadedFiles, final List locatedFiles) { - var locatedModFiles = locatedFiles.stream().filter(ModFile.class::isInstance).map(ModFile.class::cast).toList(); - for (IModFile mf : locatedModFiles) { + for (IModFile mf : locatedFiles) { LOGGER.info(LogMarkers.SCAN, "Found mod file \"{}\" of type {} with provider {}", mf.getFileName(), mf.getType(), mf.getProvider()); } - loadedFiles.addAll(locatedModFiles); + loadedFiles.addAll(locatedFiles); } } diff --git a/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModFile.java b/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModFile.java index a84b31f22..30300036f 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModFile.java +++ b/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModFile.java @@ -10,13 +10,16 @@ import cpw.mods.jarhandling.SecureJar; import net.neoforged.fml.loading.FMLLoader; import net.neoforged.fml.loading.LogMarkers; +import net.neoforged.neoforgespi.coremod.ICoreModFile; import net.neoforged.neoforgespi.language.IModFileInfo; import net.neoforged.neoforgespi.language.IModInfo; import net.neoforged.neoforgespi.language.IModLanguageProvider; import net.neoforged.neoforgespi.language.ModFileScanData; import net.neoforged.neoforgespi.locating.IModFile; +import net.neoforged.neoforgespi.locating.IModFileController; import net.neoforged.neoforgespi.locating.IModProvider; import net.neoforged.neoforgespi.locating.ModFileFactory; +import net.neoforged.neoforgespi.locating.ModFileLoadingException; import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.slf4j.Logger; @@ -29,6 +32,7 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.jar.Attributes; @@ -50,9 +54,10 @@ public class ModFile implements IModFile { private IModFileInfo modFileInfo; private ModFileScanData fileModFileScanData; private volatile CompletableFuture futureScanResult; - private List coreMods; - private List mixinConfigs; - private List accessTransformers; + private List coreMods = List.of(); + private List mixinConfigs = List.of(); + private List accessTransformers = List.of(); + private final Controller controller = new Controller(); static final Attributes.Name TYPE = new Attributes.Name("FMLModType"); private SecureJar.Status securityStatus; @@ -100,29 +105,7 @@ public List getAccessTransformers() { return accessTransformers; } - public boolean identifyMods() { - this.modFileInfo = ModFileParser.readModList(this, this.parser); - if (this.modFileInfo == null) return this.getType() != Type.MOD; - LOGGER.debug(LogMarkers.LOADING,"Loading mod file {} with languages {}", this.getFilePath(), this.modFileInfo.requiredLanguageLoaders()); - this.coreMods = ModFileParser.getCoreMods(this); - this.coreMods.forEach(mi-> LOGGER.debug(LogMarkers.LOADING,"Found coremod {}", mi.getPath())); - this.mixinConfigs = ModFileParser.getMixinConfigs(this.modFileInfo); - this.mixinConfigs.forEach(mc -> LOGGER.debug(LogMarkers.LOADING,"Found mixin config {}", mc)); - this.accessTransformers = ModFileParser.getAccessTransformers(this.modFileInfo) - .map(list -> list.stream().map(this::findResource).filter(path -> { - if (Files.notExists(path)) { - LOGGER.error(LogMarkers.LOADING, "Access transformer file {} provided by mod {} does not exist!", path, modFileInfo.moduleName()); - return false; - } - return true; - })) - .orElseGet(() -> Stream.of(findResource("META-INF", "accesstransformer.cfg")) - .filter(Files::exists)) - .toList(); - return true; - } - - public List getCoreMods() { + public List getCoreMods() { return coreMods; } @@ -141,10 +124,6 @@ public void scanFile(Consumer pathConsumer) { provider.scanFile(this, pathConsumer); } - public void setFutureScanResult(CompletableFuture future) { - this.futureScanResult = future; - } - @Override public ModFileScanData getScanResult() { if (this.futureScanResult != null) { @@ -185,12 +164,6 @@ public Path findResource(String... path) { return getSecureJar().getPath(String.join("/", path)); } - public void identifyLanguage() { - this.loaders = this.modFileInfo.requiredLanguageLoaders().stream() - .map(spec-> FMLLoader.getLanguageLoadingProvider().findLanguage(this, spec.languageName(), spec.acceptedVersions())) - .toList(); - } - @Override public String toString() { return "Mod File: " + Objects.toString(this.jar.getPrimaryPath()); @@ -216,7 +189,8 @@ public void setSecurityStatus(final SecureJar.Status status) { this.securityStatus = status; } - public ArtifactVersion getJarVersion() + @Override + public ArtifactVersion getVersion() { return new DefaultArtifactVersion(this.jarVersion); } @@ -226,4 +200,48 @@ private static String parseType(final SecureJar jar) { final Optional value = Optional.ofNullable(m.getMainAttributes().getValue(TYPE)); return value.orElse("MOD"); } + + @Override + public IModFileController getController() { + return controller; + } + + private class Controller implements IModFileController { + @Override + public void identify() { + if (getType() == Type.MOD) { + ModFile.this.modFileInfo = ModFileParser.readModList(ModFile.this, ModFile.this.parser); + if (ModFile.this.modFileInfo == null) { + throw new ModFileLoadingException("Mod %s is missing metadata".formatted(getFilePath())); + } + LOGGER.debug(LogMarkers.LOADING, "Loading mod file {} with languages {}", ModFile.this.getFilePath(), ModFile.this.modFileInfo.requiredLanguageLoaders()); + ModFile.this.coreMods = ModFileParser.getCoreMods(ModFile.this); + ModFile.this.coreMods.forEach(mi -> LOGGER.debug(LogMarkers.LOADING, "Found coremod {}", mi.getPath())); + ModFile.this.mixinConfigs = ModFileParser.getMixinConfigs(ModFile.this.modFileInfo); + ModFile.this.mixinConfigs.forEach(mc -> LOGGER.debug(LogMarkers.LOADING, "Found mixin config {}", mc)); + ModFile.this.accessTransformers = ModFileParser.getAccessTransformers(ModFile.this.modFileInfo) + .map(list -> list.stream().map(ModFile.this::findResource).filter(path -> { + if (Files.notExists(path)) { + LOGGER.error(LogMarkers.LOADING, "Access transformer file {} provided by mod {} does not exist!", path, modFileInfo.moduleName()); + return false; + } + return true; + })) + .orElseGet(() -> Stream.of(findResource("META-INF", "accesstransformer.cfg")) + .filter(Files::exists)) + .toList(); + } + } + + @Override + public void setLoaders(List loaders) { + ModFile.this.loaders = loaders; + } + + @Override + public CompletableFuture submitForScanning(ExecutorService service) { + return ModFile.this.futureScanResult = CompletableFuture.supplyAsync(ModFile.this::compileContent, service) + .whenComplete(ModFile.this::setScanResult); + } + } } diff --git a/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModFileParser.java b/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModFileParser.java index 03a0bad93..7ba3b690c 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModFileParser.java +++ b/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModFileParser.java @@ -10,6 +10,7 @@ import com.google.gson.reflect.TypeToken; import com.mojang.logging.LogUtils; import net.neoforged.fml.loading.LogMarkers; +import net.neoforged.neoforgespi.coremod.ICoreModFile; import net.neoforged.neoforgespi.language.IModFileInfo; import net.neoforged.neoforgespi.locating.IModFile; import net.neoforged.neoforgespi.locating.ModFileFactory; @@ -47,7 +48,7 @@ public static IModFileInfo modsTomlParser(final IModFile imodFile) { return new ModFileInfo(modFile, configWrapper, configWrapper::setFile); } - protected static List getCoreMods(final ModFile modFile) { + protected static List getCoreMods(final ModFile modFile) { Map coreModPaths; try { final Path coremodsjson = modFile.findResource("META-INF", "coremods.json"); @@ -64,7 +65,7 @@ protected static List getCoreMods(final ModFile modFile) { return coreModPaths.entrySet().stream() .peek(e-> LOGGER.debug(LogMarkers.LOADING,"Found coremod {} with Javascript path {}", e.getKey(), e.getValue())) - .map(e -> new CoreModFile(e.getKey(), modFile.findResource(e.getValue()),modFile)) + .map(e -> new CoreModFile(e.getKey(), modFile.findResource(e.getValue()),modFile)) .toList(); } @@ -106,4 +107,4 @@ protected static Optional> getAccessTransformers(IModFileInfo modFi return Optional.of(List.of()); } } -} \ No newline at end of file +} diff --git a/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModValidator.java b/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModValidator.java index 91b52eb79..12829c1d3 100644 --- a/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModValidator.java +++ b/loader/src/main/java/net/neoforged/fml/loading/moddiscovery/ModValidator.java @@ -23,14 +23,14 @@ public class ModValidator { private static final Logger LOGGER = LogUtils.getLogger(); - private final Map> modFiles; - private final List candidatePlugins; - private final List candidateMods; + private final Map> modFiles; + private final List candidatePlugins; + private final List candidateMods; private LoadingModList loadingModList; private List brokenFiles; private final List discoveryErrorData; - public ModValidator(final Map> modFiles, final List brokenFiles, final List discoveryErrorData) { + public ModValidator(final Map> modFiles, final List brokenFiles, final List discoveryErrorData) { this.modFiles = modFiles; this.candidateMods = lst(modFiles.get(IModFile.Type.MOD)); this.candidateMods.addAll(lst(modFiles.get(IModFile.Type.GAMELIBRARY))); @@ -40,12 +40,12 @@ public ModValidator(final Map> modFiles, final List this.brokenFiles = brokenFiles.stream().map(IModFileInfo::getFile).collect(Collectors.toList()); // mutable list } - private static List lst(List files) { + private static List lst(List files) { return files == null ? new ArrayList<>() : new ArrayList<>(files); } public void stage1Validation() { - brokenFiles.addAll(validateFiles(candidateMods)); + brokenFiles.addAll(validateAndIdentify(candidateMods)); if (LOGGER.isDebugEnabled(LogMarkers.SCAN)) { LOGGER.debug(LogMarkers.SCAN, "Found {} mod files with {} mods", candidateMods.size(), candidateMods.stream().mapToInt(mf -> mf.getModInfos().size()).sum()); } @@ -53,15 +53,25 @@ public void stage1Validation() { } @NotNull - private List validateFiles(final List mods) { - final List brokenFiles = new ArrayList<>(); - for (Iterator iterator = mods.iterator(); iterator.hasNext(); ) + private List validateAndIdentify(final List mods) { + final List brokenFiles = new ArrayList<>(); + for (Iterator iterator = mods.iterator(); iterator.hasNext(); ) { - ModFile modFile = iterator.next(); - if (!modFile.getProvider().isValid(modFile) || !modFile.identifyMods()) { + IModFile modFile = iterator.next(); + if (modFile.getType() != IModFile.Type.MOD) continue; + + if (!modFile.getProvider().isValid(modFile)) { LOGGER.warn(LogMarkers.SCAN, "File {} has been ignored - it is invalid", modFile.getFilePath()); iterator.remove(); brokenFiles.add(modFile); + } else { + try { + modFile.getController().identify(); + } catch (Exception exception) { + LOGGER.error(LogMarkers.SCAN, "File {} was not identified:", modFile.getFilePath(), exception); + iterator.remove(); + brokenFiles.add(modFile); + } } } return brokenFiles; @@ -74,21 +84,25 @@ public ITransformationService.Resource getPluginResources() { public ITransformationService.Resource getModResources() { var modFilesToLoad = Stream.concat( // mods - this.loadingModList.getModFiles().stream().map(ModFileInfo::getFile), + this.loadingModList.getModFiles().stream().map(IModFileInfo::getFile), // game libraries this.modFiles.get(IModFile.Type.GAMELIBRARY).stream()); - return new ITransformationService.Resource(IModuleLayerManager.Layer.GAME, modFilesToLoad.map(ModFile::getSecureJar).toList()); + return new ITransformationService.Resource(IModuleLayerManager.Layer.GAME, modFilesToLoad.map(IModFile::getSecureJar).toList()); } private List validateLanguages() { List errorData = new ArrayList<>(); - for (Iterator iterator = this.candidateMods.iterator(); iterator.hasNext(); ) { - final ModFile modFile = iterator.next(); - try { - modFile.identifyLanguage(); - } catch (EarlyLoadingException e) { - errorData.addAll(e.getAllData()); - iterator.remove(); + for (Iterator iterator = this.candidateMods.iterator(); iterator.hasNext(); ) { + final IModFile modFile = iterator.next(); + if (modFile.getType() == IModFile.Type.MOD) { + try { + modFile.getController().setLoaders(modFile.getModFileInfo().requiredLanguageLoaders().stream() + .map(spec-> FMLLoader.getLanguageLoadingProvider().findLanguage(modFile, spec.languageName(), spec.acceptedVersions())) + .toList()); + } catch (EarlyLoadingException e) { + errorData.addAll(e.getAllData()); + iterator.remove(); + } } } return errorData; diff --git a/spi/build.gradle b/spi/build.gradle index 6bd8a0905..741c44435 100644 --- a/spi/build.gradle +++ b/spi/build.gradle @@ -5,6 +5,7 @@ plugins { } dependencies { + compileOnly("org.jetbrains:annotations:${jetbrains_annotations_version}") implementation("cpw.mods:modlauncher:$modlauncher_version") implementation("org.ow2.asm:asm:$asm_version") implementation("org.ow2.asm:asm-commons:$asm_version") @@ -26,4 +27,4 @@ dependencies { test { useJUnitPlatform() -} \ No newline at end of file +} diff --git a/spi/src/main/java/net/neoforged/neoforgespi/locating/IModFile.java b/spi/src/main/java/net/neoforged/neoforgespi/locating/IModFile.java index 0b37b4af3..5d7e75031 100644 --- a/spi/src/main/java/net/neoforged/neoforgespi/locating/IModFile.java +++ b/spi/src/main/java/net/neoforged/neoforgespi/locating/IModFile.java @@ -6,11 +6,14 @@ package net.neoforged.neoforgespi.locating; import cpw.mods.jarhandling.SecureJar; +import net.neoforged.neoforgespi.coremod.ICoreModFile; import net.neoforged.neoforgespi.language.*; import net.neoforged.neoforgespi.language.IModFileInfo; import net.neoforged.neoforgespi.language.IModInfo; import net.neoforged.neoforgespi.language.IModLanguageProvider; import net.neoforged.neoforgespi.language.ModFileScanData; +import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.jetbrains.annotations.ApiStatus; import java.nio.file.Path; import java.util.List; @@ -28,14 +31,7 @@ */ public interface IModFile { /** - * The language loaders which are included in this mod file. - * - * If this method returns any entries then {@link #getType()} has to return {@link Type#LIBRARY}, - * else this mod file will not be loaded in the proper module layer in 1.17 and above. - * - * As such, returning entries from this method is mutually exclusive with returning entries from {@link #getModInfos()}. - * - * @return The mod language providers provided by this mod file. (Also known as the loaders). + * {@return the language loaders that will load this mod} */ List getLoaders(); @@ -92,8 +88,6 @@ public interface IModFile { * If this method returns any entries then {@link #getType()} has to return {@link Type#MOD}, * else this mod file will not be loaded in the proper module layer in 1.17 and above. * - * As such returning entries from this method is mutually exclusive with {@link #getLoaders()}. - * * @return The mods in this mod file. */ List getModInfos(); @@ -125,6 +119,36 @@ public interface IModFile { */ IModFileInfo getModFileInfo(); + /** + * {@return the coremods contained in this file} + */ + List getCoreMods(); + + /** + * {@return the names of the Mixin configs of this file} + */ + List getMixinConfigs(); + + /** + * {@return the paths to the access transformer files contained in this file} + */ + List getAccessTransformers(); + + /** + * {@return the controller of this file} + * This controller handles validating and computing information about the mods contained by the file.

+ * The controller is mostly internal, for use by FML, and should only be used by implementors. + */ + @ApiStatus.OverrideOnly + IModFileController getController(); + + /** + * {@return the version of this file} + * Usually this is the version in the jar's manifest. + * @apiNote This version may not be accurate, when possible, use the version of the mods contained in the file. + */ + ArtifactVersion getVersion(); + /** * The type of file. * Determines into which module layer the data is loaded and how metadata is loaded and processed. diff --git a/spi/src/main/java/net/neoforged/neoforgespi/locating/IModFileController.java b/spi/src/main/java/net/neoforged/neoforgespi/locating/IModFileController.java new file mode 100644 index 000000000..df97a5210 --- /dev/null +++ b/spi/src/main/java/net/neoforged/neoforgespi/locating/IModFileController.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) NeoForged and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.neoforged.neoforgespi.locating; + +import net.neoforged.neoforgespi.language.IModFileInfo; +import net.neoforged.neoforgespi.language.IModLanguageProvider; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; + +/** + * A mod file controller controller handles validating and computing information about the mods contained by the file.

+ * Controllers are mostly internal, for use by FML, and should only be used by implementors. + */ +@ApiStatus.OverrideOnly +public interface IModFileController { + /** + * Called when the mods contained in the mod file shall be identified, and any other related information (such as AT files). + */ + void identify(); + + /** + * Sets the loaders that will load the mod.

+ * The loaders that will be received are defined by {@link IModFileInfo#requiredLanguageLoaders()}. + * + * @param loaders the loaders that will load the mod + */ + void setLoaders(List loaders); + + /** + * Submit this file for content scanning. This includes computing the {@link IModFile#getScanResult() scan data} of the file. + */ + CompletableFuture submitForScanning(ExecutorService service); +} From c1da022471698907fe427da8a282de591d7b57b2 Mon Sep 17 00:00:00 2001 From: Matyrobbrt Date: Sat, 13 Jan 2024 17:41:54 +0200 Subject: [PATCH 2/2] A few defaults --- .../neoforgespi/locating/IModFile.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/spi/src/main/java/net/neoforged/neoforgespi/locating/IModFile.java b/spi/src/main/java/net/neoforged/neoforgespi/locating/IModFile.java index 5d7e75031..fbcc13b46 100644 --- a/spi/src/main/java/net/neoforged/neoforgespi/locating/IModFile.java +++ b/spi/src/main/java/net/neoforged/neoforgespi/locating/IModFile.java @@ -13,8 +13,10 @@ import net.neoforged.neoforgespi.language.IModLanguageProvider; import net.neoforged.neoforgespi.language.ModFileScanData; import org.apache.maven.artifact.versioning.ArtifactVersion; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.jetbrains.annotations.ApiStatus; +import java.lang.module.ModuleDescriptor; import java.nio.file.Path; import java.util.List; import java.util.Map; @@ -122,17 +124,23 @@ public interface IModFile { /** * {@return the coremods contained in this file} */ - List getCoreMods(); + default List getCoreMods() { + return List.of(); + } /** * {@return the names of the Mixin configs of this file} */ - List getMixinConfigs(); + default List getMixinConfigs() { + return List.of(); + } /** * {@return the paths to the access transformer files contained in this file} */ - List getAccessTransformers(); + default List getAccessTransformers() { + return List.of(); + } /** * {@return the controller of this file} @@ -147,7 +155,9 @@ public interface IModFile { * Usually this is the version in the jar's manifest. * @apiNote This version may not be accurate, when possible, use the version of the mods contained in the file. */ - ArtifactVersion getVersion(); + default ArtifactVersion getVersion() { + return new DefaultArtifactVersion(getSecureJar().moduleDataProvider().descriptor().version().map(ModuleDescriptor.Version::toString).orElse("0.0NONE")); + } /** * The type of file.