Skip to content

Advancements

fren_gor edited this page Nov 22, 2021 · 33 revisions

Advancement Classes

UltimateAdvancementAPI provides various classes to work with advancements. The classes explained in this page are the most important ones, since they are part of the "core" of the API.

Advancement

The Advancement class is the parent class of every advancement. It provides the basic methods and fields to work with advancements. It is extended only by RootAdvancement and BaseAdvancement (which will be explained in the next paragraphs), no other class can extend it. This makes sure the only possible types of Advancements are those two. Every other advancement child class extends RootAdvancement or BaseAdvancement.

An advancement. An advancement.

Two example advancements

Let's go over what information Advancement class stores/provides (so, which properties every advancement has):

  • A unique namespaced key (i.e. "advtab1:myadvancement"), which identifies the advancement and is stored into an AdvancementKey instance. It is composed by a namespace (the part before colon :), which is the namespace of the advancement tab, and a key (the part after colon :). So, for example, an advancement with namespaced key "mytab:myadv" is an advancement inside "mytab" tab and with "myadv" key. Also, every advancement inside a tab must have a unique key. Note that the namespaced key is not visible to the players in the advancement GUI;
  • An AdvancementDisplay instance, which describes the advancement visual information like title, description, icon and position in the GUI;
  • The maximum progression. The progression is a positive integer which represents, as the name says, the progression of a player. The maximum progression is the times the advancement action should be done. For example, in order to have granted an advancement that requires to mine some stone and has a maximum progression of 10, the players have to mine 10 stone blocks. Visually, it is the white number in the image after the slash / (the number before it is the player progression):
    The advancement described before.

Also, Advancement class provides some useful methods:

  • isVisible(...) handles whether the advancement is visible to a player or not. It is the core of the Advancement Visibility System;
  • incrementProgression(...) increments the progression of a player by 1. If it was already greater or equals than max progression, it will do nothing;
  • giveReward(...) allows to customize the reward given to the player when the advancement is granted;
  • registerEvent(...) is a shortcut for advancementTab.getEventManager().register(...). So it is useful to register advancement-related events;
  • There are plenty of other useful methods, you can check them out on the Javadoc.

RootAdvancement

RootAdvancement is one of the two classes that directly extends Advancement. It represents the first advancement of a tab, so it's called "root". Therefore, there must be only one RootAdvancement per tab and it has no parent advancement.

Also, RootAdvancement must be always visible and contains the background texture path (i.e. "textures/block/stone.png" is the stone texture, for more information about how to find the correct path see this page). The background texture is used to determine which image should be placed as background in the advancement GUI:

A tab with a stone background.

A tab with a stone background

BaseAdvancement

BaseAdvancement is the other class that directly extends Advancement. It represents an advancement with a parent advancement. Every advancement other than the root must be a BaseAdvancement (or one of its subclasses), since the root is the only advancement without a parent.

Example

The following code creates an advancement tab with two advancements:

  • An always-granted RootAdvancement;
  • An advancement which requires to mine 10 blocks of stone and gives a stone brick as reward.
public class MainClass extends JavaPlugin {

    @Override
    public void onEnable() {
        UltimateAdvancementAPI api = UltimateAdvancementAPI.getInstance(this);

        AdvancementTab tab = api.createAdvancementTab("mytab");

        RootAdvancement root = new RootAdvancement(tab, "root", new AdvancementDisplay(Material.OAK_SAPLING, "Root Advancement", AdvancementFrameType.CHALLENGE, false, false, 0, 0), "textures/block/cobblestone.png");
        MineAdv pickaxe = new MineAdv("pickaxe", new AdvancementDisplay(Material.STONE, "Mine Stone", AdvancementFrameType.TASK, true, true, 1.5f, 0, "Mine 10 blocks of stone."), root, 10);
        tab.registerAdvancements(root, pickaxe);

        // Show tab on player loading. Also grants the root
        tab.getEventManager().register(tab, PlayerLoadingCompletedEvent.class, event -> {
            tab.showTab(event.getPlayer());
            tab.grantRootAdvancement(event.getPlayer());
        });
    }

    public static class MineAdv extends BaseAdvancement {

        public MineAdv(@NotNull String key, @NotNull AdvancementDisplay display, @NotNull Advancement parent, @Range(from = 1L, to = 2147483647L) int maxProgression) {
            super(key, display, parent, maxProgression);

            // Register the event via the tab's EventManager
            registerEvent(BlockBreakEvent.class, e -> {
                Player player = e.getPlayer();
                if (isVisible(player) && e.getBlock().getType() == Material.STONE) {
                    incrementProgression(player);
                }
            });
        }

        @Override
        public void giveReward(@NotNull Player player) {
            // This code is called when the advancement is granted
            player.getInventory().addItem(new ItemStack(Material.STONE_BRICKS));
        }
    }
}

Result:
The result.