5 Commits
Author SHA1 Message Date
auto 41d0c94eed Add April Fools event listener for themed interactions
Introduced a new event listener, `AprilFoolsEvent`, to handle April Fools Day interactions with players. This includes good and bad actions that trigger messages, potion effects, and other behaviors based on player activities. Registered the new event listener in `PlayerUtils`.
2025-03-31 22:03:42 +02:00
auto 785a64b7e6 Refactor Glow command to optimize logic order.
Reorganized the "off" condition block to execute after clearing existing glow teams.
2025-03-24 21:26:56 +01:00
auto 7cfdc39f75 Refactor interact event handling and add trial spawner logic.
Renamed the event handler for clarity and added logic to handle trial spawner interactions with cooldown feedback for players. Introduced functional interfaces for cleaner and reusable code when processing armor stand counts and trial spawner timers.
2025-03-22 20:57:59 +01:00
auto 7c04361ea5 Add armor stand placement limits per chunk
Implemented functionality to restrict the number of armor stands a player can place in a chunk based on permissions. Added configuration support for customizable limits and proper error handling for edge cases. Registered the LimitArmorStands event listener in the plugin manager.
2025-03-22 20:33:31 +01:00
auto 10449f4a80 Refactor message-sending to use sendRichMessage API.
Replaced all instances of sendMiniMessage with sendRichMessage for improved readability and consistency across the codebase. This change ensures better handling of message formatting and placeholders.
2025-03-22 19:12:28 +01:00
14 changed files with 437 additions and 43 deletions
@@ -5,10 +5,7 @@ import com.alttd.playerutils.commands.playerutils_subcommands.RotateBlock;
import com.alttd.playerutils.config.Config;
import com.alttd.playerutils.config.KeyStorage;
import com.alttd.playerutils.config.Messages;
import com.alttd.playerutils.event_listeners.GoatHornEvent;
import com.alttd.playerutils.event_listeners.RotateBlockEvent;
import com.alttd.playerutils.event_listeners.TeleportEvent;
import com.alttd.playerutils.event_listeners.XpBottleEvent;
import com.alttd.playerutils.event_listeners.*;
import com.alttd.playerutils.util.Logger;
import org.bukkit.Bukkit;
import org.bukkit.plugin.PluginManager;
@@ -44,6 +41,8 @@ public final class PlayerUtils extends JavaPlugin {
pluginManager.registerEvents(new XpBottleEvent(this, logger), this);
pluginManager.registerEvents(new TeleportEvent(), this);
pluginManager.registerEvents(new GoatHornEvent(logger), this);
pluginManager.registerEvents(new LimitArmorStands(this, logger), this);
pluginManager.registerEvents(new AprilFoolsEvent(), this);
RotateBlockEvent rotateBlockEvent = new RotateBlockEvent(logger);
pluginManager.registerEvents(rotateBlockEvent, this);
@@ -41,10 +41,10 @@ public class PlayerUtilsCommand implements CommandExecutor, TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String cmd, @NotNull String[] args) {
if (args.length == 0) {
commandSender.sendMiniMessage(Messages.HELP.HELP_MESSAGE_WRAPPER.replaceAll("<commands>", subCommands.stream()
commandSender.sendRichMessage(Messages.HELP.HELP_MESSAGE_WRAPPER.replaceAll("<commands>", subCommands.stream()
.filter(subCommand -> commandSender.hasPermission(subCommand.getPermission()))
.map(SubCommand::getHelpMessage)
.collect(Collectors.joining("\n"))), null);
.collect(Collectors.joining("\n"))));
return true;
}
@@ -53,13 +53,13 @@ public class PlayerUtilsCommand implements CommandExecutor, TabExecutor {
return false;
if (!commandSender.hasPermission(subCommand.getPermission())) {
commandSender.sendMiniMessage(Messages.GENERIC.NO_PERMISSION, Placeholder.parsed("permission", subCommand.getPermission()));
commandSender.sendRichMessage(Messages.GENERIC.NO_PERMISSION, Placeholder.parsed("permission", subCommand.getPermission()));
return true;
}
boolean executedCorrectly = subCommand.onCommand(commandSender, args);
if (!executedCorrectly) {
commandSender.sendMiniMessage(subCommand.getHelpMessage(), null);
commandSender.sendRichMessage(subCommand.getHelpMessage());
}
return true;
}
@@ -41,20 +41,20 @@ public class Glow extends SubCommand {
Player player = playerFromArg.get();
if (args[1].equalsIgnoreCase("off")) {
turnOffGlow(commandSender, player, otherPlayer);
return true;
}
Scoreboard board = Bukkit.getScoreboardManager().getMainScoreboard();
board.getTeams().stream()
.filter(team -> team.getName().startsWith("Glow"))
.filter(team -> team.hasPlayer(player))
.forEach(team -> team.removePlayer(player));
if (args[1].equalsIgnoreCase("off")) {
turnOffGlow(commandSender, player, otherPlayer);
return true;
}
Optional<DyeColor> any = Arrays.stream(DyeColor.values()).filter(chatColor -> chatColor.name().equalsIgnoreCase(args[1])).findAny();
if (any.isEmpty()) {
commandSender.sendMiniMessage(getHelpMessage(), null);
commandSender.sendRichMessage(getHelpMessage());
return true;
}
@@ -75,36 +75,37 @@ public class Glow extends SubCommand {
private Optional<Player> getTargetPlayer(CommandSender commandSender, String[] args) {
if (args.length == 2) {
if (!(commandSender instanceof Player commandPlayer)) {
commandSender.sendMiniMessage(Messages.GENERIC.PLAYER_ONLY, null);
commandSender.sendRichMessage(Messages.GENERIC.PLAYER_ONLY);
return Optional.empty();
}
return Optional.of(commandPlayer);
}
if (!commandSender.hasPermission(getPermission() + ".other")) {
commandSender.sendMiniMessage(Messages.GENERIC.NO_PERMISSION, Placeholder.parsed("permission", getPermission() + ".other"));
commandSender.sendRichMessage(Messages.GENERIC.NO_PERMISSION, Placeholder.parsed("permission", getPermission() + ".other"));
return Optional.empty();
}
Optional<? extends Player> any = Bukkit.getOnlinePlayers().stream().filter(offlinePlayer -> offlinePlayer.getName().equalsIgnoreCase(args[2])).findAny();
if (any.isPresent()) {
return Optional.of(any.get());
} else {
commandSender.sendMiniMessage(Messages.GENERIC.PLAYER_NOT_FOUND, Placeholder.parsed("player", args[2]));
commandSender.sendRichMessage(Messages.GENERIC.PLAYER_NOT_FOUND, Placeholder.parsed("player", args[2]));
return Optional.empty();
}
}
private void turnOffGlow(CommandSender commandSender, Player player, boolean otherPlayer) {
player.sendMiniMessage(Messages.GLOW.GLOW_OFF, null);
player.sendRichMessage(Messages.GLOW.GLOW_OFF);
player.setGlowing(false);
if (otherPlayer) {
commandSender.sendMiniMessage(Messages.GLOW.GLOW_OFF_FOR_PLAYER, Placeholder.component("player", player.name()));
commandSender.sendRichMessage(Messages.GLOW.GLOW_OFF_FOR_PLAYER, Placeholder.component("player", player.name()));
}
}
private void turnOnGlow(CommandSender commandSender, Player player, Team team, DyeColor dyeColor, boolean otherPlayer) {
if (team.getScoreboard() == null) {
commandSender.sendMiniMessage(Messages.GLOW.UNABLE_TO_GET_SCOREBOARD, null);
commandSender.sendRichMessage(Messages.GLOW.UNABLE_TO_GET_SCOREBOARD);
logger.warning("Unable to get scoreboard for team");
return;
}
@@ -114,9 +115,9 @@ public class Glow extends SubCommand {
player.setScoreboard(team.getScoreboard());
player.setGlowing(true);
player.sendMiniMessage(Messages.GLOW.GLOW_ON, Placeholder.parsed("color", dyeColor.name()));
player.sendRichMessage(Messages.GLOW.GLOW_ON, Placeholder.parsed("color", dyeColor.name()));
if (otherPlayer) {
commandSender.sendMiniMessage(Messages.GLOW.GLOW_ON_FOR_PLAYER, TagResolver.resolver(
commandSender.sendRichMessage(Messages.GLOW.GLOW_ON_FOR_PLAYER, TagResolver.resolver(
Placeholder.parsed("color", dyeColor.name()),
Placeholder.component("player", player.name())
));
@@ -26,7 +26,7 @@ public class Key extends SubCommand {
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
if (!(commandSender instanceof Player player)) {
commandSender.sendMiniMessage(Messages.GENERIC.PLAYER_ONLY, null);
commandSender.sendRichMessage(Messages.GENERIC.PLAYER_ONLY);
return true;
}
@@ -36,7 +36,7 @@ public class Key extends SubCommand {
String crate = args[1].toLowerCase();
if (!Config.KEY.CRATES.containsKey(crate)) {
commandSender.sendMiniMessage(Messages.KEY.CRATE_NOT_EXIST, Placeholder.parsed("crate", crate));
commandSender.sendRichMessage(Messages.KEY.CRATE_NOT_EXIST, Placeholder.parsed("crate", crate));
return true;
}
@@ -45,7 +45,7 @@ public class Key extends SubCommand {
int totalKeys = Config.KEY.CRATES.getOrDefault(crate, 0);
int keys = crateMap.getOrDefault(uuid, 0);
if (keys >= totalKeys) {
commandSender.sendMiniMessage(Messages.KEY.RETRIEVED_ALL_KEYS, TagResolver.resolver(
commandSender.sendRichMessage(Messages.KEY.RETRIEVED_ALL_KEYS, TagResolver.resolver(
Placeholder.parsed("crate", crate),
Placeholder.parsed("keys", String.valueOf(keys))));
return true;
@@ -55,11 +55,11 @@ public class Key extends SubCommand {
logger.info(String.format("Gave %s one key for %s", player.getName(), crate));
commandSender.getServer().dispatchCommand(Bukkit.getConsoleSender(), String.format("crate give v %s 1 %s", crate, player.getName()));
if (keys + 1 == totalKeys) {
commandSender.sendMiniMessage(Messages.KEY.GAVE_FINAL_KEY, TagResolver.resolver(
commandSender.sendRichMessage(Messages.KEY.GAVE_FINAL_KEY, TagResolver.resolver(
Placeholder.parsed("crate", crate),
Placeholder.parsed("keys", String.valueOf(keys + 1))));
} else {
commandSender.sendMiniMessage(Messages.KEY.GAVE_KEY, TagResolver.resolver(
commandSender.sendRichMessage(Messages.KEY.GAVE_KEY, TagResolver.resolver(
Placeholder.parsed("crate", crate),
Placeholder.parsed("keys", String.valueOf(keys + 1)),
Placeholder.parsed("total_keys", String.valueOf(totalKeys))));
@@ -18,7 +18,7 @@ public class Reload extends SubCommand {
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
playerUtils.reloadConfigs();
commandSender.sendMiniMessage(Messages.RELOAD.RELOADED, null);
commandSender.sendRichMessage(Messages.RELOAD.RELOADED);
return true;
}
@@ -19,15 +19,15 @@ public class RotateBlock extends SubCommand {
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
if (!(commandSender instanceof Player player)) {
commandSender.sendMiniMessage(Messages.GENERIC.PLAYER_ONLY, null);
commandSender.sendRichMessage(Messages.GENERIC.PLAYER_ONLY);
return true;
}
boolean enabled = rotateBlockEvent.toggleRotate(player.getUniqueId());
if (enabled)
commandSender.sendMiniMessage(Messages.ROTATE_BLOCK.ENABLED, null);
commandSender.sendRichMessage(Messages.ROTATE_BLOCK.ENABLED);
else
commandSender.sendMiniMessage(Messages.ROTATE_BLOCK.DISABLED, null);
commandSender.sendRichMessage(Messages.ROTATE_BLOCK.DISABLED);
return true;
}
@@ -34,7 +34,7 @@ public class XPCalc extends SubCommand {
startingLevel++;
}
commandSender.sendMiniMessage(Messages.XP_CALC.XP_NEEDED, Placeholder.parsed("xp_needed", String.valueOf(totalXpNeeded)));
commandSender.sendRichMessage(Messages.XP_CALC.XP_NEEDED, Placeholder.parsed("xp_needed", String.valueOf(totalXpNeeded)));
return true;
}
@@ -31,7 +31,7 @@ public class XPCheque extends SubCommand {
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
if (!(commandSender instanceof Player player)) {
commandSender.sendMiniMessage(Messages.GENERIC.PLAYER_ONLY, null);
commandSender.sendRichMessage(Messages.GENERIC.PLAYER_ONLY);
return true;
}
@@ -48,7 +48,7 @@ public class XPCheque extends SubCommand {
}
if (amount > 64 || amount < 1) {
commandSender.sendMiniMessage(Messages.XP_CHEQUE.INVALID_AMOUNT, null);
commandSender.sendRichMessage(Messages.XP_CHEQUE.INVALID_AMOUNT);
return true;
}
@@ -60,24 +60,24 @@ public class XPCheque extends SubCommand {
}
if ((xpValue <= 0)) {
commandSender.sendMiniMessage(Messages.XP_CHEQUE.NEGATIVE, null);
commandSender.sendRichMessage(Messages.XP_CHEQUE.NEGATIVE);
return true;
}
int totalExperience = player.getTotalExperience();
if (totalExperience < (xpValue * amount)) {
commandSender.sendMiniMessage(Messages.XP_CHEQUE.NOT_ENOUGH_XP, Placeholder.parsed("xp", String.valueOf(totalExperience)));
commandSender.sendRichMessage(Messages.XP_CHEQUE.NOT_ENOUGH_XP, Placeholder.parsed("xp", String.valueOf(totalExperience)));
return true;
}
ItemStack heldItem = player.getInventory().getItemInMainHand();
if (!heldItem.getType().equals(Material.GLASS_BOTTLE)) {
commandSender.sendMiniMessage(Messages.XP_CHEQUE.NOT_HOLDING_BOTTLE, null);
commandSender.sendRichMessage(Messages.XP_CHEQUE.NOT_HOLDING_BOTTLE);
return true;
}
if (heldItem.getAmount() < amount) {
commandSender.sendMiniMessage(Messages.XP_CHEQUE.NOT_ENOUGH_BOTTLE, Placeholder.parsed("amount", String.valueOf(amount)));
commandSender.sendRichMessage(Messages.XP_CHEQUE.NOT_ENOUGH_BOTTLE, Placeholder.parsed("amount", String.valueOf(amount)));
return true;
}
@@ -122,7 +122,7 @@ public class XPCheque extends SubCommand {
NamespacedKey customXp = NamespacedKey.fromString("custom_xp", playerUtils);
if (customXp == null) {
player.sendMiniMessage(Messages.XP_CHEQUE.FAILED_STORAGE, null);
player.sendRichMessage(Messages.XP_CHEQUE.FAILED_STORAGE);
return Optional.empty();
}
persistentDataContainer.set(customXp, PersistentDataType.INTEGER, xpValue);
@@ -62,4 +62,24 @@ public class Config extends AbstractConfig{
}
}
}
public static class ARMOR_STAND_LIMIT {
private static final String prefix = "armor_stand_limit.";
public static HashMap<String, Integer> LIMIT = new HashMap<>();
@SuppressWarnings("unused")
private static void load() {
LIMIT.clear();
ConfigurationSection configurationSection = config.getConfigurationSection(prefix.substring(0, prefix.length() - 1));
if (configurationSection == null) {
config.logger.warning("No limits configured, adding default");
config.set(prefix, "default", 10);
}
Set<String> limits = configurationSection.getKeys(false);
for (String key : limits) {
LIMIT.put(key, config.getInt(prefix, key, 10));
}
}
}
}
@@ -0,0 +1,226 @@
package com.alttd.playerutils.event_listeners;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityBreedEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.player.PlayerBucketEntityEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
public class AprilFoolsEvent implements Listener {
MiniMessage miniMessage = MiniMessage.miniMessage();
List<Component> happyMessages = List.of(
miniMessage.deserialize("<green>You have a sudden urge of calmness and peace</green>"),
miniMessage.deserialize("<green>Mother nature is pleased and graces us with her beauty!</green>"),
miniMessage.deserialize("<green>The gentle breeze feels like a soothing hug from nature.</green>")
);
List<Component> angryMessages = List.of(
miniMessage.deserialize("<red>Something seems off...</red>"),
miniMessage.deserialize("<red>Mother nature is angry and furious with you!</red>"),
miniMessage.deserialize("<red>The wind picks up, carrying the anger of the earth.</red>")
);
private final List<PotionEffectType> badEffects = List.of(PotionEffectType.BLINDNESS, PotionEffectType.NAUSEA,
PotionEffectType.LEVITATION, PotionEffectType.DARKNESS, PotionEffectType.MINING_FATIGUE, PotionEffectType.SLOWNESS);
private final List<PotionEffectType> goodEffects = List.of(PotionEffectType.ABSORPTION, PotionEffectType.GLOWING,
PotionEffectType.HEALTH_BOOST, PotionEffectType.HERO_OF_THE_VILLAGE, PotionEffectType.LUCK, PotionEffectType.REGENERATION,
PotionEffectType.REGENERATION, PotionEffectType.RESISTANCE, PotionEffectType.SATURATION, PotionEffectType.STRENGTH);
private final List<Material> badBlocks = List.of(Material.SHORT_GRASS, Material.TALL_GRASS, Material.SEAGRASS,
Material.TALL_SEAGRASS, Material.LILY_PAD, Material.KELP, Material.KELP_PLANT, Material.BEEHIVE,
Material.BAMBOO, Material.MOSS_BLOCK, Material.CACTUS, Material.SMALL_DRIPLEAF, Material.BIG_DRIPLEAF);
private final List<Material> goodBlocks = List.of(Material.CACTUS, Material.AZALEA, Material.FLOWERING_AZALEA);
private final HashMap<UUID, Integer> goodActions = new HashMap<>();
private final HashMap<UUID, Integer> badActions = new HashMap<>();
private boolean isFlower(Material material) {
return Tag.FLOWERS.isTagged(material);
}
private boolean isLog(Material material) {
return Tag.LOGS.isTagged(material);
}
private boolean isLeaves(Material material) {
return Tag.LEAVES.isTagged(material);
}
private boolean isBadBlock(Material material) {
return badBlocks.contains(material) || isFlower(material) || isLog(material) || isLeaves(material);
}
private boolean isGoodBlock(@NotNull Material material) {
return goodBlocks.contains(material) || isFlower(material);
}
private boolean isNotAprilFools() {
LocalDate currentDate = LocalDate.now(ZoneOffset.UTC);
return currentDate.getMonthValue() != 4 || currentDate.getDayOfMonth() != 1;
}
/**
* Determines whether the provided count exceeds a randomly generated limit.
* The limit is generated as a random integer between 100 and 300, inclusive.
*
* @param count the value to be compared against the generated random limit
* @return true if the count is greater than the random limit; false otherwise
*/
private boolean underLimit(int count) {
int randomValue = 100 + (int) (Math.random() * 201);
return count <= randomValue;
}
private Component getRandomMessage(@NotNull List<Component> messages) {
return messages.get((int) (Math.random() * messages.size()));
}
private PotionEffectType getRandomEffect(@NotNull List<PotionEffectType> potionEffectTypes) {
return potionEffectTypes.get((int) (Math.random() * potionEffectTypes.size()));
}
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
if (isNotAprilFools()) {
return;
}
if (!isGoodBlock(event.getBlock().getType())) {
return;
}
runGoodAction(event.getPlayer());
}
@EventHandler
public void onGrassBlockBoneMealed(PlayerInteractEvent event) {
if (isNotAprilFools()) {
return;
}
if (!event.getAction().isRightClick()) {
return;
}
ItemStack itemInHand = event.getPlayer().getInventory().getItemInMainHand();
if (itemInHand.getType() != Material.BONE_MEAL) {
return;
}
Block clickedBlock = event.getClickedBlock();
if (clickedBlock == null || clickedBlock.getType() != Material.GRASS_BLOCK) {
return;
}
if (event.getHand() != EquipmentSlot.HAND) {
return;
}
runGoodAction(event.getPlayer());
}
@EventHandler
public void onAnimalBred(EntityBreedEvent event) {
if (isNotAprilFools()) {
return;
}
if (!(event.getBreeder() instanceof Player player)) {
return;
}
runGoodAction(player);
}
private void runGoodAction(@NotNull Player player) {
goodActions.merge(player.getUniqueId(), 1, Integer::sum);
if (underLimit(goodActions.get(player.getUniqueId()))) {
return;
}
player.sendMessage(getRandomMessage(happyMessages));
player.addPotionEffect(getRandomEffect(goodEffects).createEffect(60 * 20, 1));
goodActions.put(player.getUniqueId(), 0);
}
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
if (isNotAprilFools()) {
return;
}
if (!isBadBlock(event.getBlock().getType())) {
return;
}
Player player = event.getPlayer();
runBadAction(player);
}
@EventHandler
public void onAnimalKilled(EntityDeathEvent event) {
if (isNotAprilFools()) {
return;
}
LivingEntity entity = event.getEntity();
if (entity.getKiller() == null) {
return;
}
if (entity instanceof Monster) {
return;
}
Player player = entity.getKiller();
runBadAction(player);
}
@EventHandler
public void onFishCollected(PlayerBucketEntityEvent event) {
if (isNotAprilFools()) {
return;
}
Player player = event.getPlayer();
runBadAction(player);
}
@EventHandler
public void onPlayerFish(PlayerFishEvent event) {
if (isNotAprilFools()) {
return;
}
Player player = event.getPlayer();
runBadAction(player);
}
private void runBadAction(@NotNull Player player) {
badActions.merge(player.getUniqueId(), 1, Integer::sum);
if (underLimit(badActions.get(player.getUniqueId()))) {
return;
}
player.sendMessage(getRandomMessage(angryMessages));
player.addPotionEffect(getRandomEffect(badEffects).createEffect(10 * 20, 1));
badActions.put(player.getUniqueId(), 0);
}
}
@@ -0,0 +1,148 @@
package com.alttd.playerutils.event_listeners;
import com.alttd.playerutils.PlayerUtils;
import com.alttd.playerutils.config.Config;
import com.alttd.playerutils.util.Logger;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.kyori.adventure.title.Title;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.block.TrialSpawner;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
public class LimitArmorStands implements Listener {
private final PlayerUtils playerUtils;
private final Logger logger;
public LimitArmorStands(PlayerUtils playerUtils, Logger logger) {
this.playerUtils = playerUtils;
this.logger = logger;
}
@FunctionalInterface
private interface ArmorStandCountConsumer {
void apply(int armorStandCount, @NotNull Player player, @NotNull NamespacedKey namespacedKey,
@NotNull PersistentDataContainer persistentDataContainer);
}
@FunctionalInterface
private interface TrialSpawnerTimerConsumer {
void apply(int ticks, @NotNull Player player);
}
@EventHandler
public void onPlayerInteractEvent(PlayerInteractEvent event) {
handleArmorStandPlacing(event, (armorStandCount, player, namespacedKey, persistentDataContainer) -> {
int max = 0;
for (String permission : Config.ARMOR_STAND_LIMIT.LIMIT.keySet()) {
if (player.hasPermission("pu.limit." + permission)) {
max = Math.max(max, Config.ARMOR_STAND_LIMIT.LIMIT.get(permission));
}
}
if (armorStandCount >= max) {
event.setCancelled(true);
player.sendRichMessage("<red>You can not place more than <max> armor stands in a chunk</red>",
Placeholder.parsed("max", String.valueOf(max)));
return;
}
persistentDataContainer.set(namespacedKey, PersistentDataType.INTEGER, ++armorStandCount);
});
if (event.getPlayer().hasPermission("pu.trial_spawner.cooldown")) {
handleRightClickTrialSpawner(event, (ticks, player) -> {
MiniMessage miniMessage = MiniMessage.miniMessage();
Title title = Title.title(Component.empty(),
miniMessage.deserialize("<green>Cooldown <red><seconds></red></green>",
Placeholder.parsed("seconds", String.valueOf(ticks / 20))));
player.showTitle(title);
});
}
}
private void handleArmorStandPlacing(PlayerInteractEvent event, ArmorStandCountConsumer consumer) {
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
return;
}
if (!event.getMaterial().equals(Material.ARMOR_STAND)) {
return;
}
if (event.getClickedBlock() == null) {
return;
}
Player player = event.getPlayer();;
Chunk chunk = event.getClickedBlock().getChunk();
NamespacedKey namespacedKey = NamespacedKey.fromString("armor_stand_count", playerUtils);
if (namespacedKey == null) {
event.setCancelled(true);
logger.warning("Unable to retrieve name spaced key for armor stand count.");
player.sendRichMessage("<red>Something went wrong while checking the armor stand count. " +
"You will not be able to place this until this is fixed. Please contact a staff member</red>");
return;
}
PersistentDataContainer persistentDataContainer = chunk.getPersistentDataContainer();
if (!persistentDataContainer.has(namespacedKey, PersistentDataType.INTEGER)) {
persistentDataContainer.set(namespacedKey, PersistentDataType.INTEGER, countArmorStands(chunk));
}
Integer armorStandCount = persistentDataContainer.get(namespacedKey, PersistentDataType.INTEGER);
if (armorStandCount == null) {
event.setCancelled(true);
logger.warning("Unable to retrieve armor stand count.");
player.sendRichMessage("<red>Something went wrong while checking the armor stand count. " +
"You will not be able to place this until this is fixed. Please contact a staff member</red>");
return;
}
consumer.apply(armorStandCount, event.getPlayer(), namespacedKey, persistentDataContainer);
}
private void handleRightClickTrialSpawner(PlayerInteractEvent event, TrialSpawnerTimerConsumer consumer) {
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
return;
}
if (!event.getMaterial().equals(Material.AIR)) {
return;
}
if (event.getClickedBlock() == null) {
return;
}
Block block = event.getClickedBlock();
if (!block.getType().equals(Material.TRIAL_SPAWNER)) {
return;
}
if (!(block instanceof TrialSpawner trialSpawner)) {
return;
}
if (!(trialSpawner.getBlockData() instanceof org.bukkit.block.data.type.TrialSpawner trialSpawnerData)) {
return;
}
Player player = event.getPlayer();
if (!trialSpawnerData.getTrialSpawnerState().equals(org.bukkit.block.data.type.TrialSpawner.State.INACTIVE)) {
consumer.apply(0, player);
return;
}
consumer.apply(trialSpawner.getCooldownLength(), player);
}
private int countArmorStands(Chunk chunk) {
return (int) Arrays.stream(chunk.getEntities())
.filter(entity -> entity.getType().equals(EntityType.ARMOR_STAND))
.count();
}
}
@@ -103,7 +103,7 @@ public class XpBottleEvent implements Listener {
NamespacedKey customXp = NamespacedKey.fromString("custom_xp", playerUtils);
if (customXp == null) {
player.sendMiniMessage(Messages.XP_CHEQUE.FAILED_STORAGE, null);
player.sendRichMessage(Messages.XP_CHEQUE.FAILED_STORAGE);
return Optional.empty();
}
persistentDataContainer.set(customXp, PersistentDataType.INTEGER, xpValue);