Skip to content

NivarisMC/DrivenForms

Repository files navigation

DrivenForms

A Data-Driven UI library for AllayMC Showcase

Uses Minecraft Bedrock's native data-driven screen system (ClientboundDataDrivenUIShowScreenPacket / ClientboundDataStorePacket) to render custom forms with real-time callbacks — element changes fire immediately rather than waiting for a submit button.

[WARNING] Beta — does not implement every vanilla DDUI feature.

Requirements

  • AllayMC server (API 0.28.0)
  • Java 21

Installation

Add DrivenForms as a dependency in your plugin's build.gradle.kts:

repositories {
    mavenCentral()
    maven("https://repo.opencollab.dev/maven-releases/")
    maven("https://repo.opencollab.dev/maven-snapshots/")
}

dependencies {
    implementation(files("libs/DrivenForms-1.0.0.jar"))
    // or publish to a local maven repo and use:
    // implementation(group = "org.nivaris.drivenforms", name = "DrivenForms", version = "0.1.0")
}

Quick Start

Register the handler in your plugin's onEnable():

import org.allaymc.api.plugin.Plugin;
import org.nivaris.drivenforms.DataDrivenUIHandler;

public class MyPlugin extends Plugin {
    @Override
    public void onEnable() {
        if (!DataDrivenUIHandler.isRegistered()) {
            DataDrivenUIHandler.register(this);
        }
    }
}

Then send a UI to any player:

import org.nivaris.drivenforms.CustomForm;
import org.allaymc.api.player.Player;

CustomForm.create("Greeting")
    .label("Hello, world!")
    .send(player);

CustomForm

A scrollable form with multiple element types. Callbacks fire in real time as the player interacts.

Methods

Method Signature Description
label (String text) Read-only text
spacer () Vertical spacing
divider () Horizontal separator
textField (String label, String default, Consumer<String> onChange) Text input
textField (String label, String default, Consumer<String> onChange, String description) Text input with description
toggle (String label, boolean default, Consumer<Boolean> onToggle) On/off switch
dropdown (String label, List<String> options, int defaultIndex, Consumer<Integer> onSelect) Dropdown menu
slider (String label, float default, float min, float max, float step, Consumer<Float> onChange) Numeric slider
slider (String label, float default, float min, float max, float step, Consumer<Float> onChange, String description) Slider with description
button (String label, Runnable onClick) Button (closes form by default)
button (String label, Runnable onClick, boolean closeOnClick) Button with configurable auto-close
withCloseButton () Adds a close button to the form
onCloseButtonClicked (Function<Object, Boolean> onClick) Handler for close button click
whenClosed (Consumer<Integer> handler) Fires when form closes (receives CLOSE_REASON_*)
send (Player player) Display the form

Example

CustomForm.create("Settings")
    .label("Customize your preferences")
    .textField("Name", "Steve", name ->
        player.sendMessage("Name: " + name)
    )
    .toggle("Notifications", true, enabled ->
        player.sendMessage("Notifications: " + (enabled ? "ON" : "OFF"))
    )
    .dropdown("Color", List.of("Red", "Blue", "Green"), 0, index ->
        player.sendMessage("Color index: " + index)
    )
    .slider("Volume", 50, 0, 100, 1, value ->
        player.sendMessage("Volume: " + value)
    )
    .divider()
    .button("Save", () ->
        player.sendMessage("Saved!")
    )
    .whenClosed(reason ->
        player.sendMessage("Form closed, reason: " + reason)
    )
    .send(player);

MessageBox

A simple two-button dialog.

Methods

Method Signature Description
button1 (String label) Left button (returns 1 on close)
button1 (String label, String tooltip) Left button with tooltip
button2 (String label) Right button (returns 2 on close)
button2 (String label, String tooltip) Right button with tooltip
whenClosed (Consumer<Integer> handler) Fires with selection (1, 2, or 0)
send (Player player) Display the dialog

Example

MessageBox.create("Confirm", "Are you sure?")
    .button1("Yes", "I am sure")
    .button2("No")
    .whenClosed(selection -> {
        if (selection == 1) {
            player.sendMessage("Confirmed!");
        } else {
            player.sendMessage("Cancelled.");
        }
    })
    .send(player);

Close Reasons

The integer passed to whenClosed maps to these constants in DataDrivenUIHandler:

Value Constant Meaning
0 CLOSE_REASON_PROGRAMMATIC Closed by server (button click, etc.)
1 CLOSE_REASON_PROGRAMMATIC_ALL Closed by server (all forms)
2 CLOSE_REASON_CLIENT_CLOSED Player closed the form manually
3 CLOSE_REASON_BUSY Player was busy
4 CLOSE_REASON_INVALID Form was invalid

Build

./gradlew shadowJar --no-daemon

The plugin includes a built-in showcase command (/drivenforms or /df). Run it in-game to see all elements in action:

  • /drivenforms — opens the CustomForm demo
  • /drivenforms customform — opens the CustomForm demo
  • /drivenforms messagebox — opens the MessageBox demo

Default permission: operators only.

About

A Data-Driven UI library for AllayMC

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages