Skip to content

Commit

Permalink
NeoForge support (#166)
Browse files Browse the repository at this point in the history
* Initial plumbing for NeoForge support

* Fix checkstyle

* Add ModPlatform.id

* Use NeoForge-specific cache

* Use NeoForge-specific dependency configuration

This is only for the "(neo)forge" configuration exposed
as API. The other configurations remain the same.

* Add test for basic NeoForge 1.20.2 projects

* Implement hacky fast track for NeoForge field migration

In other works, we skip field migrating for now.

* Disable patched decompilation task on Neo

* Disable mixin AP for building on NeoForge

* Many changes related to NeoForge mappings and remapping

* Code style and related fixes

* McpExecutor: Add support for downloading deps via Gradle

Also adds support for downloading a file without a repo
for NeoForm functions.

* Fix wrong configurations being used on NeoForge

* Fix mixin version detection on NeoForge

* Rename MinecraftPatchedProvider jar paths on NeoForge

* Test NeoForge against a client-only MC jar

* Add DFU for codecs, support NeoForge run config templates

* Centralise userdev config reading, support missing SAS

* Set up Shadow for bundling DFU

* Use correct name for NeoForm in cache files

* RemapJarTask: Fix check using isForgeLike for Forge

* MojangMappingsMerger: Complete and reorder mappings

* Fix SRG being used on NeoForge

* Fix SRG being used on NeoForge for ATs

* Use client pipeline for merged to avoid patch issues on Neo

* Update to architectury-loom-runtime 2.0

* Fix Minecraft jar name on Neo

* Fix MojangMappingsMerger having incomplete names

* Fix NeoForge mod dependency remapping using wrong mappings

* Quiet down MojangMappingsMerger

* Fix (Neo)Forge builtin coremods not being remapped

Fixes #146.

* Disable deprecated data generation API on NeoForge

* Use release version of the forge runtime

* Revert "Set up Shadow for bundling DFU"

This reverts commit 2bb8166.

* Make NeoForge Field Migration work

* NeoForge shouldn't try to get datagen mods

* Fix checkstyle

* Remove mojang maven

* Split Forge and NeoForge extensions

* SimpleNeoForgeTest: Bump Neo version and fix Yarn version

* Remove resolved TODOs

* Re-enable joined NeoForm pipeline

* MPP: Rename srg -> intermediate jars

* Reintroduce namespace filtering for mapping trees

Should be a simple optimisation to avoid reading an
additional ns.

* ForgeRunTemplateTest: Fix code format

* Adapt SrgMerger into ForgeMappingsMerger (#169)

* Fix crash with NeoForge ext creation

* Adapt SrgMerger into ForgeMappingsMerger

* Update tiny-remapper

* Fix spotless

* Resolve reviews

* Fix checkstyle

* Remap ASMAPI.redirectFieldToMethod (#171)

* Remap ASMAPI.redirectFieldToMethod

* Move lastClassName outside the if

* Fix missing template variables in tests using forge/simple

* Add Java version to forge/simple test variables

* Disable naming service dependency on Neo

* Fix changing patch version not affecting mapped game jars

Fixes #167.

* Rename configuration: neoforge -> neoForge

---------

Co-authored-by: shedaniel <[email protected]>
  • Loading branch information
Juuxel and shedaniel authored Nov 17, 2023
1 parent e3b51e9 commit a11b828
Show file tree
Hide file tree
Showing 78 changed files with 1,389 additions and 471 deletions.
8 changes: 6 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ dependencies {
implementation libs.mcinjector
implementation libs.opencsv
implementation libs.forge.diffpatch
implementation libs.datafixerupper

// Forge mods.toml parsing
implementation libs.night.config.toml
Expand Down Expand Up @@ -254,8 +255,11 @@ spotless {
target 'src/**/*.gradle', '*.gradle'
greclipse()

// This file uses a @MAPPINGS@ token which is not valid Groovy
targetExclude('**/projects/forge/simple/build.gradle')
targetExclude(
// These files use a @MAPPINGS@ token which is not valid Groovy
'**/projects/forge/simple/build.gradle',
'**/projects/neoforge/simple/build.gradle'
)
}

kotlin {
Expand Down
4 changes: 3 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jackson = "2.15.2"
guava = "32.1.2-jre"

stitch = "0.6.2"
tiny-remapper = "1.9.22"
tiny-remapper = "1.10.23"
access-widener = "2.1.0"
mapping-io = "0.4.2"
lorenz-tiny = "4.0.2"
Expand All @@ -28,6 +28,7 @@ mcinjector = "3.8.0"
opencsv = "5.4"
forge-diffpatch = "2.0.7"
night-config = "3.6.6"
datafixerupper = "6.0.8"

[libraries]
# Loom compile libraries
Expand Down Expand Up @@ -60,6 +61,7 @@ mcinjector = { module = "de.oceanlabs.mcp:mcinjector", version.ref = "mcinjector
opencsv = { module = "com.opencsv:opencsv", version.ref = "opencsv" }
forge-diffpatch = { module = "net.minecraftforge:DiffPatch", version.ref = "forge-diffpatch" }
night-config-toml = { module = "com.electronwill.night-config:toml", version.ref = "night-config" }
datafixerupper = { module = "com.mojang:datafixerupper", version.ref = "datafixerupper" }

[plugins]
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
Expand Down
6 changes: 4 additions & 2 deletions gradle/runtime.libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ native-support = "1.0.1"

# Forge Runtime depedencies
javax-annotations = "3.0.2"
forge-runtime = "1.1.8"
forge-runtime = "2.0.9"
access-transformers = "3.0.1"
access-transformers-new = "8.0.5"
unprotect = "1.2.0"
Expand All @@ -34,7 +34,9 @@ native-support = { module = "net.fabricmc:fabric-loom-native-support", version.r

# Forge Runtime depedencies
javax-annotations = { module = "com.google.code.findbugs:jsr305", version.ref = "javax-annotations" }
forge-runtime = { module = "dev.architectury:architectury-loom-runtime", version.ref = "forge-runtime" }
mixin-remapper-service = { module = "dev.architectury:architectury-mixin-remapper-service", version.ref = "forge-runtime" }
naming-service = { module = "dev.architectury:architectury-naming-service", version.ref = "forge-runtime" }
mcp-annotations = { module = "dev.architectury:mcp-annotations", version.ref = "forge-runtime" }
access-transformers = { module = "net.minecraftforge:accesstransformers", version.ref = "access-transformers" }
access-transformers-new = { module = "net.minecraftforge:accesstransformers", version.ref = "access-transformers-new" }
unprotect = { module = "io.github.juuxel:unprotect", version.ref = "unprotect" }
Expand Down
45 changes: 45 additions & 0 deletions src/main/java/dev/architectury/loom/forge/UserdevConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package dev.architectury.loom.forge;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;

import net.fabricmc.loom.configuration.providers.forge.ForgeRunTemplate;

public record UserdevConfig(
String mcp,
String universal,
String sources,
String patches,
Optional<String> patchesOriginalPrefix,
Optional<String> patchesModifiedPrefix,
String binpatches,
BinaryPatcherConfig binpatcher,
List<String> libraries,
Map<String, ForgeRunTemplate> runs,
List<String> sass
) {
public static final Codec<UserdevConfig> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.STRING.fieldOf("mcp").forGetter(UserdevConfig::mcp),
Codec.STRING.fieldOf("universal").forGetter(UserdevConfig::universal),
Codec.STRING.fieldOf("sources").forGetter(UserdevConfig::sources),
Codec.STRING.fieldOf("patches").forGetter(UserdevConfig::patches),
Codec.STRING.optionalFieldOf("patchesOriginalPrefix").forGetter(UserdevConfig::patchesOriginalPrefix),
Codec.STRING.optionalFieldOf("patchesModifiedPrefix").forGetter(UserdevConfig::patchesModifiedPrefix),
Codec.STRING.fieldOf("binpatches").forGetter(UserdevConfig::binpatches),
BinaryPatcherConfig.CODEC.fieldOf("binpatcher").forGetter(UserdevConfig::binpatcher),
Codec.STRING.listOf().fieldOf("libraries").forGetter(UserdevConfig::libraries),
ForgeRunTemplate.MAP_CODEC.fieldOf("runs").forGetter(UserdevConfig::runs),
Codec.STRING.listOf().optionalFieldOf("sass", List.of()).forGetter(UserdevConfig::sass)
).apply(instance, UserdevConfig::new));

public record BinaryPatcherConfig(String dependency, List<String> args) {
public static final Codec<BinaryPatcherConfig> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.STRING.fieldOf("version").forGetter(BinaryPatcherConfig::dependency),
Codec.STRING.listOf().fieldOf("args").forGetter(BinaryPatcherConfig::args)
).apply(instance, BinaryPatcherConfig::new));
}
}
16 changes: 6 additions & 10 deletions src/main/java/dev/architectury/loom/util/ForgeLoggerConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
import java.util.List;
import java.util.StringJoiner;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import org.gradle.api.Project;
import org.jetbrains.annotations.Nullable;

Expand All @@ -31,18 +29,16 @@ public static void copyToPath(Project project, Path outputFile) {
throw new UncheckedIOException(e);
}

final JsonArray libraries = LoomGradleExtension.get(project)
final List<String> libraries = LoomGradleExtension.get(project)
.getForgeUserdevProvider()
.getJson()
.getAsJsonArray("libraries");
.getConfig()
.libraries();
boolean found = false;

for (JsonElement library : libraries) {
final String notation = library.getAsString();

if (LOGGER_CONFIG_ARTIFACTS.stream().anyMatch(artifact -> artifact.matches(notation))) {
for (String library : libraries) {
if (LOGGER_CONFIG_ARTIFACTS.stream().anyMatch(artifact -> artifact.matches(library))) {
final File libraryFile = project.getConfigurations()
.detachedConfiguration(project.getDependencies().create(notation))
.detachedConfiguration(project.getDependencies().create(library))
.setTransitive(false)
.getSingleFile();

Expand Down
38 changes: 38 additions & 0 deletions src/main/java/dev/architectury/loom/util/MappingOption.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package dev.architectury.loom.util;

import org.jetbrains.annotations.Nullable;

import net.fabricmc.loom.api.LoomGradleExtensionAPI;
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;

public enum MappingOption {
DEFAULT(null),
WITH_SRG(MappingsNamespace.SRG.toString()),
WITH_MOJANG(MappingsNamespace.MOJANG.toString());

private final String extraNamespace;

MappingOption(@Nullable String extraNamespace) {
this.extraNamespace = extraNamespace;
}

public MappingOption forNamespaces(String... namespaces) {
if (extraNamespace == null) return this;

for (String namespace : namespaces) {
if (extraNamespace.equals(namespace)) {
return this;
}
}

return DEFAULT;
}

public static MappingOption forPlatform(LoomGradleExtensionAPI extension) {
return switch (extension.getPlatform().get()) {
case FORGE -> WITH_SRG;
case NEOFORGE -> WITH_MOJANG;
default -> DEFAULT;
};
}
}
27 changes: 23 additions & 4 deletions src/main/java/net/fabricmc/loom/LoomGradleExtension.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessorManager;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MojangMappedMinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
import net.fabricmc.loom.configuration.providers.minecraft.mapped.SrgMinecraftProvider;
import net.fabricmc.loom.extension.LoomFiles;
Expand Down Expand Up @@ -95,6 +96,10 @@ static LoomGradleExtension get(Project project) {

void setSrgMinecraftProvider(SrgMinecraftProvider<?> srgMinecraftProvider);

MojangMappedMinecraftProvider<?> getMojangMappedMinecraftProvider();

void setMojangMappedMinecraftProvider(MojangMappedMinecraftProvider<?> srgMinecraftProvider);

default List<Path> getMinecraftJars(MappingsNamespace mappingsNamespace) {
return switch (mappingsNamespace) {
case NAMED -> getNamedMinecraftProvider().getMinecraftJarPaths();
Expand All @@ -104,6 +109,10 @@ default List<Path> getMinecraftJars(MappingsNamespace mappingsNamespace) {
ModPlatform.assertPlatform(this, ModPlatform.FORGE, () -> "SRG jars are only available on Forge.");
yield getSrgMinecraftProvider().getMinecraftJarPaths();
}
case MOJANG -> {
ModPlatform.assertPlatform(this, ModPlatform.NEOFORGE, () -> "Mojang-mapped jars are only available on NeoForge.");
yield getMojangMappedMinecraftProvider().getMinecraftJarPaths();
}
};
}

Expand Down Expand Up @@ -149,12 +158,12 @@ default boolean isDataGenEnabled() {
return isForge() && !getForge().getDataGenMods().isEmpty();
}

default boolean isForgeAndOfficial() {
return isForge() && getMcpConfigProvider().isOfficial();
default boolean isForgeLikeAndOfficial() {
return isForgeLike() && getMcpConfigProvider().isOfficial();
}

default boolean isForgeAndNotOfficial() {
return isForge() && !getMcpConfigProvider().isOfficial();
default boolean isForgeLikeAndNotOfficial() {
return isForgeLike() && !getMcpConfigProvider().isOfficial();
}

DependencyProviders getDependencyProviders();
Expand All @@ -179,4 +188,14 @@ default ForgeProvider getForgeProvider() {

ForgeRunsProvider getForgeRunsProvider();
void setForgeRunsProvider(ForgeRunsProvider forgeRunsProvider);

/**
* The mapping file that is specific to the platform settings.
* It contains SRG (Forge/common) or Mojang mappings (NeoForge) as needed.
*
* @return the platform mapping file path
*/
default Path getPlatformMappingFile() {
return getMappingConfiguration().getPlatformMappingFile(this);
}
}
2 changes: 1 addition & 1 deletion src/main/java/net/fabricmc/loom/api/ForgeExtensionAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import org.jetbrains.annotations.ApiStatus;

/**
* This is the forge extension api available exposed to build scripts.
* This is the Forge extension API available to build scripts.
*/
@ApiStatus.NonExtendable
public interface ForgeExtensionAPI {
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,18 @@ default void splitMinecraftJar() {

Provider<ModPlatform> getPlatform();

default boolean isForgeLike() {
return getPlatform().get().isForgeLike();
}

default boolean isForge() {
return getPlatform().get() == ModPlatform.FORGE;
}

default boolean isNeoForge() {
return getPlatform().get() == ModPlatform.NEOFORGE;
}

default boolean isQuilt() {
return getPlatform().get() == ModPlatform.QUILT;
}
Expand All @@ -265,4 +273,15 @@ default void addTaskBeforeRun(String task) {
ForgeExtensionAPI getForge();

void forge(Action<ForgeExtensionAPI> action);

/**
* Gets the NeoForge extension used to configure NeoForge details.
*
* @return the NeoForge extension
* @throws UnsupportedOperationException if running on another platform
* @see #isNeoForge()
*/
NeoForgeExtensionAPI getNeoForge();

void neoForge(Action<NeoForgeExtensionAPI> action);
}
50 changes: 50 additions & 0 deletions src/main/java/net/fabricmc/loom/api/NeoForgeExtensionAPI.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package net.fabricmc.loom.api;

import org.gradle.api.file.ConfigurableFileCollection;

/**
* This is the NeoForge extension API available to build scripts.
*/
public interface NeoForgeExtensionAPI {
/**
* A collection of all project access transformers.
* The collection should only contain AT files, and not directories or other files.
*
* <p>If this collection is empty, Loom tries to resolve the AT from the default path
* ({@code META-INF/accesstransformer.cfg} in the {@code main} source set).
*
* @return the collection of AT files
*/
ConfigurableFileCollection getAccessTransformers();

/**
* Adds a {@linkplain #getAccessTransformers() project access transformer}.
*
* @param file the file, evaluated as per {@link org.gradle.api.Project#file(Object)}
*/
void accessTransformer(Object file);
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ public enum MappingsNamespace {
*/
SRG,

/**
* Mojang's official names from their deobfuscation maps.
*
* <p>They are used as the mapping set in a NeoForge production environment akin to Fabric's
* {@linkplain #INTERMEDIARY intermediary mappings}.
*/
MOJANG,

/**
* Named mappings are the developer friendly names used to develop mods against.
*/
Expand All @@ -70,6 +78,7 @@ public enum MappingsNamespace {
case "official" -> OFFICIAL;
case "intermediary" -> INTERMEDIARY;
case "srg" -> SRG;
case "mojang" -> MOJANG;
case "named" -> NAMED;
default -> null;
};
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/net/fabricmc/loom/build/IntermediaryNamespaces.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2022 FabricMC
* Copyright (c) 2022-2023 FabricMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -34,8 +34,19 @@ public final class IntermediaryNamespaces {
* Returns the intermediary namespace of the project.
*/
public static String intermediary(Project project) {
return intermediaryNamespace(project).toString();
}

/**
* Returns the intermediary namespace of the project.
*/
public static MappingsNamespace intermediaryNamespace(Project project) {
LoomGradleExtension extension = LoomGradleExtension.get(project);
return extension.isForge() ? "srg" : "intermediary";
return switch (extension.getPlatform().get()) {
case FABRIC, QUILT -> MappingsNamespace.INTERMEDIARY;
case FORGE -> MappingsNamespace.SRG;
case NEOFORGE -> MappingsNamespace.MOJANG;
};
}

/**
Expand Down
Loading

0 comments on commit a11b828

Please sign in to comment.