From cc4d2c45d7f8861e9e9626cd3e2b5b2eb0080787 Mon Sep 17 00:00:00 2001 From: 1robie Date: Wed, 12 Nov 2025 20:55:26 +0100 Subject: [PATCH 1/5] feat: add conditional loading for Dialogs support based on MiniMessage format setting --- .../menu/api/configuration/Config.java | 5 ----- .../java/fr/maxlego08/menu/ZMenuPlugin.java | 18 +++++++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/API/src/main/java/fr/maxlego08/menu/api/configuration/Config.java b/API/src/main/java/fr/maxlego08/menu/api/configuration/Config.java index ade113eb..258ec532 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/configuration/Config.java +++ b/API/src/main/java/fr/maxlego08/menu/api/configuration/Config.java @@ -14,12 +14,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Objects; -@ConfigDialog( - name = "zMenu Config", - externalTitle = "zMenu Configuration" -) public class Config { // Enable debug, allows you to display errors in the console that would normally be hidden. diff --git a/src/main/java/fr/maxlego08/menu/ZMenuPlugin.java b/src/main/java/fr/maxlego08/menu/ZMenuPlugin.java index 0a52c718..896b0c32 100644 --- a/src/main/java/fr/maxlego08/menu/ZMenuPlugin.java +++ b/src/main/java/fr/maxlego08/menu/ZMenuPlugin.java @@ -169,13 +169,17 @@ public void onEnable() { servicesManager.register(Enchantments.class, this.enchantments, this, ServicePriority.Highest); if (isPaper() && NmsVersion.getCurrentVersion().isDialogsVersion()){ - Logger.info("Paper server detected, loading Dialogs support"); - ConfigManager configManager = new ConfigManager(this); - this.dialogManager = new ZDialogManager(this, configManager); - servicesManager.register(DialogManager.class, this.dialogManager, this, ServicePriority.Highest); - ConfigDialogBuilder configDialogBuilder = new ConfigDialogBuilder("zMenu Config", "zMenu Configuration"); - Logger.info(configDialogBuilder.getName()); - configManager.registerConfig(configDialogBuilder,Config.class, this); + if (Config.enableMiniMessageFormat){ + Logger.info("Paper server detected, loading Dialogs support"); + ConfigManager configManager = new ConfigManager(this); + this.dialogManager = new ZDialogManager(this, configManager); + servicesManager.register(DialogManager.class, this.dialogManager, this, ServicePriority.Highest); + ConfigDialogBuilder configDialogBuilder = new ConfigDialogBuilder("zMenu Config", "zMenu Configuration"); + Logger.info(configDialogBuilder.getName()); + configManager.registerConfig(configDialogBuilder,Config.class, this); + } else { + Logger.info("Paper server detected but MiniMessage format is disabled, Dialogs support will not be loaded. Enable MiniMessage format in config.yml to use Dialogs."); + } } this.registerInventory(EnumInventory.INVENTORY_DEFAULT, new InventoryDefault()); From 0a5e01991af3e942f2e820456382e2972a51fe48 Mon Sep 17 00:00:00 2001 From: 1robie Date: Wed, 12 Nov 2025 21:38:45 +0100 Subject: [PATCH 2/5] fix --- .../java/fr/maxlego08/menu/command/commands/CommandMenu.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/maxlego08/menu/command/commands/CommandMenu.java b/src/main/java/fr/maxlego08/menu/command/commands/CommandMenu.java index 1238f65c..50dcae89 100644 --- a/src/main/java/fr/maxlego08/menu/command/commands/CommandMenu.java +++ b/src/main/java/fr/maxlego08/menu/command/commands/CommandMenu.java @@ -1,6 +1,7 @@ package fr.maxlego08.menu.command.commands; import fr.maxlego08.menu.ZMenuPlugin; +import fr.maxlego08.menu.api.configuration.Config; import fr.maxlego08.menu.command.VCommand; import fr.maxlego08.menu.command.commands.dialogs.CommandDialog; import fr.maxlego08.menu.command.commands.players.CommandMenuPlayers; @@ -42,7 +43,7 @@ public CommandMenu(ZMenuPlugin plugin) { this.addSubCommand(new CommandMenuInventories(plugin)); // this.addSubCommand(new CommandMenuMarketplace(plugin)); - if (plugin.isPaper() && NmsVersion.getCurrentVersion().isDialogsVersion()) { + if (plugin.isPaper() && NmsVersion.getCurrentVersion().isDialogsVersion() && Config.enableMiniMessageFormat) { this.addSubCommand(new CommandDialog(plugin)); } } From 8ad4fc4e3848763d4e16ff0ffd0a04494c4b37cd Mon Sep 17 00:00:00 2001 From: 1robie Date: Wed, 26 Nov 2025 18:07:34 +0100 Subject: [PATCH 3/5] feat: update ActionPlayerData to use String for seconds and refactor related classes --- .../fr/maxlego08/menu/api/ItemManager.java | 2 +- .../menu/api/enums/PlaceholderAction.java | 5 +-- .../maxlego08/menu/api/mechanic/Mechanic.java | 8 ++--- .../menu/api/mechanic/MechanicFactory.java | 15 ++++---- .../requirement/data/ActionPlayerData.java | 2 +- .../menu/api/utils/Placeholders.java | 4 ++- .../java/fr/maxlego08/menu/ZItemManager.java | 18 ++++++---- .../menu/loader/ActionPlayerDataLoader.java | 10 ++++-- .../menu/loader/actions/DataLoader.java | 5 ++- .../actions/DiscordComponentV2Loader.java | 3 +- .../menu/loader/actions/DiscordLoader.java | 3 +- .../mechanics/itemjoin/ItemJoinMechanic.java | 7 ++-- .../itemjoin/ItemJoinMechanicFactory.java | 5 ++- .../itemjoin/ItemJoinMechanicListener.java | 34 ++++++++----------- .../menu/placeholder/MenuPlaceholders.java | 7 ++++ .../menu/players/PlayerDataLoader.java | 2 -- .../menu/requirement/ZActionPlayerData.java | 14 +++++--- 17 files changed, 82 insertions(+), 62 deletions(-) diff --git a/API/src/main/java/fr/maxlego08/menu/api/ItemManager.java b/API/src/main/java/fr/maxlego08/menu/api/ItemManager.java index c813ec0d..fbecab60 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/ItemManager.java +++ b/API/src/main/java/fr/maxlego08/menu/api/ItemManager.java @@ -32,7 +32,7 @@ public interface ItemManager { void unloadListeners(); - void registerMechanicFactory(MechanicFactory factory); + void registerMechanicFactory(MechanicFactory factory); void giveItem(Player player, String itemId); diff --git a/API/src/main/java/fr/maxlego08/menu/api/enums/PlaceholderAction.java b/API/src/main/java/fr/maxlego08/menu/api/enums/PlaceholderAction.java index adf27cd9..0ccc045f 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/enums/PlaceholderAction.java +++ b/API/src/main/java/fr/maxlego08/menu/api/enums/PlaceholderAction.java @@ -1,6 +1,7 @@ package fr.maxlego08.menu.api.enums; -import java.util.ArrayList; +import fr.maxlego08.menu.zcore.logger.Logger; + import java.util.Arrays; import java.util.List; @@ -51,7 +52,7 @@ public static PlaceholderAction from(String string) { } } } - System.err.println("Impossible to find the " + string + " action for placeholder"); + Logger.info("Impossible to find the " + string + " action for placeholder", Logger.LogType.ERROR); return null; } diff --git a/API/src/main/java/fr/maxlego08/menu/api/mechanic/Mechanic.java b/API/src/main/java/fr/maxlego08/menu/api/mechanic/Mechanic.java index 3ac7d18f..7d9e481b 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/mechanic/Mechanic.java +++ b/API/src/main/java/fr/maxlego08/menu/api/mechanic/Mechanic.java @@ -2,12 +2,12 @@ import org.bukkit.configuration.ConfigurationSection; -public abstract class Mechanic { +public abstract class Mechanic> { private final ConfigurationSection mechanicSection; - private final MechanicFactory mechanicFactory; + private final T mechanicFactory; private final String itemId; - public Mechanic(final String itemId, final MechanicFactory mechanicFactory, final ConfigurationSection mechanicSection) { + public Mechanic(final String itemId, final T mechanicFactory, final ConfigurationSection mechanicSection) { this.mechanicFactory = mechanicFactory; this.mechanicSection = mechanicSection; this.itemId = itemId; @@ -17,7 +17,7 @@ public ConfigurationSection getMechanicSection() { return mechanicSection; } - public MechanicFactory getMechanicFactory() { + public T getMechanicFactory() { return mechanicFactory; } diff --git a/API/src/main/java/fr/maxlego08/menu/api/mechanic/MechanicFactory.java b/API/src/main/java/fr/maxlego08/menu/api/mechanic/MechanicFactory.java index d27a8acc..c6514899 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/mechanic/MechanicFactory.java +++ b/API/src/main/java/fr/maxlego08/menu/api/mechanic/MechanicFactory.java @@ -5,6 +5,7 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.HashMap; @@ -12,11 +13,11 @@ import java.util.Optional; import java.util.Set; -public abstract class MechanicFactory { +public abstract class MechanicFactory { private final MenuPlugin plugin; private final ItemManager itemManager; private final String mechanicId; - private final Map mechanicByItemId = new HashMap<>(); + private final Map mechanicByItemId = new HashMap<>(); public MechanicFactory(MenuPlugin plugin, String mechanicId) { this.plugin = plugin; @@ -24,13 +25,13 @@ public MechanicFactory(MenuPlugin plugin, String mechanicId) { this.itemManager = plugin.getItemManager(); } - public abstract Mechanic parse(final MenuPlugin plugin, final String itemId, final ConfigurationSection mechanicSection, YamlConfiguration configurationFile, File file, String path); + public abstract T parse(final MenuPlugin plugin, final String itemId, final ConfigurationSection mechanicSection, YamlConfiguration configurationFile, File file, String path); - public Mechanic getMechanic(String itemId){ + public @Nullable T getMechanic(String itemId){ return mechanicByItemId.get(itemId); - }; + } - public void addToImplemented(Mechanic mechanic) { + public void addToImplemented(T mechanic) { mechanicByItemId.put(mechanic.getItemId(), mechanic); } @@ -47,7 +48,7 @@ public String getMechanicId() { return mechanicId; } - public Set> getAllMechanics(){ + public Set> getAllMechanics(){ return mechanicByItemId.entrySet(); } diff --git a/API/src/main/java/fr/maxlego08/menu/api/requirement/data/ActionPlayerData.java b/API/src/main/java/fr/maxlego08/menu/api/requirement/data/ActionPlayerData.java index 422a2ab5..60b8dd45 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/requirement/data/ActionPlayerData.java +++ b/API/src/main/java/fr/maxlego08/menu/api/requirement/data/ActionPlayerData.java @@ -36,7 +36,7 @@ public interface ActionPlayerData { * * @return The expiration time in seconds. */ - long getSeconds(); + String getSeconds(); /** * Converts the action into player data. diff --git a/API/src/main/java/fr/maxlego08/menu/api/utils/Placeholders.java b/API/src/main/java/fr/maxlego08/menu/api/utils/Placeholders.java index 1bb0c8ff..b03569a0 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/utils/Placeholders.java +++ b/API/src/main/java/fr/maxlego08/menu/api/utils/Placeholders.java @@ -1,5 +1,7 @@ package fr.maxlego08.menu.api.utils; +import fr.maxlego08.menu.zcore.logger.Logger; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -115,7 +117,7 @@ public String parse(String string, String key, String value) { } } catch (Exception exception) { exception.printStackTrace(); - System.err.println("Error with placeholder key " + key + " !"); + Logger.info("Error with placeholder key " + key + " !", Logger.LogType.ERROR); } return string; } diff --git a/src/main/java/fr/maxlego08/menu/ZItemManager.java b/src/main/java/fr/maxlego08/menu/ZItemManager.java index ff7de597..c198ea1d 100644 --- a/src/main/java/fr/maxlego08/menu/ZItemManager.java +++ b/src/main/java/fr/maxlego08/menu/ZItemManager.java @@ -17,6 +17,7 @@ import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.Plugin; @@ -34,7 +35,7 @@ public class ZItemManager implements ItemManager{ private final MenuPlugin menuPlugin; private final Map mechanicListeners = new HashMap<>(); - private final Map mechanicFactories = new HashMap<>(); + private final Map> mechanicFactories = new HashMap<>(); private final Map customItems = new HashMap<>(); @@ -86,7 +87,7 @@ public void loadCustomItem(File file) { if (mechanicSection != null) { path += "mechanics."; for (String mechanicId : mechanicSection.getKeys(false)) { - MechanicFactory factory = mechanicFactories.get(mechanicId); + MechanicFactory factory = mechanicFactories.get(mechanicId); if (factory != null) { factory.parse(this.menuPlugin, itemId, mechanicSection.getConfigurationSection(mechanicId), config, file, path + mechanicId + "."); mechanicIds.add(mechanicId); @@ -108,7 +109,7 @@ public void loadCustomItem(File file) { @Override public void reloadCustomItems() { customItems.clear(); - for (MechanicFactory factory : mechanicFactories.values()) { + for (MechanicFactory factory : mechanicFactories.values()) { factory.clearMechanics(); } this.loadCustomItems(); @@ -158,7 +159,7 @@ public void unloadListeners() { } @Override - public void registerMechanicFactory(MechanicFactory factory) { + public void registerMechanicFactory(MechanicFactory factory) { if (mechanicFactories.containsKey(factory.getMechanicId())) { Logger.info("MechanicFactory " + factory.getMechanicId() + " is already registered.", Logger.LogType.WARNING); return; @@ -177,9 +178,12 @@ public void giveItem(Player player, String itemId) { MenuItemStack menuItemStack = itemData.menuItemStack(); ItemStack itemStack = menuItemStack.build(player); ItemMeta itemMeta = itemStack.getItemMeta(); - itemMeta.getPersistentDataContainer().set(itemIdKey, PersistentDataType.STRING, itemId); - itemMeta.getPersistentDataContainer().set(ownerKey, PersistentDataType.STRING, player.getUniqueId().toString()); - itemStack.setItemMeta(itemMeta); + if (itemMeta != null) { + PersistentDataContainer persistentDataContainer = itemMeta.getPersistentDataContainer(); + persistentDataContainer.set(itemIdKey, PersistentDataType.STRING, itemId); + persistentDataContainer.set(ownerKey, PersistentDataType.STRING, player.getUniqueId().toString()); + itemStack.setItemMeta(itemMeta); + } boolean shouldCancel = false; for (String mechanicId : itemData.mechanicIds()) { diff --git a/src/main/java/fr/maxlego08/menu/loader/ActionPlayerDataLoader.java b/src/main/java/fr/maxlego08/menu/loader/ActionPlayerDataLoader.java index 58a2be40..77eed075 100644 --- a/src/main/java/fr/maxlego08/menu/loader/ActionPlayerDataLoader.java +++ b/src/main/java/fr/maxlego08/menu/loader/ActionPlayerDataLoader.java @@ -1,11 +1,11 @@ package fr.maxlego08.menu.loader; +import fr.maxlego08.menu.api.exceptions.InventoryException; import fr.maxlego08.menu.api.requirement.data.ActionPlayerData; import fr.maxlego08.menu.api.requirement.data.ActionPlayerDataType; -import fr.maxlego08.menu.api.exceptions.InventoryException; import fr.maxlego08.menu.api.storage.StorageManager; -import fr.maxlego08.menu.requirement.ZActionPlayerData; import fr.maxlego08.menu.api.utils.Loader; +import fr.maxlego08.menu.requirement.ZActionPlayerData; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; @@ -26,7 +26,11 @@ public ActionPlayerData load(YamlConfiguration configuration, String path, Objec ActionPlayerDataType type = ActionPlayerDataType.valueOf(configuration.getString(path + "type", "SET")); String key = configuration.getString(path + "key"); Object object = configuration.get(path + "value", true); - long seconds = configuration.getLong(path + "seconds", 0); + String seconds = configuration.getString(path + "seconds", null); + if (seconds == null) { + seconds = String.valueOf(configuration.getLong(path + "seconds",0)); + } + boolean mathExpression = configuration.getBoolean(path + "math", false); return new ZActionPlayerData(storageManager, key, type, object, seconds, mathExpression); diff --git a/src/main/java/fr/maxlego08/menu/loader/actions/DataLoader.java b/src/main/java/fr/maxlego08/menu/loader/actions/DataLoader.java index c43b2469..1a372e1c 100644 --- a/src/main/java/fr/maxlego08/menu/loader/actions/DataLoader.java +++ b/src/main/java/fr/maxlego08/menu/loader/actions/DataLoader.java @@ -24,7 +24,10 @@ public Action load(String path, TypedMapAccessor accessor, File file) { ActionPlayerDataType type = ActionPlayerDataType.valueOf(accessor.getString("action", "SET").toUpperCase()); String key = accessor.getString("key"); Object object = accessor.getObject("value", true); - long seconds = accessor.getLong("seconds", 0L); + String seconds = accessor.getString("seconds"); + if (seconds == null) { + seconds = String.valueOf(accessor.getLong("seconds", 0L)); + } boolean mathExpression = accessor.getBoolean("math", false); return new DataAction(new ZActionPlayerData(this.plugin.getStorageManager(), key, type, object, seconds, mathExpression), this.plugin); } diff --git a/src/main/java/fr/maxlego08/menu/loader/actions/DiscordComponentV2Loader.java b/src/main/java/fr/maxlego08/menu/loader/actions/DiscordComponentV2Loader.java index a8edd334..2b3ba758 100644 --- a/src/main/java/fr/maxlego08/menu/loader/actions/DiscordComponentV2Loader.java +++ b/src/main/java/fr/maxlego08/menu/loader/actions/DiscordComponentV2Loader.java @@ -4,6 +4,7 @@ import fr.maxlego08.menu.api.requirement.Action; import fr.maxlego08.menu.api.utils.TypedMapAccessor; import fr.maxlego08.menu.requirement.actions.DiscordComponentAction; +import fr.maxlego08.menu.zcore.logger.Logger; import fr.maxlego08.menu.zcore.utils.discord.DiscordConfigurationComponent; import java.io.File; @@ -33,7 +34,7 @@ public Action load(String path, TypedMapAccessor accessor, File file) { DiscordConfigurationComponent config = new DiscordConfigurationComponent(webhookUrl, avatarUrl, username, json); return new DiscordComponentAction(config); } else { - System.err.println("Impossible to load discord action, webhook does not exists: " + webhookUrl); + Logger.info("Impossible to load discord action, webhook does not exists: " + webhookUrl, Logger.LogType.ERROR); } return null; } diff --git a/src/main/java/fr/maxlego08/menu/loader/actions/DiscordLoader.java b/src/main/java/fr/maxlego08/menu/loader/actions/DiscordLoader.java index c319cfaf..b729db5c 100644 --- a/src/main/java/fr/maxlego08/menu/loader/actions/DiscordLoader.java +++ b/src/main/java/fr/maxlego08/menu/loader/actions/DiscordLoader.java @@ -4,6 +4,7 @@ import fr.maxlego08.menu.api.requirement.Action; import fr.maxlego08.menu.api.utils.TypedMapAccessor; import fr.maxlego08.menu.requirement.actions.DiscordAction; +import fr.maxlego08.menu.zcore.logger.Logger; import fr.maxlego08.menu.zcore.utils.discord.DiscordConfiguration; import fr.maxlego08.menu.zcore.utils.discord.DiscordEmbedConfiguration; @@ -40,7 +41,7 @@ public Action load(String path, TypedMapAccessor accessor, File file) { DiscordConfiguration config = new DiscordConfiguration(webhookUrl, avatarUrl, message, username, DiscordEmbedConfiguration.convertToEmbedObjects(values)); return new DiscordAction(config); } else { - System.err.println("Impossible to load discord action, webhook does not exists: " + webhookUrl); + Logger.info("Impossible to load discord action, webhook does not exists: " + webhookUrl); } return null; diff --git a/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanic.java b/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanic.java index 31abeb90..daee3d67 100644 --- a/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanic.java +++ b/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanic.java @@ -1,18 +1,17 @@ package fr.maxlego08.menu.mechanics.itemjoin; import fr.maxlego08.menu.api.mechanic.Mechanic; -import fr.maxlego08.menu.api.mechanic.MechanicFactory; import org.bukkit.configuration.ConfigurationSection; import java.util.OptionalInt; -public class ItemJoinMechanic extends Mechanic { +public class ItemJoinMechanic extends Mechanic { private final boolean grantOnFirstJoin; private final boolean preventInventoryChanges; private final OptionalInt fixedSlot; - public ItemJoinMechanic(String itemId, MechanicFactory mechanicFactory, ConfigurationSection mechanicSection) { - super(itemId, mechanicFactory, mechanicSection); + public ItemJoinMechanic(String itemId, ItemJoinMechanicFactory itemJoinMechanicFactory, ConfigurationSection mechanicSection) { + super(itemId, itemJoinMechanicFactory, mechanicSection); this.grantOnFirstJoin = mechanicSection.getBoolean("give-first-join", false); this.preventInventoryChanges = mechanicSection.getBoolean("prevent-inventory-modification", true); int slot = mechanicSection.getInt("fixed-slot", -1); diff --git a/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanicFactory.java b/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanicFactory.java index 70b7b66f..b4c0a0be 100644 --- a/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanicFactory.java +++ b/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanicFactory.java @@ -1,21 +1,20 @@ package fr.maxlego08.menu.mechanics.itemjoin; import fr.maxlego08.menu.api.MenuPlugin; -import fr.maxlego08.menu.api.mechanic.Mechanic; import fr.maxlego08.menu.api.mechanic.MechanicFactory; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; -public class ItemJoinMechanicFactory extends MechanicFactory { +public class ItemJoinMechanicFactory extends MechanicFactory { public ItemJoinMechanicFactory(MenuPlugin plugin) { super(plugin, "itemjoin"); plugin.getItemManager().registerListeners(plugin, "itemjoin", new ItemJoinMechanicListener(this, plugin)); } @Override - public Mechanic parse(MenuPlugin plugin, String itemId, ConfigurationSection mechanicSection, YamlConfiguration configurationFile, File file, String path) { + public ItemJoinMechanic parse(MenuPlugin plugin, String itemId, ConfigurationSection mechanicSection, YamlConfiguration configurationFile, File file, String path) { ItemJoinMechanic mechanic = new ItemJoinMechanic(itemId, this, mechanicSection); this.addToImplemented(mechanic); return mechanic; diff --git a/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanicListener.java b/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanicListener.java index f6fbce15..b7f55e77 100644 --- a/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanicListener.java +++ b/src/main/java/fr/maxlego08/menu/mechanics/itemjoin/ItemJoinMechanicListener.java @@ -2,7 +2,6 @@ import fr.maxlego08.menu.api.ItemManager; import fr.maxlego08.menu.api.MenuPlugin; -import fr.maxlego08.menu.api.mechanic.Mechanic; import fr.maxlego08.menu.api.mechanic.MechanicListener; import org.bukkit.Material; import org.bukkit.entity.ItemFrame; @@ -41,11 +40,9 @@ private Optional getProtectedMechanic(ItemStack item) { Optional itemId = itemManager.getItemId(item); if (itemId.isEmpty()) return Optional.empty(); - Mechanic mechanic = itemJoinMechanicFactory.getMechanic(itemId.get()); - if (mechanic instanceof ItemJoinMechanic itemJoinMechanic) { - if (itemJoinMechanic.preventsInventoryChanges() && itemJoinMechanic.getFixedSlot().isPresent()) { - return Optional.of(itemJoinMechanic); - } + ItemJoinMechanic mechanic = itemJoinMechanicFactory.getMechanic(itemId.get()); + if (mechanic != null && mechanic.preventsInventoryChanges() && mechanic.getFixedSlot().isPresent()) { + return Optional.of(mechanic); } return Optional.empty(); } @@ -64,11 +61,10 @@ private boolean isProtectedItem(ItemStack item) { public void onConnect(PlayerJoinEvent event) { Player player = event.getPlayer(); if (!player.hasPlayedBefore()) { - for (Map.Entry entry : itemJoinMechanicFactory.getAllMechanics()) { - if (entry.getValue() instanceof ItemJoinMechanic itemJoinMechanic) { - if (itemJoinMechanic.shouldGrantOnFirstJoin()) { - this.itemManager.giveItem(player, entry.getKey()); - } + for (Map.Entry entry : itemJoinMechanicFactory.getAllMechanics()) { + ItemJoinMechanic mechanic = entry.getValue(); + if (mechanic.shouldGrantOnFirstJoin()) { + this.itemManager.giveItem(player, entry.getKey()); } } } @@ -88,7 +84,7 @@ public void onInventoryClick(InventoryClickEvent event) { } Optional mechanic = getProtectedMechanic(event.getCurrentItem()); - if (mechanic.isPresent() && event.getSlot() == mechanic.get().getFixedSlot().getAsInt()) { + if (mechanic.isPresent() && mechanic.get().getFixedSlot().isPresent() && event.getSlot() == mechanic.get().getFixedSlot().getAsInt()) { event.setCancelled(true); } } @@ -101,7 +97,7 @@ public void onDrag(InventoryDragEvent event) { for (ItemStack draggedItem : event.getNewItems().values()) { Optional mechanic = getProtectedMechanic(draggedItem); - if (mechanic.isPresent() && event.getRawSlots().contains(mechanic.get().getFixedSlot().getAsInt())) { + if (mechanic.isPresent() && mechanic.get().getFixedSlot().isPresent() && event.getRawSlots().contains(mechanic.get().getFixedSlot().getAsInt())) { event.setCancelled(true); return; } @@ -131,13 +127,11 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { @Override public boolean onItemGive(Player player, ItemStack item, String itemId) { - Mechanic mechanic = itemJoinMechanicFactory.getMechanic(itemId); - if (mechanic instanceof ItemJoinMechanic itemJoinMechanic) { - if (itemJoinMechanic.preventsInventoryChanges() && itemJoinMechanic.getFixedSlot().isPresent()) { - int slot = itemJoinMechanic.getFixedSlot().getAsInt(); - player.getInventory().setItem(slot, item); - return true; - } + ItemJoinMechanic mechanic = itemJoinMechanicFactory.getMechanic(itemId); + if (mechanic != null && mechanic.preventsInventoryChanges() && mechanic.getFixedSlot().isPresent()) { + int slot = mechanic.getFixedSlot().getAsInt(); + player.getInventory().setItem(slot, item); + return true; } return false; } diff --git a/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java b/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java index f60de09d..94c305c4 100644 --- a/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java +++ b/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java @@ -11,6 +11,9 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryHolder; +import java.time.LocalDateTime; +import java.time.ZoneId; + public class MenuPlaceholders extends ZUtils { public void register(MenuPlugin plugin) { @@ -46,6 +49,10 @@ public void register(MenuPlugin plugin) { Object object = plugin.getGlobalPlaceholders().get(args); return object == null ? Message.GLOBAL_PLACEHOLDER_NOT_FOUND.getMessage() : String.valueOf(object); }); + + placeholder.register("time_unix_timestamp", (player, args) -> String.valueOf(System.currentTimeMillis())); + placeholder.register("time_next_day_unix_timestamp",(player,args)-> String.valueOf(LocalDateTime.now().toLocalDate().plusDays(1L).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli())); + placeholder.register("time_today_start_unix_timestamp",(player,args)-> String.valueOf(LocalDateTime.now().toLocalDate().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli())); } } diff --git a/src/main/java/fr/maxlego08/menu/players/PlayerDataLoader.java b/src/main/java/fr/maxlego08/menu/players/PlayerDataLoader.java index b73aa885..d38091b8 100644 --- a/src/main/java/fr/maxlego08/menu/players/PlayerDataLoader.java +++ b/src/main/java/fr/maxlego08/menu/players/PlayerDataLoader.java @@ -1,6 +1,5 @@ package fr.maxlego08.menu.players; -import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -14,7 +13,6 @@ public class PlayerDataLoader { public static Map> loadPlayerData(String path) throws IOException { Map> result = new HashMap<>(); - Gson gson = new Gson(); JsonObject root = JsonParser.parseReader(new FileReader(path)).getAsJsonObject(); JsonObject players = root.getAsJsonObject("players"); diff --git a/src/main/java/fr/maxlego08/menu/requirement/ZActionPlayerData.java b/src/main/java/fr/maxlego08/menu/requirement/ZActionPlayerData.java index 371cbb72..b0cda485 100644 --- a/src/main/java/fr/maxlego08/menu/requirement/ZActionPlayerData.java +++ b/src/main/java/fr/maxlego08/menu/requirement/ZActionPlayerData.java @@ -20,10 +20,10 @@ public class ZActionPlayerData extends ZUtils implements ActionPlayerData { private final String key; private final ActionPlayerDataType type; private final Object value; - private final long seconds; + private final String seconds; private final boolean enableMathExpression; - public ZActionPlayerData(StorageManager storageManager, String key, ActionPlayerDataType type, Object value, long seconds, boolean enableMathExpression) { + public ZActionPlayerData(StorageManager storageManager, String key, ActionPlayerDataType type, Object value, String seconds, boolean enableMathExpression) { super(); this.storageManager = storageManager; this.key = key; @@ -49,13 +49,19 @@ public Object getValue() { } @Override - public long getSeconds() { + public String getSeconds() { return this.seconds; } @Override public Data toData(OfflinePlayer player) { - long expiredAt = this.seconds == 0 ? 0 : System.currentTimeMillis() + (1000 * this.seconds); + long seconds; + try { + seconds = Long.parseLong(papi(this.seconds,player,false)); + } catch (Exception e) { + seconds = 0; + } + long expiredAt = seconds == 0 ? 0 : System.currentTimeMillis() + (1000 * seconds); String result = papi(this.value.toString(), player, false); String dataValue = this.enableMathExpression ? String.valueOf((int) new ExpressionBuilder(result).build().evaluate()) : result; return new ZData(this.papi(this.key, player, false), dataValue, expiredAt); From 0fdb3739228c8585b3383829199ab52c9ff82e12 Mon Sep 17 00:00:00 2001 From: 1robie Date: Wed, 26 Nov 2025 18:21:24 +0100 Subject: [PATCH 4/5] feat: implement ZMenuItemsLoad event for custom item loading --- .../menu/api/event/events/ZMenuItemsLoad.java | 58 +++++++++++++++++++ .../java/fr/maxlego08/menu/ZItemManager.java | 8 +++ .../menu/placeholder/MenuPlaceholders.java | 1 - 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 API/src/main/java/fr/maxlego08/menu/api/event/events/ZMenuItemsLoad.java diff --git a/API/src/main/java/fr/maxlego08/menu/api/event/events/ZMenuItemsLoad.java b/API/src/main/java/fr/maxlego08/menu/api/event/events/ZMenuItemsLoad.java new file mode 100644 index 00000000..e4abdd12 --- /dev/null +++ b/API/src/main/java/fr/maxlego08/menu/api/event/events/ZMenuItemsLoad.java @@ -0,0 +1,58 @@ +package fr.maxlego08.menu.api.event.events; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +/** + * Called when zMenu custom items are loaded or reloaded. + * This event is fired after all items and their mechanics have been processed. + */ +public class ZMenuItemsLoad extends Event { + + private static final HandlerList HANDLERS = new HandlerList(); + private final Set loadedItemIds; + private final boolean isReload; + + /** + * Constructor for ZMenuItemsLoad event. + * + * @param loadedItemIds Set of all loaded item IDs + * @param isReload true if this is a reload, false if initial load + */ + public ZMenuItemsLoad(@NotNull Set loadedItemIds, boolean isReload) { + this.loadedItemIds = loadedItemIds; + this.isReload = isReload; + } + + /** + * Gets the set of all loaded item IDs. + * + * @return Set of item IDs that were loaded + */ + @NotNull + public Set getLoadedItemIds() { + return loadedItemIds; + } + + /** + * Checks if this event was triggered by a reload. + * + * @return true if this is a reload, false if initial load + */ + public boolean isReload() { + return isReload; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLERS; + } + + @NotNull + public static HandlerList getHandlerList() { + return HANDLERS; + } +} diff --git a/src/main/java/fr/maxlego08/menu/ZItemManager.java b/src/main/java/fr/maxlego08/menu/ZItemManager.java index c198ea1d..2ef3e0b5 100644 --- a/src/main/java/fr/maxlego08/menu/ZItemManager.java +++ b/src/main/java/fr/maxlego08/menu/ZItemManager.java @@ -4,6 +4,7 @@ import fr.maxlego08.menu.api.MenuItemStack; import fr.maxlego08.menu.api.MenuPlugin; import fr.maxlego08.menu.api.configuration.Config; +import fr.maxlego08.menu.api.event.events.ZMenuItemsLoad; import fr.maxlego08.menu.api.mechanic.MechanicFactory; import fr.maxlego08.menu.api.mechanic.MechanicListener; import fr.maxlego08.menu.item.CustomItemData; @@ -39,6 +40,8 @@ public class ZItemManager implements ItemManager{ private final Map customItems = new HashMap<>(); + private boolean isFirstLoad = true; + public ZItemManager(ZMenuPlugin menuPlugin) { this.itemIdKey = new NamespacedKey(menuPlugin, "item-id"); this.ownerKey = new NamespacedKey(menuPlugin, "owner"); @@ -67,6 +70,11 @@ public void loadCustomItems() { } try (Stream stream = Files.walk(Paths.get(itemsFolder.getPath()))) { stream.skip(1).map(Path::toFile).filter(File::isFile).filter(e -> e.getName().endsWith(".yml")).forEach(this::loadCustomItem); + ZMenuItemsLoad event = new ZMenuItemsLoad(new HashSet<>(customItems.keySet()), !isFirstLoad); + menuPlugin.getServer().getPluginManager().callEvent(event); + if (isFirstLoad) { + isFirstLoad = false; + } } catch (IOException exception) { if (Config.enableDebug){ Logger.info("Error while loading items: " + exception.getMessage(), Logger.LogType.ERROR); diff --git a/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java b/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java index 94c305c4..429ffd74 100644 --- a/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java +++ b/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java @@ -54,5 +54,4 @@ public void register(MenuPlugin plugin) { placeholder.register("time_next_day_unix_timestamp",(player,args)-> String.valueOf(LocalDateTime.now().toLocalDate().plusDays(1L).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli())); placeholder.register("time_today_start_unix_timestamp",(player,args)-> String.valueOf(LocalDateTime.now().toLocalDate().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli())); } - } From 3a2a96e55fda848d2668875b34d6de88b93ac67a Mon Sep 17 00:00:00 2001 From: 1robie Date: Mon, 1 Dec 2025 11:47:22 +0100 Subject: [PATCH 5/5] feat: enhance action execution with deny chance actions and update data handling --- .../menu/api/requirement/Action.java | 21 +++++++++++++++++- .../requirement/data/ActionPlayerData.java | 11 ++++++++++ .../menu/api/utils/TypedMapAccessor.java | 9 ++++++++ build.gradle.kts | 2 +- .../fr/maxlego08/menu/ZButtonManager.java | 7 ++++++ .../menu/requirement/ZActionPlayerData.java | 22 ++++++++++++++----- .../menu/requirement/actions/DataAction.java | 2 +- 7 files changed, 65 insertions(+), 9 deletions(-) diff --git a/API/src/main/java/fr/maxlego08/menu/api/requirement/Action.java b/API/src/main/java/fr/maxlego08/menu/api/requirement/Action.java index bc9c66df..ce0a0491 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/requirement/Action.java +++ b/API/src/main/java/fr/maxlego08/menu/api/requirement/Action.java @@ -20,6 +20,7 @@ public abstract class Action { */ private int delay; private float chance; + private final List denyChanceActions = new ArrayList<>(); /** * Executes the action for the specified player. @@ -33,7 +34,12 @@ public abstract class Action { public void preExecute(Player player, Button button, InventoryEngine inventoryEngine, Placeholders placeholders) { placeholders.register("player", player.getName()); - if (chance < 100 && Math.random() > (chance / 100.0f)) return; + if (chance < 100 && Math.random() > (chance / 100.0f)){ + for (Action denyChanceAction : denyChanceActions){ + denyChanceAction.preExecute(player, button, inventoryEngine, placeholders); + } + return; + }; if (delay == 0) execute(player, button, inventoryEngine, placeholders); else { inventoryEngine.getPlugin().getScheduler().runAtEntityLater(player, () -> execute(player, button, inventoryEngine, placeholders), this.delay); @@ -48,6 +54,7 @@ public void setDelay(int delay) { this.delay = delay; } + @SuppressWarnings("unused") public float getChance() {return chance;} public void setChance(float chance) { @@ -60,6 +67,18 @@ public void setChance(float chance) { this.chance = chance; } + @SuppressWarnings("unused") + public List getDenyChanceActions() { + return denyChanceActions; + } + + public void setDenyChanceActions(List denyChanceActions) { + this.denyChanceActions.clear(); + if (denyChanceActions != null) { + this.denyChanceActions.addAll(denyChanceActions); + } + } + /** * Parses and flattens a list of commands by splitting each command by newline, replacing a * placeholder with the player's name, and returning a flattened list of processed commands. diff --git a/API/src/main/java/fr/maxlego08/menu/api/requirement/data/ActionPlayerData.java b/API/src/main/java/fr/maxlego08/menu/api/requirement/data/ActionPlayerData.java index 60b8dd45..dc19ccd4 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/requirement/data/ActionPlayerData.java +++ b/API/src/main/java/fr/maxlego08/menu/api/requirement/data/ActionPlayerData.java @@ -2,6 +2,7 @@ import fr.maxlego08.menu.api.players.Data; import fr.maxlego08.menu.api.players.DataManager; +import fr.maxlego08.menu.api.utils.Placeholders; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; @@ -40,17 +41,27 @@ public interface ActionPlayerData { /** * Converts the action into player data. + *

+ * DEPRECATED: Use {@link #toData(OfflinePlayer, Placeholders)} instead. * * @param player The player for whom the data is created. * @return The {@link Data}. */ + @Deprecated(since = "1.1.0.6") Data toData(OfflinePlayer player); + Data toData(OfflinePlayer player, Placeholders placeholders); + /** * Executes the action when the player clicks. + *

+ * DEPRECATED: Use {@link #execute(Player, DataManager, Placeholders)} instead. * * @param player The player who executes the action. * @param dataManager The {@link DataManager}. */ + @Deprecated(since = "1.1.0.6") void execute(Player player, DataManager dataManager); + + void execute(Player player, DataManager dataManager, Placeholders placeholders); } diff --git a/API/src/main/java/fr/maxlego08/menu/api/utils/TypedMapAccessor.java b/API/src/main/java/fr/maxlego08/menu/api/utils/TypedMapAccessor.java index 76bc88a9..5239bcd3 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/utils/TypedMapAccessor.java +++ b/API/src/main/java/fr/maxlego08/menu/api/utils/TypedMapAccessor.java @@ -324,4 +324,13 @@ public String toString() { "map=" + map + '}'; } + + @SuppressWarnings("unchecked") + public List> getMapList(String key) { + try { + return (List>) map.getOrDefault(key, new ArrayList>()); + } catch (ClassCastException e){ + return new ArrayList<>(); + } + } } diff --git a/build.gradle.kts b/build.gradle.kts index 820e1e33..9b4dcb79 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "fr.maxlego08.menu" -version = "1.1.0.5" +version = "1.1.0.6" extra.set("targetFolder", file("target/")) extra.set("apiFolder", file("target-api/")) diff --git a/src/main/java/fr/maxlego08/menu/ZButtonManager.java b/src/main/java/fr/maxlego08/menu/ZButtonManager.java index 593cbb11..92e433f5 100644 --- a/src/main/java/fr/maxlego08/menu/ZButtonManager.java +++ b/src/main/java/fr/maxlego08/menu/ZButtonManager.java @@ -175,6 +175,13 @@ public List loadActions(List> elements, String path, if (action != null) { action.setDelay(accessor.getInt("delay", 0)); action.setChance(accessor.getFloat("chance", 100)); + List> denyChanceAction = accessor.getMapList("deny-chance-actions"); + if (!denyChanceAction.isEmpty()) { + List denyActions = loadActions(denyChanceAction, path + ".deny-chance-actions", file); + if (!denyActions.isEmpty()) { + action.setDenyChanceActions(denyActions); + } + } actions.add(action); } } else { diff --git a/src/main/java/fr/maxlego08/menu/requirement/ZActionPlayerData.java b/src/main/java/fr/maxlego08/menu/requirement/ZActionPlayerData.java index b0cda485..574ed58a 100644 --- a/src/main/java/fr/maxlego08/menu/requirement/ZActionPlayerData.java +++ b/src/main/java/fr/maxlego08/menu/requirement/ZActionPlayerData.java @@ -6,6 +6,7 @@ import fr.maxlego08.menu.api.requirement.data.ActionPlayerData; import fr.maxlego08.menu.api.requirement.data.ActionPlayerDataType; import fr.maxlego08.menu.api.storage.StorageManager; +import fr.maxlego08.menu.api.utils.Placeholders; import fr.maxlego08.menu.players.ZData; import fr.maxlego08.menu.zcore.utils.ZUtils; import net.objecthunter.exp4j.ExpressionBuilder; @@ -55,6 +56,11 @@ public String getSeconds() { @Override public Data toData(OfflinePlayer player) { + return toData(player, new Placeholders()); + } + + @Override + public Data toData(OfflinePlayer player, Placeholders placeholders) { long seconds; try { seconds = Long.parseLong(papi(this.seconds,player,false)); @@ -62,7 +68,7 @@ public Data toData(OfflinePlayer player) { seconds = 0; } long expiredAt = seconds == 0 ? 0 : System.currentTimeMillis() + (1000 * seconds); - String result = papi(this.value.toString(), player, false); + String result = placeholders.parse(papi(this.value.toString(), player, false)); String dataValue = this.enableMathExpression ? String.valueOf((int) new ExpressionBuilder(result).build().evaluate()) : result; return new ZData(this.papi(this.key, player, false), dataValue, expiredAt); } @@ -77,7 +83,11 @@ public String toString() { @Override public void execute(Player player, DataManager dataManager) { + execute(player, dataManager, new Placeholders()); + } + @Override + public void execute(Player player, DataManager dataManager, Placeholders placeholders) { if (this.type == ActionPlayerDataType.REMOVE) { Optional optional = dataManager.getPlayer(player.getUniqueId()); @@ -87,27 +97,27 @@ public void execute(Player player, DataManager dataManager) { Optional optional = dataManager.getData(player.getUniqueId(), this.papi(this.key, player, false)); if (optional.isPresent()) { Data data = optional.get(); - String result = papi(this.value.toString(), player, false); + String result = placeholders.parse(papi(this.value.toString(), player, false)); data.add(this.enableMathExpression ? (int) new ExpressionBuilder(result).build().evaluate() : Integer.parseInt(result)); storageManager.upsertData(player.getUniqueId(), data); } else { - dataManager.addData(player.getUniqueId(), this.toData(player)); + dataManager.addData(player.getUniqueId(), this.toData(player,placeholders)); } } else if (this.type == ActionPlayerDataType.SUBTRACT) { Optional optional = dataManager.getData(player.getUniqueId(), this.papi(this.key, player, false)); if (optional.isPresent()) { Data data = optional.get(); - String result = papi(this.value.toString(), player, false); + String result = placeholders.parse(papi(this.value.toString(), player, false)); data.remove(this.enableMathExpression ? (int) new ExpressionBuilder(result).build().evaluate() : Integer.parseInt(result)); storageManager.upsertData(player.getUniqueId(), data); } else { - var data = this.toData(player); + var data = this.toData(player,placeholders); data.negate(); dataManager.addData(player.getUniqueId(), data); } } else if (this.type == ActionPlayerDataType.SET) { - dataManager.addData(player.getUniqueId(), this.toData(player)); + dataManager.addData(player.getUniqueId(), this.toData(player,placeholders)); } } } diff --git a/src/main/java/fr/maxlego08/menu/requirement/actions/DataAction.java b/src/main/java/fr/maxlego08/menu/requirement/actions/DataAction.java index decb5727..a15526d8 100644 --- a/src/main/java/fr/maxlego08/menu/requirement/actions/DataAction.java +++ b/src/main/java/fr/maxlego08/menu/requirement/actions/DataAction.java @@ -20,6 +20,6 @@ public DataAction(ActionPlayerData playerData, MenuPlugin plugin) { @Override protected void execute(Player player, Button button, InventoryEngine inventory, Placeholders placeholders) { - this.playerData.execute(player, this.plugin.getDataManager()); + this.playerData.execute(player, this.plugin.getDataManager(),placeholders); } }