From 5dd6cb44e51b78b126d92a64d81341c156ae815e Mon Sep 17 00:00:00 2001 From: Teriuihi Date: Sat, 25 Sep 2021 01:56:42 +0200 Subject: [PATCH] Initial commit --- .gitignore | 51 +++++++ pom.xml | 51 +++++++ src/main/java/com/alttd/GUI/GUI.java | 20 +++ src/main/java/com/alttd/GUI/GUIAction.java | 7 + src/main/java/com/alttd/GUI/GUIInventory.java | 50 +++++++ src/main/java/com/alttd/GUI/GUIListener.java | 84 +++++++++++ src/main/java/com/alttd/GUI/GUIMerchant.java | 61 ++++++++ .../java/com/alttd/GUI/windows/BuyGUI.java | 45 ++++++ .../java/com/alttd/GUI/windows/OpenGUI.java | 40 ++++++ .../java/com/alttd/GUI/windows/SellGUI.java | 45 ++++++ src/main/java/com/alttd/VillagerUI.java | 41 ++++++ .../com/alttd/commands/CommandManager.java | 92 ++++++++++++ .../java/com/alttd/commands/SubCommand.java | 31 ++++ .../subcommands/CommandCreateVillager.java | 115 +++++++++++++++ .../commands/subcommands/CommandHelp.java | 50 +++++++ .../commands/subcommands/CommandReload.java | 37 +++++ .../subcommands/CommandRemoveVillager.java | 4 + .../java/com/alttd/config/AbstractConfig.java | 132 ++++++++++++++++++ src/main/java/com/alttd/config/Config.java | 110 +++++++++++++++ .../java/com/alttd/config/VillagerConfig.java | 44 ++++++ .../java/com/alttd/config/WorthConfig.java | 47 +++++++ .../java/com/alttd/economy/Calculation.java | 67 +++++++++ .../com/alttd/events/VillagerInteract.java | 24 ++++ .../com/alttd/objects/LoadedVillagers.java | 25 ++++ .../java/com/alttd/objects/VillagerType.java | 59 ++++++++ src/main/java/com/alttd/util/Utilities.java | 25 ++++ src/main/resources/plugin.yml | 9 ++ 27 files changed, 1366 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/com/alttd/GUI/GUI.java create mode 100644 src/main/java/com/alttd/GUI/GUIAction.java create mode 100644 src/main/java/com/alttd/GUI/GUIInventory.java create mode 100644 src/main/java/com/alttd/GUI/GUIListener.java create mode 100644 src/main/java/com/alttd/GUI/GUIMerchant.java create mode 100644 src/main/java/com/alttd/GUI/windows/BuyGUI.java create mode 100644 src/main/java/com/alttd/GUI/windows/OpenGUI.java create mode 100644 src/main/java/com/alttd/GUI/windows/SellGUI.java create mode 100644 src/main/java/com/alttd/VillagerUI.java create mode 100644 src/main/java/com/alttd/commands/CommandManager.java create mode 100644 src/main/java/com/alttd/commands/SubCommand.java create mode 100644 src/main/java/com/alttd/commands/subcommands/CommandCreateVillager.java create mode 100644 src/main/java/com/alttd/commands/subcommands/CommandHelp.java create mode 100644 src/main/java/com/alttd/commands/subcommands/CommandReload.java create mode 100644 src/main/java/com/alttd/commands/subcommands/CommandRemoveVillager.java create mode 100644 src/main/java/com/alttd/config/AbstractConfig.java create mode 100644 src/main/java/com/alttd/config/Config.java create mode 100644 src/main/java/com/alttd/config/VillagerConfig.java create mode 100644 src/main/java/com/alttd/config/WorthConfig.java create mode 100644 src/main/java/com/alttd/economy/Calculation.java create mode 100644 src/main/java/com/alttd/events/VillagerInteract.java create mode 100644 src/main/java/com/alttd/objects/LoadedVillagers.java create mode 100644 src/main/java/com/alttd/objects/VillagerType.java create mode 100644 src/main/java/com/alttd/util/Utilities.java create mode 100644 src/main/resources/plugin.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e9be105 --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# +.idea +run + +.gradle/ +build/ + +# Eclipse stuff +.classpath +.project +.settings/ + +# VSCode stuff +.vscode/ + +# netbeans +nbproject/ +nbactions.xml + +# we use maven! +build.xml + +# maven +target/ +dependency-reduced-pom.xml + +# vim +.*.sw[a-p] + +# various other potential build files +build/ +bin/ +dist/ +manifest.mf + +# Mac filesystem dust +.DS_Store/ +.DS_Store + +# intellij +*.iml +*.ipr +*.iws +.idea/ +out/ + +# Linux temp files +*~ + +!gradle/wrapper/gradle-wrapper.jar +build.bat diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..0a817a3 --- /dev/null +++ b/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + org.example + VillagerShopUI + 1.0-SNAPSHOT + + + 16 + 16 + + + + + papermc + https://papermc.io/repo/repository/maven-public/ + + + sonatype-oss-snapshots + https://oss.sonatype.org/content/repositories/snapshots/ + + + jitpack.io + https://jitpack.io + + + + + + io.papermc.paper + paper-api + 1.17-R0.1-SNAPSHOT + provided + + + net.kyori + adventure-text-minimessage + 4.1.0-SNAPSHOT + + + com.github.MilkBowl + VaultAPI + 1.7 + provided + + + + \ No newline at end of file diff --git a/src/main/java/com/alttd/GUI/GUI.java b/src/main/java/com/alttd/GUI/GUI.java new file mode 100644 index 0000000..150d66c --- /dev/null +++ b/src/main/java/com/alttd/GUI/GUI.java @@ -0,0 +1,20 @@ +package com.alttd.GUI; + +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.Merchant; + +import java.util.HashMap; +import java.util.UUID; + +public interface GUI { + HashMap GUIByUUID = new HashMap<>(); + + void open(Player player); + + GUIAction getAction(int slot); + + Inventory getInventory(); + + Merchant getMerchant(); +} diff --git a/src/main/java/com/alttd/GUI/GUIAction.java b/src/main/java/com/alttd/GUI/GUIAction.java new file mode 100644 index 0000000..3a1c6d2 --- /dev/null +++ b/src/main/java/com/alttd/GUI/GUIAction.java @@ -0,0 +1,7 @@ +package com.alttd.GUI; + +import org.bukkit.entity.Player; + +public interface GUIAction { + void click(Player player); +} diff --git a/src/main/java/com/alttd/GUI/GUIInventory.java b/src/main/java/com/alttd/GUI/GUIInventory.java new file mode 100644 index 0000000..16ea63a --- /dev/null +++ b/src/main/java/com/alttd/GUI/GUIInventory.java @@ -0,0 +1,50 @@ +package com.alttd.GUI; + +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.Merchant; + +import java.util.HashMap; + +public abstract class GUIInventory implements GUI { + + protected final Inventory inventory; + protected final HashMap actions; + + public GUIInventory(InventoryType type, Component name) { + inventory = Bukkit.createInventory(null, type, name); + actions = new HashMap<>(); + } + + public Merchant getMerchant() { + return null; + } + + public Inventory getInventory() { + return inventory; + } + + public void setItem(int slot, ItemStack stack, GUIAction action){ + inventory.setItem(slot, stack); + if (action != null){ + actions.put(slot, action); + } + } + + public void setItem(int slot, ItemStack stack){ + setItem(slot, stack, null); + } + + public void open(Player player){ + player.openInventory(inventory); + GUIByUUID.put(player.getUniqueId(), this); + } + + public GUIAction getAction(int slot) { + return actions.get(slot); + } +} diff --git a/src/main/java/com/alttd/GUI/GUIListener.java b/src/main/java/com/alttd/GUI/GUIListener.java new file mode 100644 index 0000000..c8c173c --- /dev/null +++ b/src/main/java/com/alttd/GUI/GUIListener.java @@ -0,0 +1,84 @@ +package com.alttd.GUI; + +import net.kyori.adventure.text.minimessage.MiniMessage; +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.event.inventory.InventoryType; +import org.bukkit.event.inventory.TradeSelectEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MerchantRecipe; + +public class GUIListener implements Listener { + + @EventHandler + public void onClick(InventoryClickEvent event){ + if (!(event.getWhoClicked() instanceof Player player)){ + return; + } + + GUI gui = GUI.GUIByUUID.get(player.getUniqueId()); + if (gui == null || gui.getInventory() == null) { + if (event.getSlotType().equals(InventoryType.SlotType.CRAFTING) && event.getRawSlot() < 2) + event.setCancelled(true); + else if (event.getRawSlot() == 2 && event.getSlotType().equals(InventoryType.SlotType.RESULT)) { + event.setCancelled(true); + onResultSlotClick(event, gui); + } + return; + } + if (!gui.getInventory().equals(event.getInventory())) { + return; + } + event.setCancelled(true); + GUIAction action = gui.getAction(event.getSlot()); + + if (action != null){ + action.click(player); + } + } + + private void onResultSlotClick(InventoryClickEvent event, GUI gui) { + ItemStack currentItem = event.getCurrentItem(); + if (currentItem == null) + return; + if (event.getClick().isShiftClick()) + event.getWhoClicked().sendMessage(MiniMessage.get().parse(currentItem.getType().name() + ": " + event.getCurrentItem().getType().getMaxStackSize())); + else + event.getWhoClicked().sendMessage(MiniMessage.get().parse(currentItem.getType().name() + ": " + event.getCurrentItem().getAmount())); + } + + @EventHandler + public void onTradeSelect(TradeSelectEvent event) { + if (!(event.getWhoClicked() instanceof Player player)){ + return; + } + + GUI gui = GUI.GUIByUUID.get(player.getUniqueId()); + if ((!(gui instanceof GUIMerchant guiMerchant))) + return; + if (!gui.getMerchant().equals(event.getMerchant())) { + return; + } + event.setCancelled(true); + GUIAction action = guiMerchant.getAction(event.getIndex()); + + if (action != null){ + action.click(player); + } + } + + @EventHandler + public void onClose(InventoryCloseEvent event) { + GUI.GUIByUUID.remove(event.getPlayer().getUniqueId()); + } + + @EventHandler + public void onQuit(PlayerQuitEvent event){ + GUI.GUIByUUID.remove(event.getPlayer().getUniqueId()); + } + +} diff --git a/src/main/java/com/alttd/GUI/GUIMerchant.java b/src/main/java/com/alttd/GUI/GUIMerchant.java new file mode 100644 index 0000000..c999083 --- /dev/null +++ b/src/main/java/com/alttd/GUI/GUIMerchant.java @@ -0,0 +1,61 @@ +package com.alttd.GUI; + +import com.alttd.objects.VillagerType; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.HashMap; + +public abstract class GUIMerchant implements GUI{ + + protected final Merchant merchant; + protected final HashMap actions; + private final VillagerType villagerType; + + public GUIMerchant(Component name, VillagerType villagerType) { + merchant = Bukkit.createMerchant(name); + actions = new HashMap<>(); + this.villagerType = villagerType; + } + + public Merchant getMerchant() { + return merchant; + } + + public Inventory getInventory() { + return null; + } + + public void addItem(@NotNull ItemStack result, @NotNull ItemStack one, @Nullable ItemStack two, @Nullable GUIAction action){ + MerchantRecipe merchantRecipe = new MerchantRecipe(result, 0, 10000, false, 0, 0); + merchantRecipe.addIngredient(one); + if (two != null) + merchantRecipe.addIngredient(two); + merchantRecipe.setPriceMultiplier(0); + ArrayList recipes = new ArrayList<>(merchant.getRecipes()); + recipes.add(merchantRecipe); + merchant.setRecipes(recipes); + + if (action != null){ + actions.put(recipes.size() - 1, action); + } + } + + public void open(Player player){ + player.openMerchant(merchant, false); + GUIByUUID.put(player.getUniqueId(), this); + } + + public GUIAction getAction(int slot) { + return actions.get(slot); + } + + public VillagerType getVillagerType() { + return villagerType; + } +} diff --git a/src/main/java/com/alttd/GUI/windows/BuyGUI.java b/src/main/java/com/alttd/GUI/windows/BuyGUI.java new file mode 100644 index 0000000..968549c --- /dev/null +++ b/src/main/java/com/alttd/GUI/windows/BuyGUI.java @@ -0,0 +1,45 @@ +package com.alttd.GUI.windows; + +import com.alttd.GUI.GUIMerchant; +import com.alttd.config.Config; +import com.alttd.economy.Calculation; +import com.alttd.objects.VillagerType; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.Template; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public class BuyGUI extends GUIMerchant { + + private static final MiniMessage miniMessage = MiniMessage.get(); + + public BuyGUI(VillagerType villagerType) { + super(MiniMessage.get().parse(Config.BUY_WINDOW, + Template.of("trader", villagerType.getDisplayName()), + Template.of("percentage", "100")), villagerType); //TODO get percentage from player somehow + for (ItemStack itemStack : villagerType.getBuying()) { + double price = Calculation.price(itemStack); + addItem(itemStack, + getPriceItem(price), + null, + player -> player.sendMessage(MiniMessage.get().parse("Hi! you bought: " + itemStack.getAmount() + " " + itemStack.getType().name() + " for " + price + ".")) + ); + } + } + + private ItemStack getPriceItem(double price) { + if (price < 0) return nameItem(new ItemStack(Material.BARRIER), -1); + else if (price <= 10) return nameItem(new ItemStack(Material.IRON_INGOT), price); + else if (price <= 100) return nameItem(new ItemStack(Material.GOLD_INGOT), price); + else if (price <= 500) return nameItem(new ItemStack(Material.DIAMOND), price); + else return nameItem(new ItemStack(Material.NETHERITE_INGOT), price); + } + + private ItemStack nameItem(ItemStack itemStack, double price) { + ItemMeta itemMeta = itemStack.getItemMeta(); + itemMeta.displayName(miniMessage.parse("" + price + "")); //TODO configurable + itemStack.setItemMeta(itemMeta); + return itemStack; + } +} diff --git a/src/main/java/com/alttd/GUI/windows/OpenGUI.java b/src/main/java/com/alttd/GUI/windows/OpenGUI.java new file mode 100644 index 0000000..d44e83a --- /dev/null +++ b/src/main/java/com/alttd/GUI/windows/OpenGUI.java @@ -0,0 +1,40 @@ +package com.alttd.GUI.windows; + +import com.alttd.GUI.GUIInventory; +import com.alttd.config.Config; +import com.alttd.objects.VillagerType; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.Template; +import org.bukkit.Material; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public class OpenGUI extends GUIInventory { + + private static final ItemStack BUY = new ItemStack(Material.GOLD_INGOT); + private static final ItemStack SELL = new ItemStack(Material.BUCKET); + + static { + MiniMessage miniMessage = MiniMessage.get(); + ItemMeta itemMeta; + { + itemMeta = BUY.getItemMeta(); + itemMeta.displayName(miniMessage.parse("Buy")); + BUY.setItemMeta(itemMeta); + } + { + itemMeta = SELL.getItemMeta(); + itemMeta.displayName(miniMessage.parse("Sell")); + SELL.setItemMeta(itemMeta); + } + } + + public OpenGUI(VillagerType villagerType) { + super(InventoryType.HOPPER, MiniMessage.get().parse(Config.INITIAL_VILLAGER_WINDOW, + Template.of("trader", villagerType.getDisplayName()), + Template.of("percentage", "100"))); //TODO get percentage from player somehow + setItem(1, BUY, player -> new BuyGUI(villagerType).open(player)); + setItem(3, SELL, player -> new SellGUI(villagerType).open(player)); + } +} diff --git a/src/main/java/com/alttd/GUI/windows/SellGUI.java b/src/main/java/com/alttd/GUI/windows/SellGUI.java new file mode 100644 index 0000000..1235859 --- /dev/null +++ b/src/main/java/com/alttd/GUI/windows/SellGUI.java @@ -0,0 +1,45 @@ +package com.alttd.GUI.windows; + +import com.alttd.GUI.GUIMerchant; +import com.alttd.config.Config; +import com.alttd.economy.Calculation; +import com.alttd.objects.VillagerType; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.Template; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public class SellGUI extends GUIMerchant { + + private static final MiniMessage miniMessage = MiniMessage.get(); + + public SellGUI(VillagerType villagerType) { + super(MiniMessage.get().parse(Config.SELL_WINDOW, + Template.of("trader", villagerType.getDisplayName()), + Template.of("percentage", "100")), villagerType); //TODO get percentage from player somehow + for (ItemStack itemStack : villagerType.getSelling()) { + double price = Calculation.price(itemStack); + addItem(itemStack, + getPriceItem(price), + null, + player -> player.sendMessage(MiniMessage.get().parse("Hi! you sold: " + itemStack.getAmount() + " " + itemStack.getType().name() + " for " + price + ".")) + ); + } + } + + private ItemStack getPriceItem(double price) { + if (price < 0) return nameItem(new ItemStack(Material.BARRIER), -1); + else if (price <= 10) return nameItem(new ItemStack(Material.IRON_INGOT), price); + else if (price <= 100) return nameItem(new ItemStack(Material.GOLD_INGOT), price); + else if (price <= 500) return nameItem(new ItemStack(Material.DIAMOND), price); + else return nameItem(new ItemStack(Material.NETHERITE_INGOT), price); + } + + private ItemStack nameItem(ItemStack itemStack, double price) { + ItemMeta itemMeta = itemStack.getItemMeta(); + itemMeta.displayName(miniMessage.parse("" + price * -1 + "")); //TODO configurable + itemStack.setItemMeta(itemMeta); + return itemStack; + } +} diff --git a/src/main/java/com/alttd/VillagerUI.java b/src/main/java/com/alttd/VillagerUI.java new file mode 100644 index 0000000..fb147df --- /dev/null +++ b/src/main/java/com/alttd/VillagerUI.java @@ -0,0 +1,41 @@ +package com.alttd; + +import com.alttd.GUI.GUIListener; +import com.alttd.commands.CommandManager; +import com.alttd.config.Config; +import com.alttd.config.VillagerConfig; +import com.alttd.config.WorthConfig; +import com.alttd.events.VillagerInteract; +import org.bukkit.plugin.java.JavaPlugin; + +public class VillagerUI extends JavaPlugin { + + public static VillagerUI instance; + + public static VillagerUI getInstance() { + return instance; + } + + @Override + public void onLoad() { + instance = this; + } + + @Override + public void onEnable() { + registerEvents(); + new CommandManager(); + Config.reload(); + VillagerConfig.reload(); + WorthConfig.reload(); + getLogger().info("--------------------------------------------------"); + getLogger().info("Villager UI started"); + getLogger().info("--------------------------------------------------"); + } + + private void registerEvents() { + getServer().getPluginManager().registerEvents(new GUIListener(), this); + getServer().getPluginManager().registerEvents(new VillagerInteract(), this); + } + +} diff --git a/src/main/java/com/alttd/commands/CommandManager.java b/src/main/java/com/alttd/commands/CommandManager.java new file mode 100644 index 0000000..b0ae027 --- /dev/null +++ b/src/main/java/com/alttd/commands/CommandManager.java @@ -0,0 +1,92 @@ +package com.alttd.commands; + +import com.alttd.VillagerUI; +import com.alttd.commands.subcommands.CommandCreateVillager; +import com.alttd.commands.subcommands.CommandHelp; +import com.alttd.commands.subcommands.CommandReload; +import com.alttd.config.Config; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.Template; +import org.bukkit.command.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class CommandManager implements CommandExecutor, TabExecutor { + private final List subCommands; + private final MiniMessage miniMessage; + + public CommandManager() { + VillagerUI villagerUI = VillagerUI.getInstance(); + + PluginCommand command = villagerUI.getCommand("villagerui"); + if (command == null) { + subCommands = null; + miniMessage = null; + villagerUI.getLogger().severe("Unable to find villager ui command."); + return; + } + command.setExecutor(this); + command.setTabCompleter(this); + + subCommands = Arrays.asList( + new CommandHelp(this), + new CommandCreateVillager(), + new CommandReload()); + miniMessage = MiniMessage.get(); + } + + @Override + public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String cmd, @NotNull String[] args) { + if (args.length == 0) { + commandSender.sendMessage(miniMessage.parse(Config.HELP_MESSAGE_WRAPPER, Template.of("commands", subCommands.stream() + .filter(subCommand -> commandSender.hasPermission(subCommand.getPermission())) + .map(SubCommand::getHelpMessage) + .collect(Collectors.joining("\n"))))); + return true; + } + + SubCommand subCommand = getSubCommand(args[0]); + + if (!commandSender.hasPermission(subCommand.getPermission())) { + commandSender.sendMessage(miniMessage.parse(Config.NO_PERMISSION)); + return true; + } + + return subCommand.onCommand(commandSender, args); + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String cmd, @NotNull String[] args) { + List res = new ArrayList<>(); + + if (args.length <= 1) { + res.addAll(subCommands.stream() + .filter(subCommand -> commandSender.hasPermission(subCommand.getPermission())) + .map(SubCommand::getName) + .filter(name -> args.length == 0 || name.startsWith(args[0])) + .collect(Collectors.toList()) + ); + } else { + SubCommand subCommand = getSubCommand(args[0]); + if (subCommand != null && commandSender.hasPermission(subCommand.getPermission())) + res.addAll(subCommand.getTabComplete(commandSender, args)); + } + return res; + } + + public List getSubCommands() { + return subCommands; + } + + private SubCommand getSubCommand(String cmdName) { + return subCommands.stream() + .filter(subCommand -> subCommand.getName().equals(cmdName)) + .findFirst() + .orElse(null); + } +} \ No newline at end of file diff --git a/src/main/java/com/alttd/commands/SubCommand.java b/src/main/java/com/alttd/commands/SubCommand.java new file mode 100644 index 0000000..705bd5d --- /dev/null +++ b/src/main/java/com/alttd/commands/SubCommand.java @@ -0,0 +1,31 @@ +package com.alttd.commands; + +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.command.CommandSender; + +import java.util.List; + +public abstract class SubCommand { + + private final MiniMessage miniMessage; + + public SubCommand() { + miniMessage = MiniMessage.get(); + } + + public abstract boolean onCommand(CommandSender commandSender, String[] args); + + public abstract String getName(); + + public String getPermission() { + return "villagerui." + getName(); + } + + public abstract List getTabComplete(CommandSender commandSender, String[] args); + + public abstract String getHelpMessage(); + + protected MiniMessage getMiniMessage() { + return miniMessage; + } +} diff --git a/src/main/java/com/alttd/commands/subcommands/CommandCreateVillager.java b/src/main/java/com/alttd/commands/subcommands/CommandCreateVillager.java new file mode 100644 index 0000000..b4eef30 --- /dev/null +++ b/src/main/java/com/alttd/commands/subcommands/CommandCreateVillager.java @@ -0,0 +1,115 @@ +package com.alttd.commands.subcommands; + +import com.alttd.VillagerUI; +import com.alttd.commands.SubCommand; +import com.alttd.config.Config; +import com.alttd.config.VillagerConfig; +import com.alttd.objects.LoadedVillagers; +import com.alttd.objects.VillagerType; +import com.alttd.util.Utilities; +import net.kyori.adventure.text.minimessage.Template; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +public class CommandCreateVillager extends SubCommand { + + @Override + public boolean onCommand(CommandSender commandSender, String[] args) { + if (args.length < 8) { + commandSender.sendMessage(getMiniMessage().parse(getHelpMessage())); + return true; + } + + Optional first = VillagerType.getVillagerTypes().stream().filter(villagerType -> villagerType.getName().equalsIgnoreCase(args[1])).findFirst(); + if (first.isEmpty()) { + commandSender.sendMessage(getMiniMessage().parse(getHelpMessage())); + return true; + } + VillagerType villagerType = first.get(); + + World world = Bukkit.getServer().getWorld(args[7]); + if (world == null) { + commandSender.sendMessage(getMiniMessage().parse(getHelpMessage())); + return true; + } + Location location = new Location(world, Double.parseDouble(args[2]),Double.parseDouble(args[3]),Double.parseDouble(args[4]), Float.parseFloat(args[5]), Float.parseFloat(args[6])); + Villager villager = (Villager) world.spawnEntity(location, EntityType.VILLAGER, CreatureSpawnEvent.SpawnReason.CUSTOM); + villager.setPersistent(true); + villager.setInvulnerable(true); +// villager.setVillagerType(Villager.Type.); TODO choose villager type? + villager.setRemoveWhenFarAway(false); + villager.customName(getMiniMessage().parse(Config.VILLAGER_NAME, Template.of("name", villagerType.getDisplayName()))); + villager.setCustomNameVisible(true); + villager.setAI(false); + + UUID uuid = villager.getUniqueId(); + + LoadedVillagers.addLoadedVillager(uuid, villagerType); + VillagerConfig.addVillager(uuid, villagerType); + return true; + } + + @Override + public String getName() { + return "createvillager"; + } + + @Override + public List getTabComplete(CommandSender commandSender, String[] args) { + List res = new ArrayList<>(); + switch (args.length) { + case 2 -> res.addAll(VillagerType.getVillagerTypes().stream() + .map(VillagerType::getName) + .collect(Collectors.toList())); + case 3 -> { + if (commandSender instanceof Player player) { + res.add(String.valueOf(Utilities.round(player.getLocation().getX(), 2))); + } + } + case 4 -> { + if (commandSender instanceof Player player) { + res.add(String.valueOf(Utilities.round(player.getLocation().getY(), 1))); + } + } + case 5 -> { + if (commandSender instanceof Player player) { + res.add(String.valueOf(Utilities.round(player.getLocation().getZ(), 2))); + } + } + case 6 -> { + if (commandSender instanceof Player player) { + res.add(String.valueOf(Utilities.round(player.getLocation().getYaw(), 2))); + } + } + case 7 -> { + if (commandSender instanceof Player player) { + res.add(String.valueOf(Utilities.round(player.getLocation().getPitch(), 2))); + } + } + case 8 -> { + if (commandSender instanceof Player player) { + res.add(player.getLocation().getWorld().getName()); + } + } + } + return res; + } + + @Override + public String getHelpMessage() { + return Config.CREATE_VILLAGER_MESSAGE; + } +} diff --git a/src/main/java/com/alttd/commands/subcommands/CommandHelp.java b/src/main/java/com/alttd/commands/subcommands/CommandHelp.java new file mode 100644 index 0000000..5b76ca9 --- /dev/null +++ b/src/main/java/com/alttd/commands/subcommands/CommandHelp.java @@ -0,0 +1,50 @@ +package com.alttd.commands.subcommands; + +import com.alttd.commands.CommandManager; +import com.alttd.commands.SubCommand; +import com.alttd.config.Config; +import net.kyori.adventure.text.minimessage.Template; +import org.bukkit.command.CommandSender; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class CommandHelp extends SubCommand { + + private final CommandManager commandManager; + + public CommandHelp(CommandManager commandManager) { + super(); + this.commandManager = commandManager; + } + + @Override + public boolean onCommand(CommandSender commandSender, String[] args) { + commandSender.sendMessage(getMiniMessage().parse(Config.HELP_MESSAGE_WRAPPER, Template.of("commands", commandManager.getSubCommands().stream() + .filter(subCommand -> commandSender.hasPermission(subCommand.getPermission())) + .map(SubCommand::getHelpMessage) + .collect(Collectors.joining("\n"))))); + return true; + } + + @Override + public String getName() { + return "help"; + } + + @Override + public String getPermission() { + return "villagerui.use"; + } + + @Override + public List getTabComplete(CommandSender commandSender, String[] args) { + return new ArrayList<>(); + } + + @Override + public String getHelpMessage() { + return Config.HELP_MESSAGE; + } +} diff --git a/src/main/java/com/alttd/commands/subcommands/CommandReload.java b/src/main/java/com/alttd/commands/subcommands/CommandReload.java new file mode 100644 index 0000000..92569ff --- /dev/null +++ b/src/main/java/com/alttd/commands/subcommands/CommandReload.java @@ -0,0 +1,37 @@ +package com.alttd.commands.subcommands; + +import com.alttd.commands.SubCommand; +import com.alttd.config.Config; +import com.alttd.config.VillagerConfig; +import com.alttd.config.WorthConfig; +import org.bukkit.command.CommandSender; + +import java.util.ArrayList; +import java.util.List; + +public class CommandReload extends SubCommand { + + @Override + public boolean onCommand(CommandSender commandSender, String[] args) { + Config.reload(); + VillagerConfig.reload(); + WorthConfig.reload(); + commandSender.sendMessage(getMiniMessage().parse("Reloaded VillagerShopUI config.")); + return true; + } + + @Override + public String getName() { + return "reload"; + } + + @Override + public List getTabComplete(CommandSender commandSender, String[] args) { + return new ArrayList<>(); + } + + @Override + public String getHelpMessage() { + return Config.RELOAD_MESSAGE; + } +} diff --git a/src/main/java/com/alttd/commands/subcommands/CommandRemoveVillager.java b/src/main/java/com/alttd/commands/subcommands/CommandRemoveVillager.java new file mode 100644 index 0000000..01a8df9 --- /dev/null +++ b/src/main/java/com/alttd/commands/subcommands/CommandRemoveVillager.java @@ -0,0 +1,4 @@ +package com.alttd.commands.subcommands; + +public class CommandRemoveVillager { +} diff --git a/src/main/java/com/alttd/config/AbstractConfig.java b/src/main/java/com/alttd/config/AbstractConfig.java new file mode 100644 index 0000000..c1d76ae --- /dev/null +++ b/src/main/java/com/alttd/config/AbstractConfig.java @@ -0,0 +1,132 @@ +package com.alttd.config; + +import com.alttd.VillagerUI; +import com.google.common.collect.ImmutableMap; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +@SuppressWarnings({"unused", "SameParameterValue"}) +abstract class AbstractConfig { + File file; + YamlConfiguration yaml; + Logger logger; + + AbstractConfig(String filename) { + init(new File(VillagerUI.getInstance().getDataFolder(), filename), filename); + } + + AbstractConfig(File file, String filename) { + init(new File(file.getPath() + File.separator + filename), filename); + } + + private void init(File file, String filename) { + this.file = file; + this.yaml = new YamlConfiguration(); + this.logger = VillagerUI.getInstance().getLogger(); + try { + yaml.load(file); + } catch (IOException ignore) { + } catch (InvalidConfigurationException ex) { + logger.severe(String.format("Could not load %s, please correct your syntax errors", filename)); + throw new RuntimeException(ex); + } + yaml.options().copyDefaults(true); + } + + void readConfig(Class clazz, Object instance) { + for (Method method : clazz.getDeclaredMethods()) { + if (Modifier.isPrivate(method.getModifiers())) { + if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) { + try { + method.setAccessible(true); + method.invoke(instance); + } catch (InvocationTargetException ex) { + throw new RuntimeException(ex.getCause()); + } catch (Exception ex) { + logger.severe("Error invoking " + method); + ex.printStackTrace(); + } + } + } + } + + save(); + } + + private void save() { + try { + yaml.save(file); + } catch (IOException ex) { + logger.severe("Could not save " + file); + ex.printStackTrace(); + } + } + + void set(String path, Object val) { + yaml.addDefault(path, val); + yaml.set(path, val); + save(); + } + + String getString(String path, String def) { + yaml.addDefault(path, def); + return yaml.getString(path, yaml.getString(path)); + } + + boolean getBoolean(String path, boolean def) { + yaml.addDefault(path, def); + return yaml.getBoolean(path, yaml.getBoolean(path)); + } + + int getInt(String path, int def) { + yaml.addDefault(path, def); + return yaml.getInt(path, yaml.getInt(path)); + } + + double getDouble(String path, double def) { + yaml.addDefault(path, def); + return yaml.getDouble(path, yaml.getDouble(path)); + } + + List getList(String path, T def) { + yaml.addDefault(path, def); + return yaml.getList(path, yaml.getList(path)); + } + + @NonNull + Map getMap(final @NonNull String path, final @Nullable Map def) { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + if (def != null && yaml.getConfigurationSection(path) == null) { + yaml.addDefault(path, def.isEmpty() ? new HashMap<>() : def); + return def; + } + final ConfigurationSection section = yaml.getConfigurationSection(path); + if (section != null) { + for (String key : section.getKeys(false)) { + @SuppressWarnings("unchecked") + final T val = (T) section.get(key); + if (val != null) { + builder.put(key, val); + } + } + } + return builder.build(); + } + + ConfigurationSection getConfigurationSection(String path) { + return yaml.getConfigurationSection(path); + } +} \ No newline at end of file diff --git a/src/main/java/com/alttd/config/Config.java b/src/main/java/com/alttd/config/Config.java new file mode 100644 index 0000000..4376a59 --- /dev/null +++ b/src/main/java/com/alttd/config/Config.java @@ -0,0 +1,110 @@ +package com.alttd.config; + +import com.alttd.VillagerUI; +import com.alttd.objects.VillagerType; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.inventory.ItemStack; + +import java.io.File; +import java.util.HashSet; +import java.util.Set; + +public final class Config extends AbstractConfig { + + static Config config; + static int version; + + public Config() { + super(new File(System.getProperty("user.home") + File.separator + "share" + File.separator + "configs" + File.separator + "VillagerShopUI"), "config.yml"); + } + + public static void reload() { + config = new Config(); + + version = config.getInt("config-version", 1); + config.set("config-version", 1); + + config.readConfig(Config.class, null); + } + + public static String INITIAL_VILLAGER_WINDOW = " price: %"; + public static String BUY_WINDOW = " price: %"; + public static String SELL_WINDOW = " price: %"; + + private static void loadUI() { + INITIAL_VILLAGER_WINDOW = config.getString("ui.initial-window-name", INITIAL_VILLAGER_WINDOW); + BUY_WINDOW = config.getString("ui.buy-window-name", BUY_WINDOW); + SELL_WINDOW = config.getString("ui.sell-window-name", SELL_WINDOW); + } + + public static String HELP_MESSAGE_WRAPPER = "VillagerShopUI help:\n"; + public static String HELP_MESSAGE = "Show this menu: /villagerui help"; + public static String RELOAD_MESSAGE = "Reload configs: /villagerui reload"; + public static String CREATE_VILLAGER_MESSAGE = "Create a new trading villager: /villagerui createvillager "; + + private static void loadHelp() { + HELP_MESSAGE_WRAPPER = config.getString("help.help-wrapper", HELP_MESSAGE_WRAPPER); + HELP_MESSAGE = config.getString("help.help", HELP_MESSAGE); + RELOAD_MESSAGE = config.getString("help.reload", RELOAD_MESSAGE); + CREATE_VILLAGER_MESSAGE = config.getString("help.create-villager", CREATE_VILLAGER_MESSAGE); + } + + public static String NO_PERMISSION = "You do not have permission to do that."; + public static String NO_CONSOLE = "You cannot use this command from console."; + + private static void loadGeneric() { + NO_PERMISSION = config.getString("generic.no-permission", NO_PERMISSION); + NO_CONSOLE = config.getString("generic.no-console", NO_CONSOLE); + } + + public static String VILLAGER_NAME = ""; + + private static void loadIDKYET() {//TODO rename + VILLAGER_NAME = config.getString("idkyet.villager-name", VILLAGER_NAME); //TODO change path + } + + private static void loadVillagerTypes() { + VillagerType.clearVillagerTypes(); + ConfigurationSection configurationSection = config.getConfigurationSection("villager-types"); + if (configurationSection == null) { + VillagerUI.getInstance().getLogger().warning("No villager types found in config."); + return; + } + + Set keys = configurationSection.getKeys(false); + if (keys.isEmpty()) + VillagerUI.getInstance().getLogger().warning("No villager types found in config."); + + keys.forEach(key -> { + ConfigurationSection villagerType = configurationSection.getConfigurationSection(key); + if (villagerType == null) + return; + + VillagerType.addVillagerType(new VillagerType( + key, + villagerType.getString("name"), + loadProducts(villagerType.getConfigurationSection("buying")), + loadProducts(villagerType.getConfigurationSection("selling")), + villagerType.getDouble("price-modifier")) + ); + }); + } + + private static HashSet loadProducts(ConfigurationSection productsSection) { + HashSet products = new HashSet<>(); + if (productsSection == null) + return products; + + productsSection.getKeys(false).forEach(item -> { + Material material = Material.getMaterial(item); + if (material == null) { + VillagerUI.getInstance().getLogger().warning("Invalid key in products -> " + item); + return; + } + products.add(new ItemStack(material, productsSection.getInt(item))); + }); + + return products; + } +} diff --git a/src/main/java/com/alttd/config/VillagerConfig.java b/src/main/java/com/alttd/config/VillagerConfig.java new file mode 100644 index 0000000..40b6429 --- /dev/null +++ b/src/main/java/com/alttd/config/VillagerConfig.java @@ -0,0 +1,44 @@ +package com.alttd.config; + +import com.alttd.VillagerUI; +import com.alttd.objects.LoadedVillagers; +import com.alttd.objects.VillagerType; +import org.bukkit.configuration.ConfigurationSection; + +import java.util.Set; +import java.util.UUID; + +public class VillagerConfig extends AbstractConfig { + + static VillagerConfig config; + static int version; + + public VillagerConfig() { + super("villagerConfig.yml"); + } + + public static void reload() { + config = new VillagerConfig(); + + version = config.getInt("config-version", 1); + config.set("config-version", 1); + + config.readConfig(VillagerConfig.class, null); + } + + private static void loadVillagers() { + LoadedVillagers.clearLoadedVillagers(); + config.getConfigurationSection("").getKeys(false).forEach(key -> { + VillagerType villagerType = VillagerType.getVillagerType(config.getString(key, "")); + if (villagerType != null) + LoadedVillagers.addLoadedVillager(UUID.fromString(key), villagerType); + else + VillagerUI.getInstance().getLogger().warning("Invalid config entry " + key + "."); + }); + } + + public static void addVillager(UUID uuid, VillagerType villagerType) { + config.set(uuid.toString(), villagerType.getName()); + } + +} diff --git a/src/main/java/com/alttd/config/WorthConfig.java b/src/main/java/com/alttd/config/WorthConfig.java new file mode 100644 index 0000000..49db90d --- /dev/null +++ b/src/main/java/com/alttd/config/WorthConfig.java @@ -0,0 +1,47 @@ +package com.alttd.config; + +import com.alttd.VillagerUI; +import com.alttd.util.Utilities; +import it.unimi.dsi.fastutil.objects.Object2DoubleMap; +import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; + +import java.io.File; +import java.util.Set; + +public class WorthConfig extends AbstractConfig { + static WorthConfig config; + static int version; + + public WorthConfig() { + super(new File(System.getProperty("user.home") + File.separator + "share" + File.separator + "configs" + File.separator + "VillagerShopUI"), "worth.yml"); + } + + public static void reload() { + config = new WorthConfig(); + + version = config.getInt("config-version", 1); + config.set("config-version", 1); + + config.readConfig(WorthConfig.class, null); + } + + public static Object2DoubleMap prices = new Object2DoubleOpenHashMap<>(); + + private static void loadWorth() { + prices.clear(); + ConfigurationSection worth = config.getConfigurationSection("worth"); + Set keys = worth.getKeys(false); + for (String key : keys) { + Material material = Material.getMaterial(key); + if (material == null) { + VillagerUI.getInstance().getLogger().warning("Invalid key in worth.yml -> " + key); + continue; + } + + int price = (int) (worth.getDouble(key) * 100); + prices.put(Material.getMaterial(key), Utilities.round(price, 2)); + } + } +} diff --git a/src/main/java/com/alttd/economy/Calculation.java b/src/main/java/com/alttd/economy/Calculation.java new file mode 100644 index 0000000..c3e31f5 --- /dev/null +++ b/src/main/java/com/alttd/economy/Calculation.java @@ -0,0 +1,67 @@ +package com.alttd.economy; + +import com.alttd.config.WorthConfig; +import com.alttd.util.Utilities; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.inventory.*; + +import java.util.Collection; +import java.util.List; + +public class Calculation { + + /** + * Calculate the price for an item + * @param item to calculate price for + * @return price or int < 0 for error + */ + public static double price(ItemStack item) { + if (WorthConfig.prices.containsKey(item.getType())) + return Utilities.round(WorthConfig.prices.getDouble(item.getType()) * item.getAmount(), 2); + + WorthConfig.prices.put(item.getType(), Utilities.round(getPrice(item, null), 2)); + + return WorthConfig.prices.getDouble(item.getType()) * item.getAmount(); + } + + private static double getPrice(ItemStack item, Material blockedMaterial) { + if (WorthConfig.prices.containsKey(item.getType())) + return WorthConfig.prices.getDouble(item.getType()); + double price = -1; + List recipes = Bukkit.getRecipesFor(item); + for (Recipe recipe : recipes) { + double possiblePrice; + if (recipe instanceof ShapedRecipe shapedRecipe) { + Collection values = shapedRecipe.getIngredientMap().values(); + if (values.stream().anyMatch(itemStack -> itemStack.getType().equals(blockedMaterial))) + continue; + possiblePrice = getPrice(values.stream().toList(), item.getType()); + if (price == -1 || price > possiblePrice) + price = possiblePrice; + } else if (recipe instanceof ShapelessRecipe shapelessRecipe) { + if (shapelessRecipe.getIngredientList().stream().anyMatch(itemStack -> itemStack.getType().equals(blockedMaterial))) + continue; + possiblePrice = getPrice(shapelessRecipe.getIngredientList(), item.getType()); + if (price == -1 || price > possiblePrice) + price = possiblePrice; + } else if (recipe instanceof FurnaceRecipe furnaceRecipe) { + possiblePrice = getPrice(furnaceRecipe.getInput(), item.getType()); + if (price == -1 || price > possiblePrice) + price = possiblePrice; + } + } + return price; + } + + private static double getPrice(List items, Material blockedMaterial) { + double price = 0; + for (ItemStack item : items) { + double tmp = getPrice(item, blockedMaterial); + if (tmp == -1) + return -1; + price += tmp; + } + return price; + } +} diff --git a/src/main/java/com/alttd/events/VillagerInteract.java b/src/main/java/com/alttd/events/VillagerInteract.java new file mode 100644 index 0000000..7511758 --- /dev/null +++ b/src/main/java/com/alttd/events/VillagerInteract.java @@ -0,0 +1,24 @@ +package com.alttd.events; + +import com.alttd.GUI.windows.OpenGUI; +import com.alttd.objects.LoadedVillagers; +import com.alttd.objects.VillagerType; +import org.bukkit.entity.Villager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerInteractEntityEvent; + +public class VillagerInteract implements Listener { + + @EventHandler + public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { + if (!(event.getRightClicked() instanceof Villager villager)) + return; + + VillagerType loadedVillager = LoadedVillagers.getLoadedVillager(villager.getUniqueId()); + if (loadedVillager == null) + return; + + new OpenGUI(loadedVillager).open(event.getPlayer()); + } +} diff --git a/src/main/java/com/alttd/objects/LoadedVillagers.java b/src/main/java/com/alttd/objects/LoadedVillagers.java new file mode 100644 index 0000000..e9ba94b --- /dev/null +++ b/src/main/java/com/alttd/objects/LoadedVillagers.java @@ -0,0 +1,25 @@ +package com.alttd.objects; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class LoadedVillagers { + private final static Map loadedVillagers = new HashMap<>(); + + public static VillagerType getLoadedVillager(UUID uuid) { + return loadedVillagers.get(uuid); + } + + public static void addLoadedVillager(UUID uuid, VillagerType villagerType) { + loadedVillagers.put(uuid, villagerType); + } + + public static void removeLoadedVillager(UUID uuid) { + loadedVillagers.remove(uuid); + } + + public static void clearLoadedVillagers() { + loadedVillagers.clear(); + } +} diff --git a/src/main/java/com/alttd/objects/VillagerType.java b/src/main/java/com/alttd/objects/VillagerType.java new file mode 100644 index 0000000..28670d9 --- /dev/null +++ b/src/main/java/com/alttd/objects/VillagerType.java @@ -0,0 +1,59 @@ +package com.alttd.objects; + +import org.bukkit.inventory.ItemStack; + +import java.util.HashSet; +import java.util.Set; + +public class VillagerType { + private static final Set villagerTypes = new HashSet<>(); + + public static Set getVillagerTypes() { + return villagerTypes; + } + + public static VillagerType getVillagerType(String name) { + return villagerTypes.stream().filter(villagerType -> villagerType.getName().equals(name)).findFirst().orElse(null); + } + + public static void addVillagerType(VillagerType villagerType) { + villagerTypes.add(villagerType); + } + + public static void clearVillagerTypes() { + villagerTypes.clear(); + } + private final String name; + private final String displayName; + private final Set buying; + private final Set selling; + private final double priceModifier; + + public VillagerType(String name, String displayName, Set buying, Set selling, double priceModifier) { + this.name = name; + this.displayName = displayName; + this.buying = buying; + this.selling = selling; + this.priceModifier = priceModifier; + } + + public String getName() { + return name; + } + + public String getDisplayName() { + return displayName; + } + + public Set getBuying() { + return buying; + } + + public Set getSelling() { + return selling; + } + + public double getPriceModifier() { + return priceModifier; + } +} diff --git a/src/main/java/com/alttd/util/Utilities.java b/src/main/java/com/alttd/util/Utilities.java new file mode 100644 index 0000000..f47c449 --- /dev/null +++ b/src/main/java/com/alttd/util/Utilities.java @@ -0,0 +1,25 @@ +package com.alttd.util; + +public class Utilities { + /** + * Rounds num down to precision (rounds up if last cut off decimal is bigger than 4) + * + * @param num value to be rounded + * @param precision length to round to + * @return num rounded + */ + public static double round(double num, int precision) { + double scale = Math.pow(10, precision); + double total = (double) (Math.round(num * scale)) / scale; + + scale = (int) Math.pow(10, precision + 1); + long tmp = (Math.round(num * scale)); + + while (tmp > 10) + tmp /= 10; + if (tmp > 4) + total += 0.01; + + return total; + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..951b768 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,9 @@ +name: VillagerShopUI +version: ${project.version} +main: com.alttd.VillagerUI +api-version: 1.17 +commands: + villagerui: + permission: villagerui.use + description: Handles all villagerui commands + usage: /villagerui \ No newline at end of file