Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,6 @@ idea {
programParameters = "run --dist joined --neoforge net.neoforged:forge:1.20.1-47.1.54:userdev --parchment-data=org.parchmentmc.data:parchment-1.20.1:2023.09.03@zip --parchment-conflict-prefix=p_ --write-result=namedToIntermediaryMapping:build/1.20.1.tsrg --write-result=gameJarWithNeoForge:build/1.20.1-minecraft.jar --write-result=clientResources:build/1.20.1-client-extra.jar --write-result=gameSourcesWithNeoForge:build/1.20.1-minecraft-sources.jar --problems-report=build/1.20.1-problems.json"
moduleRef(project, sourceSets.main)
}
"Run Forge 1.12.2 (joined)"(Application) {
mainClass = mainClassName
programParameters = "run --dist joined --add-repository https://maven.minecraftforge.net --neoforge net.minecraftforge:forge:1.12.2-14.23.5.2860:userdev3 --write-result=gameJarWithNeoForge:build/1.12.2-minecraft.jar --write-result=clientResources:build/1.12.2-client-extra.jar --write-result=gameSourcesWithNeoForge:build/1.12.2-minecraft-sources.jar"
moduleRef(project, sourceSets.main)
}
"Run Forge 1.17.1 (joined)"(Application) {
mainClass = mainClassName
programParameters = "run --dist joined --add-repository https://maven.minecraftforge.net --neoforge net.minecraftforge:forge:1.17.1-37.1.1:userdev --write-result=gameJarWithNeoForge:build/1.17.1-minecraft.jar --write-result=clientResources:build/1.17.1-client-extra.jar --write-result=gameSourcesWithNeoForge:build/1.17.1-minecraft-sources.jar"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ public void run(ProcessingEnvironment environment) throws IOException, Interrupt
srgToOfficial.write(environment.getOutputPath("srgToOfficial"), IMappingFile.Format.SRG, false);

try (var zipCsv = new ZipOutputStream(Files.newOutputStream(environment.getOutputPath("csvMappings")))) {
// Match both modern intermediary names (m_/f_, 1.17+) and legacy SRG names (func_/field_, pre-1.17)
writeCsv(zipCsv, "methods.csv", srgToOfficial.getClasses().stream()
.flatMap(c -> c.getMethods().stream()).filter(c -> c.getOriginal().startsWith("m_")));
.flatMap(c -> c.getMethods().stream())
.filter(c -> c.getOriginal().startsWith("m_") || c.getOriginal().startsWith("func_")));
writeCsv(zipCsv, "fields.csv", srgToOfficial.getClasses().stream()
.flatMap(c -> c.getFields().stream()).filter(c -> c.getOriginal().startsWith("f_")));
.flatMap(c -> c.getFields().stream())
.filter(c -> c.getOriginal().startsWith("f_") || c.getOriginal().startsWith("field_")));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package net.neoforged.neoform.runtime.actions;

import net.neoforged.neoform.runtime.cache.CacheKeyBuilder;
import net.neoforged.neoform.runtime.engine.ProcessingEnvironment;
import net.neoforged.neoform.runtime.graph.ExecutionNodeAction;

import java.io.IOException;
import java.nio.file.Files;

