← Roadmap

EffectiveAdvancement

Advancements

Why

Your own advancement tab is a json datapack with criteria that almost never describe what you need. Usually you just want to "grant the advancement when the plugin decides".

EffectiveAdvancement is the visual layer only: tab, tree, toast, frame. No criteria — the plugin decides when by calling grant.

Minimal example

Root and child
object RootAdvancement : EffectiveAdvancement() {
    override fun getNamespacedData() = MyPlugin.instance to "root"
    override fun getParent() = null
    override fun getDisplay() = DisplayData(
        title = "My plugin",
        description = "Start",
        icon = IconData.fromItem(RubyItem.createItemStack()),
        frame = FrameType.TASK,
        background = "minecraft:textures/block/stone.png",
    )
    fun init() {}
}

object FirstRuby : EffectiveAdvancement() {
    override fun getNamespacedData() = MyPlugin.instance to "first_ruby"
    override fun getParent() = NamespacedKey(MyPlugin.instance, "root")
    override fun getDisplay() = DisplayData(
        title = "First ruby",
        description = "Find a ruby",
        icon = IconData(Material.EMERALD, hashMapOf()),
        frame = FrameType.GOAL,
    )
    fun init() {}
}

if (!FirstRuby.isGrantedTo(player)) FirstRuby.grant(player)

What to override

  • getNamespacedData() *
    Plugin and id
  • getParent() *
    Parent key or null for the root
  • getDisplay() *
    Title, description, icon, frame, background, toast, announce, hidden

* required

Pitfalls

  • The root needs a background — otherwise the tab has none.
  • The parent must be initialised — registration goes parent → child.
  • grant without checking isGrantedTo — the toast will not repeat, but there is no harm either.