separated fmllauncher code from main forge mod code. This enables much
stronger classloader separation between the two sides. Forge now loads as a regular mod. Still needs a bunch of debugging, but structure looks good and game loads in forge dev.
This commit is contained in:
parent
558e1d2fb0
commit
48846bc0ba
72 changed files with 693 additions and 755 deletions
59
build.gradle
59
build.gradle
|
@ -91,9 +91,19 @@ project(':forge') {
|
|||
|
||||
compileJava.sourceCompatibility = compileJava.targetCompatibility = sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
|
||||
group = 'net.minecraftforge.test' //TODO: remove test when we finish patches and want users to find it
|
||||
|
||||
|
||||
sourceSets {
|
||||
fmllauncher {
|
||||
java {
|
||||
srcDir "$rootDir/src/fmllauncher/java"
|
||||
}
|
||||
resources {
|
||||
srcDir "$rootDir/src/fmllauncher/resources"
|
||||
}
|
||||
}
|
||||
main {
|
||||
compileClasspath += sourceSets.fmllauncher.runtimeClasspath
|
||||
runtimeClasspath += sourceSets.fmllauncher.runtimeClasspath
|
||||
java {
|
||||
srcDir "$rootDir/src/main/java"
|
||||
}
|
||||
|
@ -210,6 +220,21 @@ project(':forge') {
|
|||
installer 'java3d:vecmath:1.5.2'
|
||||
installer 'org.apache.logging.log4j:log4j-api:2.11.1'
|
||||
installer 'org.apache.logging.log4j:log4j-core:2.11.1'
|
||||
fmllauncherImplementation 'org.ow2.asm:asm:6.2'
|
||||
fmllauncherImplementation 'org.ow2.asm:asm-commons:6.2'
|
||||
fmllauncherImplementation 'org.ow2.asm:asm-tree:6.2'
|
||||
fmllauncherImplementation 'cpw.mods:modlauncher:0.1.0'
|
||||
fmllauncherImplementation 'net.minecraftforge:accesstransformers:0.10+:shadowed'
|
||||
fmllauncherImplementation 'net.minecraftforge:eventbus:0.1+:service'
|
||||
fmllauncherImplementation 'net.minecraftforge:forgespi:0.1+'
|
||||
fmllauncherImplementation 'net.minecraftforge:coremods:0.1+'
|
||||
fmllauncherImplementation 'com.electronwill.night-config:core:3.4.0'
|
||||
fmllauncherImplementation 'com.electronwill.night-config:toml:3.4.0'
|
||||
fmllauncherImplementation 'org.apache.maven:maven-artifact:3.5.3'
|
||||
fmllauncherImplementation 'org.apache.logging.log4j:log4j-api:2.11.1'
|
||||
fmllauncherImplementation 'org.apache.logging.log4j:log4j-core:2.11.1'
|
||||
fmllauncherImplementation 'com.google.guava:guava:21.0'
|
||||
fmllauncherImplementation 'com.google.code.gson:gson:2.8.0'
|
||||
}
|
||||
|
||||
task runclient(type: JavaExec, dependsOn: [":forge:downloadAssets", ":forge:extractNatives"]) {
|
||||
|
@ -644,6 +669,37 @@ project(':forge') {
|
|||
'Implementation-Version': MCP_VERSION,
|
||||
'Implementation-Vendor': 'Forge'
|
||||
] as LinkedHashMap, 'net/minecraftforge/versions/mcp/')
|
||||
// manifest entry for FML @Mod
|
||||
manifest.attributes([
|
||||
'Specification-Title': 'Mod Language Provider',
|
||||
'Specification-Vendor': 'Forge Development LLC',
|
||||
'Specification-Version': '1',
|
||||
'Implementation-Title': 'FML Java Mod',
|
||||
'Implementation-Version': SPEC_VERSION,
|
||||
'Implementation-Vendor': 'Forge'
|
||||
] as LinkedHashMap, 'net/minecraftforge/fml/javafmlmod/')
|
||||
}
|
||||
}
|
||||
|
||||
task fmllauncherJar(type: Jar) {
|
||||
from sourceSets.fmllauncher.output
|
||||
doFirst {
|
||||
manifest.attributes([
|
||||
'Specification-Title' : 'Forge',
|
||||
'Specification-Vendor' : 'Forge Development LLC',
|
||||
'Specification-Version' : SPEC_VERSION,
|
||||
'Implementation-Title' : project.group,
|
||||
'Implementation-Version': project.version.substring(MC_VERSION.length() + 1),
|
||||
'Implementation-Vendor' : 'Forge Development LLC'
|
||||
] as LinkedHashMap, 'net/minecraftforge/versions/forge/')
|
||||
manifest.attributes([
|
||||
'Specification-Title' : 'Minecraft',
|
||||
'Specification-Vendor' : 'Mojang',
|
||||
'Specification-Version' : MC_VERSION,
|
||||
'Implementation-Title' : 'MCP',
|
||||
'Implementation-Version': MCP_VERSION,
|
||||
'Implementation-Vendor' : 'Forge'
|
||||
] as LinkedHashMap, 'net/minecraftforge/versions/mcp/')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -811,6 +867,7 @@ project(':forge') {
|
|||
artifact makeMdk
|
||||
artifact userdevJar
|
||||
artifact sourcesJar
|
||||
artifact fmllauncherJar
|
||||
|
||||
pom {
|
||||
name = 'forge'
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package net.minecraftforge.fml.language;
|
||||
|
||||
public interface ILifecycleEvent<R extends ILifecycleEvent<?>> {
|
||||
@SuppressWarnings("unchecked")
|
||||
default R concrete() {
|
||||
return (R) this;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,9 +19,8 @@
|
|||
|
||||
package net.minecraftforge.fml.language;
|
||||
|
||||
import net.minecraftforge.fml.LifecycleEventProvider;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Loaded as a ServiceLoader, from the classpath. ExtensionPoint are loaded from
|
||||
|
@ -35,8 +34,7 @@ public interface IModLanguageProvider
|
|||
|
||||
Consumer<ModFileScanData> getFileVisitor();
|
||||
|
||||
void preLifecycleEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent);
|
||||
void postLifecycleEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent);
|
||||
<R extends ILifecycleEvent<R>> void consumeLifecycleEvent(Supplier<R> consumeEvent);
|
||||
|
||||
interface IModLanguageLoader {
|
||||
<T> T loadMod(IModInfo info, ClassLoader modClassLoader, ModFileScanData modFileScanResults);
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import com.google.common.collect.ObjectArrays;
|
||||
import cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
|
@ -26,38 +27,33 @@ import net.minecraftforge.api.distmarker.Dist;
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URISyntaxException;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public class FMLDevClientLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
public class FMLClientLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "fmldevclient";
|
||||
return "fmlclient";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path[] identifyTransformationTargets()
|
||||
{
|
||||
return super.commonLibPaths(new Path[] {getForgePath()});
|
||||
return LibraryFinder.commonLibPaths(ObjectArrays.concat(FMLLoader.getForgePath(), FMLLoader.getMCPaths()));
|
||||
}
|
||||
|
||||
@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);
|
||||
|
@ -66,9 +62,7 @@ public class FMLDevClientLaunchProvider extends FMLCommonLaunchHandler implement
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setup(IEnvironment environment)
|
||||
{
|
||||
LOGGER.debug(CORE, "No jar creation necessary. Launch is dev environment");
|
||||
public void setup(final IEnvironment environment, final Map<String, ?> arguments) {
|
||||
}
|
||||
|
||||
@Override
|
|
@ -26,17 +26,12 @@ import net.minecraftforge.api.distmarker.Dist;
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
|
||||
public abstract class FMLCommonLaunchHandler
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
@ -49,57 +44,27 @@ public abstract class FMLCommonLaunchHandler
|
|||
"net.minecraftforge.eventbus.", "net.minecraftforge.api."
|
||||
);
|
||||
|
||||
private Path forgePath;
|
||||
|
||||
protected Predicate<String> getPackagePredicate() {
|
||||
return cn -> SKIPPACKAGES.stream().noneMatch(cn::startsWith);
|
||||
}
|
||||
|
||||
public void setup(final IEnvironment environment)
|
||||
public Path getForgePath(final String mcVersion, final String forgeVersion) {
|
||||
return LibraryFinder.getForgeLibraryPath(mcVersion, forgeVersion);
|
||||
}
|
||||
|
||||
public Path[] getMCPaths(final String mcVersion, final String forgeVersion) {
|
||||
return LibraryFinder.getMCPaths(mcVersion, forgeVersion, getDist().isClient() ? "client" : "server");
|
||||
}
|
||||
|
||||
public void setup(final IEnvironment environment, final Map<String, ?> arguments)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Path findLibsPath() {
|
||||
final Path asm = findJarPathFor("org/objectweb/asm/Opcodes.class", "asm");
|
||||
// go up SIX parents to find the libs dir
|
||||
final Path libs = asm.getParent().getParent().getParent().getParent().getParent().getParent();
|
||||
LOGGER.debug(CORE, "Found probable library path {}", libs);
|
||||
return libs;
|
||||
}
|
||||
Path findJarPathFor(final String className, final String jarName) {
|
||||
final URL resource = getClass().getClassLoader().getResource(className);
|
||||
try {
|
||||
Path path;
|
||||
final URI uri = resource.toURI();
|
||||
if (uri.getRawSchemeSpecificPart().contains("!")) {
|
||||
path = Paths.get(new URI(uri.getRawSchemeSpecificPart().split("!")[0]));
|
||||
} else {
|
||||
path = Paths.get(new URI("file://"+uri.getRawSchemeSpecificPart().substring(0, uri.getRawSchemeSpecificPart().length()-className.length())));
|
||||
}
|
||||
LOGGER.debug(CORE, "Found JAR {} at path {}", jarName, path.toString());
|
||||
return path;
|
||||
} catch (URISyntaxException e) {
|
||||
LOGGER.error(CORE, "Failed to find JAR for class {} - {}", className, jarName);
|
||||
throw new RuntimeException("Unable to locate "+className+" - "+jarName, e);
|
||||
}
|
||||
}
|
||||
Path[] commonLibPaths(Path[] extras) {
|
||||
final Path realms = findJarPathFor("com/mojang/realmsclient/RealmsVersion.class", "realms");
|
||||
return ObjectArrays.concat(extras, realms);
|
||||
}
|
||||
|
||||
Path getForgePath() {
|
||||
if (forgePath == null) {
|
||||
forgePath = findJarPathFor("net/minecraftforge/versions/forge/ForgeVersion.class", "forge");
|
||||
LOGGER.debug(CORE, "Found forge path {}", forgePath);
|
||||
}
|
||||
return forgePath;
|
||||
}
|
||||
public abstract Dist getDist();
|
||||
|
||||
protected void beforeStart(ITransformingClassLoader launchClassLoader)
|
||||
{
|
||||
FMLLoader.beforeStart(launchClassLoader, getForgePath());
|
||||
FMLLoader.beforeStart(launchClassLoader);
|
||||
}
|
||||
}
|
|
@ -23,14 +23,13 @@ import com.electronwill.nightconfig.core.ConfigSpec;
|
|||
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
|
||||
import com.electronwill.nightconfig.core.io.WritingMode;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public class FMLConfig
|
||||
{
|
||||
|
@ -41,11 +40,6 @@ public class FMLConfig
|
|||
configSpec.defineInList("side", Dist.CLIENT.name(), Arrays.stream(Dist.values()).map(Enum::name).collect(Collectors.toList()));
|
||||
configSpec.defineInRange("maxframerate", 60, 10, 120);
|
||||
configSpec.defineInRange("minframerate", 60, 10, 120);
|
||||
/* Tests that we know work and shouldn't be done in runtime.
|
||||
configSpec.defineInList(Arrays.asList("tasty","flavour"), Dist.CLIENT.name(), Arrays.stream(Dist.values()).map(Enum::name).collect(Collectors.toList()));
|
||||
configSpec.defineInList(Arrays.asList("tasty","teaser"), Dist.CLIENT.name(), Arrays.stream(Dist.values()).map(Enum::name).collect(Collectors.toList()));
|
||||
configSpec.define("longstring", StringUtils.repeat("AAAA", 10000), s->s!=null && ((String)s).length()>0);
|
||||
*/
|
||||
}
|
||||
|
||||
private CommentedFileConfig configData;
|
|
@ -23,48 +23,52 @@ import cpw.mods.modlauncher.api.IEnvironment;
|
|||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.relauncher.libraries.LibraryManager;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.versions.mcp.MCPVersion;
|
||||
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.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class FMLClientLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public class FMLDevClientLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private Path compiledClasses;
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "fmlclient";
|
||||
return "fmldevclient";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path[] identifyTransformationTargets()
|
||||
{
|
||||
Path libsPath = findLibsPath();
|
||||
Path patchedBinariesPath = libsPath.resolve(Paths.get(ForgeVersion.getGroup().replace('.', File.separatorChar), "forge", MCPVersion.getMCVersion() + "-" + ForgeVersion.getVersion(), "forge-" + MCPVersion.getMCVersion() + "-" + ForgeVersion.getVersion() + "-client.jar"));
|
||||
Path srgMcPath = libsPath.resolve(Paths.get("net","minecraft", "client", MCPVersion.getMCPandMCVersion(), "client-"+MCPVersion.getMCPandMCVersion()+"-srg.jar"));
|
||||
LOGGER.info("SRG MC at {} is {}", srgMcPath.toString(), Files.exists(srgMcPath) ? "present" : "missing");
|
||||
LOGGER.info("Forge patches at {} is {}", patchedBinariesPath.toString(), Files.exists(patchedBinariesPath) ? "present" : "missing");
|
||||
LOGGER.info("Forge at {} is {}", getForgePath().toString(), Files.exists(getForgePath()) ? "present" : "missing");
|
||||
if (!(Files.exists(srgMcPath) && Files.exists(patchedBinariesPath) && Files.exists(getForgePath()))) {
|
||||
throw new RuntimeException("Failed to find patched jars");
|
||||
}
|
||||
return super.commonLibPaths(new Path[] {getForgePath(), patchedBinariesPath, srgMcPath});
|
||||
return LibraryFinder.commonLibPaths(new Path[] {FMLLoader.getForgePath()});
|
||||
}
|
||||
|
||||
public Path getForgePath(final String mcVersion, final String forgeVersion) {
|
||||
// In forge dev, we just find the path for ForgeVersion for everything
|
||||
compiledClasses = LibraryFinder.findJarPathFor("net/minecraftforge/versions/forge/ForgeVersion.class", "forge");
|
||||
return compiledClasses;
|
||||
}
|
||||
|
||||
public Path[] getMCPaths(final String mcVersion, final String forgeVersion) {
|
||||
// In forge dev, we just find the path for ForgeVersion for everything
|
||||
return new Path[] { compiledClasses, compiledClasses };
|
||||
}
|
||||
|
||||
@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);
|
||||
|
@ -72,8 +76,15 @@ public class FMLClientLaunchProvider extends FMLCommonLaunchHandler implements I
|
|||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void setup(final IEnvironment environment) {
|
||||
public void setup(IEnvironment environment, final Map<String, ?> arguments)
|
||||
{
|
||||
LOGGER.debug(CORE, "No jar creation necessary. Launch is dev environment");
|
||||
// we're injecting forge into the exploded dir finder
|
||||
final Path forgemodstoml = LibraryFinder.findJarPathFor("META-INF/mods.toml", "forgemodstoml");
|
||||
((Map<String, List<Pair<Path,Path>>>) arguments).computeIfAbsent("explodedTargets", a->new ArrayList<>()).
|
||||
add(Pair.of(compiledClasses, forgemodstoml));
|
||||
}
|
||||
|
||||
@Override
|
|
@ -26,16 +26,11 @@ import net.minecraftforge.api.distmarker.Dist;
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public class FMLDevServerLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
{
|
||||
|
@ -50,7 +45,7 @@ public class FMLDevServerLaunchProvider extends FMLCommonLaunchHandler implement
|
|||
@Override
|
||||
public Path[] identifyTransformationTargets()
|
||||
{
|
||||
return super.commonLibPaths(new Path[] { getForgePath() });
|
||||
return LibraryFinder.commonLibPaths(new Path[] { FMLLoader.getForgePath() });
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -67,7 +62,7 @@ public class FMLDevServerLaunchProvider extends FMLCommonLaunchHandler implement
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setup(IEnvironment environment)
|
||||
public void setup(IEnvironment environment, final Map<String, ?> arguments)
|
||||
{
|
||||
LOGGER.debug(CORE, "No jar creation necessary. Launch is dev environment");
|
||||
}
|
|
@ -26,7 +26,6 @@ import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
|||
import cpw.mods.modlauncher.api.IncompatibleEnvironmentException;
|
||||
import cpw.mods.modlauncher.serviceapi.ILaunchPluginService;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModDiscoverer;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
|
@ -36,16 +35,15 @@ import org.apache.logging.log4j.Logger;
|
|||
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.SCAN;
|
||||
|
||||
public class FMLLoader
|
||||
{
|
||||
|
@ -61,10 +59,14 @@ public class FMLLoader
|
|||
private static RuntimeDistCleaner runtimeDistCleaner;
|
||||
private static Path gamePath;
|
||||
private static Path forgePath;
|
||||
private static Path[] mcPaths;
|
||||
static String forgeVersion;
|
||||
static String mcVersion;
|
||||
private static Predicate<String> classLoaderExclusions;
|
||||
|
||||
static void onInitialLoad(IEnvironment environment, Set<String> otherServices) throws IncompatibleEnvironmentException
|
||||
{
|
||||
final String version = ForgeVersion.getVersion();
|
||||
final String version = LauncherVersion.getVersion();
|
||||
LOGGER.debug(CORE,"FML {} loading", version);
|
||||
final Package modLauncherPackage = ITransformationService.class.getPackage();
|
||||
LOGGER.debug(CORE,"FML found ModLauncher version : {}", modLauncherPackage.getImplementationVersion());
|
||||
|
@ -110,11 +112,9 @@ public class FMLLoader
|
|||
coreModProvider = coreModProviders.get(0);
|
||||
final Package coremodPackage = coreModProvider.getClass().getPackage();
|
||||
LOGGER.debug(CORE,"FML found CoreMod version : {}", coremodPackage.getImplementationVersion());
|
||||
|
||||
languageLoadingProvider = new LanguageLoadingProvider();
|
||||
}
|
||||
|
||||
static void setupLaunchHandler(final IEnvironment environment)
|
||||
static void setupLaunchHandler(final IEnvironment environment, final Map<String, ?> arguments)
|
||||
{
|
||||
final String launchTarget = environment.getProperty(IEnvironment.Keys.LAUNCHTARGET.get()).orElse("MISSING");
|
||||
final Optional<ILaunchHandlerService> launchHandler = environment.findLaunchHandler(launchTarget);
|
||||
|
@ -131,14 +131,36 @@ public class FMLLoader
|
|||
gamePath = environment.getProperty(IEnvironment.Keys.GAMEDIR.get()).orElse(Paths.get(".").toAbsolutePath());
|
||||
|
||||
FMLCommonLaunchHandler commonLaunchHandler = (FMLCommonLaunchHandler)launchHandler.get();
|
||||
commonLaunchHandler.setup(environment);
|
||||
dist = commonLaunchHandler.getDist();
|
||||
|
||||
mcVersion = (String) arguments.get("mcVersion");
|
||||
forgeVersion = (String) arguments.get("forgeVersion");
|
||||
forgePath = commonLaunchHandler.getForgePath(mcVersion, forgeVersion);
|
||||
mcPaths = commonLaunchHandler.getMCPaths(mcVersion, forgeVersion);
|
||||
|
||||
if (!Files.exists(forgePath)) {
|
||||
LOGGER.fatal(CORE, "Failed to find forge version {} for MC {} at {}", forgeVersion, mcVersion, forgePath);
|
||||
throw new RuntimeException("Missing forge!");
|
||||
}
|
||||
if (!Files.exists(mcPaths[0])) {
|
||||
LOGGER.fatal(CORE, "Failed to find deobfuscated Minecraft version {} at {}", mcVersion, mcPaths[0]);
|
||||
throw new RuntimeException("Missing deobfuscated minecraft!");
|
||||
}
|
||||
if (!Files.exists(mcPaths[1])) {
|
||||
LOGGER.fatal(CORE, "Failed to find forge patches for Minecraft version {} at {}", mcVersion, mcPaths[1]);
|
||||
throw new RuntimeException("Missing forge patches!");
|
||||
}
|
||||
|
||||
commonLaunchHandler.setup(environment, arguments);
|
||||
classLoaderExclusions = commonLaunchHandler.getPackagePredicate();
|
||||
languageLoadingProvider = new LanguageLoadingProvider();
|
||||
|
||||
runtimeDistCleaner.getExtension().accept(dist);
|
||||
}
|
||||
public static void beginModScan()
|
||||
public static void beginModScan(final Map<String,?> arguments)
|
||||
{
|
||||
LOGGER.debug(SCAN,"Scanning for Mod Locators");
|
||||
modDiscoverer = new ModDiscoverer();
|
||||
modDiscoverer = new ModDiscoverer(arguments);
|
||||
final BackgroundScanHandler backgroundScanHandler = modDiscoverer.discoverMods();
|
||||
loadingModList = backgroundScanHandler.getLoadingModList();
|
||||
}
|
||||
|
@ -152,6 +174,10 @@ public class FMLLoader
|
|||
return languageLoadingProvider;
|
||||
}
|
||||
|
||||
static ModDiscoverer getModDiscoverer() {
|
||||
return modDiscoverer;
|
||||
}
|
||||
|
||||
public static void loadAccessTransformer()
|
||||
{
|
||||
final URL resource = FMLLoader.class.getClassLoader().getResource("forge_at.cfg");
|
||||
|
@ -181,10 +207,9 @@ public class FMLLoader
|
|||
return dist;
|
||||
}
|
||||
|
||||
public static void beforeStart(ITransformingClassLoader launchClassLoader, Path forgePath)
|
||||
public static void beforeStart(ITransformingClassLoader launchClassLoader)
|
||||
{
|
||||
FMLLoader.launchClassLoader = launchClassLoader.getInstance();
|
||||
FMLLoader.forgePath = forgePath;
|
||||
}
|
||||
|
||||
|
||||
|
@ -207,4 +232,12 @@ public class FMLLoader
|
|||
public static Path getForgePath() {
|
||||
return forgePath;
|
||||
}
|
||||
|
||||
public static Path[] getMCPaths() {
|
||||
return mcPaths;
|
||||
}
|
||||
|
||||
public static Predicate<String> getClassLoaderExclusions() {
|
||||
return classLoaderExclusions;
|
||||
}
|
||||
}
|
|
@ -20,17 +20,14 @@
|
|||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import cpw.mods.modlauncher.api.IEnvironment;
|
||||
import net.minecraftforge.fml.FileUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public enum FMLPaths
|
||||
{
|
|
@ -19,19 +19,16 @@
|
|||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import com.google.common.collect.ObjectArrays;
|
||||
import cpw.mods.modlauncher.api.IEnvironment;
|
||||
import cpw.mods.modlauncher.api.ILaunchHandlerService;
|
||||
import cpw.mods.modlauncher.api.ITransformingClassLoader;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.versions.mcp.MCPVersion;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class FMLServerLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
|
||||
|
@ -47,16 +44,7 @@ public class FMLServerLaunchProvider extends FMLCommonLaunchHandler implements I
|
|||
@Override
|
||||
public Path[] identifyTransformationTargets()
|
||||
{
|
||||
Path libsPath = findLibsPath();
|
||||
Path patchedBinariesPath = libsPath.resolve(Paths.get(ForgeVersion.getGroup().replace('.', File.separatorChar), "forge", MCPVersion.getMCVersion() + "-" + ForgeVersion.getVersion(), "forge-" + MCPVersion.getMCVersion() + "-" + ForgeVersion.getVersion() + "-server.jar"));
|
||||
Path srgMcPath = libsPath.resolve(Paths.get("net","minecraft", "server", MCPVersion.getMCPandMCVersion(), "server-"+MCPVersion.getMCPandMCVersion()+"-srg.jar"));
|
||||
LOGGER.info("SRG MC at {} is {}", srgMcPath.toString(), Files.exists(srgMcPath) ? "present" : "missing");
|
||||
LOGGER.info("Forge patches at {} is {}", patchedBinariesPath.toString(), Files.exists(patchedBinariesPath) ? "present" : "missing");
|
||||
LOGGER.info("Forge at {} is {}", getForgePath().toString(), Files.exists(getForgePath()) ? "present" : "missing");
|
||||
if (!(Files.exists(srgMcPath) && Files.exists(patchedBinariesPath) && Files.exists(getForgePath()))) {
|
||||
throw new RuntimeException("Failed to find patched jars");
|
||||
}
|
||||
return new Path[] {getForgePath(), patchedBinariesPath, srgMcPath};
|
||||
return ObjectArrays.concat(FMLLoader.getForgePath(), FMLLoader.getMCPaths());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,7 +59,7 @@ public class FMLServerLaunchProvider extends FMLCommonLaunchHandler implements I
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setup(final IEnvironment environment) {
|
||||
public void setup(final IEnvironment environment, final Map<String, ?> arguments) {
|
||||
}
|
||||
|
||||
@Override
|
|
@ -29,12 +29,10 @@ import org.apache.logging.log4j.LogManager;
|
|||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public class FMLServiceProvider implements ITransformationService
|
||||
{
|
||||
|
@ -42,8 +40,14 @@ public class FMLServiceProvider implements ITransformationService
|
|||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private ArgumentAcceptingOptionSpec<String> modsOption;
|
||||
private ArgumentAcceptingOptionSpec<String> modListsOption;
|
||||
private ArgumentAcceptingOptionSpec<String> mavenRootsOption;
|
||||
private ArgumentAcceptingOptionSpec<String> forgeOption;
|
||||
private ArgumentAcceptingOptionSpec<String> mcOption;
|
||||
private List<String> modsArgumentList;
|
||||
private List<String> modListsArgumentList;
|
||||
private List<String> mavenRootsArgumentList;
|
||||
private String targetForgeVersion;
|
||||
private String targetMcVersion;
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
|
@ -58,10 +62,16 @@ public class FMLServiceProvider implements ITransformationService
|
|||
FMLPaths.setup(environment);
|
||||
LOGGER.debug(CORE,"Loading configuration");
|
||||
FMLConfig.load();
|
||||
final Map<String, Object> arguments = new HashMap<>();
|
||||
arguments.put("modLists", modListsArgumentList);
|
||||
arguments.put("mods", modsArgumentList);
|
||||
arguments.put("mavenRoots", mavenRootsArgumentList);
|
||||
arguments.put("forgeVersion", targetForgeVersion);
|
||||
arguments.put("mcVersion", targetMcVersion);
|
||||
LOGGER.debug(CORE, "Preparing launch handler");
|
||||
FMLLoader.setupLaunchHandler(environment);
|
||||
FMLLoader.setupLaunchHandler(environment, arguments);
|
||||
LOGGER.debug(CORE,"Initiating mod scan");
|
||||
FMLLoader.beginModScan();
|
||||
FMLLoader.beginModScan(arguments);
|
||||
LOGGER.debug(CORE, "Loading access transformers");
|
||||
FMLLoader.loadAccessTransformer();
|
||||
}
|
||||
|
@ -75,8 +85,11 @@ public class FMLServiceProvider implements ITransformationService
|
|||
@Override
|
||||
public void arguments(BiFunction<String, String, OptionSpecBuilder> argumentBuilder)
|
||||
{
|
||||
forgeOption = argumentBuilder.apply("forgeVersion", "Forge Version number").withRequiredArg().ofType(String.class).required();
|
||||
mcOption = argumentBuilder.apply("mcVersion", "Minecraft Version number").withRequiredArg().ofType(String.class).required();
|
||||
modsOption = argumentBuilder.apply("mods", "List of mods to add").withRequiredArg().ofType(String.class).withValuesSeparatedBy(",");
|
||||
modListsOption = argumentBuilder.apply("modLists", "JSON modlists").withRequiredArg().ofType(String.class).withValuesSeparatedBy(",");
|
||||
mavenRootsOption = argumentBuilder.apply("mavenRoots", "Maven root directories").withRequiredArg().ofType(String.class).withValuesSeparatedBy(",");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -84,6 +97,9 @@ public class FMLServiceProvider implements ITransformationService
|
|||
{
|
||||
modsArgumentList = option.values(modsOption);
|
||||
modListsArgumentList = option.values(modListsOption);
|
||||
mavenRootsArgumentList = option.values(mavenRootsOption);
|
||||
targetForgeVersion = option.value(forgeOption);
|
||||
targetMcVersion = option.value(mcOption);
|
||||
}
|
||||
|
||||
@Nonnull
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml;
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
@ -27,7 +27,7 @@ import java.nio.file.FileAlreadyExistsException;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public class FileUtils
|
||||
{
|
|
@ -0,0 +1,39 @@
|
|||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Finds Version data from a package, with possible default values
|
||||
*/
|
||||
public class JarVersionLookupHandler {
|
||||
public static Optional<String> getImplementationVersion(final String pkgName) {
|
||||
// Note that with Java 9, you'll probably want the module's version data, hence pulling this out
|
||||
final String pkgVersion = Package.getPackage(pkgName).getImplementationVersion();
|
||||
return Optional.ofNullable(pkgVersion);
|
||||
}
|
||||
|
||||
public static Optional<String> getSpecificationVersion(final String pkgName) {
|
||||
// Note that with Java 9, you'll probably want the module's version data, hence pulling this out
|
||||
final String pkgVersion = Package.getPackage(pkgName).getSpecificationVersion();
|
||||
return Optional.ofNullable(pkgVersion);
|
||||
}
|
||||
|
||||
public static Optional<String> getImplementationVersion(final Class<?> clazz) {
|
||||
// With java 9 we'll use the module's version if it exists in preference.
|
||||
final String pkgVersion = clazz.getPackage().getImplementationVersion();
|
||||
return Optional.ofNullable(pkgVersion);
|
||||
}
|
||||
|
||||
public static Optional<String> getImplementationTitle(final Class<?> clazz) {
|
||||
// With java 9 we'll use the module's version if it exists in preference.
|
||||
final String pkgVersion = clazz.getPackage().getImplementationTitle();
|
||||
return Optional.ofNullable(pkgVersion);
|
||||
}
|
||||
|
||||
|
||||
public static Optional<String> getSpecificationVersion(final Class<?> clazz) {
|
||||
// With java 9 we'll use the module's version if it exists in preference.
|
||||
final String pkgVersion = clazz.getPackage().getSpecificationVersion();
|
||||
return Optional.ofNullable(pkgVersion);
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml;
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.fml.language.IModLanguageProvider;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ExplodedDirectoryLocator;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
|
@ -29,12 +28,16 @@ import org.apache.maven.artifact.versioning.ArtifactVersion;
|
|||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public class LanguageLoadingProvider
|
||||
{
|
||||
|
@ -73,13 +76,20 @@ public class LanguageLoadingProvider
|
|||
serviceLoader.forEach(languageProviders::add);
|
||||
|
||||
languageProviders.forEach(lp -> {
|
||||
final Package pkg = lp.getClass().getPackage();
|
||||
String implementationVersion = pkg.getImplementationVersion();
|
||||
if (implementationVersion == null) {
|
||||
implementationVersion = ForgeVersion.getSpec();
|
||||
final Path lpPath;
|
||||
try {
|
||||
lpPath = Paths.get(lp.getClass().getProtectionDomain().getCodeSource().getLocation().toURI());
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException("Huh?", e);
|
||||
}
|
||||
LOGGER.debug(CORE, "Found system classpath language provider {}, version {}", lp.name(), implementationVersion);
|
||||
languageProviderMap.put(lp.name(), new ModLanguageWrapper(lp, new DefaultArtifactVersion(implementationVersion)));
|
||||
Optional<String> implementationVersion = JarVersionLookupHandler.getImplementationVersion(lp.getClass());
|
||||
String impl = implementationVersion.orElse(Files.isDirectory(lpPath) ? FMLLoader.forgeVersion.split("\\.")[0] : null);
|
||||
if (impl == null) {
|
||||
LOGGER.fatal(CORE, "Found unversioned system classpath language provider {}", lp.name());
|
||||
throw new RuntimeException("Failed to find implementation version for language provider "+ lp.name());
|
||||
}
|
||||
LOGGER.debug(CORE, "Found system classpath language provider {}, version {}", lp.name(), impl);
|
||||
languageProviderMap.put(lp.name(), new ModLanguageWrapper(lp, new DefaultArtifactVersion(impl)));
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public class LauncherVersion {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final String launcherVersion;
|
||||
|
||||
static {
|
||||
String vers = JarVersionLookupHandler.getImplementationVersion(LauncherVersion.class).orElse(System.getProperty("fmllauncher.version"));
|
||||
if (vers == null) throw new RuntimeException("Missing FMLLauncher version, cannot continue");
|
||||
launcherVersion = vers;
|
||||
LOGGER.info(CORE, "Found FMLLauncher version {}", launcherVersion);
|
||||
}
|
||||
|
||||
public static String getVersion()
|
||||
{
|
||||
return launcherVersion;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import com.google.common.collect.ObjectArrays;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public class LibraryFinder {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static Path libsPath;
|
||||
static Path findLibsPath() {
|
||||
if (libsPath == null) {
|
||||
final Path asm = findJarPathFor("org/objectweb/asm/Opcodes.class", "asm");
|
||||
// go up SIX parents to find the libs dir
|
||||
final Path libs = asm.getParent().getParent().getParent().getParent().getParent().getParent();
|
||||
LOGGER.debug(CORE, "Found probable library path {}", libs);
|
||||
libsPath = libs;
|
||||
}
|
||||
return libsPath;
|
||||
}
|
||||
|
||||
static Path findJarPathFor(final String className, final String jarName) {
|
||||
final URL resource = LibraryFinder.class.getClassLoader().getResource(className);
|
||||
try {
|
||||
Path path;
|
||||
final URI uri = resource.toURI();
|
||||
if (uri.getRawSchemeSpecificPart().contains("!")) {
|
||||
path = Paths.get(new URI(uri.getRawSchemeSpecificPart().split("!")[0]));
|
||||
} else {
|
||||
path = Paths.get(new URI("file://"+uri.getRawSchemeSpecificPart().substring(0, uri.getRawSchemeSpecificPart().length()-className.length())));
|
||||
}
|
||||
LOGGER.debug(CORE, "Found JAR {} at path {}", jarName, path.toString());
|
||||
return path;
|
||||
} catch (NullPointerException | URISyntaxException e) {
|
||||
LOGGER.error(CORE, "Failed to find JAR for class {} - {}", className, jarName);
|
||||
throw new RuntimeException("Unable to locate "+className+" - "+jarName, e);
|
||||
}
|
||||
}
|
||||
static Path[] commonLibPaths(Path[] extras) {
|
||||
final Path realms = findJarPathFor("com/mojang/realmsclient/RealmsVersion.class", "realms");
|
||||
return ObjectArrays.concat(extras, realms);
|
||||
}
|
||||
|
||||
static Path getForgeLibraryPath(final String mcVersion, final String forgeVersion) {
|
||||
Path forgePath = findLibsPath().resolve(MavenCoordinateResolver.get("net.minecraftforge", "forge", "", "", mcVersion+"-"+forgeVersion));
|
||||
LOGGER.debug(CORE, "Found forge path {} is {}", forgePath, pathStatus(forgePath));
|
||||
return forgePath;
|
||||
}
|
||||
|
||||
static String pathStatus(final Path path) {
|
||||
return Files.exists(path) ? "present" : "missing";
|
||||
}
|
||||
static Path[] getMCPaths(final String mcVersion, final String forgeVersion, final String type) {
|
||||
Path srgMcPath = findLibsPath().resolve(MavenCoordinateResolver.get("net.minecraft", type, "", "srg", mcVersion));
|
||||
Path patchedBinariesPath = findLibsPath().resolve(MavenCoordinateResolver.get("net.minecraftforge", "forge", "", type, mcVersion+"-"+forgeVersion));
|
||||
LOGGER.info("SRG MC at {} is {}", srgMcPath.toString(), pathStatus(srgMcPath));
|
||||
LOGGER.info("Forge patches at {} is {}", patchedBinariesPath.toString(), pathStatus(patchedBinariesPath));
|
||||
return new Path[] { srgMcPath, patchedBinariesPath };
|
||||
}
|
||||
}
|
|
@ -20,9 +20,6 @@
|
|||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import com.google.common.collect.Streams;
|
||||
import net.minecraftforge.fml.LifecycleEventProvider;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.ModLoadingStage;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||
|
@ -34,7 +31,6 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
|
@ -0,0 +1,12 @@
|
|||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import org.apache.logging.log4j.Marker;
|
||||
import org.apache.logging.log4j.MarkerManager;
|
||||
|
||||
public class LogMarkers {
|
||||
public static final Marker CORE = MarkerManager.getMarker("CORE");
|
||||
public static final Marker LOADING = MarkerManager.getMarker("LOADING");
|
||||
public static final Marker SCAN = MarkerManager.getMarker("SCAN");
|
||||
public static final Marker SPLASH = MarkerManager.getMarker("SPLASH");
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* Convert a maven coordinate into a Path.
|
||||
*
|
||||
* {@code <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>}, must not be {@code null}.
|
||||
*/
|
||||
|
||||
public class MavenCoordinateResolver {
|
||||
public static Path get(final String coordinate) {
|
||||
final String[] parts = coordinate.split(":");
|
||||
final String groupId = parts[0];
|
||||
final String artifactId = parts[1];
|
||||
final String extension = parts.length > 3 ? parts[2] : "";
|
||||
final String classifier = parts.length > 4 ? parts[3] : "";
|
||||
final String version = parts[parts.length-1];
|
||||
return get(groupId, artifactId, extension, classifier, version);
|
||||
}
|
||||
|
||||
public static Path get(final String groupId, final String artifactId, final String extension, final String classifier, final String version)
|
||||
{
|
||||
final String fileName = artifactId + "-" + version +
|
||||
(!classifier.isEmpty() ? "-"+ classifier : "") +
|
||||
(!extension.isEmpty() ? "." + extension : ".jar");
|
||||
|
||||
String[] groups = groupId.split("\\.");
|
||||
Path result = Paths.get(groups[0]);
|
||||
for (int i = 1; i < groups.length; i++) {
|
||||
result = result.resolve(groups[i]);
|
||||
}
|
||||
|
||||
return result.resolve(artifactId).resolve(version).resolve(fileName);
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ import org.apache.logging.log4j.Logger;
|
|||
import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
|
||||
import org.apache.maven.artifact.versioning.VersionRange;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.CORE;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
|
||||
|
||||
public final class MavenVersionAdapter {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
|
@ -19,8 +19,7 @@
|
|||
|
||||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import net.minecraftforge.fml.Java9BackportUtils;
|
||||
import net.minecraftforge.fml.common.toposort.TopologicalSort;
|
||||
import net.minecraftforge.fml.loading.toposort.TopologicalSort;
|
||||
import net.minecraftforge.fml.language.IModInfo;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||
|
@ -36,7 +35,7 @@ import java.util.function.Supplier;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
|
||||
|
||||
public class ModSorter
|
||||
{
|
|
@ -20,7 +20,6 @@
|
|||
package net.minecraftforge.fml.loading;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import org.apache.commons.lang3.text.StrLookup;
|
||||
import org.apache.commons.lang3.text.StrSubstitutor;
|
||||
|
@ -32,9 +31,9 @@ import java.util.Map;
|
|||
public class StringSubstitutor
|
||||
{
|
||||
private static final Map<String,String> globals = ImmutableMap.of(
|
||||
"mcVersion", ForgeVersion.mcVersion,
|
||||
"forgeVersion", ForgeVersion.getVersion(),
|
||||
"mcpVersion", ForgeVersion.mcpVersion);
|
||||
"mcVersion", FMLLoader.forgeVersion,
|
||||
"forgeVersion", FMLLoader.mcVersion
|
||||
);
|
||||
|
||||
public static String replace(final String in, final ModFile file) {
|
||||
return new StrSubstitutor(getStringLookup(file)).replace(in);
|
|
@ -25,7 +25,6 @@ import java.net.MalformedURLException;
|
|||
import java.net.URL;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Created by cpw on 05/06/17.
|
|
@ -0,0 +1,71 @@
|
|||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipError;
|
||||
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.SCAN;
|
||||
|
||||
public class AbstractJarFileLocator {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
protected final Map<ModFile, FileSystem> modJars;
|
||||
|
||||
public AbstractJarFileLocator() {
|
||||
this.modJars = new HashMap<>();
|
||||
}
|
||||
|
||||
protected FileSystem createFileSystem(ModFile modFile) {
|
||||
try {
|
||||
return FileSystems.newFileSystem(modFile.getFilePath(), modFile.getClass().getClassLoader());
|
||||
} catch (ZipError | IOException e) {
|
||||
LOGGER.debug(SCAN,"Ignoring invalid JAR file {}", modFile.getFilePath());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Path findPath(final ModFile modFile, final String... path) {
|
||||
if (path.length < 1) {
|
||||
throw new IllegalArgumentException("Missing path");
|
||||
}
|
||||
return modJars.get(modFile).getPath(path[0], Arrays.copyOfRange(path, 1, path.length));
|
||||
}
|
||||
|
||||
public void scanFile(final ModFile file, final Consumer<Path> pathConsumer) {
|
||||
LOGGER.debug(SCAN,"Scan started: {}", file);
|
||||
FileSystem fs = modJars.get(file);
|
||||
fs.getRootDirectories().forEach(path -> {
|
||||
try (Stream<Path> files = Files.find(path, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) {
|
||||
files.forEach(pathConsumer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
LOGGER.debug(SCAN,"Scan finished: {}", file);
|
||||
}
|
||||
|
||||
public Optional<Manifest> findManifest(final Path file)
|
||||
{
|
||||
try (JarFile jf = new JarFile(file.toFile()))
|
||||
{
|
||||
return Optional.ofNullable(jf.getManifest());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ import java.util.concurrent.ExecutorService;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.SCAN;
|
||||
|
||||
public class BackgroundScanHandler
|
||||
{
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import net.minecraftforge.fml.loading.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.SCAN;
|
||||
|
||||
public class ExplodedDirectoryLocator implements IModLocator {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final List<Pair<Path,Path>> rootDirs;
|
||||
private final Map<ModFile, Pair<Path,Path>> mods;
|
||||
|
||||
public ExplodedDirectoryLocator() {
|
||||
this.rootDirs = new ArrayList<>();
|
||||
this.mods = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ModFile> scanMods() {
|
||||
final Path modstoml = Paths.get("META-INF", "mods.toml");
|
||||
// Collect all the mods.toml files found
|
||||
rootDirs.forEach(pathPathPair -> {
|
||||
Path resources = pathPathPair.getRight();
|
||||
Path modtoml = resources.resolve(modstoml);
|
||||
if (Files.exists(modtoml)) {
|
||||
ModFile mf = new ModFile(pathPathPair.getLeft(), this);
|
||||
mods.put(mf, pathPathPair);
|
||||
} else {
|
||||
LOGGER.warn(LOADING, "Failed to find exploded resource mods.toml in directory {}", resources.toString());
|
||||
}
|
||||
});
|
||||
return new ArrayList<>(mods.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "exploded directory";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path findPath(final ModFile modFile, final String... path) {
|
||||
if (path.length < 1) {
|
||||
throw new IllegalArgumentException("Missing path");
|
||||
}
|
||||
final Path target = Paths.get(path[0], Arrays.copyOfRange(path, 1, path.length));
|
||||
// try right path first (resources)
|
||||
Path found = mods.get(modFile).getRight().resolve(target);
|
||||
if (Files.exists(found)) return found;
|
||||
// then try left path (classes)
|
||||
return mods.get(modFile).getLeft().resolve(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanFile(final ModFile modFile, final Consumer<Path> pathConsumer) {
|
||||
LOGGER.debug(SCAN,"Scanning directory {}", modFile.getFilePath().toString());
|
||||
final Pair<Path, Path> pathPathPair = mods.get(modFile);
|
||||
// classes are in the left branch of the pair
|
||||
try (Stream<Path> files = Files.find(pathPathPair.getLeft(), Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) {
|
||||
files.forEach(pathConsumer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
LOGGER.debug(SCAN,"Directory scan complete {}", pathPathPair.getLeft());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "{ExplodedDir locator}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Manifest> findManifest(Path file)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void initArguments(final Map<String, ?> arguments) {
|
||||
final List<Pair<Path, Path>> explodedTargets = ((Map<String, List<Pair<Path, Path>>>) arguments).get("explodedTargets");
|
||||
rootDirs.addAll(explodedTargets);
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ package net.minecraftforge.fml.loading.moddiscovery;
|
|||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.Manifest;
|
||||
|
@ -39,4 +40,6 @@ public interface IModLocator {
|
|||
void scanFile(final ModFile modFile, Consumer<Path> pathConsumer);
|
||||
|
||||
Optional<Manifest> findManifest(Path file);
|
||||
|
||||
void initArguments(Map<String, ?> arguments);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import net.minecraftforge.fml.loading.FMLPaths;
|
||||
import net.minecraftforge.fml.loading.MavenCoordinateResolver;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MavenDirectoryLocator extends AbstractJarFileLocator implements IModLocator {
|
||||
private List<Path> modCoords;
|
||||
|
||||
@Override
|
||||
public List<ModFile> scanMods() {
|
||||
return modCoords.stream().
|
||||
map(mc -> new ModFile(mc, this)).
|
||||
peek(f->modJars.compute(f, (mf, fs)->createFileSystem(mf))).
|
||||
collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "maven libs";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "{Maven Directory locator for mods "+this.modCoords+"}";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void initArguments(final Map<String, ?> arguments) {
|
||||
final List<String> mavenRoots = (List<String>) arguments.get("mavenRoots");
|
||||
final List<Path> mavenRootPaths = mavenRoots.stream().map(n -> FMLPaths.GAMEDIR.get().resolve(n)).collect(Collectors.toList());
|
||||
final List<String> mods = (List<String>) arguments.get("mods");
|
||||
List<Path> localModCoords = mods.stream().map(MavenCoordinateResolver::get).collect(Collectors.toList());
|
||||
// find the modCoords path in each supplied maven path, and turn it into a mod file. (skips not found files)
|
||||
|
||||
this.modCoords = localModCoords.stream().map(mc -> mavenRootPaths.stream().map(root -> root.resolve(mc)).filter(path -> Files.exists(path)).findFirst().orElseThrow(() -> new IllegalArgumentException("Failed to locate requested mod coordinate " + mc))).collect(Collectors.toList());
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import net.minecraftforge.fml.loading.ModSorter;
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
@ -34,16 +35,18 @@ import java.util.Map;
|
|||
import java.util.ServiceLoader;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.SCAN;
|
||||
|
||||
|
||||
public class ModDiscoverer {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final ServiceLoader<IModLocator> locators;
|
||||
private final List<IModLocator> locatorList;
|
||||
|
||||
public ModDiscoverer() {
|
||||
public ModDiscoverer(Map<String, ?> arguments) {
|
||||
locators = ServiceLoader.load(IModLocator.class);
|
||||
locatorList = ServiceLoaderStreamUtils.toList(this.locators);
|
||||
locatorList.forEach(l->l.initArguments(arguments));
|
||||
LOGGER.debug(SCAN,"Found Mod Locators : {}", ()->locatorList.stream().map(iModLocator -> "("+iModLocator.name() + ":" + iModLocator.getClass().getPackage().getImplementationVersion()+")").collect(Collectors.joining(",")));
|
||||
}
|
||||
|
||||
|
@ -79,4 +82,8 @@ public class ModDiscoverer {
|
|||
loadingModList.addForScanning(backgroundScanHandler);
|
||||
return backgroundScanHandler;
|
||||
}
|
||||
|
||||
public void addExplodedTarget(final Path compiledClasses, final Path forgemodstoml) {
|
||||
|
||||
}
|
||||
}
|
|
@ -41,8 +41,8 @@ import java.util.function.Supplier;
|
|||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.SCAN;
|
||||
|
||||
public class ModFile
|
||||
{
|
|
@ -35,7 +35,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
|
||||
|
||||
public class ModFileParser {
|
||||
|
|
@ -24,42 +24,31 @@ import net.minecraftforge.fml.loading.FMLPaths;
|
|||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipError;
|
||||
|
||||
import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.uncheck;
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.SCAN;
|
||||
|
||||
/**
|
||||
* Support loading mods located in JAR files in the mods folder
|
||||
*/
|
||||
public class ModsFolderLocator implements IModLocator {
|
||||
public class ModsFolderLocator extends AbstractJarFileLocator implements IModLocator {
|
||||
private static final String SUFFIX = ".jar";
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final Path modFolder;
|
||||
private final Map<ModFile, FileSystem> modJars;
|
||||
|
||||
public ModsFolderLocator() {
|
||||
this(FMLPaths.MODSDIR.get());
|
||||
}
|
||||
|
||||
ModsFolderLocator(Path modFolder) {
|
||||
super();
|
||||
this.modFolder = modFolder;
|
||||
this.modJars = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -78,52 +67,13 @@ public class ModsFolderLocator implements IModLocator {
|
|||
return "mods folder";
|
||||
}
|
||||
|
||||
private FileSystem createFileSystem(ModFile modFile) {
|
||||
try {
|
||||
return FileSystems.newFileSystem(modFile.getFilePath(), modFile.getClass().getClassLoader());
|
||||
} catch (ZipError | IOException e) {
|
||||
LOGGER.debug(SCAN,"Ignoring invalid JAR file {}", modFile.getFilePath());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path findPath(final ModFile modFile, final String... path) {
|
||||
if (path.length < 1) {
|
||||
throw new IllegalArgumentException("Missing path");
|
||||
}
|
||||
return modJars.get(modFile).getPath(path[0], Arrays.copyOfRange(path, 1, path.length));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanFile(final ModFile file, final Consumer<Path> pathConsumer) {
|
||||
LOGGER.debug(SCAN,"Scan started: {}", file);
|
||||
FileSystem fs = modJars.get(file);
|
||||
fs.getRootDirectories().forEach(path -> {
|
||||
try (Stream<Path> files = Files.find(path, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) {
|
||||
files.forEach(pathConsumer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
LOGGER.debug(SCAN,"Scan finished: {}", file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{ModJarsFolder locator at "+this.modFolder+"}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Manifest> findManifest(final Path file)
|
||||
{
|
||||
try (JarFile jf = new JarFile(file.toFile()))
|
||||
{
|
||||
return Optional.ofNullable(jf.getManifest());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
public void initArguments(final Map<String, ?> arguments) {
|
||||
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@ import java.io.IOException;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
import static net.minecraftforge.fml.loading.LogMarkers.SCAN;
|
||||
|
||||
public class Scanner {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common.toposort;
|
||||
package net.minecraftforge.fml.loading.toposort;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import net.minecraftforge.fml.loading.EarlyLoadingException;
|
|
@ -0,0 +1 @@
|
|||
net.minecraftforge.fml.loading.RuntimeDistCleaner
|
|
@ -0,0 +1,3 @@
|
|||
net.minecraftforge.fml.loading.moddiscovery.ModsFolderLocator
|
||||
net.minecraftforge.fml.loading.moddiscovery.MavenDirectoryLocator
|
||||
net.minecraftforge.fml.loading.moddiscovery.ExplodedDirectoryLocator
|
|
@ -68,7 +68,9 @@ public class LaunchTesting
|
|||
"--version", "FMLDev",
|
||||
"--assetIndex", "1.13",
|
||||
"--assetsDir", assets,
|
||||
"--userProperties", "{}");
|
||||
"--userProperties", "{}",
|
||||
"--fml.forgeVersion", "24.0.0",
|
||||
"--fml.mcVersion", "1.13");
|
||||
} else if (Objects.equals(target, "fmldevserver")) {
|
||||
String[] launchargs = ObjectArrays.concat(new String[] {"--launchTarget", target,
|
||||
"--gameDir", "."}, args, String.class);
|
||||
|
|
|
@ -21,6 +21,7 @@ package net.minecraftforge.fml;
|
|||
|
||||
import net.minecraftforge.fml.common.event.ModLifecycleEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLModContainer;
|
||||
import net.minecraftforge.fml.language.ILifecycleEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -46,7 +47,7 @@ public enum LifecycleEventProvider
|
|||
}
|
||||
|
||||
|
||||
public static class LifecycleEvent {
|
||||
public static class LifecycleEvent implements ILifecycleEvent<LifecycleEvent> {
|
||||
private final ModLoadingStage stage;
|
||||
|
||||
public LifecycleEvent(ModLoadingStage stage)
|
||||
|
|
|
@ -92,7 +92,7 @@ public class ModList
|
|||
}
|
||||
|
||||
public void dispatchLifeCycleEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent, final Consumer<List<ModLoadingException>> errorHandler) {
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.preLifecycleEvent(lifecycleEvent));
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent));
|
||||
DeferredWorkQueue.deferredWorkQueue.clear();
|
||||
try
|
||||
{
|
||||
|
@ -105,7 +105,7 @@ public class ModList
|
|||
LOGGER.debug(LOADING, "Dispatching synchronous work, {} jobs", DeferredWorkQueue.deferredWorkQueue.size());
|
||||
DeferredWorkQueue.deferredWorkQueue.forEach(FutureTask::run);
|
||||
LOGGER.debug(LOADING, "Synchronous work queue complete");
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.postLifecycleEvent(lifecycleEvent));
|
||||
FMLLoader.getLanguageLoadingProvider().forEach(lp->lp.consumeLifecycleEvent(()->lifecycleEvent));
|
||||
}
|
||||
|
||||
public void setLoadedMods(final List<ModContainer> modContainers)
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.net.URL;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.SecureClassLoader;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
|
||||
|
@ -39,8 +40,11 @@ public class ModLoadingClassLoader extends SecureClassLoader
|
|||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
||||
private final Predicate<String> classLoadingPredicate;
|
||||
|
||||
protected ModLoadingClassLoader(final ClassLoader parent) {
|
||||
super(parent);
|
||||
this.classLoadingPredicate = FMLLoader.getClassLoaderExclusions();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,21 +53,29 @@ public class ModLoadingClassLoader extends SecureClassLoader
|
|||
return super.getResource(name);
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
|
||||
{
|
||||
|
||||
final String className = name.replace('.', '/').concat(".class");
|
||||
final Path classResource = FMLLoader.getLoadingModList().findResource(className);
|
||||
if (classResource != null)
|
||||
{
|
||||
return findClass(name);
|
||||
}
|
||||
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
if (!classLoadingPredicate.test(name)) {
|
||||
LOGGER.debug(LOADING, "Delegating to parent {}", name);
|
||||
return getParent().loadClass(name);
|
||||
}
|
||||
LOGGER.debug(LOADING, "Loading class {}", name);
|
||||
final String className = name.replace('.','/').concat(".class");
|
||||
final Path classResource = FMLLoader.getLoadingModList().findResource(className);
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.client.gui;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.common.toposort.ModSortingException;
|
||||
import net.minecraftforge.fml.common.toposort.ModSortingException.SortingExceptionData;
|
||||
|
||||
public class GuiSortingProblem extends GuiScreen {
|
||||
private SortingExceptionData<ModContainer> failedList;
|
||||
|
||||
public GuiSortingProblem(ModSortingException modSorting)
|
||||
{
|
||||
this.failedList = modSorting.getExceptionData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui()
|
||||
{
|
||||
super.initGui();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(int mouseX, int mouseY, float partialTicks)
|
||||
{
|
||||
this.drawDefaultBackground();
|
||||
int offset = Math.max(85 - (failedList.getVisitedNodes().size() + 3) * 10, 10);
|
||||
this.drawCenteredString(this.fontRenderer, "Forge Mod Loader has found a problem with your minecraft installation", this.width / 2, offset, 0xFFFFFF);
|
||||
offset+=10;
|
||||
this.drawCenteredString(this.fontRenderer, "A mod sorting cycle was detected and loading cannot continue", this.width / 2, offset, 0xFFFFFF);
|
||||
offset+=10;
|
||||
this.drawCenteredString(this.fontRenderer, String.format("The first mod in the cycle is %s", failedList.getFirstBadNode()), this.width / 2, offset, 0xFFFFFF);
|
||||
offset+=10;
|
||||
this.drawCenteredString(this.fontRenderer, "The remainder of the cycle involves these mods", this.width / 2, offset, 0xFFFFFF);
|
||||
offset+=5;
|
||||
for (ModContainer mc : failedList.getVisitedNodes())
|
||||
{/* TODO Mod dependencies
|
||||
offset+=10;
|
||||
this.drawCenteredString(this.fontRenderer, String.format("%s : before: %s, after: %s", mc.toString(), mc.getDependants(), mc.getDependencies()), this.width / 2, offset, 0xEEEEEE);
|
||||
*/}
|
||||
offset+=20;
|
||||
this.drawCenteredString(this.fontRenderer, "The file 'ForgeModLoader-client-0.log' contains more information", this.width / 2, offset, 0xFFFFFF);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.common.toposort;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.ModContainer;
|
||||
import net.minecraftforge.fml.client.IDisplayableError;
|
||||
import net.minecraftforge.fml.client.gui.GuiSortingProblem;
|
||||
import net.minecraftforge.fml.common.EnhancedRuntimeException;
|
||||
|
||||
import net.minecraftforge.fml.common.EnhancedRuntimeException.WrappedPrintStream;
|
||||
|
||||
public class ModSortingException extends EnhancedRuntimeException implements IDisplayableError
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public class SortingExceptionData<T>
|
||||
{
|
||||
public SortingExceptionData(T node, Set<T> visitedNodes)
|
||||
{
|
||||
this.firstBadNode = node;
|
||||
this.visitedNodes = visitedNodes;
|
||||
}
|
||||
|
||||
private T firstBadNode;
|
||||
private Set<T> visitedNodes;
|
||||
|
||||
public T getFirstBadNode()
|
||||
{
|
||||
return firstBadNode;
|
||||
}
|
||||
public Set<T> getVisitedNodes()
|
||||
{
|
||||
return visitedNodes;
|
||||
}
|
||||
}
|
||||
|
||||
private SortingExceptionData<?> sortingExceptionData;
|
||||
|
||||
public <T> ModSortingException(String string, T node, Set<T> visitedNodes)
|
||||
{
|
||||
super(string);
|
||||
this.sortingExceptionData = new SortingExceptionData<>(node, visitedNodes);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> SortingExceptionData<T> getExceptionData()
|
||||
{
|
||||
return (SortingExceptionData<T>) sortingExceptionData;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void printStackTrace(WrappedPrintStream stream)
|
||||
{
|
||||
SortingExceptionData<ModContainer> exceptionData = getExceptionData();
|
||||
stream.println("A dependency cycle was detected in the input mod set so an ordering cannot be determined");
|
||||
stream.println("The first mod in the cycle is " + exceptionData.getFirstBadNode());
|
||||
stream.println("The mod cycle involves:");
|
||||
for (ModContainer mc : exceptionData.getVisitedNodes())
|
||||
{/* TODO Mod dependencies
|
||||
stream.println(String.format("\t%s : before: %s, after: %s", mc.toString(), mc.getDependants(), mc.getDependencies()));
|
||||
*/}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public GuiScreen createGui()
|
||||
{
|
||||
return new GuiSortingProblem(this);
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
package net.minecraftforge.fml.javafmlmod;
|
||||
|
||||
import net.minecraftforge.fml.LifecycleEventProvider;
|
||||
import net.minecraftforge.fml.language.ILifecycleEvent;
|
||||
import net.minecraftforge.fml.language.IModLanguageProvider;
|
||||
import net.minecraftforge.fml.language.IModInfo;
|
||||
import net.minecraftforge.fml.language.ModFileScanData;
|
||||
|
@ -32,6 +32,7 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
|
@ -100,12 +101,7 @@ public class FMLJavaModLanguageProvider implements IModLanguageProvider
|
|||
}
|
||||
|
||||
@Override
|
||||
public void preLifecycleEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent)
|
||||
{
|
||||
}
|
||||
public <R extends ILifecycleEvent<R>> void consumeLifecycleEvent(final Supplier<R> consumeEvent) {
|
||||
|
||||
@Override
|
||||
public void postLifecycleEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.LOADING;
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
|
||||
public class ExplodedDirectoryLocator implements IModLocator {
|
||||
private static final String DIR = System.getProperty("fml.explodedDir", "modclasses");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final Path rootDir;
|
||||
|
||||
public ExplodedDirectoryLocator() {
|
||||
this.rootDir = FileSystems.getDefault().getPath(DIR);
|
||||
if (!Files.exists(this.rootDir)) {
|
||||
LOGGER.debug(LOADING,"Creating directory {}" + this.rootDir);
|
||||
try
|
||||
{
|
||||
Files.createDirectory(this.rootDir);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOGGER.error(LOADING,"Error creating {}", this.rootDir, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ModFile> scanMods() {
|
||||
return Collections.singletonList(new ModFile(rootDir, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "exploded directory";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path findPath(final ModFile modFile, final String... path) {
|
||||
if (path.length < 1) {
|
||||
throw new IllegalArgumentException("Missing path");
|
||||
}
|
||||
return rootDir.resolve(FileSystems.getDefault().getPath(path[0], Arrays.copyOfRange(path, 1, path.length)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanFile(final ModFile modFile, final Consumer<Path> pathConsumer) {
|
||||
LOGGER.debug(SCAN,"Scanning directory {}", rootDir);
|
||||
try (Stream<Path> files = Files.find(rootDir, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) {
|
||||
files.forEach(pathConsumer);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
LOGGER.debug(SCAN,"Directory scan complete {}", rootDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "{ExplodedDir locator at "+this.rootDir+"}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Manifest> findManifest(Path file)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
|
@ -1,244 +0,0 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.fml.loading.moddiscovery;
|
||||
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.loading.FMLEnvironment;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.IModLocator;
|
||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
||||
import net.minecraftforge.versions.mcp.MCPVersion;
|
||||
|
||||
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.*;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraftforge.fml.Logging.SCAN;
|
||||
|
||||
/*
|
||||
* Locate Forge in the classpath, this works similar to ClasspathLocator.
|
||||
* Forge/Minecraft are in the following formats:
|
||||
* Runtime:
|
||||
* %lib%/net/minecraftforge/forge/{ver}/forge-{ver}.jar or ./forge-{ver}-universal.jar - Client is in libs, Server is in root
|
||||
* %lib%/net/minecraftforge/forge/{ver}/forge-{ver}-{client|server}.jar - Forge, Vanilla classes, Patched
|
||||
* %lib%/net/minecraft/{client|server}/{mcver}/{client|server}-{mcver}-srg.jar - Vanilla classes, SRG, Unpatched
|
||||
*
|
||||
* UserDev:
|
||||
* Forge and vanilla is in a single jar file, patched, on the classpath.
|
||||
*
|
||||
* Eclipse:
|
||||
* bin/{sourceset}/
|
||||
*
|
||||
* Intellij: TODO: Verify, I don't use intellij
|
||||
* out/production/resources/../classes/ - Resources are a separate folder so we have to navigate to classes
|
||||
*
|
||||
* Gradle:
|
||||
* build/classes/{language}/{sourceset}
|
||||
* build/resources/{sourceset}
|
||||
*
|
||||
*/
|
||||
public class ForgeLocator implements IModLocator
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final String FORGE_META = "forgemod.toml";
|
||||
private static final String MAIN_SOURCESET = "main";
|
||||
private static final String LIB_RESOURCE = "org/objectweb/asm/Opcodes.class";
|
||||
private static final String LIB_PATH = "org/ow2/asm/asm".replace('/', File.separatorChar);
|
||||
private List<Path> roots = new ArrayList<>();
|
||||
private boolean filterClasses = false;
|
||||
|
||||
public ForgeLocator() { }
|
||||
|
||||
@Override
|
||||
public List<ModFile> scanMods()
|
||||
{
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
URL url = loader.getResource(FORGE_META);
|
||||
if (url == null)
|
||||
throw new IllegalStateException("Could not locate \"" + FORGE_META + "\", Forge is correupt/not on classpath!");
|
||||
|
||||
File base = getRoot(url, FORGE_META);
|
||||
if (base == null)
|
||||
throw new IllegalStateException("Could not determine root for Forge resource: " + url);
|
||||
|
||||
url = loader.getResource(LIB_RESOURCE);
|
||||
if (url == null)
|
||||
throw new IllegalStateException("Could not locate \"" + LIB_RESOURCE + "\" to locate libraries directory.");
|
||||
File libs = getRoot(url, LIB_RESOURCE);
|
||||
//If In maven style the libraries folder we need to drop the file name, and version folder
|
||||
if (libs != null && libs.getParentFile().getParentFile().getAbsolutePath().endsWith(LIB_PATH))
|
||||
{
|
||||
int count = 2 + LIB_PATH.split(Pattern.quote("" + File.separatorChar)).length;
|
||||
for (int x = 0; x < count; x++)
|
||||
libs = libs.getParentFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
libs = null;
|
||||
}
|
||||
|
||||
LOGGER.info("Forge Locator: ");
|
||||
LOGGER.info(" Forge: " + base);
|
||||
LOGGER.info(" Libraries: " + libs);
|
||||
|
||||
Path path = base.toPath();
|
||||
if (base.isDirectory())
|
||||
{ // Development workspace.
|
||||
int count = path.getNameCount();
|
||||
//Eclipse: /bin/{sourceset}/
|
||||
if (count >= 2 && MAIN_SOURCESET.equals(path.getName(count - 1).toString()) && "bin".equals(path.getName(count - 2).toString()))
|
||||
{
|
||||
roots.add(path);
|
||||
roots.add(path.getParent().resolve("userdev")); //Do I need this?
|
||||
} //Intellij: /out/production/resources/ & /out/production/classes/
|
||||
else if (count >= 1 && "resources".equals(path.getName(count - 1).toString()))
|
||||
{
|
||||
roots.add(path.getParent().resolve("classes"));
|
||||
roots.add(path);
|
||||
} //Gradle: build/resources/{sourceset} & build/classes/{language}/{sourceset}
|
||||
else if (count >= 2 && MAIN_SOURCESET.equals(path.getName(count - 1).toString()) && "resources".equals(path.getName(count - 2).toString()))
|
||||
{
|
||||
Path classes = path.getParent().getParent().resolve("classes");
|
||||
roots.add(classes.resolve(MAIN_SOURCESET));
|
||||
roots.add(classes.resolve("userdev"));
|
||||
roots.add(path);
|
||||
roots.add(path.getParent().resolve("userdev"));
|
||||
}
|
||||
filterClasses = true;
|
||||
}
|
||||
else if (base.isFile())
|
||||
{
|
||||
if (libs == null) //User dev workspace.
|
||||
{
|
||||
roots.add(path);
|
||||
}
|
||||
else //Standard install
|
||||
{
|
||||
String dist = FMLEnvironment.dist == Dist.CLIENT ? "client" : "server";
|
||||
String version = MCPVersion.getMCVersion() + "-" + ForgeVersion.getVersion();
|
||||
roots.add(path); // universal
|
||||
roots.add(libs.toPath().resolve(Paths.get(ForgeVersion.getGroup().replace('.', File.separatorChar), "forge", version, "forge-" + version + "-" + dist + ".jar"))); // Patched classes
|
||||
roots.add(libs.toPath().resolve(Paths.get("net", "minecraft", dist, MCPVersion.getMCPandMCVersion(), dist + "-" + MCPVersion.getMCPandMCVersion() + "-srg.jar"))); //Vanilla jar in srg names
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
throw new IllegalStateException("Forge path is neither File or Directory... " + base);
|
||||
|
||||
if (roots.isEmpty())
|
||||
return Collections.emptyList();
|
||||
|
||||
roots.forEach(r -> LOGGER.info(" Root: " + r));
|
||||
return Collections.singletonList(new ModFile(roots.get(0), this));
|
||||
}
|
||||
|
||||
protected File getRoot(URL url, String resource)
|
||||
{
|
||||
String path = url.getPath();
|
||||
if ("jar".equals(url.getProtocol()))
|
||||
{
|
||||
int idx = path.indexOf("!/");
|
||||
path = path.substring(0, idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Strip resource path off the end
|
||||
path = path.substring(0, path.length() - resource.length());
|
||||
}
|
||||
|
||||
if (path.startsWith("file:"))
|
||||
path = path.substring(5);
|
||||
|
||||
return new File(path).getAbsoluteFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name()
|
||||
{
|
||||
return "forge locator";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path findPath(final ModFile modFile, String... path)
|
||||
{
|
||||
if (path.length < 1)
|
||||
throw new IllegalArgumentException("Missing path");
|
||||
|
||||
if (path.length == 2 && "META-INF".equals(path[0]) && "mods.toml".equals(path[1]))
|
||||
path = FORGE_META.split("/");
|
||||
|
||||
if (filterClasses && path[path.length - 1].endsWith(".class"))
|
||||
path[path.length - 1] = path[path.length - 1] + "THIS_FILE_WILL_NEVER_EXITS_DIRTY_HAX";
|
||||
|
||||
String[] tail = Arrays.copyOfRange(path, 1, path.length);
|
||||
for (Path root : roots)
|
||||
{
|
||||
Path target = root.resolve(root.getFileSystem().getPath(path[0], tail));
|
||||
if (Files.exists(target))
|
||||
return target;
|
||||
}
|
||||
|
||||
return modFile.getFilePath().resolve(modFile.getFilePath().getFileSystem().getPath(path[0], tail));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scanFile(final ModFile modFile, final Consumer<Path> pathConsumer)
|
||||
{
|
||||
final Set<String> visited = new HashSet<>();
|
||||
roots.stream().forEach(root ->
|
||||
{
|
||||
LOGGER.debug(SCAN,"Scanning Forge: " + root);
|
||||
try (Stream<Path> files = Files.find(root, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class")))
|
||||
{
|
||||
files.forEach(f -> {
|
||||
String relative = root.relativize(f).toString(); //TODO: Test jared files...
|
||||
if (visited.add(relative))
|
||||
pathConsumer.accept(Paths.get(relative));
|
||||
});
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
LOGGER.debug(SCAN,"Forge scan complete");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "{Forge locator}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Manifest> findManifest(Path file)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
|
@ -37,13 +37,11 @@ import java.util.stream.Collectors;
|
|||
public class ResourcePackLoader
|
||||
{
|
||||
private static Map<ModFile, ModFileResourcePack> modResourcePacks;
|
||||
private static AbstractResourcePack forgePack;
|
||||
private static ResourcePackList<?> resourcePackList;
|
||||
|
||||
public static IResourcePack getResourcePackFor(String modId)
|
||||
{
|
||||
if (modId == "forge") return forgePack;
|
||||
else return modResourcePacks.get(ModList.get().getModFileById(modId).getFile());
|
||||
return modResourcePacks.get(ModList.get().getModFileById(modId).getFile());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -56,9 +54,6 @@ public class ResourcePackLoader
|
|||
modResourcePacks = ModList.get().getModFiles().stream().
|
||||
map(mf -> new ModFileResourcePack(mf.getFile())).
|
||||
collect(Collectors.toMap(ModFileResourcePack::getModFile, Function.identity()));
|
||||
forgePack = Files.isDirectory(FMLLoader.getForgePath()) ?
|
||||
new ForgeFolderPack(FMLLoader.getForgePath().toFile()) :
|
||||
new ForgeFilePack(FMLLoader.getForgePath().toFile());
|
||||
resourcePacks.addPackFinder(new ModPackFinder());
|
||||
}
|
||||
|
||||
|
@ -111,8 +106,7 @@ public class ResourcePackLoader
|
|||
@Override
|
||||
public <T extends ResourcePackInfo> void addPackInfosToMap(Map<String, T> packList, ResourcePackInfo.IFactory<T> factory)
|
||||
{
|
||||
packList.put("forge", ResourcePackInfo.func_195793_a("forge", true, ()->forgePack, factory, ResourcePackInfo.Priority.BOTTOM));
|
||||
for (Entry<ModFile, ModFileResourcePack> e : modResourcePacks.entrySet())
|
||||
for (Entry<ModFile, ModFileResourcePack> e : modResourcePacks.entrySet())
|
||||
{
|
||||
String name = "modfile/" + e.getKey().getFileName();
|
||||
packList.put(name, ResourcePackInfo.func_195793_a(name, true, ()->e.getValue(), factory, ResourcePackInfo.Priority.BOTTOM));
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
net.minecraftforge.fml.loading.RuntimeDistCleaner
|
||||
net.minecraftforge.common.asm.RuntimeEnumExtender
|
||||
net.minecraftforge.common.asm.ObjectHolderDefinalize
|
||||
net.minecraftforge.common.asm.CapabilityInjectDefinalize
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
net.minecraftforge.fml.loading.moddiscovery.ModsFolderLocator
|
||||
net.minecraftforge.fml.loading.moddiscovery.ForgeLocator
|
|
@ -148,4 +148,11 @@ public class ClasspathLocator implements IModLocator
|
|||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initArguments(final Map<String, ?> arguments) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue