Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic mapping migration #57

Merged
merged 18 commits into from
Jun 1, 2024
Merged
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
22 changes: 22 additions & 0 deletions plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ repositories {
name = "gtnh"
url = uri("https://nexus.gtnewhorizons.com/repository/public/")
}
maven {
name = "paper"
url = uri("https://papermc.io/repo/repository/maven-snapshots/")
mavenContent {
includeGroup("org.cadixdev")
}
}
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
mavenContent {
includeGroup("org.cadixdev")
}
}
mavenCentral {}
gradlePluginPortal()
}
Expand Down Expand Up @@ -116,6 +130,11 @@ dependencies {
implementation("com.google.code.gson:gson:2.10.1")
// Forge utilities (to be merged into the source tree in the future)

// Source remapping
// We use Paper's Mercury fork because it both supports Java 17 and is binary compatible with mercurymixin.
implementation("org.cadixdev:mercury:0.1.2-paperweight-SNAPSHOT")
implementation("org.cadixdev:mercurymixin:0.1.0-SNAPSHOT")
implementation("net.fabricmc:mapping-io:0.5.1")
// Use JUnit Jupiter for testing.
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
Expand Down Expand Up @@ -245,6 +264,7 @@ val depsShadowJar = tasks.register<ShadowJar>("depsShadowJar") {
// we're already shading this in combinedShadowJar
exclude(project(":oldasmwrapper"))
}
mergeServiceFiles()
}

val mainShadowJar = tasks.register<ShadowJar>("mainShadowJar") {
Expand Down Expand Up @@ -305,6 +325,8 @@ val combinedShadowJar = tasks.register<Jar>("combinedShadowJar") {
exclude("META-INF/NOTICE")
exclude("META-INF/NOTICE*")
exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "module-info.class") // shadowJar defaults
exclude("LICENSE*")
exclude(".*", "*.html", "*.profile", "*.jar", "*.properties", "*.xml", "*.list", "META-INF/eclipse.inf") // eclipse stuff
}

