Register your menu

Where and when to call MultiversionUi.register on each loader, what the arguments must be, and how to keep it safe on dedicated servers.

Last updated

Steps

A menu exists once your mod calls MultiversionUi.register. This page covers where to make that call on each loader and what can go wrong.

The call#

MultiversionUi.register("mymod", Text.translatable("mymod.name", "My Mod"), new MyMenu(config));
Argument Rule
modId Your mod id exactly as in your mod metadata: 2 – 64 characters, a lower-case letter first, then lower-case letters, digits, _ or -. Anything else throws IllegalArgumentException.
name Your mod's name as the "Mod menus" list shows it when several mods have menus.
menu Your ScreenFactory. It isn't called yet: create runs each time the player opens the menu.

A null argument throws NullPointerException. Nothing else throws: without a backend for the running game, the menu is recorded and simply never shown.

When and where#

Call it once, on the client, while the game starts. It is safe from any thread (Forge may construct mods in parallel).

Fabric, Quilt, Legacy Fabric

From your client entrypoint, a ClientModInitializer listed under entrypoints.client in fabric.mod.json:

MyModClient.java
public final class MyModClient implements ClientModInitializer {
    @Override
    public void onInitializeClient() {
        MultiversionUi.register("mymod", Text.translatable("mymod.name", "My Mod"), new MyMenu(new MyConfig()));
    }
}

With Mod Menu installed, the mod list's Config button opens your menu automatically, for every mod that depends on xis_mvui.

Forge, NeoForge

From your @Mod class's constructor. What else you need depends on the era:

  • Forge 1.13.2 – 26.3 and NeoForge: nothing. Registering from the constructor also makes the menu your mod's Config screen in the mod list, because Forge attributes it to the mod whose constructor is running. Registering later (for example in a setup event) still adds the Options button but may miss the mod list.
  • Forge 1.8 – 1.12.2: add guiFactory = MultiversionUi.LEGACY_FORGE_GUI_FACTORY to @Mod.
  • Forge 1.7.10: add guiFactory = MultiversionUi.CPW_FORGE_GUI_FACTORY to @Mod.
MyMod.java (Forge 1.13.2+)
@Mod("mymod")
public final class MyMod {
    public MyMod() {
        MultiversionUi.register("mymod", Text.translatable("mymod.name", "My Mod"), new MyMenu(new MyConfig()));
    }
}
MyMod.java (Forge 1.8 – 1.12.2)
@Mod(modid = "mymod", dependencies = "required-after:xis_mvui",
        guiFactory = MultiversionUi.LEGACY_FORGE_GUI_FACTORY)
public final class MyMod {
    public MyMod() {
        MultiversionUi.register("mymod", Text.translatable("mymod.name", "My Mod"), new MyMenu(new MyConfig()));
    }
}

The guiFactory constants are class names that Forge loads by name, so they work even though those classes aren't on your compile class path. Other versions ignore them.

Checking that it worked#

boolean registered = MultiversionUi.menu("mymod") != null;

MultiversionUi.menus() lists every registered menu, in registration order, as Registration objects with modId(), name() and menu().

Registering twice#

A second register with the same mod id logs an error and is ignored: the first menu stays. Register once. To show different screens at different times, decide inside create, which runs on every opening.

Dedicated servers#

The library is client-side. On a dedicated server it selects no backend, so a register call there does nothing and doesn't fail, as long as the library is installed.

The catch is a server without the library. The dependency declared with side = "CLIENT" doesn't make servers install it, and a Forge @Mod constructor runs on both sides. If that constructor reaches MultiversionUi on a server that lacks the library, the class is missing and the mod fails to load. If your mod also runs on servers:

  1. Keep every reference to dev.xichil.mvui in client-only classes (your menu, and a small class with the register call).
  2. In the constructor, check your loader's physical side first, and call into that class only on the client.

A Fabric client entrypoint never runs on a dedicated server, so it needs neither step.

Next steps#