Class Failsafe
java.lang.Object
dev.xichil.mvui.Failsafe
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 byModFault): 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.
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:
- Suppliers (labels, values,
enabled,visible, tooltips, rows, validators) andScreenFactory.create(UiHost)must not throw. If one does, the mod's menu is off until the game restarts. - Actions (
onPress,onChange, dialog answers,UiHost.runOnMainThread(Runnable)tasks,UiHost.runAsync(Callable, BiConsumer)callbacks) may throw: the error is logged with the mod's id and the menu stays open. Better still, catch expected errors and show them in aStatusLine. - Exceptions reach the mod's own
catchblocks unchanged; the library only adds a suppressedModFaultthat names the mod. Failsafe.enabled(modId)tells whether the mod's menu is still on.
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 -
Method Summary
Modifier and TypeMethodDescriptionstatic <T> Tstatic booleanenabled()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 booleanWhether modmodId's menu is on: false once every menu is off (enabled()) or the mod's own menu code failed this session.static voidTurns the menu of the mod whose code threwtoff (ModFault), or every menu if no mod's code did; logswhatandtif this is that mod's, or the session's, first failure.static ScreenFactoryguard(ScreenFactory menu) menuwith everyUiHostandGameBridgecall of its screens guarded: a backend failure there turns the menu off.static voidlogTo(BiConsumer<String, Throwable> sink) Where failures are logged; by defaultSystem.errin the core's format.static voidreset()Forgets earlier failures.static booleanRunsaction, guarded: if it throws,fail(String, Throwable)handles it and this returns false.
-
Field Details
-
MENU_OFF
Logged with the failing hook's name; integration tests look for it.- See Also:
-
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:
trueuntil the first backend failure
-
enabled
-
logTo
Where failures are logged; by defaultSystem.errin the core's format. The core passes the game's logger. A sink that throws falls back toSystem.err.- Parameters:
sink- receives a message and the throwable (may benull);nullrestores the default
-
run
Runsaction, 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:
trueif the action completed,falseif it threw
-
call
Callsaction, guarded: if it throws,fail(String, Throwable)handles it and this returnsfallback. Never throws.- Type Parameters:
T- the result type- Parameters:
what- what the action does, for the logaction- the actionfallback- what to return if it throws- Returns:
action's value, orfallback
-
fail
Turns the menu of the mod whose code threwtoff (ModFault), or every menu if no mod's code did; logswhatandtif 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
menuwith everyUiHostandGameBridgecall of its screens guarded: a backend failure there turns the menu off. Bridge calls then fall back so the screen can finish: a failedGameBridge.flushOptions()saves the file as the game last wrote it, a failedGameBridge.reloadOptions()asks for a restart (the file already has the loaded options), andUiHostcalls 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 withguard(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.
-