From c1faa2999dfd9a827b2ebccbe85b9b101e125969 Mon Sep 17 00:00:00 2001 From: Luke Bemish Date: Sat, 4 Apr 2026 22:33:56 -0400 Subject: [PATCH 1/4] JST enum extension support Still needs InstallerTools support --- README.md | 3 +- .../actions/ApplyDevTransformsAction.java | 28 ++++++++++++++++ .../actions/ApplySourceTransformAction.java | 32 +++++++++++++++++++ .../actions/EnumExtensionDefaults.java | 13 ++++++++ .../runtime/cli/RunNeoFormCommand.java | 19 ++++++++++- src/main/resources/tools.properties | 2 +- 6 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 src/main/java/net/neoforged/neoform/runtime/actions/EnumExtensionDefaults.java diff --git a/README.md b/README.md index 4d53261f..c4e6e381 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,9 @@ This produces the Vanilla artifacts in build/ | `--write-result=:` | This option can be passed multiple times. It tells NFRT to write a result of the execution graph to the given path, such as the recompiled Minecraft jar-file, or the sources. If you pass no such option, NFRT will print which results are available. | | `--access-transformer=` | Adds access transformers which will be applied to the source before recompiling it. | | `--interface-injection-data=` | Adds [interface injection data](https://github.com/neoforged/JavaSourceTransformer?tab=readme-ov-file#interface-injection) which will be applied to the source before recompiling it. | +| `--enum-extensions-data=` | Adds [enum extensions](https://docs.neoforged.net/docs/advanced/extensibleenums/) to apply to the sources before recompiling. | | `--repository=` | Adds additional repositories that NFRT will use when it downloads artifacts. By default, the NeoForge repository and local Maven are used. | -| `--launcher-meta-uri=` | Specifies a different URL to download the Launcher manifest from. The default is `https://launchermeta.mojang.com/mc/game/version_manifest_v2.json` | | +| `--launcher-meta-uri=` | Specifies a different URL to download the Launcher manifest from. The default is `https://launchermeta.mojang.com/mc/game/version_manifest_v2.json` | | `--disable-cache` | Disables use of the intermediate result cache. | | `--print-graph` | Prints information about the execution graph used to create the artifacts. | | `--use-eclipse-compiler` | When recompiling Minecraft sources, use the Eclipse compiler rather than javac. The Eclipse compiler is able to compile in parallel, while javac is single-threaded. | diff --git a/src/main/java/net/neoforged/neoform/runtime/actions/ApplyDevTransformsAction.java b/src/main/java/net/neoforged/neoform/runtime/actions/ApplyDevTransformsAction.java index d7132ab0..ae6ac4ba 100644 --- a/src/main/java/net/neoforged/neoform/runtime/actions/ApplyDevTransformsAction.java +++ b/src/main/java/net/neoforged/neoform/runtime/actions/ApplyDevTransformsAction.java @@ -29,6 +29,11 @@ public class ApplyDevTransformsAction extends ExternalJavaToolAction { */ private List injectedInterfaces = List.of(); + /** + * Paths to enum extensions to apply. + */ + private List enumExtensions = List.of(); + public ApplyDevTransformsAction() { super(ToolCoordinate.INSTALLER_TOOLS); } @@ -64,6 +69,20 @@ public void run(ProcessingEnvironment environment) throws IOException, Interrupt args.add(environment.getPathArgument(path.toAbsolutePath())); } + for (var path : enumExtensions) { + args.add("--enum-extensions-data"); + args.add(environment.getPathArgument(path.toAbsolutePath())); + } + + args.add("--enum-extensions-required-interface"); + args.add(EnumExtensionDefaults.REQUIRED_INTERFACE); + args.add("--enum-extensions-indexed-enum-annotation"); + args.add(EnumExtensionDefaults.INDEXED_ENUM); + args.add("--enum-extensions-marker"); + args.add(EnumExtensionDefaults.MARKER_ANNOTATION); + args.add("--enum-extensions-reserved-constructor-annotation"); + args.add(EnumExtensionDefaults.RESERVED_CONSTRUCTOR); + setArgs(args); super.run(environment); } @@ -74,6 +93,7 @@ public void computeCacheKey(CacheKeyBuilder ck) { ck.addStrings("access transformers data ids", accessTransformersData); ck.addPaths("additional access transformers", additionalAccessTransformers); ck.addPaths("injected interfaces", injectedInterfaces); + ck.addPaths("enum extensions", enumExtensions); } public void setAccessTransformersData(List accessTransformersData) { @@ -99,4 +119,12 @@ public void setInjectedInterfaces(List injectedInterfaces) { public List getInjectedInterfaces() { return injectedInterfaces; } + + public void setEnumExtensions(List enumExtensions) { + this.enumExtensions = List.copyOf(enumExtensions); + } + + public List getEnumExtensions() { + return enumExtensions; + } } diff --git a/src/main/java/net/neoforged/neoform/runtime/actions/ApplySourceTransformAction.java b/src/main/java/net/neoforged/neoform/runtime/actions/ApplySourceTransformAction.java index a6bd0490..53b052f0 100644 --- a/src/main/java/net/neoforged/neoform/runtime/actions/ApplySourceTransformAction.java +++ b/src/main/java/net/neoforged/neoform/runtime/actions/ApplySourceTransformAction.java @@ -64,6 +64,11 @@ public class ApplySourceTransformAction extends ExternalJavaToolAction { */ private List injectedInterfaces = new ArrayList<>(); + /** + * Additional paths to enum extensions. + */ + private List enumExtensions = new ArrayList<>(); + /** * Path to a Parchment data archive. */ @@ -128,6 +133,24 @@ public void run(ProcessingEnvironment environment) throws IOException, Interrupt args.add("{stubs}"); } + if (!enumExtensions.isEmpty()) { + args.add("--enable-enum-extensions"); + for (var path : enumExtensions) { + args.add("--enum-extensions-data"); + args.add(environment.getPathArgument(path.toAbsolutePath())); + } + args.add("--enum-extensions-stubs"); + args.add("{stubs}"); + args.add("--enum-extensions-required-interface"); + args.add(EnumExtensionDefaults.REQUIRED_INTERFACE); + args.add("--enum-extensions-indexed-enum-annotation"); + args.add(EnumExtensionDefaults.INDEXED_ENUM); + args.add("--enum-extensions-marker"); + args.add(EnumExtensionDefaults.MARKER_ANNOTATION); + args.add("--enum-extensions-reserved-constructor-annotation"); + args.add(EnumExtensionDefaults.RESERVED_CONSTRUCTOR); + } + if (parchmentData != null) { args.add("--enable-parchment"); args.add("--parchment-mappings=" + environment.getPathArgument(parchmentData.toAbsolutePath())); @@ -210,6 +233,7 @@ public void computeCacheKey(CacheKeyBuilder ck) { ck.addPaths("additional access transformers", additionalAccessTransformers); ck.addPaths("validated access transformers", validatedAccessTransformers); ck.addPaths("injected interfaces", injectedInterfaces); + ck.addPaths("enum extensions", enumExtensions); if (parchmentData != null) { ck.addPath("parchment data", parchmentData); } @@ -250,6 +274,14 @@ public void setInjectedInterfaces(List injectedInterfaces) { this.injectedInterfaces = List.copyOf(injectedInterfaces); } + public List getInjectedInterfaces() { + return injectedInterfaces; + } + + public void setEnumExtensions(List enumExtensions) { + this.enumExtensions = List.copyOf(enumExtensions); + } + public @Nullable Path getParchmentData() { return parchmentData; } diff --git a/src/main/java/net/neoforged/neoform/runtime/actions/EnumExtensionDefaults.java b/src/main/java/net/neoforged/neoform/runtime/actions/EnumExtensionDefaults.java new file mode 100644 index 00000000..c0c0cf48 --- /dev/null +++ b/src/main/java/net/neoforged/neoform/runtime/actions/EnumExtensionDefaults.java @@ -0,0 +1,13 @@ +package net.neoforged.neoform.runtime.actions; + +/** + * Various defaults for JST or binary enum extension + */ +final class EnumExtensionDefaults { + private EnumExtensionDefaults() {} + + static final String REQUIRED_INTERFACE = "net/neoforged/fml/common/asm/enumextension/IExtensibleEnum"; + static final String INDEXED_ENUM = "net/neoforged/fml/common/asm/enumextension/IndexedEnum"; + static final String MARKER_ANNOTATION = "net/neoforged/fml/common/asm/enumextension/ExtensionEnumEntry"; + static final String RESERVED_CONSTRUCTOR = "net/neoforged/fml/common/asm/enumextension/ReservedConstructor"; +} diff --git a/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java b/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java index 89c32d49..6a042248 100644 --- a/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java +++ b/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java @@ -75,6 +75,9 @@ public class RunNeoFormCommand extends NeoFormEngineCommand { @CommandLine.Option(names = "--interface-injection-data", arity = "*", description = "path to an interface injection data file, which extends classes with implements/extends clauses.") List interfaceInjectionDataFiles = new ArrayList<>(); + @CommandLine.Option(names = "--enum-extensions-data", arity = "*", description = "path to an enum extension data file, which adds new enum constants to existing enums.") + List enumExtensionDataFiles = new ArrayList<>(); + @Deprecated @CommandLine.Option(names = "--validate-access-transformers", description = "[DEPRECATED] Use --validated-access-transformer instead") boolean validateAccessTransformers; @@ -157,8 +160,21 @@ protected void runWithNeoFormEngine(NeoFormEngine engine, List cl )); } + if (!enumExtensionDataFiles.isEmpty()) { + var transformNode = getOrAddTransformSourcesNode(engine); + ((ApplySourceTransformAction) transformNode.action()).setEnumExtensions(enumExtensionDataFiles); + + engine.applyTransform(new ModifyAction<>( + "recompile", + RecompileSourcesAction.class, + action -> { + action.getSourcepath().add(ClasspathItem.of(transformNode.getRequiredOutput("stubs"))); + } + )); + } + // Transformations for the binpatch pipeline - if (!additionalAccessTransformers.isEmpty() || !validatedAccessTransformers.isEmpty() || !interfaceInjectionDataFiles.isEmpty()) { + if (!additionalAccessTransformers.isEmpty() || !validatedAccessTransformers.isEmpty() || !interfaceInjectionDataFiles.isEmpty() || !enumExtensionDataFiles.isEmpty()) { var graph = engine.getGraph(); // The node can be created by the NeoForge process (see applyNeoForgeProcessTransforms) var transformNode = graph.getNode("applyDevTransforms"); @@ -175,6 +191,7 @@ protected void runWithNeoFormEngine(NeoFormEngine engine, List cl allAts.addAll(validatedAccessTransformers.stream().map(Paths::get).toList()); applyDevTransformsAction.setAdditionalAccessTransformers(allAts); applyDevTransformsAction.setInjectedInterfaces(interfaceInjectionDataFiles); + applyDevTransformsAction.setEnumExtensions(enumExtensionDataFiles); } execute(engine); diff --git a/src/main/resources/tools.properties b/src/main/resources/tools.properties index 6bb3e8e4..01e9c824 100644 --- a/src/main/resources/tools.properties +++ b/src/main/resources/tools.properties @@ -1,6 +1,6 @@ # https://projects.neoforged.net/neoforged/javasourcetransformer -JAVA_SOURCE_TRANSFORMER=net.neoforged.jst:jst-cli-bundle:2.0.6 +JAVA_SOURCE_TRANSFORMER=net.neoforged.jst:jst-cli-bundle:2.0.15-pr-62-enum-extension DIFF_PATCH=io.codechicken:DiffPatch:2.0.0.36:all From 237a74ac4872cdca48fb9397aec9d6f6d7832688 Mon Sep 17 00:00:00 2001 From: Luke Bemish Date: Sun, 5 Apr 2026 23:36:08 -0400 Subject: [PATCH 2/4] Fix up a couple quirks --- .../actions/ApplySourceTransformAction.java | 2 +- .../runtime/cli/RunNeoFormCommand.java | 22 ++++++------------- src/main/resources/tools.properties | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/main/java/net/neoforged/neoform/runtime/actions/ApplySourceTransformAction.java b/src/main/java/net/neoforged/neoform/runtime/actions/ApplySourceTransformAction.java index 53b052f0..c5d82437 100644 --- a/src/main/java/net/neoforged/neoform/runtime/actions/ApplySourceTransformAction.java +++ b/src/main/java/net/neoforged/neoform/runtime/actions/ApplySourceTransformAction.java @@ -211,7 +211,7 @@ public void run(ProcessingEnvironment environment) throws IOException, Interrupt // When no interface data is given, we still have to create an empty stubs zip to satisfy // the output - if (injectedInterfaces.isEmpty()) { + if (injectedInterfaces.isEmpty() && enumExtensions.isEmpty()) { var stubsPath = environment.getOutputPath("stubs"); try { new ZipOutputStream(Files.newOutputStream(stubsPath)).close(); diff --git a/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java b/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java index 6a042248..94dde231 100644 --- a/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java +++ b/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java @@ -146,9 +146,14 @@ protected void runWithNeoFormEngine(NeoFormEngine engine, List cl } } - if (!interfaceInjectionDataFiles.isEmpty()) { + if (!interfaceInjectionDataFiles.isEmpty() || !enumExtensionDataFiles.isEmpty()) { var transformNode = getOrAddTransformSourcesNode(engine); - ((ApplySourceTransformAction) transformNode.action()).setInjectedInterfaces(interfaceInjectionDataFiles); + if (!interfaceInjectionDataFiles.isEmpty()) { + ((ApplySourceTransformAction) transformNode.action()).setInjectedInterfaces(interfaceInjectionDataFiles); + } + if (!enumExtensionDataFiles.isEmpty()) { + ((ApplySourceTransformAction) transformNode.action()).setEnumExtensions(enumExtensionDataFiles); + } // Add the stub source jar to the recomp classpath engine.applyTransform(new ModifyAction<>( @@ -160,19 +165,6 @@ protected void runWithNeoFormEngine(NeoFormEngine engine, List cl )); } - if (!enumExtensionDataFiles.isEmpty()) { - var transformNode = getOrAddTransformSourcesNode(engine); - ((ApplySourceTransformAction) transformNode.action()).setEnumExtensions(enumExtensionDataFiles); - - engine.applyTransform(new ModifyAction<>( - "recompile", - RecompileSourcesAction.class, - action -> { - action.getSourcepath().add(ClasspathItem.of(transformNode.getRequiredOutput("stubs"))); - } - )); - } - // Transformations for the binpatch pipeline if (!additionalAccessTransformers.isEmpty() || !validatedAccessTransformers.isEmpty() || !interfaceInjectionDataFiles.isEmpty() || !enumExtensionDataFiles.isEmpty()) { var graph = engine.getGraph(); diff --git a/src/main/resources/tools.properties b/src/main/resources/tools.properties index 01e9c824..b12e5c46 100644 --- a/src/main/resources/tools.properties +++ b/src/main/resources/tools.properties @@ -1,6 +1,6 @@ # https://projects.neoforged.net/neoforged/javasourcetransformer -JAVA_SOURCE_TRANSFORMER=net.neoforged.jst:jst-cli-bundle:2.0.15-pr-62-enum-extension +JAVA_SOURCE_TRANSFORMER=net.neoforged.jst:jst-cli-bundle:2.0.17-pr-62-enum-extension DIFF_PATCH=io.codechicken:DiffPatch:2.0.0.36:all From c8ed5bed00d38dc82c2348dd744eb9452671e198 Mon Sep 17 00:00:00 2001 From: Luke Bemish Date: Fri, 10 Apr 2026 20:22:29 -0400 Subject: [PATCH 3/4] Update InstallerTools --- .../neoform/runtime/actions/ApplyDevTransformsAction.java | 6 ------ src/main/resources/tools.properties | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/net/neoforged/neoform/runtime/actions/ApplyDevTransformsAction.java b/src/main/java/net/neoforged/neoform/runtime/actions/ApplyDevTransformsAction.java index ae6ac4ba..eb4b52b0 100644 --- a/src/main/java/net/neoforged/neoform/runtime/actions/ApplyDevTransformsAction.java +++ b/src/main/java/net/neoforged/neoform/runtime/actions/ApplyDevTransformsAction.java @@ -74,14 +74,8 @@ public void run(ProcessingEnvironment environment) throws IOException, Interrupt args.add(environment.getPathArgument(path.toAbsolutePath())); } - args.add("--enum-extensions-required-interface"); - args.add(EnumExtensionDefaults.REQUIRED_INTERFACE); - args.add("--enum-extensions-indexed-enum-annotation"); - args.add(EnumExtensionDefaults.INDEXED_ENUM); args.add("--enum-extensions-marker"); args.add(EnumExtensionDefaults.MARKER_ANNOTATION); - args.add("--enum-extensions-reserved-constructor-annotation"); - args.add(EnumExtensionDefaults.RESERVED_CONSTRUCTOR); setArgs(args); super.run(environment); diff --git a/src/main/resources/tools.properties b/src/main/resources/tools.properties index b12e5c46..aca4d355 100644 --- a/src/main/resources/tools.properties +++ b/src/main/resources/tools.properties @@ -7,6 +7,6 @@ DIFF_PATCH=io.codechicken:DiffPatch:2.0.0.36:all # Uses the old MCF annotation stripper since this is only used for Minecraft versions 1.20.1 and lower MCF_SIDE_ANNOTATION_STRIPPER=net.minecraftforge:mergetool:1.1.7:fatjar -INSTALLER_TOOLS=net.neoforged.installertools:installertools:4.0.12:fatjar +INSTALLER_TOOLS=net.neoforged.installertools:installertools:4.0.18-enum-extension:fatjar AUTO_RENAMING_TOOL=net.neoforged:AutoRenamingTool:2.0.17:all From f7c395a7a8f28f433863024f1a0dd880c67c49ba Mon Sep 17 00:00:00 2001 From: Luke Bemish Date: Sat, 11 Apr 2026 14:48:49 -0400 Subject: [PATCH 4/4] Use PR version for Installertools --- src/main/resources/tools.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/tools.properties b/src/main/resources/tools.properties index aca4d355..37fef829 100644 --- a/src/main/resources/tools.properties +++ b/src/main/resources/tools.properties @@ -7,6 +7,6 @@ DIFF_PATCH=io.codechicken:DiffPatch:2.0.0.36:all # Uses the old MCF annotation stripper since this is only used for Minecraft versions 1.20.1 and lower MCF_SIDE_ANNOTATION_STRIPPER=net.minecraftforge:mergetool:1.1.7:fatjar -INSTALLER_TOOLS=net.neoforged.installertools:installertools:4.0.18-enum-extension:fatjar +INSTALLER_TOOLS=net.neoforged.installertools:installertools:4.0.20-pr-44-enum-extension:fatjar AUTO_RENAMING_TOOL=net.neoforged:AutoRenamingTool:2.0.17:all