This is the Official Documentation for the CrazyAdvancementsAPI
This document is supposed to serve as a place to start for Newcomers
If you have any further questions or requests, feel free to join the Community on the Official Discord Server

Getting Started
Creating Advancements

Creating the Display

To create an Advancement you need to create your Display first. The display will contain information like Icon, Title, Description, Frame, Visibility Options, Background Texture and Positioning. So let's create variables for the required options

First off, lets look at the Icon

ItemStack icon = new ItemStack(Material.STONE);

As you can see, the Icon is just a regular spigot ItemStack. However you can also parse a Material to the constructor in case you don't need to apply things like Enchantments or SkullOwners

Next up, lets look at the Title and Description. They are of type JSONMessage which takes a BaseComponent as a parameter

JSONMessage title = new JSONMessage(new TextComponent("Title")); JSONMessage description = new JSONMessage(new TextComponent("Description"));

If you want to use colors ore other formatting, look at the Spigot page on the Chat Component API

Next on our list is a fairly straightforward item: the Frame
It sets the outline that will be visible in the Advancement Screen and will decide which message will be displayed when you get the Advancement in the Toast Notification and play a Sound if it's a Challenge

AdvancementFrame frame = AdvancementFrame.TASK;

There are 3 options to choose from: TASK, GOAL and CHALLENGE

Last but not least we have the Visibility. You can either select from one of the pre-made Visibilities or implement your own rules

AdvancementVisibility visibility = AdvancementVisibility.ALWAYS;

There are 4 Visiblities included in the API:
ALWAYS: Is always shown
PARENT_GRANTED: Only shown, when parent is granted or any child is granted
VANILLA: Only shown, when parent of parent is granted or any child is granted
HIDDEN: Only shown when granted or any child is granted

If you want to implement your own Rules, create a new instance of AdvancementVisibility or extend it
Keep in mind that you might need to update visibility in your Managers if your Visibility Rules rely on something else than an Advancement's Granted Status or an Advancement that is in a different tab and/or in a different Manager

new AdvancementVisibility() { @Override public boolean isVisible(Player player, Advancement advancement) { if(advancement.isGranted(player)) return true; Advancement parent = advancement.getParent(); return parent == null || parent.isGranted(player); } };

Now that we have the required parameters ready, let's create the Display

ItemStack icon = new ItemStack(Material.STONE); JSONMessage title = new JSONMessage(new TextComponent("Title")); JSONMessage description = new JSONMessage(new TextComponent("Description")); AdvancementFrame frame = AdvancementFrame.TASK; AdvancementVisibility visibility = AdvancementVisibility.ALWAYS; AdvancementDisplay display = new AdvancementDisplay(icon, title, description, frame, visibility);

Additional Display Options

First off, we have the Background Texture. It only has a purpose for Root Advancements (Advancements that define an Advancement Tab). The Background Texture is a direct path to the Texture File you want the player to see.

display.setBackgroundTexture("textures/block/yellow_concrete.png");

Next up, you should also position your Advancement correctly. You can set a position Origin which will be the Advancement your Advancement will be relative to. If you don't specify an Origin, the Root Advancement of the Tab will be used as an Origin. You then set the relative coordinates (float values).

display.setPositionOrigin(parent); display.setX(1); display.setY(1.5);

Creating the Advancement

Now that we have created our Display, we can move on to creating the Advancement itself. Advancements take a parent, a name, a display and a list of flags as parameters. You can ommit the parent or set it to null to make the Advancement create a new tab. You may also ommit the Flags if you don't want to apply any.

Advancement rootAdvancement = new Advancement(new NameKey("your_namespace", "advancement_name"), display);
Advancement advancement = new Advancement(parentAdvancement, new NameKey("your_namespace", "different_advancement_name"), display);
Advancement advancement = new Advancement(parentAdvancement, new NameKey("your_namespace", "another_advancement_name"), display, AdvancementFlag.SHOW_TOAST, AdvancementFlag.DISPLAY_MESSAGE);

