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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
.gradle
.gradle-user-home/
build/
run/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
Expand Down
26 changes: 25 additions & 1 deletion LEGACY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ModDevGradle Legacy Forge Plugin
ModDevGradle has a secondary plugin (ID: `net.neoforged.moddev.legacyforge`, released alongside the normal plugin with the same version)
that adds support for developing mods against MinecraftForge and Vanilla Minecraft versions 1.17 up to 1.20.1.
that adds support for developing mods against MinecraftForge and Vanilla Minecraft versions 1.12.2 up to 1.20.1.

The legacy plugin is an "addon" plugin, meaning it operates on top of the normal plugin. This means that the APIs normally used
are also available when using the legacy plugin.
Expand Down Expand Up @@ -41,6 +41,30 @@ legacyForge {
}
```

For Minecraft 1.12.2, use a Forge version such as:

```groovy
legacyForge {
version = "1.12.2-14.23.5.2860"
}
```

MDG will use Forge's `userdev3` artifact for 1.12.2. This requires an NFRT build with legacy MCP support
(`--mcp-mappings` and the legacy MCP mapping result IDs). Until that NFRT release is the MDG default, set
`neoForge.neoFormRuntime.version` to a compatible published version or substitute a local NFRT legacy build.

NFRT's 1.12.2 legacy MCP pipeline uses `de.oceanlabs.mcp:mcp_stable:39-1.12@zip` by default; if you need a
different MCP CSV mapping zip, configure it explicitly:

```groovy
legacyForge {
enable {
forgeVersion = "1.12.2-14.23.5.2860"
mcpMappings = "de.oceanlabs.mcp:mcp_stable:39-1.12@zip"
}
}
```

## Reobfuscating artifacts
Forge used SRG mappings as intermediary mappings in 1.20.1 and below. While your mod is developed against the mappings provided
by Mojang (known as official mappings), you need to reobfuscate it to SRG mappings for it to work in production.
Expand Down
30 changes: 27 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,12 @@ sourceSets {
runtimeClasspath += java8.output
}
legacy
mcpforge
test {
compileClasspath += legacy.output
runtimeClasspath += legacy.output
compileClasspath += mcpforge.output
runtimeClasspath += mcpforge.output
}
}

Expand All @@ -83,6 +86,7 @@ configurations {
// Place shaded dependencies into `compileOnly` so that they do not leak into our publications' dependencies.
compileOnly.extendsFrom shaded
legacyCompileOnly.extendsFrom shaded
mcpforgeCompileOnly.extendsFrom shaded
testCompileOnly.extendsFrom shaded
testRuntimeOnly.extendsFrom shaded
shadowRuntimeElements {
Expand Down Expand Up @@ -113,6 +117,8 @@ dependencies {
compileOnly "com.intellij:annotations:9.0.4"
testCompileOnly "com.intellij:annotations:9.0.4"
shaded "com.google.code.gson:gson:2.11.0"
shaded "org.ow2.asm:asm-commons:9.7.1"
shaded "org.tukaani:xz:1.10"
implementation "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext:1.2"
shaded "net.neoforged:EclipseLaunchConfigs:0.1.11"
shaded "net.neoforged:VscLaunchConfigs:1.0.8"
Expand All @@ -134,6 +140,11 @@ dependencies {
legacyImplementation(sourceSets.main.output)
legacyImplementation(sourceSets.java8.output)
legacyImplementation gradleApi()

mcpforgeImplementation(sourceSets.main.output)
mcpforgeImplementation(sourceSets.legacy.output)
mcpforgeImplementation(sourceSets.java8.output)
mcpforgeImplementation gradleApi()
}

java {
Expand All @@ -147,13 +158,15 @@ jar {
archiveClassifier = 'slim'
from sourceSets.java8.output
from sourceSets.legacy.output
from sourceSets.mcpforge.output
}

shadowJar {
archiveClassifier = "" // Required for the Plugin Publish Plugin to publish this jar

from sourceSets.java8.output
from sourceSets.legacy.output
from sourceSets.mcpforge.output

configurations = [project.configurations.shaded]
enableRelocation = true
Expand All @@ -164,8 +177,9 @@ assemble.dependsOn shadowJar

tasks.named("compileJava8Java").configure {
javaCompiler = javaToolchains.compilerFor {
languageVersion = JavaLanguageVersion.of(8)
languageVersion = JavaLanguageVersion.of(17)
}
options.release = 8
}

javadoc {
Expand Down Expand Up @@ -205,7 +219,7 @@ gradlePlugin {
id = 'net.neoforged.moddev.legacyforge'
implementationClass = 'net.neoforged.moddevgradle.boot.LegacyForgeModDevPlugin'
displayName = "Mod Development Plugin for Legacy Forge"
description = "This plugin helps you create Minecraft mods using the Forge platform, up to 1.20.1"
description = "This plugin helps you create Minecraft mods using the Forge platform, from 1.12.2 up to 1.20.1"
tags = ["minecraft", "neoforge", "forge", "java", "mod"]
}
repositories {
Expand All @@ -219,9 +233,16 @@ gradlePlugin {
id = 'net.neoforged.moddev.legacyforge.repositories'
implementationClass = 'net.neoforged.moddevgradle.boot.LegacyRepositoriesPlugin'
displayName = "Mod Development Repositories Plugin for Legacy Forge"
description = "This plugin adds the repositories needed for developing Minecraft mods using the Forge platform, up to 1.20.1. It is applied automatically by the legacyforge plugin, but can be applied manually in settings.gradle to make use of Gradle dependency management."
description = "This plugin adds the repositories needed for developing Minecraft mods using the Forge platform, from 1.12.2 up to 1.20.1. It is applied automatically by the legacyforge plugin, but can be applied manually in settings.gradle to make use of Gradle dependency management."
tags = ["minecraft", "neoforge", "forge", "java", "mod"]
}
mcpforge {
id = 'net.neoforged.moddev.mcpforge'
implementationClass = 'net.neoforged.moddevgradle.boot.McpForgePlugin'
displayName = "Mod Development Plugin for Legacy Forge 1.12.2 (MCP)"
description = "This plugin helps you create Minecraft mods using the Forge platform for 1.12.2 (MCP mappings). It is the isolated home for the 1.12.2/MCP-specific toolchain, distinct from legacyforge."
tags = ["minecraft", "forge", "java", "mod", "1.12.2", "mcp"]
}
}
}

Expand Down Expand Up @@ -337,6 +358,9 @@ abstract class GenerateRepoFilter extends DefaultTask {
artifacts.add(new Artifact(location[0], location[1]))
}
}
// Required by Forge 1.12.2 and still hosted on Mojang's libraries maven, but not
// referenced by Mojang's vanilla version manifests.
artifacts.add(new Artifact('lzma', 'lzma'))
final artifactList = artifacts.toList()
Collections.sort(artifactList)
final clazz = """
Expand Down
39 changes: 39 additions & 0 deletions legacytest/forge1122/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
plugins {
id 'net.neoforged.moddev.legacyforge'
}

repositories {
// The Forge 1.12.2 smoke can use a locally published NFRT build until a compatible release is default.
mavenLocal()
}

java {
toolchain {
languageVersion = JavaLanguageVersion.of(8)
}
}

neoFormRuntime {
version = '2.0.19-legacy'
}

legacyForge {
enable {
forgeVersion = '1.12.2-14.23.5.2860'
mcpMappings = 'de.oceanlabs.mcp:mcp_stable:39-1.12@zip'
// Recompilation now works end-to-end: NFRT runs ForgeFlower/MCPCleanup/recompile, with the legacy
// Java-8 toolchain auto-provisioned by Gradle (Azul Zulu on aarch64) and the legacy Maven repositories
// (Maven Central, Mojang libraries, Forge Maven) passed to NFRT via CreateMinecraftArtifacts.
disableRecompilation = false
}
runs {
client {
client()
}
}
mods {
mymod1122 {
sourceSet(sourceSets.main)
}
}
}
8 changes: 8 additions & 0 deletions legacytest/forge1122/src/main/java/mymod1122/MyMod1122.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package mymod1122;

import net.minecraftforge.fml.common.Mod;

@Mod(modid = MyMod1122.MOD_ID, name = "Legacy 1.12.2 Smoke Test", version = "1.0.0")
public class MyMod1122 {
public static final String MOD_ID = "mymod1122";
}
16 changes: 16 additions & 0 deletions legacytest/forge1122/src/main/resources/mcmod.info
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[
{
"modid": "mymod1122",
"name": "Legacy 1.12.2 Smoke Test",
"description": "Minimal Forge 1.12.2 fixture for ModDevGradle.",
"version": "1.0.0",
"mcversion": "1.12.2",
"url": "",
"updateUrl": "",
"authorList": [],
"credits": "",
"logoFile": "",
"screenshots": [],
"dependencies": []
}
]
6 changes: 6 additions & 0 deletions legacytest/forge1122/src/main/resources/pack.mcmeta
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 3,
"description": "Legacy 1.12.2 smoke test resources"
}
}
1 change: 1 addition & 0 deletions legacytest/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ plugins {
includeBuild '..'

include 'forge'
include 'forge1122'
include 'forgedownstream'
include 'nonmc'
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public static void filter(org.gradle.api.artifacts.repositories.RepositoryConten
filter.includeModule("io.netty", "netty-transport-native-unix-common");
filter.includeModule("it.unimi.dsi", "fastutil");
filter.includeModule("java3d", "vecmath");
filter.includeModule("lzma", "lzma");
filter.includeModule("net.java.dev.jna", "jna");
filter.includeModule("net.java.dev.jna", "jna-platform");
filter.includeModule("net.java.dev.jna", "platform");
Expand Down Expand Up @@ -92,6 +93,7 @@ public static void filter(org.gradle.api.artifacts.repositories.RepositoryConten
filter.includeModule("org.lwjgl.lwjgl", "lwjgl");
filter.includeModule("org.lwjgl.lwjgl", "lwjgl-platform");
filter.includeModule("org.lwjgl.lwjgl", "lwjgl_util");
filter.includeModule("org.lwjgl.lwjgl", "parent");
filter.includeModule("org.lz4", "lz4-java");
filter.includeModule("org.ow2.asm", "asm");
filter.includeModule("org.ow2.asm", "asm-all");
Expand Down
14 changes: 14 additions & 0 deletions src/java8/java/net/neoforged/moddevgradle/boot/McpForgePlugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.neoforged.moddevgradle.boot;

import org.gradle.api.Project;

/**
* Boot trampoline for the {@code net.neoforged.moddev.mcpforge} plugin (the isolated 1.12.2/MCP toolchain).
* Mirrors {@link LegacyForgeModDevPlugin}. Kept in the java8 source set so it can be loaded by the
* bootstrap classloader before the main plugin classpath is wired up.
*/
public class McpForgePlugin extends TrampolinePlugin<Project> {
public McpForgePlugin() {
super("net.neoforged.moddevgradle.mcpforge.internal.McpForgeModDevPlugin");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package net.neoforged.moddevgradle.legacyforge.internal;

import java.util.ArrayList;
import org.gradle.api.artifacts.CacheableRule;
import org.gradle.api.artifacts.ComponentMetadataContext;
import org.gradle.api.artifacts.ComponentMetadataRule;
import org.gradle.api.artifacts.DirectDependenciesMetadata;
import org.gradle.api.artifacts.DirectDependencyMetadata;

/**
* Normalizes old Forge library metadata that predates today's Maven Central coordinates or only
* exists as jar-only artifacts on Forge's Maven.
*/
@CacheableRule
public class LegacyForgeLibraryMetadataRule implements ComponentMetadataRule {
@Override
public void execute(ComponentMetadataContext context) {
var id = context.getDetails().getId();
if (!id.getVersion().equals("1.12.2-14.23.5.2860")) {
return;
}

context.getDetails().allVariants(variant -> variant.withDependencies(dependencies -> {
removeMatching(dependencies, dependency -> {
var group = dependency.getGroup();
var name = dependency.getName();
return group.equals("org.scala-lang.plugins")
|| group.equals("org.scala-lang") && name.equals("scala-actors-migration_2.11");
});

replaceDependency(dependencies, "org.scala-lang:scala-parser-combinators_2.11:1.0.1",
"org.scala-lang.modules:scala-parser-combinators_2.11:1.0.1");
replaceDependency(dependencies, "org.scala-lang:scala-swing_2.11:1.0.1",
"org.scala-lang.modules:scala-swing_2.11:1.0.1");
replaceDependency(dependencies, "org.scala-lang:scala-xml_2.11:1.0.2",
"org.scala-lang.modules:scala-xml_2.11:1.0.2");
}));
}

private static void replaceDependency(DirectDependenciesMetadata dependencies,
String oldNotation,
String newNotation) {
var oldParts = oldNotation.split(":");
removeMatching(dependencies, dependency -> dependency.getGroup().equals(oldParts[0])
&& dependency.getName().equals(oldParts[1])
&& dependency.getVersionConstraint().getRequiredVersion().equals(oldParts[2]));
dependencies.add(newNotation);
}

private static void removeMatching(DirectDependenciesMetadata dependencies,
java.util.function.Predicate<DirectDependencyMetadata> predicate) {
var toRemove = new ArrayList<DirectDependencyMetadata>();
for (var dependency : dependencies) {
if (predicate.test(dependency)) {
toRemove.add(dependency);
}
}
dependencies.removeAll(toRemove);
}
}
Loading