Skip to content

Commit

Permalink
Fix plugin discovery and construction
Browse files Browse the repository at this point in the history
  • Loading branch information
Yeregorix committed Oct 14, 2023
1 parent 80509b8 commit e7a3961
Show file tree
Hide file tree
Showing 15 changed files with 119 additions and 355 deletions.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,75 +27,73 @@
import cpw.mods.jarhandling.SecureJar;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import net.minecraftforge.fml.loading.moddiscovery.NightConfigWrapper;
import net.minecraftforge.forgespi.language.IConfigurable;
import net.minecraftforge.fml.loading.moddiscovery.ModJarMetadata;
import net.minecraftforge.forgespi.language.IModFileInfo;
import net.minecraftforge.forgespi.locating.IModFile;
import net.minecraftforge.forgespi.locating.IModLocator;
import net.minecraftforge.forgespi.locating.ModFileFactory;
import org.spongepowered.common.applaunch.AppLaunch;
import org.spongepowered.common.applaunch.plugin.PluginPlatformConstants;
import org.spongepowered.forge.applaunch.loading.metadata.PluginFileConfigurable;
import org.spongepowered.plugin.metadata.builtin.MetadataContainer;
import org.spongepowered.plugin.metadata.builtin.MetadataParser;

import java.io.Reader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public final class ModFileParsers {

private static Constructor<ModFileInfo> modFileInfoConstructor;
private static Field modFileInfoField;
private static Constructor<ModJarMetadata> modJarMetadataConstructor;

static {
try {
ModFileParsers.modFileInfoConstructor = ModFileInfo.class.getDeclaredConstructor(ModFile.class, IConfigurable.class);
ModFileParsers.modFileInfoField = NightConfigWrapper.class.getDeclaredField("file");
ModFileParsers.modJarMetadataConstructor = ModJarMetadata.class.getDeclaredConstructor();
ModFileParsers.modJarMetadataConstructor.setAccessible(true);
} catch (final Exception e) {
throw new RuntimeException(e);
}
}

public static IModFileInfo pluginMetadataParser(final String fileName, final IModFile iModFile) {
final ModFile modFile = (ModFile)iModFile;
public static IModFileInfo parsePluginMetadata(final IModFile iModFile) {
final ModFile modFile = (ModFile) iModFile;
AppLaunch.logger().debug("Considering plugin file candidate {}", modFile.getFilePath());
final Path metadataFile = modFile.findResource("META-INF/" + fileName + ".json");

final Path metadataFile = modFile.findResource(PluginPlatformConstants.METADATA_FILE_LOCATION);
if (Files.notExists(metadataFile)) {
AppLaunch.logger().debug("Plugin file '{}' is missing a 'sponge_plugins.json' metadata file in META-INF", modFile);
return null;
}

try {
final MetadataContainer container;
try (final Reader reader = Files.newBufferedReader(metadataFile, StandardCharsets.UTF_8)) {
container = MetadataParser.read(reader);
}
final PluginFileConfigurable configurable = new PluginFileConfigurable(container);

return ModFileParsers.generateModFileMetadata(modFile, configurable);
final PluginFileConfigurable config = new PluginFileConfigurable(container);
return new ModFileInfo(modFile, config, List.of());
} catch (final Exception e) {
AppLaunch.logger().warn("Could not read metadata for plugin file '{}'", modFile, e);
return null;
}
}

private static ModFileInfo generateModFileMetadata(final ModFile file, final IConfigurable configurable) throws Exception {
ModFileParsers.modFileInfoConstructor.setAccessible(true);
final ModFileInfo modFileInfo = ModFileParsers.modFileInfoConstructor.newInstance(file, configurable);
ModFileParsers.modFileInfoConstructor.setAccessible(false);
if (configurable instanceof NightConfigWrapper) {
ModFileParsers.modFileInfoField.setAccessible(true);
ModFileParsers.modFileInfoField.set(configurable, modFileInfo);
ModFileParsers.modFileInfoField.setAccessible(false);
private static ModJarMetadata newModJarMetadata() {
try {
return modJarMetadataConstructor.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}

return modFileInfo;
}

public static ModFile newPluginInstance(final SecureJar jar, final IModLocator locator, final String fileName) {
return (ModFile) ModFileFactory.FACTORY.build(jar, locator, file -> ModFileParsers.pluginMetadataParser(fileName, file));
public static ModFile newPluginInstance(final IModLocator locator, final Path... path) {
ModJarMetadata mjm = newModJarMetadata();
ModFile modFile = (ModFile) ModFileFactory.FACTORY.build(SecureJar.from(jar -> mjm, path), locator, ModFileParsers::parsePluginMetadata);
mjm.setModFile(modFile);
return modFile;
}

private ModFileParsers() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
*/
package org.spongepowered.forge.applaunch.loading.moddiscovery.locator;

import cpw.mods.jarhandling.SecureJar;
import net.minecraftforge.fml.loading.ClasspathLocatorUtils;
import net.minecraftforge.fml.loading.moddiscovery.AbstractJarFileModLocator;
import org.apache.logging.log4j.LogManager;
Expand All @@ -40,12 +39,10 @@
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;

public final class ClasspathPluginLocator extends AbstractJarFileModLocator {
private static final Logger LOGGER = LogManager.getLogger();
private static final String PLUGINS_JSON = "META-INF/sponge_plugins.json";
private Set<Path> modCoords;

@Override
Expand All @@ -55,7 +52,7 @@ public Stream<Path> scanCandidates() {

@Override
protected ModFileOrException createMod(Path... path) {
return new ModFileOrException(ModFileParsers.newPluginInstance(SecureJar.from(path), this, PluginPlatformConstants.METADATA_FILE_NAME), null);
return new ModFileOrException(ModFileParsers.newPluginInstance(this, path), null);
}

@Override
Expand All @@ -67,25 +64,23 @@ public String name() {
public void initArguments(final Map<String, ?> arguments) {
try {
this.modCoords = new LinkedHashSet<>();
this.locateMods(ClasspathPluginLocator.PLUGINS_JSON, "classpath_plugin", path -> true);
this.locateMods(PluginPlatformConstants.METADATA_FILE_LOCATION, "classpath_plugin");
} catch (IOException e) {
ClasspathPluginLocator.LOGGER.fatal("Error trying to find resources", e);
throw new RuntimeException("wha?", e);
}
}

private void locateMods(final String resource, final String name, final Predicate<Path> filter) throws IOException {
private void locateMods(final String resource, final String name) throws IOException {
final Enumeration<URL> pluginJsons = ClassLoader.getSystemClassLoader().getResources(resource);
while (pluginJsons.hasMoreElements()) {
final URL url = pluginJsons.nextElement();
final Path path = ClasspathLocatorUtils.findJarPathFor(resource, name, url);
if (Files.isDirectory(path))
continue;

if (filter.test(path)) {
ClasspathPluginLocator.LOGGER.debug("Found classpath plugin: {}", path);
this.modCoords.add(path);
}
ClasspathPluginLocator.LOGGER.debug("Found classpath plugin: {}", path);
this.modCoords.add(path);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
*/
package org.spongepowered.forge.applaunch.loading.moddiscovery.locator;

import cpw.mods.jarhandling.SecureJar;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import net.minecraftforge.fml.loading.ModDirTransformerDiscoverer;
import net.minecraftforge.fml.loading.StringUtils;
Expand All @@ -34,7 +33,6 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.spongepowered.common.applaunch.AppLaunch;
import org.spongepowered.common.applaunch.plugin.PluginPlatformConstants;
import org.spongepowered.forge.applaunch.loading.moddiscovery.ModFileParsers;

import java.nio.file.Files;
Expand Down Expand Up @@ -65,10 +63,9 @@ public List<ModFileOrException> scanMods() {
private Stream<ModFile> scanForModsIn(final Path pluginsDirectory) {
final List<Path> excluded = ModDirTransformerDiscoverer.allExcluded();
return LamdbaExceptionUtils.uncheck(() -> Files.list(pluginsDirectory))
.filter((p) -> !excluded.contains(p))
.filter((p) -> !excluded.contains(p) && StringUtils.toLowerCase(p.getFileName().toString()).endsWith(".jar"))
.sorted(Comparator.comparing((path) -> StringUtils.toLowerCase(path.getFileName().toString())))
.filter((p) -> StringUtils.toLowerCase(p.getFileName().toString()).endsWith(".jar"))
.map((p) -> ModFileParsers.newPluginInstance(SecureJar.from(p), this, PluginPlatformConstants.METADATA_FILE_NAME))
.map((p) -> ModFileParsers.newPluginInstance(this, p))
.filter(ModFile::identifyMods);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private PluginTarget(final String className, final String plugin) {
}

@Override
public <T> T loadMod(final IModInfo info, final ModFileScanData modFileScanData, final ModuleLayer moduleLayer) {
public <T> T loadMod(final IModInfo info, final ModFileScanData modFileScanData, final ModuleLayer gameLayer) {
// The following is adapted from FMLJavaModLanguageProvider.FMLModTarget

// This language class is loaded in the system level classloader - before the game even starts
Expand All @@ -93,7 +93,7 @@ public <T> T loadMod(final IModInfo info, final ModFileScanData modFileScanData,
"org.spongepowered.forge.launch.plugin.PluginModContainer", true, Thread.currentThread().getContextClassLoader());
this.logger.debug(Logging.LOADING, "Loading PluginModContainer from classloader {} - got {}", Thread.currentThread().getContextClassLoader(), pluginContainer.getClassLoader());
final Constructor<?> constructor = pluginContainer.getConstructor(IModInfo.class, String.class, ModFileScanData.class, ModuleLayer.class);
return (T) constructor.newInstance(info, className, modFileScanData, moduleLayer);
return (T) constructor.newInstance(info, className, modFileScanData, gameLayer);
}
// 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
package org.spongepowered.forge.launch.plugin;

import com.google.common.collect.MapMaker;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import org.apache.logging.log4j.LogManager;
Expand All @@ -36,6 +37,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

Expand Down Expand Up @@ -90,8 +92,9 @@ public Object instance() {
return this.modContainer.getMod();
}

private static final Map<ModContainer, ForgePluginContainer> containers = new MapMaker().weakKeys().makeMap();

public static ForgePluginContainer of(final ModContainer modContainer) {
// TODO SF 1.19.4, ensure unicity by storing references in a map
return new ForgePluginContainer(modContainer);
return containers.computeIfAbsent(modContainer, ForgePluginContainer::new);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
*/
package org.spongepowered.forge.launch.plugin;

import com.google.common.collect.ImmutableList;
import com.google.inject.Singleton;
import net.minecraftforge.fml.ModList;
import org.spongepowered.common.launch.plugin.SpongePluginManager;
import org.spongepowered.plugin.PluginContainer;

import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;

Expand All @@ -50,7 +50,8 @@ public Optional<PluginContainer> plugin(final String id) {

@Override
public Collection<PluginContainer> plugins() {
return Collections.emptyList(); // TODO SF 1.19.4, we can no longer use accessors on FML, is time for reflection?
// return Collections.unmodifiableCollection((Collection<PluginContainer>) (Object) ((ModListAccessor) ModList.get()).accessor$mods());
final ImmutableList.Builder<PluginContainer> builder = ImmutableList.builder();
ModList.get().forEachModInOrder(mod -> builder.add(ForgePluginContainer.of(mod)));
return builder.build();
}
}
Loading

0 comments on commit e7a3961

Please sign in to comment.