The Name is a unique identifier for your Advancement. You should only have a couple of different namespaces for your own project to prevent other projects from having the same namespace, so choose something unique.

The available Advancement Flags include:
SHOW_TOAST: Toast will be shown when Advancement is granted
DISPLAY_MESSAGE: Message will be displayed when someone gets an Advancement
SEND_WITH_HIDDEN_BOOLEAN: The Advancement will be sent with the hidden boolean set to true which makes it possible to create empty tabs when the Root Advancement has the hidden boolean and there are no children
TOAST_AND_MESSAGE: Shorthand for combining SHOW_TOAST and DISPLAY_MESSAGE

Additional Advancement Options

Now we have an Advancement that can either be granted or not, but you might want to have Advancements where multiple Criteria needs to be met. Thats why you can set the Criteria you want.

There are two types of Criteria:
- Criteria where a certain number needs to be reached
- Criteria where a list of requirements must be met

Lets look at the simpler one first: The Criteria where a certain number needs to be reached:

advancement.setCriteria(new Criteria(5));

As you might have guessed, this makes it so the target Number is 5

So let's move on to the more complicated one. For this one you have to pass the Constructor a String Array and a nested String Array. The first one lists all the names that you give your requirements. The second one is basically an AND group of OR groups.

advacnement.setCriteria(new Criteria(new String[] {"a", "b", "c"}, new String[][] {{"a", "b"}, {"c"}}););

The above example has 3 different actions but only two of them need to be completed. The Advancement will be granted if the Player has a and c and it will also be granted if the Player has b and c. Obviously it will also be granted if the Player meets all 3 requirements.

Advancement Rewards

You can also set a Reward to completing your Advancement.

advancement.setReward(new AdvancementReward() { @Override public void onGrant(Player player) { player.giveExp(1); } });
Advancement Managers

What are Advancement Managers?

A Advancement Manager is a place to group Advancements and Players together. Generally you want to group as many Advancements and players together as you can.
However there are practical applications like having one manager per Player or different Managers for different parts of your project.

Creating Advancement Managers

To create one, you just need to create a new instance of the AdvancementManager class. It takes a Name and optionally an array of Players you want to have in the Manager from the start.
The Name is used when you make your manager accessible and will also determine the Save Path if you use the Save Methods

AdvancementManager manager = new AdvancementManager(new NameKey("your_namespace", "manager_name"));
AdvancementManager manager = new AdvancementManager(new NameKey("your_namespace", "manager_name", player1, player2));

Instead of seperating the Players by comma, you may also just pass an Array as the second argument.

Managing Players

To add or remove Players simply call the respective methods.

manager.addPlayer(player);
manager.removePlayer(player);

Managing Advancements

To add or remove Advancements simply call the respective methods. Advancements can also be added or removed in bulk by passing an Array but always keep in mind that Advancements should always be added after their parent.

manager.addAdvancement(rootAdvancement, advancement);
manager.removeAdvancement(rootAdvancement, advancement);

If you changed your Advancement somehow, you may update it to the Player

manager.updateAdvancement(advancement);

Granting/Revoking Advancements

To Grant or Revoke Advancements you simply need to call the respective methods.

manager.grantAdvancement(player, advancement);
manager.revokeAdvancement(player, advancement);

These Methods will also return a Result which will tell you whether the operation left the Progress unchanged or changed
You may also grant or revoke specific criteria:

manager.grantCriteria(player, advancement, "a", "b");
manager.revokeCriteria(player, advancement, "a", "b");

The above examples will either grant or revoke the criteria names a and b. These methods will also return a Result, the Grant Method also has an additional Result Option that will tell you whether this operation has completed the Advancement.

Criteria Progress

If the Advancement's Criteria Type is NUMBER, you may also set the criteria progress.

