Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/20.1/forge' into 19.2/modernized
Browse files Browse the repository at this point in the history
  • Loading branch information
embeddedt committed Sep 15, 2024
2 parents 1bea6e5 + 496c59e commit 1125bc4
Show file tree
Hide file tree
Showing 24 changed files with 251 additions and 77 deletions.
12 changes: 0 additions & 12 deletions .github/workflows/build-snapshot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,6 @@ jobs:
with:
distribution: 'temurin'
java-version: 17
- name: Initialize FG cache
uses: actions/cache@v4
with:
key: ${{ steps.mod_props.outputs.minecraft_version }}-${{ steps.mod_props.outputs.parchment_version }}-${{ steps.mod_props.outputs.forge_version }}
path: |
build/fg_cache
build/createMcpToSrg
build/downloadMCMeta
build/downloadMcpConfig
build/extractSrg
restore-keys: |
${{ steps.mod_props.outputs.minecraft_version }}-${{ steps.mod_props.outputs.parchment_version }}-
- name: Initialize caches
uses: actions/cache@v3
with:
Expand Down
24 changes: 11 additions & 13 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.w3c.dom.Element

plugins {
id("idea")
id("net.minecraftforge.gradle") version("6.0.25")
id("net.minecraftforge.gradle") version("6.0.29")
id("maven-publish")
id("org.spongepowered.mixin") version("0.7.38")

Expand Down Expand Up @@ -42,13 +42,6 @@ val extraSourceSets = arrayOf("legacy", "compat")
sourceSets {
val main = getByName("main")

create("gameTest") {
java {
compileClasspath += main.compileClasspath
compileClasspath += main.output
}
}

extraSourceSets.forEach {
val sourceset = create(it)
sourceset.apply {
Expand Down Expand Up @@ -114,9 +107,7 @@ minecraft {
fun configureGameTestRun(run: RunConfig) {
run.parent(client)
run.property("forge.enableGameTest", "true")
run.mods.named("embeddium") {
sources(sourceSets["gameTest"])
}
run.property("embeddium.enableGameTest", "true")
}

create("gameTestClient") {
Expand Down Expand Up @@ -158,6 +149,10 @@ fun DependencyHandlerScope.compatCompileOnly(dependency: Dependency) {
"compatCompileOnly"(dependency)
}

fun fAPIModule(name: String): Dependency {
return fabricApiModuleFinder.module(name, "fabric_version"())
}

dependencies {
minecraft("net.minecraftforge:forge:${"minecraft_version"()}-${"forge_version"()}")

Expand All @@ -167,7 +162,10 @@ dependencies {
compatCompileOnly(fg.deobf("com.brandon3055.brandonscore:BrandonsCore:1.20.1-3.2.1.302:universal"))

// Fabric API
compileOnly("net.fabricmc.fabric-api:fabric-api:${"fabric_version"()}")
"fabricCompileOnly"(fAPIModule("fabric-api-base"))
"fabricCompileOnly"(fAPIModule("fabric-renderer-api-v1"))
"fabricCompileOnly"(fAPIModule("fabric-rendering-data-attachment-v1"))
"fabricCompileOnly"(fAPIModule("fabric-renderer-indigo"))
compileOnly("net.fabricmc:fabric-loader:${"fabric_loader_version"()}")

"runtimeOnlyNonPublishable"(fg.deobf("curse.maven:modernfix-790626:5288170"))
Expand Down Expand Up @@ -205,7 +203,7 @@ tasks.processResources {
inputs.property("version", "version"())

filesMatching("META-INF/mods.toml") {
expand("version" to "version"())
expand("file" to mapOf("jarVersion" to inputs.properties["version"]))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package org.embeddedt.embeddium.gradle.fabric.remapper;

import java.io.*;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.inject.Inject;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import com.google.common.io.ByteStreams;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Dependency;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
* Based on code from Fabric Loom, used under the terms of the MIT License.
*/
public abstract class FabricApiModuleFinder {
@Inject
public abstract Project getProject();

private static final HashMap<String, Map<String, String>> moduleVersionCache = new HashMap<>();
private static final HashMap<String, Map<String, String>> deprecatedModuleVersionCache = new HashMap<>();

public Dependency module(String moduleName, String fabricApiVersion) {
return getProject().getDependencies()
.create(getDependencyNotation(moduleName, fabricApiVersion));
}

public String moduleVersion(String moduleName, String fabricApiVersion) {
String moduleVersion = moduleVersionCache
.computeIfAbsent(fabricApiVersion, this::getApiModuleVersions)
.get(moduleName);

if (moduleVersion == null) {
moduleVersion = deprecatedModuleVersionCache
.computeIfAbsent(fabricApiVersion, this::getDeprecatedApiModuleVersions)
.get(moduleName);
}

if (moduleVersion == null) {
throw new RuntimeException("Failed to find module version for module: " + moduleName);
}

return moduleVersion;
}

private String getDependencyNotation(String moduleName, String fabricApiVersion) {
return String.format("net.fabricmc.fabric-api:%s:%s", moduleName, moduleVersion(moduleName, fabricApiVersion));
}

private Map<String, String> getApiModuleVersions(String fabricApiVersion) {
try {
return populateModuleVersionMap(getApiMavenPom(fabricApiVersion));
} catch (PomNotFoundException e) {
throw new RuntimeException("Could not find fabric-api version: " + fabricApiVersion);
}
}

private Map<String, String> getDeprecatedApiModuleVersions(String fabricApiVersion) {
try {
return populateModuleVersionMap(getDeprecatedApiMavenPom(fabricApiVersion));
} catch (PomNotFoundException e) {
// Not all fabric-api versions have deprecated modules, return an empty map to cache this fact.
return Collections.emptyMap();
}
}

private Map<String, String> populateModuleVersionMap(File pomFile) {
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document pom = docBuilder.parse(pomFile);

Map<String, String> versionMap = new HashMap<>();

NodeList dependencies = ((Element) pom.getElementsByTagName("dependencies").item(0)).getElementsByTagName("dependency");

for (int i = 0; i < dependencies.getLength(); i++) {
Element dep = (Element) dependencies.item(i);
Element artifact = (Element) dep.getElementsByTagName("artifactId").item(0);
Element version = (Element) dep.getElementsByTagName("version").item(0);

if (artifact == null || version == null) {
throw new RuntimeException("Failed to find artifact or version");
}

versionMap.put(artifact.getTextContent(), version.getTextContent());
}

return versionMap;
} catch (Exception e) {
throw new RuntimeException("Failed to parse " + pomFile.getName(), e);
}
}

private File getApiMavenPom(String fabricApiVersion) throws PomNotFoundException {
return getPom("fabric-api", fabricApiVersion);
}

private File getDeprecatedApiMavenPom(String fabricApiVersion) throws PomNotFoundException {
return getPom("fabric-api-deprecated", fabricApiVersion);
}

private File getPom(String name, String version) throws PomNotFoundException {
final var mavenPom = new File(getProject().getLayout().getBuildDirectory().getAsFile().get(), "fabric-api/%s-%s.pom".formatted(name, version));

if(!mavenPom.exists()) {
mavenPom.getParentFile().mkdirs();
try(FileOutputStream fos = new FileOutputStream(mavenPom)) {
URL url = new URL(String.format("https://maven.fabricmc.net/net/fabricmc/fabric-api/%2$s/%1$s/%2$s-%1$s.pom", version, name));
try(InputStream stream = url.openStream()) {
ByteStreams.copy(stream, fos);
}
} catch (IOException e) {
throw new UncheckedIOException("Failed to download maven info to " + mavenPom.getName(), e);
}
}

return mavenPom;
}

private static class PomNotFoundException extends Exception {
PomNotFoundException(Throwable cause) {
super(cause);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ExternalModuleDependency;
import org.gradle.api.artifacts.FileCollectionDependency;
import org.gradle.api.artifacts.ProjectDependency;
import org.gradle.api.artifacts.type.ArtifactTypeDefinition;
import org.gradle.api.attributes.Attribute;
import org.gradle.api.plugins.JavaPlugin;

Expand All @@ -12,21 +16,56 @@
* Entry point of our plugin that should be applied in the root project.
*/
public class RemapperPlugin implements Plugin<Project> {
private static final Attribute<Boolean> DEV_COMPATIBLE = Attribute.of("isEmbeddiumDevCompatibleMod", Boolean.class);

@Override
public void apply(Project project) {
// setup the transform for all projects in the build
project.getPlugins().withType(JavaPlugin.class).configureEach(javaPlugin -> configureTransform(project));
}

private Configuration createRemapConfig(Project project, String name, Configuration parent) {
var config = project.getConfigurations().create(name, spec -> {
// Require isEmbeddiumDevCompatibleMod
spec.attributes(attr -> attr.attribute(DEV_COMPATIBLE, true));

// Magic borrowed from MDG
spec.withDependencies(dependencies -> dependencies.forEach(dep -> {
if (dep instanceof ExternalModuleDependency externalModuleDependency) {
project.getDependencies().constraints(constraints -> {
constraints.add(parent.getName(), externalModuleDependency.getGroup() + ":" + externalModuleDependency.getName() + ":" + externalModuleDependency.getVersion(), c -> {
c.attributes(a -> a.attribute(DEV_COMPATIBLE, true));
});
});
} else if (dep instanceof FileCollectionDependency fileCollectionDependency) {
project.getDependencies().constraints(constraints -> {
constraints.add(parent.getName(), fileCollectionDependency.getFiles(), c -> {
c.attributes(a -> a.attribute(DEV_COMPATIBLE, true));
});
});
} else if (dep instanceof ProjectDependency projectDependency) {
project.getDependencies().constraints(constraints -> {
constraints.add(parent.getName(), projectDependency.getDependencyProject(), c -> {
c.attributes(a -> a.attribute(DEV_COMPATIBLE, true));
});
});
}
}));
});
parent.extendsFrom(config);
return config;
}

private void configureTransform(Project project) {
Attribute<String> artifactType = Attribute.of("artifactType", String.class);
Attribute<Boolean> devCompatible = Attribute.of("isEmbeddiumDevCompatibleMod", Boolean.class);

var intermediaryConfig = project.getConfigurations().create("embeddiumFabricIntermediary");
var minecraftVersion = (String)project.getProperties().get("minecraft_version");

project.getDependencies().add(intermediaryConfig.getName(), "net.fabricmc:intermediary:" + minecraftVersion + ":v2");

project.getExtensions().create("fabricApiModuleFinder", FabricApiModuleFinder.class);

// Make sure the build directory exists
project.getLayout().getBuildDirectory().get().getAsFile().mkdirs();

Expand All @@ -40,35 +79,28 @@ private void configureTransform(Project project) {
}
}

// compile and runtime classpath express that they only accept modules by requesting the isEmbeddiumDevCompatibleMod=true attribute
project.getConfigurations().matching(this::isResolvingJavaPluginConfiguration).all(c -> c.getAttributes().attribute(devCompatible, true));
createRemapConfig(project, "fabricCompileOnly", project.getConfigurations().getByName("compileOnly"));

// all Jars have a isEmbeddiumDevCompatibleMod=false attribute by default; the transform also recognizes non-Fabric mods and returns them without modification
project.getDependencies().getArtifactTypes().getByName("jar").getAttributes().attribute(devCompatible, false);
project.getDependencies().attributesSchema(schema -> schema.attribute(DEV_COMPATIBLE));
project.getDependencies().getArtifactTypes().named("jar", t -> t.getAttributes().attribute(DEV_COMPATIBLE, false));

// register the transform for Jars and "isEmbeddiumDevCompatibleMod=false -> isEmbeddiumDevCompatibleMod=true"; the plugin extension object fills the input parameter
project.getDependencies().registerTransform(RemapperTransform.class, t -> {
t.getParameters().getMinecraftVersion().set(minecraftVersion);
t.getParameters().getIntermediaryMappings().fileProvider(project.provider(() -> {
var deps = intermediaryConfig.resolve();
if(deps.isEmpty()) {
throw new IllegalStateException("No intermediary mappings found");
}
return deps.iterator().next();
}));
t.getParameters().getMojangMappings().set(mappingsFile);
t.getParameters().getRemappingCache().set(project.getLayout().getBuildDirectory().dir("embeddium_remap_cache").get().getAsFile().getAbsolutePath());
t.getFrom().attribute(artifactType, "jar").attribute(devCompatible, false);
t.getTo().attribute(artifactType, "jar").attribute(devCompatible, true);
t.parameters(params -> {
params.getMinecraftVersion().set(minecraftVersion);
params.getIntermediaryMappings().fileProvider(project.provider(() -> {
var deps = intermediaryConfig.resolve();
if(deps.isEmpty()) {
throw new IllegalStateException("No intermediary mappings found");
}
return deps.iterator().next();
}));
params.getMojangMappings().set(mappingsFile);
params.getRemappingCache().set(project.getLayout().getBuildDirectory().dir("embeddium_remap_cache").get().getAsFile().getAbsolutePath());
});
t.getFrom().attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.JAR_TYPE).attribute(DEV_COMPATIBLE, false);
t.getTo().attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.JAR_TYPE).attribute(DEV_COMPATIBLE, true);
});
}

private boolean isResolvingJavaPluginConfiguration(Configuration configuration) {
if (!configuration.isCanBeResolved()) {
return false;
}
return configuration.getName().endsWith(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME.substring(1))
|| configuration.getName().endsWith(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME.substring(1))
|| configuration.getName().endsWith(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME.substring(1));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
import net.fabricmc.mappingio.format.MappingFormat;
import net.fabricmc.mappingio.tree.MemoryMappingTree;
import net.fabricmc.mappingio.tree.VisitableMappingTree;
import org.gradle.api.artifacts.transform.InputArtifact;
import org.gradle.api.artifacts.transform.TransformAction;
import org.gradle.api.artifacts.transform.TransformOutputs;
import org.gradle.api.artifacts.transform.TransformParameters;
import org.gradle.api.artifacts.transform.*;
import org.gradle.api.file.FileSystemLocation;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
Expand All @@ -30,6 +27,7 @@
/**
* An artifact transform that deobfuscates intermediary-mapped Fabric mods to Mojmap.
*/
@CacheableTransform
abstract public class RemapperTransform implements TransformAction<RemapperTransform.Parameters> {
public interface Parameters extends TransformParameters {
@Input
Expand All @@ -48,11 +46,16 @@ public interface Parameters extends TransformParameters {
}

@InputArtifact
@PathSensitive(PathSensitivity.NONE)
protected abstract Provider<FileSystemLocation> getInputArtifact();

@Override
public void transform(TransformOutputs outputs) {
File originalJar = getInputArtifact().get().getAsFile();
if (!originalJar.exists()) {
return;
}

String originalJarName = originalJar.getName();

if(isFabricMod(originalJar)) {
Expand Down
2 changes: 0 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx3G

kotlin.code.style=official

Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading

0 comments on commit 1125bc4

Please sign in to comment.