Skip to content

Commit

Permalink
Inject interfaces to vanilla classes using JST (#1765)
Browse files Browse the repository at this point in the history
  • Loading branch information
Matyrobbrt authored Dec 15, 2024
1 parent cdd9e5b commit 52733f5
Show file tree
Hide file tree
Showing 94 changed files with 452 additions and 789 deletions.
28 changes: 11 additions & 17 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,28 +72,22 @@ immaculate {
return fileContents
}

def interfaceChange = Pattern.compile('^[-+].*(implements|(interface.*extends)).*\$', Pattern.UNIX_LINES | Pattern.MULTILINE)
custom 'noInterfaceRemoval', { String fileContents ->
def interfaceChanges = fileContents.findAll(interfaceChange)
def interfaceChange = Pattern.compile('[-+].*(implements|(interface.*extends))(.*)\\{')
custom 'noInterfaceModifications', { String fileContents ->
def interfaceChanges = fileContents.lines().filter { it.matches(interfaceChange) }.toList()
if (interfaceChanges.isEmpty()) return fileContents
String removalChange = ""
String oldInterfaces = ""
// we expect interface additions/removals in pairs of - and then +
interfaceChanges.each { String change ->
final match = change =~ interfaceChange
match.find()
final values = match.group(3).trim()
if (change.startsWith('-')) {
//Skip the - and the ending brace
int implementsIndex = change.indexOf("implements")
if (implementsIndex == -1) implementsIndex = change.indexOf("extends")
//It should never still be -1 based on our initial matching regex, but if it does fail so we can figure out why
if (implementsIndex == -1) implementsIndex = 1
removalChange = change.substring(implementsIndex, change.length() - 1).trim()
} else if (!removalChange.isEmpty() && !change.contains(removalChange)) {
throw new GradleException("Removal of interfaces via patches is not allowed!")
} else {
removalChange = ""
oldInterfaces = values
} else if (oldInterfaces != values) {
throw new GradleException("Modification of interfaces via patches is not allowed!")
}
}
if (!removalChange.isEmpty()) {
throw new GradleException("Removal of interfaces via patches is not allowed!")
}
return fileContents
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputDirectory;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
Expand All @@ -25,9 +27,14 @@ abstract class GenerateSourcePatches extends DefaultTask {
@PathSensitive(PathSensitivity.RELATIVE)
public abstract DirectoryProperty getModifiedSources();

@Optional
@OutputFile
public abstract RegularFileProperty getPatchesJar();

@Optional
@OutputDirectory
public abstract DirectoryProperty getPatchesFolder();

@Inject
public GenerateSourcePatches() {}

Expand All @@ -37,7 +44,7 @@ public void generateSourcePatches() throws IOException {
.logTo(getLogger()::lifecycle)
.baseInput(MultiInput.detectedArchive(getOriginalJar().get().getAsFile().toPath()))
.changedInput(MultiInput.folder(getModifiedSources().get().getAsFile().toPath()))
.patchesOutput(MultiOutput.detectedArchive(getPatchesJar().get().getAsFile().toPath()))
.patchesOutput(getPatchesJar().isPresent() ? MultiOutput.detectedArchive(getPatchesJar().get().getAsFile().toPath()) : MultiOutput.folder(getPatchesFolder().getAsFile().get().toPath()))
.autoHeader(true)
.level(io.codechicken.diffpatch.util.LogLevel.WARN)
.summary(false)
Expand Down
52 changes: 35 additions & 17 deletions buildSrc/src/main/java/net/neoforged/neodev/NeoDevPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,24 +100,39 @@ public void apply(Project project) {
);
var applyAt = configureAccessTransformer(
project,
configurations,
createSourceArtifacts,
neoDevBuildDir,
atFiles);

applyAt.configure(task -> task.mustRunAfter(genAtsTask));

// 3. Apply patches to the source jar from 2.
// 3. Apply interface injections after the ATs
// this jar is only used for the patches in the repo
var applyInterfaceInjection = project.getTasks().register("applyInterfaceInjection", TransformSources.class, task -> {
task.getInputJar().set(applyAt.flatMap(TransformSources::getOutputJar));
task.getInterfaceInjectionData().from(project.getRootProject().file("src/main/resources/META-INF/injected-interfaces.json"));
task.getOutputJar().set(neoDevBuildDir.map(dir -> dir.file("artifacts/interface-injected-sources.jar")));
});

tasks.withType(TransformSources.class, task -> {
task.setGroup(INTERNAL_GROUP);
task.classpath(configurations.getExecutableTool(Tools.JST));

task.getLibraries().from(configurations.neoFormClasspath);
task.getLibrariesFile().set(neoDevBuildDir.map(dir -> dir.file("minecraft-libraries-for-" + task.getName() + ".txt")));
});

// 4. Apply patches to the source jar from 3.
var patchesFolder = project.getRootProject().file("patches");
var applyPatches = tasks.register("applyPatches", ApplyPatches.class, task -> {
task.setGroup(INTERNAL_GROUP);
task.getOriginalJar().set(applyAt.flatMap(ApplyAccessTransformer::getOutputJar));
task.getOriginalJar().set(applyInterfaceInjection.flatMap(TransformSources::getOutputJar));
task.getPatchesFolder().set(patchesFolder);
task.getPatchedJar().set(neoDevBuildDir.map(dir -> dir.file("artifacts/patched-sources.jar")));
task.getRejectsFolder().set(project.getRootProject().file("rejects"));
});

// 4. Unpack jar from 3.
// 5. Unpack jar from 4.
var mcSourcesPath = project.file("src/main/java");
tasks.register("setup", Sync.class, task -> {
task.setGroup(GROUP);
Expand Down Expand Up @@ -185,14 +200,22 @@ public void apply(Project project) {
* OTHER TASKS
*/

// Generate source patches into a patch archive.
// Generate source patches into a patch archive, based on the jar with injected interfaces.
var genSourcePatches = tasks.register("generateSourcePatches", GenerateSourcePatches.class, task -> {
task.setGroup(INTERNAL_GROUP);
task.getOriginalJar().set(applyAt.flatMap(ApplyAccessTransformer::getOutputJar));
task.getOriginalJar().set(applyInterfaceInjection.flatMap(TransformSources::getOutputJar));
task.getModifiedSources().set(project.file("src/main/java"));
task.getPatchesJar().set(neoDevBuildDir.map(dir -> dir.file("source-patches.zip")));
});

// Generate source patches that are based on the production environment (without separate interface injection)
var genProductionPatches = tasks.register("generateProductionSourcePatches", GenerateSourcePatches.class, task -> {
task.setGroup(INTERNAL_GROUP);
task.getOriginalJar().set(applyAt.flatMap(TransformSources::getOutputJar));
task.getModifiedSources().set(project.file("src/main/java"));
task.getPatchesFolder().set(neoDevBuildDir.map(dir -> dir.dir("production-source-patches")));
});

// Update the patch/ folder with the current patches.
tasks.register("genPatches", Sync.class, task -> {
task.setGroup(GROUP);
Expand Down Expand Up @@ -245,7 +268,7 @@ public void apply(Project project) {
configurations,
createCleanArtifacts,
neoDevBuildDir,
patchesFolder
genProductionPatches.flatMap(GenerateSourcePatches::getPatchesFolder)
);

// Launcher profile = the version.json file used by the Minecraft launcher.
Expand Down Expand Up @@ -411,7 +434,7 @@ public void apply(Project project) {
task.from(binaryPatchOutputs.binaryPatchesForMerged(), spec -> {
spec.rename(s -> "joined.lzma");
});
task.from(project.zipTree(genSourcePatches.flatMap(GenerateSourcePatches::getPatchesJar)), spec -> {
task.from(project.fileTree(genProductionPatches.flatMap(GenerateSourcePatches::getPatchesFolder)), spec -> {
spec.into("patches/");
});
});
Expand Down Expand Up @@ -444,32 +467,27 @@ public void apply(Project project) {
setupProductionServerTest(project, installerJar);
}

private static TaskProvider<ApplyAccessTransformer> configureAccessTransformer(
private static TaskProvider<TransformSources> configureAccessTransformer(
Project project,
NeoDevConfigurations configurations,
TaskProvider<CreateMinecraftArtifacts> createSourceArtifacts,
Provider<Directory> neoDevBuildDir,
List<File> atFiles) {

// Pass -PvalidateAccessTransformers to validate ATs.
var validateAts = project.getProviders().gradleProperty("validateAccessTransformers").map(p -> true).orElse(false);
return project.getTasks().register("applyAccessTransformer", ApplyAccessTransformer.class, task -> {
task.setGroup(INTERNAL_GROUP);
task.classpath(configurations.getExecutableTool(Tools.JST));
return project.getTasks().register("applyAccessTransformer", TransformSources.class, task -> {
task.getInputJar().set(createSourceArtifacts.flatMap(CreateMinecraftArtifacts::getSourcesArtifact));
task.getAccessTransformers().from(atFiles);
task.getValidate().set(validateAts);
task.getValidateAccessTransformers().set(validateAts);
task.getOutputJar().set(neoDevBuildDir.map(dir -> dir.file("artifacts/access-transformed-sources.jar")));
task.getLibraries().from(configurations.neoFormClasspath);
task.getLibrariesFile().set(neoDevBuildDir.map(dir -> dir.file("minecraft-libraries-for-jst.txt")));
});
}

private static BinaryPatchOutputs configureBinaryPatchCreation(Project project,
NeoDevConfigurations configurations,
TaskProvider<CreateCleanArtifacts> createCleanArtifacts,
Provider<Directory> neoDevBuildDir,
File sourcesPatchesFolder) {
Provider<Directory> sourcesPatchesFolder) {
var tasks = project.getTasks();

var artConfig = configurations.getExecutableTool(Tools.AUTO_RENAMING_TOOL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.JavaExec;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;

Expand All @@ -22,20 +23,23 @@
import java.util.Arrays;

/**
* Runs <a href="https://github.com/neoforged/JavaSourceTransformer">JavaSourceTransformer</a> to apply
* access transformers to the Minecraft source code for extending the access level of existing classes/methods/etc.
* <p>
* Note that at runtime, FML also applies access transformers.
* Runs <a href="https://github.com/neoforged/JavaSourceTransformer">JavaSourceTransformer</a> over the Minecraft source code.
*/
abstract class ApplyAccessTransformer extends JavaExec {
@InputFile
public abstract RegularFileProperty getInputJar();

abstract class TransformSources extends JavaExec {
@Optional
@InputFiles
public abstract ConfigurableFileCollection getAccessTransformers();

@Input
public abstract Property<Boolean> getValidate();
@Optional
public abstract Property<Boolean> getValidateAccessTransformers();

@Optional
@InputFiles
public abstract ConfigurableFileCollection getInterfaceInjectionData();

@InputFile
public abstract RegularFileProperty getInputJar();

@OutputFile
public abstract RegularFileProperty getOutputJar();
Expand All @@ -48,7 +52,7 @@ abstract class ApplyAccessTransformer extends JavaExec {
public abstract RegularFileProperty getLibrariesFile();

@Inject
public ApplyAccessTransformer() {}
public TransformSources() {}

@Override
@TaskAction
Expand All @@ -63,15 +67,29 @@ public void exec() {
}

var args = new ArrayList<>(Arrays.asList(
"--enable-accesstransformers",
"--access-transformer-validation", getValidate().get() ? "error" : "log",
"--libraries-list", getLibrariesFile().getAsFile().get().getAbsolutePath()
));

for (var file : getAccessTransformers().getFiles()) {
if (!getAccessTransformers().isEmpty()) {
args.addAll(Arrays.asList(
"--access-transformer", file.getAbsolutePath()
"--enable-accesstransformers",
"--access-transformer-validation", getValidateAccessTransformers().get() ? "error" : "log"
));
for (var file : getAccessTransformers().getFiles()) {
args.addAll(Arrays.asList(
"--access-transformer", file.getAbsolutePath()
));
}
}

if (!getInterfaceInjectionData().isEmpty()) {
args.add("--enable-interface-injection");

for (var file : getInterfaceInjectionData().getFiles()) {
args.addAll(Arrays.asList(
"--interface-injection-data", file.getAbsolutePath()
));
}
}

args.addAll(Arrays.asList(
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ neoform_version=20241203.161809
neoforge_snapshot_next_stable=21.5

# renovate: net.neoforged.jst:jst-cli-bundle
jst_version=1.0.45
jst_version=1.0.67
legacyinstaller_version=3.0.+
# renovate: net.neoforged:AutoRenamingTool
art_version=2.0.3
Expand Down
11 changes: 0 additions & 11 deletions patches/com/mojang/blaze3d/vertex/PoseStack.java.patch

This file was deleted.

9 changes: 0 additions & 9 deletions patches/com/mojang/blaze3d/vertex/VertexConsumer.java.patch
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
--- a/com/mojang/blaze3d/vertex/VertexConsumer.java
+++ b/com/mojang/blaze3d/vertex/VertexConsumer.java
@@ -13,7 +_,7 @@
import org.lwjgl.system.MemoryStack;

@OnlyIn(Dist.CLIENT)
-public interface VertexConsumer {
+public interface VertexConsumer extends net.neoforged.neoforge.client.extensions.IVertexConsumerExtension {
VertexConsumer addVertex(float p_350761_, float p_350704_, float p_350711_);

VertexConsumer setColor(int p_350535_, int p_350875_, int p_350886_, int p_350775_);
@@ -131,11 +_,14 @@
f5 = p_331397_[i1] * p_85992_ * 255.0F;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,14 @@
@OnlyIn(Dist.CLIENT)
public static enum Type {
FLOAT(4, "Float", 5126),
@@ -113,7 +_,8 @@
@@ -113,6 +_,7 @@
}

@OnlyIn(Dist.CLIENT)
- public static enum Usage {
+ @net.neoforged.fml.common.asm.enumextension.NamedEnum
+ public static enum Usage implements net.neoforged.fml.common.asm.enumextension.IExtensibleEnum {
public static enum Usage implements net.neoforged.fml.common.asm.enumextension.IExtensibleEnum {
POSITION(
"Position",
(p_349733_, p_349734_, p_349735_, p_349736_, p_349737_) -> GlStateManager._vertexAttribPointer(
@@ -163,6 +_,10 @@
@OnlyIn(Dist.CLIENT)
public interface SetupState {
Expand Down
23 changes: 7 additions & 16 deletions patches/com/mojang/math/Transformation.java.patch
Original file line number Diff line number Diff line change
@@ -1,20 +1,9 @@
--- a/com/mojang/math/Transformation.java
+++ b/com/mojang/math/Transformation.java
@@ -13,7 +_,7 @@
import org.joml.Quaternionf;
import org.joml.Vector3f;

-public final class Transformation {
+public final class Transformation implements net.neoforged.neoforge.common.extensions.ITransformationExtension {
private final Matrix4f matrix;
public static final Codec<Transformation> CODEC = RecordCodecBuilder.create(
p_269604_ -> p_269604_.group(
@@ -157,6 +_,19 @@
@Override
public int hashCode() {
@@ -159,6 +_,19 @@
return Objects.hash(this.matrix);
+ }
+
}
+ private Matrix3f normalTransform = null;
+ public Matrix3f getNormalMatrix() {
+ checkNormalTransform();
Expand All @@ -26,6 +15,8 @@
+ normalTransform.invert();
+ normalTransform.transpose();
+ }
}
+ }
+
public Transformation slerp(Transformation p_175938_, float p_175939_) {
Vector3f vector3f = this.getTranslation();
Quaternionf quaternionf = this.getLeftRotation();
9 changes: 0 additions & 9 deletions patches/net/minecraft/advancements/Advancement.java.patch
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,3 @@

public Advancement(
Optional<ResourceLocation> p_300893_,
@@ -111,7 +_,7 @@
});
}

- public static class Builder {
+ public static class Builder implements net.neoforged.neoforge.common.extensions.IAdvancementBuilderExtension {
private Optional<ResourceLocation> parent = Optional.empty();
private Optional<DisplayInfo> display = Optional.empty();
private AdvancementRewards rewards = AdvancementRewards.EMPTY;
7 changes: 2 additions & 5 deletions patches/net/minecraft/client/KeyMapping.java.patch
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
--- a/net/minecraft/client/KeyMapping.java
+++ b/net/minecraft/client/KeyMapping.java
@@ -15,9 +_,9 @@
import net.neoforged.api.distmarker.OnlyIn;

@@ -17,7 +_,7 @@
@OnlyIn(Dist.CLIENT)
-public class KeyMapping implements Comparable<KeyMapping> {
+public class KeyMapping implements Comparable<KeyMapping>, net.neoforged.neoforge.client.extensions.IKeyMappingExtension {
public class KeyMapping implements Comparable<KeyMapping>, net.neoforged.neoforge.client.extensions.IKeyMappingExtension {
private static final Map<String, KeyMapping> ALL = Maps.newHashMap();
- private static final Map<InputConstants.Key, KeyMapping> MAP = Maps.newHashMap();
+ private static final net.neoforged.neoforge.client.settings.KeyMappingLookup MAP = new net.neoforged.neoforge.client.settings.KeyMappingLookup();
Expand Down
Loading

0 comments on commit 52733f5

Please sign in to comment.