Finish up classloading system. Use ModJARURL to locate resources

and enable ModLauncher to use those instead. This allows all mods to load
within the scope of the game classloader, removing weird conflicts and
class discovery problems.
This commit is contained in:
cpw committed 2019-01-04 23:56:10 -05:00
1 parent 6baddc7e26
commit fd9c83b65f
21 files changed
+360 -144

No files matched your search

@@ -0,0 +1,37 @@
package net.minecraftforge.userdev;
import cpw.mods.modlauncher.api.ILaunchHandlerService;
import cpw.mods.modlauncher.api.ITransformingClassLoader;
import net.minecraftforge.api.distmarker.Dist;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.concurrent.Callable;
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
public class FMLUserdevClientLaunchProvider extends FMLUserdevLaunchProvider implements ILaunchHandlerService {
private static final Logger LOGGER = LogManager.getLogger();
@Override
public Dist getDist() {
return Dist.CLIENT;
}
@Override
public String name() {
return "fmluserdevclient";
}
@Override
public Callable<Void> launchService(String[] arguments, ITransformingClassLoader launchClassLoader)
{
return () -> {
LOGGER.debug(CORE, "Launching minecraft in {} with arguments {}", launchClassLoader, arguments);
super.beforeStart(launchClassLoader);
launchClassLoader.addTargetPackageFilter(getPackagePredicate());
Class.forName("net.minecraft.client.main.Main", true, launchClassLoader.getInstance()).getMethod("main", String[].class).invoke(null, (Object)arguments);
return null;
};
}
}
@@ -0,0 +1,106 @@
package net.minecraftforge.userdev;
import com.google.common.collect.ObjectArrays;
import com.google.common.collect.Streams;
import cpw.mods.modlauncher.api.IEnvironment;
import net.minecraftforge.fml.loading.FMLCommonLaunchHandler;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.LibraryFinder;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
public abstract class FMLUserdevLaunchProvider extends FMLCommonLaunchHandler {
private static final Logger LOGGER = LogManager.getLogger();
private Path forgeJar;
private Path mcJars;
@Override
public Path getForgePath(final String mcVersion, final String forgeVersion, final String forgeGroup) {
final URL forgePath = getClass().getClassLoader().getResource("net/minecraftforge/versions/forge/ForgeVersion.class");
if (forgePath == null) {
LOGGER.fatal(CORE, "Unable to locate forge on the classpath");
throw new RuntimeException("Unable to locate forge on the classpath");
}
forgeJar = LibraryFinder.findJarPathFor("ForgeVersion.class","forge", forgePath);
return forgeJar;
}
@SuppressWarnings("unchecked")
@Override
public void setup(final IEnvironment environment, final Map<String, ?> arguments) {
final List<String> mavenRoots = new ArrayList<>((List<String>) arguments.get("mavenRoots"));
final List<String> mods = new ArrayList<>((List<String>) arguments.get("mods"));
final String forgeVersion = (String) arguments.get("forgeVersion");
final String mcVersion = (String) arguments.get("mcVersion");
final String mcpVersion = (String) arguments.get("mcpVersion");
final String forgeGroup = (String) arguments.get("forgeGroup");
final String userdevVersion = mcVersion+"-"+forgeVersion+"_mapped_snapshot_"+mcpVersion;
int dirs = forgeGroup.split("\\.").length + 2;
Path fjroot = forgeJar;
do {
fjroot = fjroot.getParent();
} while (dirs-- > 0);
final String fjpath = fjroot.toString();
LOGGER.info(CORE, "Injecting forge as mod {} from maven path {}", userdevVersion, fjpath);
mavenRoots.add(fjpath);
mods.add(forgeGroup+":userdev:"+userdevVersion);
try {
final Enumeration<URL> resources = ClassLoader.getSystemClassLoader().getResources("META-INF/mods.toml");
final ArrayList<URL> modstoml = Collections.list(resources);
modstoml.stream().filter(u-> !u.getPath().contains("!"));
} catch (IOException e) {
LOGGER.fatal("Error trying to find resources", e);
throw new RuntimeException("wha?", e);
}
LOGGER.fatal(CORE, "Got mod coordinates {} from env", System.getenv("MOD_CLASSES"));
final List<Path> modClasses = Arrays.stream(System.getenv("MOD_CLASSES").split(File.pathSeparator)).
map(Paths::get).collect(Collectors.toList());
LOGGER.fatal(CORE, "Processed mod coordinates [{}]", modClasses.stream().map(Object::toString).collect(Collectors.joining(",")));
((Map<String, List<Pair<Path,List<Path>>>>) arguments).computeIfAbsent("explodedTargets", a->new ArrayList<>()).
add(Pair.of(modClasses.get(0), modClasses.subList(1, modClasses.size())));
// generics are gross yea?
((Map)arguments).put("mavenRoots", mavenRoots);
((Map)arguments).put("mods", mods);
}
@Override
protected void validatePaths(final Path forgePath, final Path[] mcPaths, final String forgeVersion, final String mcVersion, final String mcpVersion) {
}
@Override
public Path[] getMCPaths(final String mcVersion, final String mcpVersion, final String forgeVersion, final String forgeGroup) {
final URL mcDataPath = getClass().getClassLoader().getResource("assets/minecraft/lang/en_us.json");
if (mcDataPath == null) {
LOGGER.fatal(CORE, "Unable to locate minecraft data on the classpath");
throw new RuntimeException("Unable to locate minecraft data on the classpath");
}
mcJars = LibraryFinder.findJarPathFor("en_us.json","mcdata", mcDataPath);
return new Path[] {mcJars};
}
public Path[] identifyTransformationTargets()
{
return LibraryFinder.commonLibPaths(ObjectArrays.concat(FMLLoader.getForgePath(), FMLLoader.getMCPaths()));
}
}
@@ -0,0 +1,39 @@
package net.minecraftforge.userdev;
import cpw.mods.modlauncher.api.ILaunchHandlerService;
import cpw.mods.modlauncher.api.ITransformingClassLoader;
import net.minecraftforge.api.distmarker.Dist;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.concurrent.Callable;
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
public class FMLUserdevServerLaunchProvider extends FMLUserdevLaunchProvider implements ILaunchHandlerService {
private static final Logger LOGGER = LogManager.getLogger();
@Override
public Dist getDist() {
return Dist.DEDICATED_SERVER;
}
@Override
public String name() {
return "fmluserdevserver";
}
@Override
public Callable<Void> launchService(String[] arguments, ITransformingClassLoader launchClassLoader)
{
return () -> {
LOGGER.debug(CORE, "Launching minecraft in {} with arguments {}", launchClassLoader, arguments);
super.beforeStart(launchClassLoader);
launchClassLoader.addTargetPackageFilter(getPackagePredicate());
Thread.currentThread().setContextClassLoader(launchClassLoader.getInstance());
Class.forName("net.minecraft.server.MinecraftServer", true, launchClassLoader.getInstance()).getMethod("main", String[].class).invoke(null, (Object)arguments);
return null;
};
}
}
@@ -57,25 +57,33 @@ public class UserdevLauncher
throw new IllegalArgumentException("Environment variable 'assets' must be set to a valid path.");
}
if (target == null) {
throw new IllegalArgumentException("Environment variable 'target' must be set to 'fmldevclient' or 'fmldevserver'.");
throw new IllegalArgumentException("Environment variable 'target' must be set to 'fmluserdevclient' or 'fmluserdevserver'.");
}
if (Objects.equals(target,"fmldevclient")) {
String[] launchArgs = new String[]{
"--gameDir", ".",
"--launchTarget", target,
"--fml.forgeVersion", System.getenv("FORGE_VERSION"),
"--fml.mcpVersion", System.getenv("MCP_VERSION"),
"--fml.mcVersion", System.getenv("MC_VERSION"),
"--fml.forgeGroup", System.getenv("FORGE_GROUP")
};
if (Objects.equals(target,"fmluserdevclient")) {
hackNatives();
Launcher.main("--launchTarget", target,
"--gameDir", ".",
launchArgs = ObjectArrays.concat(launchArgs, new String[] {
"--accessToken", "blah",
"--version", "FMLDev",
"--assetIndex", "1.13",
"--assetsDir", assets,
"--userProperties", "{}");
} else if (Objects.equals(target, "fmldevserver")) {
String[] launchargs = ObjectArrays.concat(new String[] {"--launchTarget", target,
"--gameDir", "."}, args, String.class);
Launcher.main(launchargs);
"--userProperties", "{}"
}, String.class);
} else if (Objects.equals(target, "fmluserdevserver")) {
// we're good
} else {
throw new IllegalArgumentException("Unknown value for 'target' property: " + target);
}
Launcher.main(launchArgs);
Thread.sleep(10000);
}
@@ -0,0 +1,2 @@
net.minecraftforge.userdev.FMLUserdevClientLaunchProvider
net.minecraftforge.userdev.FMLUserdevServerLaunchProvider
@@ -1 +0,0 @@
net.minecraftforge.userdev.ClasspathLocator