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 all 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
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ dependencies {
}
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 isModernForge() {
return isForge() && !isLegacyForge();
}

boolean supportsInclude();

default SrgProvider getSrgProvider() {
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 @@ -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().isModernForge()) {
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().isModernForge()) {
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().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 @@ -50,6 +50,7 @@
import org.gradle.api.Project;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.ModuleDependency;
import org.gradle.api.artifacts.repositories.IvyArtifactRepository;
import org.gradle.api.artifacts.transform.InputArtifact;
import org.gradle.api.artifacts.transform.TransformAction;
import org.gradle.api.artifacts.transform.TransformOutputs;
Expand All @@ -72,6 +73,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 +101,46 @@ 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 we cannot find a modern config json, try the legacy/FG2-era one
if (Files.notExists(configEntry)) {
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) {
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);
} else {
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);
addLegacyMCPRepo();
}

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 +157,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 +166,16 @@ 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()) {

if (!isLegacyForge) {
configureRuns(json.getAsJsonObject("runs"));
} else {
configureRunsForLegacyForge();
}
}

private void configureRuns(JsonObject runs) {
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 @@ -184,6 +222,35 @@ public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulation
}
}

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

private void addLegacyMCPRepo() {
getProject().getRepositories().ivy(repo -> {
// Old MCP data does not have POMs
repo.setName("LegacyMCP");
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);
});
}

public boolean isLegacyForge() {
return isLegacyForge;
}

public abstract static class RemoveNameProvider implements TransformAction<TransformParameters.None> {
@InputArtifact
public abstract Provider<FileSystemLocation> getInput();
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