Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for FG2-era Forge #70

Open
wants to merge 18 commits into
base: dev/0.10.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,17 @@ dependencies {
implementation ('de.oceanlabs.mcp:mcinjector:3.8.0')
implementation ('com.opencsv:opencsv:5.4')

// Legacy Forge access transformers
implementation ('net.md-5:SpecialSource:1.10.0')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the current AT tool not work for old MC versions?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would require remapping the entire minecraft jar (and presumably also forge? I guess ATs can apply to it as well?) from official to srg and back, only to run the AT tool. Much slower than this implementation which basically just converts the names as it looks them up.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I see. You could also remap the AT since we have tools (CadixDev's library) for that.


// Testing
testImplementation(gradleTestKit())
testImplementation('org.spockframework:spock-core:2.0-groovy-3.0') {
exclude module: 'groovy-all'
}
testImplementation 'io.javalin:javalin:3.13.11'
testImplementation 'net.fabricmc:fabric-installer:0.9.0'
runtimeOnly 'dev.architectury.architectury-pack200:dev.architectury.architectury-pack200.gradle.plugin:0.1.3'

compileOnly 'org.jetbrains:annotations:22.0.0'
}
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/net/fabricmc/loom/LoomGradleExtension.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ default boolean isForgeAndNotOfficial() {
return isForge() && !getMcpConfigProvider().isOfficial();
}

default boolean isLegacyForge() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Not really sure where to put this comment so I'll put it here) I'd prefer negating the isLegacyForge check for most if-else blocks since it currently pushes the "normal" (= modern) path further down.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I flipped a bunch of conditionals accordingly. Lmk if there are any more you'd prefer flipped.

return isForge() && getForgeUserdevProvider().isLegacyForge();
}

default boolean isModLauncher() {
Juuxel marked this conversation as resolved.
Show resolved Hide resolved
return isForge() && !isLegacyForge();
}

boolean supportsInclude();

default SrgProvider getSrgProvider() {
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/net/fabricmc/loom/LoomRepositoryPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ private void declareRepositories(RepositoryHandler repositories, LoomFiles files
sources.ignoreGradleMetadataRedirection();
});
});
repositories.ivy(repo -> {
// Old MCP data does not have POMs
repo.setName("LegacyMCP");
Juuxel marked this conversation as resolved.
Show resolved Hide resolved
repo.setUrl("https://maven.minecraftforge.net/");
repo.patternLayout(layout -> {
layout.artifact("[orgPath]/[artifact]/[revision]/[artifact]-[revision](-[classifier])(.[ext])");
// also check the zip so people do not have to explicitly specify the extension for older versions
layout.artifact("[orgPath]/[artifact]/[revision]/[artifact]-[revision](-[classifier]).zip");
});
repo.content(descriptor -> {
descriptor.includeGroup("de.oceanlabs.mcp");
});
repo.metadataSources(IvyArtifactRepository.MetadataSources::artifact);
});
repositories.mavenCentral();

