Contextual API
Controlify's contextual system powers button guides and adaptive trigger effects. A contextual domain combines:
- a context object supplied at runtime;
- contributors which expose source facts, items, blocks, and entities;
- data-defined facts derived from those values;
- guide and trigger-effect rule sets evaluated against the resulting state.
For the resource formats, see Button Guides and Adaptive Trigger Effects.
Accessing built-in domains
Domains are available during Controlify pre-initialization:
private ContextualDomain<InGameContext> inGameDomain;
@Override
public void onControlifyPreInit(PreInitContext context) {
this.inGameDomain = context.contextualDomains().inGame();
}Controlify provides inGame() and container() domains.
Contributing state
A contributor writes values into named slots. Resource-pack facts and rules can then test those slots with Minecraft's standard predicates.
@Override
public void onControlifyPreInit(PreInitContext context) {
context.contextualDomains().inGame().registerContributor((inGame, sink) -> {
sink.contributeFact(
Identifier.fromNamespaceAndPath("example", "holding_wand"),
inGame.player().getMainHandItem().is(EXAMPLE_WAND)
);
sink.contributeItem(
Identifier.fromNamespaceAndPath("example", "focus_item"),
inGame.player().getOffhandItem()
);
});
}ContextualStateSink can contribute booleans with contributeFact, or values with contributeItem, contributeBlock, and contributeEntity. Contributors run in registration order; a later contribution to the same identifier replaces the earlier value.
Creating a domain
Custom domains use a context type implementing Context:
public record SpellContext(
ControllerEntity controller,
GuideVerbosity verbosity,
ItemStack selectedSpell
) implements Context {}Register the domain and its contributor during pre-initialization:
private ContextualDomain<SpellContext> spellDomain;
@Override
public void onControlifyPreInit(PreInitContext context) {
Identifier id = Identifier.fromNamespaceAndPath("example", "spells");
this.spellDomain = context.contextualDomains().register(id, (spell, sink) -> {
sink.contributeItem(
Identifier.fromNamespaceAndPath("example", "selected_spell"),
spell.selectedSpell()
);
});
}Controlify automatically registers the domain's fact resource loader. Rules for the domain use the same domain identifier in their asset path.
Using a guide instance
Create the instance once, update it when contextual state may have changed, and render it independently:
GuideInstance<SpellContext> guide = spellDomain.createGuideInstance(minecraft.font);
void tick(SpellContext context) {
guide.update(context);
}Use extractRenderState for HUD-style rendering, or renderable when adding the guide to a screen.
Using a trigger-effect instance
Trigger-effect instances are evaluated in the same way:
TriggerEffectInstance<SpellContext> effects = spellDomain.createTriggerEffectInstance();
void tick(SpellContext context) {
effects.update(context);
DualsenseTriggerEffect left = effects.getLeftTriggerEffect();
DualsenseTriggerEffect right = effects.getRightTriggerEffect();
}The trigger-effect API is experimental. A matching rule only applies when its for binding is currently bound to the corresponding controller trigger.