Add Advancement API beta
This commit is contained in:
1 parent
e5d9a8663c
commit
24b385d3f7
10 files changed
+666
-24
No files matched your search
@@ -1,3 +0,0 @@
|
||||
[submodule "libs/Utilities-OG"]
|
||||
path = libs/Utilities-OG
|
||||
url = https://github.com/true-og/Utilities-OG
|
||||
@@ -15,6 +15,93 @@ See [Template-OG](https://github.com/true-og/Template-OG) or [KotlinTemplate-OG]
|
||||
[SudoSigns-OG](https://github.com/true-og/sudosigns-og)
|
||||
[TheHerobrine-OG](https://github.com/true-og/TheHerobrine-OG/)
|
||||
|
||||
## Core GUI API
|
||||
|
||||
Extend `GUIBase`, add `GUIItem`s in `setupItems()`, and call `open(false)`.
|
||||
|
||||
Java:
|
||||
|
||||
```java
|
||||
public final class ExampleMenu extends GUIBase {
|
||||
public ExampleMenu(JavaPlugin plugin, Player player) {
|
||||
super(plugin, player, "&6Example Menu", 27, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupItems() {
|
||||
GUIItem item = new GUIItem(Material.DIAMOND, 1, "&bReward");
|
||||
item.lore(List.of(UtilitiesOG.trueogExpand("&7Click to claim.")));
|
||||
item.button(new GUIButton() {
|
||||
@Override public boolean leftClick() { getPlayer().sendMessage("Claimed"); return true; }
|
||||
@Override public boolean leftClickShift() { return leftClick(); }
|
||||
@Override public boolean rightClick() { return leftClick(); }
|
||||
@Override public boolean rightClickShift() { return leftClick(); }
|
||||
});
|
||||
|
||||
addItem(13, item);
|
||||
}
|
||||
}
|
||||
|
||||
new ExampleMenu(plugin, player).open(false);
|
||||
```
|
||||
|
||||
Kotlin:
|
||||
|
||||
```kotlin
|
||||
class ExampleMenu(plugin: JavaPlugin, player: Player) : GUIBase(plugin, player, "&6Example Menu", 27, true) {
|
||||
override fun setupItems() {
|
||||
val item = GUIItem(Material.DIAMOND, 1, "&bReward")
|
||||
item.lore(listOf(UtilitiesOG.trueogExpand("&7Click to claim.")))
|
||||
item.button(object : GUIButton {
|
||||
override fun leftClick(): Boolean { player.sendMessage("Claimed"); return true }
|
||||
override fun leftClickShift() = leftClick()
|
||||
override fun rightClick() = leftClick()
|
||||
override fun rightClickShift() = leftClick()
|
||||
})
|
||||
|
||||
addItem(13, item)
|
||||
}
|
||||
}
|
||||
|
||||
ExampleMenu(plugin, player).open(false)
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
* `fillEmpty = true` fills unused slots with gray glass panes.
|
||||
* GUI item clicks are cancelled automatically.
|
||||
* A `GUIButton` method should return `true` when the click was handled.
|
||||
* Non-button items can call `item.playErrorSound(false)` to make clicks silent.
|
||||
|
||||
## Advancement API
|
||||
|
||||
`AdvancementMenu` displays an ordered list of read-only advancement items in a paginated inventory. Items are placed
|
||||
from the top-left slot downward through each column, reserving the bottom row for previous, close, and next controls.
|
||||
|
||||
Java:
|
||||
|
||||
```java
|
||||
Map<String, List<String>> values = new LinkedHashMap<>();
|
||||
values.put("&cHome Two", List.of("&7Unlock the second home.", "&eRequired: &fWin 1 duel"));
|
||||
values.put("&cHome Three", List.of("&7Unlock the third home.", "&eRequired: &fBuild a full beacon"));
|
||||
|
||||
AdvancementMenu.open(plugin, player, "&6Advancements", values);
|
||||
```
|
||||
|
||||
Kotlin:
|
||||
|
||||
```kotlin
|
||||
val values = linkedMapOf(
|
||||
"&cHome Two" to listOf("&7Unlock the second home.", "&eRequired: &fWin 1 duel"),
|
||||
"&cHome Three" to listOf("&7Unlock the third home.", "&eRequired: &fBuild a full beacon"),
|
||||
)
|
||||
|
||||
AdvancementMenu.open(plugin, player, "&6Advancements", values)
|
||||
```
|
||||
|
||||
The simple map API displays every entry as `RED_WOOL`. Use an ordered map, such as `LinkedHashMap`, when item order
|
||||
matters. Callers that need custom state or icons can still pass `List<AdvancementItem>` directly.
|
||||
|
||||
## License
|
||||
|
||||
Public domain.
|
||||
@@ -56,7 +56,6 @@ repositories {
|
||||
dependencies {
|
||||
compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT") // Declare Purpur API version to be packaged.
|
||||
compileOnly("io.github.miniplaceholders:miniplaceholders-api:2.2.3") // Import MiniPlaceholders API.
|
||||
compileOnlyApi(project(":libs:Utilities-OG")) // Import TrueOG Network Utilities-OG Java API (from source).
|
||||
}
|
||||
|
||||
/* ---------------------- Reproducible jars ---------------------------- */
|
||||
|
||||
Submodule libs/Utilities-OG deleted from 3e26fb1a84.
@@ -5,7 +5,6 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
@@ -28,7 +27,6 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
@@ -162,17 +160,15 @@ public abstract class GUIBase implements Listener {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
final Inventory inventory = ((HumanEntity) player).getOpenInventory().getTopInventory();
|
||||
final Component inventoryTitle = player.getOpenInventory().title();
|
||||
final String inventoryTitleText = inventoryTitle.examinableName();
|
||||
if (!StringUtils.equalsIgnoreCase(inventoryTitleText, inventoryName)) {
|
||||
final Inventory openInventory = ((HumanEntity) player).getOpenInventory().getTopInventory();
|
||||
if (openInventory != inventory) {
|
||||
|
||||
cancel();
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
inventory.clear();
|
||||
openInventory.clear();
|
||||
inventoryContents.clear();
|
||||
setupItems();
|
||||
int counter = 0;
|
||||
@@ -194,18 +190,18 @@ public abstract class GUIBase implements Listener {
|
||||
|
||||
itemErrors.remove(i.getKey());
|
||||
itemTimings.remove(i.getKey());
|
||||
inventory.setItem(i.getKey(), i.getValue().build());
|
||||
openInventory.setItem(i.getKey(), i.getValue().build());
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
inventory.setItem(i.getKey(), error.build());
|
||||
openInventory.setItem(i.getKey(), error.build());
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
inventory.setItem(i.getKey(), i.getValue().build());
|
||||
openInventory.setItem(i.getKey(), i.getValue().build());
|
||||
|
||||
}
|
||||
|
||||
@@ -213,9 +209,9 @@ public abstract class GUIBase implements Listener {
|
||||
|
||||
for (int i = 0; i < inventorySize; i++) {
|
||||
|
||||
if (inventory.getItem(i) == null) {
|
||||
if (openInventory.getItem(i) == null) {
|
||||
|
||||
inventory.setItem(i, fillSlot());
|
||||
openInventory.setItem(i, fillSlot());
|
||||
|
||||
}
|
||||
|
||||
@@ -368,10 +364,7 @@ public abstract class GUIBase implements Listener {
|
||||
public void close(InventoryCloseEvent event) {
|
||||
|
||||
final Player closer = (Player) event.getPlayer();
|
||||
final Component inventoryTitle = player.getOpenInventory().title();
|
||||
final String inventoryTitleText = inventoryTitle.examinableName();
|
||||
final boolean condition = StringUtils.equalsIgnoreCase(inventoryTitleText, inventoryName) && isOpen
|
||||
&& closer == player;
|
||||
final boolean condition = event.getInventory() == inventory && isOpen && closer == player;
|
||||
if (!condition) {
|
||||
|
||||
return;
|
||||
@@ -429,4 +422,4 @@ public abstract class GUIBase implements Listener {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.trueog.utilitiesog.UtilitiesOG;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
@Accessors(fluent = true)
|
||||
public class GUIItem {
|
||||
@@ -149,7 +149,8 @@ public class GUIItem {
|
||||
public ItemStack build() {
|
||||
|
||||
final ItemStack i;
|
||||
final TextComponent displayNameTextComponent = UtilitiesOG.trueogExpand(displayName);
|
||||
final TextComponent displayNameTextComponent = LegacyComponentSerializer.legacyAmpersand()
|
||||
.deserialize(displayName);
|
||||
final List<TextComponent> loreTextComponent = lore;
|
||||
try {
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package net.trueog.gxui.advancements;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
// One requirement entry beneath an advancement. Built by AdvancementMenu.Builder.
|
||||
final class AdvancementAttribute {
|
||||
|
||||
private final String name;
|
||||
private final boolean done;
|
||||
private final long current;
|
||||
private final long target;
|
||||
private final boolean hasProgress;
|
||||
|
||||
AdvancementAttribute(String name, boolean done) {
|
||||
|
||||
this.name = Objects.requireNonNull(name, "name");
|
||||
this.done = done;
|
||||
this.current = 0L;
|
||||
this.target = 0L;
|
||||
this.hasProgress = false;
|
||||
|
||||
}
|
||||
|
||||
AdvancementAttribute(String name, long current, long target) {
|
||||
|
||||
this.name = Objects.requireNonNull(name, "name");
|
||||
this.current = current;
|
||||
this.target = target;
|
||||
this.done = current >= target;
|
||||
this.hasProgress = true;
|
||||
|
||||
}
|
||||
|
||||
String getName() {
|
||||
|
||||
return name;
|
||||
|
||||
}
|
||||
|
||||
boolean isDone() {
|
||||
|
||||
return done;
|
||||
|
||||
}
|
||||
|
||||
boolean hasProgress() {
|
||||
|
||||
return hasProgress;
|
||||
|
||||
}
|
||||
|
||||
long getCurrent() {
|
||||
|
||||
return current;
|
||||
|
||||
}
|
||||
|
||||
long getTarget() {
|
||||
|
||||
return target;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package net.trueog.gxui.advancements;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
record AdvancementItem(String name, AdvancementState state, List<AdvancementAttribute> attributes,
|
||||
List<String> footer)
|
||||
{
|
||||
|
||||
AdvancementItem(String name, AdvancementState state, List<AdvancementAttribute> attributes, List<String> footer) {
|
||||
|
||||
this.name = Objects.requireNonNull(name, "name");
|
||||
this.state = Objects.requireNonNull(state, "state");
|
||||
this.attributes = List.copyOf(Objects.requireNonNull(attributes, "attributes"));
|
||||
this.footer = List.copyOf(Objects.requireNonNull(footer, "footer"));
|
||||
|
||||
}
|
||||
|
||||
String getName() {
|
||||
|
||||
return name;
|
||||
|
||||
}
|
||||
|
||||
AdvancementState getState() {
|
||||
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
List<AdvancementAttribute> getAttributes() {
|
||||
|
||||
return attributes;
|
||||
|
||||
}
|
||||
|
||||
List<String> getFooter() {
|
||||
|
||||
return footer;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,418 @@
|
||||
package net.trueog.gxui.advancements;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import net.trueog.gxui.GUIBase;
|
||||
import net.trueog.gxui.GUIButton;
|
||||
import net.trueog.gxui.GUIItem;
|
||||
|
||||
// Read-only paginated inventory for advancement-style progress displays.
|
||||
// Construct with AdvancementMenu.builder(plugin, player, title). Run open() to display.
|
||||
public class AdvancementMenu extends GUIBase {
|
||||
|
||||
public static final int INVENTORY_SIZE = 54;
|
||||
public static final int ADVANCEMENTS_PER_PAGE = 45;
|
||||
public static final int PREVIOUS_PAGE_SLOT = 45;
|
||||
public static final int CLOSE_SLOT = 49;
|
||||
public static final int NEXT_PAGE_SLOT = 53;
|
||||
|
||||
private static final List<Integer> ADVANCEMENT_SLOTS = createAdvancementSlots();
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final String baseTitle;
|
||||
private final List<AdvancementItem> advancementItems;
|
||||
private final int page;
|
||||
|
||||
private AdvancementMenu(JavaPlugin plugin, Player player, String inventoryName,
|
||||
List<AdvancementItem> advancementItems, int page)
|
||||
{
|
||||
|
||||
super(plugin, player, buildInventoryName(inventoryName, advancementItems, page), INVENTORY_SIZE, true);
|
||||
this.plugin = plugin;
|
||||
this.baseTitle = inventoryName;
|
||||
this.advancementItems = advancementItems;
|
||||
this.page = normalizePage(page, getTotalPages(advancementItems.size()));
|
||||
|
||||
}
|
||||
|
||||
public static Builder builder(JavaPlugin plugin, Player player, String inventoryName) {
|
||||
|
||||
return new Builder(plugin, player, inventoryName);
|
||||
|
||||
}
|
||||
|
||||
public int getPage() {
|
||||
|
||||
return page;
|
||||
|
||||
}
|
||||
|
||||
public int getTotalPages() {
|
||||
|
||||
return getTotalPages(advancementItems.size());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupItems() {
|
||||
|
||||
final int firstAdvancement = page * ADVANCEMENTS_PER_PAGE;
|
||||
final int lastAdvancement = Math.min(firstAdvancement + ADVANCEMENTS_PER_PAGE, advancementItems.size());
|
||||
for (int advancementIndex = firstAdvancement; advancementIndex < lastAdvancement; advancementIndex++) {
|
||||
|
||||
final int pageIndex = advancementIndex - firstAdvancement;
|
||||
addItem(ADVANCEMENT_SLOTS.get(pageIndex), buildAdvancementItem(advancementItems.get(advancementIndex)));
|
||||
|
||||
}
|
||||
|
||||
if (page > 0) {
|
||||
|
||||
addItem(PREVIOUS_PAGE_SLOT, buildPageButton(Material.ARROW, "&ePrevious Page", page - 1));
|
||||
|
||||
}
|
||||
|
||||
addItem(CLOSE_SLOT, buildCloseButton());
|
||||
|
||||
if (page + 1 < getTotalPages()) {
|
||||
|
||||
addItem(NEXT_PAGE_SLOT, buildPageButton(Material.ARROW, "&eNext Page", page + 1));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private GUIItem buildAdvancementItem(AdvancementItem advancementItem) {
|
||||
|
||||
final AdvancementState state = advancementItem.getState();
|
||||
final String displayName = state.getColor() + advancementItem.getName();
|
||||
final GUIItem guiItem = new GUIItem(state.getDefaultMaterial(), 1, displayName);
|
||||
|
||||
guiItem.lore(toLoreComponents(buildLore(advancementItem)));
|
||||
guiItem.playErrorSound(false);
|
||||
|
||||
return guiItem;
|
||||
|
||||
}
|
||||
|
||||
private static List<String> buildLore(AdvancementItem advancementItem) {
|
||||
|
||||
final List<String> lore = new ArrayList<>();
|
||||
lore.add(advancementItem.getState().getStatusLine());
|
||||
|
||||
final List<AdvancementAttribute> attributes = advancementItem.getAttributes();
|
||||
if (!attributes.isEmpty()) {
|
||||
|
||||
lore.add("");
|
||||
lore.add("&7Requirements:");
|
||||
attributes.forEach(attribute -> lore.add(formatAttribute(attribute)));
|
||||
|
||||
}
|
||||
|
||||
final List<String> footer = advancementItem.getFooter();
|
||||
if (!footer.isEmpty()) {
|
||||
|
||||
lore.add("");
|
||||
lore.addAll(footer);
|
||||
|
||||
}
|
||||
|
||||
return lore;
|
||||
|
||||
}
|
||||
|
||||
private static String formatAttribute(AdvancementAttribute attribute) {
|
||||
|
||||
final String color = attribute.isDone() ? "&a" : "&c";
|
||||
if (attribute.hasProgress()) {
|
||||
|
||||
return color + attribute.getName() + ": &f" + attribute.getCurrent() + "&7/&f" + attribute.getTarget();
|
||||
|
||||
}
|
||||
|
||||
final String status = attribute.isDone() ? "Done" : "Not done";
|
||||
return color + attribute.getName() + ": &f" + status;
|
||||
|
||||
}
|
||||
|
||||
private GUIItem buildCloseButton() {
|
||||
|
||||
final GUIItem guiItem = new GUIItem(Material.BARRIER, 1, "&cClose");
|
||||
guiItem.playErrorSound(false);
|
||||
guiItem.button(createButton(() -> getPlayer().closeInventory()));
|
||||
|
||||
return guiItem;
|
||||
|
||||
}
|
||||
|
||||
private GUIItem buildPageButton(Material material, String displayName, int targetPage) {
|
||||
|
||||
final GUIItem guiItem = new GUIItem(material, 1, displayName);
|
||||
guiItem.lore(toLoreComponents(List.of("&7Page " + (targetPage + 1) + " of " + getTotalPages())));
|
||||
guiItem.playErrorSound(false);
|
||||
guiItem.button(createButton(() -> openPage(targetPage)));
|
||||
|
||||
return guiItem;
|
||||
|
||||
}
|
||||
|
||||
private void openPage(int targetPage) {
|
||||
|
||||
new AdvancementMenu(plugin, getPlayer(), baseTitle, advancementItems, targetPage).open(false);
|
||||
|
||||
}
|
||||
|
||||
private GUIButton createButton(Runnable clickHandler) {
|
||||
|
||||
return new GUIButton() {
|
||||
|
||||
@Override
|
||||
public boolean leftClick() {
|
||||
|
||||
return handleClick();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean leftClickShift() {
|
||||
|
||||
return handleClick();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean rightClick() {
|
||||
|
||||
return handleClick();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean rightClickShift() {
|
||||
|
||||
return handleClick();
|
||||
|
||||
}
|
||||
|
||||
private boolean handleClick() {
|
||||
|
||||
clickHandler.run();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private static final LegacyComponentSerializer LEGACY = LegacyComponentSerializer.legacyAmpersand();
|
||||
|
||||
private List<TextComponent> toLoreComponents(List<String> lore) {
|
||||
|
||||
return lore.stream().map(AdvancementMenu::toTextComponent).toList();
|
||||
|
||||
}
|
||||
|
||||
private static TextComponent toTextComponent(String line) {
|
||||
|
||||
final Component component = LEGACY.deserialize(line);
|
||||
// LegacyComponentSerializer always produces a TextComponent root.
|
||||
return (TextComponent) component;
|
||||
|
||||
}
|
||||
|
||||
private static String buildInventoryName(String inventoryName, List<AdvancementItem> advancementItems, int page) {
|
||||
|
||||
Objects.requireNonNull(inventoryName, "inventoryName");
|
||||
final int totalPages = getTotalPages(Objects.requireNonNull(advancementItems, "advancementItems").size());
|
||||
if (totalPages == 1) {
|
||||
|
||||
return inventoryName;
|
||||
|
||||
}
|
||||
|
||||
final int normalizedPage = normalizePage(page, totalPages);
|
||||
return inventoryName + " &7(" + (normalizedPage + 1) + "/" + totalPages + ")";
|
||||
|
||||
}
|
||||
|
||||
private static int getTotalPages(int itemCount) {
|
||||
|
||||
return Math.max(1, (int) Math.ceil((double) itemCount / ADVANCEMENTS_PER_PAGE));
|
||||
|
||||
}
|
||||
|
||||
private static int normalizePage(int page, int totalPages) {
|
||||
|
||||
if (page < 0) {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
return page >= totalPages ? totalPages - 1 : page;
|
||||
|
||||
}
|
||||
|
||||
private static List<Integer> createAdvancementSlots() {
|
||||
|
||||
final List<Integer> slots = new ArrayList<>(ADVANCEMENTS_PER_PAGE);
|
||||
// Column-first ordering matches "start top-left and go down".
|
||||
for (int column = 0; column < 9; column++) {
|
||||
|
||||
for (int row = 0; row < 5; row++) {
|
||||
|
||||
slots.add(row * 9 + column);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(slots);
|
||||
|
||||
}
|
||||
|
||||
private static int parsePage(String[] args) {
|
||||
|
||||
if (args == null || args.length == 0) {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
return Math.max(0, Integer.parseInt(args[0]) - 1);
|
||||
|
||||
} catch (NumberFormatException ignored) {
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Fluent builder for an AdvancementMenu. Plugins only depend on this class,
|
||||
// AdvancementState, and Java primitives.
|
||||
public static final class Builder {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final Player player;
|
||||
private final String title;
|
||||
private final List<AdvancementItem> items = new ArrayList<>();
|
||||
|
||||
private String pendingName;
|
||||
private AdvancementState pendingState;
|
||||
private List<AdvancementAttribute> pendingAttributes;
|
||||
private List<String> pendingFooter;
|
||||
|
||||
private Builder(JavaPlugin plugin, Player player, String title) {
|
||||
|
||||
this.plugin = Objects.requireNonNull(plugin, "plugin");
|
||||
this.player = Objects.requireNonNull(player, "player");
|
||||
this.title = Objects.requireNonNull(title, "title");
|
||||
|
||||
}
|
||||
|
||||
// Start a new advancement slot. Following attribute/footer calls attach to this
|
||||
// one.
|
||||
public Builder add(String name, AdvancementState state) {
|
||||
|
||||
flushPending();
|
||||
this.pendingName = Objects.requireNonNull(name, "name");
|
||||
this.pendingState = Objects.requireNonNull(state, "state");
|
||||
this.pendingAttributes = new ArrayList<>();
|
||||
this.pendingFooter = new ArrayList<>();
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
// Add a progress-counter attribute (e.g. 250/1000). Coloured by current >=
|
||||
// target.
|
||||
public Builder progress(String name, long current, long target) {
|
||||
|
||||
requirePending();
|
||||
pendingAttributes.add(new AdvancementAttribute(name, current, target));
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
// Add a boolean attribute.
|
||||
public Builder bool(String name, boolean done) {
|
||||
|
||||
requirePending();
|
||||
pendingAttributes.add(new AdvancementAttribute(name, done));
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
// Append free-form footer lines (formatting allowed).
|
||||
public Builder footer(String... lines) {
|
||||
|
||||
requirePending();
|
||||
Collections.addAll(pendingFooter, lines);
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
// Open at the page parsed from command args (e.g. "/cmd 2").
|
||||
public AdvancementMenu open(String[] args) {
|
||||
|
||||
return openAt(parsePage(args));
|
||||
|
||||
}
|
||||
|
||||
// Open at page 1.
|
||||
public AdvancementMenu open() {
|
||||
|
||||
return openAt(0);
|
||||
|
||||
}
|
||||
|
||||
private AdvancementMenu openAt(int page) {
|
||||
|
||||
flushPending();
|
||||
final AdvancementMenu menu = new AdvancementMenu(plugin, player, title, List.copyOf(items), page);
|
||||
menu.open(false);
|
||||
return menu;
|
||||
|
||||
}
|
||||
|
||||
private void requirePending() {
|
||||
|
||||
if (pendingName == null) {
|
||||
|
||||
throw new IllegalStateException("Call add(name, state) before adding attributes or footer lines");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void flushPending() {
|
||||
|
||||
if (pendingName == null) {
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
items.add(new AdvancementItem(pendingName, pendingState, pendingAttributes, pendingFooter));
|
||||
pendingName = null;
|
||||
pendingState = null;
|
||||
pendingAttributes = null;
|
||||
pendingFooter = null;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.trueog.gxui.advancements;
|
||||
|
||||
import org.bukkit.Material;
|
||||
|
||||
// Visual state of an advancement slot. Drives material colour and lore status line.
|
||||
public enum AdvancementState {
|
||||
|
||||
COMPLETE(Material.LIME_WOOL, "&a", "&aCompleted"), IN_PROGRESS(Material.YELLOW_WOOL, "&e", "&eIn Progress"),
|
||||
LOCKED(Material.GRAY_WOOL, "&7", "&7Locked");
|
||||
|
||||
private final Material defaultMaterial;
|
||||
private final String color;
|
||||
private final String statusLine;
|
||||
|
||||
AdvancementState(Material defaultMaterial, String color, String statusLine) {
|
||||
|
||||
this.defaultMaterial = defaultMaterial;
|
||||
this.color = color;
|
||||
this.statusLine = statusLine;
|
||||
|
||||
}
|
||||
|
||||
public Material getDefaultMaterial() {
|
||||
|
||||
return defaultMaterial;
|
||||
|
||||
}
|
||||
|
||||
String getColor() {
|
||||
|
||||
return color;
|
||||
|
||||
}
|
||||
|
||||
String getStatusLine() {
|
||||
|
||||
return statusLine;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user