Page MenuHomeDevCentral

D3647.diff
No OneTemporary

D3647.diff

diff --git a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/SuhaylPlugin.java b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/SuhaylPlugin.java
--- a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/SuhaylPlugin.java
+++ b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/SuhaylPlugin.java
@@ -3,27 +3,48 @@
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
-import org.eu.loupsgris.quilvaryn.config.DefaultSuhaylConfig;
import org.eu.loupsgris.quilvaryn.config.SuhaylConfig;
+import org.eu.loupsgris.quilvaryn.items.CommandmentStick;
import org.eu.loupsgris.quilvaryn.listeners.HappyGhastBehavior;
import org.eu.loupsgris.quilvaryn.listeners.OptimizedWeather;
+import org.eu.loupsgris.quilvaryn.listeners.WanderingTraderBehavior;
+import org.eu.loupsgris.quilvaryn.menus.WanderingTraderMenu;
+import org.eu.loupsgris.quilvaryn.services.WanderingTraderService;
public class SuhaylPlugin extends JavaPlugin {
public SuhaylConfig config;
+ public static String NAMESPACE = "suhayl";
+
@Override
public void onEnable() {
- config = new DefaultSuhaylConfig();
+ config = SuhaylConfig.Load(this.getConfig());
// Register features
Bukkit.getPluginManager().registerEvents(new OptimizedWeather(this), this);
Bukkit.getPluginManager().registerEvents(new HappyGhastBehavior(this), this);
+
+ registerCommandmentStick();
+ }
+
+ private void registerCommandmentStick() {
+ WanderingTraderService service = new WanderingTraderService(config, getLogger());
+
+ WanderingTraderMenu menu = new WanderingTraderMenu(service, config);
+ Bukkit.getPluginManager().registerEvents(menu, this);
+
+ WanderingTraderBehavior listener = new WanderingTraderBehavior(
+ service,
+ menu
+ );
+ Bukkit.getPluginManager().registerEvents(listener, this);
+
+ Bukkit.addRecipe(CommandmentStick.getRecipe());
}
@Override
public void onDisable() {
getLogger().info("Suhayl quality of life plugin disabled.");
}
-
}
diff --git a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/config/DefaultSuhaylConfig.java b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/config/DefaultSuhaylConfig.java
deleted file mode 100644
--- a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/config/DefaultSuhaylConfig.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.eu.loupsgris.quilvaryn.config;
-
-public class DefaultSuhaylConfig extends SuhaylConfig {
-
- public DefaultSuhaylConfig() {
- happyGhastSpeedBoost = 2.0;
- rainRate = 0.7;
- }
-
-}
diff --git a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/config/SuhaylConfig.java b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/config/SuhaylConfig.java
--- a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/config/SuhaylConfig.java
+++ b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/config/SuhaylConfig.java
@@ -1,10 +1,17 @@
package org.eu.loupsgris.quilvaryn.config;
+import org.bukkit.configuration.file.FileConfiguration;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
public class SuhaylConfig {
/*
* No-op values:
- * 1.0 for multipliers
+ * 1.0 for multipliers.
+ * 0.0 for cooldown delays.
*
* Actual default values are in Default- class.
*/
@@ -13,4 +20,50 @@
public double rainRate = 1.0;
+ public int commandmentStickBanTime = 0;
+
+ public Map<String, String> commandmentStickMessages = new HashMap<>();
+
+ public static SuhaylConfig Load (FileConfiguration inFileConfig) {
+ SuhaylConfig loadedConfig = new SuhaylConfig();
+
+ SuhaylConfig defaultConfig = new SuhaylConfig();
+ defaultConfig.setDefault();
+
+ loadedConfig.commandmentStickBanTime = inFileConfig.getInt(
+ "commandment-stick.banish-minutes",
+ defaultConfig.commandmentStickBanTime
+ );
+
+ Object value = inFileConfig.get("commandment-stick.messages");
+ if (value instanceof Map messages) {
+ try {
+ loadedConfig.commandmentStickMessages = messages;
+ } catch (Exception ignored) {
+ }
+ }
+
+ return loadedConfig;
+ }
+
+ public String getCommandmentStickMessage(String key, String defaultMessage) {
+ return commandmentStickMessages.getOrDefault(key, defaultMessage);
+ }
+
+ public Optional<String> getCommandmentStickMessage(String key) {
+ if (!commandmentStickMessages.containsKey(key)) {
+ return Optional.empty();
+ }
+
+ return Optional.of(commandmentStickMessages.get(key));
+ }
+
+ public void setDefault() {
+ happyGhastSpeedBoost = 2.0;
+
+ rainRate = 0.7;
+
+ commandmentStickBanTime = 20;
+ }
+
}
diff --git a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/items/CommandmentStick.java b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/items/CommandmentStick.java
new file mode 100644
--- /dev/null
+++ b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/items/CommandmentStick.java
@@ -0,0 +1,80 @@
+package org.eu.loupsgris.quilvaryn.items;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.NamedTextColor;
+
+import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.ShapedRecipe;
+
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.persistence.PersistentDataContainer;
+import org.bukkit.persistence.PersistentDataType;
+import org.eu.loupsgris.quilvaryn.SuhaylPlugin;
+
+import java.util.List;
+
+public class CommandmentStick {
+
+ public static String ITEM_TAG = "is_commandment_stick";
+
+ public static ItemStack getItem() {
+ ItemStack item = new ItemStack(Material.BLAZE_ROD);
+
+ item.editMeta(meta -> {
+ // Gold is uncommon
+ meta.customName(
+ Component.text("Commandment Stick", NamedTextColor.GOLD)
+ );
+
+ meta.lore(List.of(
+ Component.text("§7Right-click a Wandering Trader"),
+ Component.text("§7to give them instructions.")
+ ));
+
+ NamespacedKey key = new NamespacedKey(SuhaylPlugin.NAMESPACE, ITEM_TAG);
+ meta.getPersistentDataContainer()
+ .set(key, PersistentDataType.BOOLEAN, true);
+
+ meta.setMaxStackSize(1);
+ });
+
+ return item;
+ }
+
+ public static Boolean isItem(ItemStack item) {
+ if (item.getType() != Material.BLAZE_ROD || !item.hasItemMeta()) {
+ return false;
+ }
+
+ ItemMeta meta = item.getItemMeta();
+ PersistentDataContainer pdc = meta.getPersistentDataContainer();
+
+ NamespacedKey key = new NamespacedKey(SuhaylPlugin.NAMESPACE, ITEM_TAG);
+ return
+ pdc.has(key, PersistentDataType.BOOLEAN)
+ &&
+ pdc.get(key, PersistentDataType.BOOLEAN);
+ }
+
+ public static ShapedRecipe getRecipe () {
+ NamespacedKey key = new NamespacedKey(
+ SuhaylPlugin.NAMESPACE, "commandment_stick"
+ );
+ ItemStack item = getItem();
+
+ ShapedRecipe recipe = new ShapedRecipe(key, item);
+ recipe.shape(
+ " G ",
+ " P ",
+ " S "
+ );
+ recipe.setIngredient('G', Material.GOLD_NUGGET);
+ recipe.setIngredient('P', Material.PAPER);
+ recipe.setIngredient('S', Material.STICK);
+
+ return recipe;
+ }
+
+}
diff --git a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/listeners/WanderingTraderBehavior.java b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/listeners/WanderingTraderBehavior.java
new file mode 100644
--- /dev/null
+++ b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/listeners/WanderingTraderBehavior.java
@@ -0,0 +1,61 @@
+package org.eu.loupsgris.quilvaryn.listeners;
+
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.event.player.PlayerInteractAtEntityEvent;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+
+import org.eu.loupsgris.quilvaryn.items.CommandmentStick;
+import org.eu.loupsgris.quilvaryn.menus.WanderingTraderMenu;
+import org.eu.loupsgris.quilvaryn.services.WanderingTraderService;
+
+import java.util.UUID;
+
+public class WanderingTraderBehavior implements Listener {
+
+ private final WanderingTraderService service;
+
+ private final WanderingTraderMenu menu;
+
+ public WanderingTraderBehavior(WanderingTraderService service, WanderingTraderMenu menu) {
+ this.service = service;
+ this.menu = menu;
+ }
+
+ @EventHandler
+ public void onTraderSpawn(CreatureSpawnEvent event) {
+ if (event.getEntityType() != EntityType.WANDERING_TRADER) {
+ return;
+ }
+
+ if (!service.canTradersVisit()) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void onUseStick(PlayerInteractAtEntityEvent event) {
+ if (event.getRightClicked().getType() != EntityType.WANDERING_TRADER) {
+ return;
+ }
+
+ if (event.getHand() != EquipmentSlot.HAND) return;
+
+ Player player = event.getPlayer();
+ ItemStack item = player.getInventory().getItemInMainHand();
+
+ if (!CommandmentStick.isItem(item)) {
+ return;
+ }
+
+ event.setCancelled(true);
+
+ UUID traderId = event.getRightClicked().getUniqueId();
+ menu.openFor(player, traderId);
+ }
+
+}
diff --git a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/menus/WanderingTraderMenu.java b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/menus/WanderingTraderMenu.java
new file mode 100644
--- /dev/null
+++ b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/menus/WanderingTraderMenu.java
@@ -0,0 +1,113 @@
+package org.eu.loupsgris.quilvaryn.menus;
+
+import net.kyori.adventure.text.Component;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryCloseEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+
+import org.eu.loupsgris.quilvaryn.config.SuhaylConfig;
+import org.eu.loupsgris.quilvaryn.services.WanderingTraderService;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class WanderingTraderMenu implements Listener {
+
+ private final WanderingTraderService service;
+
+ private final Map<UUID, UUID> openMenus;
+
+ private final String title;
+
+ private final String labelLeave;
+
+ private final String labelBanish;
+
+ private final String labelSilence;
+
+ public WanderingTraderMenu (WanderingTraderService service, SuhaylConfig config) {
+ this.service = service;
+
+ openMenus = new HashMap<>();
+
+ title = config.getCommandmentStickMessage("menu-title", "#WANDERING_TRADER_MENU_TITLE");
+
+ labelLeave = config.getCommandmentStickMessage("option-leave", "#OPTION_LEAVE");
+ labelBanish = config.getCommandmentStickMessage("option-banish", "#OPTION_BANISH");
+ labelSilence = config.getCommandmentStickMessage("option-silence", "#OPTION_SIlENCE");
+ }
+
+ public void openFor(Player player, UUID traderId) {
+ Inventory inventory = Bukkit.createInventory(player, 9, title);
+
+ inventory.setItem(2, buildButton(Material.LIME_DYE, labelLeave));
+ inventory.setItem(4, buildButton(Material.CLOCK, labelBanish));
+ inventory.setItem(6, buildButton(Material.MUSIC_DISC_13, labelSilence));
+
+ openMenus.put(player.getUniqueId(), traderId);
+
+ player.openInventory(inventory);
+ }
+
+ private ItemStack buildButton(Material material, String name) {
+ ItemStack item = new ItemStack(material);
+
+ item.editMeta(meta -> {
+ meta.displayName(
+ Component.text(name)
+ );
+ });
+
+ return item;
+ }
+
+ @EventHandler
+ public void onClick(InventoryClickEvent event) {
+ if (!(event.getWhoClicked() instanceof Player player)) {
+ return;
+ }
+
+ if (!event.getView().getTitle().equals(title)) {
+ return;
+ }
+
+ event.setCancelled(true);
+
+ UUID traderId = openMenus.get(player.getUniqueId());
+ if (traderId == null) {
+ return;
+ }
+
+ var current = event.getCurrentItem();
+ if (current == null || !current.hasItemMeta()) {
+ return;
+ }
+ String name = current.getItemMeta().getDisplayName();
+
+ if (name.equals(labelLeave)) {
+ service.askToLeave(player, traderId);
+ player.closeInventory();
+ } else if (name.equals(labelBanish)) {
+ service.banish(player, traderId);
+ player.closeInventory();
+ } else if (name.equals(labelSilence)) {
+ service.toggleSilence(player, traderId);
+ }
+ }
+
+ @EventHandler
+ public void onClose(InventoryCloseEvent e) {
+ if (e.getView().getTitle().equals(title)) {
+ openMenus.remove(e.getPlayer().getUniqueId());
+ }
+ }
+
+}
diff --git a/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/services/WanderingTraderService.java b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/services/WanderingTraderService.java
new file mode 100644
--- /dev/null
+++ b/plugins/suhayl/src/main/java/org/eu/loupsgris/quilvaryn/services/WanderingTraderService.java
@@ -0,0 +1,101 @@
+package org.eu.loupsgris.quilvaryn.services;
+
+import org.bukkit.World;
+import org.bukkit.entity.*;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+
+import org.eu.loupsgris.quilvaryn.config.SuhaylConfig;
+
+import java.util.UUID;
+import java.util.logging.Logger;
+
+public class WanderingTraderService {
+
+ private final SuhaylConfig config;
+
+ private final Logger logger;
+
+ private long banishUntil = 0L;
+
+ public WanderingTraderService(SuhaylConfig config, Logger logger) {
+ this.config = config;
+ this.logger = logger;
+ }
+
+ public void askToLeave(Player requester, UUID traderId) {
+ World world = requester.getWorld();
+ Entity entity = world.getEntity(traderId);
+ if (!(entity instanceof WanderingTrader trader)) {
+ logger.info("Potential plugin issue - askToLeave called on non wandering trader");
+ return;
+ }
+
+ // Brief particles and invisibility before removal
+ // That allows to render the disapproval of the trader of the request
+ trader.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, 40, 1, true, false, false));
+
+ removeLeashedTraderLlamas(trader);
+ trader.remove();
+
+ logger.info("Wandering trader removed.");
+ }
+
+ public void banish(Player requester, UUID traderId) {
+ askToLeave(requester, traderId);
+
+ int banTime = this.config.commandmentStickBanTime;
+ banishUntil = System.currentTimeMillis() + banTime * 60_000L;
+
+ requester.sendMessage("§7Wandering traders are discouraged from visiting for a while.");
+ }
+
+ public void toggleSilence(Player requester, UUID traderId) {
+ World world = requester.getWorld();
+ Entity entity = world.getEntity(traderId);
+ if (!(entity instanceof WanderingTrader trader)) {
+ logger.info("Potential plugin issue - toggleSilence called on non wandering trader");
+ return;
+ }
+
+ if (trader.isSilent()) {
+ trader.setSilent(false);
+ sendMessageToPlayer(requester, "silenced");
+ } else {
+ // Shhh!
+ trader.setSilent(true);
+ sendMessageToPlayer(requester, "unsilenced");
+ }
+ }
+
+ private void sendMessageToPlayer(Player player, String messageKey) {
+ config
+ .getCommandmentStickMessage(messageKey)
+ .ifPresent(player::sendMessage);
+ }
+
+ private void removeLeashedTraderLlamas(WanderingTrader trader) {
+ trader
+ .getWorld()
+ .getNearbyEntities(trader.getLocation(), 16, 16, 16)
+ .forEach(this::tryToRemoveLlama);
+ }
+
+ private void tryToRemoveLlama(Entity entity) {
+ if (!(entity instanceof TraderLlama llama)) {
+ return;
+ }
+
+ if (isUnderTraderControl(llama)) {
+ llama.remove();
+ }
+ }
+
+ private boolean isUnderTraderControl(TraderLlama llama) {
+ return llama.isLeashed() && llama.getLeashHolder() instanceof WanderingTrader;
+ }
+
+ public boolean canTradersVisit() {
+ return System.currentTimeMillis() > banishUntil;
+ }
+}
diff --git a/plugins/suhayl/src/main/resources/config.yml b/plugins/suhayl/src/main/resources/config.yml
new file mode 100644
--- /dev/null
+++ b/plugins/suhayl/src/main/resources/config.yml
@@ -0,0 +1,11 @@
+commandment-stick:
+ banish-minutes: 120
+ messages:
+ menu-title: "Trader Etiquette"
+ option-leave: "All business is done, you can leave."
+ option-banish: "Come back later. No more trader this week."
+ option-silence: "Shhh… be quiet."
+
+ left-message: "§aThe trader nods and drifts away…"
+ silenced: "§7The trader goes quiet."
+ unsilenced: "§7The trader finds their voice again."

File Metadata

Mime Type
text/plain
Expires
Tue, Aug 26, 20:04 (7 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2936061
Default Alt Text
D3647.diff (17 KB)

Event Timeline