tasks.jar.configure {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package com.gtnewhorizons.retrofuturagradle.modutils;

import java.io.CharArrayReader;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Collections;
import java.util.stream.Collectors;

import javax.inject.Inject;

import net.fabricmc.mappingio.adapter.MappingNsRenamer;
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
import net.fabricmc.mappingio.format.srg.SrgFileReader;
import net.fabricmc.mappingio.format.srg.SrgFileWriter;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
import net.fabricmc.mappingio.tree.VisitableMappingTree;

import org.cadixdev.lorenz.MappingSet;
import org.cadixdev.lorenz.io.MappingFormats;
import org.cadixdev.lorenz.io.MappingsReader;
import org.cadixdev.lorenz.io.MappingsWriter;
import org.cadixdev.mercury.Mercury;
import org.cadixdev.mercury.mixin.MixinRemapper;
import org.cadixdev.mercury.remapper.MercuryRemapper;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.InputDirectory;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.options.Option;

import com.gtnewhorizons.retrofuturagradle.util.Utilities;

public abstract class MigrateMappingsTask extends DefaultTask {

private static final boolean DEBUG_WRITE_DIFF = Boolean.parseBoolean(System.getenv("RFG_DEBUG_WRITE_MAPPING_DIFF"));

@Optional
@InputDirectory
@PathSensitive(PathSensitivity.RELATIVE)
@Option(
option = "mcpDir",
description = "The directory containing the mappings to migrate to, using MCP's fields.csv and methods.csv format.")
public abstract DirectoryProperty getMcpDir();

@InputDirectory
@PathSensitive(PathSensitivity.RELATIVE)
@Option(option = "inputDir", description = "The directory containing the source code to migrate.")
public abstract DirectoryProperty getInputDir();

@OutputDirectory
@Option(option = "outputDir", description = "The directory the migrated source code should be written to.")
public abstract DirectoryProperty getOutputDir();

@InputFile
@PathSensitive(PathSensitivity.NONE)
public abstract RegularFileProperty getSourceSrg();

@InputFile
@PathSensitive(PathSensitivity.NONE)
public abstract RegularFileProperty getSourceFieldsCsv();

@InputFile
@PathSensitive(PathSensitivity.NONE)
public abstract RegularFileProperty getSourceMethodsCsv();

@InputFiles
@Classpath
public abstract ConfigurableFileCollection getCompileClasspath();

@Inject
public MigrateMappingsTask() {
getInputDir().convention(getProject().getLayout().getProjectDirectory().dir("src/main/java"));
getOutputDir().convention(getProject().getLayout().getProjectDirectory().dir("src/main/java"));
}

@TaskAction
public void migrateMappings() throws Exception {
if (!getMcpDir().isPresent()) {
throw new IllegalArgumentException("A target mapping must be set using --mcpDir.");
}
File sourceFields = getSourceFieldsCsv().getAsFile().get();
File sourceMethods = getSourceMethodsCsv().getAsFile().get();

File target = getMcpDir().get().getAsFile();
File srg = getSourceSrg().getAsFile().get();

MemoryMappingTree notchSrg = new MemoryMappingTree();
SrgFileReader.read(Files.newBufferedReader(srg.toPath()), "official", "srg", notchSrg);

MemoryMappingTree sourceSrgMcp = new MemoryMappingTree();
Utilities.loadSrgMcpMappings(sourceSrgMcp, notchSrg, sourceMethods, sourceFields, null, null);

MemoryMappingTree targetSrgMcp = new MemoryMappingTree();
Utilities.loadSrgMcpMappings(
targetSrgMcp,
notchSrg,
new File(target, "methods.csv"),
new File(target, "fields.csv"),
null,
null);

MemoryMappingTree joinedSrgMcp = new MemoryMappingTree();
joinedSrgMcp.setSrcNamespace("srg");
sourceSrgMcp.accept(new MappingNsRenamer(joinedSrgMcp, Collections.singletonMap("mcp", "mcpSource")));
targetSrgMcp.accept(new MappingNsRenamer(joinedSrgMcp, Collections.singletonMap("mcp", "mcpTarget")));

MemoryMappingTree diffMcp = new MemoryMappingTree();
diffMcp.setSrcNamespace("mcpSource");
joinedSrgMcp.accept(new MappingSourceNsSwitch(diffMcp, "mcpSource"));
diffMcp.setDstNamespaces(Collections.singletonList("mcpTarget"));

MappingSet diffMcpLorenz = mappingIoToLorenz(diffMcp);

if (DEBUG_WRITE_DIFF) {
try (MappingsWriter w = MappingFormats.SRG
.createWriter(new File(getProject().getRootDir(), "diff.srg").toPath())) {
w.write(diffMcpLorenz);
}
}

final Mercury mercury = new Mercury();

mercury.getClassPath().addAll(
getCompileClasspath().getFiles().stream().map(File::toPath).filter(Files::exists)
.collect(Collectors.toList()));

// Fixes some issues like broken javadoc in Forge, and JDT not understanding Hodgepodge's obfuscated voxelmap
// targets.
mercury.setGracefulClasspathChecks(true);

mercury.getProcessors().add(MixinRemapper.create(diffMcpLorenz));
mercury.getProcessors().add(MercuryRemapper.create(diffMcpLorenz));

mercury.setSourceCompatibility(
getProject().getExtensions().getByType(JavaPluginExtension.class).getSourceCompatibility().toString());

mercury.rewrite(getInputDir().getAsFile().get().toPath(), getOutputDir().getAsFile().get().toPath());
}

/** Converts a MappingIO mapping to Lorenz's type. May not preserve parameter names and comments. */
private static MappingSet mappingIoToLorenz(VisitableMappingTree mappingIoMappings) throws IOException {
CharArrayWriter writer = new CharArrayWriter();
mappingIoMappings.accept(new SrgFileWriter(writer, false));
CharArrayReader reader = new CharArrayReader(writer.toCharArray());
MappingSet lorenzMappings = MappingSet.create();

try (final MappingsReader mappingsReader = MappingFormats.SRG.createReader(reader)) {
mappingsReader.read(lorenzMappings);
}
return lorenzMappings;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
import org.gradle.api.file.*;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.BasePluginExtension;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.plugins.scala.ScalaPlugin;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.jvm.tasks.Jar;
import org.gradle.language.jvm.tasks.ProcessResources;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.gradle.plugin.KaptExtension;
Expand Down Expand Up @@ -105,6 +107,24 @@ public ModUtils(Project project, MinecraftExtension mcExt, MinecraftTasks minecr
"Apply MCP decompiler cleanup to the main source set, doing things like replacing numerical OpenGL constants with their names");
});

project.getTasks().register("migrateMappings", MigrateMappingsTask.class, task -> {
task.setGroup(TASK_GROUP_USER);
task.setDescription("Migrate main source set to a new set of mappings");
task.dependsOn("extractMcpData", "extractForgeUserdev", "packagePatchedMc", "injectTags");
task.getSourceSrg()
.set(mcpTasks.getTaskGenerateForgeSrgMappings().flatMap(GenSrgMappingsTask::getInputSrg));
task.getSourceFieldsCsv()
.set(mcpTasks.getTaskGenerateForgeSrgMappings().flatMap(GenSrgMappingsTask::getFieldsCsv));
task.getSourceMethodsCsv()
.set(mcpTasks.getTaskGenerateForgeSrgMappings().flatMap(GenSrgMappingsTask::getMethodsCsv));
ConfigurableFileCollection cp = task.getCompileClasspath();
cp.from(project.getConfigurations().getByName("compileClasspath"));
cp.from(project.getTasks().named("packagePatchedMc", Jar.class));
cp.from(
project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets()
.getByName("injectedTags").getOutput());
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not entirely sure if I'm supposed to use .named here, when I tried using it it gave me an inscrutable compiler error so I went with getting it directly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfigurableFileCollection#from evaluates whatever is passed as-if they're passed to Project#files already, no need to also call Project#files here.

});

if (!disableDependencyDeobfuscation) {
project.getDependencies().getAttributesSchema().attribute(DEOBFUSCATOR_TRANSFORMED, ams -> {
ams.getCompatibilityRules().add(DeobfuscatorTransformerCompatRules.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -33,6 +34,10 @@

import javax.annotation.Nullable;

import net.fabricmc.mappingio.MappedElementKind;
import net.fabricmc.mappingio.tree.MappingTree;
import net.fabricmc.mappingio.tree.VisitableMappingTree;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -507,6 +512,65 @@ public static MappingsSet loadMappingCsvs(File methodsCsv, File fieldsCsv, @Null
}
}

public static void loadSrgMcpMappings(VisitableMappingTree srgMcp, VisitableMappingTree notchSrg, File methodsCsv,
File fieldsCsv, @Nullable File paramsCsv, @Nullable Collection<File> extraParamsCsvs) throws IOException {
MappingsSet mappings = loadMappingCsvs(methodsCsv, fieldsCsv, paramsCsv, extraParamsCsvs, null);

do {
if (srgMcp.visitHeader()) {
srgMcp.visitNamespaces("srg", Collections.singletonList("mcp"));
}

if (srgMcp.visitContent()) {
for (MappingTree.ClassMapping notchSrgClass : notchSrg.getClasses()) {
if (srgMcp.visitClass(notchSrgClass.getDstName(0))) {
srgMcp.visitDstName(MappedElementKind.CLASS, 0, notchSrgClass.getDstName(0));
if (srgMcp.visitElementContent(MappedElementKind.CLASS)) {
for (MappingTree.FieldMapping notchSrgField : notchSrgClass.getFields()) {
if (srgMcp.visitField(notchSrgField.getDstName(0), notchSrgField.getDstDesc(0))) {
Utilities.Mapping mapping = mappings.fieldMappings.get(notchSrgField.getDstName(0));
srgMcp.visitDstName(
MappedElementKind.FIELD,
0,
mapping != null ? mapping.name : null);
srgMcp.visitElementContent(MappedElementKind.FIELD);
// TODO javadoc
}
}
for (MappingTree.MethodMapping notchSrgMethod : notchSrgClass.getMethods()) {
if (srgMcp.visitMethod(notchSrgMethod.getDstName(0), notchSrgMethod.getDstDesc(0))) {
Utilities.Mapping mapping = mappings.methodMappings
.get(notchSrgMethod.getDstName(0));
srgMcp.visitDstName(
MappedElementKind.METHOD,
0,
mapping != null ? mapping.name : null);
// TODO javadoc

if (srgMcp.visitElementContent(MappedElementKind.METHOD)) {
for (MappingTree.MethodArgMapping notchSrgArg : notchSrgMethod.getArgs()) {
String dstName = mappings.paramMappings.get(notchSrgArg.getDstName(0));
if (srgMcp.visitMethodArg(
-1,
notchSrgArg.getLvIndex(),
notchSrgArg.getSrcName())) {
if (dstName != null) {
srgMcp.visitDstName(MappedElementKind.METHOD_ARG, 0, dstName);
}
srgMcp.visitElementContent(MappedElementKind.METHOD_ARG);
}
}
}
}
}
}
}
}
}

} while (!srgMcp.visitEnd());
}

/**
* @param classBytes The .class bytes to remap
* @param mappings The combined mappings set to use for renaming items
Expand Down
14 changes: 14 additions & 0 deletions testdepmod/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ buildscript {
includeGroup("net.minecraft")
}
}
maven {
name = "paper"
url = uri("https://papermc.io/repo/repository/maven-snapshots/")
mavenContent {
includeGroup("org.cadixdev")
}
}
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
mavenContent {
includeGroup("org.cadixdev")
}
}
mavenCentral {}
}
}
Expand Down
14 changes: 14 additions & 0 deletions testmod/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ buildscript {
includeGroup("net.minecraft")
}
}
maven {
name = "paper"
url = uri("https://papermc.io/repo/repository/maven-snapshots/")
mavenContent {
includeGroup("org.cadixdev")
}
}
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/content/repositories/snapshots/")
mavenContent {
includeGroup("org.cadixdev")
}
}
mavenCentral()
}
}
Expand Down
Loading
Loading