repositories.ivy(repo -> {
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/net/fabricmc/loom/api/ForgeExtensionAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import org.gradle.api.provider.SetProperty;
import org.jetbrains.annotations.ApiStatus;

import net.fabricmc.loom.configuration.providers.forge.fg2.Pack200Provider;

/**
* This is the forge extension api available exposed to build scripts.
*/
Expand Down Expand Up @@ -148,4 +150,6 @@ interface DataGenConsumer {
* @see ForgeLocalMod
*/
NamedDomainObjectContainer<ForgeLocalMod> getLocalMods();

Property<Pack200Provider> getPack200Provider();
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ private static boolean shouldRemapMod(Logger logger, File artifact, Object id, b
}

if (forge) {
if (zipFile.getEntry("META-INF/mods.toml") != null) {
if (zipFile.getEntry("META-INF/mods.toml") != null || zipFile.getEntry("mcmod.info") != null) {
logger.info("Found Forge mod in " + config + ": {}", id);
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public void configureMixin() {
ConfigurationContainer configs = project.getConfigurations();
LoomGradleExtension extension = LoomGradleExtension.get(project);

if (!extension.ideSync()) {
if (!extension.ideSync() || extension.isLegacyForge()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IDE sync check here is done for a reason and the mixin AP shouldn't be used in IDE builds.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tbh I don't recall why I even added it. I must have had some issues with Mixin before but I can no longer reproduce that, so I'll remove it again.

Out of curiosity, do you happen to know the reason? Removing mixin from the AP classpath just for the IDE seems wrong (you have to manually build to get its errors/warnings) and I've not noticed anything wrong while it was there. The oldest commit I could track it back to (5c2b669) doesn't give any reason.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Afaik the 0.8.5 AP detects IDEA and disables itself accordingly, Mixin has done that for eclipse for a while too.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Mixin AP would be used to have errors if it's not disabled, and those errors are wrong

for (Configuration processorConfig : apConfigurations) {
project.getLogger().info("Adding mixin to classpath of AP config: " + processorConfig.getName());
// Pass named MC classpath to mixin AP classpath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,9 @@ public static void configureCompile(Project p) {
}

if (extension.isForge()) {
dependencyManager.addProvider(new ForgeUniversalProvider(project));
dependencyManager.addProvider(new McpConfigProvider(project));
dependencyManager.addProvider(new PatchProvider(project));
dependencyManager.addProvider(new ForgeUniversalProvider(project));
}

dependencyManager.addProvider(extension.isForge() ? new FieldMigratedMappingsProvider(project) : new MappingsProviderImpl(project));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -66,15 +66,15 @@ public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulation
.property("client", "java.library.path", getExtension().getMinecraftProvider().nativesDir().getAbsolutePath())
.property("client", "org.lwjgl.librarypath", getExtension().getMinecraftProvider().nativesDir().getAbsolutePath());

if (!getExtension().isForge()) {
if (!getExtension().isModLauncher()) {
launchConfig
.argument("client", "--assetIndex")
.argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion()))
.argument("client", "--assetsDir")
.argument("client", new File(getDirectories().getUserCache(), "assets").getAbsolutePath());
}

if (getExtension().isForge()) {
if (getExtension().isModLauncher()) {
Juuxel marked this conversation as resolved.
Show resolved Hide resolved
launchConfig
// Should match YarnNamingService.PATH_TO_MAPPINGS in forge-runtime
.property("fabric.yarnWithSrg.path", getExtension().getMappingsProvider().tinyMappingsWithSrg.toAbsolutePath().toString())
Expand Down Expand Up @@ -103,11 +103,29 @@ public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulation
}
}

if (getExtension().isLegacyForge()) {
launchConfig
.argument("client", "--tweakClass")
.argument("client", Constants.LegacyForge.FML_TWEAKER)
.argument("server", "--tweakClass")
.argument("server", Constants.LegacyForge.FML_SERVER_TWEAKER)

.argument("--accessToken")
.argument("undefined")

.property("net.minecraftforge.gradle.GradleStart.srg.srg-mcp", getExtension().getMappingsProvider().srgToNamedSrg.toAbsolutePath().toString())
.property("mixin.env.remapRefMap", "true");

for (String config : PropertyUtil.getAndFinalize(getExtension().getForge().getMixinConfigs())) {
launchConfig.argument("--mixin").argument(config);
}
}

addDependency(Constants.Dependencies.DEV_LAUNCH_INJECTOR + Constants.Dependencies.Versions.DEV_LAUNCH_INJECTOR, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES);
addDependency(Constants.Dependencies.TERMINAL_CONSOLE_APPENDER + Constants.Dependencies.Versions.TERMINAL_CONSOLE_APPENDER, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES);
addDependency(Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS, JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME);

if (getExtension().isForge()) {
if (getExtension().isForge() && !getExtension().isLegacyForge()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (getExtension().isForge() && !getExtension().isLegacyForge()) {
if (getExtension().isModernForge()) {

addDependency(Constants.Dependencies.FORGE_RUNTIME + Constants.Dependencies.Versions.FORGE_RUNTIME, Constants.Configurations.FORGE_EXTRA);
addDependency(Constants.Dependencies.JAVAX_ANNOTATIONS + Constants.Dependencies.Versions.JAVAX_ANNOTATIONS, JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME);
}
Expand Down Expand Up @@ -197,7 +215,7 @@ public String getTargetConfig() {
}

public static class LaunchConfig {
private final Map<String, List<String>> values = new HashMap<>();
private final Map<String, List<String>> values = new LinkedHashMap<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's wrong with a normal hashmap?

Copy link
Author

@Johni0702 Johni0702 Jan 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one's a bit subtle but I couldn't think of any better solution. It all comes down to the fact that order of "--tweakClass" arguments matters. We add the default server/client forge tweakers to the "server"/"client" arguments right from the start. So if the user adds their own "server" or "client" tweaker, all is fine. But if they add their own tweaker to the "common" arguments, then the actual order of the final arguments depends on HashMap iteration order because that's the order in which the three section ("common","client" and "server") are written to the dev-launch-injector file (common isn't merged into the other ones until the game actually starts; come to think of it, maybe we should just merge them at build time rather than runtime? thought that would be kinda out of scope for this PR).


public LaunchConfig property(String key, String value) {
return property("common", key, value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,21 @@ protected String createMappingsIdentifier(String mappingsName, String version, S
public void manipulateMappings(Path mappingsJar) throws IOException {
Stopwatch stopwatch = Stopwatch.createStarted();
LoomGradleExtension extension = getExtension();

if (extension.isLegacyForge()) {
// Legacy forge patches are in official namespace, so if the type of a field is changed by them, then that
// is effectively a new field and not traceable to any mapping. Therefore this does not apply to it.
return;
}

this.rawTinyMappings = tinyMappings;
this.rawTinyMappingsWithSrg = tinyMappingsWithSrg;
String mappingsJarName = mappingsJar.getFileName().toString();

if (getExtension().shouldGenerateSrgTiny()) {
if (Files.notExists(rawTinyMappingsWithSrg) || isRefreshDeps()) {
// Merge tiny mappings with srg
SrgMerger.mergeSrg(getProject().getLogger(), getExtension().getMappingsProvider()::getMojmapSrgFileIfPossible, getRawSrgFile(), rawTinyMappings, rawTinyMappingsWithSrg, true);
SrgMerger.mergeSrg(getProject().getLogger(), getExtension().getMappingsProvider()::getMojmapSrgFileIfPossible, getRawSrgFile(), rawTinyMappings, rawTinyMappingsWithSrg, true, false);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public class ForgeUserdevProvider extends DependencyProvider {
private File userdevJar;
private JsonObject json;
private Consumer<Runnable> postPopulationScheduler;
private boolean isLegacyForge;

public ForgeUserdevProvider(Project project) {
super(project);
Expand Down Expand Up @@ -99,19 +100,44 @@ public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulation
Files.copy(resolved.toPath(), userdevJar.toPath(), StandardCopyOption.REPLACE_EXISTING);

try (FileSystem fs = FileSystems.newFileSystem(new URI("jar:" + resolved.toURI()), ImmutableMap.of("create", false))) {
Files.copy(fs.getPath("config.json"), configJson, StandardCopyOption.REPLACE_EXISTING);
Path configEntry = fs.getPath("config.json");

if (!Files.exists(configEntry)) {
Johni0702 marked this conversation as resolved.
Show resolved Hide resolved
configEntry = fs.getPath("dev.json");
Juuxel marked this conversation as resolved.
Show resolved Hide resolved
}

Files.copy(configEntry, configJson, StandardCopyOption.REPLACE_EXISTING);
}
}

try (Reader reader = Files.newBufferedReader(configJson)) {
json = new Gson().fromJson(reader, JsonObject.class);
}

addDependency(json.get("mcp").getAsString(), Constants.Configurations.MCP_CONFIG);
addDependency(json.get("mcp").getAsString(), Constants.Configurations.SRG);
addDependency(json.get("universal").getAsString(), Constants.Configurations.FORGE_UNIVERSAL);
isLegacyForge = !json.has("mcp");

if (isLegacyForge) {
Map<String, String> mcpDep = Map.of(
"group", "de.oceanlabs.mcp",
"name", "mcp",
"version", json.get("inheritsFrom").getAsString(),
"classifier", "srg",
"ext", "zip"
);
addDependency(mcpDep, Constants.Configurations.MCP_CONFIG);
addDependency(mcpDep, Constants.Configurations.SRG);
addDependency(dependency.getDepString() + ":universal", Constants.Configurations.FORGE_UNIVERSAL);
} else {
addDependency(json.get("mcp").getAsString(), Constants.Configurations.MCP_CONFIG);
addDependency(json.get("mcp").getAsString(), Constants.Configurations.SRG);
addDependency(json.get("universal").getAsString(), Constants.Configurations.FORGE_UNIVERSAL);
}

for (JsonElement lib : json.get("libraries").getAsJsonArray()) {
if (isLegacyForge) {
lib = lib.getAsJsonObject().get("name");
}

Dependency dep = null;

if (lib.getAsString().startsWith("org.spongepowered:mixin:")) {
Expand All @@ -128,7 +154,7 @@ public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulation
dep = addDependency(lib.getAsString(), Constants.Configurations.FORGE_DEPENDENCIES);
}

if (lib.getAsString().split(":").length < 4) {
if (!isLegacyForge && lib.getAsString().split(":").length < 4) {
((ModuleDependency) dep).attributes(attributes -> {
attributes.attribute(transformed, true);
});
Expand All @@ -137,7 +163,10 @@ public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulation

// TODO: Should I copy the patches from here as well?
// That'd require me to run the "MCP environment" fully up to merging.
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject("runs").entrySet()) {

JsonObject runs = isLegacyForge ? new JsonObject() : json.getAsJsonObject("runs");
Juuxel marked this conversation as resolved.
Show resolved Hide resolved

for (Map.Entry<String, JsonElement> entry : runs.entrySet()) {
LaunchProviderSettings launchSettings = getExtension().getLaunchConfigs().findByName(entry.getKey());
RunConfigSettings settings = getExtension().getRunConfigs().findByName(entry.getKey());
JsonObject value = entry.getValue().getAsJsonObject();
Expand Down Expand Up @@ -182,6 +211,18 @@ public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulation
});
}
}

if (isLegacyForge) {
getExtension().getRunConfigs().configureEach(config -> {
if (Constants.Forge.LAUNCH_TESTING.equals(config.getDefaultMainClass())) {
config.setDefaultMainClass(Constants.LegacyForge.LAUNCH_WRAPPER);
}
});
}
}

public boolean isLegacyForge() {
return isLegacyForge;
}

public abstract static class RemoveNameProvider implements TransformAction<TransformParameters.None> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ public McpConfigProvider(Project project) {

@Override
public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws Exception {
if (getExtension().isLegacyForge()) {
official = false;
return;
}

init(dependency.getDependency().getVersion());

Path mcpZip = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not resolve MCPConfig")).toPath();
Expand Down
Loading