Skip to content

feat!: Use ServiceLoader for Renderer registry, RendererReadyEntrypoint#5185

Open
sylv256 wants to merge 18 commits intoFabricMC:26.1from
sylv256:rendering-0
Open

feat!: Use ServiceLoader for Renderer registry, RendererReadyEntrypoint#5185
sylv256 wants to merge 18 commits intoFabricMC:26.1from
sylv256:rendering-0

Conversation

@sylv256
Copy link
Member

@sylv256 sylv256 commented Feb 4, 2026

Problem

Because Renderer can be rendered at any point before or during Minecraft's initialization until it is used, problems arise when it's necessary to use it early. For example, in order to disable Indigo, FRAPI implementations need to add a custom field to their fabric.mod.json. Renderers should not need to add a field to their FMJ just to disable Indigo, let alone any other Renderer. Also, mods extending FRAPI such as Conduit need a defined point in time during and after which Renderer is ready to use. All of this introduces inconsistent behavior and quickly becomes a headache. See #3109 for more details.

Solution

This Pull Request overhauls and adds new concepts to FRAPI's Renderer registration.

RendererProvider

interface RendererProvider {
    static RendererProvider get() { // Gets or finds the RendererProvider for the renderer that will be loaded
        // ...
    }

    String id(); // "Renderer ID", usually the mod ID of the renderer

    @ApiStatus.OverrideOnly
    Renderer getRenderer(); // Gets or instantiates the Renderer implementation

    @ApiStatus.OverrideOnly
    default int priority() { // The priority in which this renderer will be loaded (highest loads)
        return 1000; // 1000 is fine for most renderers
    }
}

Instead of manually calling Renderer#register, renderers are now registered with a Service Loader. This lets mods get basic information about the renderer that will be loaded at any point during the game's execution as they can be loaded immediately, and this is especially useful for Mixin Config Plugins.

RendererReadyEntrypoint

In fabric.mod.json, it is defined as fabric-renderer-ready.

Sometimes, mods will want to use Renderer right away, and this is where the issues with the prior system really reveal themselves. Previously, if a mod wanted Renderer, they would have to either use Renderer#get and hope it's already registered, or they would Mixin into Renderer#register to ensure that Renderer has been registered before using it.

Conduit is a library built to create and implement extensions for FRAPI. In order for Conduit's extensions, implementations, and users to use FRAPI and Conduit effectively, a RendererReadyEntrypoint is required. Some operations are best done as soon as the Renderer is ready, so having an entrypoint to ensure code that requires Renderer does not use it before it is registered is powerful.

Tests & Integrity

I've added two checks: one in FRAPI itself to ensure a renderer is loaded, and one in its Client Testmod that asserts RendererReadyEntrypoint is invoked. If either of these conditions fail, an exception is thrown.

Additional Information

Proof that it works
image

Fixes #3109

@sylv256 sylv256 added module: renderer indigo Pull requests and issues related to Indigo's implementation of the rendering api area: rendering labels Feb 4, 2026
@sylv256 sylv256 marked this pull request as draft February 4, 2026 05:54
@sylv256
Copy link
Member Author

sylv256 commented Feb 4, 2026

Setting to draft as changes were requested

 - Crash when no `RendererProvider` is present
 - Replace `fabric-renderer-indigo:contains_renderer` mechanism with the `RendererProvider#priority` system
# Conflicts:
#	fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/api/client/renderer/v1/Renderer.java
#	fabric-renderer-api-v1/src/client/java/net/fabricmc/fabric/impl/client/renderer/RendererManager.java
#	fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/Indigo.java
#	fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/IndigoMixinConfigPlugin.java
#	fabric-renderer-indigo/src/client/java/net/fabricmc/fabric/impl/client/indigo/renderer/IndigoRenderer.java
@sylv256 sylv256 marked this pull request as ready for review February 4, 2026 20:55
@PepperCode1 PepperCode1 self-requested a review February 5, 2026 04:22
}

/**
* Get or instantiate an implementation of {@link Renderer}.
Copy link
Member

Choose a reason for hiding this comment

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

This javadoc should clarify that this method is called only if this provider is selected and that this method is guaranteed to run at the same time as ClientModInitializer.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure if this is relevant anymore.

if (needsLoad) {
for (ModContainer container : FabricLoader.getInstance().getAllMods()) {
final ModMetadata meta = container.getMetadata();
indigoApplicable = RendererProvider.get().id().equals("fabric-renderer-indigo");
Copy link
Member

Choose a reason for hiding this comment

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

If the API exposes the entire RendererProvider instance instead of just the ID, then using an instanceof check like FREX instead of having the ID in the API at all would work. I suggested only exposing the ID because mods should not be creating renderers or checking provider priorities manually.

Copy link
Member Author

@sylv256 sylv256 Feb 5, 2026

Choose a reason for hiding this comment

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

Mods may have a genuine need to check the ID of the RendererProvider, so I think we should keep it rather than forcing them to rely on Renderers' implementation details. Everything else can be OverrideOnly.

If it's somehow any better, we can do an instanceof check here since that works in implementation. I just wanted to have a good example of how to use the API.

@sylv256
Copy link
Member Author

sylv256 commented Feb 6, 2026

???
image

Comment on lines +57 to +68
* The higher a renderer's priority is, the more likely it is to be loaded. So, the
* {@link RendererProvider} with the highest priority is loaded.
*
* @return this renderer's priority.
* @implSpec Implementations of {@link Renderer} should use priority {@code 1000} in most cases.
* However, they may choose any priority or even change priorities based on some conditions.
* Implementors should avoid priorities of {@code 0} or below as that is Indigo's priority.
*/
@ApiStatus.OverrideOnly
default int priority() {
return 1000;
}
Copy link
Member

Choose a reason for hiding this comment

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

This is an anti pattern, and something we dont do else where. It always ends up in a mess and people will put max int to force them selves to be first. Im really no keen on this at all. Use the toposort with a before/after mod id.

Copy link
Member Author

Choose a reason for hiding this comment

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

Is this in CONTRIBUTING.md? If not I'll probably add it

Copy link
Member

Choose a reason for hiding this comment

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

It may be a good idea, we have used the toposorting logic in quite a few places now. Let me know if you need help to wire it up.

Copy link
Member Author

Choose a reason for hiding this comment

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

Is there an example in fapi where it's used?

Copy link
Member

Choose a reason for hiding this comment

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

ParticleGroupRegistryImpl.registerOrdering
or ArrayBackedEvent.addPhaseOrdering
or ModPackResourcesSorter.addLoadOrdering

net.fabricmc.fabric.impl.base.toposort.NodeSorting is what everything uses. Don't spend ages on this if you cannot figure it out, do let me know if you arent making any progress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: rendering module: renderer indigo Pull requests and issues related to Indigo's implementation of the rendering api

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FRAPI relies on mod load order

3 participants