diff --git a/build.gradle b/build.gradle index 930895dcc0..fc1b671c0d 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:[5.1.39,)' + classpath 'net.minecraftforge.gradle:ForgeGradle:[5.1.39,5.2.0)' } } @@ -59,23 +59,22 @@ ext { COREMODS_VERSION = '5.0.1' EVENTBUS_VERSION = '5.0.3' MODLAUNCHER_VERSION = '9.1.3' - SECUREJARHANDLER_VERSION = '1.0.3' + SECUREJARHANDLER_VERSION = '1.0.8' BOOTSTRAPLAUNCHER_VERSION = '1.0.0' - ASM_VERSION = '9.2' + ASM_VERSION = '9.5' INSTALLER_VERSION = '2.1.+' MIXIN_VERSION = '0.8.5' - JARJAR_VERSION = '0.3.0' + JARJAR_VERSION = '0.3.19' GIT_INFO = gradleutils.gitInfo VERSION = gradleutils.getFilteredMCTagOffsetBranchVersion(true, '[0-9]', MC_VERSION) // FML_VERSION = gradleutils.getFilteredMCTagOffsetBranchVersion(true, 'FML', MC_VERSION) FORGE_VERSION = VERSION.substring(MC_VERSION.length() + 1) - SPECIAL_SOURCE = 'net.md-5:SpecialSource:1.10.0' BINPATCH_TOOL = 'net.minecraftforge:binarypatcher:1.0.12:fatjar' INSTALLER_TOOLS = 'net.minecraftforge:installertools:1.3.0' JAR_SPLITTER = 'net.minecraftforge:jarsplitter:1.1.4' - FART = 'net.minecraftforge:ForgeAutoRenamingTool:0.1.22:all' + FART = 'net.minecraftforge:ForgeAutoRenamingTool:0.1.25:all' MIN_TAG_FOR_CHANGELOG = "39.0" LAST_RB = GIT_INFO.tag.rsplit('.', 1)[1] as int >= 1 ? GIT_INFO.tag + '.0' : null } @@ -258,6 +257,7 @@ def sharedDeps = { moduleonly "org.ow2.asm:asm-util:${ASM_VERSION}" moduleonly "org.ow2.asm:asm-analysis:${ASM_VERSION}" moduleonly "cpw.mods:bootstraplauncher:${BOOTSTRAPLAUNCHER_VERSION}" + moduleonly "net.minecraftforge:JarJarFileSystems:${JARJAR_VERSION}" installer "cpw.mods:securejarhandler:${SECUREJARHANDLER_VERSION}" installer "org.ow2.asm:asm:${ASM_VERSION}" @@ -281,7 +281,8 @@ def sharedDeps = { installer 'org.jline:jline-terminal:3.12.+' //Dep of TerminaalConsoleeAppender installer "org.spongepowered:mixin:${MIXIN_VERSION}" installer 'org.openjdk.nashorn:nashorn-core:15.3' - installer "net.minecraftforge:JarJar:${JARJAR_VERSION}" + installer "net.minecraftforge:JarJarSelector:${JARJAR_VERSION}" + installer "net.minecraftforge:JarJarMetadata:${JARJAR_VERSION}" /* installer 'org.lwjgl:lwjgl:3.2.2' @@ -450,6 +451,7 @@ def sharedFmlonlyForge = { Project prj -> run.jvmArgs '--add-modules', 'ALL-MODULE-PATH' // Additions to these JVM module args should be mirrored to server_files/args.txt and other similar blocks in the buildscript run.jvmArgs '--add-opens', 'java.base/java.util.jar=cpw.mods.securejarhandler' + run.jvmArgs '--add-opens', 'java.base/java.lang.invoke=cpw.mods.securejarhandler' run.jvmArgs '--add-exports', 'java.base/sun.security.util=cpw.mods.securejarhandler' run.jvmArgs '--add-exports', 'jdk.naming.dns/com.sun.jndi.dns=java.naming' } @@ -640,6 +642,7 @@ project(':fmlonly') { '--add-modules', 'ALL-MODULE-PATH', // Additions to these JVM module args should be mirrored to server_files/args.txt and other similar blocks in the buildscript '--add-opens', 'java.base/java.util.jar=cpw.mods.securejarhandler', + '--add-opens', 'java.base/java.lang.invoke=cpw.mods.securejarhandler', '--add-exports', 'java.base/sun.security.util=cpw.mods.securejarhandler', '--add-exports', 'jdk.naming.dns/com.sun.jndi.dns=java.naming' ] @@ -1200,7 +1203,7 @@ project(':forge') { } def baseForgeVersionProperty = project.objects.property(String) - baseForgeVersionProperty.set(project.provider { getLatestForgeVersion(MC_VERSION) }.map { MC_VERSION + '-' + it }) + baseForgeVersionProperty.set(project.provider { TeamcityRequests.attemptFindBase(rootDir) ?: getLatestForgeVersion(MC_VERSION) }) baseForgeVersionProperty.finalizeValueOnRead() def jarCompatibilityTaskSetup = { task -> task.group = 'jar compatibility' @@ -1277,6 +1280,7 @@ project(':forge') { '--add-modules', 'ALL-MODULE-PATH', // Additions to these JVM module args should be mirrored to server_files/args.txt and other similar blocks in the buildscript '--add-opens', 'java.base/java.util.jar=cpw.mods.securejarhandler', + '--add-opens', 'java.base/java.lang.invoke=cpw.mods.securejarhandler', '--add-exports', 'java.base/sun.security.util=cpw.mods.securejarhandler', '--add-exports', 'jdk.naming.dns/com.sun.jndi.dns=java.naming' ] diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 19adbbe7a5..110556af31 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,11 +1,12 @@ repositories { maven { url = 'https://maven.minecraftforge.net/' } - mavenCentral() + mavenCentral() } dependencies { - implementation 'org.ow2.asm:asm:9.1' - implementation 'org.ow2.asm:asm-tree:9.1' - implementation 'net.minecraftforge:srgutils:0.4.+' + implementation 'org.ow2.asm:asm:9.5' + implementation 'org.ow2.asm:asm-tree:9.5' + implementation 'net.minecraftforge:srgutils:0.5.+' implementation 'commons-io:commons-io:2.8.0' implementation 'com.google.code.gson:gson:2.10' + implementation 'org.eclipse.jgit:org.eclipse.jgit:6.5.0.202303070854-r' } \ No newline at end of file diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/TeamcityRequests.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/TeamcityRequests.groovy new file mode 100644 index 0000000000..d6b73c32fc --- /dev/null +++ b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/TeamcityRequests.groovy @@ -0,0 +1,74 @@ +package net.minecraftforge.forge.tasks + +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import groovy.transform.CompileStatic +import org.eclipse.jgit.api.Git + +import javax.annotation.Nullable +import java.util.stream.Collectors + +@CompileStatic +class TeamcityRequests { + public static final Gson GSON = new Gson() + + @Nullable + static T jsonRequest(TypeToken clazz, String url) throws Exception { + final HttpURLConnection conn = (HttpURLConnection) URI.create(url).toURL().openConnection() + conn.setRequestProperty('Accept', 'application/json') + conn.setReadTimeout(5 * 1000) + conn.setConnectTimeout(5 * 1000) + conn.connect() + + if (conn.responseCode !== 200) { + return null + } + + try (final InputStream is = conn.getInputStream()) { + GSON.fromJson(new InputStreamReader(is), clazz.getType()) + } + } + + @Nullable + static Map buildsByCommit() throws IOException { + final Map builds = [:] + jsonRequest(new TypeToken() {}, "https://teamcity.minecraftforge.net/guestAuth/app/rest/builds?fields=build:(revisions,number)&locator=buildType:(id:MinecraftForge_MinecraftForge_MinecraftForge_MinecraftForge__Build),count:300,status:SUCCESS") + ?.build?.forEach { + it.revisions.revision.each { rev -> builds[rev.version] = it } + } + return builds + } + + @Nullable + static String attemptFindBase(File gitPath) { + try (final git = Git.open(gitPath)) { + final Map buildByCommit = buildsByCommit() + for (final commit in git.log().setMaxCount(100).call()) { + // Find the first commit which was built on CI + final build = buildByCommit[commit.id.name] + if (build) { + return build.number + } + } + } catch (Exception ignored) {} + return null + } + + static final class Builds { + public List build + } + + static final class Build { + public String number + public Revisions revisions + } + + static final class Revisions { + public int count + public List revision + } + + static final class Revision { + public String version + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/Util.groovy b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/Util.groovy index 76b171b7d1..a98526aff1 100644 --- a/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/Util.groovy +++ b/buildSrc/src/main/groovy/net/minecraftforge/forge/tasks/Util.groovy @@ -143,8 +143,9 @@ public class Util { } } - public static String getLatestForgeVersion(mcVersion) { - def json = new JsonSlurper().parseText(new URL("https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json").getText("UTF-8")) - return json.promos["$mcVersion-latest"] + static String getLatestForgeVersion(mcVersion) { + final json = new JsonSlurper().parseText(new URL('https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json').getText('UTF-8')) + final ver = json.promos["$mcVersion-latest"] + ver === null ? null : (mcVersion + '-' + ver) } } \ No newline at end of file diff --git a/fmlloader/build.gradle b/fmlloader/build.gradle index 7249d4cc99..f461c8f150 100644 --- a/fmlloader/build.gradle +++ b/fmlloader/build.gradle @@ -27,7 +27,9 @@ dependencies { api('com.electronwill.night-config:toml:3.6.4') api('cpw.mods:modlauncher:9.0.+') api('net.minecraftforge:coremods:5.0.+') - api "net.minecraftforge:JarJar:${JARJAR_VERSION}" + api "net.minecraftforge:JarJarSelector:${JARJAR_VERSION}" + api "net.minecraftforge:JarJarMetadata:${JARJAR_VERSION}" + implementation("cpw.mods:securejarhandler:${SECUREJARHANDLER_VERSION}") implementation('org.apache.logging.log4j:log4j-core:2.17.0') annotationProcessor('org.apache.logging.log4j:log4j-core:2.17.0') diff --git a/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/JarInJarDependencyLocator.java b/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/JarInJarDependencyLocator.java index 8cf7a832e2..3b81f03715 100644 --- a/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/JarInJarDependencyLocator.java +++ b/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/JarInJarDependencyLocator.java @@ -5,6 +5,7 @@ package net.minecraftforge.fml.loading.moddiscovery; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import net.minecraftforge.fml.loading.EarlyLoadingException; import net.minecraftforge.forgespi.language.IModInfo; @@ -16,10 +17,15 @@ import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.artifact.versioning.VersionRange; import org.jetbrains.annotations.NotNull; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -34,20 +40,16 @@ public class JarInJarDependencyLocator extends AbstractJarFileDependencyLocator } @Override - public List scanMods(final Iterable loadedMods) { + public List scanMods(final Iterable loadedMods) + { final List sources = Lists.newArrayList(); loadedMods.forEach(sources::add); - final List dependenciesToLoad = JarSelector.detectAndSelect( - sources, - this::loadResourceFromModFile, - this::loadModFileFrom, - this::identifyMod, - this::exception - ); + final List dependenciesToLoad = JarSelector.detectAndSelect(sources, this::loadResourceFromModFile, this::loadModFileFrom, this::identifyMod, this::exception); - if (dependenciesToLoad.isEmpty()) { + if (dependenciesToLoad.isEmpty()) + { LOGGER.info("No dependencies to load found. Skipping!"); return Collections.emptyList(); } @@ -68,46 +70,87 @@ public class JarInJarDependencyLocator extends AbstractJarFileDependencyLocator return IModFile.Type.GAMELIBRARY.name(); } + @SuppressWarnings("resource") + @Override + protected Optional loadModFileFrom(final IModFile file, final Path path) + { + try + { + final Path pathInModFile = file.findResource(path.toString()); + final URI filePathUri = new URI("jij:" + (pathInModFile.toAbsolutePath().toUri().getRawSchemeSpecificPart())).normalize(); + final Map outerFsArgs = ImmutableMap.of("packagePath", pathInModFile); + final FileSystem zipFS = FileSystems.newFileSystem(filePathUri, outerFsArgs); + final Path pathInFS = zipFS.getPath("/"); + return createMod(pathInFS); + } + catch (Exception e) + { + LOGGER.error("Failed to load mod file {} from {}", path, file.getFileName()); + + throw new RuntimeException("Failed to load mod file " + file.getFileName(), e); + } + } + protected EarlyLoadingException exception(Collection> failedDependencies) { final List errors = failedDependencies.stream() - .filter(entry -> !entry.sources().isEmpty()) //Should never be the case, but just to be sure - .map(entry -> new EarlyLoadingException.ExceptionData( - getErrorTranslationKey(entry), - entry.identifier().group() + ":" + entry.identifier().artifact(), - entry.sources() - .stream() - .flatMap(this::getModWithVersionRangeStream) - .map(this::formatError) - .collect(Collectors.joining(", ")))).toList(); + .filter(entry -> !entry.sources().isEmpty()) //Should never be the case, but just to be sure + .map(this::buildExceptionData) + .toList(); return new EarlyLoadingException(failedDependencies.size() + " Dependency restrictions were not met.", null, errors); } + @NotNull + private EarlyLoadingException.ExceptionData buildExceptionData(final JarSelector.ResolutionFailureInformation entry) + { + return new EarlyLoadingException.ExceptionData( + getErrorTranslationKey(entry), + entry.identifier().group() + ":" + entry.identifier().artifact(), + entry.sources() + .stream() + .flatMap(this::getModWithVersionRangeStream) + .map(this::formatError) + .collect(Collectors.joining(", ")) + ); + } + @NotNull private String getErrorTranslationKey(final JarSelector.ResolutionFailureInformation entry) { - return entry.failureReason() == JarSelector.FailureReason.VERSION_RESOLUTION_FAILED - ? "fml.dependencyloading.conflictingdependencies" - : "fml.dependencyloading.mismatchedcontaineddependencies"; + return entry.failureReason() == JarSelector.FailureReason.VERSION_RESOLUTION_FAILED ? + "fml.dependencyloading.conflictingdependencies" : + "fml.dependencyloading.mismatchedcontaineddependencies"; } @NotNull private Stream getModWithVersionRangeStream(final JarSelector.SourceWithRequestedVersionRange file) { - return file.sources().stream().map(IModFile::getModFileInfo) - .flatMap(modFileInfo -> modFileInfo.getMods().stream()) - .map(modInfo -> new ModWithVersionRange(modInfo, file.requestedVersionRange(), file.includedVersion())); + return file.sources() + .stream() + .map(IModFile::getModFileInfo) + .flatMap(modFileInfo -> modFileInfo.getMods().stream()) + .map(modInfo -> new ModWithVersionRange(modInfo, file.requestedVersionRange(), file.includedVersion())); } @NotNull private String formatError(final ModWithVersionRange modWithVersionRange) { - return "\u00a7e" + modWithVersionRange.modInfo().getModId() + "\u00a7r - \u00a74" - + modWithVersionRange.versionRange().toString() + "\u00a74 - \u00a72" - + modWithVersionRange.artifactVersion().toString() + "\u00a72"; + return "\u00a7e" + modWithVersionRange.modInfo().getModId() + "\u00a7r - \u00a74" + modWithVersionRange.versionRange().toString() + "\u00a74 - \u00a72" + modWithVersionRange.artifactVersion().toString() + "\u00a72"; } - private record ModWithVersionRange(IModInfo modInfo, VersionRange versionRange, ArtifactVersion artifactVersion) {} + @Override + protected String identifyMod(final IModFile modFile) + { + if (modFile.getModFileInfo() == null || modFile.getModInfos().isEmpty()) + { + return modFile.getFileName(); + } + + return modFile.getModInfos().stream().map(IModInfo::getModId).collect(Collectors.joining()); + } + + private record ModWithVersionRange(IModInfo modInfo, VersionRange versionRange, ArtifactVersion artifactVersion) + {} } diff --git a/server_files/args.txt b/server_files/args.txt index 6dd9824f33..84df94b0e5 100644 --- a/server_files/args.txt +++ b/server_files/args.txt @@ -1,6 +1,7 @@ -p @MODULE_PATH@ --add-modules @MODULES@ --add-opens java.base/java.util.jar=cpw.mods.securejarhandler +--add-opens java.base/java.lang.invoke=cpw.mods.securejarhandler --add-exports java.base/sun.security.util=cpw.mods.securejarhandler --add-exports jdk.naming.dns/com.sun.jndi.dns=java.naming -Djava.net.preferIPv6Addresses=system diff --git a/src/test/resources/META-INF/jarjar/ForgeJiJTestMod-1.5.jar b/src/test/resources/META-INF/jarjar/ForgeJiJTestMod-1.5.jar new file mode 100644 index 0000000000..be2cb6620a Binary files /dev/null and b/src/test/resources/META-INF/jarjar/ForgeJiJTestMod-1.5.jar differ diff --git a/src/test/resources/META-INF/jarjar/metadata.json b/src/test/resources/META-INF/jarjar/metadata.json index 4b0210ed9c..0bf777d705 100644 --- a/src/test/resources/META-INF/jarjar/metadata.json +++ b/src/test/resources/META-INF/jarjar/metadata.json @@ -7,9 +7,11 @@ }, "version": { "range": "[1.0,)", - "artifactVersion": "1.2" + "artifactVersion": "1.5" }, - "path": "META-INF/jarjar/ForgeJiJTestMod-1.2.jar" + "_pathMixin_should_crash_on_startup": "META-INF/jarjar/ForgeJiJTestMod-1.5.jar", + "path": "META-INF/jarjar/ForgeJiJTestMod-1.2.jar", + "_path_crash_test": "META-INF/jarjar/jijroot-1.3.jar" } ] } \ No newline at end of file