-
Notifications
You must be signed in to change notification settings - Fork 0
Rubric Events
Rubric fires events on every reload and every programmatic set(...). Two subscription surfaces:
-
ConfigEventBus— per-pathChangeEvents. For code that cares about individual values. -
ReloadListener<S>— pair of(previous, current)POJOs after a reload. For code that reconciles state wholesale.
Fired for every path whose value differs between snapshots. Delivered on the platform main thread via Platform#mainThreadExecutor().
manager.getEvents().subscribe(event -> {
// event.path() — dotted path of the changed value
// event.oldValue()
// event.newValue()
// event.tier() — Reload.Tier for this entry
});Path-filtered convenience:
manager.getEvents().subscribe("display.opacity", event -> {
setOverlayOpacity((Double)event.newValue());
});Notes:
-
ChangeEvents are only fired when there's a diff between two snapshots. The initial load doesn't fire (there was no "previous"). - Programmatic edits (
manager.set(path, value)) go through the diff pipeline, so subscribers see them. - File-watch reloads (external editor saved the file) also fire the diff pipeline. Debounced by
io.fileWatchDebounceMillis. - Remote sync applies go through the same diff. Check
manager.originOf(path)if you need to distinguishLOCAL_EDITvsFROM_REMOTE.
Fired after every non-initial load(), on the main thread. Signature:
public interface ReloadListener<S> {
void onReload(S previous, S current);
}Usage:
manager.addReloadListener((previous, current) -> {
// Compare or wholesale-swap. Both instances are safe to read;
// the manager already updated `current` to be the live state.
});
// Later, if you're tearing down:
manager.removeReloadListener(listener);Reload listeners are useful when the config change requires a coordinated rebuild (rebuild a cached lookup table, tear down and re-open a GUI screen, reconcile in-flight requests). ChangeEvents are more precise; reload listeners are simpler when you don't care which value changed.
-
dispatch(changes)schedules everyChangeEventonto the main-thread executor as a separate task. Subscribers see events in path order per reload. -
fireReloadListeners(previous, current)also runs on the main thread. Ordering between theChangeEventbatch and theReloadListenerbatch is deterministic: change events run first, then reload listeners.
If a listener throws, Rubric catches the RuntimeException and continues — a faulty listener does not break the reload pipeline.
For code that only cares about a single value, ConfigValue<V> bundles read + subscribe:
final ConfigValue<Double> opacity = handle.value("display.opacity", Double.class);
opacity.subscribe(v -> setOverlayOpacity(v));
final double current = opacity.get();Under the hood, ConfigValue<V> reads the snapshot and attaches a path-filtered subscription to the event bus.
The event bus is per-manager, per-config. It does not cross configs, and it does not fire on other mods' configs. If two mods both subscribe to your config's event bus, they run independently and their order is by registration.
Rubric
Reference
Runtime
GUI
Help