Read and write options.txt

Use GameBridge to flush, reload and apply the game's options.txt from a menu, and report the options that need a restart.

Last updated

Steps

Most menus never touch the game's own settings. A mod that saves or restores options.txt, such as a settings profile mod, uses GameBridge, which every menu gets from host.game().

What it offers#

Method Does If the backend fails
flushOptions() Makes the game write its in-memory options to options.txt now, so a copy made afterwards has the newest values. the file stays as the game last wrote it
reloadOptions() Re-reads options.txt and applies what it can in the running game (graphics, sound, controls, language…). Returns a ReloadResult. returns a result saying options.txt needs a restart
isInWorld() Whether a single- or multiplayer world is loaded, for example to warn before loading options. false

Call them on the main thread, which is where actions run. None of them throws on a registered menu's host.

Save a copy#

Flush first, then copy the file off the main thread:

Button.builder("save")
        .label(Text.translatable("mymod.save", "Save profile"))
        .onPress(() -> {
            host.game().flushOptions();
            host.runAsync(() -> {
                store.copyFrom(optionsFile);
                return null;
            }, (ignored, error) -> status.show(
                    error == null ? StatusLine.Kind.SUCCESS : StatusLine.Kind.ERROR,
                    error == null ? Text.translatable("mymod.saved", "Saved")
                                  : Text.translatable("mymod.save.failed", "Couldn't save")));
        })
        .build();

Load a copy and apply it#

Write the file off the main thread, then apply it in onDone and report what needs a restart:

host.runAsync(() -> {
    store.copyTo(optionsFile);
    return null;
}, (ignored, error) -> {
    if (error != null) {
        status.show(StatusLine.Kind.ERROR, Text.translatable("mymod.load.failed", "Couldn't load"));
        return;
    }
    ReloadResult r = host.game().reloadOptions();
    if (r.needsRestart()) {
        status.show(StatusLine.Kind.WARNING, Text.translatable("mymod.restart", "Restart to apply: %s",
                String.join(", ", r.restartOptions())));
    } else {
        status.show(StatusLine.Kind.SUCCESS, Text.translatable("mymod.loaded", "Loaded"));
    }
});

ReloadResult.restartOptions() is a set of options.txt keys, such as fullscreenResolution. When nothing could be applied, it holds options.txt itself.

Outside a menu#

To make the game re-read options.txt from anywhere, for example a mod that restores options at startup, use the static call:

boolean taken = MultiversionUi.reloadGameOptions();

Test it#

dev.xichil.mvui.fake.FakeGame, from the API's test fixtures, is the GameBridge of FakeHost. It counts calls and lets you choose what they return:

FakeGame game = new FakeGame()
        .inWorld(true)
        .reloadResult(ReloadResult.needsRestart("fullscreenResolution"));
FakeHost host = new FakeHost(game);
host.open(menu.create(host));
host.click("load");
assertEquals(1, game.reloads());

Next steps#