/**
* Copies a NeoForm data source (a file embedded in the NeoForm config zip) to a node output,
* making it available as an input to downstream nodes in the execution graph.
*/
public class ExtractNeoFormDataAction implements ExecutionNodeAction {
private final String dataKey;

public ExtractNeoFormDataAction(String dataKey) {
this.dataKey = dataKey;
}

@Override
public void run(ProcessingEnvironment environment) throws IOException, InterruptedException {
Files.copy(environment.extractData(dataKey), environment.getOutputPath("output"));
}

@Override
public void computeCacheKey(CacheKeyBuilder ck) {
ExecutionNodeAction.super.computeCacheKey(ck);
ck.add("data key", dataKey);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public void acceptResult(CompilationResult result) {
while (entries.hasMoreElements()) {
var entry = entries.nextElement();
if (!entry.isDirectory()) {
if (entry.getName().endsWith(".java")) {
if (entry.getName().endsWith(".java") && !entry.getName().equals("package-info-template.java")) {
futures.add(executor.submit(() -> {
// TODO This is copy heavy and should be optimized
try (var in = sourcesZip.getInputStream(entry)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public void run(ProcessingEnvironment environment) throws IOException, Interrupt
try (var stream = Files.walk(sourceRoot).filter(Files::isRegularFile)) {
stream.forEach(path -> {
var filename = path.getFileName().toString();
if (filename.endsWith(".java")) {
if (filename.endsWith(".java") && !filename.equals("package-info-template.java")) {
sourcePaths.add(path);
} else {
nonSourcePaths.add(path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,30 @@ public Artifact get(MavenCoordinate mavenCoordinate) throws IOException {
return externalArtifact;
}

// Yet another special case: dynamic versions!
// Used in 1.12.1, for example. And yes, this will be very slow.
if (mavenCoordinate.isDynamicVersion()) {
var availableVersions = MavenMetadata.gatherVersions(
downloadManager,
repositoryBaseUrls,
mavenCoordinate.groupId(),
mavenCoordinate.artifactId()
);
for (var availableVersion : availableVersions) {
if (mavenCoordinate.matchesVersion(availableVersion.version())) {
var concreteMavenCoordinate = mavenCoordinate.withVersion(availableVersion.version());
return get(concreteMavenCoordinate, availableVersion.repositoryUrl());
}
}

throw new FileNotFoundException("Could not find " + mavenCoordinate + " in any repository.");
}

var finalLocation = artifactsCache.resolve(mavenCoordinate.toRelativeRepositoryPath());

// Special case: NeoForge reference libraries that are only available via the Mojang download server
if (mavenCoordinate.groupId().equals("com.mojang") && mavenCoordinate.artifactId().equals("logging")) {
if ((mavenCoordinate.groupId().equals("com.mojang") && mavenCoordinate.artifactId().equals("logging"))
|| (mavenCoordinate.groupId().equals("net.minecraft") && mavenCoordinate.artifactId().equals("launchwrapper"))) {
return get(mavenCoordinate, MINECRAFT_LIBRARIES_URI);
}

Expand Down Expand Up @@ -258,11 +278,22 @@ public interface DownloadAction {
}

private Artifact getFromExternalManifest(MavenCoordinate artifactCoordinate) {
// Try direct match first
var artifact = externallyProvided.get(artifactCoordinate);
if (artifact != null) {
return artifact;
}

// Find any manifest entry for the same group/artifact/classifier and evaluate if it matches a dynamic version constraint
if (artifactCoordinate.isDynamicVersion()) {
for (var entry : externallyProvided.entrySet()) {
if (artifactCoordinate.equalsWithoutVersion(entry.getKey())
&& artifactCoordinate.matchesVersion(entry.getKey().version())) {
return entry.getValue();
}
}
}

// Fall back to looking up a wildcard version for dependency replacement in includeBuild scenarios
if (!"*".equals(artifactCoordinate.version())) {
artifact = externallyProvided.get(artifactCoordinate.withVersion("*"));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package net.neoforged.neoform.runtime.artifacts;

import net.neoforged.neoform.runtime.downloads.DownloadManager;
import net.neoforged.neoform.runtime.utils.Logger;
import org.w3c.dom.Element;

import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;

/**
* Support class for querying maven metadata from a remote repository.
* The format is documented here: https://maven.apache.org/repositories/metadata.html
* We only deal with A-level metadata since we're interested in listing the versions of
* a specific artifact.
*/
final class MavenMetadata {
private static final Logger LOG = Logger.create();

private MavenMetadata() {
}

static List<AvailableVersion> gatherVersions(DownloadManager downloadManager,
List<URI> repositoryBaseUrls,
String groupId,
String artifactId) throws IOException {
var versions = new ArrayList<AvailableVersion>();
for (var repositoryBaseUrl : repositoryBaseUrls) {
versions.addAll(gatherVersions(downloadManager, repositoryBaseUrl, groupId, artifactId));
}
return versions;
}

static List<AvailableVersion> gatherVersions(DownloadManager downloadManager,
URI repositoryBaseUrl,
String groupId,
String artifactId) throws IOException {
var metadataUri = repositoryBaseUrl.toString();
if (!metadataUri.endsWith("/")) {
metadataUri += "/";
}
metadataUri += groupId.replace('.', '/') + "/" + artifactId + "/maven-metadata.xml";

byte[] metadataContent;

var tempFile = Files.createTempFile("maven-metadata", ".xml");
try {
Files.deleteIfExists(tempFile); // The downloader should assume it does not exist yet
downloadManager.download(URI.create(metadataUri), tempFile);
metadataContent = Files.readAllBytes(tempFile);
} catch (FileNotFoundException fnf) {
return List.of(); // Repository doesn't have artifact
} finally {
Files.deleteIfExists(tempFile);
}

try (var in = new ByteArrayInputStream(metadataContent)) {
var result = new ArrayList<AvailableVersion>();
var documentBuilder = DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder();
var document = documentBuilder.parse(in).getDocumentElement();
var nodes = document.getChildNodes();
for (var i = 0; i < nodes.getLength(); i++) {
if (nodes.item(i) instanceof Element versioningEl && "versioning".equals(versioningEl.getTagName())) {
for (var versions = versioningEl.getFirstChild(); versions != null; versions = versions.getNextSibling()) {
if (versions instanceof Element versionsEl && "versions".equals(versionsEl.getTagName())) {
for (var child = versionsEl.getFirstChild(); child != null; child = child.getNextSibling()) {
if (child instanceof Element childEl && "version".equals(childEl.getTagName())) {
result.add(new AvailableVersion(
repositoryBaseUrl,
childEl.getTextContent().trim()
));
}
}
}
}
}
}
return result;
} catch (Exception e) {
LOG.println("Failed to parse Maven metadata from " + metadataUri + ": " + e);
throw new RuntimeException(e);
}
}

record AvailableVersion(URI repositoryUrl, String version) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.jar.JarFile;
Expand Down Expand Up @@ -220,6 +221,15 @@ private static void applyNeoForgeProcessTransforms(NeoFormEngine engine, JarFile
// The MCF sources have a bogus MANIFEST that should be ignored
Pattern.compile("^(?!META-INF/MANIFEST.MF$).*")
));
// Older Forge versions ship pre-compiled dev-only classes and service registrations
// (e.g. ILaunchHandlerService) under inject/ in the userdev jar.
if (neoforgeConfig.injectFolder() != null) {
action.getInjectedSources().add(new InjectFromZipFileSource(
neoforgeZipFile,
neoforgeConfig.injectFolder(),
Pattern.compile("^(?!.*\\.class$).*")
));
}
}
));
}
Expand Down Expand Up @@ -263,8 +273,28 @@ private static void applyNeoForgeProcessTransforms(NeoFormEngine engine, JarFile
}
}

// Source post-processors were used to post-process the decompiler output before applying the NF patches.
// Example version: 1.12.2.
var nfPatchesInputNode = "patch";
var sourcePreProcessor = neoforgeConfig.sourcePreProcessor();
if (sourcePreProcessor != null) {
engine.applyTransform(new ReplaceNodeOutput(
"patch", "output", "applyUserdevSourcePreprocessor",
(builder, previousOutput) -> {
var newOutput = engine.applyFunctionToNode(neoforgeConfig.libraries(), Map.of(
// Provide the output of patch as the input
"input", "{patchOutput}"
), NodeOutputType.ZIP, sourcePreProcessor, builder);
return Objects.requireNonNull(newOutput);
}
)
);
// Patches now need to use this node as input
nfPatchesInputNode = "applyUserdevSourcePreprocessor";
}

// Append a patch step to the NeoForge patches
engine.applyTransform(new ReplaceNodeOutput("patch", "output", "applyNeoforgePatches",
engine.applyTransform(new ReplaceNodeOutput(nfPatchesInputNode, "output", "applyNeoforgePatches",
(builder, previousOutput) -> {
return PatchActionFactory.makeAction(builder,
new DataSource(neoforgeZipFile, neoforgeConfig.patchesFolder(), engine.getFileHashingService()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.google.gson.annotations.SerializedName;
import net.neoforged.neoform.runtime.config.neoform.NeoFormFunction;
import net.neoforged.neoform.runtime.utils.FilenameUtil;
import net.neoforged.neoform.runtime.utils.MavenCoordinate;
import org.jetbrains.annotations.Nullable;
Expand All @@ -28,10 +29,13 @@ public record NeoForgeConfig(
@SerializedName("universal") String universalArtifact,
@SerializedName("patchesOriginalPrefix") @Nullable String basePathPrefix,
@SerializedName("patchesModifiedPrefix") @Nullable String modifiedPathPrefix,
@SerializedName("inject") @Nullable String injectFolder,
Map<String, JsonObject> runs,
List<MavenCoordinate> libraries,
List<String> modules,
@SerializedName("sass") List<String> sideAnnotationStrippers
@SerializedName("sass") List<String> sideAnnotationStrippers,
// This was used in older MC versions (i.e. 1.12.2)
@SerializedName("processor") @Nullable NeoFormFunction sourcePreProcessor
) {
public static NeoForgeConfig from(ZipFile zipFile) throws IOException {
byte[] configContent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public record NeoFormConfig(int spec,
Map<String, List<NeoFormStep>> steps,
Map<String, NeoFormFunction> functions,
Map<String, List<MavenCoordinate>> libraries) {
public NeoFormConfig {
if (javaVersion == 0) {
javaVersion = 8; // Older versions did not explicitly specify 8
}
}

public NeoFormDistConfig getDistConfig(String dist) {
if (!steps.containsKey(dist)) {
Expand Down
Loading
Loading