Class Failsafe

java.lang.Object
dev.xichil.mvui.Failsafe

public final class Failsafe extends Object
The fail-safe around every backend entry point (D9, TODO.md 9.1): Options screen hooks, opening the menu, the mod list's config screen, a menu screen's init and drawing, and GameBridge calls. What happens to a Throwable from one of them depends on whose code threw it:
  • A mod's own menu code (its ScreenFactory, an entry's suppliers, tagged by ModFault): only that mod's menu turns off for the rest of the session, logged once per mod. Every other mod's menu keeps working. Opening the mod's menu then shows a screen that says it is off (UiTexts.MENU_OFF), and the list of mod menus greys it out. An entry's action that throws turns nothing off: the backend logs it and the menu stays.
  • Anything else is the backend's, for example because a Minecraft update renamed something. It can't be blamed on one mod, so every menu turns off, logged once; later failures are not logged.
The game and the mods keep running either way; they just lose the menus that are off.

Off for every mod means no new way into any menu: hooks check enabled() and leave the Options screen and mod list unchanged. Menu screens already open stay usable, so the player can still leave them; run(String, Runnable) and call(String, Supplier, T) keep guarding what they do.

For mods

A mod needs nothing from this class: MultiversionUi.register(String, Text, ScreenFactory) applies the guard by itself. What it means for a mod's code:

The rest (run, call, fail, guard, logTo) is for the library's runtime and backends. The system property -Dxis_mvui.disable=true turns the library off; ForcedFailure makes every backend hook fail, to test this path.

  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final String
    Logged with the failing hook's name; integration tests look for it.
    static final String
    Logged with the failing mod's id when only its menu turns off; integration tests look for it.
  • Method Summary

    Modifier and Type
    Method
    Description
    static <T> T
    call(String what, Supplier<T> action, T fallback)
    Calls action, guarded: if it throws, fail(String, Throwable) handles it and this returns fallback.
    static boolean
    Whether the library's menus are on: false once a backend entry point failed (or the runtime couldn't start), for the rest of the session.
    static boolean
    enabled(String modId)
    Whether mod modId's menu is on: false once every menu is off (enabled()) or the mod's own menu code failed this session.
    static void
    fail(String what, Throwable t)
    Turns the menu of the mod whose code threw t off (ModFault), or every menu if no mod's code did; logs what and t if this is that mod's, or the session's, first failure.
    menu with every UiHost and GameBridge call of its screens guarded: a backend failure there turns the menu off.
    static void
    Where failures are logged; by default System.err in the core's format.
    static void
    Forgets earlier failures.
    static boolean
    run(String what, Runnable action)
    Runs action, guarded: if it throws, fail(String, Throwable) handles it and this returns false.

    Methods inherited from class Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • MOD_MENU_OFF

      public static final String MOD_MENU_OFF
      Logged with the failing mod's id when only its menu turns off; integration tests look for it.
      See Also:
  • Method Details

    • enabled

      public static boolean enabled()
      Whether the library's menus are on: false once a backend entry point failed (or the runtime couldn't start), for the rest of the session. Hooks then leave the game's screens unchanged.
      Returns:
      true until the first backend failure
    • enabled

      public static boolean enabled(String modId)
      Whether mod modId's menu is on: false once every menu is off (enabled()) or the mod's own menu code failed this session.
      Parameters:
      modId - a mod id
      Returns:
      true if the mod's menu can open normally
    • logTo

      public static void logTo(BiConsumer<String, Throwable> sink)
      Where failures are logged; by default System.err in the core's format. The core passes the game's logger. A sink that throws falls back to System.err.
      Parameters:
      sink - receives a message and the throwable (may be null); null restores the default
    • run

      public static boolean run(String what, Runnable action)
      Runs action, guarded: if it throws, fail(String, Throwable) handles it and this returns false. Never throws.
      Parameters:
      what - what the action does, for the log, e.g. "Adding the Options screen button"
      action - the action
      Returns:
      true if the action completed, false if it threw
    • call

      public static <T> T call(String what, Supplier<T> action, T fallback)
      Calls action, guarded: if it throws, fail(String, Throwable) handles it and this returns fallback. Never throws.
      Type Parameters:
      T - the result type
      Parameters:
      what - what the action does, for the log
      action - the action
      fallback - what to return if it throws
      Returns:
      action's value, or fallback
    • fail

      public static void fail(String what, Throwable t)
      Turns the menu of the mod whose code threw t off (ModFault), or every menu if no mod's code did; logs what and t if this is that mod's, or the session's, first failure. There is no way back during the session.
      Parameters:
      what - what failed, for the log, e.g. "Opening the menu"
      t - the failure
    • guard

      public static ScreenFactory guard(ScreenFactory menu)
      menu with every UiHost and GameBridge call of its screens guarded: a backend failure there turns the menu off. Bridge calls then fall back so the screen can finish: a failed GameBridge.flushOptions() saves the file as the game last wrote it, a failed GameBridge.reloadOptions() asks for a restart (the file already has the loaded options), and UiHost calls rethrow, so the menu's own error handling reports them. For the library's own menus; MultiversionUi.register(String, Text, ScreenFactory) guards each mod's with guard(String, Text, ScreenFactory).
      Parameters:
      menu - the library's menu
      Returns:
      a guarded wrapper delegating to menu
    • reset

      public static void reset()
      Forgets earlier failures. Tests only: a session never turns a menu back on.