manager.setCriteriaProgress(player, advancement, 3);

The above example will set the number the player has reached so far. This method also returns a Result which can be unchanged, changed, completed or invalid if the Criteria Type does not match.

Saving and Loading Progress

Saving and Loading Progress to the default Directory

If you only have one server where the Advancements apply this is the normal way to save Advancements as they will be stored within the plugin folder of the Server.
The nested directory depends on your Advancement Managers name
To save or load Data you have to pass a player and optionally a list of Advancements. If no Advancements are listed, all Advancements in the Manager will be saved/loaded, otherwise only the selected Advancements will be saved/loaded

manager.saveProgress(player);
manager.saveProgress(player, rootAdvancement, advancement);
manager.loadProgress(player);
manager.loadProgress(player, rootAdvancement, advancement);

Saving and Loading Progress in General

If you don't want to use the default Directory you can just create a new Save File Object and save the output json whereever you want.

manager.createNewSave(player);
manager.createNewSave(player, rootAdvancement, advancement);
SaveFile saveFile = SaveFile.fromJSON(""/*Insert the JSON String here*/); manager.loadProgress(player, saveFile);
Advancement Screen

Changing the selected Advancement Tab

You may change the Tab a Player is viewing. Note that this will not open the Advancement Screen but the player will still see the tab as soon as they open their Advancement Screen. The tab needs to be a NameKey. Just get the Name of the Root Advancement you want to set active and pass it.

CrazyAdvancements.setActiveTab(player, nameKey);

Getting the selected Advancement Tab

You may also get the current Tab. Keep in mind that this is a cached value and there may be certain situations where this value is incorrect.

CrazyAdvancementsAPI.getActiveTab(player);

Detecting Player Interaction

You can detect when a Player changes their current tab or when they close their Advancement Screen by listening to the respective events:
- AdvancementTabChangeEvent: Is called when a player changes their tab or when they open their Advancement Screen
- AdvancementScreenCloseEvent: Is called when a player closes their Advancement Screen

Toast Notifications

What are Toast Notifications?

Toast Notifications are Notifications that are displayed in the form of Advancement Toasts and don't require additional setup like Advancements need with their Advancement Manager.

Creating a Toast Notification

To create a new Toast Notification, you just have to create a new instance of the ToastNofication class.
It takes an icon, a description and a frame as arguments.

ToastNotification notification = new ToastNotification(icon, description, frame);

The icon is an ItemStack, the description is a JSONMessage and the Frame is an AdvancementFrame.
You then just have to send the notification to the player.

notification.send(player);
Advanced Features
Advancement Packets

Why should you send Advancement Packets yourself?

There are many reasons to send Packets yourself, i especially recommend it if you have a setup where you don't add advancements after the first add where it is very important that advancements and tabs remain in a specified order.
Because you control when packets are sent you have more control over when things update and you are able to prevent unexpected situations.

How do you send an Advancements Packet?

You just need to create a new instance of the AdvancementsPacket class. It takes 4 arguments: A player, a reset boolean, a list of advancements and a list of NameKeys.
If the reset boolean is set to true, the Player's Advancement Screen will be completely wiped before adding the Advancements in the advancement list.
The list of NameKeys describes a list of Advancements to remove
If you want to update progress, just include the Advancement in the advancement list

AdvancementsPacket packet = new AdvancementsPacket(player, false, advancements, removedAdvancements); packet.send();

Keep in mind that these packets will not trigger Toasts if Advancements get completed, for Toasts use Toast Notifications.

Granting/Revoking Advancements and Criteria

If you send Advancement Packets yourself, you shouldn't add the Advancements to a Manager, to manage Criteria, use the Advancement's Progress

AdvancementProgress progress = advancement.getProgress(player);
progress.grant();
progress.grantCriteria("a", "b");
progress.revoke();
progress.revokeCriteria("a", "b");
progress.setCriteriaProgress(3);