Skip to content

Conversation

@kikugie
Copy link

@kikugie kikugie commented Sep 5, 2025

Motivation

Multi-version mods often have a shared source directory, which is then processed to generated sources for each subproject. Currently Loom expects fabric.mod.json to be in src/main/resources (or client)` of the project's folder.
In multi-version projects, this file is located in the shared source, and due to the hardcoded path, Loom doesn't recognize it, leading to issues with using injected interfaces.

Implementation

This PR adds fabricModJsonPath property to the Loom extension. If specified that file is used, otherwise falling back to the existing behaviour.

Copy link
Member

@modmuss50 modmuss50 left a comment

Choose a reason for hiding this comment

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

If you can an intergration test to cover this would be very useful. Let me know if you need help with it.

@Nullable
public static FabricModJson createFromSourceSetsNullable(Project project, SourceSet... sourceSets) throws IOException {
final File file = SourceSetHelper.findFirstFileInResource(FABRIC_MOD_JSON, project, sourceSets);
final RegularFileProperty fmjPath = project.getExtensions().getByType(LoomGradleExtensionAPI.class).getFabricModJsonPath();
Copy link
Member

Choose a reason for hiding this comment

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

I dont think this right place to do this, FabricModJsonHelpers.getModsInProject is the place for it.

Copy link
Author

@kikugie kikugie Sep 5, 2025

Choose a reason for hiding this comment

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

What exactly? My implementation was based on the fact that the createFromSourceSetsNullable method is called from the Loom and Fabric API extensions (LoomGradleExtensionApiImpl.getModVersion and FabricApiAbstractSourceSet.configureSourceSet), so using the property here would provide the desired file to those too.

@kikugie
Copy link
Author

kikugie commented Sep 10, 2025

A thing to consider in a next commit is the way to deal with fmj used in the datagen source set. Currently it still uses the old method, but it would also be helpful to be able to specify its path.

* Returns the list of mods provided by either {@code overrideFile} property
* or {@code fabric.mod.json} in the {@code sourceSets} array.
*/
public static List<FabricModJson> getModsInProject(Project project, Provider<File> overrideFile, SourceSet... sourceSets) {
Copy link
Member

Choose a reason for hiding this comment

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

Why is this needed? Can you just not always get it from the extension? I dont get why this is needed in the fabricapi extension?

Copy link
Member

@modmuss50 modmuss50 left a comment

Choose a reason for hiding this comment

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

Im happy with the API design and rough implementation. However it really needs some proper thought about what is a fatal error and what isnt. The null handling is a bit of a mess here, its not clear what can be null and what isnt.

I think what we really want is that if a user specifies a custom FMJ path, it should be a non null file that exists, and is a valid FMJ. Aything other than that should cause a hard crash.

Also please make sure to run checkstyle / spotless (there is an intelij plugin that makes it easy to see what is wrong). If you run gradlew build -x test locally you can verify that it will build on CI. (Dont try to run all the tests locally otherwise you will be waiting all day)

@kikugie
Copy link
Author

kikugie commented Oct 2, 2025

image Not my issue 🤷

@modmuss50
Copy link
Member

Not my issue 🤷

It was, I fixed it by running spotlessApply

*/
public static List<FabricModJson> getModsInProject(Project project) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
var overrideFile = extension.getFabricModJsonPath().getAsFile();
Copy link
Member

Choose a reason for hiding this comment

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

FYI: I see you like to use var wherever possible, this isnt something we tend to do. In other fabric projects we disallow var other than for new instance creataion. e.g var a = new Object() is fine as you can clearly see the type. Loom doesnt enforce this as there are some places where gradle forces you to use an obtuse type, but for simple types such a File in this case I wouldnt choose to use var as it makes the code harder to read.

Dont worry about it for this PR its just a minor nit pick.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks for pointing out. I used var for consistency with the other cases I've seen in the area, but I can replace it if needed.

Copy link
Member

Choose a reason for hiding this comment

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

Ive done it :) I also moved the tests to one of the existing files, this is becuase each test file gets a new github actions job, there was nothing wrong with having its own file but it will be a tiny bit quicker. Im happy with this PR now :) Thanks.

import net.fabricmc.loom.task.GenerateSourcesTask;
import net.fabricmc.loom.util.DeprecationHelper;
import net.fabricmc.loom.util.MirrorUtil;
import net.fabricmc.loom.util.fmj.FabricModJson;
Copy link
Author

Choose a reason for hiding this comment

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

Linters - my greatest nemesis

@Mat0u5
Copy link

Mat0u5 commented Oct 3, 2025

You two are the best <3

@modmuss50 modmuss50 merged commit 7f95c3c into FabricMC:exp/1.12 Oct 3, 2025
46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants