Class MultiversionUi

java.lang.Object
dev.xichil.mvui.MultiversionUi

public final class MultiversionUi extends Object
Where mods register their menus with Xi's Multiversion UI Lib, and the static entry point of the API. A mod builds its screens from this API's widgets (MenuScreen, Button, Toggle…) once, and registers a ScreenFactory that creates the first one; the library's backend for the running Minecraft version draws them with that version's vanilla GUI classes.

Registering

// Fabric / Quilt / Legacy Fabric: in the "client" entrypoint
public final class MyModClient implements ClientModInitializer {
    public void onInitializeClient() {
        MultiversionUi.register("mymod", Text.translatable("mymod.name", "My Mod"), new MyMenu());
    }
}

// Forge / NeoForge: in the @Mod class's constructor, on the client only
public MyMod() {
    if (isClient()) {
        MultiversionUi.register("mymod", Text.translatable("mymod.name", "My Mod"), new MyMenu());
    }
}
The mod must also declare a dependency on the library mod ("xis_mvui") in its loader's metadata, and must not bundle this API jar: the library's own jar provides it at runtime.

Where players find a registered menu

  • The Options screen gets one button (labelled by ScreenFactory.buttonLabel() when only one mod is registered, otherwise UiTexts.MOD_MENUS). With one registered menu it opens that menu; with several, a "Mod menus" list with one button per mod, labelled with the name passed to register(String, Text, ScreenFactory).
  • The mod list's Config button:
    • Forge and NeoForge 1.13+: automatic, provided register(String, Text, ScreenFactory) runs in the mod's @Mod constructor (Forge attributes the config screen to the mod whose constructor is running).
    • Fabric and Quilt with Mod Menu: automatic for every mod that depends on "xis_mvui".
    • Forge 1.8 – 1.12.2: set guiFactory = MultiversionUi.LEGACY_FORGE_GUI_FACTORY in the mod's @Mod annotation.
    • Forge 1.7.10: set guiFactory = MultiversionUi.CPW_FORGE_GUI_FACTORY.
  • The mod's own code, e.g. a key binding or a button on another screen: menuScreen(String, Object) returns the menu as the running version's screen object, ready to pass to the game's setScreen/ displayGuiScreen.

Safety

Everything here is safe to call on any loader and version. Without a backend for the running game, or without the library's runtime at all (as in unit tests that only have this API jar), menus are recorded in menus() but never shown, and nothing throws.

Any number of mods can register. Each mod's menu fails on its own: if its code throws while a screen is built or refreshed, only that mod's menu turns off and the others keep working (Failsafe).

  • Field Details

    • MOD_ID

      public static final String MOD_ID
      The library's mod id, "xis_mvui": what a mod names in its dependency declaration, e.g. "depends": { "xis_mvui": ">=1.0.0" } in fabric.mod.json, a modId = "xis_mvui" dependency in mods.toml, or @Mod(dependencies = "required-after:xis_mvui") on Forge 1.7.10 – 1.12.2. Also the namespace of the library's own translation keys (xis_mvui.*).
      See Also:
    • LEGACY_FORGE_GUI_FACTORY

      public static final String LEGACY_FORGE_GUI_FACTORY
      Class name for @Mod(guiFactory = MultiversionUi.LEGACY_FORGE_GUI_FACTORY) on Forge 1.8 – 1.12.2. It makes the mod list's Config button open the selected mod's registered menu. Forge loads the class by name, so the constant works even though the class is not on a mod's compile class path. Ignored on other versions.
      See Also:
    • CPW_FORGE_GUI_FACTORY

      public static final String CPW_FORGE_GUI_FACTORY
      Class name for @Mod(guiFactory = MultiversionUi.CPW_FORGE_GUI_FACTORY) on Forge 1.7.10 (whose FML lives in the cpw.mods.fml packages). Same effect as LEGACY_FORGE_GUI_FACTORY.
      See Also:
  • Method Details

    • register

      public static void register(String modId, Text name, ScreenFactory menu)
      Registers menu as mod modId's menu, shown as name in the list of mod menus.

      When and where to call it: once, on the client, while the game initializes: from the mod's client entrypoint on Fabric, Quilt and Legacy Fabric, or from its @Mod constructor on Forge and NeoForge (where that also makes it the mod list's Config screen on 1.13+). Calling it later works for the Options screen button but may miss the mod list. Any thread: Forge may construct mods in parallel.

      What happens: the menu is wrapped by Failsafe (so failures of the mod's code turn off only its menu), added to menus(), and handed to the library's runtime, which hooks the Options screen when the first menu is registered. menu is not called yet: ScreenFactory.create(UiHost) runs each time the player opens the menu.

      Never fails for reasons outside the caller's control: without a backend for the running game there is simply no menu, and a second registration for the same modId logs an error and is ignored (the first menu stays). Only invalid arguments throw.

      Parameters:
      modId - the registering mod's id, as in its loader metadata: 2 – 64 characters, starting with a lower-case letter, then lower-case letters, digits, _ or -
      name - the mod's name as the "Mod menus" list shows it, e.g. Text.translatable("mymod.name", "My Mod")
      menu - builds the menu's first screen each time it opens
      Throws:
      IllegalArgumentException - if modId isn't a valid mod id
      NullPointerException - if an argument is null
    • reloadGameOptions

      public static boolean reloadGameOptions()
      Makes the running game re-read options.txt and apply it, for a mod that changed the file after the game read it (e.g. a mod that restores saved options at startup). Inside a menu, prefer host.game().reloadOptions() (GameBridge.reloadOptions()), which also reports which options need a restart.

      Any thread: the backend moves the work to the main thread itself, so it may not have happened yet when this returns. Never throws.

      Returns:
      true if a backend took the request; false if there is no backend to do it (the game then applies the file on its next launch) or the backend failed