From f25e696448113e8d40b1cb4e135a0069dd7e3a5d Mon Sep 17 00:00:00 2001 From: akastijn Date: Sun, 5 Apr 2026 17:06:17 +0200 Subject: [PATCH] Add prize management improvements and `/easter getprizes` subcommand --- .../com/alttd/easter/commands/Command.java | 2 + .../commands/subcommands/GetPrizes.java | 61 +++++++++++++++++++ .../easter/commands/subcommands/SetPrize.java | 28 ++++++++- .../java/com/alttd/easter/config/Config.java | 45 +++++++++++++- .../alttd/easter/gui/TurnInGuiManager.java | 13 +++- src/main/resources/plugin.yml | 3 + 6 files changed, 145 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/alttd/easter/commands/subcommands/GetPrizes.java diff --git a/src/main/java/com/alttd/easter/commands/Command.java b/src/main/java/com/alttd/easter/commands/Command.java index dac52a9..df1272f 100644 --- a/src/main/java/com/alttd/easter/commands/Command.java +++ b/src/main/java/com/alttd/easter/commands/Command.java @@ -4,6 +4,7 @@ import com.alttd.easter.Easter; import com.alttd.easter.commands.subcommands.Reload; import com.alttd.easter.commands.subcommands.SetPrize; import com.alttd.easter.commands.subcommands.SpawnEggs; +import com.alttd.easter.commands.subcommands.GetPrizes; import com.alttd.easter.config.Messages; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -38,6 +39,7 @@ public class Command implements CommandExecutor, TabExecutor { subCommands = List.of( new Reload(easter), new SetPrize(), + new GetPrizes(), new SpawnEggs() ); } diff --git a/src/main/java/com/alttd/easter/commands/subcommands/GetPrizes.java b/src/main/java/com/alttd/easter/commands/subcommands/GetPrizes.java new file mode 100644 index 0000000..1b667dd --- /dev/null +++ b/src/main/java/com/alttd/easter/commands/subcommands/GetPrizes.java @@ -0,0 +1,61 @@ +package com.alttd.easter.commands.subcommands; + +import com.alttd.easter.commands.SubCommand; +import com.alttd.easter.config.Config; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.command.CommandSender; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.List; + +public class GetPrizes extends SubCommand { + + @Override + public boolean onCommand(CommandSender commandSender, String[] args) { + List list = Config.PRIZES.LIST; + if (list.isEmpty()) { + commandSender.sendRichMessage("No prizes are configured."); + return true; + } + commandSender.sendRichMessage("Configured prizes (index : material - name)"); + for (int i = 0; i < list.size(); i++) { + ItemStack item = list.get(i); + String material = item.getType().name(); + String name = material; + ItemMeta meta = item.getItemMeta(); + if (meta != null && meta.hasDisplayName()) { + Component component = meta.displayName(); + if (component != null) { + name = PlainTextComponentSerializer.plainText().serialize(component); + } + } + commandSender.sendRichMessage(" : - ", + TagResolver.resolver( + Placeholder.parsed("index", String.valueOf(i)), + Placeholder.parsed("material", material), + Placeholder.parsed("name", name) + )); + } + return true; + } + + @Override + public String getName() { + return "getprizes"; + } + + @Override + public List getTabComplete(CommandSender commandSender, String[] args) { + return new ArrayList<>(); + } + + @Override + public String getHelpMessage() { + return "List configured prizes with index: /easter getprizes"; + } +} diff --git a/src/main/java/com/alttd/easter/commands/subcommands/SetPrize.java b/src/main/java/com/alttd/easter/commands/subcommands/SetPrize.java index cb0ea28..c6fda5d 100644 --- a/src/main/java/com/alttd/easter/commands/subcommands/SetPrize.java +++ b/src/main/java/com/alttd/easter/commands/subcommands/SetPrize.java @@ -7,6 +7,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; import java.util.List; public class SetPrize extends SubCommand { @@ -22,8 +23,23 @@ public class SetPrize extends SubCommand { player.sendRichMessage(Messages.SETPRIZE.EMPTY_HAND); return true; } - Config.PRIZES.addPrize(item.clone()); - player.sendRichMessage(Messages.SETPRIZE.SUCCESS); + // args[0] is the subcommand name. Optional args[1] may be index. + if (args.length >= 2) { + try { + int index = Integer.parseInt(args[1]); + if (index < 0 || index > Config.PRIZES.LIST.size()) { + player.sendRichMessage("Index out of bounds. Valid range: 0 - " + Config.PRIZES.LIST.size() + ""); + return true; + } + Config.PRIZES.setPrizeAt(index, item.clone()); + player.sendRichMessage("Set prize at index " + index + ""); + } catch (NumberFormatException e) { + player.sendRichMessage("Invalid index. Usage: /easter setprize [index]"); + } + } else { + Config.PRIZES.addPrize(item.clone()); + player.sendRichMessage(Messages.SETPRIZE.SUCCESS); + } return true; } @@ -34,6 +50,14 @@ public class SetPrize extends SubCommand { @Override public List getTabComplete(CommandSender commandSender, String[] args) { + if (args.length == 2) { + List res = new ArrayList<>(); + int maxIndex = Config.PRIZES.LIST.size(); + for (int i = 0; i <= maxIndex; i++) { + res.add(String.valueOf(i)); + } + return res; + } return List.of(); } diff --git a/src/main/java/com/alttd/easter/config/Config.java b/src/main/java/com/alttd/easter/config/Config.java index 7341cb7..7f3561d 100644 --- a/src/main/java/com/alttd/easter/config/Config.java +++ b/src/main/java/com/alttd/easter/config/Config.java @@ -69,6 +69,7 @@ public class Config extends AbstractConfig { public static class PRIZES { private static final String prefix = "prizes."; public static List LIST = new ArrayList<>(); + private static int NEXT_INDEX = 0; @SuppressWarnings("unused") private static void load() { @@ -83,18 +84,58 @@ public class Config extends AbstractConfig { } // ensure path exists config.yaml.addDefault(prefix + "list", LIST); + // load next index and clamp to range + NEXT_INDEX = config.getInt(prefix, "next-index", 0); + if (LIST.isEmpty()) { + NEXT_INDEX = 0; + } else if (NEXT_INDEX < 0 || NEXT_INDEX >= LIST.size()) { + NEXT_INDEX = NEXT_INDEX % LIST.size(); + if (NEXT_INDEX < 0) NEXT_INDEX += LIST.size(); + } + config.yaml.addDefault(prefix + "next-index", NEXT_INDEX); } public static void addPrize(ItemStack item) { LIST.add(item); config.set(prefix, "list", LIST); + // keep NEXT_INDEX valid + if (NEXT_INDEX < 0 || NEXT_INDEX >= LIST.size()) { + NEXT_INDEX = 0; + } + config.set(prefix, "next-index", NEXT_INDEX); } - public static ItemStack getRandomPrize() { + public static void setPrizeAt(int index, ItemStack item) { + if (index < 0 || index > LIST.size()) { + throw new IndexOutOfBoundsException("Index must be between 0 and " + LIST.size()); + } + if (index == LIST.size()) { + LIST.add(item); + } else { + LIST.set(index, item); + } + config.set(prefix, "list", LIST); + // adjust NEXT_INDEX if necessary if (LIST.isEmpty()) { + NEXT_INDEX = 0; + } else if (NEXT_INDEX >= LIST.size()) { + NEXT_INDEX = NEXT_INDEX % LIST.size(); + } + config.set(prefix, "next-index", NEXT_INDEX); + } + + public static ItemStack getNextPrize() { + if (LIST.isEmpty()) { + log.warn("[Easter] No prizes configured. Staff should configure prizes using /easter setprize."); return null; } - return LIST.get((int) (Math.random() * LIST.size())).clone(); + if (NEXT_INDEX < 0 || NEXT_INDEX >= LIST.size()) { + NEXT_INDEX = 0; + } + ItemStack prize = LIST.get(NEXT_INDEX).clone(); + NEXT_INDEX = (NEXT_INDEX + 1) % LIST.size(); + config.set(prefix, "next-index", NEXT_INDEX); + return prize; } } } diff --git a/src/main/java/com/alttd/easter/gui/TurnInGuiManager.java b/src/main/java/com/alttd/easter/gui/TurnInGuiManager.java index 318b0fb..8c5bc1b 100644 --- a/src/main/java/com/alttd/easter/gui/TurnInGuiManager.java +++ b/src/main/java/com/alttd/easter/gui/TurnInGuiManager.java @@ -10,7 +10,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.Bukkit; -import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -127,9 +126,17 @@ public class TurnInGuiManager implements Listener { int prevMilestones = prevTotal / 4; int newMilestones = newTotal / 4; int prizesToGive = Math.max(0, newMilestones - prevMilestones); + List prizeList = Config.PRIZES.LIST; for (int i = 0; i < prizesToGive; i++) { - var prize = Config.PRIZES.getRandomPrize(); - if (prize != null) { + int intendedIndex = prevMilestones + i; + if (prizeList.isEmpty()) { + log.warn("No prizes configured. Tried to give prize for intended index {}. Staff should configure prizes using /easter setprize.", intendedIndex); + } else { + int wrappedIndex = intendedIndex % prizeList.size(); + if (intendedIndex >= prizeList.size() || intendedIndex < 0) { + log.warn("Prize index overflow: intended index {} -> wrapped to {} (prize list size {}).", intendedIndex, wrappedIndex, prizeList.size()); + } + ItemStack prize = prizeList.get(wrappedIndex).clone(); player.getInventory().addItem(prize); } player.sendRichMessage(Messages.RABBIT.REWARD); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 30c7c32..24f3c4f 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -17,6 +17,9 @@ permissions: easter.setprize: description: Set the held item as a prize default: op + easter.getprizes: + description: List configured prizes with their index + default: op easter.spawneggs: description: Give yourself debug eggs default: op